better extmark inclusivity
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m21s
All checks were successful
NeoVim tests / code-quality (push) Successful in 1m21s
This commit is contained in:
parent
28714fb51b
commit
103270a241
@ -10,9 +10,6 @@ local Renderer = require('u.renderer').Renderer
|
||||
local h = require('u.renderer').h
|
||||
local tracker = require 'u.tracker'
|
||||
|
||||
-- Utility to trim brackets from strings:
|
||||
local function trimb(s) return (s:gsub('^%[(.*)%]$', '%1')) end
|
||||
|
||||
-- Create a new, temporary, buffer to the side:
|
||||
vim.cmd.vnew()
|
||||
vim.bo.buftype = 'nofile'
|
||||
@ -21,13 +18,13 @@ vim.bo.buflisted = false
|
||||
local renderer = Renderer.new()
|
||||
|
||||
-- Create two signals:
|
||||
local s_name = tracker.create_signal '[whoever-you-are]'
|
||||
local s_age = tracker.create_signal '[ideally-a-number]'
|
||||
local s_name = tracker.create_signal 'whoever-you-are'
|
||||
local s_age = tracker.create_signal 'ideally-a-number'
|
||||
|
||||
-- We can create derived information from the signals above. Say we want to do
|
||||
-- some validation on the input for `age`: we can do that with a memo:
|
||||
local s_age_info = tracker.create_memo(function()
|
||||
local age_raw = trimb(s_age:get())
|
||||
local age_raw = s_age:get()
|
||||
local age_digits = age_raw:match '^%s*(%d+)%s*$'
|
||||
local age_n = age_digits and tonumber(age_digits) or nil
|
||||
return {
|
||||
@ -59,9 +56,8 @@ tracker.create_effect(function()
|
||||
on_change = function(text) s_name:set(text) end,
|
||||
}, name),
|
||||
},
|
||||
'\n',
|
||||
{
|
||||
'Age: ',
|
||||
'\nAge: ',
|
||||
h.Structure({
|
||||
on_change = function(text) s_age:set(text) end,
|
||||
}, age),
|
||||
@ -72,7 +68,7 @@ tracker.create_effect(function()
|
||||
-- Show the values of the signals here, too, so that we can see the
|
||||
-- reactivity in action. If you change the values in the tags above, you
|
||||
-- can see the changes reflected here immediately.
|
||||
{ 'Hello, "', trimb(name), '"!' },
|
||||
{ 'Hello, "', name, '"!' },
|
||||
|
||||
--
|
||||
-- A more complex example: we can do much more complex rendering, based on
|
||||
|
@ -382,6 +382,8 @@ function Range:save_to_extmark()
|
||||
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,
|
||||
})
|
||||
|
@ -28,7 +28,6 @@ M.h = setmetatable({}, {
|
||||
}
|
||||
end,
|
||||
__index = function(_, name)
|
||||
-- vim.print('dynamic hl ' .. name)
|
||||
return function(attributes, children)
|
||||
return M.h('text', vim.tbl_deep_extend('force', { hl = name }, attributes), children)
|
||||
end
|
||||
@ -324,6 +323,13 @@ function Renderer:_reconcile() -- {{{
|
||||
id = extmark.id,
|
||||
end_row = extmark.stop[1],
|
||||
end_col = extmark.stop[2],
|
||||
-- If we change the text starting from the beginning (where the extmark
|
||||
-- is), we don't want the extmark to move to the right.
|
||||
right_gravity = false,
|
||||
-- If we change the text starting from the end (where the end extmark
|
||||
-- is), we don't want the extmark to move to stay stationary: we want
|
||||
-- it to move to the right.
|
||||
end_right_gravity = true,
|
||||
}, extmark.opts)
|
||||
)
|
||||
end
|
||||
@ -385,7 +391,7 @@ function Renderer:_on_text_changed()
|
||||
local end_row0, end_col0 = details.end_row, details.end_col
|
||||
|
||||
if start_row0 == end_row0 and start_col0 == end_col0 then
|
||||
-- Invalid extmark
|
||||
on_change ''
|
||||
else
|
||||
local lines = vim.fn.getregion(
|
||||
{ self.bufnr, start_row0 + 1, start_col0 + 1 },
|
||||
@ -405,9 +411,11 @@ end
|
||||
---
|
||||
--- @private (private for now)
|
||||
--- @param pos0 [number; number]
|
||||
--- @param mode string?
|
||||
--- @return { extmark: u.renderer.RendererExtmark; tag: u.renderer.Tag; }[]
|
||||
function Renderer:get_pos_infos(pos0) -- {{{
|
||||
function Renderer:get_pos_infos(pos0, mode) -- {{{
|
||||
local cursor_line0, cursor_col0 = pos0[1], pos0[2]
|
||||
if not mode then mode = vim.api.nvim_get_mode().mode end
|
||||
|
||||
-- The cursor (block) occupies **two** extmark spaces: one for it's left
|
||||
-- edge, and one for it's right. We need to do our own intersection test,
|
||||
@ -437,10 +445,23 @@ function Renderer:get_pos_infos(pos0) -- {{{
|
||||
--- @param ext u.renderer.RendererExtmark
|
||||
:filter(function(ext)
|
||||
if ext.stop[1] ~= nil and ext.stop[2] ~= nil then
|
||||
return cursor_line0 >= ext.start[1]
|
||||
and cursor_col0 >= ext.start[2]
|
||||
and cursor_line0 <= ext.stop[1]
|
||||
and cursor_col0 < ext.stop[2]
|
||||
-- If we've "ciw" and "collapsed" an extmark onto the cursor,
|
||||
-- the cursor pos will equal the exmark's start AND end. In this
|
||||
-- case, we want to include the extmark.
|
||||
return (
|
||||
cursor_line0 == ext.start[1]
|
||||
and cursor_col0 == ext.start[2]
|
||||
and cursor_line0 == ext.stop[1]
|
||||
and cursor_col0 == ext.stop[2]
|
||||
)
|
||||
or (
|
||||
cursor_line0 >= ext.start[1]
|
||||
and cursor_col0 >= ext.start[2]
|
||||
and cursor_line0 <= ext.stop[1]
|
||||
-- In insert mode, the cursor is "thin", so <= to compensate:
|
||||
-- In normal mode, the cursor is "wide", so < to compensate:
|
||||
and (mode == 'i' and cursor_col0 <= ext.stop[2] or cursor_col0 < ext.stop[2])
|
||||
)
|
||||
else
|
||||
return true
|
||||
end
|
||||
|
@ -103,11 +103,27 @@ describe('Renderer', function()
|
||||
}
|
||||
|
||||
local pos_infos = r:get_pos_infos { 0, 2 }
|
||||
|
||||
assert.are.same(#pos_infos, 1)
|
||||
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup1')
|
||||
assert.are.same(pos_infos[1].extmark.start, { 0, 0 })
|
||||
assert.are.same(pos_infos[1].extmark.stop, { 0, 5 })
|
||||
pos_infos = r:get_pos_infos { 0, 4 }
|
||||
assert.are.same(#pos_infos, 1)
|
||||
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup1')
|
||||
assert.are.same(pos_infos[1].extmark.start, { 0, 0 })
|
||||
assert.are.same(pos_infos[1].extmark.stop, { 0, 5 })
|
||||
|
||||
pos_infos = r:get_pos_infos { 0, 5 }
|
||||
assert.are.same(#pos_infos, 1)
|
||||
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup2')
|
||||
assert.are.same(pos_infos[1].extmark.start, { 0, 5 })
|
||||
assert.are.same(pos_infos[1].extmark.stop, { 0, 11 })
|
||||
|
||||
-- In insert mode, bounds are eagerly included:
|
||||
pos_infos = r:get_pos_infos({ 0, 5 }, 'i')
|
||||
assert.are.same(#pos_infos, 2)
|
||||
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup1')
|
||||
assert.are.same(pos_infos[2].tag.attributes.hl, 'HighlightGroup2')
|
||||
end)
|
||||
end)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user