on master help sign in
17 files changed+880−326
since splitsnapshots
unifiedsplit
.github/workflows/ci.yml+1−1 .gitignore+1 README.md+87−11 doc/nvim-autopairs-rules.txt+306−64 doc/nvim-autopairs.txt+76−11 lua/nvim-autopairs.lua+95−111 lua/nvim-autopairs/_log.lua+8−8 lua/nvim-autopairs/completion/cmp.lua+58−41 lua/nvim-autopairs/completion/handlers.lua+52 lua/nvim-autopairs/conds.lua+77−14 lua/nvim-autopairs/fastwrap.lua+11−20 lua/nvim-autopairs/rule.lua+23−30 lua/nvim-autopairs/rules/basic.lua+11−5 lua/nvim-autopairs/utils.lua+3−2 tests/minimal.vim+1 tests/nvim-autopairs_spec.lua+62−1 tests/test_utils.lua+8−7
.github/workflows/ci.yml+1−1
@@ -11,7 +11,7 @@ jobs:
1111 matrix:
1212 include:
1313 - os: ubuntu-20.04
14− url: https://github.com/neovim/neovim/releases/download/v0.5.0/nvim-linux64.tar.gz
14+ url: https://github.com/neovim/neovim/releases/download/v0.7.0/nvim-linux64.tar.gz
1515 manager: sudo apt-get
1616 packages: -y fd-find
1717 steps:
.gitignorenew file+1
@@ -0,0 +1 @@
1+doc/tags
README.md+87−11
@@ -2,11 +2,29 @@
22
33A super powerful autopair plugin for Neovim that supports multiple characters.
44
5−Requires neovim 0.5+
5+Requires neovim 0.7
66
7−### Setup
8−``` lua
9−require('nvim-autopairs').setup{}
7+## Installation
8+
9+Install the plugin with your preferred package manager:
10+
11+### [vim-plug](https://github.com/junegunn/vim-plug)
12+
13+```vim
14+Plug 'windwp/nvim-autopairs'
15+
16+lua << EOF
17+require("nvim-autopairs").setup {}
18+EOF
19+```
20+
21+### [packer](https://github.com/wbthomason/packer.nvim)
22+
23+```lua
24+use {
25+ "windwp/nvim-autopairs",
26+ config = function() require("nvim-autopairs").setup {} end
27+}
1028```
1129
1230## Default values
@@ -15,11 +33,14 @@ require('nvim-autopairs').setup{}
1533local disable_filetype = { "TelescopePrompt" }
1634local disable_in_macro = false -- disable when recording or executing a macro
1735local disable_in_visualblock = false -- disable when insert after visual block mode
18−local ignored_next_char = string.gsub([[ [%w%%%'%[%"%.] ]],"%s+", "")
36+local disable_in_replace_mode = true
37+local ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=]
1938local enable_moveright = true
2039local enable_afterquote = true -- add bracket pairs after quote
2140local enable_check_bracket_line = true --- check bracket in same line
2241local enable_bracket_in_quote = true --
42+local enable_abbr = false -- trigger abbreviation
43+local break_undo = true -- switch for basic rule break undo sequence
2344local check_ts = false
2445local map_cr = true
2546local map_bs = true -- map the <BS> key
@@ -58,13 +79,54 @@ Check readme.md on nvim-cmp repo.
5879-- If you want insert `(` after select function or method item
5980local cmp_autopairs = require('nvim-autopairs.completion.cmp')
6081local cmp = require('cmp')
61−cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done({ map_char = { tex = '' } }))
62−
82+cmp.event:on(
83+ 'confirm_done',
84+ cmp_autopairs.on_confirm_done()
85+)
86+```
6387
64−-- add a lisp filetype (wrap my-function), FYI: Hardcoded = { "clojure", "clojurescript", "fennel", "janet" }
65−cmp_autopairs.lisp[#cmp_autopairs.lisp+1] = "racket"
88+You can customize the kind of completion to add `(` or any character.
6689
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+)
67126```
127+
128+Don't use `nil` to disable a filetype. If a filetype is `nil` then `*` is used as fallback.
129+
68130</details>
69131<details>
70132<summary><b>coq_nvim</b></summary>
@@ -216,6 +278,7 @@ You can use treesitter to check for a pair.
216278
217279```lua
218280local npairs = require("nvim-autopairs")
281+local Rule = require('nvim-autopairs.rule')
219282
220283npairs.setup({
221284 check_ts = true,
@@ -277,9 +340,17 @@ Before Input After
277340 require('nvim-autopairs').enable()
278341 require('nvim-autopairs').remove_rule('(') -- remove rule (
279342 require('nvim-autopairs').clear_rules() -- clear all rules
280− require('nvim-autopairs').get_rule('"') -- get rule " then modify it
343+ -- get rule " then modify it. It can return a list of rule or just a rule
344+ require('nvim-autopairs').get_rule('"')
345+```
281346
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("["}))
282352```
353+
283354### FastWrap
284355
285356``` text
@@ -300,7 +371,7 @@ npairs.setup({
300371 fast_wrap = {
301372 map = '<M-e>',
302373 chars = { '{', '[', '(', '"', "'" },
303− pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], '%s+', ''),
374+ pattern = [=[[%'%"%)%>%]%)%}%,]]=],
304375 end_key = '$',
305376 keys = 'qwertyuiopzxcvbnmasdfghjkl',
306377 check_comma = true,
@@ -320,3 +391,8 @@ npairs.setup({
320391
321392### Custom rules
322393[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+306−64
@@ -3,94 +3,134 @@
33==============================================================================
44Table of Contents *nvim-autopairs-rules-table-of-contents*
55
6− - Define rule with a pairs |nvim-autopairs-rules-define-rule-with-a-pairs|
7− - Rules |nvim-autopairs-rules-rules|
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|
815
9−DEFINE RULE WITH A PAIRS *nvim-autopairs-rules-define-rule-with-a-pairs*
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+<
1028
11−Rule(begin_pair, end_pair, filetypes)
1229
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:
1332
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")`
33+>
34+ Rule("(", ")") -- Enabled for all filetypes
35+ Rule("(", ")", "markdown") -- As a string
36+ Rule("(", ")", {"markdown", "vim"}) -- As a table
37+<
1838
1939
20−RULES *nvim-autopairs-rules-rules*
40+Additionally, it is possible to specify filetypes where the rule should **not**
41+be enabled by prefixing it with a `-` character:
2142
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 │
43+>
44+ Rule("(", ")", "-markdown") -- All filetypes *except* markdown
45+<
3946
4047
41− *nvim-autopairs-rules-replace_endpair*
48+==============================================================================
49+2. Controlling rule behavior *nvim-autopairs-rules-controlling-rule-behavior*
4250
43−replace_endpair paramaters 2 of replace_endpair use to
44− combine with with_pair function
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.
4557
58+METHOD OVERVIEW *nvim-autopairs-rules-method-overview*
4659
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−<
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.
5763
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 │
5881
59−CONDITION ~
82+
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*
96+
97+nvim-autopairs comes with a variety of common predicates ready to use simply by
98+including:
6099
61100>
62101 local cond = require('nvim-autopairs.conds')
63102<
64103
65104
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−
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 │
87125
88126
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.
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.
91130
131+TREESITTER CONDITIONS ~
92132
93−TREESITTER CONDITION ~
133+Predicates based on the state of the Treesitter graph can be used by including:
94134
95135>
96136 local ts_conds = require('nvim-autopairs.ts-conds')
@@ -102,6 +142,208 @@ TREESITTER CONDITION ~
102142│is_not_ts_node({node_table})│check not in treesitter node │
103143
104144
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+
105347Generated by panvimdoc <https://github.com/kdheepak/panvimdoc>
106348
107349vim:tw=78:ts=8:noet:ft=help:norl:
doc/nvim-autopairs.txt+76−11
@@ -4,6 +4,7 @@
44Table of Contents *nvim-autopairs-table-of-contents*
55
66 - nvim-autopairs |nvim-autopairs-nvim-autopairs|
7+ - Installation |nvim-autopairs-installation|
78 - Default values |nvim-autopairs-default-values|
89
910NVIM-AUTOPAIRS *nvim-autopairs-nvim-autopairs*
@@ -12,10 +13,28 @@ A super powerful autopair plugin for Neovim that supports multiple characters.
1213
1314Requires neovim 0.5+
1415
15−SETUP ~
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> ~
1621
1722>
18− require('nvim-autopairs').setup{}
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+ }
1938<
2039
2140
@@ -25,11 +44,12 @@ DEFAULT VALUES *nvim-autopairs-default-values*
2544 local disable_filetype = { "TelescopePrompt" }
2645 local disable_in_macro = false -- disable when recording or executing a macro
2746 local disable_in_visualblock = false -- disable when insert after visual block mode
28− local ignored_next_char = string.gsub([[ [%w%%%'%[%"%.] ]],"%s+", "")
47+ local ignored_next_char = [=[[%w%%%'%[%"%.]]=]
2948 local enable_moveright = true
3049 local enable_afterquote = true -- add bracket pairs after quote
3150 local enable_check_bracket_line = true --- check bracket in same line
3251 local enable_bracket_in_quote = true --
52+ local break_undo = true -- switch for basic rule break undo sequence
3353 local check_ts = false
3454 local map_cr = true
3555 local map_bs = true -- map the <BS> key
@@ -72,14 +92,59 @@ Check readme.md on nvim-cmp repo.
7292 -- If you want insert `(` after select function or method item
7393 local cmp_autopairs = require('nvim-autopairs.completion.cmp')
7494 local cmp = require('cmp')
75− cmp.event:on( 'confirm_done', cmp_autopairs.on_confirm_done({ map_char = { tex = '' } }))
76−
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')
77108
78− -- add a lisp filetype (wrap my-function), FYI: Hardcoded = { "clojure", "clojurescript", "fennel", "janet" }
79− cmp_autopairs.lisp[#cmp_autopairs.lisp+1] = "racket"
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+ )
80142<
81143
82144
145+Don’t use `nil` to disable a filetype. If a filetype is `nil` then `*` is
146+used as fallback.
147+
83148coq_nvim ~
84149
85150>
@@ -131,9 +196,8 @@ without completion plugin ~
131196<
132197
133198
134−Mapping `<CR>` another completion plugin
135− <https://github.com/windwp/nvim-autopairs/wiki/Completion-plugin>
136−
199+another completion plugin
200+<https://github.com/windwp/nvim-autopairs/wiki/Completion-plugin>
137201
138202If you have a problem with indent after you press `<CR>` please check the
139203settings of treesitter indent or install a plugin that has indent support for
@@ -234,6 +298,7 @@ You can use treesitter to check for a pair.
234298
235299>
236300 local npairs = require("nvim-autopairs")
301+ local Rule = require('nvim-autopairs.rule')
237302
238303 npairs.setup({
239304 check_ts = true,
@@ -328,7 +393,7 @@ FASTWRAP ~
328393 fast_wrap = {
329394 map = '<M-e>',
330395 chars = { '{', '[', '(', '"', "'" },
331− pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], '%s+', ''),
396+ pattern = [=[[%'%"%)%>%]%)%}%,]]=],
332397 end_key = '$',
333398 keys = 'qwertyuiopzxcvbnmasdfghjkl',
334399 check_comma = true,
lua/nvim-autopairs.lua+95−111
@@ -19,12 +19,15 @@ local default = {
1919 disable_filetype = { 'TelescopePrompt', 'spectre_panel' },
2020 disable_in_macro = false,
2121 disable_in_visualblock = false,
22− ignored_next_char = string.gsub([[ [%w%%%'%[%"%.] ]], '%s+', ''),
22+ disable_in_replace_mode = true,
23+ ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=],
24+ break_undo = true,
2325 check_ts = false,
2426 enable_moveright = true,
2527 enable_afterquote = true,
2628 enable_check_bracket_line = true,
2729 enable_bracket_in_quote = true,
30+ enable_abbr = false,
2831 ts_config = {
2932 lua = { 'string', 'source' },
3033 javascript = { 'string', 'template_string' },
@@ -51,18 +54,21 @@ M.setup = function(opt)
5154 end
5255
5356 M.force_attach()
54−
55− api.nvim_exec(
56− [[
57− augroup autopairs_buf
58− autocmd!
59− autocmd BufEnter,BufWinEnter * lua require("nvim-autopairs").on_attach()
60− autocmd BufDelete * lua require("nvim-autopairs").set_buf_rule(nil,tonumber(vim.fn.expand("<abuf>")))
61− autocmd FileType * lua require("nvim-autopairs").force_attach()
62− augroup end
63− ]],
64− false
65− )
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+ })
6672end
6773
6874M.add_rule = function(rule)
@@ -97,10 +103,10 @@ M.remove_rule = function(pair)
97103 if r.start_pair ~= pair then
98104 table.insert(state_tbl, r)
99105 elseif r.key_map and r.key_map ~= '' then
100− vim.api.nvim_buf_del_keymap(0, 'i', r.key_map)
106+ api.nvim_buf_del_keymap(0, 'i', r.key_map)
101107 end
102108 end
103− M.set_buf_rule(state_tbl)
109+ M.set_buf_rule(state_tbl, 0)
104110 end
105111 M.force_attach()
106112end
@@ -131,6 +137,15 @@ M.force_attach = function(bufnr)
131137 M.on_attach(bufnr)
132138end
133139
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+
134149local function is_disable()
135150 if M.state.disabled then
136151 return true
@@ -145,22 +160,23 @@ local function is_disable()
145160 return true
146161 end
147162
148− if
149− M.config.disable_in_macro
163+ if M.config.disable_in_macro
150164 and (vim.fn.reg_recording() ~= '' or vim.fn.reg_executing() ~= '')
151165 then
152166 return true
153167 end
154168
169+ if M.config.disable_in_replace_mode and vim.api.nvim_get_mode().mode == "R" then
170+ return true
171+ end
172+
155173 if M.config.disable_in_visualblock and utils.is_block_wise_mode() then
156174 return true
157175 end
158176
159177 if utils.check_filetype(M.config.disable_filetype, vim.bo.filetype) then
160− -- should have a way to remove the mapping when vim.bo.filetype = ''
161− -- now we only remove a rule
162− -- the event FileType happen after BufEnter
163− M.set_buf_rule({})
178+ del_keymaps()
179+ M.set_buf_rule({}, 0)
164180 return true
165181 end
166182 return false
@@ -168,14 +184,14 @@ end
168184
169185---@return table <number, Rule>
170186M.get_buf_rules = function(bufnr)
171− return M.state.rules[bufnr or vim.api.nvim_get_current_buf()] or {}
187+ return M.state.rules[bufnr or api.nvim_get_current_buf()] or {}
172188end
173189
174−---@param rules table list or rule
190+---@param rules nil|table list or rule
175191---@param bufnr number buffer number
176192M.set_buf_rule = function(rules, bufnr)
177193 if bufnr == 0 or bufnr == nil then
178− bufnr = vim.api.nvim_get_current_buf()
194+ bufnr = api.nvim_get_current_buf()
179195 end
180196 M.state.rules[bufnr] = rules
181197end
@@ -189,8 +205,7 @@ M.on_attach = function(bufnr)
189205
190206 local rules = {}
191207 for _, rule in pairs(M.config.rules) do
192− if
193− utils.check_filetype(rule.filetypes, vim.bo.filetype)
208+ if utils.check_filetype(rule.filetypes, vim.bo.filetype)
194209 and utils.check_not_filetype(rule.not_filetypes, vim.bo.filetype)
195210 then
196211 table.insert(rules, rule)
@@ -226,78 +241,50 @@ M.on_attach = function(bufnr)
226241 if utils.is_attached(bufnr) then
227242 return
228243 end
244+ del_keymaps()
229245 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
230256 for _, rule in pairs(rules) do
231257 if rule.key_map ~= nil then
232258 if rule.is_regex == false then
233259 if rule.key_map == '' then
234260 rule.key_map = rule.start_pair:sub(#rule.start_pair)
235261 end
236− local key = string.format('"%s"', rule.key_map)
237− if rule.key_map == '"' then
238− key = [['"']]
239− end
240− local mapping = string.format('v:lua.MPairs.autopairs_map(%d,%s)', bufnr, key)
241− api.nvim_buf_set_keymap(
242− bufnr,
243− 'i',
244− rule.key_map,
245− mapping,
246− { expr = true, noremap = true }
247− )
248−
262+ expr_map(rule.key_map)
249263 local key_end = rule.key_end or rule.end_pair:sub(1, 1)
250264 if #key_end >= 1 and key_end ~= rule.key_map and rule.move_cond ~= nil then
251− mapping = string.format(
252− [[v:lua.MPairs.autopairs_map(%d, '%s')]],
253− bufnr,
254− key_end
255− )
256− vim.api.nvim_buf_set_keymap(
257− bufnr,
258− 'i',
259− key_end,
260− mapping,
261− { expr = true, noremap = true }
262− )
265+ expr_map(key_end)
263266 end
264267 else
265268 if rule.key_map ~= '' then
266− local mapping = string.format(
267− "v:lua.MPairs.autopairs_map(%d,'%s')",
268− bufnr,
269− rule.key_map
270− )
271− api.nvim_buf_set_keymap(
272− bufnr,
273− 'i',
274− rule.key_map,
275− mapping,
276− { expr = true, noremap = true }
277− )
269+ expr_map(rule.key_map)
278270 elseif rule.is_endwise == false then
279271 enable_insert_auto = true
280272 end
281273 end
282274 end
283275 end
276+ api.nvim_buf_set_var(bufnr, 'autopairs_keymaps', autopairs_keymaps)
284277
285278 if enable_insert_auto then
286279 -- capture all key use it to trigger regex pairs
287280 -- it can make an issue with paste from register
288− api.nvim_exec(
289− string.format(
290− [[
291− augroup autopairs_insert_%d
292− autocmd!
293− autocmd InsertCharPre <buffer=%d> call luaeval("require('nvim-autopairs').autopairs_insert(%d, _A)", v:char)
294− augroup end ]],
295− bufnr,
296− bufnr,
297− bufnr
298− ),
299− false
300− )
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+ })
301288 end
302289
303290 if M.config.fast_wrap and M.config.fast_wrap.map then
@@ -315,7 +302,7 @@ M.on_attach = function(bufnr)
315302 bufnr,
316303 'i',
317304 '<bs>',
318− string.format('v:lua.MPairs.autopairs_bs(%d)', bufnr),
305+ 'v:lua.MPairs.autopairs_bs()',
319306 { expr = true, noremap = true }
320307 )
321308 end
@@ -326,7 +313,7 @@ M.on_attach = function(bufnr)
326313 "i",
327314 utils.key.c_h,
328315 string.format("v:lua.MPairs.autopairs_c_h(%d)", bufnr),
329− {expr = true, noremap = true}
316+ { expr = true, noremap = true }
330317 )
331318 end
332319
@@ -346,7 +333,7 @@ local autopairs_delete = function(bufnr, key)
346333 if is_disable() then
347334 return utils.esc(key)
348335 end
349− bufnr = bufnr or 0
336+ bufnr = bufnr or api.nvim_get_current_buf()
350337 local line = utils.text_get_current_line(bufnr)
351338 local _, col = utils.get_cursor()
352339 local rules = M.get_buf_rules(bufnr)
@@ -359,22 +346,23 @@ local autopairs_delete = function(bufnr, key)
359346 #rule.end_pair,
360347 rule.is_regex
361348 )
362− if
363− utils.compare(rule.start_pair, prev_char, rule.is_regex)
349+ if utils.compare(rule.start_pair, prev_char, rule.is_regex)
364350 and utils.compare(rule.end_pair, next_char, rule.is_regex)
365351 and rule:can_del({
366352 ts_node = M.state.ts_node,
353+ rule = rule,
367354 bufnr = bufnr,
368355 prev_char = prev_char,
369356 next_char = next_char,
370357 line = line,
358+ col = col,
371359 })
372360 then
373361 local input = ''
374− for _ = 1, vim.api.nvim_strwidth(rule.start_pair), 1 do
362+ for _ = 1, api.nvim_strwidth(rule.start_pair), 1 do
375363 input = input .. utils.key.bs
376364 end
377− for _ = 1, vim.api.nvim_strwidth(rule.end_pair), 1 do
365+ for _ = 1, api.nvim_strwidth(rule.end_pair), 1 do
378366 input = input .. utils.key.del
379367 end
380368 return utils.esc('<c-g>U' .. input)
@@ -407,8 +395,8 @@ M.autopairs_map = function(bufnr, char)
407395 local rules = M.get_buf_rules(bufnr)
408396 for _, rule in pairs(rules) do
409397 if rule.start_pair then
410− if rule.key_map and rule.key_map:match('<.*>') then
411− new_text = line:sub(1, col) .. line:sub(col + 1, #line)
398+ if char:match('<.*>') then
399+ new_text = line
412400 add_char = 0
413401 else
414402 new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line)
@@ -437,8 +425,7 @@ M.autopairs_map = function(bufnr, char)
437425 -- log.debug("start_pair" .. rule.start_pair)
438426 -- log.debug('prev_char' .. prev_char)
439427 -- log.debug('next_char' .. next_char)
440− if
441− utils.compare(rule.end_pair, next_char, rule.is_regex)
428+ if utils.compare(rule.end_pair, next_char, rule.is_regex)
442429 and rule:can_move(cond_opt)
443430 then
444431 local end_pair = rule:get_end_pair(cond_opt)
@@ -446,8 +433,8 @@ M.autopairs_map = function(bufnr, char)
446433 return utils.esc(utils.repeat_key(utils.key.join_right, end_pair_length))
447434 end
448435
449− if
450− utils.compare(rule.start_pair, prev_char, rule.is_regex)
436+ if rule.key_map == char
437+ and utils.compare(rule.start_pair, prev_char, rule.is_regex)
451438 and rule:can_pair(cond_opt)
452439 then
453440 local end_pair = rule:get_end_pair(cond_opt)
@@ -460,16 +447,19 @@ M.autopairs_map = function(bufnr, char)
460447 if end_pair:match('<.*>') then
461448 end_pair = utils.esc(end_pair)
462449 end
463− local result= char .. end_pair .. utils.esc(move_text)
450+ local result = char .. end_pair .. utils.esc(move_text)
464451 if rule.is_undo then
465− result = utils.esc(utils.key.undo_sequence) .. result..utils.esc(utils.key.undo_sequence)
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
466456 end
467457 log.debug("key_map :" .. result)
468458 return result
469459 end
470460 end
471461 end
472− return M.autopairs_afterquote(new_text, char)
462+ return M.autopairs_afterquote(new_text, utils.esc(char))
473463end
474464
475465M.autopairs_insert = function(bufnr, char)
@@ -511,8 +501,7 @@ M.autopairs_insert = function(bufnr, char)
511501 return false
512502 end
513503
514− if
515− utils.compare(rule.start_pair, prev_char, rule.is_regex)
504+ if utils.compare(rule.start_pair, prev_char, rule.is_regex)
516505 and rule:can_pair(cond_opt)
517506 then
518507 local end_pair = rule:get_end_pair(cond_opt)
@@ -556,35 +545,31 @@ M.autopairs_cr = function(bufnr)
556545 prev_char = prev_char,
557546 next_char = next_char,
558547 }
559−
560− local end_pair = rule:get_end_pair(cond_opt)
561− local end_pair_length = rule:get_end_pair_length(end_pair)
562−
563548 -- log.debug('prev_char' .. rule.start_pair)
564549 -- log.debug('prev_char' .. prev_char)
565550 -- log.debug('next_char' .. next_char)
566− if
567− rule.is_endwise
551+ if rule.is_endwise
568552 and utils.compare(rule.start_pair, prev_char, rule.is_regex)
569553 and rule:can_cr(cond_opt)
570554 then
555+ local end_pair = rule:get_end_pair(cond_opt)
556+ local end_pair_length = rule:get_end_pair_length(end_pair)
571557 return utils.esc(
572558 end_pair
573− .. utils.repeat_key(utils.key.join_left, end_pair_length)
574− -- FIXME do i need to re indent twice #118
575− .. '<cr><esc>====O'
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'
576562 )
577563 end
578564
579565 cond_opt.check_endwise_ts = false
580566
581− if
582− utils.compare(rule.start_pair, prev_char, rule.is_regex)
567+ if utils.compare(rule.start_pair, prev_char, rule.is_regex)
583568 and utils.compare(rule.end_pair, next_char, rule.is_regex)
584569 and rule:can_cr(cond_opt)
585570 then
586571 log.debug('do_cr')
587− return utils.esc(rule:get_map_cr({rule = rule, line = line, color = col, bufnr = bufnr}))
572+ return utils.esc(rule:get_map_cr({ rule = rule, line = line, color = col, bufnr = bufnr }))
588573 end
589574 end
590575 end
@@ -597,8 +582,7 @@ M.autopairs_afterquote = function(line, key_char)
597582 line = line or utils.text_get_current_line(0)
598583 local _, col = utils.get_cursor()
599584 local prev_char, next_char = utils.text_cusor_line(line, col + 1, 1, 1, false)
600− if
601− utils.is_bracket(prev_char)
585+ if utils.is_bracket(prev_char)
602586 and utils.is_quote(next_char)
603587 and not utils.is_in_quotes(line, col, next_char)
604588 then
@@ -616,7 +600,7 @@ M.autopairs_afterquote = function(line, key_char)
616600 is_prev_slash = char == '\\'
617601 end
618602 if count == 2 and index >= (#line - 2) then
619− local rules = M.get_buf_rules(vim.api.nvim_get_current_buf())
603+ local rules = M.get_buf_rules(api.nvim_get_current_buf())
620604 for _, rule in pairs(rules) do
621605 if rule.start_pair == prev_char and char_end ~= rule.end_pair then
622606 local new_text = line:sub(0, index)
@@ -648,13 +632,13 @@ end
648632
649633M.map_cr = function()
650634 M.completion_confirm = function()
651− if vim.fn.pumvisible() ~= 0 then
635+ if vim.fn.pumvisible() ~= 0 then
652636 return M.esc("<cr>")
653637 else
654638 return M.autopairs_cr()
655639 end
656640 end
657− vim.api.nvim_set_keymap(
641+ api.nvim_set_keymap(
658642 'i',
659643 '<CR>',
660644 '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+}
17if _G.__is_log then
28 return require('plenary.log').new {
39 plugin = 'nvim-autopairs',
410 level = (_G.__is_log == true and 'debug') or 'warn',
5− }
6−else
7− return{
8− debug = function(_) end,
9− info = function(_) end,
10− error = function(_) end,
11−
12− }
11+ } or empty
1312end
13+return empty
lua/nvim-autopairs/completion/cmp.lua+58−41
@@ -1,60 +1,77 @@
1−local utils = require('nvim-autopairs.utils')
2−
1+local autopairs = require('nvim-autopairs')
2+local handlers = require('nvim-autopairs.completion.handlers')
33local cmp = require('cmp')
44
5+local Kind = cmp.lsp.CompletionItemKind
6+
57local M = {}
68
7−M.lisp = { "clojure", "clojurescript", "fennel", "janet" }
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+}
844
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 {})
45+M.on_confirm_done = function(opts)
46+ opts = vim.tbl_deep_extend('force', {
47+ filetypes = M.filetypes
48+ }, opts or {})
2849
2950 return function(evt)
3051 local entry = evt.entry
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)
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')
3455 local item = entry:get_completion_item()
3556
36− local char = opt.map_char[vim.bo.filetype] or '('
37− if char == '' then
38− return
57+ -- Without options and fallback
58+ if not opts.filetypes[filetype] and not opts.filetypes["*"] then
59+ return
3960 end
4061
41− if ignore_append(char, opt.kinds, next_char, prev_char, item) or evt.commit_character == char then
42− return
62+ if opts.filetypes[filetype] == false then
63+ return
4364 end
4465
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
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)
5072 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)
5773 end
5874 end
5975end
76+
6077return M
lua/nvim-autopairs/completion/handlers.luanew file+52
@@ -0,0 +1,52 @@
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+77−14
@@ -1,5 +1,16 @@
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
314
415local cond = {}
516
@@ -31,6 +42,7 @@ cond.before_regex = function(regex, length)
3142 if not regex then
3243 return cond.none()
3344 end
45+ ---@param opts CondOpts
3446 return function(opts)
3547 log.debug('before_regex')
3648 if length < 0 then
@@ -46,6 +58,7 @@ end
4658
4759cond.before_text = function(text)
4860 local length = #text
61+ ---@param opts CondOpts
4962 return function(opts)
5063 log.debug('before_text')
5164 local str = utils.text_sub_char(opts.line, opts.col - 1, -length)
@@ -58,6 +71,7 @@ end
5871
5972cond.after_text = function(text)
6073 local length = #text
74+ ---@param opts CondOpts
6175 return function(opts)
6276 log.debug('after_text')
6377 local str = utils.text_sub_char(opts.line, opts.col, length)
@@ -73,6 +87,7 @@ cond.after_regex = function(regex, length)
7387 if not regex then
7488 return cond.none()
7589 end
90+ ---@param opts CondOpts
7691 return function(opts)
7792 log.debug('after_regex')
7893 if length < 0 then
@@ -99,6 +114,7 @@ end
99114
100115cond.not_after_text = function(text)
101116 local length = #text
117+ ---@param opts CondOpts
102118 return function(opts)
103119 log.debug('not_after_text')
104120 local str = utils.text_sub_char(opts.line, opts.col, length)
@@ -113,6 +129,7 @@ cond.not_before_regex = function(regex, length)
113129 if not regex then
114130 return cond.none()
115131 end
132+ ---@param opts CondOpts
116133 return function(opts)
117134 log.debug('not_before_regex')
118135 if length < 0 then
@@ -130,6 +147,7 @@ cond.not_after_regex = function(regex, length)
130147 if not regex then
131148 return cond.none()
132149 end
150+ ---@param opts CondOpts
133151 return function(opts)
134152 log.debug('not_after_regex')
135153 if length < 0 then
@@ -156,16 +174,41 @@ local function count_bracket_char(line, prev_char, next_char)
156174 return count_prev_char, count_next_char
157175end
158176
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+
159198cond.is_bracket_line = function()
199+ ---@param opts CondOpts
160200 return function(opts)
161201 log.debug('is_bracket_line')
162− if utils.is_bracket(opts.char) and opts.next_char == opts.rule.end_pair then
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
163206 -- (( many char |)) => add
164207 -- ( many char |)) => not add
165208 local count_prev_char, count_next_char = count_bracket_char(
166209 opts.line,
167− opts.char,
168− opts.next_char
210+ opts.rule.start_pair,
211+ opts.rule.end_pair
169212 )
170213 if count_prev_char ~= count_next_char then
171214 return false
@@ -175,26 +218,27 @@ cond.is_bracket_line = function()
175218end
176219
177220cond.is_bracket_line_move = function()
221+ ---@param opts CondOpts
178222 return function(opts)
179223 log.debug('is_bracket_line_move')
180− if
181− utils.is_close_bracket(opts.char)
224+ if utils.is_close_bracket(opts.char)
182225 and opts.char == opts.rule.end_pair
183226 then
227+ -- (( many char |)) => move
184228 -- (( many char |) => not move
185− local count_prev_char, count_next_char = count_bracket_char(
229+ local is_balanced = is_brackets_balanced_around_position(
186230 opts.line,
187231 opts.rule.start_pair,
188− opts.char
232+ opts.char,
233+ opts.col
189234 )
190− if count_prev_char ~= 0 and count_prev_char > count_next_char then
191− return false
192− end
235+ return is_balanced
193236 end
194237 end
195238end
196239
197240cond.not_inside_quote = function()
241+ ---@param opts CondOpts
198242 return function(opts)
199243 log.debug('not_inside_quote')
200244 if utils.is_in_quotes(opts.text, opts.col - 1) then
@@ -204,6 +248,7 @@ cond.not_inside_quote = function()
204248end
205249
206250cond.is_inside_quote = function()
251+ ---@param opts CondOpts
207252 return function(opts)
208253 log.debug('is_inside_quote')
209254 if utils.is_in_quotes(opts.text, opts.col - 1) then
@@ -213,10 +258,10 @@ cond.is_inside_quote = function()
213258end
214259
215260cond.not_add_quote_inside_quote = function()
261+ ---@param opts CondOpts
216262 return function(opts)
217263 log.debug('not_add_quote_inside_quote')
218− if
219− utils.is_quote(opts.char)
264+ if utils.is_quote(opts.char)
220265 and utils.is_in_quotes(opts.text, opts.col - 1)
221266 then
222267 return false
@@ -225,6 +270,7 @@ cond.not_add_quote_inside_quote = function()
225270end
226271
227272cond.move_right = function()
273+ ---@param opts CondOpts
228274 return function(opts)
229275 log.debug('move_right')
230276 if opts.next_char == opts.char then
@@ -249,6 +295,7 @@ cond.move_right = function()
249295end
250296
251297cond.is_end_line = function()
298+ ---@param opts CondOpts
252299 return function(opts)
253300 log.debug('is_end_line')
254301 local end_text = opts.line:sub(opts.col + 1)
@@ -261,10 +308,10 @@ end
261308
262309--- Check the next char is quote and cursor is inside quote
263310cond.is_bracket_in_quote = function()
311+ ---@param opts CondOpts
264312 return function(opts)
265313 log.debug("is_bracket_in_quote")
266− if
267− utils.is_bracket(opts.char)
314+ if utils.is_bracket(opts.char)
268315 and utils.is_quote(opts.next_char)
269316 and utils.is_in_quotes(opts.line, opts.col - 1, opts.next_char)
270317 then
@@ -284,6 +331,22 @@ cond.not_filetypes = function(filetypes)
284331 end
285332end
286333
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+
287350---@deprecated
288351cond.not_after_regex_check = cond.not_after_regex
289352---@deprecated
lua/nvim-autopairs/fastwrap.lua+11−20
@@ -6,7 +6,7 @@ local M = {}
66local default_config = {
77 map = '<M-e>',
88 chars = { '{', '[', '(', '"', "'" },
9− pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], '%s+', ''),
9+ pattern = [=[[%'%"%)%>%]%)%}%,]]=],
1010 end_key = '$',
1111 keys = 'qwertyuiopzxcvbnmasdfghjkl',
1212 highlight = 'Search',
@@ -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 {})
22+ config = vim.tbl_extend('force', default_config, cfg or {}) or {}
2323 npairs.config.fast_wrap = config
2424 end
2525end
@@ -56,31 +56,23 @@ M.show = function(line)
5656 local index = 1
5757 local str_length = #line
5858 local offset = -1
59− local is_end_key = true
6059 for i = col + 2, #line, 1 do
6160 local char = line:sub(i, i)
6261 local char2 = line:sub(i - 1, i)
63− if
64− string.match(char, config.pattern)
62+ if string.match(char, config.pattern)
6563 or (char == ' ' and string.match(char2, '%w'))
6664 then
6765 local key = config.keys:sub(index, index)
6866 index = index + 1
69− if
70− utils.is_quote(char)
67+ if utils.is_quote(char)
7168 or (
72− utils.is_close_bracket(char)
69+ utils.is_close_bracket(char)
7370 and utils.is_in_quotes(line, col, prev_char)
7471 )
7572 then
7673 offset = 0
7774 end
7875
79− if i == str_length then
80− is_end_key = false
81− key = config.end_key
82− offset = 0
83− end
8476 table.insert(
8577 list_pos,
8678 { col = i + offset, key = key, char = char, pos = i }
@@ -88,12 +80,10 @@ M.show = function(line)
8880 end
8981 end
9082
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
83+ table.insert(
84+ list_pos,
85+ { col = str_length + 1, key = config.end_key, pos = str_length + 1 }
86+ )
9787
9888 M.highlight_wrap(list_pos, row, col, #line)
9989 vim.defer_fn(function()
@@ -142,7 +132,8 @@ M.highlight_wrap = function(tbl_pos, row, col, end_col)
142132 M.ns_fast_wrap,
143133 config.highlight_grey,
144134 { row, col },
145− { row, end_col }
135+ { row, end_col },
136+ {}
146137 )
147138 end
148139 for _, pos in ipairs(tbl_pos) do
lua/nvim-autopairs/rule.lua+23−30
@@ -1,5 +1,4 @@
11local Cond = require('nvim-autopairs.conds')
2−local log = require('nvim-autopairs._log')
32
43--- @class Rule
54--- @field start_pair string
@@ -8,8 +7,8 @@ local log = require('nvim-autopairs._log')
87--- @field map_cr_func function dynamic change mapping_cr
98--- @field end_pair_length number change end_pair length for key map like <left>
109--- @field key_map string|nil equal nil mean it will skip on autopairs map
11−--- @field filetypes table
12−--- @field not_filetypes table
10+--- @field filetypes table|nil
11+--- @field not_filetypes table|nil
1312--- @field is_regex boolean use regex to compare
1413--- @field is_multibyte boolean
1514--- @field is_endwise boolean only use on end_wise
@@ -33,21 +32,21 @@ function Rule.new(...)
3332 end
3433 end
3534 opt = vim.tbl_extend('force', {
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,
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,
4948 end_pair_length = nil,
50− }, opt)
49+ }, opt) or {}
5150
5251 ---@param rule Rule
5352 local function constructor(rule)
@@ -71,6 +70,7 @@ function Rule.new(...)
7170 end
7271 return rule
7372 end
73+
7474 local r = setmetatable(opt, { __index = Rule })
7575 return constructor(r)
7676end
@@ -87,7 +87,6 @@ function Rule:use_key(key_map)
8787end
8888
8989function Rule:use_undo(value)
90− if value ~= nil then value = true end
9190 self.is_undo = value
9291 return self
9392end
@@ -114,7 +113,6 @@ function Rule:get_map_cr(opts)
114113 return '<c-g>u<cr><c-c>O'
115114end
116115
117−
118116function Rule:replace_map_cr(value)
119117 self.map_cr_func = value
120118 return self
@@ -148,38 +146,33 @@ function Rule:set_end_pair_length(length)
148146end
149147
150148function Rule:with_move(cond)
151− if self.move_cond == nil then self.move_cond = {}end
149+ if self.move_cond == nil then self.move_cond = {} end
152150 table.insert(self.move_cond, cond)
153151 return self
154152end
155153
156154function Rule:with_del(cond)
157− if self.del_cond == nil then self.del_cond = {}end
155+ if self.del_cond == nil then self.del_cond = {} end
158156 table.insert(self.del_cond, cond)
159157 return self
160158end
161159
162160function Rule:with_cr(cond)
163− if self.cr_cond == nil then self.cr_cond = {}end
161+ if self.cr_cond == nil then self.cr_cond = {} end
164162 table.insert(self.cr_cond, cond)
165163 return self
166164end
167165
168166---add condition to rule
169167---@param cond any
170−---@param pos number = 1. It have higher priority to another condition
168+---@param pos number|nil = 1. It have higher priority to another condition
171169---@return Rule
172170function Rule:with_pair(cond, pos)
173− if self.pair_cond == nil then self.pair_cond = {}end
174− if pos then
175− table.insert(self.pair_cond, pos, cond)
176− else
177− table.insert(self.pair_cond, cond)
178− end
171+ if self.pair_cond == nil then self.pair_cond = {} end
172+ self.pair_cond[pos or (#self.pair_cond+1)] = cond
179173 return self
180174end
181175
182−
183176function Rule:only_cr(cond)
184177 self.key_map = nil
185178 self.pair_cond = false
lua/nvim-autopairs/rules/basic.lua+11−5
@@ -11,7 +11,7 @@ local function setup(opt)
1111 if #opt.ignored_next_char > 1 then
1212 rule:with_pair(cond.not_after_regex(opt.ignored_next_char))
1313 end
14− rule:use_undo(true)
14+ rule:use_undo(opt.break_undo)
1515 return rule
1616 end
1717
@@ -36,24 +36,30 @@ local function setup(opt)
3636 Rule("```.*$", "```", { 'markdown', 'vimwiki', 'rmarkdown', 'rmd', 'pandoc' })
3737 :only_cr()
3838 :use_regex(true),
39− Rule('"""', '"""', { 'python', 'elixir', 'julia', 'kotlin' }),
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)),
4043 basic("'", "'", '-rust')
4144 :with_pair(cond.not_before_regex("%w")),
4245 basic("'", "'", 'rust')
4346 :with_pair(cond.not_before_regex("[%w<&]"))
4447 :with_pair(cond.not_after_text(">")),
4548 basic("`", "`"),
46− basic('"', '"','-vim'),
47− basic('"', '"','vim')
49+ basic('"', '"', '-vim'),
50+ basic('"', '"', 'vim')
4851 :with_pair(cond.not_before_regex("^%s*$", -1)),
4952 bracket("(", ")"),
5053 bracket("[", "]"),
5154 bracket("{", "}"),
5255 Rule(">[%w%s]*$", "^%s*</",
53− { 'html', 'typescript', 'typescriptreact', 'javascript' , 'javascriptreact', 'svelte', 'vue', 'xml', 'rescript'})
56+ { 'html', 'typescript', 'typescriptreact', 'javascript', 'javascriptreact', 'svelte', 'vue', 'xml',
57+ 'rescript' })
5458 :only_cr()
5559 :use_regex(true)
5660 }
5761 return rules
5862end
63+
5964return { setup = setup }
65+
lua/nvim-autopairs/utils.lua+3−2
@@ -11,7 +11,8 @@ 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"
14+ noundo_sequence = "<c-g>U",
15+ abbr = "<c-]>"
1516}
1617
1718M.set_vchar = function(text)
@@ -73,7 +74,7 @@ M.is_in_quotes = function (line, pos, quote_type)
7374end
7475
7576M.is_attached = function(bufnr)
76− local _, check = pcall(api.nvim_buf_get_var, bufnr, "nvim-autopairs")
77+ local _, check = pcall(api.nvim_buf_get_var, bufnr or 0, "nvim-autopairs")
7778 return check == 1
7879end
7980
tests/minimal.vim+1
@@ -24,6 +24,7 @@ set indentexpr=
2424
2525lua << EOF
2626require("plenary/busted")
27+require("nvim-treesitter").setup()
2728vim.cmd[[luafile ./tests/test_utils.lua]]
2829require("nvim-autopairs").setup()
2930EOF
tests/nvim-autopairs_spec.lua+62−1
@@ -1,4 +1,3 @@
1−local helpers = {}
21local npairs = require('nvim-autopairs')
32local Rule = require('nvim-autopairs.rule')
43local cond = require('nvim-autopairs.conds')
@@ -50,6 +49,13 @@ local data = {
5049 before = [[""| ]],
5150 after = [["""|""" ]]
5251 },
52+ {
53+ name = "don't repeat python quote" ,
54+ filetype = "python",
55+ key = [["]],
56+ before = [[a"""|""" ]],
57+ after = [[a""""|"" ]]
58+ },
5359
5460 {
5561 name = "add markdown quote" ,
@@ -237,6 +243,43 @@ local data = {
237243 "]"
238244 }
239245 },
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+ },
240283 {
241284 name = "breakline on markdown " ,
242285 filetype="markdown",
@@ -645,6 +688,24 @@ local data = {
645688 [[}]],
646689 },
647690 },
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+ }
648709}
649710
650711local run_data = _G.Test_filter(data)
tests/test_utils.lua+8−7
@@ -27,6 +27,7 @@ utils.feed = function(text, num)
2727 result = result .. text
2828 end
2929 api.nvim_feedkeys(
30+ ---@diagnostic disable-next-line: param-type-mismatch
3031 api.nvim_replace_termcodes(result, true, false, true),
3132 'x',
3233 true
@@ -59,8 +60,7 @@ local compare_text = function(linenr, text_after, name, cursor_add, end_cursor)
5960 )
6061 for i = 1, #text_after, 1 do
6162 local t = string.gsub(text_after[i], '%|', '')
62− if
63− t
63+ if 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(done)
95+ it('test ' .. value.name, function(_)
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(text, '%|', '')
106+ local txt = string.gsub(tostring(text), '%|', '')
107107 table.insert(text_before, txt)
108− if string.match(text, '%|') then
109− if string.find(text, '%|') then
110− pos_before.colnr = string.find(text, '%|')
108+ if string.match(tostring(text), '%|') then
109+ if string.find(tostring(text), '%|') then
110+ pos_before.colnr = string.find(tostring(text), '%|')
111111 pos_before.linenr = value.linenr + index - 1
112112 end
113113 end
@@ -120,6 +120,7 @@ _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
123124 if vim.fn.filereadable(vim.fn.expand(value.filepath)) == 1 then
124125 vim.cmd(':e ' .. value.filepath)
125126 if value.filetype then