refactor extmark to its own file
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m24s
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m24s
This commit is contained in:
parent
c6b0076630
commit
fc29454c55
@ -2,7 +2,7 @@ local Range = require 'u.range'
|
|||||||
local Renderer = require('u.renderer').Renderer
|
local Renderer = require('u.renderer').Renderer
|
||||||
|
|
||||||
--- @class u.Buffer
|
--- @class u.Buffer
|
||||||
--- @field bufnr number
|
--- @field bufnr integer
|
||||||
--- @field b vim.var_accessor
|
--- @field b vim.var_accessor
|
||||||
--- @field bo vim.bo
|
--- @field bo vim.bo
|
||||||
--- @field renderer u.renderer.Renderer
|
--- @field renderer u.renderer.Renderer
|
||||||
|
71
lua/u/extmark.lua
Normal file
71
lua/u/extmark.lua
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
local Pos = require 'u.pos'
|
||||||
|
|
||||||
|
---@class u.Extmark
|
||||||
|
---@field bufnr integer
|
||||||
|
---@field id integer
|
||||||
|
---@field nsid integer
|
||||||
|
local Extmark = {}
|
||||||
|
Extmark.__index = Extmark
|
||||||
|
|
||||||
|
--- @param bufnr integer
|
||||||
|
--- @param nsid integer
|
||||||
|
--- @param id integer
|
||||||
|
function Extmark.new(bufnr, nsid, id)
|
||||||
|
return setmetatable({
|
||||||
|
bufnr = bufnr,
|
||||||
|
nsid = nsid,
|
||||||
|
id = id,
|
||||||
|
}, Extmark)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param range u.Range
|
||||||
|
--- @param nsid integer
|
||||||
|
function Extmark.from_range(range, nsid)
|
||||||
|
local r = range:to_charwise()
|
||||||
|
local stop = r.stop or r.start
|
||||||
|
local end_row = stop.lnum - 1
|
||||||
|
local end_col = stop.col
|
||||||
|
if range.mode == 'V' then
|
||||||
|
end_row = end_row + 1
|
||||||
|
end_col = 0
|
||||||
|
end
|
||||||
|
local id = vim.api.nvim_buf_set_extmark(r.start.bufnr, nsid, r.start.lnum - 1, r.start.col - 1, {
|
||||||
|
right_gravity = false,
|
||||||
|
end_right_gravity = true,
|
||||||
|
end_row = end_row,
|
||||||
|
end_col = end_col,
|
||||||
|
})
|
||||||
|
return Extmark.new(r.start.bufnr, nsid, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Extmark:range()
|
||||||
|
local Range = require 'u.range'
|
||||||
|
|
||||||
|
local raw_extmark =
|
||||||
|
vim.api.nvim_buf_get_extmark_by_id(self.bufnr, self.nsid, self.id, { details = true })
|
||||||
|
local start_row0, start_col0, details = unpack(raw_extmark)
|
||||||
|
|
||||||
|
--- @type u.Pos
|
||||||
|
local start = Pos.from00(self.bufnr, start_row0, start_col0)
|
||||||
|
--- @type u.Pos?
|
||||||
|
local stop = details
|
||||||
|
and details.end_row
|
||||||
|
and details.end_col
|
||||||
|
and Pos.from01(self.bufnr, details.end_row, details.end_col)
|
||||||
|
|
||||||
|
local n_buf_lines = vim.api.nvim_buf_line_count(self.bufnr)
|
||||||
|
if stop and stop.lnum > n_buf_lines then
|
||||||
|
stop.lnum = n_buf_lines
|
||||||
|
stop = stop:eol()
|
||||||
|
end
|
||||||
|
if stop and stop.col == 0 then
|
||||||
|
stop.col = 1
|
||||||
|
stop = stop:next(-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Range.new(start, stop, 'v')
|
||||||
|
end
|
||||||
|
|
||||||
|
function Extmark:delete() vim.api.nvim_buf_del_extmark(self.bufnr, self.nsid, self.id) end
|
||||||
|
|
||||||
|
return Extmark
|
@ -7,9 +7,9 @@ local function line_text(bufnr, lnum)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @class u.Pos
|
--- @class u.Pos
|
||||||
--- @field bufnr number buffer number
|
--- @field bufnr integer buffer number
|
||||||
--- @field lnum number 1-based line index
|
--- @field lnum integer 1-based line index
|
||||||
--- @field col number 1-based column index
|
--- @field col integer 1-based column index
|
||||||
--- @field off number
|
--- @field off number
|
||||||
local Pos = {}
|
local Pos = {}
|
||||||
Pos.__index = Pos
|
Pos.__index = Pos
|
||||||
@ -31,14 +31,13 @@ end
|
|||||||
function Pos.new(bufnr, lnum, col, off)
|
function Pos.new(bufnr, lnum, col, off)
|
||||||
if bufnr == nil or bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() end
|
if bufnr == nil or bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() end
|
||||||
if off == nil then off = 0 end
|
if off == nil then off = 0 end
|
||||||
local pos = {
|
--- @type u.Pos
|
||||||
|
return setmetatable({
|
||||||
bufnr = bufnr,
|
bufnr = bufnr,
|
||||||
lnum = lnum,
|
lnum = lnum,
|
||||||
col = col,
|
col = col,
|
||||||
off = off,
|
off = off,
|
||||||
}
|
}, Pos)
|
||||||
setmetatable(pos, Pos)
|
|
||||||
return pos
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param bufnr? number
|
--- @param bufnr? number
|
||||||
@ -47,6 +46,12 @@ end
|
|||||||
--- @param off? number
|
--- @param off? number
|
||||||
function Pos.from00(bufnr, lnum0, col0, off) return Pos.new(bufnr, lnum0 + 1, col0 + 1, off) end
|
function Pos.from00(bufnr, lnum0, col0, off) return Pos.new(bufnr, lnum0 + 1, col0 + 1, off) end
|
||||||
|
|
||||||
|
--- @param bufnr? number
|
||||||
|
--- @param lnum0 number 1-based
|
||||||
|
--- @param col1 number 1-based
|
||||||
|
--- @param off? number
|
||||||
|
function Pos.from01(bufnr, lnum0, col1, off) return Pos.new(bufnr, lnum0 + 1, col1, off) end
|
||||||
|
|
||||||
--- @param bufnr? number
|
--- @param bufnr? number
|
||||||
--- @param lnum1 number 1-based
|
--- @param lnum1 number 1-based
|
||||||
--- @param col0 number 1-based
|
--- @param col0 number 1-based
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
|
local Extmark = require 'u.extmark'
|
||||||
local Pos = require 'u.pos'
|
local Pos = require 'u.pos'
|
||||||
|
|
||||||
local ESC = vim.api.nvim_replace_termcodes('<Esc>', true, false, true)
|
local ESC = vim.api.nvim_replace_termcodes('<Esc>', true, false, true)
|
||||||
local NS = vim.api.nvim_create_namespace 'u.range'
|
local NS = vim.api.nvim_create_namespace 'u.range'
|
||||||
|
|
||||||
---@class u.ExtmarkRange
|
|
||||||
---@field bufnr number
|
|
||||||
---@field id number
|
|
||||||
local ExtmarkRange = {}
|
|
||||||
ExtmarkRange.__index = ExtmarkRange
|
|
||||||
|
|
||||||
--- @class u.Range
|
--- @class u.Range
|
||||||
--- @field start u.Pos
|
--- @field start u.Pos
|
||||||
--- @field stop u.Pos|nil
|
--- @field stop u.Pos|nil
|
||||||
@ -90,34 +85,6 @@ function Range.from_marks(lpos, rpos)
|
|||||||
return Range.new(start, stop, mode)
|
return Range.new(start, stop, mode)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param bufnr number
|
|
||||||
--- @param extmark vim.api.keyset.get_extmark_item_by_id
|
|
||||||
function Range.from_extmark(bufnr, extmark)
|
|
||||||
---@type integer, integer, vim.api.keyset.extmark_details | nil
|
|
||||||
local start_row0, start_col0, details = unpack(extmark)
|
|
||||||
|
|
||||||
local start = Pos.new(bufnr, start_row0 + 1, start_col0 + 1)
|
|
||||||
local stop = details and Pos.new(bufnr, details.end_row + 1, details.end_col)
|
|
||||||
|
|
||||||
if stop ~= nil then
|
|
||||||
-- Check for invalid extmark range:
|
|
||||||
if stop < start then return Range.new(stop) end
|
|
||||||
|
|
||||||
-- Check for stop-mark past the end of the buffer:
|
|
||||||
local buf_max_lines = vim.api.nvim_buf_line_count(bufnr)
|
|
||||||
if stop.lnum > buf_max_lines then
|
|
||||||
stop.lnum = buf_max_lines
|
|
||||||
stop = stop:eol()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- A stop mark at position 0 means it is at the end of the last line.
|
|
||||||
-- Move it back.
|
|
||||||
if stop.col == 0 then stop = stop:must_next(-1) end
|
|
||||||
end
|
|
||||||
|
|
||||||
return Range.new(start, stop, 'v')
|
|
||||||
end
|
|
||||||
|
|
||||||
--- @param bufnr? number
|
--- @param bufnr? number
|
||||||
function Range.from_buf_text(bufnr)
|
function Range.from_buf_text(bufnr)
|
||||||
if bufnr == nil or bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() end
|
if bufnr == nil or bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() end
|
||||||
@ -392,22 +359,7 @@ function Range:save_to_marks(left, right)
|
|||||||
(self:is_empty() and self.start or self.stop):save_to_mark(right)
|
(self:is_empty() and self.start or self.stop):save_to_mark(right)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Range:save_to_extmark()
|
function Range:save_to_extmark() return Extmark.from_range(self, NS) end
|
||||||
local r = self:to_charwise()
|
|
||||||
local end_row = r.stop.lnum - 1
|
|
||||||
local end_col = r.stop.col
|
|
||||||
if self.mode == 'V' then
|
|
||||||
end_row = end_row + 1
|
|
||||||
end_col = 0
|
|
||||||
end
|
|
||||||
local id = vim.api.nvim_buf_set_extmark(r.start.bufnr, NS, r.start.lnum - 1, r.start.col - 1, {
|
|
||||||
right_gravity = false,
|
|
||||||
end_right_gravity = true,
|
|
||||||
end_row = end_row,
|
|
||||||
end_col = end_col,
|
|
||||||
})
|
|
||||||
return ExtmarkRange.new(r.start.bufnr, id)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Range:set_visual_selection()
|
function Range:set_visual_selection()
|
||||||
if self:is_empty() then return end
|
if self:is_empty() then return end
|
||||||
@ -703,17 +655,4 @@ function Range:highlight(group, opts)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function ExtmarkRange.new(bufnr, id) return setmetatable({ bufnr = bufnr, id = id }, ExtmarkRange) end
|
|
||||||
|
|
||||||
function ExtmarkRange:range()
|
|
||||||
return Range.from_extmark(
|
|
||||||
self.bufnr,
|
|
||||||
vim.api.nvim_buf_get_extmark_by_id(self.bufnr, NS, self.id, {
|
|
||||||
details = true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
function ExtmarkRange:delete() vim.api.nvim_buf_del_extmark(self.bufnr, NS, self.id) end
|
|
||||||
|
|
||||||
return Range
|
return Range
|
||||||
|
@ -6,19 +6,19 @@ M.debug = false
|
|||||||
-- class Signal
|
-- class Signal
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- @class u.Signal
|
--- @class u.Signal<T>
|
||||||
--- @field name? string
|
--- @field name? string
|
||||||
--- @field private changing boolean
|
--- @field private changing boolean
|
||||||
--- @field private value any
|
--- @field private value T
|
||||||
--- @field private subscribers table<function, boolean>
|
--- @field private subscribers table<function, boolean>
|
||||||
--- @field private on_dispose_callbacks function[]
|
--- @field private on_dispose_callbacks function[]
|
||||||
local Signal = {}
|
local Signal = {}
|
||||||
M.Signal = Signal
|
M.Signal = Signal
|
||||||
Signal.__index = Signal
|
Signal.__index = Signal
|
||||||
|
|
||||||
--- @param value any
|
--- @param value `T`
|
||||||
--- @param name? string
|
--- @param name? string
|
||||||
--- @return u.Signal
|
--- @return u.Signal<T>
|
||||||
function Signal:new(value, name)
|
function Signal:new(value, name)
|
||||||
local obj = setmetatable({
|
local obj = setmetatable({
|
||||||
name = name,
|
name = name,
|
||||||
@ -30,7 +30,7 @@ function Signal:new(value, name)
|
|||||||
return obj
|
return obj
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param value any
|
--- @param value T
|
||||||
function Signal:set(value)
|
function Signal:set(value)
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
@ -67,11 +67,12 @@ function Signal:set(value)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param value T
|
||||||
function Signal:schedule_set(value)
|
function Signal:schedule_set(value)
|
||||||
vim.schedule(function() self:set(value) end)
|
vim.schedule(function() self:set(value) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @return any
|
--- @return T
|
||||||
function Signal:get()
|
function Signal:get()
|
||||||
local ctx = M.ExecutionContext.current()
|
local ctx = M.ExecutionContext.current()
|
||||||
if ctx then ctx:track(self) end
|
if ctx then ctx:track(self) end
|
||||||
@ -85,8 +86,8 @@ function Signal:update(fn) self:set(fn(self.value)) end
|
|||||||
function Signal:schedule_update(fn) self:schedule_set(fn(self.value)) end
|
function Signal:schedule_update(fn) self:schedule_set(fn(self.value)) end
|
||||||
|
|
||||||
--- @generic U
|
--- @generic U
|
||||||
--- @param fn fun(value: T): U
|
--- @param fn fun(value: T): `U`
|
||||||
--- @return u.Signal --<U>
|
--- @return u.Signal<U>
|
||||||
function Signal:map(fn)
|
function Signal:map(fn)
|
||||||
local mapped_signal = M.create_memo(function()
|
local mapped_signal = M.create_memo(function()
|
||||||
local value = self:get()
|
local value = self:get()
|
||||||
@ -95,13 +96,13 @@ function Signal:map(fn)
|
|||||||
return mapped_signal
|
return mapped_signal
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @return u.Signal
|
--- @return u.Signal<T>
|
||||||
function Signal:clone()
|
function Signal:clone()
|
||||||
return self:map(function(x) return x end)
|
return self:map(function(x) return x end)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param fn fun(value: T): boolean
|
--- @param fn fun(value: T): boolean
|
||||||
--- @return u.Signal -- <T>
|
--- @return u.Signal<T>
|
||||||
function Signal:filter(fn)
|
function Signal:filter(fn)
|
||||||
local filtered_signal = M.create_signal(nil, self.name and self.name .. ':filtered' or nil)
|
local filtered_signal = M.create_signal(nil, self.name and self.name .. ':filtered' or nil)
|
||||||
local unsubscribe_from_self = self:subscribe(function(value)
|
local unsubscribe_from_self = self:subscribe(function(value)
|
||||||
@ -112,10 +113,10 @@ function Signal:filter(fn)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- @param ms number
|
--- @param ms number
|
||||||
--- @return u.Signal -- <T>
|
--- @return u.Signal<T>
|
||||||
function Signal:debounce(ms)
|
function Signal:debounce(ms)
|
||||||
local function set_timeout(timeout, callback)
|
local function set_timeout(timeout, callback)
|
||||||
local timer = (vim.uv or vim.loop).new_timer()
|
local timer = assert((vim.uv or vim.loop).new_timer(), 'could not create new timer')
|
||||||
timer:start(timeout, 0, function()
|
timer:start(timeout, 0, function()
|
||||||
timer:stop()
|
timer:stop()
|
||||||
timer:close()
|
timer:close()
|
||||||
@ -127,7 +128,7 @@ function Signal:debounce(ms)
|
|||||||
local filtered = M.create_signal(self.value, self.name and self.name .. ':debounced' or nil)
|
local filtered = M.create_signal(self.value, self.name and self.name .. ':debounced' or nil)
|
||||||
|
|
||||||
--- @diagnostic disable-next-line: undefined-doc-name
|
--- @diagnostic disable-next-line: undefined-doc-name
|
||||||
--- @type { queued: { value: T, ts: number }[]; timer?: uv_timer_t; }
|
--- @type { queued: { value: T, ts: number }[], timer?: uv.uv_timer_t }
|
||||||
local state = { queued = {}, timer = nil }
|
local state = { queued = {}, timer = nil }
|
||||||
local function clear_timeout()
|
local function clear_timeout()
|
||||||
if state.timer == nil then return end
|
if state.timer == nil then return end
|
||||||
@ -202,6 +203,7 @@ end
|
|||||||
-- class ExecutionContext
|
-- class ExecutionContext
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- @type u.ExecutionContext|nil
|
||||||
local CURRENT_CONTEXT = nil
|
local CURRENT_CONTEXT = nil
|
||||||
|
|
||||||
--- @class u.ExecutionContext
|
--- @class u.ExecutionContext
|
||||||
@ -262,16 +264,18 @@ end
|
|||||||
-- Helpers
|
-- Helpers
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
--- @param value any
|
--- @generic T
|
||||||
|
--- @param value `T`
|
||||||
--- @param name? string
|
--- @param name? string
|
||||||
--- @return u.Signal
|
--- @return u.Signal<T>
|
||||||
function M.create_signal(value, name) return Signal:new(value, name) end
|
function M.create_signal(value, name) return Signal:new(value, name) end
|
||||||
|
|
||||||
--- @param fn function
|
--- @generic T
|
||||||
|
--- @param fn fun(): `T`
|
||||||
--- @param name? string
|
--- @param name? string
|
||||||
--- @return u.Signal
|
--- @return u.Signal
|
||||||
function M.create_memo(fn, name)
|
function M.create_memo(fn, name)
|
||||||
--- @type u.Signal
|
--- @type u.Signal<T> | nil
|
||||||
local result
|
local result
|
||||||
local unsubscribe = M.create_effect(function()
|
local unsubscribe = M.create_effect(function()
|
||||||
local value = fn()
|
local value = fn()
|
||||||
@ -282,8 +286,8 @@ function M.create_memo(fn, name)
|
|||||||
result = M.create_signal(value, name and ('m.s:' .. name) or nil)
|
result = M.create_signal(value, name and ('m.s:' .. name) or nil)
|
||||||
end
|
end
|
||||||
end, name)
|
end, name)
|
||||||
result:on_dispose(unsubscribe)
|
assert(result):on_dispose(unsubscribe)
|
||||||
return result
|
return assert(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @param fn function
|
--- @param fn function
|
||||||
|
Loading…
x
Reference in New Issue
Block a user