pass 1: get rid of obsolete modules
Some checks failed
ci / ci (push) Failing after 3m9s

This commit is contained in:
2026-04-04 10:19:23 -06:00
parent 9199a9bc3a
commit b00d8d2fa7
20 changed files with 29 additions and 3758 deletions

View File

@@ -1,31 +0,0 @@
--- @diagnostic disable: undefined-field, need-check-nil
local Buffer = require 'u.buffer'
local withbuf = loadfile './spec/withbuf.lua'()
describe('Buffer', function()
it('should replace all lines', function()
withbuf({}, function()
local buf = Buffer.from_nr()
buf:all():replace 'bleh'
local actual_lines = vim.api.nvim_buf_get_lines(buf.bufnr, 0, -1, false)
assert.are.same({ 'bleh' }, actual_lines)
end)
end)
it('should replace all but first and last lines', function()
withbuf({
'one',
'two',
'three',
}, function()
local buf = Buffer.from_nr()
buf:lines(2, -2):replace 'too'
local actual_lines = vim.api.nvim_buf_get_lines(buf.bufnr, 0, -1, false)
assert.are.same({
'one',
'too',
'three',
}, actual_lines)
end)
end)
end)

View File

@@ -863,34 +863,40 @@ describe('Range', function()
end)
it('discerns range bounds from extmarks beyond the end of the buffer', function()
local Buffer = require 'u.buffer'
local function set_tmp_options(bufnr)
vim.bo[bufnr].bufhidden = 'delete'
vim.bo[bufnr].buflisted = false
vim.bo[bufnr].buftype = 'nowrite'
end
vim.cmd.vnew()
local left = Buffer.current()
left:set_tmp_options()
local left_bufnr = vim.api.nvim_get_current_buf()
set_tmp_options(left_bufnr)
local left = Range.from_buf_text(left_bufnr)
vim.cmd.vnew()
local right = Buffer.current()
right:set_tmp_options()
local right_bufnr = vim.api.nvim_get_current_buf()
set_tmp_options(left_bufnr)
local right = Range.from_buf_text(right_bufnr)
left:all():replace {
left:replace {
'one',
'two',
'three',
}
local left_all_ext = left:all():save_to_extmark()
local left_all_ext = left:save_to_extmark()
right:all():replace {
right:replace {
'foo',
'bar',
}
vim.api.nvim_set_current_buf(right.bufnr)
vim.api.nvim_set_current_buf(right_bufnr)
vim.cmd [[normal! ggyG]]
vim.api.nvim_set_current_buf(left.bufnr)
vim.api.nvim_set_current_buf(left_bufnr)
vim.cmd [[normal! ggVGp]]
assert.are.same({ 'foo', 'bar' }, left_all_ext:range():lines())
vim.api.nvim_buf_delete(left.bufnr, { force = true })
vim.api.nvim_buf_delete(right.bufnr, { force = true })
vim.api.nvim_buf_delete(left_bufnr, { force = true })
vim.api.nvim_buf_delete(right_bufnr, { force = true })
end)
end)

View File

@@ -1,298 +0,0 @@
--- @diagnostic disable: undefined-field, need-check-nil
local R = require 'u.renderer'
local withbuf = loadfile './spec/withbuf.lua'()
local function getlines() return vim.api.nvim_buf_get_lines(0, 0, -1, true) end
describe('Renderer', function()
it('should render text in an empty buffer', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render { 'hello', ' ', 'world' }
assert.are.same(getlines(), { 'hello world' })
end)
end)
it('should result in the correct text after repeated renders', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render { 'hello', ' ', 'world' }
assert.are.same(getlines(), { 'hello world' })
r:render { 'goodbye', ' ', 'world' }
assert.are.same(getlines(), { 'goodbye world' })
r:render { 'hello', ' ', 'universe' }
assert.are.same(getlines(), { 'hello universe' })
end)
end)
it('should handle tags correctly', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render {
R.h('text', { hl = 'HighlightGroup' }, 'hello '),
R.h('text', { hl = 'HighlightGroup' }, 'world'),
}
assert.are.same(getlines(), { 'hello world' })
end)
end)
it('should reconcile added lines', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render { 'line 1', '\n', 'line 2' }
assert.are.same(getlines(), { 'line 1', 'line 2' })
-- Add a new line:
r:render { 'line 1', '\n', 'line 2\n', 'line 3' }
assert.are.same(getlines(), { 'line 1', 'line 2', 'line 3' })
end)
end)
it('should reconcile deleted lines', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render { 'line 1', '\nline 2', '\nline 3' }
assert.are.same(getlines(), { 'line 1', 'line 2', 'line 3' })
-- Remove a line:
r:render { 'line 1', '\nline 3' }
assert.are.same(getlines(), { 'line 1', 'line 3' })
end)
end)
it('should handle multiple nested elements', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render {
R.h('text', {}, {
'first line',
}),
'\n',
R.h('text', {}, 'second line'),
}
assert.are.same(getlines(), { 'first line', 'second line' })
r:render {
R.h('text', {}, 'updated first line'),
'\n',
R.h('text', {}, 'third line'),
}
assert.are.same(getlines(), { 'updated first line', 'third line' })
end)
end)
--
-- get_tags_at
--
it('should return no extmarks for an empty buffer', function()
withbuf({}, function()
local r = R.Renderer.new(0)
local pos_infos = r:get_tags_at { 0, 0 }
assert.are.same(pos_infos, {})
end)
end)
it('should return correct extmark for a given position', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render {
R.h('text', { hl = 'HighlightGroup1' }, 'Hello'),
R.h('text', { hl = 'HighlightGroup2' }, ' World'),
}
local pos_infos = r:get_tags_at { 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_tags_at { 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_tags_at { 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_tags_at({ 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)
it('should return multiple extmarks for overlapping text', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render {
R.h('text', { hl = 'HighlightGroup1' }, {
'Hello',
R.h(
'text',
{ hl = 'HighlightGroup2', extmark = { hl_group = 'HighlightGroup2' } },
' World'
),
}),
}
local pos_infos = r:get_tags_at { 0, 5 }
assert.are.same(#pos_infos, 2)
assert.are.same(pos_infos[1].tag.attributes.hl, 'HighlightGroup2')
assert.are.same(pos_infos[2].tag.attributes.hl, 'HighlightGroup1')
end)
end)
it('repeated patch_lines calls should not change the buffer content', function()
local lines = {
[[{ {]],
[[ bounds = {]],
[[ start1 = { 1, 1 },]],
[[ stop1 = { 4, 1 }]],
[[ },]],
[[ end_right_gravity = true,]],
[[ id = 1,]],
[[ ns_id = 623,]],
[[ ns_name = "my.renderer:91",]],
[[ right_gravity = false]],
[[ } }]],
[[]],
}
withbuf(lines, function()
local Buffer = require 'u.buffer'
R.Renderer.patch_lines(0, nil, lines)
assert.are.same(Buffer.current():all():lines(), lines)
R.Renderer.patch_lines(0, lines, lines)
assert.are.same(Buffer.current():all():lines(), lines)
R.Renderer.patch_lines(0, lines, lines)
assert.are.same(Buffer.current():all():lines(), lines)
end)
end)
it('should fire text-changed events', function()
withbuf({}, function()
local Buffer = require 'u.buffer'
local buf = Buffer.current()
local r = R.Renderer.new(0)
local captured_changed_text = ''
r:render {
R.h('text', {
on_change = function(txt) captured_changed_text = txt end,
}, {
'one\n',
'two\n',
'three\n',
}),
}
vim.fn.setreg('"', 'bleh')
vim.cmd [[normal! ggVGp]]
-- For some reason, the autocmd does not fire in the busted environment.
-- We'll call the handler ourselves:
r:_on_text_changed()
assert.are.same(buf:all():text(), 'bleh')
assert.are.same(captured_changed_text, 'bleh')
vim.fn.setreg('"', '')
vim.cmd [[normal! ggdG]]
-- We'll call the handler ourselves:
r:_on_text_changed()
assert.are.same(buf:all():text(), '')
assert.are.same(captured_changed_text, '')
end)
withbuf({}, function()
local Buffer = require 'u.buffer'
local buf = Buffer.current()
local r = R.Renderer.new(0)
--- @type string?
local captured_changed_text = nil
r:render {
'prefix:',
R.h('text', {
on_change = function(txt) captured_changed_text = txt end,
}, {
'one',
}),
'suffix',
}
vim.fn.setreg('"', 'bleh')
vim.api.nvim_win_set_cursor(0, { 1, 9 })
vim.cmd [[normal! vhhd]]
-- For some reason, the autocmd does not fire in the busted environment.
-- We'll call the handler ourselves:
r:_on_text_changed()
assert.are.same(buf:all():text(), 'prefix:suffix')
assert.are.same(captured_changed_text, '')
end)
end)
it('should find tags by position', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render {
'pre',
R.h('text', {
id = 'outer',
}, {
'inner-pre',
R.h('text', {
id = 'inner',
}, {
'inner-text',
}),
'inner-post',
}),
'post',
}
local tags = r:get_tags_at { 0, 11 }
assert.are.same(#tags, 1)
assert.are.same(tags[1].tag.attributes.id, 'outer')
tags = r:get_tags_at { 0, 12 }
assert.are.same(#tags, 2)
assert.are.same(tags[1].tag.attributes.id, 'inner')
assert.are.same(tags[2].tag.attributes.id, 'outer')
end)
end)
it('should find tags by id', function()
withbuf({}, function()
local r = R.Renderer.new(0)
r:render {
R.h('text', {
id = 'outer',
}, {
'inner-pre',
R.h('text', {
id = 'inner',
}, {
'inner-text',
}),
'inner-post',
}),
'post',
}
local bounds = r:get_tag_bounds 'outer'
assert.are.same(bounds, { start = { 0, 0 }, stop = { 0, 29 } })
bounds = r:get_tag_bounds 'inner'
assert.are.same(bounds, { start = { 0, 9 }, stop = { 0, 19 } })
end)
end)
end)

View File

@@ -1,207 +0,0 @@
--- @diagnostic disable: undefined-field, need-check-nil
local tracker = require 'u.tracker'
local Signal = tracker.Signal
local ExecutionContext = tracker.ExecutionContext
describe('Signal', function()
local signal
before_each(function() signal = Signal:new(0, 'testSignal') end)
it('should initialize with correct parameters', function()
assert.is.equal(signal.value, 0)
assert.is.equal(signal.name, 'testSignal')
assert.is.not_nil(signal.subscribers)
assert.is.equal(#signal.subscribers, 0)
assert.is.equal(signal.changing, false)
end)
it('should set new value and notify subscribers', function()
local called = false
signal:subscribe(function(value)
called = true
assert.is.equal(value, 42)
end)
signal:set(42)
assert.is.equal(called, true)
end)
it('should not notify subscribers during circular dependency', function()
signal.changing = true
local notified = false
signal:subscribe(function() notified = true end)
signal:set(42)
assert.is.equal(notified, false) -- No notification should occur
end)
it('should get current value', function()
signal:set(100)
assert.is.equal(signal:get(), 100)
end)
it('should update value with function', function()
signal:set(10)
signal:update(function(value) return value * 2 end)
assert.is.equal(signal:get(), 20)
end)
it('should dispose subscribers', function()
local called = false
local unsubscribe = signal:subscribe(function() called = true end)
unsubscribe()
signal:set(10)
assert.is.equal(called, false) -- Should not be notified
end)
describe('Signal:map', function()
it('should transform the signal value', function()
local test_signal = Signal:new(5)
local mapped_signal = test_signal:map(function(value) return value * 2 end)
assert.is.equal(mapped_signal:get(), 10) -- Initial transformation
test_signal:set(10)
assert.is.equal(mapped_signal:get(), 20) -- Updated transformation
end)
it('should handle empty transformations', function()
local test_signal = Signal:new(nil)
local mapped_signal = test_signal:map(function(value) return value or 'default' end)
assert.is.equal(mapped_signal:get(), 'default') -- Return default
test_signal:set 'new value'
assert.is.equal(mapped_signal:get(), 'new value') -- Return new value
end)
end)
describe('Signal:filter', function()
it('should only emit values that pass the filter', function()
local test_signal = Signal:new(5)
local filtered_signal = test_signal:filter(function(value) return value > 10 end)
assert.is.equal(filtered_signal:get(), nil) -- Initial value should not pass
test_signal:set(15)
assert.is.equal(filtered_signal:get(), 15) -- Now filtered
test_signal:set(8)
assert.is.equal(filtered_signal:get(), 15) -- Does not pass the filter
end)
it('should handle empty initial values', function()
local test_signal = Signal:new(nil)
local filtered_signal = test_signal:filter(function(value) return value ~= nil end)
assert.is.equal(filtered_signal:get(), nil) -- Should be nil
test_signal:set(10)
assert.is.equal(filtered_signal:get(), 10) -- Should pass now
end)
end)
describe('create_memo', function()
it('should compute a derived value and update when dependencies change', function()
local test_signal = Signal:new(2)
local memoized_signal = tracker.create_memo(function() return test_signal:get() * 2 end)
assert.is.equal(memoized_signal:get(), 4) -- Initially compute 2 * 2
test_signal:set(3)
assert.is.equal(memoized_signal:get(), 6) -- Update to 3 * 2 = 6
test_signal:set(5)
assert.is.equal(memoized_signal:get(), 10) -- Update to 5 * 2 = 10
end)
it('should not recompute if the dependencies do not change', function()
local call_count = 0
local test_signal = Signal:new(10)
local memoized_signal = tracker.create_memo(function()
call_count = call_count + 1
return test_signal:get() + 1
end)
assert.is.equal(memoized_signal:get(), 11) -- Compute first value
assert.is.equal(call_count, 1) -- Should compute once
memoized_signal:get() -- Call again, should use memoized value
assert.is.equal(call_count, 1) -- Still should only be one call
test_signal:set(10) -- Set the same value
assert.is.equal(memoized_signal:get(), 11)
assert.is.equal(call_count, 2)
test_signal:set(20)
assert.is.equal(memoized_signal:get(), 21)
assert.is.equal(call_count, 3)
end)
end)
describe('create_effect', function()
it('should track changes and execute callback', function()
local test_signal = Signal:new(5)
local call_count = 0
tracker.create_effect(function()
test_signal:get() -- track as a dependency
call_count = call_count + 1
end)
assert.is.equal(call_count, 1)
test_signal:set(10)
assert.is.equal(call_count, 2)
end)
it('should clean up signals and not call after dispose', function()
local test_signal = Signal:new(5)
local call_count = 0
local unsubscribe = tracker.create_effect(function()
call_count = call_count + 1
return test_signal:get() * 2
end)
assert.is.equal(call_count, 1) -- Initially calls
unsubscribe() -- Unsubscribe the effect
test_signal:set(10) -- Update signal value
assert.is.equal(call_count, 1) -- Callback should not be called again
end)
end)
end)
describe('ExecutionContext', function()
local context
before_each(function() context = ExecutionContext:new() end)
it('should initialize a new context', function()
assert.is.table(context.signals)
assert.is.table(context.subscribers)
end)
it('should track signals', function()
local signal = Signal:new(0)
context:track(signal)
assert.is.equal(next(context.signals), signal) -- Check if signal is tracked
end)
it('should subscribe to signals', function()
local signal = Signal:new(0)
local callback_called = false
context:track(signal)
context:subscribe(function() callback_called = true end)
signal:set(100)
assert.is.equal(callback_called, true) -- Callback should be called
end)
it('should dispose tracked signals', function()
local signal = Signal:new(0)
context:track(signal)
context:dispose()
assert.is.falsy(next(context.signals)) -- Should not have any tracked signals
end)
end)