@@ -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,17 +395,9 @@ 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.is_regex and rule.key_map and rule.key_map ~= '' 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
413− elseif rule.key_map and rule.key_map:match('<.*>') then
414− -- if it is a special key like <c-a>
415− if utils.esc(rule.key_map) ~= char then
416− new_text = ''
417− else
418− new_text = line:sub(1, col) .. line:sub(col + 1, #line)
419− add_char = 0
420− end
421401 else
422402 new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line)
423403 add_char = rule.key_map and #rule.key_map or 1
@@ -445,8 +425,7 @@ M.autopairs_map = function(bufnr, char)
445425 -- log.debug("start_pair" .. rule.start_pair)
446426 -- log.debug('prev_char' .. prev_char)
447427 -- log.debug('next_char' .. next_char)
448− if
449− utils.compare(rule.end_pair, next_char, rule.is_regex)
428+ if utils.compare(rule.end_pair, next_char, rule.is_regex)
450429 and rule:can_move(cond_opt)
451430 then
452431 local end_pair = rule:get_end_pair(cond_opt)
@@ -454,8 +433,8 @@ M.autopairs_map = function(bufnr, char)
454433 return utils.esc(utils.repeat_key(utils.key.join_right, end_pair_length))
455434 end
456435
457− if
458− 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)
459438 and rule:can_pair(cond_opt)
460439 then
461440 local end_pair = rule:get_end_pair(cond_opt)
@@ -468,16 +447,19 @@ M.autopairs_map = function(bufnr, char)
468447 if end_pair:match('<.*>') then
469448 end_pair = utils.esc(end_pair)
470449 end
471− local result= char .. end_pair .. utils.esc(move_text)
450+ local result = char .. end_pair .. utils.esc(move_text)
472451 if rule.is_undo then
473− 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
474456 end
475457 log.debug("key_map :" .. result)
476458 return result
477459 end
478460 end
479461 end
480− return M.autopairs_afterquote(new_text, char)
462+ return M.autopairs_afterquote(new_text, utils.esc(char))
481463end
482464
483465M.autopairs_insert = function(bufnr, char)
@@ -519,8 +501,7 @@ M.autopairs_insert = function(bufnr, char)
519501 return false
520502 end
521503
522− if
523− utils.compare(rule.start_pair, prev_char, rule.is_regex)
504+ if utils.compare(rule.start_pair, prev_char, rule.is_regex)
524505 and rule:can_pair(cond_opt)
525506 then
526507 local end_pair = rule:get_end_pair(cond_opt)
@@ -559,46 +540,36 @@ M.autopairs_cr = function(bufnr)
559540 check_endwise_ts = true,
560541 rule = rule,
561542 bufnr = bufnr,
562− col = col + 1,
543+ col = col,
563544 line = line,
564545 prev_char = prev_char,
565546 next_char = next_char,
566547 }
567−
568− local end_pair = rule:get_end_pair(cond_opt)
569− local end_pair_length = rule:get_end_pair_length(end_pair)
570−
571548 -- log.debug('prev_char' .. rule.start_pair)
572549 -- log.debug('prev_char' .. prev_char)
573550 -- log.debug('next_char' .. next_char)
574− if
575− rule.is_endwise
551+ if rule.is_endwise
576552 and utils.compare(rule.start_pair, prev_char, rule.is_regex)
577553 and rule:can_cr(cond_opt)
578554 then
555+ local end_pair = rule:get_end_pair(cond_opt)
556+ local end_pair_length = rule:get_end_pair_length(end_pair)
579557 return utils.esc(
580558 end_pair
581− .. utils.repeat_key(utils.key.join_left, end_pair_length)
582− -- FIXME do i need to re indent twice #118
583− .. '<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'
584562 )
585563 end
586− if
587− utils.compare(rule.start_pair, prev_char, rule.is_regex)
564+
565+ cond_opt.check_endwise_ts = false
566+
567+ if utils.compare(rule.start_pair, prev_char, rule.is_regex)
588568 and utils.compare(rule.end_pair, next_char, rule.is_regex)
589− and rule:can_cr({
590− ts_node = M.state.ts_node,
591− check_endwise_ts = false,
592− bufnr = bufnr,
593− rule = rule,
594− col = col,
595− prev_char = prev_char,
596− next_char = next_char,
597− line = line,
598− })
569+ and rule:can_cr(cond_opt)
599570 then
600571 log.debug('do_cr')
601− 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 }))
602573 end
603574 end
604575 end
@@ -611,8 +582,7 @@ M.autopairs_afterquote = function(line, key_char)
611582 line = line or utils.text_get_current_line(0)
612583 local _, col = utils.get_cursor()
613584 local prev_char, next_char = utils.text_cusor_line(line, col + 1, 1, 1, false)
614− if
615− utils.is_bracket(prev_char)
585+ if utils.is_bracket(prev_char)
616586 and utils.is_quote(next_char)
617587 and not utils.is_in_quotes(line, col, next_char)
618588 then
@@ -630,7 +600,7 @@ M.autopairs_afterquote = function(line, key_char)
630600 is_prev_slash = char == '\\'
631601 end
632602 if count == 2 and index >= (#line - 2) then
633− local rules = M.get_buf_rules(vim.api.nvim_get_current_buf())
603+ local rules = M.get_buf_rules(api.nvim_get_current_buf())
634604 for _, rule in pairs(rules) do
635605 if rule.start_pair == prev_char and char_end ~= rule.end_pair then
636606 local new_text = line:sub(0, index)
@@ -662,13 +632,13 @@ end
662632
663633M.map_cr = function()
664634 M.completion_confirm = function()
665− if vim.fn.pumvisible() ~= 0 then
635+ if vim.fn.pumvisible() ~= 0 then
666636 return M.esc("<cr>")
667637 else
668638 return M.autopairs_cr()
669639 end
670640 end
671− vim.api.nvim_set_keymap(
641+ api.nvim_set_keymap(
672642 'i',
673643 '<CR>',
674644 'v:lua.MPairs.completion_confirm()',