(range) organize file
Some checks failed
NeoVim tests / plenary-tests (push) Failing after 7s

This commit is contained in:
Jonathan Apodaca 2025-04-14 12:06:29 -06:00
parent d03807afba
commit 3c7dd84ff2
2 changed files with 106 additions and 89 deletions

View File

@ -43,25 +43,23 @@ end
function Pos.invalid() return Pos.new(0, 0, 0, 0) end function Pos.invalid() return Pos.new(0, 0, 0, 0) 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.__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 function Pos.__le(a, b) return a < b or a == b end
function Pos.__eq(a, b) function Pos.__eq(a, b)
return Pos.is(a) and Pos.is(b) and a.bufnr == b.bufnr and a.lnum == b.lnum and a.col == b.col return getmetatable(a) == Pos and getmetatable(b) == Pos and a.bufnr == b.bufnr and a.lnum == b.lnum and a.col == b.col
end end
function Pos.__add(x, y) function Pos.__add(x, y)
if type(x) == 'number' then if type(x) == 'number' then
x, y = y, x x, y = y, x
end end
if not Pos.is(x) or type(y) ~= 'number' then return nil end if getmetatable(x) ~= Pos or type(y) ~= 'number' then return nil end
return x:next(y) return x:next(y)
end end
function Pos.__sub(x, y) function Pos.__sub(x, y)
if type(x) == 'number' then if type(x) == 'number' then
x, y = y, x x, y = y, x
end end
if not Pos.is(x) or type(y) ~= 'number' then return nil end if getmetatable(x) ~= Pos or type(y) ~= 'number' then return nil end
return x:next(-y) return x:next(-y)
end end

View File

@ -1,5 +1,10 @@
--- @module
--- @brief Utilities for manipulating ranges of text.
local Pos = require 'u.pos' local Pos = require 'u.pos'
-- Certain functions in the Range class yank text. In order to prevent unwanted
-- highlighting, we intercept and discard some calls to the `on_yank` callback.
local orig_on_yank = (vim.hl or vim.highlight).on_yank local orig_on_yank = (vim.hl or vim.highlight).on_yank
local on_yank_enabled = true; local on_yank_enabled = true;
((vim.hl or vim.highlight) --[[@as any]]).on_yank = function(opts) ((vim.hl or vim.highlight) --[[@as any]]).on_yank = function(opts)
@ -36,6 +41,10 @@ function Range.__tostring(self)
) )
end end
--------------------------------------------------------------------------------
-- Range constructors:
--------------------------------------------------------------------------------
--- @param start u.Pos --- @param start u.Pos
--- @param stop u.Pos|nil --- @param stop u.Pos|nil
--- @param mode? 'v'|'V' --- @param mode? 'v'|'V'
@ -51,7 +60,20 @@ function Range.new(start, stop, mode)
return r return r
end end
function Range.is(x) return getmetatable(x) == Range end --- @param ranges (u.Range|nil)[]
function Range.smallest(ranges)
--- @type u.Range[]
ranges = vim.iter(ranges):filter(function(r) return r ~= nil and not r:is_empty() end):totable()
if #ranges == 0 then return nil end
-- find smallest match
local smallest = ranges[1]
for _, r in ipairs(ranges) do
local start, stop = r.start, r.stop
if start > smallest.start and stop < smallest.stop then smallest = r end
end
return smallest
end
--- @param lpos string --- @param lpos string
--- @param rpos string --- @param rpos string
@ -221,7 +243,6 @@ function Range.from_cmd_args(args)
return Range.new(start, stop, mode) return Range.new(start, stop, mode)
end end
---
function Range.find_nearest_brackets() function Range.find_nearest_brackets()
return Range.smallest { return Range.smallest {
Range.from_motion('a<', { contains_cursor = true }), Range.from_motion('a<', { contains_cursor = true }),
@ -239,28 +260,15 @@ function Range.find_nearest_quotes()
} }
end end
--- @param ranges (u.Range|nil)[] --------------------------------------------------------------------------------
function Range.smallest(ranges) -- Structural utilities:
--- @type u.Range[] --------------------------------------------------------------------------------
ranges = vim.iter(ranges):filter(function(r) return r ~= nil and not r:is_empty() end):totable()
if #ranges == 0 then return nil end
-- find smallest match
local smallest = ranges[1]
for _, r in ipairs(ranges) do
local start, stop = r.start, r.stop
if start > smallest.start and stop < smallest.stop then smallest = r end
end
return smallest
end
function Range:clone() function Range:clone()
return Range.new(self.start:clone(), self.stop ~= nil and self.stop:clone() or nil, self.mode) return Range.new(self.start:clone(), self.stop ~= nil and self.stop:clone() or nil, self.mode)
end end
function Range:line_count()
if self:is_empty() then return 0 end function Range:is_empty() return self.stop == nil end
return self.stop.lnum - self.start.lnum + 1
end
function Range:to_linewise() function Range:to_linewise()
local r = self:clone() local r = self:clone()
@ -272,32 +280,6 @@ function Range:to_linewise()
return r return r
end end
function Range:is_empty() return self.stop == nil end
function Range:trim_start()
if self:is_empty() then return end
local r = self:clone()
while r.start:char():match '%s' do
local next = r.start:next(1)
if next == nil then break end
r.start = next
end
return r
end
function Range:trim_stop()
if self:is_empty() then return end
local r = self:clone()
while r.stop:char():match '%s' do
local next = r.stop:next(-1)
if next == nil then break end
r.stop = next
end
return r
end
--- @param x u.Pos | u.Range --- @param x u.Pos | u.Range
function Range:contains(x) function Range:contains(x)
if getmetatable(x) == Pos then if getmetatable(x) == Pos then
@ -336,6 +318,52 @@ function Range:difference(other)
return left, right return left, right
end end
--- @param left string
--- @param right string
function Range:save_to_pos(left, right)
if self:is_empty() then
self.start:save_to_pos(left)
self.start:save_to_pos(right)
else
self.start:save_to_pos(left)
self.stop:save_to_pos(right)
end
end
--- @param left string
--- @param right string
function Range:save_to_marks(left, right)
if self:is_empty() then
self.start:save_to_mark(left)
self.start:save_to_mark(right)
else
self.start:save_to_mark(left)
self.stop:save_to_mark(right)
end
end
function Range:set_visual_selection()
if self:is_empty() then return end
if vim.api.nvim_get_current_buf() ~= self.start.bufnr then
error 'Range:set_visual_selection() called on a buffer other than the current buffer'
end
local curr_mode = vim.fn.mode()
if curr_mode ~= self.mode then vim.cmd.normal { args = { self.mode }, bang = true } end
self.start:save_to_pos '.'
vim.cmd.normal { args = { 'o' }, bang = true }
self.stop:save_to_pos '.'
end
--------------------------------------------------------------------------------
-- Range.from_* functions:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Text access/manipulation utilities:
--------------------------------------------------------------------------------
function Range:length() function Range:length()
if self:is_empty() then return 0 end if self:is_empty() then return 0 end
@ -353,6 +381,35 @@ function Range:length()
return len return len
end end
function Range:line_count()
if self:is_empty() then return 0 end
return self.stop.lnum - self.start.lnum + 1
end
function Range:trim_start()
if self:is_empty() then return end
local r = self:clone()
while r.start:char():match '%s' do
local next = r.start:next(1)
if next == nil then break end
r.start = next
end
return r
end
function Range:trim_stop()
if self:is_empty() then return end
local r = self:clone()
while r.stop:char():match '%s' do
local next = r.stop:next(-1)
if next == nil then break end
r.stop = next
end
return r
end
--- @param i number 1-based --- @param i number 1-based
--- @param j? number 1-based --- @param j? number 1-based
function Range:sub(i, j) function Range:sub(i, j)
@ -507,44 +564,6 @@ function Range:must_shrink(amount)
return shrunk return shrunk
end end
--- @param left string
--- @param right string
function Range:save_to_pos(left, right)
if self:is_empty() then
self.start:save_to_pos(left)
self.start:save_to_pos(right)
else
self.start:save_to_pos(left)
self.stop:save_to_pos(right)
end
end
--- @param left string
--- @param right string
function Range:save_to_marks(left, right)
if self:is_empty() then
self.start:save_to_mark(left)
self.start:save_to_mark(right)
else
self.start:save_to_mark(left)
self.stop:save_to_mark(right)
end
end
function Range:set_visual_selection()
if self:is_empty() then return end
if vim.api.nvim_get_current_buf() ~= self.start.bufnr then
error 'Range:set_visual_selection() called on a buffer other than the current buffer'
end
local curr_mode = vim.fn.mode()
if curr_mode ~= self.mode then vim.cmd.normal { args = { self.mode }, bang = true } end
self.start:save_to_pos '.'
vim.cmd.normal { args = { 'o' }, bang = true }
self.stop:save_to_pos '.'
end
--- @param group string --- @param group string
--- @param opts? { timeout?: number, priority?: number, on_macro?: boolean } --- @param opts? { timeout?: number, priority?: number, on_macro?: boolean }
function Range:highlight(group, opts) function Range:highlight(group, opts)