Add jj and herdr
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
local T
|
||||
local expect = MiniTest.expect
|
||||
local child = MiniTest.new_child_neovim()
|
||||
|
||||
local source = debug.getinfo(1, 'S').source
|
||||
local root = vim.fn.fnamemodify(source:sub(2), ':p:h:h')
|
||||
|
||||
local function write_config(lines)
|
||||
child.lua_func(function(config_lines)
|
||||
local path = vim.env.HERDR_SPLITS_CONFIG
|
||||
vim.fn.mkdir(vim.fn.fnamemodify(path, ':h'), 'p')
|
||||
vim.fn.writefile(config_lines, path)
|
||||
end, lines)
|
||||
end
|
||||
|
||||
T = MiniTest.new_set({
|
||||
hooks = {
|
||||
pre_case = function()
|
||||
child.restart({ '--noplugin', '-u', 'NONE', '-i', 'NONE' })
|
||||
child.cmd('set runtimepath^=' .. vim.fn.fnameescape(root))
|
||||
child.lua([[
|
||||
local test_dir = vim.fn.tempname()
|
||||
vim.fn.mkdir(test_dir, 'p')
|
||||
vim.g.herdr_splits_test_dir = test_dir
|
||||
vim.env.HOME = test_dir .. '/home'
|
||||
vim.env.XDG_CONFIG_HOME = test_dir .. '/xdg'
|
||||
vim.env.HERDR_SPLITS_CONFIG = test_dir .. '/nested/herdr-splits.conf'
|
||||
vim.env.HERDR_BIN_PATH = test_dir .. '/missing-herdr'
|
||||
vim.env.HERDR_PLUGIN_CONFIG_DIR = nil
|
||||
]])
|
||||
end,
|
||||
post_case = function()
|
||||
local test_dir = child.g.herdr_splits_test_dir
|
||||
child.stop()
|
||||
vim.fn.delete(test_dir, 'rf')
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
T['to_herdr translates key notation'] = function()
|
||||
local translate = function(value)
|
||||
return child.lua_func(function(key)
|
||||
return require('herdr-splits.conf').to_herdr(key)
|
||||
end, value)
|
||||
end
|
||||
|
||||
expect.equality(translate('<C-M-Left>'), 'ctrl+alt+left')
|
||||
expect.equality(translate('<A-Return>'), 'alt+enter')
|
||||
expect.equality(translate('<S-Space>'), 'shift+space')
|
||||
expect.equality(translate('H'), 'h')
|
||||
expect.equality(translate('<Escape>'), 'esc')
|
||||
expect.equality(translate(''), vim.NIL)
|
||||
expect.equality(translate(false), vim.NIL)
|
||||
expect.equality(translate('<C>'), vim.NIL)
|
||||
end
|
||||
|
||||
T['read_managed handles a missing file'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local values, adopted = require('herdr-splits.conf').read_managed()
|
||||
return { adopted = adopted, count = vim.tbl_count(values) }
|
||||
end)
|
||||
|
||||
expect.equality(result, { adopted = false, count = 0 })
|
||||
end
|
||||
|
||||
T['read_managed adopts managed legacy values with last value winning'] = function()
|
||||
write_config({
|
||||
'# legacy config',
|
||||
' nav_key_left = ctrl+old',
|
||||
'nav_key_left=ctrl+new # last value wins',
|
||||
'resize_key_up = alt+up',
|
||||
'unzoom_on_nav=false',
|
||||
'nav_at_edge=stop',
|
||||
'unknown_key=ignored',
|
||||
})
|
||||
|
||||
local result = child.lua_func(function()
|
||||
local values, adopted = require('herdr-splits.conf').read_managed()
|
||||
return {
|
||||
adopted = adopted,
|
||||
nav_left = values.nav_keys.left,
|
||||
resize_up = values.resize_keys.up,
|
||||
unzoom_on_nav = values.unzoom_on_nav,
|
||||
nav_at_edge = values.nav_at_edge,
|
||||
unknown = values.unknown_key,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
adopted = true,
|
||||
nav_left = 'ctrl+new',
|
||||
resize_up = 'alt+up',
|
||||
unzoom_on_nav = false,
|
||||
nav_at_edge = 'stop',
|
||||
})
|
||||
end
|
||||
|
||||
T['write creates generated content without leftover temporary files'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local conf = require('herdr-splits.conf')
|
||||
local ok, err = conf.write({
|
||||
nav_keys = { left = 'ctrl+h', down = 'ctrl+j', up = 'ctrl+k', right = 'ctrl+l' },
|
||||
resize_keys = { left = 'alt+h', down = 'alt+j', up = 'alt+k', right = 'alt+l' },
|
||||
unzoom_on_nav = false,
|
||||
nav_at_edge = 'stop',
|
||||
})
|
||||
local values, adopted = conf.read_managed()
|
||||
return {
|
||||
ok = ok,
|
||||
err = err,
|
||||
adopted = adopted,
|
||||
adopted_count = vim.tbl_count(values),
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, { ok = true, adopted = false, adopted_count = 0 })
|
||||
|
||||
local content = child.lua_func(function()
|
||||
local file = assert(io.open(vim.env.HERDR_SPLITS_CONFIG, 'r'))
|
||||
local bytes = file:read('*a')
|
||||
file:close()
|
||||
return bytes
|
||||
end)
|
||||
expect.equality(content, table.concat({
|
||||
'# herdr-splits-generated-v1',
|
||||
'# herdr-splits plugin config — GENERATED by herdr-splits.nvim setup().',
|
||||
'# Regenerated from defaults + setup() opts on every setup(); do not edit by hand.',
|
||||
'# A headerless/legacy conf is adopted once on migration (see the startup',
|
||||
'# notice), then overwritten thereafter — remove an opt in setup() to revert.',
|
||||
'nav_key_left=ctrl+h',
|
||||
'nav_key_down=ctrl+j',
|
||||
'nav_key_up=ctrl+k',
|
||||
'nav_key_right=ctrl+l',
|
||||
'resize_key_left=alt+h',
|
||||
'resize_key_down=alt+j',
|
||||
'resize_key_up=alt+k',
|
||||
'resize_key_right=alt+l',
|
||||
'unzoom_on_nav=false',
|
||||
'nav_at_edge=stop',
|
||||
'',
|
||||
}, '\n'))
|
||||
expect.equality(child.lua_get([[vim.fn.glob(vim.env.HERDR_SPLITS_CONFIG .. '.tmp.*', false, true)]]), {})
|
||||
end
|
||||
|
||||
T['config setup applies precedence and resets omitted managed options'] = function()
|
||||
write_config({
|
||||
'nav_key_left=ctrl+legacy',
|
||||
'resize_key_left=alt+legacy',
|
||||
'unzoom_on_nav=false',
|
||||
'nav_at_edge=stop',
|
||||
})
|
||||
|
||||
local result = child.lua_func(function()
|
||||
vim.notify = function() end
|
||||
local config = require('herdr-splits.config')
|
||||
|
||||
config.setup({
|
||||
nav_keys = { left = '<C-x>' },
|
||||
unzoom_on_nav = true,
|
||||
})
|
||||
local first = {
|
||||
nav_left = config.nav_keys.left,
|
||||
resize_left = config.resize_keys.left,
|
||||
unzoom_on_nav = config.unzoom_on_nav,
|
||||
nav_at_edge = config.nav_at_edge,
|
||||
}
|
||||
|
||||
config.setup({ nav_keys = { right = '<C-r>' } })
|
||||
local second = {
|
||||
nav_left = config.nav_keys.left,
|
||||
nav_right = config.nav_keys.right,
|
||||
resize_left = config.resize_keys.left,
|
||||
unzoom_on_nav = config.unzoom_on_nav,
|
||||
nav_at_edge = config.nav_at_edge,
|
||||
}
|
||||
return { first = first, second = second }
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
first = {
|
||||
nav_left = 'ctrl+x',
|
||||
resize_left = 'alt+legacy',
|
||||
unzoom_on_nav = true,
|
||||
nav_at_edge = 'stop',
|
||||
},
|
||||
second = {
|
||||
nav_left = 'ctrl+h',
|
||||
nav_right = 'ctrl+r',
|
||||
resize_left = 'alt+h',
|
||||
unzoom_on_nav = true,
|
||||
nav_at_edge = 'wrap',
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
return T
|
||||
@@ -0,0 +1,267 @@
|
||||
local T
|
||||
local expect = MiniTest.expect
|
||||
local child = MiniTest.new_child_neovim()
|
||||
|
||||
local source = debug.getinfo(1, 'S').source
|
||||
local root = vim.fn.fnamemodify(source:sub(2), ':p:h:h')
|
||||
|
||||
T = MiniTest.new_set({
|
||||
hooks = {
|
||||
pre_case = function()
|
||||
child.restart({ '--noplugin', '-u', 'NONE', '-i', 'NONE' })
|
||||
child.cmd('set runtimepath^=' .. vim.fn.fnameescape(root))
|
||||
end,
|
||||
post_case = function()
|
||||
child.stop()
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
T['resolves the binary and requires a complete session environment'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local config = require('herdr-splits.config')
|
||||
local herdr = require('herdr-splits.herdr')
|
||||
|
||||
vim.env.HERDR_BIN_PATH = '/env/herdr'
|
||||
config.herdr_bin = nil
|
||||
local from_env = herdr.herdr_bin()
|
||||
config.herdr_bin = '/config/herdr'
|
||||
local from_config = herdr.herdr_bin()
|
||||
config.herdr_bin = nil
|
||||
vim.env.HERDR_BIN_PATH = nil
|
||||
local fallback = herdr.herdr_bin()
|
||||
|
||||
vim.env.HERDR_ENV = nil
|
||||
vim.env.HERDR_PANE_ID = nil
|
||||
local absent = { herdr.is_in_session(), herdr.current_pane_id() or '<nil>' }
|
||||
vim.env.HERDR_ENV = '1'
|
||||
vim.env.HERDR_PANE_ID = ''
|
||||
local empty = { herdr.is_in_session(), herdr.current_pane_id() or '<nil>' }
|
||||
vim.env.HERDR_PANE_ID = 'pane-7'
|
||||
local present = { herdr.is_in_session(), herdr.current_pane_id() }
|
||||
|
||||
return {
|
||||
binaries = { from_env, from_config, fallback },
|
||||
absent = absent,
|
||||
empty = empty,
|
||||
present = present,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
binaries = { '/env/herdr', '/config/herdr', 'herdr' },
|
||||
absent = { false, '<nil>' },
|
||||
empty = { false, '<nil>' },
|
||||
present = { true, 'pane-7' },
|
||||
})
|
||||
end
|
||||
|
||||
T['parses edge responses and rejects invalid command output'] = function()
|
||||
local result = child.lua_func(function()
|
||||
vim.env.HERDR_ENV = '1'
|
||||
vim.env.HERDR_PANE_ID = 'pane-7'
|
||||
local config = require('herdr-splits.config')
|
||||
config.herdr_bin = '/fake/herdr'
|
||||
|
||||
local queue = {
|
||||
{ stdout = vim.json.encode({ result = { edges = { left = true } } }), stderr = '', code = 0 },
|
||||
{ stdout = vim.json.encode({ result = { edges = { left = false } } }), stderr = '', code = 0 },
|
||||
{ stdout = '{bad', stderr = '', code = 0 },
|
||||
{ stdout = '', stderr = '', code = 0 },
|
||||
{ stdout = vim.json.encode({ result = {} }), stderr = '', code = 0 },
|
||||
{ stdout = '{}', stderr = 'failed', code = 2 },
|
||||
{ stdout = vim.json.encode({ result = { edges = {} } }), stderr = '', code = 0 },
|
||||
{ stdout = '{"result":{"edges":{"left":null}}}', stderr = '', code = 0 },
|
||||
{ stdout = vim.json.encode({ result = { edges = { left = 'yes' } } }), stderr = '', code = 0 },
|
||||
}
|
||||
local calls = {}
|
||||
vim.system = function(argv, opts)
|
||||
calls[#calls + 1] = { argv = vim.deepcopy(argv), opts = vim.deepcopy(opts) }
|
||||
local item = table.remove(queue, 1)
|
||||
return { wait = function() return item end }
|
||||
end
|
||||
|
||||
package.loaded['herdr-splits.herdr'] = nil
|
||||
local herdr = require('herdr-splits.herdr')
|
||||
local values = {}
|
||||
for i = 1, 9 do
|
||||
local value = herdr.current_pane_at_edge('left')
|
||||
values[i] = value == nil and '<nil>' or value
|
||||
end
|
||||
return { values = values, calls = calls }
|
||||
end)
|
||||
|
||||
expect.equality(result.values, {
|
||||
true, false, '<nil>', '<nil>', '<nil>', '<nil>', '<nil>', '<nil>', '<nil>',
|
||||
})
|
||||
expect.equality(#result.calls, 9)
|
||||
for _, call in ipairs(result.calls) do
|
||||
expect.equality(call, {
|
||||
argv = { '/fake/herdr', 'pane', 'edges', '--current' },
|
||||
opts = { text = true },
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
T['parses zoom responses and rejects invalid command output'] = function()
|
||||
local result = child.lua_func(function()
|
||||
vim.env.HERDR_ENV = '1'
|
||||
vim.env.HERDR_PANE_ID = 'pane-7'
|
||||
local queue = {
|
||||
{ stdout = vim.json.encode({ result = { layout = { zoomed = true } } }), stderr = '', code = 0 },
|
||||
{ stdout = vim.json.encode({ result = { layout = { zoomed = false } } }), stderr = '', code = 0 },
|
||||
{ stdout = '{bad', stderr = '', code = 0 },
|
||||
{ stdout = vim.json.encode({ result = {} }), stderr = '', code = 0 },
|
||||
{ stdout = '{}', stderr = '', code = 1 },
|
||||
{ stdout = vim.json.encode({ result = { layout = {} } }), stderr = '', code = 0 },
|
||||
{ stdout = '{"result":{"layout":{"zoomed":null}}}', stderr = '', code = 0 },
|
||||
{ stdout = vim.json.encode({ result = { layout = { zoomed = 1 } } }), stderr = '', code = 0 },
|
||||
}
|
||||
local calls = {}
|
||||
vim.system = function(argv, opts)
|
||||
calls[#calls + 1] = { argv = vim.deepcopy(argv), opts = vim.deepcopy(opts) }
|
||||
local item = table.remove(queue, 1)
|
||||
return { wait = function() return item end }
|
||||
end
|
||||
|
||||
package.loaded['herdr-splits.herdr'] = nil
|
||||
local herdr = require('herdr-splits.herdr')
|
||||
local values = {}
|
||||
for i = 1, 8 do
|
||||
local value = herdr.current_pane_is_zoomed()
|
||||
values[i] = value == nil and '<nil>' or value
|
||||
end
|
||||
return { values = values, calls = calls }
|
||||
end)
|
||||
|
||||
expect.equality(result.values, {
|
||||
true, false, '<nil>', '<nil>', '<nil>', '<nil>', '<nil>', '<nil>',
|
||||
})
|
||||
expect.equality(#result.calls, 8)
|
||||
for _, call in ipairs(result.calls) do
|
||||
expect.equality(call.argv, { 'herdr', 'pane', 'layout', '--current' })
|
||||
expect.equality(call.opts, { text = true })
|
||||
end
|
||||
end
|
||||
|
||||
T['rejects JSON null for pane queries'] = function()
|
||||
local result = child.lua_func(function()
|
||||
vim.env.HERDR_ENV = '1'
|
||||
vim.env.HERDR_PANE_ID = 'pane-7'
|
||||
local queue = {
|
||||
'null',
|
||||
'{"result":null}',
|
||||
'{"result":{"edges":null}}',
|
||||
'null',
|
||||
'{"result":null}',
|
||||
'{"result":{"layout":null}}',
|
||||
}
|
||||
vim.system = function()
|
||||
local stdout = table.remove(queue, 1)
|
||||
return {
|
||||
wait = function()
|
||||
return { stdout = stdout, stderr = '', code = 0 }
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
package.loaded['herdr-splits.herdr'] = nil
|
||||
local herdr = require('herdr-splits.herdr')
|
||||
local values = {}
|
||||
for _ = 1, 3 do
|
||||
local ok, value = pcall(herdr.current_pane_at_edge, 'left')
|
||||
values[#values + 1] = { ok, value == nil and '<nil>' or value }
|
||||
end
|
||||
for _ = 1, 3 do
|
||||
local ok, value = pcall(herdr.current_pane_is_zoomed)
|
||||
values[#values + 1] = { ok, value == nil and '<nil>' or value }
|
||||
end
|
||||
return values
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
{ true, '<nil>' },
|
||||
{ true, '<nil>' },
|
||||
{ true, '<nil>' },
|
||||
{ true, '<nil>' },
|
||||
{ true, '<nil>' },
|
||||
{ true, '<nil>' },
|
||||
})
|
||||
end
|
||||
|
||||
T['focus and unzoom use exact commands and report exit status'] = function()
|
||||
local result = child.lua_func(function()
|
||||
vim.env.HERDR_ENV = '1'
|
||||
vim.env.HERDR_PANE_ID = 'pane-7'
|
||||
local queue = {
|
||||
{ stdout = '', stderr = '', code = 0 },
|
||||
{ stdout = '', stderr = 'no neighbor', code = 1 },
|
||||
{ stdout = '', stderr = '', code = 0 },
|
||||
{ stdout = '', stderr = 'failed', code = 1 },
|
||||
}
|
||||
local calls = {}
|
||||
vim.system = function(argv, opts)
|
||||
calls[#calls + 1] = { argv = vim.deepcopy(argv), opts = vim.deepcopy(opts) }
|
||||
local item = table.remove(queue, 1)
|
||||
return { wait = function() return item end }
|
||||
end
|
||||
|
||||
package.loaded['herdr-splits.herdr'] = nil
|
||||
local herdr = require('herdr-splits.herdr')
|
||||
return {
|
||||
values = {
|
||||
herdr.focus_pane('right'),
|
||||
herdr.focus_pane('left'),
|
||||
herdr.unzoom(),
|
||||
herdr.unzoom(),
|
||||
},
|
||||
calls = calls,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result.values, { true, false, true, false })
|
||||
expect.equality(result.calls, {
|
||||
{ argv = { 'herdr', 'pane', 'focus', '--direction', 'right', '--current' }, opts = { text = true } },
|
||||
{ argv = { 'herdr', 'pane', 'focus', '--direction', 'left', '--current' }, opts = { text = true } },
|
||||
{ argv = { 'herdr', 'pane', 'zoom', '--off', '--current' }, opts = { text = true } },
|
||||
{ argv = { 'herdr', 'pane', 'zoom', '--off', '--current' }, opts = { text = true } },
|
||||
})
|
||||
end
|
||||
|
||||
T['resize formats ratios and reports exit status'] = function()
|
||||
local result = child.lua_func(function()
|
||||
vim.env.HERDR_ENV = '1'
|
||||
vim.env.HERDR_PANE_ID = 'pane-7'
|
||||
local queue = {
|
||||
{ stdout = '', stderr = '', code = 0 },
|
||||
{ stdout = '', stderr = 'failed', code = 1 },
|
||||
}
|
||||
local calls = {}
|
||||
vim.system = function(argv, opts)
|
||||
calls[#calls + 1] = { argv = vim.deepcopy(argv), opts = vim.deepcopy(opts) }
|
||||
local item = table.remove(queue, 1)
|
||||
return { wait = function() return item end }
|
||||
end
|
||||
|
||||
package.loaded['herdr-splits.herdr'] = nil
|
||||
local herdr = require('herdr-splits.herdr')
|
||||
return {
|
||||
values = { herdr.resize_pane('down', 0.03), herdr.resize_pane('left', 1 / 3) },
|
||||
calls = calls,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result.values, { true, false })
|
||||
expect.equality(result.calls, {
|
||||
{
|
||||
argv = { 'herdr', 'pane', 'resize', '--direction', 'down', '--amount', '0.0300', '--current' },
|
||||
opts = { text = true },
|
||||
},
|
||||
{
|
||||
argv = { 'herdr', 'pane', 'resize', '--direction', 'left', '--amount', '0.3333', '--current' },
|
||||
opts = { text = true },
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
return T
|
||||
@@ -0,0 +1,520 @@
|
||||
local T
|
||||
local expect = MiniTest.expect
|
||||
local child = MiniTest.new_child_neovim()
|
||||
|
||||
local source = debug.getinfo(1, 'S').source
|
||||
local root = vim.fn.fnamemodify(source:sub(2), ':p:h:h')
|
||||
|
||||
T = MiniTest.new_set({
|
||||
hooks = {
|
||||
pre_case = function()
|
||||
child.restart({ '--noplugin', '-u', 'NONE', '-i', 'NONE' })
|
||||
child.cmd('set runtimepath^=' .. vim.fn.fnameescape(root))
|
||||
end,
|
||||
post_case = function()
|
||||
child.stop()
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
T['moves through native horizontal and vertical splits without delegation'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
focus_pane = function(direction) calls[#calls + 1] = direction end,
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local horizontal = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(horizontal, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(horizontal[1])
|
||||
nav.move_cursor('right')
|
||||
local moved_right = vim.api.nvim_get_current_win() == horizontal[2]
|
||||
|
||||
vim.cmd('only')
|
||||
vim.o.splitbelow = true
|
||||
vim.cmd('split')
|
||||
local vertical = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(vertical, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[1] < vim.api.nvim_win_get_position(b)[1]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(vertical[1])
|
||||
nav.move_cursor('down')
|
||||
local moved_down = vim.api.nvim_get_current_win() == vertical[2]
|
||||
|
||||
return { moved_right = moved_right, moved_down = moved_down, calls = calls }
|
||||
end)
|
||||
|
||||
expect.equality(result, { moved_right = true, moved_down = true, calls = {} })
|
||||
end
|
||||
|
||||
T['applies typed navigation counts without wrapping or delegation'] = function()
|
||||
child.lua_func(function()
|
||||
_G.nav_delegations = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
focus_pane = function(direction)
|
||||
_G.nav_delegations[#_G.nav_delegations + 1] = direction
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
vim.o.splitright = true
|
||||
for _ = 1, 3 do
|
||||
vim.cmd('vsplit')
|
||||
end
|
||||
_G.nav_count_wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(_G.nav_count_wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(_G.nav_count_wins[1])
|
||||
vim.keymap.set('n', 'x', function()
|
||||
nav.move_cursor('right', { at_edge = 'stop' })
|
||||
end)
|
||||
end)
|
||||
|
||||
child.type_keys('2x')
|
||||
local after_two = child.lua_get('vim.api.nvim_get_current_win() == _G.nav_count_wins[3]')
|
||||
child.type_keys('5x')
|
||||
local exhausted_at_last = child.lua_get('vim.api.nvim_get_current_win() == _G.nav_count_wins[4]')
|
||||
child.type_keys('5x')
|
||||
local stayed_at_last = child.lua_get('vim.api.nvim_get_current_win() == _G.nav_count_wins[4]')
|
||||
local delegations = child.lua_get('_G.nav_delegations')
|
||||
|
||||
expect.equality({
|
||||
after_two = after_two,
|
||||
exhausted_at_last = exhausted_at_last,
|
||||
stayed_at_last = stayed_at_last,
|
||||
delegations = delegations,
|
||||
}, {
|
||||
after_two = true,
|
||||
exhausted_at_last = true,
|
||||
stayed_at_last = true,
|
||||
delegations = {},
|
||||
})
|
||||
end
|
||||
|
||||
T['delegates normal floats but not embedded floats'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
focus_pane = function(direction)
|
||||
calls[#calls + 1] = direction
|
||||
return true
|
||||
end,
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
local normal = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, true), true, {
|
||||
relative = 'editor', row = 1, col = 1, width = 12, height = 3, zindex = 50,
|
||||
})
|
||||
nav.move_cursor('right')
|
||||
local normal_stayed = vim.api.nvim_get_current_win() == normal
|
||||
|
||||
vim.api.nvim_open_win(vim.api.nvim_create_buf(false, true), true, {
|
||||
relative = 'editor', row = 2, col = 2, width = 12, height = 3, zindex = 49,
|
||||
})
|
||||
nav.move_cursor('left')
|
||||
|
||||
return { calls = calls, normal_stayed = normal_stayed }
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
calls = { 'right' },
|
||||
normal_stayed = true,
|
||||
})
|
||||
end
|
||||
|
||||
T['applies no-session stop, wrap, and callback edge behavior'] = function()
|
||||
local result = child.lua_func(function()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
local function horizontal_pair()
|
||||
vim.cmd('only')
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[1])
|
||||
return wins
|
||||
end
|
||||
|
||||
local stop_wins = horizontal_pair()
|
||||
nav.move_cursor('left', { at_edge = 'stop' })
|
||||
local stopped = vim.api.nvim_get_current_win() == stop_wins[1]
|
||||
|
||||
local wrap_wins = horizontal_pair()
|
||||
nav.move_cursor('left', { at_edge = 'wrap' })
|
||||
local wrapped = vim.api.nvim_get_current_win() == wrap_wins[2]
|
||||
|
||||
local callback_wins = horizontal_pair()
|
||||
local callback = {}
|
||||
nav.move_cursor('left', {
|
||||
at_edge = function(ctx)
|
||||
callback.direction = ctx.direction
|
||||
callback.is_sidebar = ctx.is_sidebar
|
||||
callback.has_split = type(ctx.split) == 'function'
|
||||
callback.has_wrap = type(ctx.wrap) == 'function'
|
||||
ctx.wrap()
|
||||
end,
|
||||
})
|
||||
callback.wrapped = vim.api.nvim_get_current_win() == callback_wins[2]
|
||||
|
||||
return {
|
||||
stopped = stopped,
|
||||
wrapped = wrapped,
|
||||
callback = callback,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
stopped = true,
|
||||
wrapped = true,
|
||||
callback = {
|
||||
direction = 'left',
|
||||
is_sidebar = false,
|
||||
has_split = true,
|
||||
has_wrap = true,
|
||||
wrapped = true,
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
T['creates local edge splits and preserves split preferences'] = function()
|
||||
local result = child.lua_func(function()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
local cases = {}
|
||||
|
||||
local function exercise(direction, preference)
|
||||
vim.cmd('only')
|
||||
vim.o.splitright = preference
|
||||
vim.o.splitbelow = preference
|
||||
local before = #vim.api.nvim_tabpage_list_wins(0)
|
||||
local original = vim.api.nvim_get_current_win()
|
||||
|
||||
nav.move_cursor(direction, { at_edge = 'split' })
|
||||
|
||||
local current = vim.api.nvim_get_current_win()
|
||||
local original_position = vim.api.nvim_win_get_position(original)
|
||||
local current_position = vim.api.nvim_win_get_position(current)
|
||||
local placement_matches_preference
|
||||
if direction == 'left' or direction == 'right' then
|
||||
if preference then
|
||||
placement_matches_preference = current_position[2] > original_position[2]
|
||||
else
|
||||
placement_matches_preference = current_position[2] < original_position[2]
|
||||
end
|
||||
elseif preference then
|
||||
placement_matches_preference = current_position[1] > original_position[1]
|
||||
else
|
||||
placement_matches_preference = current_position[1] < original_position[1]
|
||||
end
|
||||
|
||||
cases[#cases + 1] = {
|
||||
direction = direction,
|
||||
preference = preference,
|
||||
created_one = #vim.api.nvim_tabpage_list_wins(0) == before + 1,
|
||||
focused_new = current ~= original,
|
||||
placement_matches_preference = placement_matches_preference,
|
||||
splitright_restored = vim.o.splitright == preference,
|
||||
splitbelow_restored = vim.o.splitbelow == preference,
|
||||
}
|
||||
end
|
||||
|
||||
for _, direction in ipairs({ 'left', 'right', 'up', 'down' }) do
|
||||
exercise(direction, false)
|
||||
exercise(direction, true)
|
||||
end
|
||||
return cases
|
||||
end)
|
||||
|
||||
local expected = {}
|
||||
for _, direction in ipairs({ 'left', 'right', 'up', 'down' }) do
|
||||
for _, preference in ipairs({ false, true }) do
|
||||
expected[#expected + 1] = {
|
||||
direction = direction,
|
||||
preference = preference,
|
||||
created_one = true,
|
||||
focused_new = true,
|
||||
placement_matches_preference = true,
|
||||
splitright_restored = true,
|
||||
splitbelow_restored = true,
|
||||
}
|
||||
end
|
||||
end
|
||||
expect.equality(result, expected)
|
||||
end
|
||||
|
||||
T['uses Herdr neighbors and falls back locally on focus or edge failures'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local edge_queue = { false, false, '<nil>' }
|
||||
local focus_queue = { true, false }
|
||||
local calls = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
unzoom_enabled = function() return false end,
|
||||
current_pane_at_edge = function(direction)
|
||||
calls[#calls + 1] = 'edge:' .. direction
|
||||
local value = table.remove(edge_queue, 1)
|
||||
if value == '<nil>' then return nil end
|
||||
return value
|
||||
end,
|
||||
focus_pane = function(direction)
|
||||
calls[#calls + 1] = 'focus:' .. direction
|
||||
return table.remove(focus_queue, 1)
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
local function at_left()
|
||||
vim.cmd('only')
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[1])
|
||||
return wins
|
||||
end
|
||||
|
||||
local success_wins = at_left()
|
||||
nav.move_cursor('left')
|
||||
local focus_success_stays = vim.api.nvim_get_current_win() == success_wins[1]
|
||||
|
||||
local failure_wins = at_left()
|
||||
nav.move_cursor('left')
|
||||
local focus_failure_wraps = vim.api.nvim_get_current_win() == failure_wins[2]
|
||||
|
||||
local unknown_wins = at_left()
|
||||
nav.move_cursor('left')
|
||||
local unknown_wraps = vim.api.nvim_get_current_win() == unknown_wins[2]
|
||||
|
||||
return {
|
||||
focus_success_stays = focus_success_stays,
|
||||
focus_failure_wraps = focus_failure_wraps,
|
||||
unknown_wraps = unknown_wraps,
|
||||
calls = calls,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
focus_success_stays = true,
|
||||
focus_failure_wraps = true,
|
||||
unknown_wraps = true,
|
||||
calls = {
|
||||
'edge:left', 'focus:left',
|
||||
'edge:left', 'focus:left',
|
||||
'edge:left',
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
T['unzooms and retries native movement before querying Herdr edges'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
local start_win = vim.api.nvim_get_current_win()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
unzoom_enabled = function() return true end,
|
||||
current_pane_is_zoomed = function()
|
||||
calls[#calls + 1] = 'zoomed'
|
||||
return true
|
||||
end,
|
||||
unzoom = function()
|
||||
calls[#calls + 1] = 'unzoom'
|
||||
local old_splitright = vim.o.splitright
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
vim.api.nvim_set_current_win(start_win)
|
||||
vim.o.splitright = old_splitright
|
||||
return true
|
||||
end,
|
||||
current_pane_at_edge = function()
|
||||
calls[#calls + 1] = 'edge'
|
||||
return false
|
||||
end,
|
||||
focus_pane = function()
|
||||
calls[#calls + 1] = 'focus'
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
require('herdr-splits.nav').move_cursor('right')
|
||||
|
||||
return {
|
||||
moved = vim.api.nvim_get_current_win() ~= start_win,
|
||||
windows = #vim.api.nvim_tabpage_list_wins(0),
|
||||
calls = calls,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, { moved = true, windows = 2, calls = { 'zoomed', 'unzoom' } })
|
||||
end
|
||||
|
||||
T['wraps through the reverse Herdr neighbor unless nav_at_edge stops it'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local mode = 'wrap'
|
||||
local calls = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
unzoom_enabled = function() return false end,
|
||||
current_pane_at_edge = function(direction)
|
||||
calls[#calls + 1] = 'edge:' .. direction
|
||||
return direction == 'left'
|
||||
end,
|
||||
nav_at_edge = function() return mode end,
|
||||
focus_pane = function(direction)
|
||||
calls[#calls + 1] = 'focus:' .. direction
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
local function at_left()
|
||||
vim.cmd('only')
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[1])
|
||||
return wins
|
||||
end
|
||||
|
||||
local herdr_wrap_wins = at_left()
|
||||
nav.move_cursor('left')
|
||||
local herdr_wrap_stays = vim.api.nvim_get_current_win() == herdr_wrap_wins[1]
|
||||
|
||||
mode = 'stop'
|
||||
local local_wrap_wins = at_left()
|
||||
nav.move_cursor('left')
|
||||
local local_wraps = vim.api.nvim_get_current_win() == local_wrap_wins[2]
|
||||
|
||||
return { herdr_wrap_stays = herdr_wrap_stays, local_wraps = local_wraps, calls = calls }
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
herdr_wrap_stays = true,
|
||||
local_wraps = true,
|
||||
calls = { 'edge:left', 'edge:right', 'focus:right', 'edge:left' },
|
||||
})
|
||||
end
|
||||
|
||||
T['command-line window delegates to Herdr at the screen edge and never wincmds'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
local edge = false
|
||||
local nav_mode = 'wrap'
|
||||
package.loaded['herdr-splits.win'] = {
|
||||
is_command_line_window = function() return true end,
|
||||
is_floating = function() return false end,
|
||||
is_embedded_floating_window = function() return false end,
|
||||
is_ignored_or_preview = function() return false end,
|
||||
dir_keys = { left = 'h', right = 'l', up = 'k', down = 'j' },
|
||||
dir_keys_reverse = { left = 'l', right = 'h', up = 'j', down = 'k' },
|
||||
reverse_direction = { left = 'right', right = 'left', up = 'down', down = 'up' },
|
||||
}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
current_pane_at_edge = function(direction)
|
||||
calls[#calls + 1] = 'edge:' .. direction
|
||||
return edge
|
||||
end,
|
||||
nav_at_edge = function() return nav_mode end,
|
||||
focus_pane = function(direction)
|
||||
calls[#calls + 1] = 'focus:' .. direction
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
-- single window: will_wrap is true in every direction, mirroring the
|
||||
-- full-width/bottom command-line window geometry.
|
||||
vim.cmd('only')
|
||||
|
||||
edge = false
|
||||
nav.move_cursor('left')
|
||||
local c1 = vim.deepcopy(calls); calls = {}
|
||||
|
||||
edge = true
|
||||
nav_mode = 'wrap'
|
||||
nav.move_cursor('right')
|
||||
local c2 = vim.deepcopy(calls); calls = {}
|
||||
|
||||
nav_mode = 'stop'
|
||||
nav.move_cursor('right')
|
||||
local c3 = vim.deepcopy(calls)
|
||||
|
||||
return { neighbor = c1, wrap_reverse = c2, stop_noop = c3 }
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
neighbor = { 'edge:left', 'focus:left' },
|
||||
wrap_reverse = { 'edge:right', 'focus:left' },
|
||||
stop_noop = { 'edge:right' },
|
||||
})
|
||||
end
|
||||
|
||||
T['command-line window no-ops silently when not at a screen edge'] = function()
|
||||
local result = child.lua_func(function()
|
||||
package.loaded['herdr-splits.win'] = {
|
||||
is_command_line_window = function() return true end,
|
||||
is_floating = function() return false end,
|
||||
is_embedded_floating_window = function() return false end,
|
||||
is_ignored_or_preview = function() return false end,
|
||||
dir_keys = { left = 'h', right = 'l', up = 'k', down = 'j' },
|
||||
dir_keys_reverse = { left = 'l', right = 'h', up = 'j', down = 'k' },
|
||||
reverse_direction = { left = 'right', right = 'left', up = 'down', down = 'up' },
|
||||
}
|
||||
local focused = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
current_pane_at_edge = function() return false end,
|
||||
nav_at_edge = function() return 'wrap' end,
|
||||
focus_pane = function(d) focused[#focused + 1] = d; return true end,
|
||||
}
|
||||
package.loaded['herdr-splits.nav'] = nil
|
||||
local nav = require('herdr-splits.nav')
|
||||
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
-- left window: 'right' has a Neovim neighbor -> will_wrap == false
|
||||
vim.api.nvim_set_current_win(wins[1])
|
||||
nav.move_cursor('right')
|
||||
return { stayed = vim.api.nvim_get_current_win() == wins[1], focused = focused }
|
||||
end)
|
||||
|
||||
-- Without the guard, wincmd l would move to wins[2]; with it, silent no-op.
|
||||
expect.equality(result, { stayed = true, focused = {} })
|
||||
end
|
||||
|
||||
return T
|
||||
@@ -0,0 +1,60 @@
|
||||
local T
|
||||
local expect = MiniTest.expect
|
||||
local child = MiniTest.new_child_neovim()
|
||||
|
||||
local source = debug.getinfo(1, 'S').source
|
||||
local root = vim.fn.fnamemodify(source:sub(2), ':p:h:h')
|
||||
|
||||
T = MiniTest.new_set({
|
||||
hooks = {
|
||||
pre_case = function()
|
||||
child.restart({ '--noplugin', '-u', 'NONE', '-i', 'NONE' })
|
||||
child.cmd('set runtimepath^=' .. vim.fn.fnameescape(root))
|
||||
end,
|
||||
post_case = function()
|
||||
child.stop()
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
T['public module loads its expected API'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local plugin = require('herdr-splits')
|
||||
local names = {
|
||||
'setup',
|
||||
'sync_herdr',
|
||||
'resize_left',
|
||||
'resize_down',
|
||||
'resize_up',
|
||||
'resize_right',
|
||||
'move_cursor_left',
|
||||
'move_cursor_down',
|
||||
'move_cursor_up',
|
||||
'move_cursor_right',
|
||||
'add_ignored_filetype',
|
||||
'add_ignored_buftype',
|
||||
}
|
||||
local types = {}
|
||||
for _, name in ipairs(names) do
|
||||
types[name] = type(plugin[name])
|
||||
end
|
||||
return types
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
setup = 'function',
|
||||
sync_herdr = 'function',
|
||||
resize_left = 'function',
|
||||
resize_down = 'function',
|
||||
resize_up = 'function',
|
||||
resize_right = 'function',
|
||||
move_cursor_left = 'function',
|
||||
move_cursor_down = 'function',
|
||||
move_cursor_up = 'function',
|
||||
move_cursor_right = 'function',
|
||||
add_ignored_filetype = 'function',
|
||||
add_ignored_buftype = 'function',
|
||||
})
|
||||
end
|
||||
|
||||
return T
|
||||
@@ -0,0 +1,302 @@
|
||||
local T
|
||||
local expect = MiniTest.expect
|
||||
local child = MiniTest.new_child_neovim()
|
||||
|
||||
local source = debug.getinfo(1, 'S').source
|
||||
local root = vim.fn.fnamemodify(source:sub(2), ':p:h:h')
|
||||
|
||||
T = MiniTest.new_set({
|
||||
hooks = {
|
||||
pre_case = function()
|
||||
child.restart({ '--noplugin', '-u', 'NONE', '-i', 'NONE' })
|
||||
child.cmd('set runtimepath^=' .. vim.fn.fnameescape(root))
|
||||
end,
|
||||
post_case = function()
|
||||
child.stop()
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
T['uses the correct horizontal resize sign at both sides'] = function()
|
||||
local deltas = child.lua_func(function()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local resize = require('herdr-splits.resize')
|
||||
vim.o.equalalways = false
|
||||
vim.o.winminwidth = 1
|
||||
|
||||
local function delta(side, direction)
|
||||
vim.cmd('only')
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[side == 'left' and 1 or 2])
|
||||
local before = vim.api.nvim_win_get_width(0)
|
||||
resize.resize(direction, 2)
|
||||
return vim.api.nvim_win_get_width(0) - before
|
||||
end
|
||||
|
||||
return {
|
||||
left_left = delta('left', 'left'),
|
||||
left_right = delta('left', 'right'),
|
||||
right_left = delta('right', 'left'),
|
||||
right_right = delta('right', 'right'),
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(deltas, { left_left = -2, left_right = 2, right_left = 2, right_right = -2 })
|
||||
end
|
||||
|
||||
T['uses the correct vertical resize sign at top and bottom'] = function()
|
||||
local deltas = child.lua_func(function()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local resize = require('herdr-splits.resize')
|
||||
vim.o.equalalways = false
|
||||
vim.o.winminheight = 1
|
||||
|
||||
local function delta(side, direction)
|
||||
vim.cmd('only')
|
||||
vim.o.splitbelow = true
|
||||
vim.cmd('split')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[1] < vim.api.nvim_win_get_position(b)[1]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[side == 'top' and 1 or 2])
|
||||
local before = vim.api.nvim_win_get_height(0)
|
||||
resize.resize(direction, 2)
|
||||
return vim.api.nvim_win_get_height(0) - before
|
||||
end
|
||||
|
||||
return {
|
||||
top_up = delta('top', 'up'),
|
||||
top_down = delta('top', 'down'),
|
||||
bottom_up = delta('bottom', 'up'),
|
||||
bottom_down = delta('bottom', 'down'),
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(deltas, { top_up = -2, top_down = 2, bottom_up = 2, bottom_down = -2 })
|
||||
end
|
||||
|
||||
T['floors explicit cell amounts and clamps nonpositive values'] = function()
|
||||
local deltas = child.lua_func(function()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local resize = require('herdr-splits.resize')
|
||||
vim.o.equalalways = false
|
||||
vim.o.winminwidth = 1
|
||||
|
||||
local function delta(amount)
|
||||
vim.cmd('only')
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[1])
|
||||
local before = vim.api.nvim_win_get_width(0)
|
||||
resize.resize('right', amount)
|
||||
return vim.api.nvim_win_get_width(0) - before
|
||||
end
|
||||
|
||||
return { floored = delta(2.9), zero = delta(0), negative = delta(-4) }
|
||||
end)
|
||||
|
||||
expect.equality(deltas, { floored = 2, zero = 1, negative = 1 })
|
||||
end
|
||||
|
||||
T['multiplies native resize cells by the typed count'] = function()
|
||||
local before = child.lua_func(function()
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return false end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local config = require('herdr-splits.config')
|
||||
config.neovim_amount = 2
|
||||
vim.o.equalalways = false
|
||||
vim.o.winminwidth = 1
|
||||
vim.o.splitright = true
|
||||
vim.cmd('vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
vim.api.nvim_set_current_win(wins[1])
|
||||
vim.keymap.set('n', 'x', function()
|
||||
require('herdr-splits.resize').resize('right')
|
||||
end)
|
||||
return vim.api.nvim_win_get_width(0)
|
||||
end)
|
||||
|
||||
child.type_keys('3x')
|
||||
local after = child.lua_get('vim.api.nvim_win_get_width(0)')
|
||||
expect.equality(after - before, 6)
|
||||
end
|
||||
|
||||
T['delegates full-terminal ratios for defaults, counts, and explicit amounts'] = function()
|
||||
child.lua_func(function()
|
||||
_G.resize_calls = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
current_pane_is_zoomed = function() return false end,
|
||||
resize_pane = function(direction, amount)
|
||||
_G.resize_calls[#_G.resize_calls + 1] = { direction, amount }
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local config = require('herdr-splits.config')
|
||||
config.default_amount = 0.03
|
||||
local resize = require('herdr-splits.resize')
|
||||
resize.resize('left')
|
||||
resize.resize('right', 0.2)
|
||||
resize.resize('left', 2)
|
||||
vim.keymap.set('n', 'x', function() resize.resize('right') end)
|
||||
end)
|
||||
|
||||
child.type_keys('3x')
|
||||
local calls = child.lua_get('_G.resize_calls')
|
||||
expect.equality(calls, {
|
||||
{ 'left', 0.03 },
|
||||
{ 'right', 0.2 },
|
||||
{ 'left', 0.03 },
|
||||
{ 'right', 0.09 },
|
||||
})
|
||||
end
|
||||
|
||||
T['delegates vertical full-terminal ratios using real geometry'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
current_pane_is_zoomed = function() return false end,
|
||||
resize_pane = function(direction, amount)
|
||||
calls[#calls + 1] = { direction, amount }
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local config = require('herdr-splits.config')
|
||||
config.default_amount = 0.03
|
||||
local win = require('herdr-splits.win')
|
||||
local resize = require('herdr-splits.resize')
|
||||
|
||||
local geometry = {
|
||||
full_height = win.is_full_height(),
|
||||
at_top = win.at_top_edge(),
|
||||
at_bottom = win.at_bottom_edge(),
|
||||
}
|
||||
resize.resize('up')
|
||||
resize.resize('down', 0.2)
|
||||
return { geometry = geometry, calls = calls }
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
geometry = { full_height = true, at_top = true, at_bottom = true },
|
||||
calls = { { 'up', 0.03 }, { 'down', 0.2 } },
|
||||
})
|
||||
end
|
||||
|
||||
T['delegates normal floats but suppresses embedded, sidebar, and zoomed windows'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
local zoomed = false
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
current_pane_is_zoomed = function() return zoomed end,
|
||||
resize_pane = function(direction, amount)
|
||||
calls[#calls + 1] = { direction, amount }
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local resize = require('herdr-splits.resize')
|
||||
local base = vim.api.nvim_get_current_win()
|
||||
|
||||
local normal = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, true), true, {
|
||||
relative = 'editor', row = 1, col = 1, width = 12, height = 3, zindex = 50,
|
||||
})
|
||||
resize.resize('right', 0.15)
|
||||
|
||||
local embedded = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, true), true, {
|
||||
relative = 'editor', row = 2, col = 2, width = 12, height = 3, zindex = 49,
|
||||
})
|
||||
resize.resize('left')
|
||||
|
||||
vim.api.nvim_set_current_win(base)
|
||||
vim.api.nvim_win_close(embedded, true)
|
||||
vim.api.nvim_win_close(normal, true)
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
vim.api.nvim_set_option_value('buftype', 'nofile', { buf = bufnr })
|
||||
resize.resize('left')
|
||||
|
||||
vim.api.nvim_set_option_value('buftype', '', { buf = bufnr })
|
||||
zoomed = true
|
||||
resize.resize('right')
|
||||
|
||||
return { calls = calls, current = vim.api.nvim_get_current_win() == base }
|
||||
end)
|
||||
|
||||
expect.equality(result, { calls = { { 'right', 0.15 } }, current = true })
|
||||
end
|
||||
|
||||
T['command-line window horizontal resize delegates past the nofile sidebar rule'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local calls = {}
|
||||
local cmdwin = true
|
||||
package.loaded['herdr-splits.win'] = {
|
||||
is_command_line_window = function() return cmdwin end,
|
||||
is_embedded_floating_window = function() return false end,
|
||||
is_floating = function() return false end,
|
||||
is_ignored_or_preview = function() return true end,
|
||||
is_full_width = function() return true end,
|
||||
is_full_height = function() return false end,
|
||||
at_left_edge = function() return true end,
|
||||
at_right_edge = function() return true end,
|
||||
at_top_edge = function() return true end,
|
||||
at_bottom_edge = function() return true end,
|
||||
win_position = function() return 'start' end,
|
||||
}
|
||||
package.loaded['herdr-splits.herdr'] = {
|
||||
is_in_session = function() return true end,
|
||||
current_pane_is_zoomed = function() return false end,
|
||||
resize_pane = function(direction, amount)
|
||||
calls[#calls + 1] = { direction, amount }
|
||||
return true
|
||||
end,
|
||||
}
|
||||
package.loaded['herdr-splits.resize'] = nil
|
||||
local config = require('herdr-splits.config')
|
||||
config.default_amount = 0.03
|
||||
local resize = require('herdr-splits.resize')
|
||||
|
||||
-- cmdwin + full-width + nofile: horizontal resize delegates to Herdr
|
||||
cmdwin = true
|
||||
resize.resize('left')
|
||||
resize.resize('right', 0.2)
|
||||
|
||||
-- ordinary nofile buffer (not cmdwin): sidebar rule still blocks delegation
|
||||
cmdwin = false
|
||||
resize.resize('left')
|
||||
|
||||
return { calls = calls }
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
calls = { { 'left', 0.03 }, { 'right', 0.2 } },
|
||||
})
|
||||
end
|
||||
|
||||
return T
|
||||
@@ -0,0 +1,138 @@
|
||||
local T
|
||||
local expect = MiniTest.expect
|
||||
local child = MiniTest.new_child_neovim()
|
||||
|
||||
local source = debug.getinfo(1, 'S').source
|
||||
local root = vim.fn.fnamemodify(source:sub(2), ':p:h:h')
|
||||
|
||||
T = MiniTest.new_set({
|
||||
hooks = {
|
||||
pre_case = function()
|
||||
child.restart({ '--noplugin', '-u', 'NONE', '-i', 'NONE' })
|
||||
child.cmd('set runtimepath^=' .. vim.fn.fnameescape(root))
|
||||
end,
|
||||
post_case = function()
|
||||
child.stop()
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
T['win_position identifies horizontal split positions'] = function()
|
||||
local positions = child.lua_func(function()
|
||||
vim.cmd('vsplit | vsplit')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[2] < vim.api.nvim_win_get_position(b)[2]
|
||||
end)
|
||||
|
||||
local out = {}
|
||||
for _, win in ipairs(wins) do
|
||||
vim.api.nvim_set_current_win(win)
|
||||
out[#out + 1] = require('herdr-splits.win').win_position('left')
|
||||
end
|
||||
return out
|
||||
end)
|
||||
|
||||
expect.equality(positions, { 'start', 'middle', 'last' })
|
||||
end
|
||||
|
||||
T['win_position identifies vertical split positions'] = function()
|
||||
local positions = child.lua_func(function()
|
||||
vim.cmd('split | split')
|
||||
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||
table.sort(wins, function(a, b)
|
||||
return vim.api.nvim_win_get_position(a)[1] < vim.api.nvim_win_get_position(b)[1]
|
||||
end)
|
||||
|
||||
local out = {}
|
||||
for _, win in ipairs(wins) do
|
||||
vim.api.nvim_set_current_win(win)
|
||||
out[#out + 1] = require('herdr-splits.win').win_position('up')
|
||||
end
|
||||
return out
|
||||
end)
|
||||
|
||||
expect.equality(positions, { 'start', 'middle', 'last' })
|
||||
end
|
||||
|
||||
T['floating classification distinguishes embedded floats'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local win = require('herdr-splits.win')
|
||||
local normal = vim.api.nvim_get_current_win()
|
||||
local low = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, true), false, {
|
||||
relative = 'editor', row = 1, col = 1, width = 10, height = 3, zindex = 49,
|
||||
})
|
||||
local default = vim.api.nvim_open_win(vim.api.nvim_create_buf(false, true), false, {
|
||||
relative = 'editor', row = 2, col = 2, width = 10, height = 3, zindex = 50,
|
||||
})
|
||||
|
||||
return {
|
||||
normal_floating = win.is_floating(normal),
|
||||
normal_embedded = win.is_embedded_floating_window(normal),
|
||||
low_floating = win.is_floating(low),
|
||||
low_embedded = win.is_embedded_floating_window(low),
|
||||
default_floating = win.is_floating(default),
|
||||
default_embedded = win.is_embedded_floating_window(default),
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
normal_floating = false,
|
||||
normal_embedded = false,
|
||||
low_floating = true,
|
||||
low_embedded = true,
|
||||
default_floating = true,
|
||||
default_embedded = false,
|
||||
})
|
||||
end
|
||||
|
||||
T['ignored window classification uses buffer type and filetype'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local win = require('herdr-splits.win')
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local regular = win.is_ignored_win()
|
||||
|
||||
vim.api.nvim_set_option_value('buftype', 'nofile', { buf = bufnr })
|
||||
local ignored_buftype = win.is_ignored_win()
|
||||
vim.api.nvim_set_option_value('buftype', '', { buf = bufnr })
|
||||
|
||||
vim.api.nvim_set_option_value('filetype', 'neo-tree', { buf = bufnr })
|
||||
local ignored_filetype = win.is_ignored_win()
|
||||
return {
|
||||
regular = regular,
|
||||
ignored_buftype = ignored_buftype,
|
||||
ignored_filetype = ignored_filetype,
|
||||
}
|
||||
end)
|
||||
|
||||
expect.equality(result, {
|
||||
regular = false,
|
||||
ignored_buftype = true,
|
||||
ignored_filetype = true,
|
||||
})
|
||||
end
|
||||
|
||||
T['preview windows are ignored only when configured'] = function()
|
||||
local result = child.lua_func(function()
|
||||
local win = require('herdr-splits.win')
|
||||
local config = require('herdr-splits.config')
|
||||
vim.wo.previewwindow = true
|
||||
|
||||
config.ignore_previewwindows = false
|
||||
local disabled = win.is_ignored_or_preview()
|
||||
config.ignore_previewwindows = true
|
||||
local enabled = win.is_ignored_or_preview()
|
||||
return { disabled = disabled, enabled = enabled }
|
||||
end)
|
||||
|
||||
expect.equality(result, { disabled = false, enabled = true })
|
||||
end
|
||||
|
||||
T['command-line window is not active in a normal buffer'] = function()
|
||||
local result = child.lua_func(function()
|
||||
return require('herdr-splits.win').is_command_line_window()
|
||||
end)
|
||||
expect.equality(result, false)
|
||||
end
|
||||
|
||||
return T
|
||||
Reference in New Issue
Block a user