on fa6876f help sign in
15 files changed+316−848
since splitsnapshots
unifiedsplit
.gitignore−1 README.md+7−63 doc/nvim-autopairs-rules.txt+64−306 doc/nvim-autopairs.txt+9−73 lua/nvim-autopairs.lua+111−94 lua/nvim-autopairs/_log.lua+8−8 lua/nvim-autopairs/completion/cmp.lua+41−58 lua/nvim-autopairs/completion/handlers.lua−52 lua/nvim-autopairs/conds.lua+14−77 lua/nvim-autopairs/fastwrap.lua+19−10 lua/nvim-autopairs/rule.lua+29−23 lua/nvim-autopairs/rules/basic.lua+4−10 lua/nvim-autopairs/utils.lua+2−3 tests/nvim-autopairs_spec.lua+1−62 tests/test_utils.lua+7−8
.gitignoredeleted−1
@@ -1 +0,0 @@
1−doc/tags
README.md+7−63
@@ -2,7 +2,7 @@
22
33A super powerful autopair plugin for Neovim that supports multiple characters.
44
5−Requires neovim 0.7
5+Requires neovim 0.5+
66
77## Installation
88
@@ -33,13 +33,11 @@ use {
3333local disable_filetype = { "TelescopePrompt" }
3434local disable_in_macro = false -- disable when recording or executing a macro
3535local disable_in_visualblock = false -- disable when insert after visual block mode
36−local disable_in_replace_mode = true
37−local ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=]
36+local ignored_next_char = [=[[%w%%%'%[%"%.]]=]
3837local enable_moveright = true
3938local enable_afterquote = true -- add bracket pairs after quote
4039local enable_check_bracket_line = true --- check bracket in same line
4140local enable_bracket_in_quote = true --
42−local enable_abbr = false -- trigger abbreviation
4341local break_undo = true -- switch for basic rule break undo sequence
4442local check_ts = false
4543local map_cr = true
@@ -79,54 +77,13 @@ Check readme.md on nvim-cmp repo.
7977-- If you want insert `(` after select function or method item
8078local cmp_autopairs = require('nvim-autopairs.completion.cmp')
8179local cmp = require('cmp')
82−cmp.event:on(
83− 'confirm_done',
84− cmp_autopairs.on_confirm_done()
85−)
86−```
80+cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done({ map_char = { tex = '' } }))
8781
88−You can customize the kind of completion to add `(` or any character.
89−
90−```lua
91−local handlers = require('nvim-autopairs.completion.handlers')
92−
93−cmp.event:on(
94− 'confirm_done',
95− cmp_autopairs.on_confirm_done({
96− filetypes = {
97− -- "*" is a alias to all filetypes
98− ["*"] = {
99− ["("] = {
100− kind = {
101− cmp.lsp.CompletionItemKind.Function,
102− cmp.lsp.CompletionItemKind.Method,
103− },
104− handler = handlers["*"]
105− }
106− },
107− lua = {
108− ["("] = {
109− kind = {
110− cmp.lsp.CompletionItemKind.Function,
111− cmp.lsp.CompletionItemKind.Method
112− },
113− ---@param char string
114− ---@param item item completion
115− ---@param bufnr buffer number
116− handler = function(char, item, bufnr)
117− -- Your handler function. Inpect with print(vim.inspect{char, item, bufnr})
118− end
119− }
120− },
121− -- Disable for tex
122− tex = false
123− }
124− })
125−)
126−```
12782
128−Don't use `nil` to disable a filetype. If a filetype is `nil` then `*` is used as fallback.
83+-- add a lisp filetype (wrap my-function), FYI: Hardcoded = { "clojure", "clojurescript", "fennel", "janet" }
84+cmp_autopairs.lisp[#cmp_autopairs.lisp+1] = "racket"
12985
86+```
13087</details>
13188<details>
13289<summary><b>coq_nvim</b></summary>
@@ -340,17 +297,9 @@ Before Input After
340297 require('nvim-autopairs').enable()
341298 require('nvim-autopairs').remove_rule('(') -- remove rule (
342299 require('nvim-autopairs').clear_rules() -- clear all rules
343− -- get rule " then modify it. It can return a list of rule or just a rule
344− require('nvim-autopairs').get_rule('"')
345−```
300+ require('nvim-autopairs').get_rule('"') -- get rule " then modify it
346301
347−* Sample
348−```lua
349−-- remove add single quote on filetype scheme or lisp
350−require("nvim-autopairs").get_rule("'")[1].not_filetypes = { "scheme", "lisp" }
351−require("nvim-autopairs").get_rule("'")[1]:with_pair(cond.not_after_text("["}))
352302```
353−
354303### FastWrap
355304
356305``` text
@@ -391,8 +340,3 @@ npairs.setup({
391340
392341### Custom rules
393342[rules](https://github.com/windwp/nvim-autopairs/wiki/Custom-rules)
394−
395−## Sponsors
396−
397−Thanks to everyone who sponsors my projects and makes continued development maintenance possible!
398−<!-- patreon --><a href="https://github.com/t4t5"><img src="https://github.com/t4t5.png" width="60px" alt="" /></a><!-- patreon-->
doc/nvim-autopairs-rules.txt+64−306
@@ -3,134 +3,94 @@
33==============================================================================
44Table of Contents *nvim-autopairs-rules-table-of-contents*
55
6−1. Rule Basics |nvim-autopairs-rules-rule-basics|
7−2. Controlling rule behavior |nvim-autopairs-rules-controlling-rule-behavior|
8− - Method Overview |nvim-autopairs-rules-method-overview|
9− - Conditions |nvim-autopairs-rules-conditions|
10−3. Method Explanations |nvim-autopairs-rules-method-explanations|
11− - The `with_*` methods |nvim-autopairs-rules-the-`with_*`-methods|
12− - The `use_*` methods |nvim-autopairs-rules-the-`use_*`-methods|
13− - Shorthand methods |nvim-autopairs-rules-shorthand-methods|
14− - Advanced methods |nvim-autopairs-rules-advanced-methods|
15−
16−==============================================================================
17−1. Rule Basics *nvim-autopairs-rules-rule-basics*
18−
19−At its core, a rule consists of two things: a **pair definition** and an
20−optional **declaration of filetypes** where the rule is in effect. A pair
21−definition has an opening part and a closing part. Each of these parts can be
22−as simple as a single character like a pair of parenthesis, or multiple
23−characters like Markdown code fences. Defining a rule is straightforward:
24−
25−>
26− Rule(begin_pair, end_pair, filetypes)
27−<
6+ - Define rule with a pairs |nvim-autopairs-rules-define-rule-with-a-pairs|
7+ - Rules |nvim-autopairs-rules-rules|
288
9+DEFINE RULE WITH A PAIRS *nvim-autopairs-rules-define-rule-with-a-pairs*
2910
30−Where `begin_pair` is the opening part of the pair and `end_pair` is the
31−closing part. `filetypes` may be specified in multiple ways:
32−
33−>
34− Rule("(", ")") -- Enabled for all filetypes
35− Rule("(", ")", "markdown") -- As a string
36− Rule("(", ")", {"markdown", "vim"}) -- As a table
37−<
11+Rule(begin_pair, end_pair, filetypes)
3812
3913
40−Additionally, it is possible to specify filetypes where the rule should **not**
41−be enabled by prefixing it with a `-` character:
14+- You can use string or a table(array) on file type
15+ `Rule("(",")", "markdown")` ,`Rule("(",")", {"markdown","vim"})`
16+- If you add minus "-" before file type mean that rule is not working on that file type.
17+ `Rule("a","a","-vim")`
4218
43−>
44− Rule("(", ")", "-markdown") -- All filetypes *except* markdown
45−<
4619
20+RULES *nvim-autopairs-rules-rules*
4721
48−==============================================================================
49−2. Controlling rule behavior *nvim-autopairs-rules-controlling-rule-behavior*
22+│ function │ usage │
23+│with_pair(cond) │add condition to check for pair event │
24+│with_move(cond) │add condition to check for move right event │
25+│with_cr(cond) │add condition to check for break line event │
26+│with_del(cond) │add condition to check for delete pair event │
27+│only_cr(cond) │disable move,del and pair event Only use break li│
28+│ │ne event │
29+│use_regex(bool,"<key>")│input pair use regex and trigger by key │
30+│ │ │
31+│use_key('<key>') │change trigger key │
32+│replace_endpair(func) │change a map pair with function │
33+│set_end_pair_length(num│help to move a cursor to a middle of the end pair│
34+│ber) │ │
35+│ │when you use a replace_endpair with key <left> <P│
36+│ │lug> │
37+│replace_map_cr(func) │change a map on cr key with with function │
38+│end_wise(cond) │expand pair only on enter key │
5039
51−By default, rules are very simple and will always complete a pair the moment
52−the opening part is typed. This is fine and in some cases desirable, but the
53−rules API allows you to control the manner and context in which pairs are
54−completed; this is done by attaching **conditions** (predicates) to **events**
55−and adding **modifiers** to the rule. `Rule` objects expose a variety of
56−methods to add these predicates and modifiers to the rule.
5740
58−METHOD OVERVIEW *nvim-autopairs-rules-method-overview*
41+ *nvim-autopairs-rules-replace_endpair*
5942
60−These methods allow control over if, when, and how rules perform completion of
61−pairs. Each method returns the `Rule` object so that they may be chained
62−together to easily define complex rules.
43+replace_endpair paramaters 2 of replace_endpair use to
44+ combine with with_pair function
6345
64−│ method │ usage │
65−│with_pair(cond) │add condition to check during pair event │
66−│with_move(cond) │add condition to check during move right event │
67−│with_cr(cond) │add condition to check during line break event │
68−│with_del(cond) │add condition to check during delete pair event │
69−│only_cr(cond) │enable _only_ the line break event; disable everything │
70−│ │else │
71−│use_regex(bool, "<k│interpret begin_pair as regex; optionally set trigger k│
72−│ey>") │ey │
73−│use_key("<key>") │set trigger key │
74−│replace_endpair(fun│define ending part with a function; optionally add with│
75−│c, check_pair) │_pair │
76−│set_end_pair_length│override offset used to position the cursor between the│
77−│(number) │ pair when replace_endpair is used │
78−│replace_map_cr(func│change the mapping for used for <CR> during the line br│
79−│) │eak event │
80−│end_wise(cond) │make the rule an end-wise rule │
8146
47+>
48+ Rule("(",")")
49+ :use_key("<c-h>")
50+ :replace_endpair(function() return "<bs><del>" end, true)
51+ -- it is a short version of this
52+ Rule("(","")
53+ :use_key("<c-h>")
54+ :with_pair(cond.after_text(")")) -- check text after cursor is )
55+ :replace_endpair(function() return "<bs><del>" end)
56+<
8257
83−AIDING UNDERSTANDING: "WHEN" INSTEAD OF "WITH" ~
84−
85−It may be helpful to think of the `with_<event>` functions as reading more like
86−`when_<event>` instead, as the condition is checked **when** `<event>` happens
87−(or wants to happen). This naming scheme more accurately describes how the
88−`Rule` is affected and reads more intuitively when reading a rule definition.
89−
90−For example, given a rule definition `Rule("(", ")")`, each method has a
91−certain effect on how and when the ending part of the pair, the closing
92−parenthesis, is completed. The ending part is only completed **when**
93−associated conditions are met upon typing the opening part of the pair.
94−
95−CONDITIONS *nvim-autopairs-rules-conditions*
9658
97−nvim-autopairs comes with a variety of common predicates ready to use simply by
98−including:
59+CONDITION ~
9960
10061>
10162 local cond = require('nvim-autopairs.conds')
10263<
10364
10465
105−│ function │ Usage │
106−│none() │always false │
107−│done() │always true │
108−│before_text(text) │text exists before opening part │
109−│after_text(text) │text exists after opening part │
110−│before_regex(regex, length│regex matches before opening part │
111−│) │ │
112−│after_regex(regex, length)│regex matches after opening part │
113−│ │ │
114−│not_before_text(text) │text is not before opening part │
115−│not_after_text(text) │text is not after opening part │
116−│not_before_regex(regex, le│regex doesn’t match before opening part │
117−│ngth) │ │
118−│not_after_regex(regex, len│regex doesn’t match after opening part │
119−│gth) │ │
120−│not_inside_quote() │not currently within quotation marks │
121−│is_inside_quote() │currently within quotation marks │
122−│not_filetypes({table}) │current filetype is not inside table │
123−│is_bracket_in_quote() │check the next char is quote and cursor is insi│
124−│ │de quote │
66+│ function │ Usage │
67+│none() │always wrong │
68+│done() │always correct │
69+│before_text(text) │check character before │
70+│after_text(text) │check character after │
71+│before_regex(regex,length│check character before with lua regex │
72+│) │ │
73+│after_regex(regex,length)│check character after with lua regex │
74+│ │ │
75+│not_before_text(text) │check character before │
76+│not_after_text(text) │check character after │
77+│not_before_regex(regex,le│check character before with lua regex │
78+│ngth) │ │
79+│not_after_regex(regex,len│check character after with lua regex │
80+│gth) │ │
81+│not_inside_quote() │check is not inside a quote │
82+│is_inside_quote() │check is inside a quote │
83+│not_filetypes({table}) │check filetype is not inside table │
84+│is_bracket_in_quote() │check the next char is quote and cursor is insi│
85+│ │de quote │
86+
12587
12688
127−**N.B.** While `cond.not_filetypes` is available, it’s better to use the
128−minus syntax on the desired filetype in the initial rule declaration, since
129−then the rule is completely removed from the buffer.
89+- cond.not_filetypes should be use by add minus on filetype when you declare rule.
90+ Rule("a","a","-vim") because it is complete remove that rule on buffer.
13091
131−TREESITTER CONDITIONS ~
13292
133−Predicates based on the state of the Treesitter graph can be used by including:
93+TREESITTER CONDITION ~
13494
13595>
13696 local ts_conds = require('nvim-autopairs.ts-conds')
@@ -142,208 +102,6 @@ Predicates based on the state of the Treesitter graph can be used by including:
142102│is_not_ts_node({node_table})│check not in treesitter node │
143103
144104
145−==============================================================================
146−3. Method Explanations *nvim-autopairs-rules-method-explanations*
147−
148−This section explains each method in more detail: their signatures and how they
149−modify the rule’s behavior are all outlined here.
150−
151−THE `WITH_*` METHODS *nvim-autopairs-rules-the-`with_*`-methods*
152−
153−Calling these methods on a `Rule` will add predicate functions to their
154−corresponding event, which determines whether the effect of the event actually
155−takes place. There are no predicates if you don’t define any, and so any
156−events without predicates behave as if they had a single predicate that always
157−returns true.
158−
159−A `Rule` may have more than one predicate defined for a given event, and the
160−order that they are defined will be the order that they are checked. However,
161−the **first** non-`nil` value returned by a predicate is used and the remaining
162−predicates (if any) are **not** executed. In other words, predicates defined
163−earlier have priority over predicates defined later.
164−
165−`WITH_PAIR(COND, POS)` ~
166−
167−After typing the opening part, `cond` will fire and the ending part will only
168−be added if `cond` returned true. `with_pair` may be called more than once, and
169−by default, each predicate is appended to a list. When the "pair" event fires,
170−the _first_ predicate to return non-nil is used as the condition result.
171−Specifying `pos` allows explicit control over the order of the predicates.
172−
173−`WITH_MOVE(COND)` ~
174−
175−If `cond` is true, the cursor is simply moved right when typing the ending part
176−of the pair and the next character is also the ending part, e.g. `|" -> "|`
177−when typing `"`. If `cond` returns false, the ending part is inserted as normal
178−instead.
179−
180−`WITH_CR(COND)` ~
181−
182−If `cond` is true, then move the ending part of the pair to a new line below
183−the cursor after pressing `<CR>` while the cursor is between the pair (think
184−curly braces opening a block). Otherwise `<CR>` behaves as normal. For example:
185−
186−>
187− {|}
188−<
189−
190−
191−Typing `<CR>` produces the following when `cond` is true:
192−
193−>
194− {
195− |
196− }
197−<
198−
199−
200−`WITH_DEL(COND)` ~
201−
202−If `cond` is true, when the cursor is between the pair, pressing `<BS>` to
203−delete the opening part of the pair will delete the ending part as well.
204−
205−THE `USE_*` METHODS *nvim-autopairs-rules-the-`use_*`-methods*
206−
207−The `use_*` functions alter how auto-pairing is triggered. Normally, the first
208−argument to `Rule` is taken literally as the opening part of the pair and as
209−soon as it is typed the "pair" event fires.
210−
211−`USE_KEY(KEY)` ~
212−
213−The pair is only completed when `key` is pressed, instead of the moment that
214−the opening part is typed. This is particularly useful in `use_regex`.
215−
216−`USE_REGEX(BOOL, KEY)` ~
217−
218−Causes the opening part to be interpreted as a lua pattern that triggers
219−insertion of the ending part when matched. If `key` is specified, then it acts
220−as an implicit `use_key`.
221−
222−SHORTHAND METHODS *nvim-autopairs-rules-shorthand-methods*
223−
224−These methods exist as convenient shortcuts for defining certain behaviors.
225−
226−`END_WISE(FUNC)` ~
227−
228−This method is used to make "end-wise" rules, which is terminology that should
229−be familiar to users of other auto-pair plugins, e.g. Lexima. Specifically,
230−this method makes it so that the ending part of the pair will be completed
231−_only upon pressing `<CR>` after the opening part_, in which case the "newline"
232−event is fired as usual.
233−
234−This behavior is useful for languages with statement constructs like Lua and
235−Bash. For example, defining the following `Rule`:
236−
237−>
238− Rule('then', 'end'):end_wise(function(opts))
239− -- Add any context checks here, e.g. line starts with "if"
240− return string.match(opts.line, '^%s*if') ~= nil
241− end)
242−<
243−
244−
245−And then pressing `<CR>` at the following cursor position:
246−
247−>
248− if foo == bar then|
249−<
250−
251−
252−Would be completed as this (assuming some kind of automatic indent is enabled):
253−
254−>
255− if foo == bar then
256− |
257− end
258−<
259−
260−
261−`ONLY_CR(COND)` ~
262−
263−This shortcut method disables the "pair", "del", and "move" events by setting a
264−single predicate for each that is always false. Additionally, the effect of any
265−`use_key` modifiers are removed as well. If `cond` is specified, a "newline"
266−predicate is set as if `with_cr` were called.
267−
268−This method is convenient for defining _simple_ end-wise rules. As an example,
269−a default rule is defined with `only_cr` for Markdown code blocks with an
270−explicit language; the closing triple-backtick is not completed until you press
271−`<CR>` after specifying the language:
272−
273−>
274− ```lua <-- <CR> pressed here
275− |
276− ```
277−<
278−
279−
280−ADVANCED METHODS *nvim-autopairs-rules-advanced-methods*
281−
282−These methods allow you to define more complex and dynamic rules. When combined
283−with `with_*` and `use_*` methods, it is possible to create very powerful
284−auto-pairs.
285−
286−`REPLACE_ENDPAIR(FUNC, CHECK_PAIR)` ~
287−
288−Facilitates the creation of dynamic ending parts. When the "pair" event fires
289−and the ending part is to be completed, `func` is called with a single `opts`
290−argument and should return a string. The returned string will be sent to
291−`nvim_feedkeys` to insert the ending part of the pair.
292−
293−The `opts` parameter is a table that provides context for the current pair
294−completion, and can be useful for determining what to return. Note that because
295−`nvim_feedkeys` is used, arbitrary Vim functionality can be leveraged, such as
296−including `<Esc>` to be able to send normal mode commands.
297−
298− *nvim-autopairs-rules-Optional-`check_pair`-parameter*
299−
300−Optional `check_pair` parameter The `check_pair` parameter is optional,
301− and can either be a boolean or function.
302− If `check_pair` is a function, it is
303− passed as-is to `with_pair` to create a
304− "pair" predicate. If `check_pair` is
305− true, then an implicit
306− `with_pair(cond.after_text(rule.end_pair))`
307− predicate is added, where
308− `rule.end_pair` is the second argument
309− to the `Rule` constructor. If
310− `check_pair` is false, an "always false"
311− `with_pair` predicate is added.
312−
313−
314−As an example, these two rule definitions are equivalent:
315−
316−>
317− -- This...
318− Rule("(", ")")
319− :use_key("<C-h>")
320− :replace_endpair(function() return "<BS><Del>" end, true)
321−
322− -- ...is shorthand for this
323− Rule("(", "")
324− :use_key("<C-h>")
325− :with_pair(cond.after_text(")")) -- check that text after cursor is `)`
326− :replace_endpair(function() return "<BS><Del>" end)
327−<
328−
329−
330−`SET_END_PAIR_LENGTH(LEN)` ~
331−
332−When completing the ending part of a pair, the cursor necessarily moves
333−backward so that is in between the opening part and the closing part. In order
334−to do this, the `Rule` must know the length of the ending part, which by
335−default is trivially determined. However, if you would like to override where
336−the cursor is placed after completion, i.e. using `replace_endpair`, you can
337−explicitly set the ending part length with this method.
338−
339−`REPLACE_MAP_CR(FUNC)` ~
340−
341−This method allows you to set a custom mapping for the "newline" (`<CR>`) event
342−that will be used instead of the normal behavior. This can be helpful for
343−enforcing certain styles or or adding additional edits. `func` is called with a
344−single `opts` argument and should return a string specifying the mapping for
345−`<CR>`. The default mapping is: `<C-g>u<CR><C-c>O`.
346−
347105Generated by panvimdoc <https://github.com/kdheepak/panvimdoc>
348106
349107vim:tw=78:ts=8:noet:ft=help:norl:
doc/nvim-autopairs.txt+9−73
@@ -4,7 +4,6 @@
44Table of Contents *nvim-autopairs-table-of-contents*
55
66 - nvim-autopairs |nvim-autopairs-nvim-autopairs|
7− - Installation |nvim-autopairs-installation|
87 - Default values |nvim-autopairs-default-values|
98
109NVIM-AUTOPAIRS *nvim-autopairs-nvim-autopairs*
@@ -13,28 +12,10 @@ A super powerful autopair plugin for Neovim that supports multiple characters.
1312
1413Requires neovim 0.5+
1514
16−INSTALLATION *nvim-autopairs-installation*
17−
18−Install the plugin with your preferred package manager:
19−
20−VIM-PLUG <HTTPS://GITHUB.COM/JUNEGUNN/VIM-PLUG> ~
15+SETUP ~
2116
2217>
23− Plug 'windwp/nvim-autopairs'
24−
25− lua << EOF
26− require("nvim-autopairs").setup {}
27− EOF
28−<
29−
30−
31−PACKER <HTTPS://GITHUB.COM/WBTHOMASON/PACKER.NVIM> ~
32−
33−>
34− use {
35− "windwp/nvim-autopairs",
36− config = function() require("nvim-autopairs").setup {} end
37− }
18+ require('nvim-autopairs').setup{}
3819<
3920
4021
@@ -92,59 +73,14 @@ Check readme.md on nvim-cmp repo.
9273 -- If you want insert `(` after select function or method item
9374 local cmp_autopairs = require('nvim-autopairs.completion.cmp')
9475 local cmp = require('cmp')
95− cmp.event:on(
96− 'confirm_done',
97− cmp_autopairs.on_confirm_done()
98− )
99−<
100−
101−
102−Mapping `<CR>` You can customize the kind of completion
103− to add `(` or any character.
104−
105−
106−>
107− local handlers = require('nvim-autopairs.completion.handlers')
76+ cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done({ map_char = { tex = '' } }))
10877
109− cmp.event:on(
110− 'confirm_done',
111− cmp_autopairs.on_confirm_done({
112− filetypes = {
113− -- "*" is a alias to all filetypes
114− ["*"] = {
115− ["("] = {
116− kind = {
117− cmp.lsp.CompletionItemKind.Function,
118− cmp.lsp.CompletionItemKind.Method,
119− },
120− handler = handlers["*"]
121− }
122− },
123− lua = {
124− ["("] = {
125− kind = {
126− cmp.lsp.CompletionItemKind.Function,
127− cmp.lsp.CompletionItemKind.Method
128− },
129− ---@param char string
130− ---@param item item completion
131− ---@param bufnr buffer number
132− handler = function(char, item, bufnr)
133− -- Your handler function. Inpect with print(vim.inspect{char, item, bufnr})
134− end
135− }
136− },
137− -- Disable for tex
138− tex = false
139− }
140− })
141− )
78+
79+ -- add a lisp filetype (wrap my-function), FYI: Hardcoded = { "clojure", "clojurescript", "fennel", "janet" }
80+ cmp_autopairs.lisp[#cmp_autopairs.lisp+1] = "racket"
14281<
14382
14483
145−Don’t use `nil` to disable a filetype. If a filetype is `nil` then `*` is
146−used as fallback.
147−
14884coq_nvim ~
14985
15086>
@@ -196,8 +132,9 @@ without completion plugin ~
196132<
197133
198134
199−another completion plugin
200−<https://github.com/windwp/nvim-autopairs/wiki/Completion-plugin>
135+Mapping `<CR>` another completion plugin
136+ <https://github.com/windwp/nvim-autopairs/wiki/Completion-plugin>
137+
201138
202139If you have a problem with indent after you press `<CR>` please check the
203140settings of treesitter indent or install a plugin that has indent support for
@@ -298,7 +235,6 @@ You can use treesitter to check for a pair.
298235
299236>
300237 local npairs = require("nvim-autopairs")
301− local Rule = require('nvim-autopairs.rule')
302238
303239 npairs.setup({
304240 check_ts = true,
lua/nvim-autopairs.lua+111−94
@@ -19,15 +19,13 @@ local default = {
1919 disable_filetype = { 'TelescopePrompt', 'spectre_panel' },
2020 disable_in_macro = false,
2121 disable_in_visualblock = false,
22− disable_in_replace_mode = true,
23− ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=],
22+ ignored_next_char = [=[[%w%%%'%[%"%.]]=],
2423 break_undo = true,
2524 check_ts = false,
2625 enable_moveright = true,
2726 enable_afterquote = true,
2827 enable_check_bracket_line = true,
2928 enable_bracket_in_quote = true,
30− enable_abbr = false,
3129 ts_config = {
3230 lua = { 'string', 'source' },
3331 javascript = { 'string', 'template_string' },
@@ -54,21 +52,18 @@ M.setup = function(opt)
5452 end
5553
5654 M.force_attach()
57− local group = api.nvim_create_augroup('autopairs_buf', { clear = true })
58− api.nvim_create_autocmd({ 'BufEnter', 'BufWinEnter' }, {
59− group = group, pattern = '*',
60− callback = function() M.on_attach() end
61− })
62− api.nvim_create_autocmd('BufDelete', {
63− group = group, pattern = '*',
64− callback = function(data)
65− M.set_buf_rule(nil, tonumber(data.buf) or 0)
66− end,
67− })
68− api.nvim_create_autocmd('FileType', {
69− group = group, pattern = '*',
70− callback = function() M.force_attach() end
71− })
55+
56+ api.nvim_exec(
57+ [[
58+ augroup autopairs_buf
59+ autocmd!
60+ autocmd BufEnter,BufWinEnter * lua require("nvim-autopairs").on_attach()
61+ autocmd BufDelete * lua require("nvim-autopairs").set_buf_rule(nil,tonumber(vim.fn.expand("<abuf>")))
62+ autocmd FileType * lua require("nvim-autopairs").force_attach()
63+ augroup end
64+ ]],
65+ false
66+ )
7267end
7368
7469M.add_rule = function(rule)
@@ -103,10 +98,10 @@ M.remove_rule = function(pair)
10398 if r.start_pair ~= pair then
10499 table.insert(state_tbl, r)
105100 elseif r.key_map and r.key_map ~= '' then
106− api.nvim_buf_del_keymap(0, 'i', r.key_map)
101+ vim.api.nvim_buf_del_keymap(0, 'i', r.key_map)
107102 end
108103 end
109− M.set_buf_rule(state_tbl, 0)
104+ M.set_buf_rule(state_tbl)
110105 end
111106 M.force_attach()
112107end
@@ -137,15 +132,6 @@ M.force_attach = function(bufnr)
137132 M.on_attach(bufnr)
138133end
139134
140−local del_keymaps = function()
141− local status, autopairs_keymaps = pcall(api.nvim_buf_get_var, 0, 'autopairs_keymaps')
142− if status and autopairs_keymaps and #autopairs_keymaps > 0 then
143− for _, key in pairs(autopairs_keymaps) do
144− pcall(api.nvim_buf_del_keymap, 0, 'i', key)
145− end
146− end
147−end
148−
149135local function is_disable()
150136 if M.state.disabled then
151137 return true
@@ -160,23 +146,22 @@ local function is_disable()
160146 return true
161147 end
162148
163− if M.config.disable_in_macro
149+ if
150+ M.config.disable_in_macro
164151 and (vim.fn.reg_recording() ~= '' or vim.fn.reg_executing() ~= '')
165152 then
166153 return true
167154 end
168155
169− if M.config.disable_in_replace_mode and vim.api.nvim_get_mode().mode == "R" then
170− return true
171− end
172−
173156 if M.config.disable_in_visualblock and utils.is_block_wise_mode() then
174157 return true
175158 end
176159
177160 if utils.check_filetype(M.config.disable_filetype, vim.bo.filetype) then
178− del_keymaps()
179− M.set_buf_rule({}, 0)
161+ -- should have a way to remove the mapping when vim.bo.filetype = ''
162+ -- now we only remove a rule
163+ -- the event FileType happen after BufEnter
164+ M.set_buf_rule({})
180165 return true
181166 end
182167 return false
@@ -184,14 +169,14 @@ end
184169
185170---@return table <number, Rule>
186171M.get_buf_rules = function(bufnr)
187− return M.state.rules[bufnr or api.nvim_get_current_buf()] or {}
172+ return M.state.rules[bufnr or vim.api.nvim_get_current_buf()] or {}
188173end
189174
190−---@param rules nil|table list or rule
175+---@param rules table list or rule
191176---@param bufnr number buffer number
192177M.set_buf_rule = function(rules, bufnr)
193178 if bufnr == 0 or bufnr == nil then
194− bufnr = api.nvim_get_current_buf()
179+ bufnr = vim.api.nvim_get_current_buf()
195180 end
196181 M.state.rules[bufnr] = rules
197182end
@@ -205,7 +190,8 @@ M.on_attach = function(bufnr)
205190
206191 local rules = {}
207192 for _, rule in pairs(M.config.rules) do
208− if utils.check_filetype(rule.filetypes, vim.bo.filetype)
193+ if
194+ utils.check_filetype(rule.filetypes, vim.bo.filetype)
209195 and utils.check_not_filetype(rule.not_filetypes, vim.bo.filetype)
210196 then
211197 table.insert(rules, rule)
@@ -241,50 +227,78 @@ M.on_attach = function(bufnr)
241227 if utils.is_attached(bufnr) then
242228 return
243229 end
244− del_keymaps()
245230 local enable_insert_auto = false
246− local autopairs_keymaps = {}
247− local expr_map = function(key)
248− api.nvim_buf_set_keymap(bufnr, 'i', key, '', {
249− expr = true,
250− noremap = true,
251− desc = "autopairs map key",
252− callback = function() return M.autopairs_map(bufnr, key) end,
253− })
254− table.insert(autopairs_keymaps, key)
255− end
256231 for _, rule in pairs(rules) do
257232 if rule.key_map ~= nil then
258233 if rule.is_regex == false then
259234 if rule.key_map == '' then
260235 rule.key_map = rule.start_pair:sub(#rule.start_pair)
261236 end
262− expr_map(rule.key_map)
237+ local key = string.format('"%s"', rule.key_map)
238+ if rule.key_map == '"' then
239+ key = [['"']]
240+ end
241+ local mapping = string.format('v:lua.MPairs.autopairs_map(%d,%s)', bufnr, key)
242+ api.nvim_buf_set_keymap(
243+ bufnr,
244+ 'i',
245+ rule.key_map,
246+ mapping,
247+ { expr = true, noremap = true }
248+ )
249+
263250 local key_end = rule.key_end or rule.end_pair:sub(1, 1)
264251 if #key_end >= 1 and key_end ~= rule.key_map and rule.move_cond ~= nil then
265− expr_map(key_end)
252+ mapping = string.format(
253+ [[v:lua.MPairs.autopairs_map(%d, '%s')]],
254+ bufnr,
255+ key_end
256+ )
257+ vim.api.nvim_buf_set_keymap(
258+ bufnr,
259+ 'i',
260+ key_end,
261+ mapping,
262+ { expr = true, noremap = true }
263+ )
266264 end
267265 else
268266 if rule.key_map ~= '' then
269− expr_map(rule.key_map)
267+ local mapping = string.format(
268+ "v:lua.MPairs.autopairs_map(%d,'%s')",
269+ bufnr,
270+ rule.key_map
271+ )
272+ api.nvim_buf_set_keymap(
273+ bufnr,
274+ 'i',
275+ rule.key_map,
276+ mapping,
277+ { expr = true, noremap = true }
278+ )
270279 elseif rule.is_endwise == false then
271280 enable_insert_auto = true
272281 end
273282 end
274283 end
275284 end
276− api.nvim_buf_set_var(bufnr, 'autopairs_keymaps', autopairs_keymaps)
277285
278286 if enable_insert_auto then
279287 -- capture all key use it to trigger regex pairs
280288 -- it can make an issue with paste from register
281− api.nvim_create_autocmd('InsertCharPre', {
282− group = api.nvim_create_augroup(string.format("autopairs_insert_%d", bufnr), { clear = true }),
283− buffer = bufnr,
284− callback = function()
285− M.autopairs_insert(bufnr, vim.v.char)
286− end
287− })
289+ api.nvim_exec(
290+ string.format(
291+ [[
292+ augroup autopairs_insert_%d
293+ autocmd!
294+ autocmd InsertCharPre <buffer=%d> call luaeval("require('nvim-autopairs').autopairs_insert(%d, _A)", v:char)
295+ augroup end ]],
296+ bufnr,
297+ bufnr,
298+ bufnr
299+ ),
300+ false
301+ )
288302 end
289303
290304 if M.config.fast_wrap and M.config.fast_wrap.map then
@@ -302,7 +316,7 @@ M.on_attach = function(bufnr)
302316 bufnr,
303317 'i',
304318 '<bs>',
305− 'v:lua.MPairs.autopairs_bs()',
319+ string.format('v:lua.MPairs.autopairs_bs(%d)', bufnr),
306320 { expr = true, noremap = true }
307321 )
308322 end
@@ -313,7 +327,7 @@ M.on_attach = function(bufnr)
313327 "i",
314328 utils.key.c_h,
315329 string.format("v:lua.MPairs.autopairs_c_h(%d)", bufnr),
316− { expr = true, noremap = true }
330+ {expr = true, noremap = true}
317331 )
318332 end
319333
@@ -333,7 +347,7 @@ local autopairs_delete = function(bufnr, key)
333347 if is_disable() then
334348 return utils.esc(key)
335349 end
336− bufnr = bufnr or api.nvim_get_current_buf()
350+ bufnr = bufnr or 0
337351 local line = utils.text_get_current_line(bufnr)
338352 local _, col = utils.get_cursor()
339353 local rules = M.get_buf_rules(bufnr)
@@ -346,23 +360,22 @@ local autopairs_delete = function(bufnr, key)
346360 #rule.end_pair,
347361 rule.is_regex
348362 )
349− if utils.compare(rule.start_pair, prev_char, rule.is_regex)
363+ if
364+ utils.compare(rule.start_pair, prev_char, rule.is_regex)
350365 and utils.compare(rule.end_pair, next_char, rule.is_regex)
351366 and rule:can_del({
352367 ts_node = M.state.ts_node,
353− rule = rule,
354368 bufnr = bufnr,
355369 prev_char = prev_char,
356370 next_char = next_char,
357371 line = line,
358− col = col,
359372 })
360373 then
361374 local input = ''
362− for _ = 1, api.nvim_strwidth(rule.start_pair), 1 do
375+ for _ = 1, vim.api.nvim_strwidth(rule.start_pair), 1 do
363376 input = input .. utils.key.bs
364377 end
365− for _ = 1, api.nvim_strwidth(rule.end_pair), 1 do
378+ for _ = 1, vim.api.nvim_strwidth(rule.end_pair), 1 do
366379 input = input .. utils.key.del
367380 end
368381 return utils.esc('<c-g>U' .. input)
@@ -395,8 +408,8 @@ M.autopairs_map = function(bufnr, char)
395408 local rules = M.get_buf_rules(bufnr)
396409 for _, rule in pairs(rules) do
397410 if rule.start_pair then
398− if char:match('<.*>') then
399− new_text = line
411+ if rule.key_map and rule.key_map:match('<.*>') then
412+ new_text = line:sub(1, col) .. line:sub(col + 1, #line)
400413 add_char = 0
401414 else
402415 new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line)
@@ -425,7 +438,8 @@ M.autopairs_map = function(bufnr, char)
425438 -- log.debug("start_pair" .. rule.start_pair)
426439 -- log.debug('prev_char' .. prev_char)
427440 -- log.debug('next_char' .. next_char)
428− if utils.compare(rule.end_pair, next_char, rule.is_regex)
441+ if
442+ utils.compare(rule.end_pair, next_char, rule.is_regex)
429443 and rule:can_move(cond_opt)
430444 then
431445 local end_pair = rule:get_end_pair(cond_opt)
@@ -433,8 +447,8 @@ M.autopairs_map = function(bufnr, char)
433447 return utils.esc(utils.repeat_key(utils.key.join_right, end_pair_length))
434448 end
435449
436− if rule.key_map == char
437− and utils.compare(rule.start_pair, prev_char, rule.is_regex)
450+ if
451+ utils.compare(rule.start_pair, prev_char, rule.is_regex)
438452 and rule:can_pair(cond_opt)
439453 then
440454 local end_pair = rule:get_end_pair(cond_opt)
@@ -447,19 +461,16 @@ M.autopairs_map = function(bufnr, char)
447461 if end_pair:match('<.*>') then
448462 end_pair = utils.esc(end_pair)
449463 end
450− local result = char .. end_pair .. utils.esc(move_text)
464+ local result= char .. end_pair .. utils.esc(move_text)
451465 if rule.is_undo then
452− result = utils.esc(utils.key.undo_sequence) .. result .. utils.esc(utils.key.undo_sequence)
453− end
454− if M.config.enable_abbr then
455− result = utils.esc(utils.key.abbr) .. result
466+ result = utils.esc(utils.key.undo_sequence) .. result..utils.esc(utils.key.undo_sequence)
456467 end
457468 log.debug("key_map :" .. result)
458469 return result
459470 end
460471 end
461472 end
462− return M.autopairs_afterquote(new_text, utils.esc(char))
473+ return M.autopairs_afterquote(new_text, char)
463474end
464475
465476M.autopairs_insert = function(bufnr, char)
@@ -501,7 +512,8 @@ M.autopairs_insert = function(bufnr, char)
501512 return false
502513 end
503514
504− if utils.compare(rule.start_pair, prev_char, rule.is_regex)
515+ if
516+ utils.compare(rule.start_pair, prev_char, rule.is_regex)
505517 and rule:can_pair(cond_opt)
506518 then
507519 local end_pair = rule:get_end_pair(cond_opt)
@@ -545,31 +557,35 @@ M.autopairs_cr = function(bufnr)
545557 prev_char = prev_char,
546558 next_char = next_char,
547559 }
560+
561+ local end_pair = rule:get_end_pair(cond_opt)
562+ local end_pair_length = rule:get_end_pair_length(end_pair)
563+
548564 -- log.debug('prev_char' .. rule.start_pair)
549565 -- log.debug('prev_char' .. prev_char)
550566 -- log.debug('next_char' .. next_char)
551− if rule.is_endwise
567+ if
568+ rule.is_endwise
552569 and utils.compare(rule.start_pair, prev_char, rule.is_regex)
553570 and rule:can_cr(cond_opt)
554571 then
555− local end_pair = rule:get_end_pair(cond_opt)
556− local end_pair_length = rule:get_end_pair_length(end_pair)
557572 return utils.esc(
558573 end_pair
559− .. utils.repeat_key(utils.key.join_left, end_pair_length)
560− -- FIXME do i need to re indent twice #118
561− .. '<cr><esc>====O'
574+ .. utils.repeat_key(utils.key.join_left, end_pair_length)
575+ -- FIXME do i need to re indent twice #118
576+ .. '<cr><esc>====O'
562577 )
563578 end
564579
565580 cond_opt.check_endwise_ts = false
566581
567− if utils.compare(rule.start_pair, prev_char, rule.is_regex)
582+ if
583+ utils.compare(rule.start_pair, prev_char, rule.is_regex)
568584 and utils.compare(rule.end_pair, next_char, rule.is_regex)
569585 and rule:can_cr(cond_opt)
570586 then
571587 log.debug('do_cr')
572− return utils.esc(rule:get_map_cr({ rule = rule, line = line, color = col, bufnr = bufnr }))
588+ return utils.esc(rule:get_map_cr({rule = rule, line = line, color = col, bufnr = bufnr}))
573589 end
574590 end
575591 end
@@ -582,7 +598,8 @@ M.autopairs_afterquote = function(line, key_char)
582598 line = line or utils.text_get_current_line(0)
583599 local _, col = utils.get_cursor()
584600 local prev_char, next_char = utils.text_cusor_line(line, col + 1, 1, 1, false)
585− if utils.is_bracket(prev_char)
601+ if
602+ utils.is_bracket(prev_char)
586603 and utils.is_quote(next_char)
587604 and not utils.is_in_quotes(line, col, next_char)
588605 then
@@ -600,7 +617,7 @@ M.autopairs_afterquote = function(line, key_char)
600617 is_prev_slash = char == '\\'
601618 end
602619 if count == 2 and index >= (#line - 2) then
603− local rules = M.get_buf_rules(api.nvim_get_current_buf())
620+ local rules = M.get_buf_rules(vim.api.nvim_get_current_buf())
604621 for _, rule in pairs(rules) do
605622 if rule.start_pair == prev_char and char_end ~= rule.end_pair then
606623 local new_text = line:sub(0, index)
@@ -632,13 +649,13 @@ end
632649
633650M.map_cr = function()
634651 M.completion_confirm = function()
635− if vim.fn.pumvisible() ~= 0 then
652+ if vim.fn.pumvisible() ~= 0 then
636653 return M.esc("<cr>")
637654 else
638655 return M.autopairs_cr()
639656 end
640657 end
641− api.nvim_set_keymap(
658+ vim.api.nvim_set_keymap(
642659 'i',
643660 '<CR>',
644661 'v:lua.MPairs.completion_confirm()',
lua/nvim-autopairs/_log.lua+8−8
@@ -1,13 +1,13 @@
1−---@diagnostic disable: undefined-field
2−local empty = {
3− debug = function(_) end,
4− info = function(_) end,
5− error = function(_) end,
6−}
71if _G.__is_log then
82 return require('plenary.log').new {
93 plugin = 'nvim-autopairs',
104 level = (_G.__is_log == true and 'debug') or 'warn',
11− } or empty
5+ }
6+else
7+ return{
8+ debug = function(_) end,
9+ info = function(_) end,
10+ error = function(_) end,
11+
12+ }
1213end
13−return empty
lua/nvim-autopairs/completion/cmp.lua+41−58
@@ -1,77 +1,60 @@
1−local autopairs = require('nvim-autopairs')
2−local handlers = require('nvim-autopairs.completion.handlers')
3−local cmp = require('cmp')
1+local utils = require('nvim-autopairs.utils')
42
5−local Kind = cmp.lsp.CompletionItemKind
3+local cmp = require('cmp')
64
75local M = {}
86
9−M.filetypes = {
10− -- Alias to all filetypes
11− ["*"] = {
12− ["("] = {
13− kind = { Kind.Function, Kind.Method },
14− handler = handlers["*"]
15− }
16− },
17− clojure = {
18− ["("] = {
19− kind = { Kind.Function, Kind.Method },
20− handler = handlers.lisp
21− }
22− },
23− clojurescript = {
24− ["("] = {
25− kind = { Kind.Function, Kind.Method },
26− handler = handlers.lisp
27− }
28− },
29− fennel = {
30− ["("] = {
31− kind = { Kind.Function, Kind.Method },
32− handler = handlers.lisp
33− }
34− },
35− janet = {
36− ["("] = {
37− kind = { Kind.Function, Kind.Method },
38− handler = handlers.lisp
39− }
40− },
41− tex = false,
42− haskell = false
43−}
7+M.lisp = { "clojure", "clojurescript", "fennel", "janet" }
448
45−M.on_confirm_done = function(opts)
46− opts = vim.tbl_deep_extend('force', {
47− filetypes = M.filetypes
48− }, opts or {})
9+local ignore_append = function(char, kinds, next_char, prev_char, item)
10+ if char == '' or prev_char == char or next_char == char
11+ or (item.data and item.data.funcParensDisabled)
12+ or (not utils.is_in_table(kinds, item.kind))
13+ or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]")
14+ or (item.insertText and item.insertText:match "[%(%[%$]")
15+ then
16+ return true
17+ end
18+end
19+
20+M.on_confirm_done = function(opt)
21+ opt = vim.tbl_deep_extend('force', {
22+ map_char = { tex = '' },
23+ kinds = {
24+ cmp.lsp.CompletionItemKind.Method,
25+ cmp.lsp.CompletionItemKind.Function,
26+ },
27+ }, opt or {})
4928
5029 return function(evt)
5130 local entry = evt.entry
52− local commit_character = evt.commit_character
53− local bufnr = vim.api.nvim_get_current_buf()
54− local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
31+ local line = utils.text_get_current_line(0)
32+ local _, col = utils.get_cursor()
33+ local prev_char, next_char = utils.text_cusor_line(line, col, 1, 1, false)
5534 local item = entry:get_completion_item()
5635
57− -- Without options and fallback
58− if not opts.filetypes[filetype] and not opts.filetypes["*"] then
59− return
36+ local char = opt.map_char[vim.bo.filetype] or '('
37+ if char == '' then
38+ return
6039 end
6140
62− if opts.filetypes[filetype] == false then
63− return
41+ if ignore_append(char, opt.kinds, next_char, prev_char, item) or evt.commit_character == char then
42+ return
6443 end
6544
66− -- If filetype is nil then use *
67− local completion_options = opts.filetypes[filetype] or opts.filetypes["*"]
68−
69− for char, value in pairs(completion_options) do
70− if vim.tbl_contains(value.kind, item.kind) then
71− value.handler(char, item, bufnr, commit_character)
45+ if utils.is_in_table(M.lisp, vim.bo.filetype) then
46+ local length = #item.label
47+ if utils.text_sub_char(line, col - length, 1) == "(" then
48+ utils.feed("<Space>")
49+ return
7250 end
51+ utils.feed(utils.key.left, length)
52+ utils.feed("(")
53+ utils.feed(utils.key.right, length)
54+ utils.feed("<Space>")
55+ else
56+ vim.api.nvim_feedkeys(char, 'i', true)
7357 end
7458 end
7559end
76−
7760return M
lua/nvim-autopairs/completion/handlers.luadeleted−52
@@ -1,52 +0,0 @@
1−-- local autopairs = require('nvim-autopairs')
2−local utils = require('nvim-autopairs.utils')
3−
4−local M = {}
5−
6−---@param char string
7−---@param item table
8−---@param bufnr number
9−M["*"] = function(char, item, bufnr, commit_character)
10− local line = utils.text_get_current_line(bufnr)
11− local _, col = utils.get_cursor()
12− local char_before, char_after = utils.text_cusor_line(line, col, 1, 1, false)
13−
14− if char == '' or char_before == char or char_after == char
15− or (item.data and type(item.data) == 'table' and item.data.funcParensDisabled)
16− or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]")
17− or (item.insertText and item.insertText:match "[%(%[%$]")
18− or char == commit_character
19− then
20− return
21− end
22−
23− vim.api.nvim_feedkeys(char, "i", true)
24−end
25−
26−---Handler with "clojure", "clojurescript", "fennel", "janet
27−M.lisp = function (char, item, bufnr, commit_character)
28− local line = utils.text_get_current_line(bufnr)
29− local _, col = utils.get_cursor()
30− local char_before, char_after = utils.text_cusor_line(line, col, 1, 1, false)
31− local length = #item.label
32−
33− if char == '' or char_before == char or char_after == char
34− or (item.data and item.data.funcParensDisabled)
35− or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]")
36− or (item.insertText and item.insertText:match "[%(%[%$]")
37− or char == commit_character
38− then
39− return
40− end
41−
42− if utils.text_sub_char(line, col - length, 1) == "(" then
43− utils.feed("<Space>")
44− return
45− end
46− utils.feed(utils.key.left, length)
47− utils.feed(char)
48− utils.feed(utils.key.right, length)
49− utils.feed("<Space>")
50−end
51−
52−return M
lua/nvim-autopairs/conds.lua+14−77
@@ -1,16 +1,5 @@
11local utils = require('nvim-autopairs.utils')
22local log = require('nvim-autopairs._log')
3−---@class CondOpts
4−---@field ts_node table
5−---@field text string
6−---@field rule table
7−---@field bufnr number
8−---@field col number
9−---@field char string
10−---@field line string
11−---@field prev_char string
12−---@field next_char string
13−---@field is_endwise string
143
154local cond = {}
165
@@ -42,7 +31,6 @@ cond.before_regex = function(regex, length)
4231 if not regex then
4332 return cond.none()
4433 end
45− ---@param opts CondOpts
4634 return function(opts)
4735 log.debug('before_regex')
4836 if length < 0 then
@@ -58,7 +46,6 @@ end
5846
5947cond.before_text = function(text)
6048 local length = #text
61− ---@param opts CondOpts
6249 return function(opts)
6350 log.debug('before_text')
6451 local str = utils.text_sub_char(opts.line, opts.col - 1, -length)
@@ -71,7 +58,6 @@ end
7158
7259cond.after_text = function(text)
7360 local length = #text
74− ---@param opts CondOpts
7561 return function(opts)
7662 log.debug('after_text')
7763 local str = utils.text_sub_char(opts.line, opts.col, length)
@@ -87,7 +73,6 @@ cond.after_regex = function(regex, length)
8773 if not regex then
8874 return cond.none()
8975 end
90− ---@param opts CondOpts
9176 return function(opts)
9277 log.debug('after_regex')
9378 if length < 0 then
@@ -114,7 +99,6 @@ end
11499
115100cond.not_after_text = function(text)
116101 local length = #text
117− ---@param opts CondOpts
118102 return function(opts)
119103 log.debug('not_after_text')
120104 local str = utils.text_sub_char(opts.line, opts.col, length)
@@ -129,7 +113,6 @@ cond.not_before_regex = function(regex, length)
129113 if not regex then
130114 return cond.none()
131115 end
132− ---@param opts CondOpts
133116 return function(opts)
134117 log.debug('not_before_regex')
135118 if length < 0 then
@@ -147,7 +130,6 @@ cond.not_after_regex = function(regex, length)
147130 if not regex then
148131 return cond.none()
149132 end
150− ---@param opts CondOpts
151133 return function(opts)
152134 log.debug('not_after_regex')
153135 if length < 0 then
@@ -174,41 +156,16 @@ local function count_bracket_char(line, prev_char, next_char)
174156 return count_prev_char, count_next_char
175157end
176158
177−-- Checks if bracket chars are balanced around specific postion.
178−---@param line string
179−---@param open_char string
180−---@param close_char string
181−---@param col integer position
182−local function is_brackets_balanced_around_position(line, open_char, close_char, col)
183− local balance = 0
184− for i = 1, #line, 1 do
185− local c = line:sub(i, i)
186− if c == open_char then
187− balance = balance + 1
188− elseif balance > 0 and c == close_char then
189− balance = balance - 1
190− if col <= i and balance == 0 then
191− break
192− end
193− end
194− end
195− return balance == 0
196−end
197−
198159cond.is_bracket_line = function()
199− ---@param opts CondOpts
200160 return function(opts)
201161 log.debug('is_bracket_line')
202− if utils.is_bracket(opts.char) and
203− (opts.next_char == opts.rule.end_pair
204− or opts.next_char == opts.rule.start_pair)
205− then
162+ if utils.is_bracket(opts.char) and opts.next_char == opts.rule.end_pair then
206163 -- (( many char |)) => add
207164 -- ( many char |)) => not add
208165 local count_prev_char, count_next_char = count_bracket_char(
209166 opts.line,
210− opts.rule.start_pair,
211− opts.rule.end_pair
167+ opts.char,
168+ opts.next_char
212169 )
213170 if count_prev_char ~= count_next_char then
214171 return false
@@ -218,27 +175,26 @@ cond.is_bracket_line = function()
218175end
219176
220177cond.is_bracket_line_move = function()
221− ---@param opts CondOpts
222178 return function(opts)
223179 log.debug('is_bracket_line_move')
224− if utils.is_close_bracket(opts.char)
180+ if
181+ utils.is_close_bracket(opts.char)
225182 and opts.char == opts.rule.end_pair
226183 then
227− -- (( many char |)) => move
228184 -- (( many char |) => not move
229− local is_balanced = is_brackets_balanced_around_position(
185+ local count_prev_char, count_next_char = count_bracket_char(
230186 opts.line,
231187 opts.rule.start_pair,
232− opts.char,
233− opts.col
188+ opts.char
234189 )
235− return is_balanced
190+ if count_prev_char ~= 0 and count_prev_char > count_next_char then
191+ return false
192+ end
236193 end
237194 end
238195end
239196
240197cond.not_inside_quote = function()
241− ---@param opts CondOpts
242198 return function(opts)
243199 log.debug('not_inside_quote')
244200 if utils.is_in_quotes(opts.text, opts.col - 1) then
@@ -248,7 +204,6 @@ cond.not_inside_quote = function()
248204end
249205
250206cond.is_inside_quote = function()
251− ---@param opts CondOpts
252207 return function(opts)
253208 log.debug('is_inside_quote')
254209 if utils.is_in_quotes(opts.text, opts.col - 1) then
@@ -258,10 +213,10 @@ cond.is_inside_quote = function()
258213end
259214
260215cond.not_add_quote_inside_quote = function()
261− ---@param opts CondOpts
262216 return function(opts)
263217 log.debug('not_add_quote_inside_quote')
264− if utils.is_quote(opts.char)
218+ if
219+ utils.is_quote(opts.char)
265220 and utils.is_in_quotes(opts.text, opts.col - 1)
266221 then
267222 return false
@@ -270,7 +225,6 @@ cond.not_add_quote_inside_quote = function()
270225end
271226
272227cond.move_right = function()
273− ---@param opts CondOpts
274228 return function(opts)
275229 log.debug('move_right')
276230 if opts.next_char == opts.char then
@@ -295,7 +249,6 @@ cond.move_right = function()
295249end
296250
297251cond.is_end_line = function()
298− ---@param opts CondOpts
299252 return function(opts)
300253 log.debug('is_end_line')
301254 local end_text = opts.line:sub(opts.col + 1)
@@ -308,10 +261,10 @@ end
308261
309262--- Check the next char is quote and cursor is inside quote
310263cond.is_bracket_in_quote = function()
311− ---@param opts CondOpts
312264 return function(opts)
313265 log.debug("is_bracket_in_quote")
314− if utils.is_bracket(opts.char)
266+ if
267+ utils.is_bracket(opts.char)
315268 and utils.is_quote(opts.next_char)
316269 and utils.is_in_quotes(opts.line, opts.col - 1, opts.next_char)
317270 then
@@ -331,22 +284,6 @@ cond.not_filetypes = function(filetypes)
331284 end
332285end
333286
334−--- Check the character before the cursor is not equal
335−---@param char string character to compare
336−---@param index number the position of character before current curosr
337−cond.not_before_char = function(char, index)
338− index = index or 1
339− ---@param opts CondOpts
340− return function(opts)
341− log.debug('not_before_char')
342− local match_char = #opts.line > index
343− and opts.line:sub(#opts.line - index, #opts.line - index) or ''
344− if match_char == char and match_char ~= "" then
345− return false
346− end
347− end
348−end
349−
350287---@deprecated
351288cond.not_after_regex_check = cond.not_after_regex
352289---@deprecated
lua/nvim-autopairs/fastwrap.lua+19−10
@@ -19,7 +19,7 @@ local config = {}
1919
2020M.setup = function(cfg)
2121 if config.chars == nil then
22− config = vim.tbl_extend('force', default_config, cfg or {}) or {}
22+ config = vim.tbl_extend('force', default_config, cfg or {})
2323 npairs.config.fast_wrap = config
2424 end
2525end
@@ -56,23 +56,31 @@ M.show = function(line)
5656 local index = 1
5757 local str_length = #line
5858 local offset = -1
59+ local is_end_key = true
5960 for i = col + 2, #line, 1 do
6061 local char = line:sub(i, i)
6162 local char2 = line:sub(i - 1, i)
62− if string.match(char, config.pattern)
63+ if
64+ string.match(char, config.pattern)
6365 or (char == ' ' and string.match(char2, '%w'))
6466 then
6567 local key = config.keys:sub(index, index)
6668 index = index + 1
67− if utils.is_quote(char)
69+ if
70+ utils.is_quote(char)
6871 or (
69− utils.is_close_bracket(char)
72+ utils.is_close_bracket(char)
7073 and utils.is_in_quotes(line, col, prev_char)
7174 )
7275 then
7376 offset = 0
7477 end
7578
79+ if i == str_length then
80+ is_end_key = false
81+ key = config.end_key
82+ offset = 0
83+ end
7684 table.insert(
7785 list_pos,
7886 { col = i + offset, key = key, char = char, pos = i }
@@ -80,10 +88,12 @@ M.show = function(line)
8088 end
8189 end
8290
83− table.insert(
84− list_pos,
85− { col = str_length + 1, key = config.end_key, pos = str_length + 1 }
86− )
91+ if is_end_key then
92+ table.insert(
93+ list_pos,
94+ { col = str_length + 1, key = config.end_key, pos = str_length + 1 }
95+ )
96+ end
8797
8898 M.highlight_wrap(list_pos, row, col, #line)
8999 vim.defer_fn(function()
@@ -132,8 +142,7 @@ M.highlight_wrap = function(tbl_pos, row, col, end_col)
132142 M.ns_fast_wrap,
133143 config.highlight_grey,
134144 { row, col },
135− { row, end_col },
136− {}
145+ { row, end_col }
137146 )
138147 end
139148 for _, pos in ipairs(tbl_pos) do
lua/nvim-autopairs/rule.lua+29−23
@@ -1,4 +1,5 @@
11local Cond = require('nvim-autopairs.conds')
2+local log = require('nvim-autopairs._log')
23
34--- @class Rule
45--- @field start_pair string
@@ -7,8 +8,8 @@ local Cond = require('nvim-autopairs.conds')
78--- @field map_cr_func function dynamic change mapping_cr
89--- @field end_pair_length number change end_pair length for key map like <left>
910--- @field key_map string|nil equal nil mean it will skip on autopairs map
10−--- @field filetypes table|nil
11−--- @field not_filetypes table|nil
11+--- @field filetypes table
12+--- @field not_filetypes table
1213--- @field is_regex boolean use regex to compare
1314--- @field is_multibyte boolean
1415--- @field is_endwise boolean only use on end_wise
@@ -32,21 +33,21 @@ function Rule.new(...)
3233 end
3334 end
3435 opt = vim.tbl_extend('force', {
35− key_map = "",
36− start_pair = nil,
37− end_pair = nil,
38− end_pair_func = false,
39− filetypes = nil,
40− not_filetypes = nil,
41− move_cond = nil,
42− del_cond = {},
43− cr_cond = {},
44− pair_cond = {},
45− is_endwise = false,
46− is_regex = false,
47− is_multibyte = false,
36+ key_map = "",
37+ start_pair = nil,
38+ end_pair = nil,
39+ end_pair_func = false,
40+ filetypes = nil,
41+ not_filetypes = nil,
42+ move_cond = nil,
43+ del_cond = {},
44+ cr_cond = {},
45+ pair_cond = {},
46+ is_endwise = false,
47+ is_regex = false,
48+ is_multibyte = false,
4849 end_pair_length = nil,
49− }, opt) or {}
50+ }, opt)
5051
5152 ---@param rule Rule
5253 local function constructor(rule)
@@ -70,7 +71,6 @@ function Rule.new(...)
7071 end
7172 return rule
7273 end
73−
7474 local r = setmetatable(opt, { __index = Rule })
7575 return constructor(r)
7676end
@@ -113,6 +113,7 @@ function Rule:get_map_cr(opts)
113113 return '<c-g>u<cr><c-c>O'
114114end
115115
116+
116117function Rule:replace_map_cr(value)
117118 self.map_cr_func = value
118119 return self
@@ -146,33 +147,38 @@ function Rule:set_end_pair_length(length)
146147end
147148
148149function Rule:with_move(cond)
149− if self.move_cond == nil then self.move_cond = {} end
150+ if self.move_cond == nil then self.move_cond = {}end
150151 table.insert(self.move_cond, cond)
151152 return self
152153end
153154
154155function Rule:with_del(cond)
155− if self.del_cond == nil then self.del_cond = {} end
156+ if self.del_cond == nil then self.del_cond = {}end
156157 table.insert(self.del_cond, cond)
157158 return self
158159end
159160
160161function Rule:with_cr(cond)
161− if self.cr_cond == nil then self.cr_cond = {} end
162+ if self.cr_cond == nil then self.cr_cond = {}end
162163 table.insert(self.cr_cond, cond)
163164 return self
164165end
165166
166167---add condition to rule
167168---@param cond any
168−---@param pos number|nil = 1. It have higher priority to another condition
169+---@param pos number = 1. It have higher priority to another condition
169170---@return Rule
170171function Rule:with_pair(cond, pos)
171− if self.pair_cond == nil then self.pair_cond = {} end
172− self.pair_cond[pos or (#self.pair_cond+1)] = cond
172+ if self.pair_cond == nil then self.pair_cond = {}end
173+ if pos then
174+ table.insert(self.pair_cond, pos, cond)
175+ else
176+ table.insert(self.pair_cond, cond)
177+ end
173178 return self
174179end
175180
181+
176182function Rule:only_cr(cond)
177183 self.key_map = nil
178184 self.pair_cond = false
lua/nvim-autopairs/rules/basic.lua+4−10
@@ -36,30 +36,24 @@ local function setup(opt)
3636 Rule("```.*$", "```", { 'markdown', 'vimwiki', 'rmarkdown', 'rmd', 'pandoc' })
3737 :only_cr()
3838 :use_regex(true),
39− Rule('"""', '"""', { 'python', 'elixir', 'julia', 'kotlin' })
40− :with_pair(cond.not_before_char('"', 3)),
41− Rule("'''", "'''", { 'python' })
42− :with_pair(cond.not_before_char('"', 3)),
39+ Rule('"""', '"""', { 'python', 'elixir', 'julia', 'kotlin' }),
4340 basic("'", "'", '-rust')
4441 :with_pair(cond.not_before_regex("%w")),
4542 basic("'", "'", 'rust')
4643 :with_pair(cond.not_before_regex("[%w<&]"))
4744 :with_pair(cond.not_after_text(">")),
4845 basic("`", "`"),
49− basic('"', '"', '-vim'),
50− basic('"', '"', 'vim')
46+ basic('"', '"','-vim'),
47+ basic('"', '"','vim')
5148 :with_pair(cond.not_before_regex("^%s*$", -1)),
5249 bracket("(", ")"),
5350 bracket("[", "]"),
5451 bracket("{", "}"),
5552 Rule(">[%w%s]*$", "^%s*</",
56− { 'html', 'typescript', 'typescriptreact', 'javascript', 'javascriptreact', 'svelte', 'vue', 'xml',
57− 'rescript' })
53+ { 'html', 'typescript', 'typescriptreact', 'javascript' , 'javascriptreact', 'svelte', 'vue', 'xml', 'rescript'})
5854 :only_cr()
5955 :use_regex(true)
6056 }
6157 return rules
6258end
63−
6459return { setup = setup }
65−
lua/nvim-autopairs/utils.lua+2−3
@@ -11,8 +11,7 @@ M.key = {
1111 join_left = "<c-g>U<left>",
1212 join_right = "<c-g>U<right>",
1313 undo_sequence = "<c-g>u",
14− noundo_sequence = "<c-g>U",
15− abbr = "<c-]>"
14+ noundo_sequence = "<c-g>U"
1615}
1716
1817M.set_vchar = function(text)
@@ -74,7 +73,7 @@ M.is_in_quotes = function (line, pos, quote_type)
7473end
7574
7675M.is_attached = function(bufnr)
77− local _, check = pcall(api.nvim_buf_get_var, bufnr or 0, "nvim-autopairs")
76+ local _, check = pcall(api.nvim_buf_get_var, bufnr, "nvim-autopairs")
7877 return check == 1
7978end
8079
tests/nvim-autopairs_spec.lua+1−62
@@ -1,3 +1,4 @@
1+local helpers = {}
12local npairs = require('nvim-autopairs')
23local Rule = require('nvim-autopairs.rule')
34local cond = require('nvim-autopairs.conds')
@@ -49,13 +50,6 @@ local data = {
4950 before = [[""| ]],
5051 after = [["""|""" ]]
5152 },
52− {
53− name = "don't repeat python quote" ,
54− filetype = "python",
55− key = [["]],
56− before = [[a"""|""" ]],
57− after = [[a""""|"" ]]
58− },
5953
6054 {
6155 name = "add markdown quote" ,
@@ -243,43 +237,6 @@ local data = {
243237 "]"
244238 }
245239 },
246− {
247− name = "move ) inside nested function call" ,
248− filetype="javascript",
249− key = [[)]],
250− before = {
251− "fn(fn(|))",
252− },
253− after = {
254− "fn(fn()|)",
255− }
256− },
257− {
258− name = "move } inside singleline function's params" ,
259− filetype="javascript",
260− key = [[}]],
261− before = {
262− "({|}) => {}",
263− },
264− after = {
265− "({}|) => {}",
266− }
267− },
268− {
269− name = "move } inside multiline function's params" ,
270− filetype="javascript",
271− key = [[}]],
272− before = {
273− "({|}) => {",
274− "",
275− "}",
276− },
277− after = {
278− "({}|) => {",
279− "",
280− "}",
281− }
282− },
283240 {
284241 name = "breakline on markdown " ,
285242 filetype="markdown",
@@ -688,24 +645,6 @@ local data = {
688645 [[}]],
689646 },
690647 },
691− {
692− name='open bracker on back tick',
693− key = [[(]],
694− before = [[ |`abcd`]],
695− after = [[ (`abcd`) ]]
696− },
697− {
698− name='should not add bracket on line have bracket ',
699− key = [[(]],
700− before = [[ |(abcd))]],
701− after = [[ ((abcd)) ]]
702− },
703− {
704− name='not add bracket on line have bracket ',
705− key = [[(]],
706− before = [[ |(abcd) ( visual)]],
707− after = [[ ()(abcd) ( visual)]]
708− }
709648}
710649
711650local run_data = _G.Test_filter(data)
tests/test_utils.lua+7−8
@@ -27,7 +27,6 @@ utils.feed = function(text, num)
2727 result = result .. text
2828 end
2929 api.nvim_feedkeys(
30− ---@diagnostic disable-next-line: param-type-mismatch
3130 api.nvim_replace_termcodes(result, true, false, true),
3231 'x',
3332 true
@@ -60,7 +59,8 @@ local compare_text = function(linenr, text_after, name, cursor_add, end_cursor)
6059 )
6160 for i = 1, #text_after, 1 do
6261 local t = string.gsub(text_after[i], '%|', '')
63− if t
62+ if
63+ t
6464 and new_text[i]
6565 and t:gsub('%s+$', '') ~= new_text[i]:gsub('%s+$', '')
6666 then
@@ -92,7 +92,7 @@ end
9292
9393_G.Test_withfile = function(test_data, cb)
9494 for _, value in pairs(test_data) do
95− it('test ' .. value.name, function(_)
95+ it('test ' .. value.name, function(done)
9696 local text_before = {}
9797 value.linenr = value.linenr or 1
9898 local pos_before = {
@@ -103,11 +103,11 @@ _G.Test_withfile = function(test_data, cb)
103103 value.before = { value.before }
104104 end
105105 for index, text in pairs(value.before) do
106− local txt = string.gsub(tostring(text), '%|', '')
106+ local txt = string.gsub(text, '%|', '')
107107 table.insert(text_before, txt)
108− if string.match(tostring(text), '%|') then
109− if string.find(tostring(text), '%|') then
110− pos_before.colnr = string.find(tostring(text), '%|')
108+ if string.match(text, '%|') then
109+ if string.find(text, '%|') then
110+ pos_before.colnr = string.find(text, '%|')
111111 pos_before.linenr = value.linenr + index - 1
112112 end
113113 end
@@ -120,7 +120,6 @@ _G.Test_withfile = function(test_data, cb)
120120 if cb.before_each then
121121 cb.before_each(value)
122122 end
123− ---@diagnostic disable-next-line: missing-parameter
124123 if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then
125124 vim.cmd(':e ' .. value.filepath)
126125 if value.filetype then