pax_global_header00006660000000000000000000000064150306262240014512gustar00rootroot0000000000000052 comment=23320e75953ac82e559c610bec5a90d9c6dfa743 windwp-nvim-autopairs-23320e7/000077500000000000000000000000001503062622400162455ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/.editorconfig000066400000000000000000000003051503062622400207200ustar00rootroot00000000000000 root = true [*] indent_style = space indent_size = 4 [*.lua] indent_style = space indent_size = 4 [*.vim] indent_style = space indent_size = 4 [*.snippets] indent_style = tab indent_size = 4 windwp-nvim-autopairs-23320e7/.github/000077500000000000000000000000001503062622400176055ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/.github/FUNDING.yml000066400000000000000000000000701503062622400214170ustar00rootroot00000000000000github: ['windwp'] custom: https://paypal.me/trieule1vn windwp-nvim-autopairs-23320e7/.github/ISSUE_TEMPLATE/000077500000000000000000000000001503062622400217705ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/.github/ISSUE_TEMPLATE/bug_report.yml000066400000000000000000000055321503062622400246700ustar00rootroot00000000000000name: Bug report description: Report a problem with nvim-autopairs labels: [bug] body: - type: markdown attributes: value: | Before reporting: search [existing issues](https://github.com/windwp/nvim-autopairs/issues) and make sure that both nvim-autopairs and its dependencies are updated to the latest version. - type: textarea attributes: label: "Description" description: "A short description of the problem you are reporting." validations: required: true - type: textarea attributes: label: "Mapping bug" description: "report a bug about mapping `` key and completion plugin" value: | 1.If you report a bug about indent. Please remember that plugin doesn't do anything about indent. It just trigger the indent of your vim config so if you have wrong indent config then it will do wrong indent. You can check by select a block of code and press `==` 2. provide result of command `:verbose imap `. validations: required: false - type: textarea attributes: label: "Steps to reproduce" description: "Steps to reproduce using the minimal config provided below." placeholder: | - It will beter if you can provide a video of gif validations: required: false - type: textarea attributes: label: "Minimal config" description: "Minimal(!) configuration necessary to reproduce the issue. Save this as `minimal.lua`. If _absolutely_ necessary, add plugins and config options from your `init.lua` at the indicated lines." render: Lua value: | vim.cmd [[set runtimepath=$VIMRUNTIME]] vim.cmd [[set packpath=/tmp/nvim/site]] local package_root = '/tmp/nvim/site/pack' local install_path = package_root .. '/packer/start/packer.nvim' local function load_plugins() require('packer').startup { { 'wbthomason/packer.nvim', { 'windwp/nvim-autopairs', }, -- ADD PLUGINS THAT ARE _NECESSARY_ FOR REPRODUCING THE ISSUE }, config = { package_root = package_root, compile_path = install_path .. '/plugin/packer_compiled.lua', display = { non_interactive = true }, }, } end _G.load_config = function() require('nvim-autopairs').setup() end if vim.fn.isdirectory(install_path) == 0 then print("Installing nvim-autopairs and dependencies.") vim.fn.system { 'git', 'clone', '--depth=1', 'https://github.com/wbthomason/packer.nvim', install_path } end load_plugins() require('packer').sync() vim.cmd [[autocmd User PackerComplete ++once echo "Ready!" | lua load_config()]] validations: required: true windwp-nvim-autopairs-23320e7/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000351503062622400237560ustar00rootroot00000000000000blank_issues_enabled: false windwp-nvim-autopairs-23320e7/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011341503062622400255140ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. windwp-nvim-autopairs-23320e7/.github/generated-files-bot.yml000066400000000000000000000003571503062622400241550ustar00rootroot00000000000000generatedFiles: - path: "doc/nvim-autopairs.txt" - path: "doc/nvim-autopairs-rules.txt" message: "`nvim-autopairs.txt` is generated from README.md. Make changes there instead." ignoreAuthors: - 'github-actions[bot]' - 'windwp' windwp-nvim-autopairs-23320e7/.github/stale.yml000066400000000000000000000012721503062622400214420ustar00rootroot00000000000000# Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 # Issues with these labels will never be considered stale exemptLabels: - pinned - security # Label to use when marking an issue as stale staleLabel: wontfix # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false only: issues windwp-nvim-autopairs-23320e7/.github/workflows/000077500000000000000000000000001503062622400216425ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/.github/workflows/ci.yml000066400000000000000000000032621503062622400227630ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: x64-ubuntu: name: X64-ubuntu runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: - os: ubuntu-20.04 url: https://github.com/neovim/neovim/releases/latest/download/nvim-linux64.tar.gz manager: sudo apt-get packages: -y fd-find steps: - uses: actions/checkout@v2 - run: date +%F > todays-date - name: Restore from todays cache uses: actions/cache@v2 with: path: _neovim key: ${{ runner.os }}-${{ matrix.url }}-${{ hashFiles('todays-date') }} - name: Prepare run: | ${{ matrix.manager }} update ${{ matrix.manager }} install ${{ matrix.packages }} test -d _neovim || { mkdir -p _neovim curl -sL ${{ matrix.url }} | tar xzf - --strip-components=1 -C "${PWD}/_neovim" } mkdir -p ~/.local/share/nvim/site/pack/vendor/start git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim git clone --depth 1 https://github.com/nvim-treesitter/nvim-treesitter ~/.local/share/nvim/site/pack/vendor/start/nvim-treesitter git clone --depth 1 https://github.com/nvim-treesitter/playground ~/.local/share/nvim/site/pack/vendor/start/playground ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start - name: Run tests run: | export PATH="${PWD}/_neovim/bin:${PATH}" export VIM="${PWD}/_neovim/share/nvim/runtime" nvim --headless -u tests/minimal.vim -c "TSInstallSync all" -c "q" make test windwp-nvim-autopairs-23320e7/.github/workflows/docs.yml000066400000000000000000000033361503062622400233220ustar00rootroot00000000000000name: panvimdoc on: push: paths: - README.md branches: - master jobs: docs: runs-on: ubuntu-latest permissions: contents: write pull-requests: write env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} name: markdown to vimdoc steps: - uses: actions/checkout@v2 - name: Setup git run: | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" printf 'VIMDOC_BRANCH=bot/vimdoc/%s\n' ${GITHUB_REF#refs/heads/} >> $GITHUB_ENV - name: Checkout to vimdoc branch run: git checkout -b ${VIMDOC_BRANCH} - name: panvimdoc uses: kdheepak/panvimdoc@v2.7.1 with: vimdoc: nvim-autopairs description: A super powerful autopair for Neovim. - name: clone rules api docs run: | git clone --depth 1 https://github.com/windwp/nvim-autopairs.wiki.git ../nvim-autopairs.wiki cp ../nvim-autopairs.wiki/Rules-API.md ./Rules-API.md - name: panvimdoc uses: kdheepak/panvimdoc@v2.7.1 with: vimdoc: nvim-autopairs-rules description: nvim-autopairs rules pandoc: "Rules-API.md" toc: true - name: Create PR run: | if ! [[ -z $(git status -s) ]]; then git add doc/nvim-autopairs.txt git add doc/nvim-autopairs-rules.txt git commit -m "chore: generated vimdoc" git push --force https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY} ${VIMDOC_BRANCH} gh pr create --fill --base ${GITHUB_REF#refs/heads/} --head ${VIMDOC_BRANCH} || true fi windwp-nvim-autopairs-23320e7/.github/workflows/sponsors.yml000066400000000000000000000014131503062622400242520ustar00rootroot00000000000000name: Generate Sponsors README on: workflow_dispatch: schedule: - cron: 0 0 1 */3 * permissions: contents: write jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout 🛎️ uses: actions/checkout@v2 - name: Setup Git Config run: | git config --global user.name 'github-actions[bot]' git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' - name: Generate Sponsors 💖 uses: JamesIves/github-sponsors-readme-action@v1 with: token: ${{ secrets.PAT }} file: 'README.md' - name: Deploy to GitHub Pages 🚀 uses: JamesIves/github-pages-deploy-action@v4 with: branch: master folder: '.' windwp-nvim-autopairs-23320e7/.gitignore000066400000000000000000000000111503062622400202250ustar00rootroot00000000000000doc/tags windwp-nvim-autopairs-23320e7/.luarc.json000066400000000000000000000002461503062622400203260ustar00rootroot00000000000000{ "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", "Lua.diagnostics.disable": [ "undefined-field" ] }windwp-nvim-autopairs-23320e7/LICENSE000066400000000000000000000020501503062622400172470ustar00rootroot00000000000000MIT License Copyright (c) 2021 windwp Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. windwp-nvim-autopairs-23320e7/Makefile000066400000000000000000000003621503062622400177060ustar00rootroot00000000000000test: nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal.vim'}" test-file: nvim --headless --noplugin -u tests/minimal.vim -c "lua require(\"plenary.busted\").run(\"$(FILE)\")" windwp-nvim-autopairs-23320e7/README.md000066400000000000000000000255741503062622400175410ustar00rootroot00000000000000## nvim-autopairs A super powerful autopair plugin for Neovim that supports multiple characters. Requires neovim 0.7 ## Installation Install the plugin with your preferred package manager: ### [lazy.nvim](https://github.com/folke/lazy.nvim) ```lua { 'windwp/nvim-autopairs', event = "InsertEnter", config = true -- use opts = {} for passing setup options -- this is equivalent to setup({}) function } ``` ### [vim-plug](https://github.com/junegunn/vim-plug) ```vim Plug 'windwp/nvim-autopairs' lua << EOF require("nvim-autopairs").setup {} EOF ``` ### [packer](https://github.com/wbthomason/packer.nvim) ```lua use { "windwp/nvim-autopairs", event = "InsertEnter", config = function() require("nvim-autopairs").setup {} end } ``` ## Default values ``` lua { enabled = function(bufnr) return true end, -- control if auto-pairs should be enabled when attaching to a buffer disable_filetype = { "TelescopePrompt", "spectre_panel", "snacks_picker_input" }, disable_in_macro = true, -- disable when recording or executing a macro disable_in_visualblock = false, -- disable when insert after visual block mode disable_in_replace_mode = true, ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=], enable_moveright = true, enable_afterquote = true, -- add bracket pairs after quote enable_check_bracket_line = true, --- check bracket in same line enable_bracket_in_quote = true, -- enable_abbr = false, -- trigger abbreviation break_undo = true, -- switch for basic rule break undo sequence check_ts = false, map_cr = true, map_bs = true, -- map the key map_c_h = false, -- Map the key to delete a pair map_c_w = false, -- map to delete a pair if possible } ``` ### Override default values ``` lua require('nvim-autopairs').setup({ disable_filetype = { "TelescopePrompt" , "vim" }, }) ``` #### Mapping `` ``` Before Input After ------------------------------------ {|} { | } ------------------------------------ ```
nvim-cmp

You need to add mapping `CR` on nvim-cmp setup. Check readme.md on nvim-cmp repo.

``` lua -- If you want insert `(` after select function or method item local cmp_autopairs = require('nvim-autopairs.completion.cmp') local cmp = require('cmp') cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done() ) ``` You can customize the kind of completion to add `(` or any character. ```lua local handlers = require('nvim-autopairs.completion.handlers') cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done({ filetypes = { -- "*" is a alias to all filetypes ["*"] = { ["("] = { kind = { cmp.lsp.CompletionItemKind.Function, cmp.lsp.CompletionItemKind.Method, }, handler = handlers["*"] } }, lua = { ["("] = { kind = { cmp.lsp.CompletionItemKind.Function, cmp.lsp.CompletionItemKind.Method }, ---@param char string ---@param item table item completion ---@param bufnr number buffer number ---@param rules table ---@param commit_character table handler = function(char, item, bufnr, rules, commit_character) -- Your handler function. Inspect with print(vim.inspect{char, item, bufnr, rules, commit_character}) end } }, -- Disable for tex tex = false } }) ) ``` Don't use `nil` to disable a filetype. If a filetype is `nil` then `*` is used as fallback.
coq_nvim ``` lua local remap = vim.api.nvim_set_keymap local npairs = require('nvim-autopairs') npairs.setup({ map_bs = false, map_cr = false }) vim.g.coq_settings = { keymap = { recommended = false } } -- these mappings are coq recommended mappings unrelated to nvim-autopairs remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) -- skip it, if you use another global object _G.MUtils= {} MUtils.CR = function() if vim.fn.pumvisible() ~= 0 then if vim.fn.complete_info({ 'selected' }).selected ~= -1 then return npairs.esc('') else return npairs.esc('') .. npairs.autopairs_cr() end else return npairs.autopairs_cr() end end remap('i', '', 'v:lua.MUtils.CR()', { expr = true, noremap = true }) MUtils.BS = function() if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info({ 'mode' }).mode == 'eval' then return npairs.esc('') .. npairs.autopairs_bs() else return npairs.autopairs_bs() end end remap('i', '', 'v:lua.MUtils.BS()', { expr = true, noremap = true }) ```
without completion plugin ```lua -- add option map_cr npairs.setup({ map_cr = true }) ```
[another completion plugin](https://github.com/windwp/nvim-autopairs/wiki/Completion-plugin) If you have a problem with indent after you press ` ` please check the settings of treesitter indent or install a plugin that has indent support for your filetype. ### Rule nvim-autopairs uses rules with conditions to check pairs. ``` lua local Rule = require('nvim-autopairs.rule') local npairs = require('nvim-autopairs') npairs.add_rule(Rule("$$","$$","tex")) -- you can use some built-in conditions local cond = require('nvim-autopairs.conds') print(vim.inspect(cond)) npairs.add_rules({ Rule("$", "$",{"tex", "latex"}) -- don't add a pair if the next character is % :with_pair(cond.not_after_regex("%%")) -- don't add a pair if the previous character is xxx :with_pair(cond.not_before_regex("xxx", 3)) -- don't move right when repeat character :with_move(cond.none()) -- don't delete if the next character is xx :with_del(cond.not_after_regex("xx")) -- disable adding a newline when you press :with_cr(cond.none()) }, -- disable for .vim files, but it work for another filetypes Rule("a","a","-vim") ) npairs.add_rules({ Rule("$$","$$","tex") :with_pair(function(opts) print(vim.inspect(opts)) if opts.line=="aa $$" then -- don't add pair on that line return false end end) } ) -- you can use regex -- press u1234 => u1234number npairs.add_rules({ Rule("u%d%d%d%d$", "number", "lua") :use_regex(true) }) -- press x1234 => x12341234 npairs.add_rules({ Rule("x%d%d%d%d$", "number", "lua") :use_regex(true) :replace_endpair(function(opts) -- print(vim.inspect(opts)) return opts.prev_char:sub(#opts.prev_char - 3,#opts.prev_char) end) }) -- you can do anything with regex +special key -- example press tab to uppercase text: -- press b1234s => B1234S1234S npairs.add_rules({ Rule("b%d%d%d%d%w$", "", "vim") :use_regex(true,"") :replace_endpair(function(opts) return opts.prev_char:sub(#opts.prev_char - 4,#opts.prev_char) .."viwU" end) }) -- you can exclude filetypes npairs.add_rule( Rule("$$","$$") :with_pair(cond.not_filetypes({"lua"})) ) --- check ./lua/nvim-autopairs/rules/basic.lua ``` [Rules API](https://github.com/windwp/nvim-autopairs/wiki/Rules-API) ### Treesitter You can use treesitter to check for a pair. ```lua local npairs = require("nvim-autopairs") local Rule = require('nvim-autopairs.rule') npairs.setup({ check_ts = true, ts_config = { lua = {'string'},-- it will not add a pair on that treesitter node javascript = {'template_string'}, java = false,-- don't check treesitter on java } }) local ts_conds = require('nvim-autopairs.ts-conds') -- press % => %% only while inside a comment or string npairs.add_rules({ Rule("%", "%", "lua") :with_pair(ts_conds.is_ts_node({'string','comment'})), Rule("$", "$", "lua") :with_pair(ts_conds.is_not_ts_node({'function'})) }) ``` ### Don't add pairs if it already has a close pair in the same line if **next character** is a close pair and it doesn't have an open pair in same line, then it will not add a close pair ``` text Before Input After ------------------------------------ ( |)) ( ( (|)) ``` ``` lua require('nvim-autopairs').setup({ enable_check_bracket_line = false }) ``` ### Don't add pairs if the next char is alphanumeric You can customize how nvim-autopairs will behave if it encounters a specific character ``` lua require('nvim-autopairs').setup({ ignored_next_char = "[%w%.]" -- will ignore alphanumeric and `.` symbol }) ``` ``` text Before Input After ------------------------------------ |foobar ( (|foobar |.foobar ( (|.foobar ``` ### Plugin Integration ``` lua require('nvim-autopairs').disable() require('nvim-autopairs').enable() require('nvim-autopairs').toggle() require('nvim-autopairs').remove_rule('(') -- remove rule ( require('nvim-autopairs').clear_rules() -- clear all rules require('nvim-autopairs').get_rules('"') ``` * Sample ```lua -- remove add single quote on filetype scheme or lisp require("nvim-autopairs").get_rules("'")[1].not_filetypes = { "scheme", "lisp" } require("nvim-autopairs").get_rules("'")[1]:with_pair(cond.not_after_text("[")) ``` ### FastWrap ``` text Before Input After Note ----------------------------------------------------------------- (|foobar then press $ (|foobar) (|)(foobar) then press q (|(foobar)) (|foo bar then press qh (|foo) bar (|foo bar then press qH (foo|) bar (|foo bar then press qH (foo)| bar if cursor_pos_before = false ``` ```lua -- put this to setup function and press to use fast_wrap npairs.setup({ fast_wrap = {}, }) -- change default fast_wrap npairs.setup({ fast_wrap = { map = '', chars = { '{', '[', '(', '"', "'" }, pattern = [=[[%'%"%>%]%)%}%,]]=], end_key = '$', before_key = 'h', after_key = 'l', cursor_pos_before = true, keys = 'qwertyuiopzxcvbnmasdfghjkl', manual_position = true, highlight = 'Search', highlight_grey='Comment' }, }) ``` ### autotag html and tsx [autotag](https://github.com/windwp/nvim-ts-autotag) ### Endwise [endwise](https://github.com/windwp/nvim-autopairs/wiki/Endwise) ### Custom rules [rules](https://github.com/windwp/nvim-autopairs/wiki/Custom-rules) ## Sponsors Thanks to everyone who sponsors my projects and makes continued development maintenance possible! windwp-nvim-autopairs-23320e7/doc/000077500000000000000000000000001503062622400170125ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/doc/nvim-autopairs-rules.txt000066400000000000000000000367411503062622400236740ustar00rootroot00000000000000*nvim-autopairs-rules.txt* nvim-autopairs rules ============================================================================== Table of Contents *nvim-autopairs-rules-table-of-contents* 1. Rule Basics |nvim-autopairs-rules-rule-basics| 2. Controlling rule behavior |nvim-autopairs-rules-controlling-rule-behavior| - Method Overview |nvim-autopairs-rules-method-overview| - Conditions |nvim-autopairs-rules-conditions| 3. Method Explanations |nvim-autopairs-rules-method-explanations| - The `with_*` methods |nvim-autopairs-rules-the-`with_*`-methods| - The `use_*` methods |nvim-autopairs-rules-the-`use_*`-methods| - Shorthand methods |nvim-autopairs-rules-shorthand-methods| - Advanced methods |nvim-autopairs-rules-advanced-methods| ============================================================================== 1. Rule Basics *nvim-autopairs-rules-rule-basics* At its core, a rule consists of two things: a **pair definition** and an optional **declaration of filetypes** where the rule is in effect. A pair definition has an opening part and a closing part. Each of these parts can be as simple as a single character like a pair of parenthesis, or multiple characters like Markdown code fences. Defining a rule is straightforward: > Rule(begin_pair, end_pair, filetypes) < Where `begin_pair` is the opening part of the pair and `end_pair` is the closing part. `filetypes` may be specified in multiple ways: > Rule("(", ")") -- Enabled for all filetypes Rule("(", ")", "markdown") -- As a string Rule("(", ")", {"markdown", "vim"}) -- As a table < Additionally, it is possible to specify filetypes where the rule should **not** be enabled by prefixing it with a `-` character: > Rule("(", ")", "-markdown") -- All filetypes *except* markdown < ============================================================================== 2. Controlling rule behavior *nvim-autopairs-rules-controlling-rule-behavior* By default, rules are very simple and will always complete a pair the moment the opening part is typed. This is fine and in some cases desirable, but the rules API allows you to control the manner and context in which pairs are completed; this is done by attaching **conditions** (predicates) to **events** and adding **modifiers** to the rule. `Rule` objects expose a variety of methods to add these predicates and modifiers to the rule. METHOD OVERVIEW *nvim-autopairs-rules-method-overview* These methods allow control over if, when, and how rules perform completion of pairs. Each method returns the `Rule` object so that they may be chained together to easily define complex rules. │ method │ usage │ │with_pair(cond) │add condition to check during pair event │ │with_move(cond) │add condition to check during move right event │ │with_cr(cond) │add condition to check during line break event │ │with_del(cond) │add condition to check during delete pair event │ │only_cr(cond) │enable _only_ the line break event; disable everything │ │ │else │ │use_regex(bool, "") │ey │ │use_key("") │set trigger key │ │replace_endpair(fun│define ending part with a function; optionally add with│ │c, check_pair) │_pair │ │set_end_pair_length│override offset used to position the cursor between the│ │(number) │ pair when replace_endpair is used │ │replace_map_cr(func│change the mapping for used for during the line br│ │) │eak event │ │end_wise(cond) │make the rule an end-wise rule │ AIDING UNDERSTANDING: "WHEN" INSTEAD OF "WITH" ~ It may be helpful to think of the `with_` functions as reading more like `when_` instead, as the condition is checked **when** `` happens (or wants to happen). This naming scheme more accurately describes how the `Rule` is affected and reads more intuitively when reading a rule definition. For example, given a rule definition `Rule("(", ")")`, each method has a certain effect on how and when the ending part of the pair, the closing parenthesis, is completed. The ending part is only completed **when** associated conditions are met upon typing the opening part of the pair. CONDITIONS *nvim-autopairs-rules-conditions* nvim-autopairs comes with a variety of common predicates ready to use simply by including: > local cond = require('nvim-autopairs.conds') < │ function │ Usage │ │none() │always false │ │done() │always true │ │before_text(text) │text exists before opening part │ │after_text(text) │text exists after opening part │ │before_regex(regex, length│regex matches before opening part │ │) │ │ │after_regex(regex, length)│regex matches after opening part │ │ │ │ │not_before_text(text) │text is not before opening part │ │not_after_text(text) │text is not after opening part │ │not_before_regex(regex, le│regex doesn’t match before opening part │ │ngth) │ │ │not_after_regex(regex, len│regex doesn’t match after opening part │ │gth) │ │ │not_inside_quote() │not currently within quotation marks │ │is_inside_quote() │currently within quotation marks │ │not_filetypes({table}) │current filetype is not inside table │ │is_bracket_in_quote() │check the next char is quote and cursor is insi│ │ │de quote │ **N.B.** While `cond.not_filetypes` is available, it’s better to use the minus syntax on the desired filetype in the initial rule declaration, since then the rule is completely removed from the buffer. TREESITTER CONDITIONS ~ Predicates based on the state of the Treesitter graph can be used by including: > local ts_conds = require('nvim-autopairs.ts-conds') < │ function │ Usage │ │is_ts_node({node_table}) │check current treesitter node│ │is_not_ts_node({node_table})│check not in treesitter node │ ============================================================================== 3. Method Explanations *nvim-autopairs-rules-method-explanations* This section explains each method in more detail: their signatures and how they modify the rule’s behavior are all outlined here. THE `WITH_*` METHODS *nvim-autopairs-rules-the-`with_*`-methods* Calling these methods on a `Rule` will add predicate functions to their corresponding event, which determines whether the effect of the event actually takes place. There are no predicates if you don’t define any, and so any events without predicates behave as if they had a single predicate that always returns true. The predicate functions will receive an `opts` table with the following fields: - `rule` the `Rule` object - `bufnr` the buffer number - `col` the current column (1-indexed) - `ts_node` the current treesitter node (if treesitter is enabled) - `text` the current line, with typed char inserted - `line` the current line, before substitutions - `char` the typed char - `prev_char` the text just before cursor (with length `== #rule.start_pair`) - `next_char` the text just after cursor (with length `== #rule.start_pair` if rule is not regex, else end of line) A `Rule` may have more than one predicate defined for a given event, and the order that they are defined will be the order that they are checked. However, the **first** non-`nil` value returned by a predicate is used and the remaining predicates (if any) are **not** executed. In other words, predicates defined earlier have priority over predicates defined later. `WITH_PAIR(COND, POS)` ~ After typing the opening part, the ending part will only be added if `cond(opts)` returned true. `with_pair` may be called more than once, and by default, each predicate is appended to a list. When the "pair" event fires, the _first_ predicate to return non-nil is used as the condition result. Specifying `pos` allows explicit control over the order of the predicates. `WITH_MOVE(COND)` ~ If `cond(opts)` is true, the cursor is simply moved right when typing the ending part of the pair and the next character is also the ending part, e.g. `foo|"` => `foo"|` when typing `"`. If `cond(opts)` returns false, the ending part is inserted as normal instead. `WITH_CR(COND)` ~ If `cond(opts)` is true, then move the ending part of the pair to a new line below the cursor after pressing `` while the cursor is between the pair (think curly braces opening a block). Otherwise `` behaves as normal. For example: > {|} < Typing `` produces the following when `cond` is true: > { | } < `WITH_DEL(COND)` ~ If `cond(opts)` is true, when the cursor is between the pair, pressing `` to delete the opening part of the pair will delete the ending part as well. THE `USE_*` METHODS *nvim-autopairs-rules-the-`use_*`-methods* The `use_*` functions alter how auto-pairing is triggered. Normally, the first argument to `Rule` is taken literally as the opening part of the pair and as soon as it is typed the "pair" event fires. `USE_KEY(KEY)` ~ The pair is only completed when `key` is pressed, instead of the moment that the opening part is typed. This is particularly useful in `use_regex`. `USE_REGEX(BOOL, KEY)` ~ Causes the opening part to be interpreted as a lua pattern that triggers insertion of the ending part when matched. If `key` is specified, then it acts as an implicit `use_key`. SHORTHAND METHODS *nvim-autopairs-rules-shorthand-methods* These methods exist as convenient shortcuts for defining certain behaviors. `END_WISE(FUNC)` ~ This method is used to make "end-wise" rules, which is terminology that should be familiar to users of other auto-pair plugins, e.g. Lexima. Specifically, this method makes it so that the ending part of the pair will be completed _only upon pressing `` after the opening part_, in which case the "newline" event is fired as usual. This behavior is useful for languages with statement constructs like Lua and Bash. For example, defining the following `Rule`: > Rule('then', 'end'):end_wise(function(opts)) -- Add any context checks here, e.g. line starts with "if" return string.match(opts.line, '^%s*if') ~= nil end) < And then pressing `` at the following cursor position: > if foo == bar then| < Would be completed as this (assuming some kind of automatic indent is enabled): > if foo == bar then | end < `ONLY_CR(COND)` ~ This shortcut method disables the "pair", "del", and "move" events by setting a single predicate for each that is always false. Additionally, the effect of any `use_key` modifiers are removed as well. If `cond` is specified, a "newline" predicate is set as if `with_cr` were called. This method is convenient for defining _simple_ end-wise rules. As an example, a default rule is defined with `only_cr` for Markdown code blocks with an explicit language; the closing triple-backtick is not completed until you press `` after specifying the language: > ```lua <-- pressed here | ``` < ADVANCED METHODS *nvim-autopairs-rules-advanced-methods* These methods allow you to define more complex and dynamic rules. When combined with `with_*` and `use_*` methods, it is possible to create very powerful auto-pairs. `REPLACE_ENDPAIR(FUNC, CHECK_PAIR)` ~ Facilitates the creation of dynamic ending parts. When the "pair" event fires and the ending part is to be completed, `func` is called with a single `opts` argument and should return a string. The returned string will be sent to `nvim_feedkeys` to insert the ending part of the pair. The `opts` parameter is a table that provides context for the current pair completion, and can be useful for determining what to return. Note that because `nvim_feedkeys` is used, arbitrary Vim functionality can be leveraged, such as including `` to be able to send normal mode commands. *nvim-autopairs-rules-Optional-`check_pair`-parameter* Optional `check_pair` parameter The `check_pair` parameter is optional, and can either be a boolean or function. If `check_pair` is a function, it is passed as-is to `with_pair` to create a "pair" predicate. If `check_pair` is true, then an implicit `with_pair(cond.after_text(rule.end_pair))` predicate is added, where `rule.end_pair` is the second argument to the `Rule` constructor. If `check_pair` is false, an "always false" `with_pair` predicate is added. As an example, these two rule definitions are equivalent: > -- This... Rule("(", ")") :use_key("") :replace_endpair(function() return "" end, true) -- ...is shorthand for this Rule("(", "") :use_key("") :with_pair(cond.after_text(")")) -- check that text after cursor is `)` :replace_endpair(function() return "" end) < `SET_END_PAIR_LENGTH(LEN)` ~ When completing the ending part of a pair, the cursor necessarily moves backward so that is in between the opening part and the closing part. In order to do this, the `Rule` must know the length of the ending part, which by default is trivially determined. However, if you would like to override where the cursor is placed after completion, i.e. using `replace_endpair`, you can explicitly set the ending part length with this method. `REPLACE_MAP_CR(FUNC)` ~ This method allows you to set a custom mapping for the "newline" (``) event that will be used instead of the normal behavior. This can be helpful for enforcing certain styles or or adding additional edits. `func` is called with a single `opts` argument and should return a string specifying the mapping for ``. The default mapping is: `uO`. Generated by panvimdoc vim:tw=78:ts=8:noet:ft=help:norl: windwp-nvim-autopairs-23320e7/doc/nvim-autopairs.txt000066400000000000000000000315401503062622400225340ustar00rootroot00000000000000*nvim-autopairs.txt* A super powerful autopair for Neovim. ============================================================================== Table of Contents *nvim-autopairs-table-of-contents* - nvim-autopairs |nvim-autopairs-nvim-autopairs| - Installation |nvim-autopairs-installation| - Default values |nvim-autopairs-default-values| - Sponsors |nvim-autopairs-sponsors| NVIM-AUTOPAIRS *nvim-autopairs-nvim-autopairs* A super powerful autopair plugin for Neovim that supports multiple characters. Requires neovim 0.7 INSTALLATION *nvim-autopairs-installation* Install the plugin with your preferred package manager: LAZY.NVIM ~ > { 'windwp/nvim-autopairs', event = "InsertEnter", config = true -- use opts = {} for passing setup options -- this is equivalent to setup({}) function } < VIM-PLUG ~ > Plug 'windwp/nvim-autopairs' lua << EOF require("nvim-autopairs").setup {} EOF < PACKER ~ > use { "windwp/nvim-autopairs", event = "InsertEnter", config = function() require("nvim-autopairs").setup {} end } < DEFAULT VALUES *nvim-autopairs-default-values* > { enabled = function(bufnr) return true end, -- control if auto-pairs should be enabled when attaching to a buffer disable_filetype = { "TelescopePrompt", "spectre_panel" } disable_in_macro = true -- disable when recording or executing a macro disable_in_visualblock = false -- disable when insert after visual block mode disable_in_replace_mode = true ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=] enable_moveright = true enable_afterquote = true -- add bracket pairs after quote enable_check_bracket_line = true --- check bracket in same line enable_bracket_in_quote = true -- enable_abbr = false -- trigger abbreviation break_undo = true -- switch for basic rule break undo sequence check_ts = false map_cr = true map_bs = true -- map the key map_c_h = false -- Map the key to delete a pair map_c_w = false -- map to delete a pair if possible } < OVERRIDE DEFAULT VALUES ~ > require('nvim-autopairs').setup({ disable_filetype = { "TelescopePrompt" , "vim" }, }) < *nvim-autopairs-Mapping-``* > Before Input After ------------------------------------ {|} { | } ------------------------------------ < nvim-cmp ~

You need to add mapping `CR` on nvim-cmp setup. Check readme.md on nvim-cmp repo.

> -- If you want insert `(` after select function or method item local cmp_autopairs = require('nvim-autopairs.completion.cmp') local cmp = require('cmp') cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done() ) < Mapping `` You can customize the kind of completion to add `(` or any character. > local handlers = require('nvim-autopairs.completion.handlers') cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done({ filetypes = { -- "*" is a alias to all filetypes ["*"] = { ["("] = { kind = { cmp.lsp.CompletionItemKind.Function, cmp.lsp.CompletionItemKind.Method, }, handler = handlers["*"] } }, lua = { ["("] = { kind = { cmp.lsp.CompletionItemKind.Function, cmp.lsp.CompletionItemKind.Method }, ---@param char string ---@param item table item completion ---@param bufnr number buffer number ---@param rules table ---@param commit_character table handler = function(char, item, bufnr, rules, commit_character) -- Your handler function. Inspect with print(vim.inspect{char, item, bufnr, rules, commit_character}) end } }, -- Disable for tex tex = false } }) ) < Don’t use `nil` to disable a filetype. If a filetype is `nil` then `*` is used as fallback. coq_nvim ~ > local remap = vim.api.nvim_set_keymap local npairs = require('nvim-autopairs') npairs.setup({ map_bs = false, map_cr = false }) vim.g.coq_settings = { keymap = { recommended = false } } -- these mappings are coq recommended mappings unrelated to nvim-autopairs remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) remap('i', '', [[pumvisible() ? "" : ""]], { expr = true, noremap = true }) -- skip it, if you use another global object _G.MUtils= {} MUtils.CR = function() if vim.fn.pumvisible() ~= 0 then if vim.fn.complete_info({ 'selected' }).selected ~= -1 then return npairs.esc('') else return npairs.esc('') .. npairs.autopairs_cr() end else return npairs.autopairs_cr() end end remap('i', '', 'v:lua.MUtils.CR()', { expr = true, noremap = true }) MUtils.BS = function() if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info({ 'mode' }).mode == 'eval' then return npairs.esc('') .. npairs.autopairs_bs() else return npairs.autopairs_bs() end end remap('i', '', 'v:lua.MUtils.BS()', { expr = true, noremap = true }) < without completion plugin ~ > -- add option map_cr npairs.setup({ map_cr = true }) < another completion plugin If you have a problem with indent after you press `` please check the settings of treesitter indent or install a plugin that has indent support for your filetype. RULE ~ nvim-autopairs uses rules with conditions to check pairs. > local Rule = require('nvim-autopairs.rule') local npairs = require('nvim-autopairs') npairs.add_rule(Rule("$$","$$","tex")) -- you can use some built-in conditions local cond = require('nvim-autopairs.conds') print(vim.inspect(cond)) npairs.add_rules({ Rule("$", "$",{"tex", "latex"}) -- don't add a pair if the next character is % :with_pair(cond.not_after_regex("%%")) -- don't add a pair if the previous character is xxx :with_pair(cond.not_before_regex("xxx", 3)) -- don't move right when repeat character :with_move(cond.none()) -- don't delete if the next character is xx :with_del(cond.not_after_regex("xx")) -- disable adding a newline when you press :with_cr(cond.none()) }, -- disable for .vim files, but it work for another filetypes Rule("a","a","-vim") ) npairs.add_rules({ Rule("$$","$$","tex") :with_pair(function(opts) print(vim.inspect(opts)) if opts.line=="aa $$" then -- don't add pair on that line return false end end) } ) -- you can use regex -- press u1234 => u1234number npairs.add_rules({ Rule("u%d%d%d%d$", "number", "lua") :use_regex(true) }) -- press x1234 => x12341234 npairs.add_rules({ Rule("x%d%d%d%d$", "number", "lua") :use_regex(true) :replace_endpair(function(opts) -- print(vim.inspect(opts)) return opts.prev_char:sub(#opts.prev_char - 3,#opts.prev_char) end) }) -- you can do anything with regex +special key -- example press tab to uppercase text: -- press b1234s => B1234S1234S npairs.add_rules({ Rule("b%d%d%d%d%w$", "", "vim") :use_regex(true,"") :replace_endpair(function(opts) return opts.prev_char:sub(#opts.prev_char - 4,#opts.prev_char) .."viwU" end) }) -- you can exclude filetypes npairs.add_rule( Rule("$$","$$") :with_pair(cond.not_filetypes({"lua"})) ) --- check ./lua/nvim-autopairs/rules/basic.lua < Rules API TREESITTER ~ You can use treesitter to check for a pair. > local npairs = require("nvim-autopairs") local Rule = require('nvim-autopairs.rule') npairs.setup({ check_ts = true, ts_config = { lua = {'string'},-- it will not add a pair on that treesitter node javascript = {'template_string'}, java = false,-- don't check treesitter on java } }) local ts_conds = require('nvim-autopairs.ts-conds') -- press % => %% only while inside a comment or string npairs.add_rules({ Rule("%", "%", "lua") :with_pair(ts_conds.is_ts_node({'string','comment'})), Rule("$", "$", "lua") :with_pair(ts_conds.is_not_ts_node({'function'})) }) < DON’T ADD PAIRS IF IT ALREADY HAS A CLOSE PAIR IN THE SAME LINE ~ if **next character** is a close pair and it doesn’t have an open pair in same line, then it will not add a close pair > Before Input After ------------------------------------ ( |)) ( ( (|)) < > require('nvim-autopairs').setup({ enable_check_bracket_line = false }) < DON’T ADD PAIRS IF THE NEXT CHAR IS ALPHANUMERIC ~ You can customize how nvim-autopairs will behave if it encounters a specific character > require('nvim-autopairs').setup({ ignored_next_char = "[%w%.]" -- will ignore alphanumeric and `.` symbol }) < > Before Input After ------------------------------------ |foobar ( (|foobar |.foobar ( (|.foobar < PLUGIN INTEGRATION ~ > require('nvim-autopairs').disable() require('nvim-autopairs').enable() require('nvim-autopairs').toggle() require('nvim-autopairs').remove_rule('(') -- remove rule ( require('nvim-autopairs').clear_rules() -- clear all rules require('nvim-autopairs').get_rules('"') < - Sample > -- remove add single quote on filetype scheme or lisp require("nvim-autopairs").get_rules("'")[1].not_filetypes = { "scheme", "lisp" } require("nvim-autopairs").get_rules("'")[1]:with_pair(cond.not_after_text("[")) < FASTWRAP ~ > Before Input After Note ----------------------------------------------------------------- (|foobar then press $ (|foobar) (|)(foobar) then press q (|(foobar)) (|foo bar then press qh (|foo) bar (|foo bar then press qH (foo|) bar (|foo bar then press qH (foo)| bar if cursor_pos_before = false < > -- put this to setup function and press to use fast_wrap npairs.setup({ fast_wrap = {}, }) -- change default fast_wrap npairs.setup({ fast_wrap = { map = '', chars = { '{', '[', '(', '"', "'" }, pattern = [=[[%'%"%>%]%)%}%,]]=], end_key = '$', before_key = 'h', after_key = 'l', cursor_pos_before = true, avoid_move_to_end = true, -- stay for direct end_key use keys = 'qwertyuiopzxcvbnmasdfghjkl', manual_position = true, highlight = 'Search', highlight_grey='Comment' }, }) < AUTOTAG HTML AND TSX ~ autotag ENDWISE ~ endwise CUSTOM RULES ~ rules SPONSORS *nvim-autopairs-sponsors* Thanks to everyone who sponsors my projects and makes continued development maintenance possible! george looshch Generated by panvimdoc vim:tw=78:ts=8:noet:ft=help:norl: windwp-nvim-autopairs-23320e7/lua/000077500000000000000000000000001503062622400170265ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/lua/nvim-autopairs.lua000066400000000000000000000510611503062622400225120ustar00rootroot00000000000000local log = require('nvim-autopairs._log') local utils = require('nvim-autopairs.utils') local basic_rule = require('nvim-autopairs.rules.basic') local api = vim.api local highlighter = nil local M = {} M.state = { disabled = false, rules = {}, buf_ts = {}, } local default = { map_bs = true, map_c_h = false, map_c_w = false, map_cr = true, enabled = nil, disable_filetype = { 'TelescopePrompt', 'spectre_panel', 'snacks_picker_input' }, disable_in_macro = true, disable_in_visualblock = false, disable_in_replace_mode = true, ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=], break_undo = true, check_ts = false, enable_moveright = true, enable_afterquote = true, enable_check_bracket_line = true, enable_bracket_in_quote = true, enable_abbr = false, ts_config = { lua = { 'string', 'source', 'string_content' }, javascript = { 'string', 'template_string' }, }, } M.setup = function(opt) M.config = vim.tbl_deep_extend('force', default, opt or {}) if M.config.fast_wrap then require('nvim-autopairs.fastwrap').setup(M.config.fast_wrap) end M.config.rules = basic_rule.setup(M.config) if M.config.check_ts then local ok, ts_rule = pcall(require, 'nvim-autopairs.rules.ts_basic') if ok then highlighter = require "vim.treesitter.highlighter" M.config.rules = ts_rule.setup(M.config) end end if M.config.map_cr then M.map_cr() end M.force_attach() local group = api.nvim_create_augroup('autopairs_buf', { clear = true }) api.nvim_create_autocmd({ 'BufEnter', 'BufWinEnter' }, { group = group, pattern = '*', callback = function() M.on_attach() end }) api.nvim_create_autocmd('BufDelete', { group = group, pattern = '*', callback = function(data) local cur = api.nvim_get_current_buf() local bufnr = tonumber(data.buf) or 0 if bufnr ~= cur then M.set_buf_rule(nil, bufnr) end end, }) api.nvim_create_autocmd('FileType', { group = group, pattern = '*', callback = function() M.force_attach() end }) end M.add_rule = function(rule) M.add_rules({ rule }) end M.get_rule = function(start_pair) local tbl = M.get_rules(start_pair) if #tbl == 1 then return tbl[1] end return tbl end M.get_rules = function(start_pair) local tbl = {} for _, r in pairs(M.config.rules) do if r.start_pair == start_pair then table.insert(tbl, r) end end return tbl end M.remove_rule = function(pair) local tbl = {} for _, r in pairs(M.config.rules) do if r.start_pair ~= pair then table.insert(tbl, r) end end M.config.rules = tbl if M.state.rules then local state_tbl = {} local rules = M.get_buf_rules() for _, r in pairs(rules) do if r.start_pair ~= pair then table.insert(state_tbl, r) elseif r.key_map and r.key_map ~= '' then api.nvim_buf_del_keymap(0, 'i', r.key_map) end end M.set_buf_rule(state_tbl, 0) end M.force_attach() end M.add_rules = function(rules) for _, rule in pairs(rules) do table.insert(M.config.rules, rule) end M.force_attach() end M.clear_rules = function() M.state.rules = {} M.config.rules = {} end M.disable = function() M.state.disabled = true end M.enable = function() M.state.disabled = false end M.toggle = function() M.state.disabled = not M.state.disabled end --- force remap key to buffer M.force_attach = function(bufnr) utils.set_attach(bufnr, 0) M.on_attach(bufnr) end local del_keymaps = function() local status, autopairs_keymaps = pcall(api.nvim_buf_get_var, 0, 'autopairs_keymaps') if status and autopairs_keymaps and #autopairs_keymaps > 0 then for _, key in pairs(autopairs_keymaps) do pcall(api.nvim_buf_del_keymap, 0, 'i', key) end end end local function is_disable() if M.state.disabled then return true end if vim.bo.filetype == '' and api.nvim_win_get_config(0).relative ~= '' then -- disable for any floating window without filetype return true end if vim.bo.modifiable == false then return true end if M.config.disable_in_macro and (vim.fn.reg_recording() ~= '' or vim.fn.reg_executing() ~= '') then return true end if M.config.disable_in_replace_mode and vim.api.nvim_get_mode().mode == "R" then return true end if M.config.disable_in_visualblock and utils.is_block_wise_mode() then return true end if vim.v.count > 0 then return true end if utils.check_filetype(M.config.disable_filetype, vim.bo.filetype) or (M.config.enabled and not M.config.enabled(api.nvim_get_current_buf())) then del_keymaps() M.set_buf_rule({}, 0) return true end return false end ---@return table M.get_buf_rules = function(bufnr) return M.state.rules[bufnr or api.nvim_get_current_buf()] or {} end ---@param rules nil|table list or rule ---@param bufnr number buffer number M.set_buf_rule = function(rules, bufnr) if bufnr == 0 or bufnr == nil then bufnr = api.nvim_get_current_buf() end M.state.rules[bufnr] = rules end M.on_attach = function(bufnr) -- log.debug('on_attach' .. vim.bo.filetype) if is_disable() then return end bufnr = bufnr or api.nvim_get_current_buf() local rules = {} for _, rule in pairs(M.config.rules) do if utils.check_filetype(rule.filetypes, vim.bo.filetype) and utils.check_not_filetype(rule.not_filetypes, vim.bo.filetype) then table.insert(rules, rule) end end -- sort by pair and keymap table.sort(rules, function(a, b) if a.start_pair == b.start_pair then if not b.key_map then return a.key_map end if not a.key_map then return b.key_map end return #a.key_map < #b.key_map end if #a.start_pair == #b.start_pair then return string.byte(a.start_pair) > string.byte(b.start_pair) end return #a.start_pair > #b.start_pair end) M.set_buf_rule(rules, bufnr) if M.config.check_ts then if highlighter and highlighter.active[bufnr] then M.state.ts_node = M.config.ts_config[vim.bo.filetype] else M.state.ts_node = nil end end if utils.is_attached(bufnr) then return end del_keymaps() local enable_insert_auto = false local autopairs_keymaps = {} local expr_map = function(key) api.nvim_buf_set_keymap(bufnr, 'i', key, '', { expr = true, noremap = true, desc = "autopairs map key", callback = function() return M.autopairs_map(bufnr, key) end, }) table.insert(autopairs_keymaps, key) end for _, rule in pairs(rules) do if rule.key_map ~= nil then if rule.is_regex == false then if rule.key_map == '' then rule.key_map = rule.start_pair:sub(#rule.start_pair) end expr_map(rule.key_map) local key_end = rule.key_end or rule.end_pair:sub(1, 1) if #key_end >= 1 and key_end ~= rule.key_map and rule.move_cond ~= nil then expr_map(key_end) end else if rule.key_map ~= '' then expr_map(rule.key_map) elseif rule.is_endwise == false then enable_insert_auto = true end end end end api.nvim_buf_set_var(bufnr, 'autopairs_keymaps', autopairs_keymaps) if enable_insert_auto then -- capture all key use it to trigger regex pairs -- it can make an issue with paste from register api.nvim_create_autocmd('InsertCharPre', { group = api.nvim_create_augroup(string.format("autopairs_insert_%d", bufnr), { clear = true }), buffer = bufnr, callback = function() M.autopairs_insert(bufnr, vim.v.char) end }) end if M.config.fast_wrap and M.config.fast_wrap.map then api.nvim_buf_set_keymap( bufnr, 'i', M.config.fast_wrap.map, "llua require('nvim-autopairs.fastwrap').show()", { noremap = true } ) end if M.config.map_bs then api.nvim_buf_set_keymap( bufnr, 'i', '', '', { callback = M.autopairs_bs, expr = true, noremap = true } ) end if M.config.map_c_h then api.nvim_buf_set_keymap( bufnr, "i", utils.key.c_h, '', { callback = M.autopairs_c_h, expr = true, noremap = true } ) end if M.config.map_c_w then api.nvim_buf_set_keymap( bufnr, 'i', '', '', { callback = M.autopairs_c_w, expr = true, noremap = true } ) end api.nvim_buf_set_var(bufnr, 'nvim-autopairs', 1) end local autopairs_delete = function(bufnr, key) if is_disable() then return utils.esc(key) end bufnr = bufnr or api.nvim_get_current_buf() local line = utils.text_get_current_line(bufnr) local _, col = utils.get_cursor() local rules = M.get_buf_rules(bufnr) for _, rule in pairs(rules) do if rule.start_pair then local prev_char, next_char = utils.text_cusor_line( line, col, #rule.start_pair, #rule.end_pair, rule.is_regex ) if utils.compare(rule.start_pair, prev_char, rule.is_regex) and utils.compare(rule.end_pair, next_char, rule.is_regex) and rule:can_del({ ts_node = M.state.ts_node, rule = rule, bufnr = bufnr, prev_char = prev_char, next_char = next_char, line = line, col = col, }) then local input = '' for _ = 1, api.nvim_strwidth(rule.start_pair), 1 do input = input .. utils.key.bs end for _ = 1, api.nvim_strwidth(rule.end_pair), 1 do input = input .. utils.key.del end return utils.esc('U' .. input) end end end return utils.esc(key) end M.autopairs_c_w = function(bufnr) return autopairs_delete(bufnr, 'U') end M.autopairs_c_h = function(bufnr) return autopairs_delete(bufnr, utils.key.c_h) end M.autopairs_bs = function(bufnr) return autopairs_delete(bufnr, utils.key.bs) end M.autopairs_map = function(bufnr, char) if is_disable() then return char end local line = utils.text_get_current_line(bufnr) local _, col = utils.get_cursor() local new_text = '' local add_char = 1 local rules = M.get_buf_rules(bufnr) for _, rule in pairs(rules) do if rule.start_pair then if char:match('<.*>') then new_text = line add_char = 0 else new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line) add_char = rule.key_map and #rule.key_map or 1 end -- log.debug("new_text:[" .. new_text .. "]") local prev_char, next_char = utils.text_cusor_line( new_text, col + add_char, #rule.start_pair, #rule.end_pair, rule.is_regex ) local cond_opt = { ts_node = M.state.ts_node, text = new_text, rule = rule, bufnr = bufnr, col = col + 1, char = char, line = line, prev_char = prev_char, next_char = next_char, } -- log.debug("start_pair" .. rule.start_pair) -- log.debug('prev_char' .. prev_char) -- log.debug('next_char' .. next_char) local char_matches_rule = (rule.end_pair == char or rule.key_map == char) -- for simple pairs, char will match end_pair -- for more complex pairs, user should map the wanted end char with `use_key` -- on a dedicated rule if char_matches_rule and utils.compare(rule.end_pair, next_char, rule.is_regex) and rule:can_move(cond_opt) then local end_pair = rule:get_end_pair(cond_opt) local end_pair_length = rule:get_end_pair_length(end_pair) return utils.esc(utils.repeat_key(utils.key.join_right, end_pair_length)) end if rule.key_map == char and utils.compare(rule.start_pair, prev_char, rule.is_regex) and rule:can_pair(cond_opt) then local end_pair = rule:get_end_pair(cond_opt) local end_pair_length = rule:get_end_pair_length(end_pair) local move_text = utils.repeat_key(utils.key.join_left, end_pair_length) if add_char == 0 then move_text = '' char = '' end if end_pair:match('<.*>') then end_pair = utils.esc(end_pair) end local result = char .. end_pair .. utils.esc(move_text) if rule.is_undo then result = utils.esc(utils.key.undo_sequence) .. result .. utils.esc(utils.key.undo_sequence) end if M.config.enable_abbr then result = utils.esc(utils.key.abbr) .. result end log.debug("key_map :" .. result) return result end end end return M.autopairs_afterquote(new_text, utils.esc(char)) end M.autopairs_insert = function(bufnr, char) if is_disable() then return char end local line = utils.text_get_current_line(bufnr) local _, col = utils.get_cursor() local new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line) local rules = M.get_buf_rules(bufnr) for _, rule in pairs(rules) do if rule.start_pair and rule.is_regex and rule.key_map == '' then local prev_char, next_char = utils.text_cusor_line( new_text, col + 1, #rule.start_pair, #rule.end_pair, rule.is_regex ) local cond_opt = { ts_node = M.state.ts_node, text = new_text, rule = rule, bufnr = bufnr, col = col + 1, char = char, line = line, prev_char = prev_char, next_char = next_char, } -- log.debug("start_pair" .. rule.start_pair) -- log.debug('prev_char' .. prev_char) -- log.debug('next_char' .. next_char) if next_char == rule.end_pair and rule:can_move(cond_opt) then utils.set_vchar('') vim.schedule(function() utils.feed(utils.key.right, -1) end) return false end if utils.compare(rule.start_pair, prev_char, rule.is_regex) and rule:can_pair(cond_opt) then local end_pair = rule:get_end_pair(cond_opt) utils.set_vchar(char .. end_pair) vim.schedule(function() utils.feed(utils.key.left, rule:get_end_pair_length(end_pair)) end) return end end end return char end M.autopairs_cr = function(bufnr) if is_disable() then return utils.esc('') end bufnr = bufnr or api.nvim_get_current_buf() local line = utils.text_get_current_line(bufnr) local _, col = utils.get_cursor() -- log.debug("on_cr") local rules = M.get_buf_rules(bufnr) for _, rule in pairs(rules) do if rule.start_pair then local prev_char, next_char = utils.text_cusor_line( line, col, #rule.start_pair, #rule.end_pair, rule.is_regex ) local cond_opt = { ts_node = M.state.ts_node, check_endwise_ts = true, rule = rule, bufnr = bufnr, col = col, line = line, prev_char = prev_char, next_char = next_char, } -- log.debug('prev_char' .. rule.start_pair) -- log.debug('prev_char' .. prev_char) -- log.debug('next_char' .. next_char) if rule.is_endwise and utils.compare(rule.start_pair, prev_char, rule.is_regex) and rule:can_cr(cond_opt) then local end_pair = rule:get_end_pair(cond_opt) return utils.esc( '' .. end_pair -- FIXME do i need to re indent twice #118 .. 'normal! ====' ) end cond_opt.check_endwise_ts = false if utils.compare(rule.start_pair, prev_char, rule.is_regex) and utils.compare(rule.end_pair, next_char, rule.is_regex) and rule:can_cr(cond_opt) then log.debug('do_cr') return utils.esc(rule:get_map_cr({ rule = rule, line = line, color = col, bufnr = bufnr })) end end end return utils.esc('') end --- add bracket pairs after quote (|"aaaaa" => (|"aaaaaa") M.autopairs_afterquote = function(line, key_char) if M.config.enable_afterquote and not utils.is_block_wise_mode() then line = line or utils.text_get_current_line(0) local _, col = utils.get_cursor() local prev_char, next_char = utils.text_cusor_line(line, col + 1, 1, 1, false) if utils.is_bracket(prev_char) and utils.is_quote(next_char) and not utils.is_in_quotes(line, col, next_char) then local count = 0 local index = 0 local is_prev_slash = false local char_end = '' for i = col, #line, 1 do local char = line:sub(i, i + #next_char - 1) if not is_prev_slash and char == next_char then count = count + 1 char_end = line:sub(i + 1, i + #next_char) index = i end is_prev_slash = char == '\\' end if count == 2 and index >= (#line - 2) then local rules = M.get_buf_rules(api.nvim_get_current_buf()) for _, rule in pairs(rules) do if rule.start_pair == prev_char and char_end ~= rule.end_pair then local new_text = line:sub(0, index) .. rule.end_pair .. line:sub(index + 1, #line) M.state.expr_quote = new_text local append = 'a' if col > 0 then append = 'la' end return utils.esc( "lua require'nvim-autopairs'.autopairs_closequote_expr()" .. append ) end end end end end return key_char end M.autopairs_closequote_expr = function() ---@diagnostic disable-next-line: param-type-mismatch vim.fn.setline('.', M.state.expr_quote) end M.check_break_line_char = function() return M.autopairs_cr() end M.completion_confirm = function() if vim.fn.pumvisible() ~= 0 then return M.esc("") else return M.autopairs_cr() end end M.map_cr = function() api.nvim_set_keymap( 'i', '', "v:lua.require'nvim-autopairs'.completion_confirm()", { expr = true, noremap = true } ) end M.esc = utils.esc return M windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/000077500000000000000000000000001503062622400220045ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/_log.lua000066400000000000000000000005141503062622400234270ustar00rootroot00000000000000---@diagnostic disable: undefined-field local empty = { debug = function(_) end, info = function(_) end, error = function(_) end, } if _G.__is_log then return require('plenary.log').new { plugin = 'nvim-autopairs', level = (_G.__is_log == true and 'debug') or 'warn', } or empty end return empty windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/completion/000077500000000000000000000000001503062622400241555ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/completion/cmp.lua000066400000000000000000000046471503062622400254520ustar00rootroot00000000000000local autopairs = require('nvim-autopairs') local handlers = require('nvim-autopairs.completion.handlers') local cmp = require('cmp') local Kind = cmp.lsp.CompletionItemKind local M = {} M.filetypes = { -- Alias to all filetypes ["*"] = { ["("] = { kind = { Kind.Function, Kind.Method }, handler = handlers["*"] } }, python = { ["("] = { kind = { Kind.Function, Kind.Method }, handler = handlers.python } }, clojure = { ["("] = { kind = { Kind.Function, Kind.Method }, handler = handlers.lisp } }, clojurescript = { ["("] = { kind = { Kind.Function, Kind.Method }, handler = handlers.lisp } }, fennel = { ["("] = { kind = { Kind.Function, Kind.Method }, handler = handlers.lisp } }, janet = { ["("] = { kind = { Kind.Function, Kind.Method }, handler = handlers.lisp } }, tex = false, plaintex = false, context = false, haskell = false, purescript = false, sh = false, bash = false, nix = false, helm = false } M.on_confirm_done = function(opts) opts = vim.tbl_deep_extend('force', { filetypes = M.filetypes }, opts or {}) return function(evt) if evt.commit_character then return end local entry = evt.entry local commit_character = entry:get_commit_characters() local bufnr = vim.api.nvim_get_current_buf() local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype') local item = entry:get_completion_item() -- Without options and fallback if not opts.filetypes[filetype] and not opts.filetypes["*"] then return end if opts.filetypes[filetype] == false then return end -- If filetype is nil then use * local completion_options = opts.filetypes[filetype] or opts.filetypes["*"] local rules = vim.tbl_filter(function(rule) return completion_options[rule.key_map] end, autopairs.get_buf_rules(bufnr)) for char, value in pairs(completion_options) do if vim.tbl_contains(value.kind, item.kind) then value.handler(char, item, bufnr, rules, commit_character) end end end end return M windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/completion/compe.lua000066400000000000000000000054761503062622400257770ustar00rootroot00000000000000local npairs = require('nvim-autopairs') local Completion = require('compe.completion') local utils = require('nvim-autopairs.utils') local method_kind = nil local function_kind = nil local options = {} local M = {} M.completion_done = function() local line = utils.text_get_current_line(0) local _, col = utils.get_cursor() local prev_char, next_char = utils.text_cusor_line(line, col, 1, 1, false) local filetype = vim.bo.filetype local char = options.map_char[filetype] or options.map_char["all"] or '(' if char == '' then return end if prev_char ~= char and next_char ~= char then if method_kind == nil then method_kind = require('vim.lsp.protocol').CompletionItemKind[2] function_kind = require('vim.lsp.protocol').CompletionItemKind[3] end local item = Completion._confirm_item if item.kind == method_kind or item.kind == function_kind then -- check insert text have ( from snippet local completion_item = item.user_data.compe.completion_item if ( completion_item.textEdit and completion_item.textEdit.newText and completion_item.textEdit.newText:match('[%(%[%$]') ) or (completion_item.insertText and completion_item.insertText:match('[%(%[%$]')) then return end vim.api.nvim_feedkeys(char, 'i', true) end end end M.setup = function(opt) opt = opt or { map_cr = true, map_complete = true, auto_select = false, map_char = {all = '('}} if not opt.map_char then opt.map_char = {} end options = opt local map_cr = opt.map_cr local map_complete = opt.map_complete vim.g.completion_confirm_key = '' if map_cr then vim.api.nvim_set_keymap( 'i', '', '', { callback = M.completion_confirm, expr = true, noremap = true } ) end if opt.auto_select then M.completion_confirm = function() if vim.fn.pumvisible() ~= 0 then return vim.fn['compe#confirm']({ keys = '', select = true }) else return npairs.autopairs_cr() end end else M.completion_confirm = function() if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info()['selected'] ~= -1 then return vim.fn['compe#confirm'](npairs.esc('')) else return npairs.autopairs_cr() end end end if map_complete then vim.cmd([[ augroup autopairs_compe autocmd! autocmd User CompeConfirmDone lua require'nvim-autopairs.completion.compe'.completion_done() augroup end ]]) end end return M windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/completion/handlers.lua000066400000000000000000000052601503062622400264630ustar00rootroot00000000000000local autopairs = require('nvim-autopairs') local utils = require('nvim-autopairs.utils') local M = {} ---@param char string ---@param item table ---@param bufnr number ---@param rules table ---@param commit_character table M["*"] = function(char, item, bufnr, rules, _) local line = utils.text_get_current_line(bufnr) local _, col = utils.get_cursor() local char_before, char_after = utils.text_cusor_line(line, col, 1, 1, false) if char == '' or char_before == char or char_after == char or (item.data and type(item.data) == 'table' and item.data.funcParensDisabled) or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]") or (item.insertText and item.insertText:match "[%(%[%$]") then return end if vim.tbl_isempty(rules) then return end local new_text = '' local add_char = 1 for _, rule in pairs(rules) do if rule.start_pair then local prev_char, next_char = utils.text_cusor_line( new_text, col + add_char, #rule.start_pair, #rule.end_pair, rule.is_regex ) local cond_opt = { ts_node = autopairs.state.ts_node, text = new_text, rule = rule, bufnr = bufnr, col = col + 1, char = char, line = line, prev_char = prev_char, next_char = next_char, } if rule.key_map and rule:can_pair(cond_opt) then vim.api.nvim_feedkeys(rule.key_map, "i", true) return end end end end ---Handler with "clojure", "clojurescript", "fennel", "janet M.lisp = function (char, item, bufnr, _, _) local line = utils.text_get_current_line(bufnr) local _, col = utils.get_cursor() local char_before, char_after = utils.text_cusor_line(line, col, 1, 1, false) local length = #item.label if char == '' or char_before == char or char_after == char or (item.data and item.data.funcParensDisabled) or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]") or (item.insertText and item.insertText:match "[%(%[%$]") then return end if utils.text_sub_char(line, col - length, 1) == "(" then utils.feed("") return end utils.feed(utils.key.left, length) utils.feed(char) utils.feed(utils.key.right, length) utils.feed("") end M.python = function(char, item, bufnr, rules, _) if item.data then item.data.funcParensDisabled = false end M["*"](char,item,bufnr,rules) end return M windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/conds.lua000066400000000000000000000225641503062622400236260ustar00rootroot00000000000000local utils = require('nvim-autopairs.utils') local log = require('nvim-autopairs._log') ---@class CondOpts ---@field ts_node table ---@field text string ---@field rule table ---@field bufnr number ---@field col number ---@field char string ---@field line string ---@field prev_char string ---@field next_char string ---@field is_endwise string local cond = {} -- cond -- @return false when it is not correct -- true when it is correct -- nil when it is not determine -- stylua: ignore cond.none = function() return function() return false end end -- stylua: ignore cond.done = function() return function() return true end end cond.invert = function(func) return function(...) local result = func(...) if result ~= nil then return not result end return nil end end cond.before_regex = function(regex, length) length = length or 1 if length < 0 then length = nil end length = length and -length ---@param opts CondOpts return function(opts) log.debug('before_regex') local str = utils.text_sub_char(opts.line, opts.col - 1, length or -opts.col) if str:match(regex) then return true end return false end end cond.before_text = function(text) local length = #text ---@param opts CondOpts return function(opts) log.debug('before_text') local str = utils.text_sub_char(opts.line, opts.col - 1, -length) if str == text then return true end return false end end cond.after_text = function(text) local length = #text ---@param opts CondOpts return function(opts) log.debug('after_text') local str = utils.text_sub_char(opts.line, opts.col, length) if str == text then return true end return false end end cond.after_regex = function(regex, length) length = length or 1 if length < 0 then length = nil end ---@param opts CondOpts return function(opts) log.debug('after_regex') local str = utils.text_sub_char(opts.line, opts.col, length or #opts.line) if str:match(regex) then return true end return false end end cond.not_before_text = function(text) local length = #text return function(opts) log.debug('not_before_text') local str = utils.text_sub_char(opts.line, opts.col - 1, -length) if str == text then return false end end end cond.not_after_text = function(text) local length = #text ---@param opts CondOpts return function(opts) log.debug('not_after_text') local str = utils.text_sub_char(opts.line, opts.col, length) if str == text then return false end end end cond.not_before_regex = function(regex, length) length = length or 1 if length < 0 then length = nil end length = length and -length ---@param opts CondOpts return function(opts) log.debug('not_before_regex') log.debug(length) local str = utils.text_sub_char(opts.line, opts.col - 1, length or -opts.col) if str:match(regex) then return false end end end cond.not_after_regex = function(regex, length) length = length or 1 if length < 0 then length = nil end ---@param opts CondOpts return function(opts) log.debug('not_after_regex') local str = utils.text_sub_char(opts.line, opts.col, length or #opts.line) if str:match(regex) then return false end end end local function count_bracket_char(line, prev_char, next_char) local count_prev_char = 0 local count_next_char = 0 for i = 1, #line, 1 do local c = line:sub(i, i) if c == prev_char then count_prev_char = count_prev_char + 1 elseif c == next_char then count_next_char = count_next_char + 1 end end return count_prev_char, count_next_char end -- Checks if bracket chars are balanced around specific postion. ---@param line string ---@param open_char string ---@param close_char string ---@param col integer position local function is_brackets_balanced_around_position(line, open_char, close_char, col) local balance = 0 for i = 1, #line, 1 do local c = line:sub(i, i) if c == open_char then balance = balance + 1 elseif balance > 0 and c == close_char then balance = balance - 1 if col <= i and balance == 0 then break end end end return balance == 0 end cond.is_bracket_line = function() ---@param opts CondOpts return function(opts) log.debug('is_bracket_line') if utils.is_bracket(opts.char) and (opts.next_char == opts.rule.end_pair or opts.next_char == opts.rule.start_pair) then -- (( many char |)) => add -- ( many char |)) => not add local count_prev_char, count_next_char = count_bracket_char( opts.line, opts.rule.start_pair, opts.rule.end_pair ) if count_prev_char ~= count_next_char then return false end end end end cond.is_bracket_line_move = function() ---@param opts CondOpts return function(opts) log.debug('is_bracket_line_move') if utils.is_close_bracket(opts.char) and opts.char == opts.rule.end_pair then -- (( many char |)) => move -- (( many char |) => not move local is_balanced = is_brackets_balanced_around_position( opts.line, opts.rule.start_pair, opts.char, opts.col ) return is_balanced end end end cond.not_inside_quote = function() ---@param opts CondOpts return function(opts) log.debug('not_inside_quote') if utils.is_in_quotes(opts.text, opts.col - 1) then return false end end end cond.is_inside_quote = function() ---@param opts CondOpts return function(opts) log.debug('is_inside_quote') if utils.is_in_quotes(opts.text, opts.col - 1) then return true end end end cond.not_add_quote_inside_quote = function() ---@param opts CondOpts return function(opts) log.debug('not_add_quote_inside_quote') if utils.is_quote(opts.char) and utils.is_in_quotes(opts.text, opts.col - 1) then return false end end end cond.move_right = function() ---@param opts CondOpts return function(opts) log.debug('move_right') if opts.next_char == opts.char then if utils.is_close_bracket(opts.char) then return end -- move right when have quote on end line or in quote -- situtaion |" => "| if utils.is_quote(opts.char) then if opts.col == string.len(opts.line) then return end -- ("|") => (""|) -- "" |" " => "" "| " if utils.is_in_quotes(opts.line, opts.col - 1, opts.char) then return end end end return false end end cond.is_end_line = function() ---@param opts CondOpts return function(opts) log.debug('is_end_line') local end_text = opts.line:sub(opts.col + 1) -- end text is blank if end_text ~= '' and end_text:match('^%s+$') == nil then return false end end end --- Check the next char is quote and cursor is inside quote cond.is_bracket_in_quote = function() ---@param opts CondOpts return function(opts) log.debug("is_bracket_in_quote") if utils.is_bracket(opts.char) and utils.is_quote(opts.next_char) and utils.is_in_quotes(opts.line, opts.col - 1, opts.next_char) then return true end end end cond.not_filetypes = function(filetypes) return function() log.debug('not_filetypes') for _, filetype in pairs(filetypes) do if vim.bo.filetype == filetype then return false end end end end --- Check the character before the cursor is not equal ---@param char string character to compare ---@param index number the position of character before current curosr cond.not_before_char = function(char, index) index = index or 1 ---@param opts CondOpts return function(opts) log.debug('not_before_char') local match_char = #opts.line > index and opts.line:sub(#opts.line - index, #opts.line - index) or '' if match_char == char and match_char ~= "" then return false end end end ---@deprecated cond.not_after_regex_check = cond.not_after_regex ---@deprecated cond.after_regex_check = cond.after_regex ---@deprecated cond.before_regex_check = cond.before_regex ---@deprecated cond.not_before_regex_check = cond.not_before_regex ---@deprecated cond.after_text_check = cond.after_text ---@deprecated cond.not_after_text_check = cond.not_after_text ---@deprecated cond.before_text_check = cond.before_text ---@deprecated cond.not_before_text_check = cond.not_before_text return cond windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/fastwrap.lua000066400000000000000000000204251503062622400243410ustar00rootroot00000000000000local utils = require('nvim-autopairs.utils') local log = require('nvim-autopairs._log') local npairs = require('nvim-autopairs') local M = {} local default_config = { map = '', chars = { '{', '[', '(', '"', "'" }, pattern = [=[[%'%"%>%]%)%}%,%`]]=], end_key = '$', avoid_move_to_end = true, -- choose your move behaviour for non-alphabetical end_keys' before_key = 'h', after_key = 'l', cursor_pos_before = true, keys = 'qwertyuiopzxcvbnmasdfghjkl', highlight = 'Search', highlight_grey = 'Comment', manual_position = true, use_virt_lines = true } M.ns_fast_wrap = vim.api.nvim_create_namespace('autopairs_fastwrap') local config = {} M.setup = function(cfg) if config.chars == nil then config = vim.tbl_extend('force', default_config, cfg or {}) or {} npairs.config.fast_wrap = config end end function M.getchar_handler() local ok, key = pcall(vim.fn.getchar) if not ok then return nil end if key ~= 27 and type(key) == 'number' then local key_str = vim.fn.nr2char(key) return key_str end return nil end M.show = function(line) line = line or utils.text_get_current_line(0) log.debug(line) local row, col = utils.get_cursor() local prev_char = utils.text_cusor_line(line, col, 1, 1, false) local end_pair = '' if utils.is_in_table(config.chars, prev_char) then local rules = npairs.get_buf_rules() for _, rule in pairs(rules) do if rule.start_pair == prev_char then end_pair = rule.end_pair end end if end_pair == '' then return end local list_pos = {} --holds target locations local index = 1 local str_length = #line local offset = -1 for i = col + 2, #line, 1 do local char = line:sub(i, i) local char2 = line:sub(i - 1, i) if string.match(char, config.pattern) or (char == ' ' and string.match(char2, '%w')) then local key = config.keys:sub(index, index) index = index + 1 if not config.manual_position and ( utils.is_quote(char) or ( utils.is_close_bracket(char) and utils.is_in_quotes(line, col, prev_char) ) ) then offset = 0 end if config.manual_position and i == str_length then key = config.end_key end table.insert( list_pos, { col = i + offset, key = key, char = char, pos = i } ) end end log.debug(list_pos) local end_col, end_pos if config.manual_position then end_col = str_length + offset end_pos = str_length else end_col = str_length + 1 end_pos = str_length + 1 end -- add end_key to list extmark if #list_pos == 0 or list_pos[#list_pos].key ~= config.end_key then table.insert( list_pos, { col = end_col, key = config.end_key, pos = end_pos, char = config.end_key } ) end -- Create a whitespace string for the current line which replaces every non whitespace -- character with a space and preserves tabs, so we can use it for highlighting with -- virtual lines so that highlighting lines up correctly. -- The string is limited to the last position in list_pos local whitespace_line = line:sub(1, list_pos[#list_pos].end_pos):gsub("[^ \t]", " ") M.highlight_wrap(list_pos, row, col, #line, whitespace_line) vim.defer_fn(function() -- get the first char local char = #list_pos == 1 and config.end_key or M.getchar_handler() vim.api.nvim_buf_clear_namespace(0, M.ns_fast_wrap, row, row + 1) for _, pos in pairs(list_pos) do -- handle end_key specially if char == config.end_key and char == pos.key then vim.print("Run to end!") -- M.highlight_wrap({pos = pos.pos, key = config.end_key}, row, col, #line, whitespace_line) local move_end_key = (not config.avoid_move_to_end and char == string.upper(config.end_key)) M.move_bracket(line, pos.col+1, end_pair, move_end_key) break end local hl_mark = { { pos = pos.pos - 1, key = config.before_key }, { pos = pos.pos + 1, key = config.after_key }, } if config.manual_position and (char == pos.key or char == string.upper(pos.key)) then M.highlight_wrap(hl_mark, row, col, #line, whitespace_line) M.choose_pos(row, line, pos, end_pair) break end if char == pos.key then M.move_bracket(line, pos.col, end_pair, false) break end if char == string.upper(pos.key) then M.move_bracket(line, pos.col, end_pair, true) break end end vim.cmd('startinsert') end, 10) return end vim.cmd('startinsert') end M.choose_pos = function(row, line, pos, end_pair) vim.defer_fn(function() -- select a second key local char = pos.char == nil and config.before_key or pos.char == config.end_key and config.after_key or M.getchar_handler() vim.api.nvim_buf_clear_namespace(0, M.ns_fast_wrap, row, row + 1) if not char then return end local change_pos = false local col = pos.col if char == string.upper(config.before_key) or char == string.upper(config.after_key) then change_pos = true end if char == config.after_key or char == string.upper(config.after_key) then col = pos.col + 1 end M.move_bracket(line, col, end_pair, change_pos) vim.cmd('startinsert') end, 10) end M.move_bracket = function(line, target_pos, end_pair, change_pos) log.debug(target_pos) line = line or utils.text_get_current_line(0) local row, col = utils.get_cursor() local _, next_char = utils.text_cusor_line(line, col, 1, 1, false) -- remove an autopairs if that exist if next_char == end_pair then line = line:sub(1, col) .. line:sub(col + 2, #line) target_pos = target_pos - 1 end line = line:sub(1, target_pos) .. end_pair .. line:sub(target_pos + 1, #line) vim.api.nvim_set_current_line(line) if change_pos then vim.api.nvim_win_set_cursor(0, { row + 1, target_pos + (config.cursor_pos_before and 0 or 1) }) end end M.highlight_wrap = function(tbl_pos, row, col, end_col, whitespace_line) local bufnr = vim.api.nvim_win_get_buf(0) if config.use_virt_lines then local virt_lines = {} local start = 0 local left_col = vim.fn.winsaveview().leftcol if left_col > 0 then vim.fn.winrestview({ leftcol = 0 }) end for _, pos in ipairs(tbl_pos) do virt_lines[#virt_lines + 1] = { whitespace_line:sub(start + 1, pos.pos - 1), 'Normal' } virt_lines[#virt_lines + 1] = { pos.key, config.highlight } start = pos.pos end vim.api.nvim_buf_set_extmark(bufnr, M.ns_fast_wrap, row, 0, { virt_lines = { virt_lines }, hl_mode = 'blend', }) else if config.highlight_grey then (vim.hl or vim.highlight).range( bufnr, M.ns_fast_wrap, config.highlight_grey, { row, col }, { row, end_col }, {} ) end for _, pos in ipairs(tbl_pos) do vim.api.nvim_buf_set_extmark(bufnr, M.ns_fast_wrap, row, pos.pos - 1, { virt_text = { { pos.key, config.highlight } }, virt_text_pos = 'overlay', hl_mode = 'blend', }) end end end return M windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/rule.lua000066400000000000000000000134261503062622400234640ustar00rootroot00000000000000local Cond = require('nvim-autopairs.conds') --- @class Rule --- @field start_pair string --- @field end_pair string --- @field end_pair_func function dynamic change end_pair --- @field map_cr_func function dynamic change mapping_cr --- @field end_pair_length number change end_pair length for key map like --- @field key_map string|nil equal nil mean it will skip on autopairs map --- @field filetypes table|nil --- @field not_filetypes table|nil --- @field is_regex boolean use regex to compare --- @field is_multibyte boolean --- @field is_endwise boolean only use on end_wise --- @field is_undo boolean add break undo sequence local Rule = setmetatable({}, { __call = function(self, ...) return self.new(...) end, }) ---@return Rule function Rule.new(...) local params = { ... } local opt = {} if type(params[1]) == 'table' then opt = params[1] else opt.start_pair = params[1] opt.end_pair = params[2] if type(params[3]) == 'string' then opt.filetypes = { params[3] } else opt.filetypes = params[3] end end opt = vim.tbl_extend('force', { key_map = "", start_pair = nil, end_pair = nil, end_pair_func = false, filetypes = nil, not_filetypes = nil, move_cond = nil, del_cond = {}, cr_cond = {}, pair_cond = {}, is_endwise = false, is_regex = false, is_multibyte = false, end_pair_length = nil, }, opt) or {} ---@param rule Rule local function constructor(rule) -- check multibyte if #rule.start_pair ~= vim.api.nvim_strwidth(rule.start_pair) then rule:use_multibyte() end -- check filetypes and not_filetypes -- if have something like "-vim" it will add to not_filetypes if rule.filetypes then local ft, not_ft = {}, {} for _, value in pairs(rule.filetypes) do if value:sub(1, 1) == '-' then table.insert(not_ft, value:sub(2, #value)) else table.insert(ft, value) end end rule.filetypes = #ft > 0 and ft or nil rule.not_filetypes = #not_ft > 0 and not_ft or nil end return rule end local r = setmetatable(opt, { __index = Rule }) return constructor(r) end function Rule:use_regex(value, key_map) self.is_regex = value self.key_map = key_map or '' return self end function Rule:use_key(key_map) self.key_map = key_map or '' return self end function Rule:use_undo(value) self.is_undo = value return self end function Rule:use_multibyte() self.is_multibyte = true self.end_pair_length = vim.fn.strdisplaywidth(self.end_pair) self.key_map = string.match(self.start_pair, "[^\128-\191][\128-\191]*$") self.key_end = string.match(self.end_pair, "[%z\1-\127\194-\244][\128-\191]*") return self end function Rule:get_end_pair(opts) if self.end_pair_func then return self.end_pair_func(opts) end return self.end_pair end function Rule:get_map_cr(opts) if self.map_cr_func then return self.map_cr_func(opts) end return 'unormal! ====' end function Rule:replace_map_cr(value) self.map_cr_func = value return self end function Rule:get_end_pair_length(opts) if self.end_pair_length then return self.end_pair_length end if type(opts) == 'string' then return #opts end return #self.get_end_pair(opts) end function Rule:replace_endpair(value, check_pair) self.end_pair_func = value if check_pair ~= nil then if check_pair == true then self:with_pair(Cond.after_text(self.end_pair)) else self:with_pair(check_pair) end end return self end function Rule:set_end_pair_length(length) self.end_pair_length = length return self end function Rule:with_move(cond) if self.move_cond == nil then self.move_cond = {} end table.insert(self.move_cond, cond) return self end function Rule:with_del(cond) if self.del_cond == nil then self.del_cond = {} end table.insert(self.del_cond, cond) return self end function Rule:with_cr(cond) if self.cr_cond == nil then self.cr_cond = {} end table.insert(self.cr_cond, cond) return self end ---add condition to rule ---@param cond any ---@param pos number|nil = 1. It have higher priority to another condition ---@return Rule function Rule:with_pair(cond, pos) if self.pair_cond == nil then self.pair_cond = {} end if pos then table.insert(self.pair_cond, pos, cond) else table.insert(self.pair_cond, cond) end return self end function Rule:only_cr(cond) self.key_map = nil self.pair_cond = false self.move_cond = false self.del_cond = false if cond then return self:with_cr(cond) end return self end function Rule:end_wise(cond) self.is_endwise = true return self:only_cr(cond) end local function can_do(conds, opt) if type(conds) == 'table' then for _, cond in pairs(conds) do local result = cond(opt) if result ~= nil then return result end end return true elseif type(conds) == 'function' then return conds(opt) == true end return false end function Rule:can_pair(opt) return can_do(self.pair_cond, opt) end function Rule:can_move(opt) return can_do(self.move_cond, opt) end function Rule:can_del(opt) return can_do(self.del_cond, opt) end function Rule:can_cr(opt) return can_do(self.cr_cond, opt) end return Rule windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/rules/000077500000000000000000000000001503062622400231365ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/rules/basic.lua000066400000000000000000000064551503062622400247340ustar00rootroot00000000000000local Rule = require("nvim-autopairs.rule") local cond = require("nvim-autopairs.conds") local utils = require('nvim-autopairs.utils') local function quote_creator(opt) local quote = function(...) local move_func = opt.enable_moveright and cond.move_right or cond.none ---@type Rule local rule = Rule(...) :with_move(move_func()) :with_pair(cond.not_add_quote_inside_quote()) if #opt.ignored_next_char > 1 then rule:with_pair(cond.not_after_regex(opt.ignored_next_char)) end rule:use_undo(opt.break_undo) return rule end return quote end local function bracket_creator(opt) local quote = quote_creator(opt) local bracket = function(...) local rule = quote(...) if opt.enable_check_bracket_line == true then rule:with_pair(cond.is_bracket_line()) :with_move(cond.is_bracket_line_move()) end if opt.enable_bracket_in_quote then -- still add bracket if text is quote "|" and next_char have " rule:with_pair(cond.is_bracket_in_quote(), 1) end return rule end return bracket end local function setup(opt) local quote = quote_creator(opt) local bracket = bracket_creator(opt) local rules = { Rule("", { "html", "markdown" }):with_cr(cond.none()), Rule("```", "```", { "markdown", "vimwiki", "rmarkdown", "rmd", "pandoc", "quarto", "typst" }) :with_pair(cond.not_before_char('`', 3)), Rule("```.*$", "```", { "markdown", "vimwiki", "rmarkdown", "rmd", "pandoc", "quarto", "typst" }):only_cr():use_regex(true), Rule('"""', '"""', { "python", "elixir", "julia", "kotlin", "scala","sbt" }):with_pair(cond.not_before_char('"', 3)), Rule("'''", "'''", { "python" }):with_pair(cond.not_before_char("'", 3)), quote("'", "'", { "-rust", "-nix" }) :with_pair(function(opts) -- python literals string local str = utils.text_sub_char(opts.line, opts.col - 1, 1) if vim.bo.filetype == 'python' and str:match("[frbuFRBU]") then return true end end) :with_pair(cond.not_before_regex("%w")), quote("'", "'", "rust"):with_pair(cond.not_before_regex("[%w<&]")):with_pair(cond.not_after_text(">")), Rule("''", "''", 'nix'):with_move(cond.after_text("'")), quote("`", "`"), quote('"', '"', "-vim"), quote('"', '"', "vim"):with_pair(cond.not_before_regex("^%s*$", -1)), bracket("(", ")"), bracket("[", "]"), bracket("{", "}"), Rule( ">[%w%s]*$", "^%s*$', 'end', 'elixir', nil), } return rules windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/rules/endwise-lua.lua000066400000000000000000000003701503062622400260560ustar00rootroot00000000000000local endwise = require('nvim-autopairs.ts-rule').endwise local rules = { endwise('then$', 'end', 'lua', 'if_statement'), endwise('function.*%(.*%)$', 'end', 'lua', {'function_declaration', 'local_function', 'function'}), } return rules windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/rules/endwise-ruby.lua000066400000000000000000000017131503062622400262600ustar00rootroot00000000000000local endwise = require('nvim-autopairs.ts-rule').endwise local rules = { endwise('%sdo$', 'end', 'ruby', nil), endwise('%sdo%s|.*|$', 'end', 'ruby', nil), endwise('begin$', 'end', 'ruby', nil), endwise('def%s.+$', 'end', 'ruby', nil), endwise('module%s.+$', 'end', 'ruby', nil), endwise('class%s.+$', 'end', 'ruby', nil), endwise('[%s=]%sif%s.+$', 'end', 'ruby', nil), endwise('[%s=]%sunless%s.+$', 'end', 'ruby', nil), endwise('[%s=]%scase%s.+$', 'end', 'ruby', nil), endwise('[%s=]%swhile%s.+$', 'end', 'ruby', nil), endwise('[%s=]%suntil%s.+$', 'end', 'ruby', nil), endwise('^if%s.+$', 'end', 'ruby', nil), endwise('^unless%s.+$', 'end', 'ruby', nil), endwise('^case%s.+$', 'end', 'ruby', nil), endwise('^while%s.+$', 'end', 'ruby', nil), endwise('^until%s.+$', 'end', 'ruby', nil), } return rules windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/rules/ts_basic.lua000066400000000000000000000010271503062622400254300ustar00rootroot00000000000000local basic = require('nvim-autopairs.rules.basic') local utils = require('nvim-autopairs.utils') local ts_conds = require('nvim-autopairs.ts-conds') local ts_extend = { "'", '"', '(', '[', '{', '`', } return { setup = function (config) local rules=basic.setup(config) for _, rule in pairs(rules) do if utils.is_in_table(ts_extend, rule.start_pair) then rule:with_pair(ts_conds.is_not_ts_node_comment()) end end return rules end } windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/ts-conds.lua000066400000000000000000000126771503062622400242560ustar00rootroot00000000000000local log = require('nvim-autopairs._log') local utils = require('nvim-autopairs.utils') local ts_get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text local conds = {} conds.is_endwise_node = function(nodes) if nodes == nil then return function() return true end end if type(nodes) == 'string' then nodes = {nodes} end return function (opts) log.debug('is_endwise_node') if not opts.check_endwise_ts then return true end if nodes == nil then return true end if #nodes == 0 then return true end vim.treesitter.get_parser():parse() local target = vim.treesitter.get_node({ ignore_injections = false }) if target ~= nil and utils.is_in_table(nodes, target:type()) then local text = ts_get_node_text(target) or {""} local last = text[#text]:match(opts.rule.end_pair) -- check last character is match with end_pair if last == nil then return true end -- log.debug('last:' .. last) -- if match then we need tocheck parent node -- some time treesiter is group 2 node then we need check that local begin_target,_, end_target = target:range() local begin_parent,_, end_parent = target:parent():range() -- log.debug(target:range()) -- log.debug(ts_get_node_text(target)) -- log.debug(target:parent():range()) -- log.debug(ts_get_node_text(target:parent())) if ( begin_target ~= begin_parent and end_target == end_parent ) or (end_parent - end_target == 1) then return true end -- return true else end return false end end conds.is_in_range = function(callback, position) assert( type(callback) == 'function' and type(position) == 'function', 'callback and position should be a function' ) return function(opts) log.debug('is_in_range') -- `parser` will be a table (on success) or a string (error message) local _, parser = pcall(vim.treesitter.get_parser) if not type(parser) == 'string' then return end local cursor = position() assert( type(cursor) == 'table' and #cursor == 2, 'position should be return a table like {line, col}' ) local line = cursor[1] local col = cursor[2] local bufnr = 0 local root_lang_tree = vim.treesitter.get_parser(bufnr) local lang_tree = root_lang_tree:language_for_range({ line, col, line, col }) local result for _, tree in ipairs(lang_tree:trees()) do local root = tree:root() if root and vim.treesitter.is_in_node_range(root, line, col) then local node = root:named_descendant_for_range(line, col, line, col) local anonymous_node = root:descendant_for_range( line, col, line, col ) result = { node = node, lang = lang_tree:lang(), type = node:type(), cursor = vim.api.nvim_win_get_cursor(0), line = vim.api.nvim_buf_get_lines(bufnr, line, line + 1, true)[1], range = { node:range() }, anonymous = anonymous_node:type(), } end end return callback(result) end end conds.is_ts_node = function(nodes) if type(nodes) == 'string' then nodes = {nodes} end assert(nodes ~= nil, "ts nodes should be string or table") return function (opts) log.debug('is_ts_node') if #nodes == 0 then return end vim.treesitter.get_parser():parse() local target = vim.treesitter.get_node({ ignore_injections = false }) if target ~= nil and utils.is_in_table(nodes, target:type()) then return true end return false end end conds.is_not_ts_node = function(nodes) if type(nodes) == 'string' then nodes = {nodes} end assert(nodes ~= nil, "ts nodes should be string or table") return function (opts) log.debug('is_not_ts_node') if #nodes == 0 then return end vim.treesitter.get_parser():parse() local target = vim.treesitter.get_node({ ignore_injections = false }) if target ~= nil and utils.is_in_table(nodes, target:type()) then return false end end end conds.is_not_ts_node_comment = function() return function(opts) log.debug('not_in_ts_node_comment') if not opts.ts_node then return end vim.treesitter.get_parser():parse() local target = vim.treesitter.get_node({ ignore_injections = false }) if target ~= nil and utils.is_in_table(opts.ts_node, target:type()) then return false end end end conds.is_not_in_context = function() return function(opts) local context = require("nvim-autopairs.ts-utils") .get_language_tree_at_position({ utils.get_cursor() }) if not vim.tbl_contains(opts.rule.filetypes, context:lang()) then return false end end end return conds windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/ts-rule.lua000066400000000000000000000007661503062622400241130ustar00rootroot00000000000000local Rule = require('nvim-autopairs.rule') local cond = require('nvim-autopairs.conds') local ts_conds = require('nvim-autopairs.ts-conds') return { endwise = function (...) local params = {...} local rule = Rule(...) :use_regex(true) :end_wise(cond.is_end_line()) if params[4] then -- rule:with_cr(ts_conds.is_endwise_node(params[4])) rule:with_cr(ts_conds.is_ts_node(params[4])) end return rule end } windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/ts-utils.lua000066400000000000000000000015361503062622400243000ustar00rootroot00000000000000local ts_get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text local M = {} local flatten = (function() if vim.fn.has "nvim-0.11" == 1 then return function(t) return vim.iter(t):flatten():totable() end else return function(t) return vim.tbl_flatten(t) end end end)() --- Returns the language tree at the given position. ---@return LanguageTree function M.get_language_tree_at_position(position) local language_tree = vim.treesitter.get_parser() language_tree:for_each_tree(function(_, tree) if tree:contains(flatten({ position, position })) then language_tree = tree end end) return language_tree end function M.get_tag_name(node) local tag_name = nil if node ~=nil then tag_name = ts_get_node_text(node) end return tag_name end return M windwp-nvim-autopairs-23320e7/lua/nvim-autopairs/utils.lua000066400000000000000000000122231503062622400236470ustar00rootroot00000000000000local M = {} local api = vim.api local log = require('nvim-autopairs._log') M.key = { del = "", bs = "", c_h = "", left = "", right = "", join_left = "U", join_right = "U", undo_sequence = "u", noundo_sequence = "U", abbr = "" } M.set_vchar = function(text) text = text:gsub('"', '\\"') vim.v.char = text end M.is_quote = function(char) return char == "'" or char == '"' or char == '`' end M.is_bracket = function(char) return char == "(" or char == '[' or char == '{' or char == '<' end M.is_close_bracket = function(char) return char == ")" or char == ']' or char == '}' or char == '>' end M.compare = function(value, text, is_regex) if is_regex and string.match(text, value) then return true elseif text == value then return true end return false end ---check cursor is inside a quote ---@param line string ---@param pos number position in line ---@param quote_type nil|string specify a quote ---@return boolean M.is_in_quotes = function(line, pos, quote_type) local cIndex = 0 local result = false local last_char = quote_type or '' while cIndex < string.len(line) and cIndex < pos do cIndex = cIndex + 1 local char = line:sub(cIndex, cIndex) local prev_char = line:sub(cIndex - 1, cIndex - 1) if result == true and char == last_char and prev_char ~= "\\" then result = false last_char = quote_type or '' elseif result == false and M.is_quote(char) and (not quote_type or char == quote_type) --a single quote with a word before is not count unless it is a -- prefixed string in python (e.g. f'string {with_brackets}') and not ( char == "'" and prev_char:match('%w') and (vim.bo.filetype ~= 'python' or prev_char:match('[^frbuFRBU]')) ) then last_char = quote_type or char result = true end end return result end M.is_attached = function(bufnr) local _, check = pcall(api.nvim_buf_get_var, bufnr or 0, "nvim-autopairs") return check == 1 end M.set_attach = function(bufnr, value) api.nvim_buf_set_var(bufnr or 0, "nvim-autopairs", value) end M.is_in_table = function(tbl, val) if tbl == nil then return false end for _, value in pairs(tbl) do if val == value then return true end end return false end M.check_filetype = function(tbl, filetype) if tbl == nil then return true end return M.is_in_table(tbl, filetype) end M.check_not_filetype = function(tbl, filetype) if tbl == nil then return true end return not M.is_in_table(tbl, filetype) end M.is_in_range = function(row, col, range) local start_row, start_col, end_row, end_col = unpack(range) return (row > start_row or (start_row == row and col >= start_col)) and (row < end_row or (row == end_row and col <= end_col)) end M.get_cursor = function(bufnr) local row, col = unpack(api.nvim_win_get_cursor(bufnr or 0)) return row - 1, col end M.text_get_line = function(bufnr, lnum) return api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, false)[1] or '' end M.text_get_current_line = function(bufnr) local row = unpack(api.nvim_win_get_cursor(0)) or 1 return M.text_get_line(bufnr, row - 1) end M.repeat_key = function(key, num) local text = '' for _ = 1, num, 1 do text = text .. key end return text end --- cut text from position with number character ---@param line string text ---@param col number position of text ---@param prev_count number number char previous ---@param next_count number number char next ---@param is_regex boolean if it is regex then will cut all M.text_cusor_line = function(line, col, prev_count, next_count, is_regex) if is_regex then prev_count = col next_count = #line - col end local prev = M.text_sub_char(line, col, -prev_count) local next = M.text_sub_char(line, col + 1, next_count) return prev, next end M.text_sub_char = function(line, start, num) local finish = start if num < 0 then start = start + num + 1 else finish = start + num - 1 end if start + finish < 0 then return "" end return string.sub(line, start, finish) end -- P(M.text_sub_char("aa'' aaa", 3, -1)) M.insert_char = function(text) api.nvim_put({ text }, "c", false, true) end M.feed = function(text, num) num = num or 1 if num < 1 then num = 1 end local result = '' for _ = 1, num, 1 do result = result .. text end log.debug("result" .. result) api.nvim_feedkeys(api.nvim_replace_termcodes( result, true, false, true), "n", true) end M.esc = function(cmd) return vim.api.nvim_replace_termcodes(cmd, true, false, true) end M.is_block_wise_mode = function() return vim.fn.visualmode() == '' end --- get prev_char with out key_map M.get_prev_char = function(opt) return opt.line:sub(opt.col - 1, opt.col + #opt.rule.start_pair - 2) end return M windwp-nvim-autopairs-23320e7/style.toml000066400000000000000000000001331503062622400202770ustar00rootroot00000000000000column_width = 85 indent_type = "Spaces" quote_style = "AutoPreferSingle" indent_width = 4 windwp-nvim-autopairs-23320e7/tests/000077500000000000000000000000001503062622400174075ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/tests/afterquote_spec.lua000066400000000000000000000050751503062622400233120ustar00rootroot00000000000000local npairs = require('nvim-autopairs') _G.npairs = npairs npairs.setup({ enable_afterquote = true, }) local data = { { name = 'add bracket after quote ', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[const abc=|"test" ]], after = [[const abc=(|"test") ]], }, { name = 'add bracket after quote ', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[|"test"]], after = [[(|"test")]], }, { name = 'check quote without any text on end similar', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[ const [template, setTemplate] = useState|'')]], after = [[ const [template, setTemplate] = useState(|'')]], }, { name = 'add bracket after quote ', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[{]], before = [[(|"test") ]], after = [[({|"test"}) ]], }, { name = 'add bracket after quote ', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[const abc=|"visu\"dsa" ]], after = [[const abc=(|"visu\"dsa") ]], }, { name = 'not add on exist quote', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[const abc=|"visu\"dsa") ]], after = [[const abc=(|"visu\"dsa") ]], }, { name = 'test add close quote on match', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[const abc=|"visu\"dsa" ]], after = [[const abc=(|"visu\"dsa") ]], }, { name = 'not add bracket with quote have comma', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[|"data", abcdef]], after = [[(|"data", abcdef]], }, { name = 'not add bracket with quote have comma', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[(]], before = [[|"data", "abcdef"]], after = { [[(|"data", "abcdef"]] }, }, } local run_data = _G.Test_filter(data) describe('[afterquote tag]', function() _G.Test_withfile(run_data, {}) end) windwp-nvim-autopairs-23320e7/tests/endwise/000077500000000000000000000000001503062622400210455ustar00rootroot00000000000000windwp-nvim-autopairs-23320e7/tests/endwise/init.lua000066400000000000000000000001421503062622400225100ustar00rootroot00000000000000local data1, data2 local function wind() vim.api.nvim_get_current_buf() end windwp-nvim-autopairs-23320e7/tests/endwise/javascript.js000066400000000000000000000000221503062622400235430ustar00rootroot00000000000000 windwp-nvim-autopairs-23320e7/tests/endwise/main.rs000066400000000000000000000000331503062622400223330ustar00rootroot00000000000000fn main() { } windwp-nvim-autopairs-23320e7/tests/endwise/ruby.rb000066400000000000000000000000331503062622400223470ustar00rootroot00000000000000module MyFirstModule end windwp-nvim-autopairs-23320e7/tests/endwise/sample.lua000066400000000000000000000002701503062622400230300ustar00rootroot00000000000000local M={} M.autopairs_bs = function(rules) for _, rule in pairs(rules) do if rule.start_pair then end if rule.start_pair then end end end return M windwp-nvim-autopairs-23320e7/tests/endwise/sample.md000066400000000000000000000001041503062622400226430ustar00rootroot00000000000000# Example Markdown File ```javascript let; let; let; let; let; ``` windwp-nvim-autopairs-23320e7/tests/endwise_spec.lua000066400000000000000000000037261503062622400225720ustar00rootroot00000000000000local npairs = require('nvim-autopairs') local ts = require('nvim-treesitter.configs') local log = require('nvim-autopairs._log') ts.setup({ ensure_installed = { 'lua' }, highlight = { enable = true }, }) _G.npairs = npairs vim.api.nvim_set_keymap( 'i', '', 'v:lua.npairs.autopairs_cr()', { expr = true, noremap = true } ) local data = { { name = 'lua function add endwise', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[]], before = [[function a()| ]], after = { [[function a() ]], [[| ]], [[ end ]], }, }, { name = 'lua function add endwise', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[]], before = [[function a()|x ab ]], after = { [[function a() ]], [[|x ab]], }, }, { name = 'add if endwise', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[]], before = [[if data== 'fdsafdsa' then| ]], after = { [[if data== 'fdsafdsa' then ]], [[|]], [[end ]], }, }, { name = 'undo on key', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[{u]], before = [[local abc = | ]], after = { [[local abc = {|} ]], [[]], [[]], }, }, } local run_data = _G.Test_filter(data) describe('[endwise tag]', function() _G.Test_withfile(run_data, { -- need to understand this ??? new line make change cursor zzz cursor_add = 1, before_each = function(value) npairs.add_rules( require('nvim-autopairs.rules.endwise-' .. value.filetype) ) end, }) end) windwp-nvim-autopairs-23320e7/tests/fastwrap_spec.lua000066400000000000000000000030101503062622400227450ustar00rootroot00000000000000-- local npairs = require('nvim-autopairs') -- _G.npairs = npairs -- npairs.setup({ -- enable_afterquote = true, -- fast_wrap = true, -- }) -- local data = { -- { -- only = true, -- name = 'move end wise after quote ', -- filepath = './tests/endwise/init.lua', -- filetype = 'lua', -- linenr = 5, -- key = [[]], -- before = [[const abc=(|"test",data ]], -- after = [[const abc=(|"test"),data ]], -- }, -- { -- name = 'move end wise after quote ', -- filepath = './tests/endwise/init.lua', -- filetype = 'lua', -- linenr = 5, -- key = [[]], -- before = [[const abc=(|"test"),data ]], -- after = [[const abc=(|"test",data) ]], -- }, -- { -- name = 'move end wise after quote ', -- filepath = './tests/endwise/init.lua', -- filetype = 'lua', -- linenr = 5, -- key = [[]], -- before = [[const abc=(|"test",data),dadas ]], -- after = [[const abc=(|"test",data,dadas) ]], -- }, -- { -- name = 'move end wise after quote ', -- filepath = './tests/endwise/init.lua', -- filetype = 'lua', -- linenr = 5, -- key = [[]], -- before = [[Plug {(|'dsfdsa',) on = 'aaa'} ]], -- after = [[Plug {('dsfdsa', on = 'aaa')} ]], -- }, -- } -- local run_data = _G.Test_filter(data) -- describe('[endwise tag]', function() -- _G.Test_withfile(run_data, {}) -- end) windwp-nvim-autopairs-23320e7/tests/minimal.vim000066400000000000000000000011351503062622400215520ustar00rootroot00000000000000set rtp +=. set rtp +=../plenary.nvim/ set rtp +=../nvim-treesitter set rtp +=../playground/ lua _G.__is_log = true lua vim.fn.setenv("DEBUG_PLENARY", true) runtime! plugin/plenary.vim runtime! plugin/nvim-treesitter.vim runtime! plugin/playground.vim runtime! plugin/nvim-autopairs.vim set noswapfile set nobackup filetype indent off set expandtab set shiftwidth=4 set nowritebackup set noautoindent set nocindent set nosmartindent set indentexpr= lua << EOF require("plenary/busted") require("nvim-treesitter").setup() vim.cmd[[luafile ./tests/test_utils.lua]] require("nvim-autopairs").setup() EOF windwp-nvim-autopairs-23320e7/tests/nvim-autopairs_spec.lua000066400000000000000000000567541503062622400241230ustar00rootroot00000000000000local npairs = require('nvim-autopairs') local Rule = require('nvim-autopairs.rule') local cond = require('nvim-autopairs.conds') local log = require('nvim-autopairs._log') _G.log = log local utils = require('nvim-autopairs.utils') _G.npairs = npairs; -- make test-file FILE=tests/nvim-autopairs_spec.lua -- use only = true to test 1 case -- stylua: ignore local data = { { -- only = true, name = "1 add normal bracket", key = [[{]], before = [[x| ]], after = [[x{|} ]] }, { name = "2 add bracket inside bracket", key = [[{]], before = [[{|} ]], after = [[{{|}} ]] }, { name = "3 test single quote ", filetype = "lua", key = "'", before = [[data,|) ]], after = [[data,'|') ]] }, { name = "4 add normal bracket", key = [[(]], before = [[aaaa| x ]], after = [[aaaa(|) x ]] }, { name = "5 add normal quote", key = [["]], before = [[aa| aa]], after = [[aa"|" aa]] }, { name = "6 add python quote", filetype = "python", key = [["]], before = [[""| ]], after = [["""|""" ]] }, { name = "7 don't repeat python quote", filetype = "python", key = [["]], before = [[a"""|""" ]], after = [[a""""|"" ]] }, { name = "8 add markdown quote", filetype = "markdown", key = [[`]], before = [[``| ]], after = [[```|``` ]] }, { name = "9 don't add single quote with previous alphabet char", key = [[']], before = [[aa| aa ]], after = [[aa'| aa ]] }, { name = "10 don't add single quote with alphabet char", key = [[']], before = [[a|x ]], after = [[a'|x ]] }, { name = "11 don't add single quote on end line", key = [[']], before = [[c aa|]], after = [[c aa'|]] }, { name = "12 don't add quote after alphabet char", key = [["]], before = [[aa |aa]], after = [[aa "|aa]] }, { name = "13 don't add quote inside quote", key = [["]], before = [["aa | aa]], after = [["aa "| aa]] }, { name = "14 add quote if not inside quote", key = [["]], before = [["aa " | aa]], after = [["aa " "|" aa]] }, { name = "15 don't add pair after alphabet char", key = [[(]], before = [[aa |aa]], after = [[aa (|aa]] }, { name = "16 don't add pair after dot char", key = [[(]], before = [[aa |.aa]], after = [[aa (|.aa]] }, { name = "17 don't add bracket have open bracket in same line", key = [[(]], before = [[( many char |))]], after = [[( many char (|))]] }, { filetype = 'vim', name = "18 add bracket inside quote when nextchar is ignore", key = [[{]], before = [["|"]], after = [["{|}"]] }, { filetype = '', name = "19 add bracket inside quote when next char is ignore", key = [[{]], before = [[" |"]], after = [[" {|}"]] }, { name = "20 move right on quote line ", key = [["]], before = [["|"]], after = [[""|]] }, { name = "21 move right end line ", key = [["]], before = [[aaaa|"]], after = [[aaaa"|]] }, { name = "22 move right when inside quote", key = [["]], before = [[("abcd|")]], after = [[("abcd"|)]] }, { name = "23 move right when inside quote", key = [["]], before = [[foo("|")]], after = [[foo(""|)]] }, { name = "24 move right square bracket", key = [[)]], before = [[("abcd|) ]], after = [[("abcd)| ]] }, { name = "25 move right bracket", key = [[}]], before = [[("abcd|}} ]], after = [[("abcd}|} ]] }, { -- ref: issue #331 name = "26 move right, should not move on non-end-pair char: `§|§` with (", setup_func = function() npairs.add_rule(Rule("§", "§"):with_move(cond.done())) end, key = [[(]], before = [[§|§]], after = [[§(|)§]] }, { -- ref: issue #331 name = "27 move right, should not move on non-end-pair char: `#|#` with \"", setup_func = function() npairs.add_rule(Rule("#", "#"):with_move(cond.done())) end, key = [["]], before = [[#|#]], after = [[#"|"#]] }, { -- ref: issue #331 and #330 name = "28 move right, should not move on non-end-pair char: `<|>` with (", setup_func = function() npairs.add_rule(Rule("<", ">"):with_move(cond.done())) end, key = [[(]], before = [[<|>]], after = [[<(|)>]], }, { name = "29 move right when inside grave with special slash", key = [[`]], before = [[(`abcd\"|`)]], after = [[(`abcd\"`|)]] }, { name = "30 move right when inside quote with special slash", key = [["]], before = [[("abcd\"|")]], after = [[("abcd\""|)]] }, { filetype = 'rust', name = "31 move right double quote after single quote", key = [["]], before = [[ ('x').expect("|");]], after = [[ ('x').expect(""|);]], }, { filetype = 'rust', name = "32 move right, should not move when bracket not closing", key = [[}]], before = [[{{ |} ]], after = [[{{ }|} ]] }, { filetype = 'rust', name = "33 move right, should move when bracket closing", key = [[}]], before = [[{ }|} ]], after = [[{ }}| ]] }, { name = "34 delete bracket", filetype = "javascript", key = [[]], before = [[aaa(|) ]], after = [[aaa| ]] }, { name = "35 breakline on {", filetype = "javascript", key = [[]], before = [[a{|}]], after = { "a{", "|", "}" } }, { setup_func = function() vim.opt.indentexpr = "nvim_treesitter#indent()" end, name = "36 breakline on (", filetype = "javascript", key = [[]], before = [[function ab(|)]], after = { "function ab(", "|", ")" } }, { name = "37 breakline on ]", filetype = "javascript", key = [[]], before = [[a[|] ]], after = { "a[", "|", "]" } }, { name = "38 move ) inside nested function call", filetype = "javascript", key = [[)]], before = { "fn(fn(|))", }, after = { "fn(fn()|)", } }, { name = "39 move } inside singleline function's params", filetype = "javascript", key = [[}]], before = { "({|}) => {}", }, after = { "({}|) => {}", } }, { name = "40 move } inside multiline function's params", filetype = "javascript", key = [[}]], before = { "({|}) => {", "", "}", }, after = { "({}|) => {", "", "}", } }, { name = "41 breakline on markdown ", filetype = "markdown", key = [[]], before = [[``` lua|```]], after = { [[``` lua]], [[|]], [[```]] } }, { name = "42 breakline on < html", filetype = "html", key = [[]], before = [[
|
]], after = { [[
]], [[|]], [[
]] } }, { name = "43 breakline on < html with text", filetype = "html", key = [[]], before = [[
ads |
]], after = { [[
ads]], [[|]], [[
]] }, }, { name = "44 breakline on < html with space after cursor", filetype = "html", key = [[]], before = [[
ads |
]], after = { [[
ads]], [[|]], [[
]] }, }, { name = "45 do not mapping on > html", filetype = "html", key = [[>]], before = [[| ]] }, { name = "46 press multiple key", filetype = "html", key = [[((((]], before = [[a| ]], after = [[a((((|)))) ]] }, { setup_func = function() npairs.add_rules({ Rule('u%d%d%d%d$', 'number', 'lua'):use_regex(true), }) end, name = "47 text regex", filetype = "lua", key = "4", before = [[u123| ]], after = [[u1234|number ]] }, { setup_func = function() npairs.add_rules({ Rule('x%d%d%d%d$', 'number', 'lua'):use_regex(true):replace_endpair(function(opts) return opts.prev_char:sub(#opts.prev_char - 3, #opts.prev_char) end), }) end, name = "48 text regex with custom end_pair", filetype = "lua", key = "4", before = [[x123| ]], after = [[x1234|1234 ]] }, { setup_func = function() npairs.add_rules({ Rule('b%d%d%d%d%w$', '', 'vim'):use_regex(true, ''):replace_endpair(function(opts) return opts.prev_char:sub(#opts.prev_char - 4, #opts.prev_char) .. 'viwUi' end), }) end, name = "49 text regex with custom key", filetype = "vim", key = "", before = [[b1234s| ]], after = [[B|1234S1234S ]] }, { setup_func = function() npairs.add_rules({ Rule('b%d%d%d%d%w$', '', 'vim'):use_regex(true, ''):replace_endpair(function(opts) return opts.prev_char:sub(#opts.prev_char - 4, #opts.prev_char) .. 'viwUi' end), }) end, name = "50 test move right custom char", filetype = "vim", key = "", before = [[b1234s| ]], after = [[B|1234S1234S ]] }, { setup_func = function() npairs.add_rules({ Rule("-", "+", "vim") :with_move(function(opt) return utils.get_prev_char(opt) == "x" end) :with_move(cond.done()) }) end, name = "51 test move right custom char plus", filetype = "vim", key = "+", before = [[x|+ ]], after = [[x+| ]] }, { setup_func = function() npairs.add_rules({ Rule("/**", "**/", "javascript") :with_move(cond.none()) }) end, name = "52 test javascript comment", filetype = "javascript", key = "*", before = [[/*| ]], after = [[/**|**/ ]] }, { setup_func = function() npairs.add_rules({ Rule("(", ")") :use_key("") :replace_endpair(function() return "" end, true) }) end, name = "53 test map custom key", filetype = "latex", key = [[]], before = [[ abcde(|) ]], after = [[ abcde| ]], }, { setup_func = function() npairs.add_rules { Rule(' ', ' '):with_pair(function(opts) local pair = opts.line:sub(opts.col, opts.col + 1) return vim.tbl_contains({ '()', '[]', '{}' }, pair) end), Rule('( ', ' )') :with_pair(function() return false end) :with_del(function() return false end) :with_move(function() return true end) :use_regex(false, ")") } end, name = "54 test multiple move right", filetype = "latex", key = [[)]], before = [[( | ) ]], after = [[( )| ]], }, { setup_func = function() npairs.setup({ enable_check_bracket_line = false }) end, name = "55 test disable check bracket line", filetype = "latex", key = [[(]], before = [[(|))) ]], after = [[((|)))) ]], }, { setup_func = function() npairs.add_rules({ Rule("<", ">", { "rust" }) :with_pair(cond.before_text("Vec")) }) end, name = "56 test disable check bracket line", filetype = "rust", key = [[<]], before = [[Vec| ]], after = [[Vec<|> ]], }, { setup_func = function() npairs.add_rule(Rule("!", "!"):with_pair(cond.not_filetypes({ "lua" }))) end, name = "57 disable pairs in lua", filetype = "lua", key = "!", before = [[x| ]], after = [[x!| ]] }, { setup_func = function() npairs.clear_rules() npairs.add_rules({ Rule("%(.*%)%s*%=>", " { }", { "typescript", "typescriptreact", "javascript" }) :use_regex(true) :set_end_pair_length(2) }) end, name = "58 mapping regex with custom end_pair_length", filetype = "typescript", key = ">", before = [[(o)=| ]], after = [[(o)=> { | } ]] }, { setup_func = function() npairs.add_rules({ Rule('(', ')'):use_key(''):replace_endpair(function() return '' end, true), Rule('(', ')'):use_key(''):replace_endpair(function() return '' end, true), }) end, name = "59 mapping same pair with different key", filetype = "typescript", key = "(", before = [[(test|) ]], after = [[(test(|)) ]] }, { setup_func = function() npairs.clear_rules() npairs.add_rule(Rule("„", "”")) end, name = "60 multibyte character from custom keyboard", not_replace_term_code = true, key = "„", before = [[a | ]], after = [[a „|” ]], end_cursor = 3 }, { setup_func = function() npairs.clear_rules() npairs.add_rule(Rule("„", "”"):with_move(cond.done())) end, name = "61 multibyte character move_right", not_replace_term_code = true, key = "”", before = [[a „|”xx ]], after = [[a „”|xx ]], end_cursor = 6 }, { setup_func = function() npairs.clear_rules() npairs.add_rule(Rule("„", "”"):with_move(cond.done())) end, name = "62 multibyte character delete", key = "", before = [[a „|” ]], after = [[a | ]], }, { setup_func = function() npairs.clear_rules() npairs.add_rule(Rule("a„", "”b"):with_move(cond.done())) end, not_replace_term_code = true, name = "63 multibyte character and multiple ", key = "„", before = [[a| ]], after = [[a„|”b ]], end_cursor = 2 }, { setup_func = function() npairs.setup({ map_c_h = true }) end, name = "64 map ", key = "", before = [[aa'|' ]], after = [[aa| ]], }, { setup_func = function() npairs.setup({ map_c_w = true }) end, name = "65 map ", key = "", before = [[aa'|' ]], after = [[aa| ]], }, { setup_func = function() npairs.clear_rules() npairs.add_rule(Rule("x", "x", { '-vim', '-rust' })) end, filetype = 'vim', name = "66 disable filetype vim", key = [[x]], before = [[a | ]], after = [[a x| ]] }, { filetype = 'vim', name = "67 undo on quote", key = [[{123u]], end_cursor = 12, before = [[local abc=| ]], after = [[local abc={|} ]] }, { filetype = 'vim', name = "68 undo on bracket", key = [['123u]], end_cursor = 12, before = [[local abc=| ]], after = [[local abc='|' ]] }, { filetype = 'vim', name = "69 double quote on vim after char", key = [["ab]], before = [[echo | ]], after = [[echo "ab|" ]] }, { filetype = 'vim', name = "70 double quote on vim on begin", key = [["ab]], before = [[ | aaa]], after = [[ "ab| aaa]] }, { setup_func = function() npairs.add_rule( Rule('struct%s[a-zA-Z]+%s?{$', '};') :use_regex(true, "{") ) end, filetype = 'javascript', name = "71 custom endwise rule", key = [[{]], before = [[struct abc | ]], after = [[struct abc {|};]], }, { setup_func = function() npairs.clear_rules() npairs.add_rule(Rule("{", "}"):end_wise()) end, filetype = 'javascript', name = "72 custom endwise rule", key = [[]], before = [[function () {| ]], after = { [[function () {]], [[|]], [[}]], }, }, { setup_func = function() vim.opt.smartindent = true end, filetype = 'ps1', name = "73 indent on powershell", key = [[]], before = [[function () {|} ]], after = { [[function () {]], [[|]], [[}]], }, }, { setup_func = function() npairs.clear_rules() npairs.add_rule( Rule("{", "") :replace_endpair(function() return "}" end) :end_wise() ) end, filetype = 'javascript', name = "74 custom endwise rule with custom end_pair", key = [[]], before = [[function () {| ]], after = { [[function () {]], [[|]], [[}]], }, }, { name = "75 open bracker on back tick", key = [[(]], before = [[ |`abcd`]], after = [[ (`abcd`) ]] }, { name = "76 should not add bracket on line have bracket ", key = [[(]], before = [[ |(abcd))]], after = [[ ((abcd)) ]] }, { name = "77 not add bracket on line have bracket ", key = [[(]], before = [[ |(abcd) ( visual)]], after = [[ ()(abcd) ( visual)]] }, { name = "78 should add single quote when it have primes char", key = [[']], before = [[Ben's friends say: | ]], after = [[Ben's friends say: '|' ]] }, { name = "79 a quote with single quote string", key = "'", before = [[{{("It doesn't name %s", ''), 'ErrorMsg'| }}, ]], after = [[{{("It doesn't name %s", ''), 'ErrorMsg''|' }}, ]], end_cursor = 41 }, { name = "80 add normal quote with '", key = [["]], before = [[aa| 'aa]], after = [[aa"|" 'aa]] }, { name = "81 add closing single quote for python prefixed string", filetype = "python", key = [[']], before = [[print(f|)]], after = [[print(f'|')]] }, { name = "82 add closing single quote for capital python prefixed string", filetype = "python", key = [[']], before = [[print(B|)]], after = [[print(B'|')]] }, { name = "83 don't add closing single quote for random prefix string", filetype = "python", key = [[']], before = [[print(s|)]], after = [[print(s'|)]] }, { name = "84 don't add closing single quote for other filetype prefixed string", filetype = "lua", key = [[']], before = [[print(f|)]], after = [[print(f'|)]] }, { name = "85 allow brackets in prefixed python single quote string", filetype = "python", key = [[{]], before = [[print(f'|')]], after = [[print(f'{|}')]] }, { name = "86 move ' is working on python", filetype = "python", key = [[']], before = [[('|') ]], after = [[(''|) ]] }, { setup_func = function() npairs.add_rules({ Rule('123456', '789'):with_pair(cond.before_regex('^12345$', 5)), }) end, name = '87 test before_regex with a specific string length', key = [[123456]], before = [[ some text before| ]], after = [[ some text before123456|789 ]], }, { name = "88 disable on count mode", filetype = "txt", key = function() local keys = vim.api.nvim_replace_termcodes('2otest({', true, true, true) vim.api.nvim_feedkeys(keys, 'x', true) end, before = [[ | ]], after = { '', ' test({', } }, { name = "89 key on markdown", filetype = "markdown", key = [[]], before = [[|```python ]], after = { "", "|```python" } }, } local run_data = _G.Test_filter(data) describe("autopairs ", function() _G.Test_withfile(run_data, { cursor_add = 0, before_each = function(value) npairs.setup() vim.opt.indentexpr = "" if value.setup_func then value.setup_func() end end, }) end) windwp-nvim-autopairs-23320e7/tests/test_utils.lua000066400000000000000000000133261503062622400223160ustar00rootroot00000000000000local utils = require('nvim-autopairs.utils') local log = require('nvim-autopairs._log') local api = vim.api local ts_get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text local helpers = {} function helpers.feed(text, feed_opts, is_replace) feed_opts = feed_opts or 'n' if not is_replace then text = vim.api.nvim_replace_termcodes(text, true, false, true) end vim.api.nvim_feedkeys(text, feed_opts, true) end function helpers.insert(text, is_replace) helpers.feed('i' .. text, 'x', is_replace) end utils.insert_char = function(text) api.nvim_put({ text }, 'c', true, true) end utils.feed = function(text, num) local result = '' for _ = 1, num, 1 do result = result .. text end api.nvim_feedkeys( ---@diagnostic disable-next-line: param-type-mismatch api.nvim_replace_termcodes(result, true, false, true), 'x', true ) end _G.eq = assert.are.same _G.Test_filter = function(data) local run_data = {} for _, value in pairs(data) do if value.only == true then table.insert(run_data, value) break end end if #run_data == 0 then run_data = data end return run_data end local compare_text = function(linenr, text_after, name, cursor_add, end_cursor) cursor_add = cursor_add or 0 local new_text = vim.api.nvim_buf_get_lines( 0, linenr - 1, linenr + #text_after - 1, true ) for i = 1, #text_after, 1 do local t = string.gsub(text_after[i], '%|', '') if t and new_text[i] and t:gsub('%s+$', '') ~= new_text[i]:gsub('%s+$', '') then eq(t, new_text[i], '\n\n text error: ' .. name .. '\n') end local p_after = string.find(text_after[i], '%|') if p_after then local row, col = utils.get_cursor() if end_cursor then eq(row, linenr + i - 2, '\n\n cursor row error: ' .. name .. '\n') eq( col + 1, end_cursor, '\n\n end cursor column error : ' .. name .. '\n' ) else eq(row, linenr + i - 2, '\n\n cursor row error: ' .. name .. '\n') p_after = p_after + cursor_add eq( col, math.max(p_after - 2, 0), '\n\n cursor column error : ' .. name .. '\n' ) end end end return true end _G.Test_withfile = function(test_data, cb) for _, value in pairs(test_data) do it('test ' .. value.name, function(_) local text_before = {} value.linenr = value.linenr or 1 local pos_before = { linenr = value.linenr, colnr = 0, } if not vim.tbl_islist(value.before) then value.before = { value.before } end for index, text in pairs(value.before) do local txt = string.gsub(tostring(text), '%|', '') table.insert(text_before, txt) if string.match(tostring(text), '%|') then if string.find(tostring(text), '%|') then pos_before.colnr = string.find(tostring(text), '%|') pos_before.linenr = value.linenr + index - 1 end end end if not vim.tbl_islist(value.after) then value.after = { value.after } end vim.bo.filetype = value.filetype or 'text' vim.cmd(':bd!') if cb.before_each then cb.before_each(value) end ---@diagnostic disable-next-line: missing-parameter if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then vim.cmd(':e ' .. value.filepath) if value.filetype then vim.bo.filetype = value.filetype end vim.cmd(':e') else vim.cmd(':new') if value.filetype then vim.bo.filetype = value.filetype end end local status, parser = pcall(vim.treesitter.get_parser, 0) if status then parser:parse(true) end vim.api.nvim_buf_set_lines( 0, value.linenr - 1, value.linenr + #text_before, false, text_before ) vim.api.nvim_win_set_cursor( 0, { pos_before.linenr, pos_before.colnr - 1 } ) if type(value.key) == "function" then log.debug("call key") value.key() else log.debug('insert:' .. value.key) helpers.insert(value.key, value.not_replace_term_code) vim.wait(2) helpers.feed('') end compare_text( value.linenr, value.after, value.name, cb.cursor_add, value.end_cursor ) if cb.after_each then cb.after_each(value) end vim.cmd(':bd!') end) end end _G.dump_node = function(node) local text = ts_get_node_text(node) for _, txt in pairs(text) do print(txt) end end _G.dump_node_text = function(target) for node in target:iter_children() do local node_type = node:type() local text = ts_get_node_text(node) log.debug('type:' .. node_type .. ' ') log.debug(text) end end windwp-nvim-autopairs-23320e7/tests/treesitter_spec.lua000066400000000000000000000070721503062622400233240ustar00rootroot00000000000000local npairs = require('nvim-autopairs') local ts = require('nvim-treesitter.configs') local log = require('nvim-autopairs._log') local Rule = require('nvim-autopairs.rule') local ts_conds = require('nvim-autopairs.ts-conds') _G.npairs = npairs vim.api.nvim_set_keymap( 'i', '', 'v:lua.npairs.check_break_line_char()', { expr = true, noremap = true } ) ts.setup({ ensure_installed = { 'lua', 'javascript', 'rust', 'markdown', 'markdown_inline' }, highlight = { enable = true }, autopairs = { enable = true }, }) local data = { { name = 'treesitter lua quote', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [["]], before = { [[ [[ aaa| ]], [[ ]], ']]', }, after = [[ [[ aaa"| ]], }, { setup_func = function() npairs.add_rules({ Rule('%', '%', 'lua'):with_pair( ts_conds.is_ts_node({ 'string', 'comment', 'string_content' }) ), }) end, name = 'ts_conds is_ts_node quote', filepath = './tests/endwise/init.lua', filetype = 'lua', linenr = 5, key = [[%]], before = { [[ [[ abcde | ]], [[ ]], ']]', }, after = [[ [[ abcde %|% ]], }, { name = 'ts_conds is_ts_node failed', filepath = './tests/endwise/init.lua', linenr = 5, filetype = 'lua', key = '%', before = { [[local abcd| = ' visual ']] }, after = [[local abcd%| = ' visual ']], }, { setup_func = function() npairs.add_rules({ Rule('<', '>', 'rust'):with_pair(ts_conds.is_ts_node({ 'type_identifier', 'let_declaration', 'parameters', })), }) end, name = 'ts_conds is_ts_node failed', filepath = './tests/endwise/main.rs', linenr = 5, filetype = 'rust', key = '<', before = [[pub fn noop(_inp: Vec|) {]], after = [[pub fn noop(_inp: Vec<|>) {]], }, { setup_func = function() npairs.add_rules({ Rule('*', '*', { 'markdown', 'markdown_inline' }) :with_pair(ts_conds.is_not_in_context()), }) end, name = 'ts_context markdown `*` success md_context', filepath = './tests/endwise/sample.md', linenr = 2, filetype = 'markdown', key = '*', before = [[|]], after = [[*|*]], }, { setup_func = function() npairs.add_rules({ Rule('*', '*', { 'markdown', 'markdown_inline' }) :with_pair(ts_conds.is_not_in_context()), }) end, name = 'ts_context codeblock `*` fail js_context', filepath = './tests/endwise/sample.md', linenr = 6, filetype = 'markdown', key = '*', before = [[let calc = 1 |]], after = [[let calc = 1 *|]], }, } local run_data = _G.Test_filter(data) describe('[treesitter check]', function() _G.Test_withfile(run_data, { before_each = function(value) npairs.setup({ check_ts = true, ts_config = { javascript = { 'template_string', 'comment' }, }, }) if value.setup_func then value.setup_func() end end, }) end) windwp-nvim-autopairs-23320e7/tests/utils_spec.lua000066400000000000000000000023131503062622400222630ustar00rootroot00000000000000local utils = require('nvim-autopairs.utils') local log = require('nvim-autopairs._log') local eq = assert.are.same local data = { { text = "add normal bracket", start = 2, num = 2, result = 'dd' }, { text = "iood", start = 1, num = 2, result = 'io' }, { text = "add normal bracket", start = 0, num = -2, result = '' }, { text = "add normal bracket", start = 3, num = -2, result = 'dd' }, { text = [["""]], start = 3, num = -3, result = '"""' }, { text = [["""]], start = 3, num = 3, result = '"' }, { text = [["""]], start = 2, num = 2, result = '""' }, } describe('utils test substring ', function() for _, value in pairs(data) do it('test sub: ' .. value.text, function() local result = utils.text_sub_char(value.text, value.start, value.num) eq(value.result, result, 'start ' .. value.start .. ' num' .. value.num) end) end end) vim.wait(100)