fix(vim.region): handle multibyte inclusive selection properly (#26129)

This commit is contained in:
zeertzjq 2023-11-21 14:25:45 +08:00 committed by GitHub
parent 4880385809
commit fec5e3ab24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 9 deletions

View File

@ -1728,7 +1728,7 @@ vim.region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive})
• {pos2} integer[]|string End of region as a (line, column) tuple
or |getpos()|-compatible string
• {regtype} (string) |setreg()|-style selection type
• {inclusive} (boolean) Controls whether `pos2` column is inclusive
• {inclusive} (boolean) Controls whether the ending column is inclusive
(see also 'selection').
Return: ~

View File

@ -492,7 +492,7 @@ end
---@param pos1 integer[]|string Start of region as a (line, column) tuple or |getpos()|-compatible string
---@param pos2 integer[]|string End of region as a (line, column) tuple or |getpos()|-compatible string
---@param regtype string \|setreg()|-style selection type
---@param inclusive boolean Controls whether `pos2` column is inclusive (see also 'selection').
---@param inclusive boolean Controls whether the ending column is inclusive (see also 'selection').
---@return table region Dict of the form `{linenr = {startcol,endcol}}`. `endcol` is exclusive, and
---whole lines are returned as `{startcol,endcol} = {0,-1}`.
function vim.region(bufnr, pos1, pos2, regtype, inclusive)
@ -502,11 +502,11 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
if type(pos1) == 'string' then
local pos = vim.fn.getpos(pos1)
pos1 = { pos[2] - 1, pos[3] - 1 + pos[4] }
pos1 = { pos[2] - 1, pos[3] - 1 }
end
if type(pos2) == 'string' then
local pos = vim.fn.getpos(pos2)
pos2 = { pos[2] - 1, pos[3] - 1 + pos[4] }
pos2 = { pos[2] - 1, pos[3] - 1 }
end
if pos1[1] > pos2[1] or (pos1[1] == pos2[1] and pos1[2] > pos2[2]) then
@ -525,9 +525,8 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
-- in case of block selection, columns need to be adjusted for non-ASCII characters
-- TODO: handle double-width characters
local bufline
if regtype:byte() == 22 then
bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1]
local bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1]
pos1[2] = vim.str_utfindex(bufline, pos1[2])
end
@ -538,7 +537,7 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
c1 = pos1[2]
c2 = c1 + regtype:sub(2)
-- and adjust for non-ASCII characters
bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1]
local bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1]
local utflen = vim.str_utfindex(bufline, #bufline)
if c1 <= utflen then
c1 = vim.str_byteindex(bufline, c1)
@ -555,7 +554,11 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
c2 = -1
else
c1 = (l == pos1[1]) and pos1[2] or 0
c2 = (l == pos2[1]) and (pos2[2] + (inclusive and 1 or 0)) or -1
if inclusive and l == pos2[1] then
local bufline = vim.api.nvim_buf_get_lines(bufnr, pos2[1], pos2[1] + 1, true)[1]
pos2[2] = vim.fn.byteidx(bufline, vim.fn.charidx(bufline, pos2[2]) + 1)
end
c2 = (l == pos2[1]) and pos2[2] or -1
end
table.insert(region, l, { c1, c2 })
end

View File

@ -2395,7 +2395,14 @@ describe('lua stdlib', function()
text tαxt txtα tex
text tαxt tαxt
]]))
eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
eq({5,13}, exec_lua[[ return vim.region(0,{0,5},{0,13},'v',false)[0] ]])
eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,13},'v',true)[0] ]])
eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,14},'v',true)[0] ]])
eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,15},'v',false)[0] ]])
eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,15},'v',true)[0] ]])
eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,16},'v',true)[0] ]])
eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,17},'v',false)[0] ]])
eq({5,18}, exec_lua[[ return vim.region(0,{0,5},{0,17},'v',true)[0] ]])
end)
it('blockwise', function()
insert([[αα]])