add Range:difference
All checks were successful
NeoVim tests / plenary-tests (push) Successful in 9s
All checks were successful
NeoVim tests / plenary-tests (push) Successful in 9s
This commit is contained in:
@@ -12,8 +12,17 @@ end
|
||||
--- @field col number 1-based column index
|
||||
--- @field off number
|
||||
local Pos = {}
|
||||
Pos.__index = Pos
|
||||
Pos.MAX_COL = MAX_COL
|
||||
|
||||
function Pos.__tostring(self)
|
||||
if self.off ~= 0 then
|
||||
return string.format('Pos(%d:%d){bufnr=%d, off=%d}', self.lnum, self.col, self.bufnr, self.off)
|
||||
else
|
||||
return string.format('Pos(%d:%d){bufnr=%d}', self.lnum, self.col, self.bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param bufnr? number
|
||||
--- @param lnum number 1-based
|
||||
--- @param col number 1-based
|
||||
@@ -28,31 +37,13 @@ function Pos.new(bufnr, lnum, col, off)
|
||||
col = col,
|
||||
off = off,
|
||||
}
|
||||
|
||||
local function str()
|
||||
if pos.off ~= 0 then
|
||||
return string.format('Pos(%d:%d){bufnr=%d, off=%d}', pos.lnum, pos.col, pos.bufnr, pos.off)
|
||||
else
|
||||
return string.format('Pos(%d:%d){bufnr=%d}', pos.lnum, pos.col, pos.bufnr)
|
||||
end
|
||||
end
|
||||
setmetatable(pos, {
|
||||
__index = Pos,
|
||||
__tostring = str,
|
||||
__lt = Pos.__lt,
|
||||
__le = Pos.__le,
|
||||
__eq = Pos.__eq,
|
||||
})
|
||||
setmetatable(pos, Pos)
|
||||
return pos
|
||||
end
|
||||
|
||||
function Pos.invalid() return Pos.new(0, 0, 0, 0) end
|
||||
|
||||
function Pos.is(x)
|
||||
if not type(x) == 'table' then return false end
|
||||
local mt = getmetatable(x)
|
||||
return mt and mt.__index == Pos
|
||||
end
|
||||
function Pos.is(x) return getmetatable(x) == Pos end
|
||||
|
||||
function Pos.__lt(a, b) return a.lnum < b.lnum or (a.lnum == b.lnum and a.col < b.col) end
|
||||
function Pos.__le(a, b) return a < b or a == b end
|
||||
|
||||
@@ -12,6 +12,29 @@ end
|
||||
--- @field stop u.Pos|nil
|
||||
--- @field mode 'v'|'V'
|
||||
local Range = {}
|
||||
Range.__index = Range
|
||||
function Range.__tostring(self)
|
||||
--- @param p u.Pos
|
||||
local function posstr(p)
|
||||
if p == nil then
|
||||
return 'nil'
|
||||
elseif p.off ~= 0 then
|
||||
return string.format('Pos(%d:%d){off=%d}', p.lnum, p.col, p.off)
|
||||
else
|
||||
return string.format('Pos(%d:%d)', p.lnum, p.col)
|
||||
end
|
||||
end
|
||||
|
||||
local _1 = posstr(self.start)
|
||||
local _2 = posstr(self.stop)
|
||||
return string.format(
|
||||
'Range{bufnr=%d, mode=%s, start=%s, stop=%s}',
|
||||
self.start.bufnr,
|
||||
self.mode,
|
||||
_1,
|
||||
_2
|
||||
)
|
||||
end
|
||||
|
||||
--- @param start u.Pos
|
||||
--- @param stop u.Pos|nil
|
||||
@@ -23,36 +46,12 @@ function Range.new(start, stop, mode)
|
||||
end
|
||||
|
||||
local r = { start = start, stop = stop, mode = mode or 'v' }
|
||||
local function str()
|
||||
--- @param p u.Pos
|
||||
local function posstr(p)
|
||||
if p == nil then
|
||||
return 'nil'
|
||||
elseif p.off ~= 0 then
|
||||
return string.format('Pos(%d:%d){off=%d}', p.lnum, p.col, p.off)
|
||||
else
|
||||
return string.format('Pos(%d:%d)', p.lnum, p.col)
|
||||
end
|
||||
end
|
||||
|
||||
local _1 = posstr(r.start)
|
||||
local _2 = posstr(r.stop)
|
||||
return string.format(
|
||||
'Range{bufnr=%d, mode=%s, start=%s, stop=%s}',
|
||||
r.start.bufnr,
|
||||
r.mode,
|
||||
_1,
|
||||
_2
|
||||
)
|
||||
end
|
||||
setmetatable(r, { __index = Range, __tostring = str })
|
||||
setmetatable(r, Range)
|
||||
return r
|
||||
end
|
||||
|
||||
function Range.is(x)
|
||||
local mt = getmetatable(x)
|
||||
return mt and mt.__index == Range
|
||||
end
|
||||
function Range.is(x) return getmetatable(x) == Range end
|
||||
|
||||
--- @param lpos string
|
||||
--- @param rpos string
|
||||
@@ -299,8 +298,44 @@ function Range:trim_stop()
|
||||
return r
|
||||
end
|
||||
|
||||
--- @param p u.Pos
|
||||
function Range:contains(p) return not self:is_empty() and p >= self.start and p <= self.stop end
|
||||
--- @param x u.Pos | u.Range
|
||||
function Range:contains(x)
|
||||
if getmetatable(x) == Pos then
|
||||
return not self:is_empty() and x >= self.start and x <= self.stop
|
||||
elseif getmetatable(x) == Range then
|
||||
return self:contains(x.start) and self:contains(x.stop)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- TODO: test
|
||||
--- @param other u.Range
|
||||
--- @return u.Range|nil, u.Range|nil
|
||||
function Range:difference(other)
|
||||
local outer, inner = self, other
|
||||
if not outer:contains(inner) then
|
||||
outer, inner = inner, outer
|
||||
end
|
||||
if not outer:contains(inner) then return nil, nil end
|
||||
|
||||
local left
|
||||
if outer.start ~= inner.start then
|
||||
local stop = inner.start:clone() - 1
|
||||
left = Range.new(outer.start, stop)
|
||||
else
|
||||
left = Range.new(outer.start) -- empty range
|
||||
end
|
||||
|
||||
local right
|
||||
if inner.stop ~= outer.stop then
|
||||
local start = inner.stop:clone() + 1
|
||||
right = Range.new(start, outer.stop)
|
||||
else
|
||||
right = Range.new(inner.stop) -- empty range
|
||||
end
|
||||
|
||||
return left, right
|
||||
end
|
||||
|
||||
--- @return string[]
|
||||
function Range:lines()
|
||||
|
||||
Reference in New Issue
Block a user