@@ -19,13 +19,15 @@ local default = {
1919 disable_filetype = { 'TelescopePrompt', 'spectre_panel' },
2020 disable_in_macro = false,
2121 disable_in_visualblock = false,
22− ignored_next_char = [=[[%w%%%'%[%"%.]]=],
22+ disable_in_replace_mode = true,
23+ ignored_next_char = [=[[%w%%%'%[%"%.%`%$]]=],
2324 break_undo = true,
2425 check_ts = false,
2526 enable_moveright = true,
2627 enable_afterquote = true,
2728 enable_check_bracket_line = true,
2829 enable_bracket_in_quote = true,
30+ enable_abbr = false,
2931 ts_config = {
3032 lua = { 'string', 'source' },
3133 javascript = { 'string', 'template_string' },
@@ -52,18 +54,21 @@ M.setup = function(opt)
5254 end
5355
5456 M.force_attach()
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− )
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+ })
6772end
6873
6974M.add_rule = function(rule)
@@ -98,7 +103,7 @@ M.remove_rule = function(pair)
98103 if r.start_pair ~= pair then
99104 table.insert(state_tbl, r)
100105 elseif r.key_map and r.key_map ~= '' then
101− vim.api.nvim_buf_del_keymap(0, 'i', r.key_map)
106+ api.nvim_buf_del_keymap(0, 'i', r.key_map)
102107 end
103108 end
104109 M.set_buf_rule(state_tbl, 0)
@@ -132,6 +137,15 @@ M.force_attach = function(bufnr)
132137 M.on_attach(bufnr)
133138end
134139
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+
135149local function is_disable()
136150 if M.state.disabled then
137151 return true
@@ -152,14 +166,16 @@ local function is_disable()
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
178+ del_keymaps()
163179 M.set_buf_rule({}, 0)
164180 return true
165181 end
@@ -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
@@ -225,78 +241,50 @@ M.on_attach = function(bufnr)
225241 if utils.is_attached(bufnr) then
226242 return
227243 end
244+ del_keymaps()
228245 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
229256 for _, rule in pairs(rules) do
230257 if rule.key_map ~= nil then
231258 if rule.is_regex == false then
232259 if rule.key_map == '' then
233260 rule.key_map = rule.start_pair:sub(#rule.start_pair)
234261 end
235− local key = string.format('"%s"', rule.key_map)
236− if rule.key_map == '"' then
237− key = [['"']]
238− end
239− local mapping = string.format('v:lua.MPairs.autopairs_map(%d,%s)', bufnr, key)
240− api.nvim_buf_set_keymap(
241− bufnr,
242− 'i',
243− rule.key_map,
244− mapping,
245− { expr = true, noremap = true }
246− )
247−
262+ expr_map(rule.key_map)
248263 local key_end = rule.key_end or rule.end_pair:sub(1, 1)
249264 if #key_end >= 1 and key_end ~= rule.key_map and rule.move_cond ~= nil then
250− mapping = string.format(
251− [[v:lua.MPairs.autopairs_map(%d, '%s')]],
252− bufnr,
253− key_end
254− )
255− vim.api.nvim_buf_set_keymap(
256− bufnr,
257− 'i',
258− key_end,
259− mapping,
260− { expr = true, noremap = true }
261− )
265+ expr_map(key_end)
262266 end
263267 else
264268 if rule.key_map ~= '' then
265− local mapping = string.format(
266− "v:lua.MPairs.autopairs_map(%d,'%s')",
267− bufnr,
268− rule.key_map
269− )
270− api.nvim_buf_set_keymap(
271− bufnr,
272− 'i',
273− rule.key_map,
274− mapping,
275− { expr = true, noremap = true }
276− )
269+ expr_map(rule.key_map)
277270 elseif rule.is_endwise == false then
278271 enable_insert_auto = true
279272 end
280273 end
281274 end
282275 end
276+ api.nvim_buf_set_var(bufnr, 'autopairs_keymaps', autopairs_keymaps)
283277
284278 if enable_insert_auto then
285279 -- capture all key use it to trigger regex pairs
286280 -- it can make an issue with paste from register
287− api.nvim_exec(
288− string.format(
289− [[
290− augroup autopairs_insert_%d
291− autocmd!
292− autocmd InsertCharPre <buffer=%d> call luaeval("require('nvim-autopairs').autopairs_insert(%d, _A)", v:char)
293− augroup end ]],
294− bufnr,
295− bufnr,
296− bufnr
297− ),
298− false
299− )
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+ })
300288 end
301289
302290 if M.config.fast_wrap and M.config.fast_wrap.map then
@@ -314,7 +302,7 @@ M.on_attach = function(bufnr)
314302 bufnr,
315303 'i',
316304 '<bs>',
317− string.format('v:lua.MPairs.autopairs_bs(%d)', bufnr),
305+ 'v:lua.MPairs.autopairs_bs()',
318306 { expr = true, noremap = true }
319307 )
320308 end
@@ -345,7 +333,7 @@ local autopairs_delete = function(bufnr, key)
345333 if is_disable() then
346334 return utils.esc(key)
347335 end
348− bufnr = bufnr or 0
336+ bufnr = bufnr or api.nvim_get_current_buf()
349337 local line = utils.text_get_current_line(bufnr)
350338 local _, col = utils.get_cursor()
351339 local rules = M.get_buf_rules(bufnr)
@@ -362,17 +350,19 @@ local autopairs_delete = function(bufnr, key)
362350 and utils.compare(rule.end_pair, next_char, rule.is_regex)
363351 and rule:can_del({
364352 ts_node = M.state.ts_node,
353+ rule = rule,
365354 bufnr = bufnr,
366355 prev_char = prev_char,
367356 next_char = next_char,
368357 line = line,
358+ col = col,
369359 })
370360 then
371361 local input = ''
372− for _ = 1, vim.api.nvim_strwidth(rule.start_pair), 1 do
362+ for _ = 1, api.nvim_strwidth(rule.start_pair), 1 do
373363 input = input .. utils.key.bs
374364 end
375− for _ = 1, vim.api.nvim_strwidth(rule.end_pair), 1 do
365+ for _ = 1, api.nvim_strwidth(rule.end_pair), 1 do
376366 input = input .. utils.key.del
377367 end
378368 return utils.esc('<c-g>U' .. input)
@@ -405,8 +395,8 @@ M.autopairs_map = function(bufnr, char)
405395 local rules = M.get_buf_rules(bufnr)
406396 for _, rule in pairs(rules) do
407397 if rule.start_pair then
408− if rule.key_map and rule.key_map:match('<.*>') then
409− new_text = line:sub(1, col) .. line:sub(col + 1, #line)
398+ if char:match('<.*>') then
399+ new_text = line
410400 add_char = 0
411401 else
412402 new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line)
@@ -443,7 +433,8 @@ M.autopairs_map = function(bufnr, char)
443433 return utils.esc(utils.repeat_key(utils.key.join_right, end_pair_length))
444434 end
445435
446− if 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)
447438 and rule:can_pair(cond_opt)
448439 then
449440 local end_pair = rule:get_end_pair(cond_opt)
@@ -460,12 +451,15 @@ M.autopairs_map = function(bufnr, char)
460451 if rule.is_undo then
461452 result = utils.esc(utils.key.undo_sequence) .. result .. utils.esc(utils.key.undo_sequence)
462453 end
454+ if M.config.enable_abbr then
455+ result = utils.esc(utils.key.abbr) .. result
456+ end
463457 log.debug("key_map :" .. result)
464458 return result
465459 end
466460 end
467461 end
468− return M.autopairs_afterquote(new_text, char)
462+ return M.autopairs_afterquote(new_text, utils.esc(char))
469463end
470464
471465M.autopairs_insert = function(bufnr, char)
@@ -551,10 +545,6 @@ M.autopairs_cr = function(bufnr)
551545 prev_char = prev_char,
552546 next_char = next_char,
553547 }
554−
555− local end_pair = rule:get_end_pair(cond_opt)
556− local end_pair_length = rule:get_end_pair_length(end_pair)
557−
558548 -- log.debug('prev_char' .. rule.start_pair)
559549 -- log.debug('prev_char' .. prev_char)
560550 -- log.debug('next_char' .. next_char)
@@ -562,6 +552,8 @@ M.autopairs_cr = function(bufnr)
562552 and utils.compare(rule.start_pair, prev_char, rule.is_regex)
563553 and rule:can_cr(cond_opt)
564554 then
555+ local end_pair = rule:get_end_pair(cond_opt)
556+ local end_pair_length = rule:get_end_pair_length(end_pair)
565557 return utils.esc(
566558 end_pair
567559 .. utils.repeat_key(utils.key.join_left, end_pair_length)
@@ -608,7 +600,7 @@ M.autopairs_afterquote = function(line, key_char)
608600 is_prev_slash = char == '\\'
609601 end
610602 if count == 2 and index >= (#line - 2) then
611− local rules = M.get_buf_rules(vim.api.nvim_get_current_buf())
603+ local rules = M.get_buf_rules(api.nvim_get_current_buf())
612604 for _, rule in pairs(rules) do
613605 if rule.start_pair == prev_char and char_end ~= rule.end_pair then
614606 local new_text = line:sub(0, index)
@@ -646,7 +638,7 @@ M.map_cr = function()
646638 return M.autopairs_cr()
647639 end
648640 end
649− vim.api.nvim_set_keymap(
641+ api.nvim_set_keymap(
650642 'i',
651643 '<CR>',
652644 'v:lua.MPairs.completion_confirm()',