diff --git a/lua/nvim-autopairs.lua b/lua/nvim-autopairs.lua index cef320c..ab32fe2 100644 --- a/lua/nvim-autopairs.lua +++ b/lua/nvim-autopairs.lua @@ -215,8 +215,8 @@ M.on_attach = function(bufnr) { expr = true, noremap = true } ) - local key_end = rule.end_pair:sub(1, 1) - if #key_end == 1 and key_end ~= rule.key_map and rule.move_cond ~= nil then + local key_end = rule.key_end or rule.end_pair:sub(1, 1) + if #key_end >= 1 and key_end ~= rule.key_map and rule.move_cond ~= nil then mapping = string.format( [[v:lua.MPairs.autopairs_map(%d, '%s')]], bufnr, @@ -318,10 +318,10 @@ M.autopairs_bs = function(bufnr) }) then local input = '' - for _ = 1, #rule.start_pair, 1 do + for _ = 1, vim.fn.strdisplaywidth(rule.start_pair), 1 do input = input .. utils.key.bs end - for _ = 1, #rule.end_pair, 1 do + for _ = 1, vim.fn.strdisplaywidth(rule.end_pair), 1 do input = input .. utils.key.right .. utils.key.bs end return utils.esc('U' .. input) @@ -344,7 +344,8 @@ M.autopairs_map = function(bufnr, char) if rule.is_regex and rule.key_map and rule.key_map ~= '' then new_text = line:sub(1, col) .. line:sub(col + 1, #line) add_char = 0 - elseif rule.key_map and #rule.key_map > 1 then + elseif rule.key_map and rule.key_map:match("<.*>") then + -- if it is a special key liek if utils.esc(rule.key_map) ~= char then new_text = '' else @@ -353,7 +354,7 @@ M.autopairs_map = function(bufnr, char) end else new_text = line:sub(1, col) .. char .. line:sub(col + 1, #line) - add_char = 1 + add_char = rule.key_map and #rule.key_map or 1 end -- log.debug("new_text:[" .. new_text .. "]") @@ -383,7 +384,8 @@ M.autopairs_map = function(bufnr, char) and rule:can_move(cond_opt) then local end_pair = rule:get_end_pair(cond_opt) - return utils.esc(utils.repeat_key(utils.key.join_right, #end_pair)) + local end_pair_length = rule:get_end_pair_length(end_pair) + return utils.esc(utils.repeat_key(utils.key.join_right, end_pair_length)) end if @@ -397,7 +399,10 @@ M.autopairs_map = function(bufnr, char) move_text = '' char = '' end - return utils.esc(char .. end_pair .. move_text) + if end_pair:match("<.*>") then + end_pair = utils.esc(end_pair) + end + return char .. end_pair .. utils.esc(move_text) end end end @@ -564,7 +569,7 @@ M.autopairs_afterquote = function(line, key_char) end end end - return utils.esc(key_char) + return key_char end M.autopairs_closequote_expr = function() @@ -578,3 +583,4 @@ end M.esc = utils.esc _G.MPairs = M return M + diff --git a/lua/nvim-autopairs/rule.lua b/lua/nvim-autopairs/rule.lua index 1fbc07c..5720558 100644 --- a/lua/nvim-autopairs/rule.lua +++ b/lua/nvim-autopairs/rule.lua @@ -1,5 +1,5 @@ -local log = require('nvim-autopairs._log') local Rule = {} +local log = require('nvim-autopairs._log') local Cond = require('nvim-autopairs.conds') @@ -33,11 +33,21 @@ function Rule.new(...) is_endwise = false, -- use regex to compare is_regex = false, + is_multibyte = false, -- some end_pair have key map like .. then the length of string is -- not correct end_pair_length = nil, },opt) - return setmetatable(opt, {__index = Rule}) + + local function verify(rule) + -- check multibyte + if #rule.start_pair ~= vim.fn.strdisplaywidth(rule.start_pair) then + rule:use_multibyte() + end + return rule + end + local r = setmetatable(opt, {__index = Rule}) + return verify(r) end function Rule:use_regex(value,key_map) @@ -51,6 +61,14 @@ function Rule:use_key(key_map) return self end +function Rule:use_multibyte() + self.is_multibyte = true + self.end_pair_length = vim.fn.strdisplaywidth(self.end_pair) + self.key_map = string.match(self.start_pair, "[^\128-\191][\128-\191]*$") + self.key_end = string.match(self.end_pair, "[%z\1-\127\194-\244][\128-\191]*") + return self +end + function Rule:get_end_pair(opts) if self.end_pair_func then return self.end_pair_func(opts) diff --git a/tests/nvim-autopairs_spec.lua b/tests/nvim-autopairs_spec.lua index 5853207..4fd3abf 100644 --- a/tests/nvim-autopairs_spec.lua +++ b/tests/nvim-autopairs_spec.lua @@ -29,14 +29,16 @@ npairs.add_rules({ }) vim.api.nvim_set_keymap('i' , '','v:lua.npairs.check_break_line_char()', {expr = true , noremap = true}) -function helpers.feed(text, feed_opts) +function helpers.feed(text, feed_opts, is_replace) feed_opts = feed_opts or 'n' - local to_feed = vim.api.nvim_replace_termcodes(text, true, false, true) - vim.api.nvim_feedkeys(to_feed, feed_opts, true) + if not is_replace then + text = vim.api.nvim_replace_termcodes(text, true, false, true) + end + vim.api.nvim_feedkeys(text, feed_opts, true) end -function helpers.insert(text) - helpers.feed('i' .. text, 'x') +function helpers.insert(text, is_replace) + helpers.feed('i' .. text, 'x',is_replace) end local data = { @@ -397,7 +399,7 @@ local data = { :set_end_pair_length(2) }) end, - name="mapping regex with custom end_pair_length", + name = "mapping regex with custom end_pair_length", filetype="typescript", key=">", before = [[(o)=| ]], @@ -415,12 +417,58 @@ local data = { end, true), }) end, - name="mapping same pair with different key", + name = "mapping same pair with different key", filetype="typescript", key="(", before = [[(test|) ]], after = [[(test(|)) ]] + }, + { + setup_func = function() + npairs.clear_rules() + npairs.add_rule(Rule("„","”")) + end, + name = "multibyte character from custom keyboard", + not_replace_term_code = true, + key = "„", + before = [[a | ]], + after = [[a „|” ]], + end_cursor = 6, + }, + { + setup_func = function() + npairs.clear_rules() + npairs.add_rule(Rule("„","”"):with_move(cond.done())) + end, + name = "multibyte character move_right", + not_replace_term_code = true, + key = "”", + before = [[a „|”xx ]], + after = [[a „”|xx ]], + end_cursor = 9, + }, + { + setup_func = function() + npairs.clear_rules() + npairs.add_rule(Rule("„", "”"):with_move(cond.done())) + end, + name = "multibyte character delete", + key = "", + before = [[a „|” ]], + after = [[a | ]], + }, + { + setup_func = function() + npairs.clear_rules() + npairs.add_rule(Rule("a„", "”b"):with_move(cond.done())) + end, + not_replace_term_code = true, + name = "multibyte character and multiple ", + key = "„", + before = [[a| ]], + after = [[a„|”b ]], + end_cursor = 5, } } @@ -452,14 +500,14 @@ local function Test(test_data) npairs.on_attach(vim.api.nvim_get_current_buf()) vim.fn.setline(line , before) vim.fn.setpos('.' ,{0, line, p_before , 0}) - helpers.insert(value.key) + helpers.insert(value.key,value.not_replace_term_code ) vim.wait(10) helpers.feed("") local result = vim.fn.getline(line) local pos = vim.fn.getpos('.') if value.key ~= '' then eq(after, result , "\n\n text error: " .. value.name .. "\n") - eq(p_after, pos[3] + 1, "\n\n pos error: " .. value.name .. "\n") + eq(p_after, value.end_cursor or (pos[3] + 1), "\n\n pos error: " .. value.name .. "\n") else local line2 = vim.fn.getline(line + 2)