Add Range:length and Range:sub
All checks were successful
NeoVim tests / plenary-tests (push) Successful in 9s

This commit is contained in:
Jonathan Apodaca 2025-04-13 17:06:17 -06:00
parent 9f5fdb4f2b
commit 58e447aad6
2 changed files with 100 additions and 10 deletions

View File

@ -308,7 +308,6 @@ function Range:contains(x)
return false return false
end end
--- TODO: test
--- @param other u.Range --- @param other u.Range
--- @return u.Range|nil, u.Range|nil --- @return u.Range|nil, u.Range|nil
function Range:difference(other) function Range:difference(other)
@ -337,6 +336,64 @@ function Range:difference(other)
return left, right return left, right
end end
function Range:length()
if self:is_empty() then return 0 end
local line_positions =
vim.fn.getregionpos(self.start:as_real():as_vim(), self.stop:as_real():as_vim(), { type = 'v' })
local len = 0
for linenr, line in ipairs(line_positions) do
if linenr > 1 then len = len + 1 end -- each newline is counted as a char
local line_start_col = line[1][3]
local line_stop_col = line[2][3]
local line_len = line_stop_col - line_start_col + 1
len = len + line_len
end
return len
end
--- @param i number 1-based
--- @param j? number 1-based
function Range:sub(i, j)
local line_positions =
vim.fn.getregionpos(self.start:as_real():as_vim(), self.stop:as_real():as_vim(), { type = 'v' })
--- @param idx number 1-based
--- @return u.Pos|nil
local function get_pos(idx)
if idx < 0 then return get_pos(self:length() + idx + 1) end
-- find the position of the first line that contains the i-th character:
local curr_len = 0
for linenr, line in ipairs(line_positions) do
if linenr > 1 then curr_len = curr_len + 1 end -- each newline is counted as a char
local line_start_col = line[1][3]
local line_stop_col = line[2][3]
local line_len = line_stop_col - line_start_col + 1
if curr_len + line_len >= idx then
return Pos.new(self.start.bufnr, line[1][2], line_start_col + (idx - curr_len) - 1)
end
curr_len = curr_len + line_len
end
end
local start = get_pos(i)
if not start then
-- start is inalid, so return an empty range:
return Range.new(self.start, nil, self.mode)
end
local stop
if j then stop = get_pos(j) end
if not stop then
-- stop is inalid, so return an empty range:
return Range.new(start, nil, self.mode)
end
return Range.new(start, stop, 'v')
end
--- @return string[] --- @return string[]
function Range:lines() function Range:lines()
if self:is_empty() then return {} end if self:is_empty() then return {} end
@ -346,10 +403,6 @@ end
--- @return string --- @return string
function Range:text() return vim.fn.join(self:lines(), '\n') end function Range:text() return vim.fn.join(self:lines(), '\n') end
--- @param i number 1-based
--- @param j? number 1-based
function Range:sub(i, j) return self:text():sub(i, j) end
--- @param l number --- @param l number
--- @return { line: string; idx0: { start: number; stop: number; }; lnum: number; range: fun():u.Range; text: fun():string }|nil --- @return { line: string; idx0: { start: number; stop: number; }; lnum: number; range: fun():u.Range; text: fun():string }|nil
function Range:line(l) function Range:line(l)

View File

@ -446,6 +446,28 @@ describe('Range', function()
end) end)
end) end)
it('length', function()
withbuf({ 'line one', 'and line two' }, function()
local range = Range.new(Pos.new(nil, 2, 4), Pos.new(nil, 2, 9), 'v')
assert.are.same(range:length(), #range:text())
range = Range.new(Pos.new(nil, 1, 4), Pos.new(nil, 2, 9), 'v')
assert.are.same(range:length(), #range:text())
end)
end)
it('sub', function()
withbuf({ 'line one', 'and line two' }, function()
local range = Range.new(Pos.new(nil, 2, 4), Pos.new(nil, 2, 9), 'v')
assert.are.same(range:text(), ' line ')
assert.are.same(range:sub(1, -1):text(), ' line ')
assert.are.same(range:sub(2, -2):text(), 'line')
assert.are.same(range:sub(1, 5):text(), ' line')
assert.are.same(range:sub(2, 5):text(), 'line')
assert.are.same(range:sub(20, 25):text(), '')
end)
end)
it('shrink', function() it('shrink', function()
withbuf({ 'line one', 'and line two' }, function() withbuf({ 'line one', 'and line two' }, function()
local range = Range.new(Pos.new(nil, 2, 3), Pos.new(nil, 3, 5), 'v') local range = Range.new(Pos.new(nil, 2, 3), Pos.new(nil, 3, 5), 'v')
@ -462,7 +484,10 @@ describe('Range', function()
assert.are.same(shrunk.start, Pos.new(nil, 2, 4)) assert.are.same(shrunk.start, Pos.new(nil, 2, 4))
assert.are.same(shrunk.stop, Pos.new(nil, 3, 4)) assert.are.same(shrunk.stop, Pos.new(nil, 3, 4))
assert.has.error(function() range:must_shrink(100) end, 'error in Range:must_shrink: Range:shrink() returned nil') assert.has.error(
function() range:must_shrink(100) end,
'error in Range:must_shrink: Range:shrink() returned nil'
)
end) end)
end) end)
@ -500,10 +525,16 @@ describe('Range', function()
local r = Range.new(Pos.new(b, 1, 5), Pos.new(b, 1, 9), 'v') local r = Range.new(Pos.new(b, 1, 5), Pos.new(b, 1, 9), 'v')
r:replace 'bleh1' r:replace 'bleh1'
assert.are.same({ 'The bleh1 brown fox jumps over the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false)) assert.are.same(
{ 'The bleh1 brown fox jumps over the lazy dog' },
vim.api.nvim_buf_get_lines(b, 0, -1, false)
)
r:replace 'bleh2' r:replace 'bleh2'
assert.are.same({ 'The bleh2 brown fox jumps over the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false)) assert.are.same(
{ 'The bleh2 brown fox jumps over the lazy dog' },
vim.api.nvim_buf_get_lines(b, 0, -1, false)
)
end) end)
end) end)
@ -517,11 +548,17 @@ describe('Range', function()
assert.are.same({ 'jumps', 'over' }, r:lines()) assert.are.same({ 'jumps', 'over' }, r:lines())
r:replace 'bleh1' r:replace 'bleh1'
assert.are.same({ 'The quick brown fox bleh1 the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false)) assert.are.same(
{ 'The quick brown fox bleh1 the lazy dog' },
vim.api.nvim_buf_get_lines(b, 0, -1, false)
)
assert.are.same({ 'bleh1' }, r:lines()) assert.are.same({ 'bleh1' }, r:lines())
r:replace 'blehGoo2' r:replace 'blehGoo2'
assert.are.same({ 'The quick brown fox blehGoo2 the lazy dog' }, vim.api.nvim_buf_get_lines(b, 0, -1, false)) assert.are.same(
{ 'The quick brown fox blehGoo2 the lazy dog' },
vim.api.nvim_buf_get_lines(b, 0, -1, false)
)
end) end)
end) end)