@@ -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()',