aboutsummaryrefslogtreecommitdiff
path: root/test/functional/ui/screen.lua
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/ui/screen.lua')
-rw-r--r--test/functional/ui/screen.lua939
1 files changed, 605 insertions, 334 deletions
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 810a68d387..e8d7d5c72d 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -72,23 +72,44 @@
local helpers = require('test.functional.helpers')(nil)
local busted = require('busted')
-local deepcopy = helpers.deepcopy
+local deepcopy = vim.deepcopy
local shallowcopy = helpers.shallowcopy
local concat_tables = helpers.concat_tables
-local pesc = helpers.pesc
+local pesc = vim.pesc
local run_session = helpers.run_session
local eq = helpers.eq
local dedent = helpers.dedent
local get_session = helpers.get_session
local create_callindex = helpers.create_callindex
-local inspect = require('vim.inspect')
+local inspect = vim.inspect
local function isempty(v)
return type(v) == 'table' and next(v) == nil
end
+--- @class test.functional.ui.screen.Grid
+--- @field rows table[][]
+--- @field width integer
+--- @field height integer
+
--- @class test.functional.ui.screen
+--- @field colors table<string,integer>
+--- @field colornames table<integer,string>
+--- @field uimeths table<string,function>
+--- @field options? table<string,any>
+--- @field timeout integer
+--- @field win_position table<integer,table<string,integer>>
+--- @field float_pos table<integer,table>
+--- @field cmdline table<integer,table>
+--- @field cmdline_block table[]
+--- @field hl_groups table<string,integer>
+--- @field messages table<integer,table>
+--- @field private _cursor {grid:integer,row:integer,col:integer}
+--- @field private _grids table<integer,test.functional.ui.screen.Grid>
+--- @field private _grid_win_extmarks table<integer,table>
+--- @field private _attr_table table<integer,table>
+--- @field private _hl_info table<integer,table>
local Screen = {}
Screen.__index = Screen
@@ -103,13 +124,14 @@ end
local default_screen_timeout = default_timeout_factor * 3500
-function Screen._init_colors(session)
+local function _init_colors()
+ local session = get_session()
local status, rv = session:request('nvim_get_color_map')
if not status then
error('failed to get color map')
end
- local colors = rv
- local colornames = {}
+ local colors = rv --- @type table<string,integer>
+ local colornames = {} --- @type table<integer,string>
for name, rgb in pairs(colors) do
-- we disregard the case that colornames might not be unique, as
-- this is just a helper to get any canonical name of a color
@@ -119,17 +141,14 @@ function Screen._init_colors(session)
Screen.colornames = colornames
end
+--- @param width? integer
+--- @param height? integer
+--- @return test.functional.ui.screen
function Screen.new(width, height)
if not Screen.colors then
- Screen._init_colors(get_session())
+ _init_colors()
end
- if not width then
- width = 53
- end
- if not height then
- height = 14
- end
local self = setmetatable({
timeout = default_screen_timeout,
title = '',
@@ -140,6 +159,7 @@ function Screen.new(width, height)
suspended = false,
mode = 'normal',
options = {},
+ pwd = '',
popupmenu = nil,
cmdline = {},
cmdline_block = {},
@@ -161,30 +181,35 @@ function Screen.new(width, height)
_default_attr_ids = nil,
mouse_enabled = true,
_attrs = {},
- _hl_info = {[0]={}},
- _attr_table = {[0]={{},{}}},
+ _hl_info = { [0] = {} },
+ _attr_table = { [0] = { {}, {} } },
_clear_attrs = nil,
_new_attrs = false,
- _width = width,
- _height = height,
+ _width = width or 53,
+ _height = height or 14,
_grids = {},
_grid_win_extmarks = {},
_cursor = {
- grid = 1, row = 1, col = 1
+ grid = 1,
+ row = 1,
+ col = 1,
},
_busy = false,
}, Screen)
+
local function ui(method, ...)
if self.rpc_async then
- self._session:notify('nvim_ui_'..method, ...)
+ self._session:notify('nvim_ui_' .. method, ...)
else
- local status, rv = self._session:request('nvim_ui_'..method, ...)
+ local status, rv = self._session:request('nvim_ui_' .. method, ...)
if not status then
error(rv[2])
end
end
end
+
self.uimeths = create_callindex(ui)
+
return self
end
@@ -200,13 +225,21 @@ function Screen:set_rgb_cterm(val)
self._rgb_cterm = val
end
+--- @class test.functional.ui.screen.Opts
+--- @field ext_linegrid? boolean
+--- @field ext_multigrid? boolean
+--- @field ext_newgrid? boolean
+--- @field ext_popupmenu? boolean
+--- @field ext_wildmenu? boolean
+--- @field rgb? boolean
+--- @field _debug_float? boolean
+
+--- @param options test.functional.ui.screen.Opts
+--- @param session? test.Session
function Screen:attach(options, session)
- if session == nil then
- session = get_session()
- end
- if options == nil then
- options = {}
- end
+ session = session or get_session()
+ options = options or {}
+
if options.ext_linegrid == nil then
options.ext_linegrid = true
end
@@ -241,106 +274,178 @@ function Screen:try_resize_grid(grid, columns, rows)
self.uimeths.try_resize_grid(grid, columns, rows)
end
+--- @param option 'ext_linegrid'|'ext_multigrid'|'ext_popupmenu'|'ext_wildmenu'|'rgb'
+--- @param value boolean
function Screen:set_option(option, value)
self.uimeths.set_option(option, value)
+ --- @diagnostic disable-next-line:no-unknown
self._options[option] = value
end
-- canonical order of ext keys, used to generate asserts
local ext_keys = {
- 'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos',
- 'messages', 'msg_history', 'showmode', 'showcmd', 'ruler', 'float_pos', 'win_viewport'
+ 'popupmenu',
+ 'cmdline',
+ 'cmdline_block',
+ 'wildmenu_items',
+ 'wildmenu_pos',
+ 'messages',
+ 'msg_history',
+ 'showmode',
+ 'showcmd',
+ 'ruler',
+ 'float_pos',
+ 'win_viewport',
}
--- Asserts that the screen state eventually matches an expected state.
---
--- Can be called with positional args:
--- screen:expect(grid, [attr_ids])
--- screen:expect(condition)
--- or keyword args (supports more options):
--- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end}
---
---
--- grid: Expected screen state (string). Each line represents a screen
--- row. Last character of each row (typically "|") is stripped.
--- Common indentation is stripped.
--- "{MATCH:x}" in a line is matched against Lua pattern `x`.
--- attr_ids: Expected text attributes. Screen rows are transformed according
--- to this table, as follows: each substring S composed of
--- characters having the same attributes will be substituted by
--- "{K:S}", where K is a key in `attr_ids`. Any unexpected
--- attributes in the final state are an error.
--- Use screen:set_default_attr_ids() to define attributes for many
--- expect() calls.
--- extmarks: Expected win_extmarks accumulated for the grids. For each grid,
--- the win_extmark messages are accumulated into an array.
--- condition: Function asserting some arbitrary condition. Return value is
--- ignored, throw an error (use eq() or similar) to signal failure.
--- any: Lua pattern string expected to match a screen line. NB: the
--- following chars are magic characters
--- ( ) . % + - * ? [ ^ $
--- and must be escaped with a preceding % for a literal match.
--- mode: Expected mode as signaled by "mode_change" event
--- unchanged: Test that the screen state is unchanged since the previous
--- expect(...). Any flush event resulting in a different state is
--- considered an error. Not observing any events until timeout
--- is acceptable.
--- intermediate:Test that the final state is the same as the previous expect,
--- but expect an intermediate state that is different. If possible
--- it is better to use an explicit screen:expect(...) for this
--- intermediate state.
--- reset: Reset the state internal to the test Screen before starting to
--- receive updates. This should be used after command("redraw!")
--- or some other mechanism that will invoke "redraw!", to check
--- that all screen state is transmitted again. This includes
--- state related to ext_ features as mentioned below.
--- timeout: maximum time that will be waited until the expected state is
--- seen (or maximum time to observe an incorrect change when
--- `unchanged` flag is used)
---
--- The following keys should be used to expect the state of various ext_
--- features. Note that an absent key will assert that the item is currently
--- NOT present on the screen, also when positional form is used.
---
--- popupmenu: Expected ext_popupmenu state,
--- cmdline: Expected ext_cmdline state, as an array of cmdlines of
--- different level.
--- cmdline_block: Expected ext_cmdline block (for function definitions)
--- wildmenu_items: Expected items for ext_wildmenu
--- wildmenu_pos: Expected position for ext_wildmenu
+local expect_keys = {
+ grid = true,
+ attr_ids = true,
+ condition = true,
+ mouse_enabled = true,
+ any = true,
+ mode = true,
+ unchanged = true,
+ intermediate = true,
+ reset = true,
+ timeout = true,
+ request_cb = true,
+ hl_groups = true,
+ extmarks = true,
+}
+
+for _, v in ipairs(ext_keys) do
+ expect_keys[v] = true
+end
+
+--- @class test.function.ui.screen.Expect
+---
+--- Expected screen state (string). Each line represents a screen
+--- row. Last character of each row (typically "|") is stripped.
+--- Common indentation is stripped.
+--- "{MATCH:x}" in a line is matched against Lua pattern `x`.
+--- "*n" at the end of a line means it repeats `n` times.
+--- @field grid? string
+---
+--- Expected text attributes. Screen rows are transformed according
+--- to this table, as follows: each substring S composed of
+--- characters having the same attributes will be substituted by
+--- "{K:S}", where K is a key in `attr_ids`. Any unexpected
+--- attributes in the final state are an error.
+--- Use an empty table for a text-only (no attributes) expectation.
+--- Use screen:set_default_attr_ids() to define attributes for many
+--- expect() calls.
+--- @field attr_ids? table<integer,table<string,any>>
+---
+--- Expected win_extmarks accumulated for the grids. For each grid,
+--- the win_extmark messages are accumulated into an array.
+--- @field extmarks? table<integer,table>
+---
+--- Function asserting some arbitrary condition. Return value is
+--- ignored, throw an error (use eq() or similar) to signal failure.
+--- @field condition? fun()
+---
+--- Lua pattern string expected to match a screen line. NB: the
+--- following chars are magic characters
+--- ( ) . % + - * ? [ ^ $
+--- and must be escaped with a preceding % for a literal match.
+--- @field any? string
+---
+--- Expected mode as signaled by "mode_change" event
+--- @field mode? string
+---
+--- Test that the screen state is unchanged since the previous
+--- expect(...). Any flush event resulting in a different state is
+--- considered an error. Not observing any events until timeout
+--- is acceptable.
+--- @field unchanged? boolean
+---
+--- Test that the final state is the same as the previous expect,
+--- but expect an intermediate state that is different. If possible
+--- it is better to use an explicit screen:expect(...) for this
+--- intermediate state.
+--- @field intermediate? boolean
+---
+--- Reset the state internal to the test Screen before starting to
+--- receive updates. This should be used after command("redraw!")
+--- or some other mechanism that will invoke "redraw!", to check
+--- that all screen state is transmitted again. This includes
+--- state related to ext_ features as mentioned below.
+--- @field reset? boolean
+---
+--- maximum time that will be waited until the expected state is
+--- seen (or maximum time to observe an incorrect change when
+--- `unchanged` flag is used)
+--- @field timeout? integer
+---
+--- @field mouse_enabled? boolean
+---
+--- @field win_viewport? table<integer,table<string,integer>>
+--- @field float_pos? {[1]:integer,[2]:integer}
+--- @field hl_groups? table<string,integer>
+---
+--- The following keys should be used to expect the state of various ext_
+--- features. Note that an absent key will assert that the item is currently
+--- NOT present on the screen, also when positional form is used.
+---
+--- Expected ext_popupmenu state,
+--- @field popupmenu? table
+---
+--- Expected ext_cmdline state, as an array of cmdlines of
+--- different level.
+--- @field cmdline? table
+---
+--- Expected ext_cmdline block (for function definitions)
+--- @field cmdline_block? table
+---
+--- items for ext_wildmenu
+--- @field wildmenu_items? table
+---
+--- position for ext_wildmenu
+--- @field wildmenu_pos? table
+
+--- Asserts that the screen state eventually matches an expected state.
+---
+--- Can be called with positional args:
+--- screen:expect(grid, [attr_ids])
+--- screen:expect(condition)
+--- or keyword args (supports more options):
+--- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end}
+---
+--- @param expected string|function|test.function.ui.screen.Expect
+--- @param attr_ids? table<integer,table<string,any>>
function Screen:expect(expected, attr_ids, ...)
- local grid, condition = nil, nil
- local expected_rows = {}
- assert(next({...}) == nil, "invalid args to expect()")
- if type(expected) == "table" then
- assert(not (attr_ids ~= nil))
- local is_key = {grid=true, attr_ids=true, condition=true, mouse_enabled=true,
- any=true, mode=true, unchanged=true, intermediate=true,
- reset=true, timeout=true, request_cb=true, hl_groups=true, extmarks=true}
- for _, v in ipairs(ext_keys) do
- is_key[v] = true
- end
- for k, _ in pairs(expected) do
- if not is_key[k] then
- error("Screen:expect: Unknown keyword argument '"..k.."'")
+ --- @type string, fun()
+ local grid, condition
+
+ assert(next({ ... }) == nil, 'invalid args to expect()')
+
+ if type(expected) == 'table' then
+ assert(attr_ids == nil)
+ for k, _ in
+ pairs(expected --[[@as table<string,any>]])
+ do
+ if not expect_keys[k] then
+ error("Screen:expect: Unknown keyword argument '" .. k .. "'")
end
end
grid = expected.grid
attr_ids = expected.attr_ids
condition = expected.condition
- assert(not (expected.any ~= nil and grid ~= nil))
- elseif type(expected) == "string" then
+ assert(expected.any == nil or grid == nil)
+ elseif type(expected) == 'string' then
grid = expected
expected = {}
- elseif type(expected) == "function" then
- assert(not (attr_ids ~= nil))
+ elseif type(expected) == 'function' then
+ assert(attr_ids == nil)
condition = expected
expected = {}
else
assert(false)
end
- if grid ~= nil then
+ local expected_rows = {} --- @type string[]
+ if grid then
-- Remove the last line and dedent. Note that gsub returns more then one
-- value.
grid = dedent(grid:gsub('\n[ ]+$', ''), 0)
@@ -348,15 +453,23 @@ function Screen:expect(expected, attr_ids, ...)
table.insert(expected_rows, row)
end
end
+
local attr_state = {
- ids = attr_ids or self._default_attr_ids,
+ ids = attr_ids or self._default_attr_ids,
}
+
+ if isempty(attr_ids) then
+ attr_state.ids = nil
+ end
+
if self._options.ext_linegrid then
attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {})
end
+
self._new_attrs = false
self:_wait(function()
- if condition ~= nil then
+ if condition then
+ --- @type boolean, string
local status, res = pcall(condition)
if not status then
return tostring(res)
@@ -369,27 +482,47 @@ function Screen:expect(expected, attr_ids, ...)
local actual_rows = self:render(not expected.any, attr_state)
- if expected.any ~= nil then
+ if expected.any then
-- Search for `any` anywhere in the screen lines.
local actual_screen_str = table.concat(actual_rows, '\n')
- if nil == string.find(actual_screen_str, expected.any) then
+ if not actual_screen_str:find(expected.any) then
return (
'Failed to match any screen lines.\n'
- .. 'Expected (anywhere): "' .. expected.any .. '"\n'
- .. 'Actual:\n |' .. table.concat(actual_rows, '\n |') .. '\n\n')
+ .. 'Expected (anywhere): "'
+ .. expected.any
+ .. '"\n'
+ .. 'Actual:\n |'
+ .. table.concat(actual_rows, '\n |')
+ .. '\n\n'
+ )
end
end
- if grid ~= nil then
- local err_msg, msg_expected_rows = nil, {}
+ if grid then
+ for i, row in ipairs(expected_rows) do
+ local count --- @type integer?
+ row, count = row:match('^(.*%|)%*(%d+)$')
+ if row then
+ count = tonumber(count)
+ table.remove(expected_rows, i)
+ for _ = 1, count do
+ table.insert(expected_rows, i, row)
+ end
+ end
+ end
+ local err_msg = nil
-- `expected` must match the screen lines exactly.
if #actual_rows ~= #expected_rows then
- err_msg = "Expected screen height " .. #expected_rows
- .. ' differs from actual height ' .. #actual_rows .. '.'
+ err_msg = 'Expected screen height '
+ .. #expected_rows
+ .. ' differs from actual height '
+ .. #actual_rows
+ .. '.'
end
+ local msg_expected_rows = shallowcopy(expected_rows)
+ local msg_actual_rows = shallowcopy(actual_rows)
for i, row in ipairs(expected_rows) do
- msg_expected_rows[i] = row
- local pat = nil
+ local pat = nil --- @type string?
if actual_rows[i] and row ~= actual_rows[i] then
local after = row
while true do
@@ -398,6 +531,7 @@ function Screen:expect(expected, attr_ids, ...)
pat = pat and (pat .. pesc(after))
break
end
+ --- @type string
pat = (pat or '') .. pesc(after:sub(1, s - 1)) .. m
after = after:sub(e + 1)
end
@@ -405,7 +539,7 @@ function Screen:expect(expected, attr_ids, ...)
if row ~= actual_rows[i] and (not pat or not actual_rows[i]:match(pat)) then
msg_expected_rows[i] = '*' .. msg_expected_rows[i]
if i <= #actual_rows then
- actual_rows[i] = '*' .. actual_rows[i]
+ msg_actual_rows[i] = '*' .. msg_actual_rows[i]
end
if err_msg == nil then
err_msg = 'Row ' .. tostring(i) .. ' did not match.'
@@ -414,11 +548,18 @@ function Screen:expect(expected, attr_ids, ...)
end
if err_msg ~= nil then
return (
- err_msg..'\nExpected:\n |'..table.concat(msg_expected_rows, '\n |')..'\n'
- ..'Actual:\n |'..table.concat(actual_rows, '\n |')..'\n\n'..[[
+ err_msg
+ .. '\nExpected:\n |'
+ .. table.concat(msg_expected_rows, '\n |')
+ .. '\n'
+ .. 'Actual:\n |'
+ .. table.concat(msg_actual_rows, '\n |')
+ .. '\n\n'
+ .. [[
To print the expect() call that would assert the current screen state, use
screen:snapshot_util(). In case of non-deterministic failures, use
-screen:redraw_debug() to show all intermediate screen states. ]])
+screen:redraw_debug() to show all intermediate screen states.]]
+ )
end
end
@@ -447,12 +588,18 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
-- Convert assertion errors into invalid screen state descriptions.
- for _, k in ipairs(concat_tables(ext_keys, {'mode', 'mouse_enabled'})) do
+ for _, k in ipairs(concat_tables(ext_keys, { 'mode', 'mouse_enabled' })) do
-- Empty states are considered the default and need not be mentioned.
- if (not (expected[k] == nil and isempty(extstate[k]))) then
+ if not (expected[k] == nil and isempty(extstate[k])) then
local status, res = pcall(eq, expected[k], extstate[k], k)
if not status then
- return (tostring(res)..'\nHint: full state of "'..k..'":\n '..inspect(extstate[k]))
+ return (
+ tostring(res)
+ .. '\nHint: full state of "'
+ .. k
+ .. '":\n '
+ .. inspect(extstate[k])
+ )
end
end
end
@@ -461,7 +608,7 @@ screen:redraw_debug() to show all intermediate screen states. ]])
for name, id in pairs(expected.hl_groups) do
local expected_hl = attr_state.ids[id]
local actual_hl = self._attr_table[self.hl_groups[name]][(self._options.rgb and 1) or 2]
- local status, res = pcall(eq, expected_hl, actual_hl, "highlight "..name)
+ local status, res = pcall(eq, expected_hl, actual_hl, 'highlight ' .. name)
if not status then
return tostring(res)
end
@@ -472,9 +619,10 @@ screen:redraw_debug() to show all intermediate screen states. ]])
for gridid, expected_marks in pairs(expected.extmarks) do
local stored_marks = self._grid_win_extmarks[gridid]
if stored_marks == nil then
- return 'no win_extmark for grid '..tostring(gridid)
+ return 'no win_extmark for grid ' .. tostring(gridid)
end
- local status, res = pcall(eq, expected_marks, stored_marks, "extmarks for grid "..tostring(gridid))
+ local status, res =
+ pcall(eq, expected_marks, stored_marks, 'extmarks for grid ' .. tostring(gridid))
if not status then
return tostring(res)
end
@@ -482,7 +630,7 @@ screen:redraw_debug() to show all intermediate screen states. ]])
for gridid, _ in pairs(self._grid_win_extmarks) do
local expected_marks = expected.extmarks[gridid]
if expected_marks == nil then
- return 'unexpected win_extmark for grid '..tostring(gridid)
+ return 'unexpected win_extmark for grid ' .. tostring(gridid)
end
end
end
@@ -490,7 +638,6 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs)
- waittime_ms = waittime_ms and waittime_ms or 100
-- Collect the current screen state.
local kwargs = self:get_snapshot(nil, ignore_attrs)
@@ -505,8 +652,12 @@ function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs)
self:expect(kwargs)
end
+--- @private
+--- @param check fun(): string
+--- @param flags table<string,any>
function Screen:_wait(check, flags)
- local err, checked = false, false
+ local err --- @type string?
+ local checked = false
local success_seen = false
local failure_after_success = false
local did_flush = true
@@ -537,16 +688,18 @@ function Screen:_wait(check, flags)
-- For an "unchanged" test, flags.timeout is the time during which the state
-- must not change, so always wait this full time.
- if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then
- minimal_timeout = timeout
+ if flags.unchanged then
+ minimal_timeout = flags.timeout or default_timeout_factor * 20
end
assert(timeout >= minimal_timeout)
local did_minimal_timeout = false
local function notification_cb(method, args)
- assert(method == 'redraw', string.format(
- 'notification_cb: unexpected method (%s, args=%s)', method, inspect(args)))
+ assert(
+ method == 'redraw',
+ string.format('notification_cb: unexpected method (%s, args=%s)', method, inspect(args))
+ )
did_flush = self:_redraw(args)
if not did_flush then
return
@@ -557,12 +710,12 @@ function Screen:_wait(check, flags)
intermediate_seen = true
end
- if not err then
+ if not err and (not flags.intermediate or intermediate_seen) then
success_seen = true
if did_minimal_timeout then
self._session:stop()
end
- elseif success_seen and #args > 0 then
+ elseif err and success_seen and #args > 0 then
success_seen = false
failure_after_success = true
-- print(inspect(args))
@@ -572,7 +725,7 @@ function Screen:_wait(check, flags)
end
local eof = run_session(self._session, flags.request_cb, notification_cb, nil, minimal_timeout)
if not did_flush then
- err = "no flush received"
+ err = 'no flush received'
elseif not checked then
err = check()
if not err and flags.unchanged then
@@ -583,12 +736,13 @@ function Screen:_wait(check, flags)
if not success_seen and not eof then
did_minimal_timeout = true
- eof = run_session(self._session, flags.request_cb, notification_cb, nil, timeout-minimal_timeout)
+ eof =
+ run_session(self._session, flags.request_cb, notification_cb, nil, timeout - minimal_timeout)
end
local did_warn = false
if warn_immediate and immediate_seen then
- print([[
+ print([[
warning: Screen test succeeded immediately. Try to avoid this unless the
purpose of the test really requires it.]])
@@ -622,21 +776,24 @@ between asynchronous (feed(), nvim_input()) and synchronous API calls.
did_warn = true
end
-
if err then
- if eof then err = err..'\n\n'..eof[2] end
- busted.fail(err, 3)
+ if eof then
+ err = err .. '\n\n' .. eof[2]
+ end
+ busted.fail(err .. '\n\nSnapshot:\n' .. self:_print_snapshot(), 3)
elseif did_warn then
- if eof then print(eof[2]) end
+ if eof then
+ print(eof[2])
+ end
local tb = debug.traceback()
local index = string.find(tb, '\n%s*%[C]')
- print(string.sub(tb,1,index))
+ print(string.sub(tb, 1, index))
end
if flags.intermediate then
- assert(intermediate_seen, "expected intermediate screen state before final screen state")
+ assert(intermediate_seen, 'expected intermediate screen state before final screen state')
elseif flags.unchanged then
- assert(not intermediate_seen, "expected screen state to be unchanged")
+ assert(not intermediate_seen, 'expected screen state to be unchanged')
end
end
@@ -648,23 +805,31 @@ function Screen:sleep(ms, request_cb)
run_session(self._session, request_cb, notification_cb, nil, ms)
end
+--- @private
+--- @param updates {[1]:string, [integer]:any[]}[]
function Screen:_redraw(updates)
local did_flush = false
for k, update in ipairs(updates) do
-- print('--', inspect(update))
local method = update[1]
for i = 2, #update do
- local handler_name = '_handle_'..method
+ local handler_name = '_handle_' .. method
+ --- @type function
local handler = self[handler_name]
- assert(handler ~= nil, "missing handler: Screen:"..handler_name)
+ assert(handler ~= nil, 'missing handler: Screen:' .. handler_name)
local status, res = pcall(handler, self, unpack(update[i]))
if not status then
- error(handler_name..' failed'
- ..'\n payload: '..inspect(update)
- ..'\n error: '..tostring(res))
+ error(
+ handler_name
+ .. ' failed'
+ .. '\n payload: '
+ .. inspect(update)
+ .. '\n error: '
+ .. tostring(res)
+ )
end
end
- if k == #updates and method == "flush" then
+ if k == #updates and method == 'flush' then
did_flush = true
end
end
@@ -674,12 +839,15 @@ end
function Screen:_handle_resize(width, height)
self:_handle_grid_resize(1, width, height)
self._scroll_region = {
- top = 1, bot = height, left = 1, right = width
+ top = 1,
+ bot = height,
+ left = 1,
+ right = width,
}
self._grid = self._grids[1]
end
-local function min(x,y)
+local function min(x, y)
if x < y then
return x
else
@@ -692,14 +860,14 @@ function Screen:_handle_grid_resize(grid, width, height)
for _ = 1, height do
local cols = {}
for _ = 1, width do
- table.insert(cols, {text = ' ', attrs = self._clear_attrs, hl_id = 0})
+ table.insert(cols, { text = ' ', attrs = self._clear_attrs, hl_id = 0 })
end
table.insert(rows, cols)
end
if grid > 1 and self._grids[grid] ~= nil then
local old = self._grids[grid]
- for i = 1, min(height,old.height) do
- for j = 1, min(width,old.width) do
+ for i = 1, min(height, old.height) do
+ for j = 1, min(width, old.width) do
rows[i][j] = old.rows[i][j]
end
end
@@ -710,13 +878,12 @@ function Screen:_handle_grid_resize(grid, width, height)
self._cursor.col = 1
end
self._grids[grid] = {
- rows=rows,
- width=width,
- height=height,
+ rows = rows,
+ width = width,
+ height = height,
}
end
-
function Screen:_handle_msg_set_pos(grid, row, scrolled, char)
self.msg_grid = grid
self.msg_grid_pos = row
@@ -724,8 +891,7 @@ function Screen:_handle_msg_set_pos(grid, row, scrolled, char)
self.msg_sep_char = char
end
-function Screen:_handle_flush()
-end
+function Screen:_handle_flush() end
function Screen:_reset()
-- TODO: generalize to multigrid later
@@ -740,18 +906,20 @@ function Screen:_reset()
self._grid_win_extmarks = {}
end
+--- @param cursor_style_enabled boolean
+--- @param mode_info table[]
function Screen:_handle_mode_info_set(cursor_style_enabled, mode_info)
self._cursor_style_enabled = cursor_style_enabled
for _, item in pairs(mode_info) do
- -- attr IDs are not stable, but their value should be
- if item.attr_id ~= nil then
- item.attr = self._attr_table[item.attr_id][1]
- item.attr_id = nil
- end
- if item.attr_id_lm ~= nil then
- item.attr_lm = self._attr_table[item.attr_id_lm][1]
- item.attr_id_lm = nil
- end
+ -- attr IDs are not stable, but their value should be
+ if item.attr_id ~= nil then
+ item.attr = self._attr_table[item.attr_id][1]
+ item.attr_id = nil
+ end
+ if item.attr_id_lm ~= nil then
+ item.attr_lm = self._attr_table[item.attr_id_lm][1]
+ item.attr_id_lm = nil
+ end
end
self._mode_info = mode_info
end
@@ -763,7 +931,10 @@ function Screen:_handle_clear()
-- newer clients, to check we remain compatible with both kind of clients,
-- ensure the scroll region is in a reset state.
local expected_region = {
- top = 1, bot = self._grid.height, left = 1, right = self._grid.width
+ top = 1,
+ bot = self._grid.height,
+ left = 1,
+ right = self._grid.width,
}
eq(expected_region, self._scroll_region)
self:_handle_grid_clear(1)
@@ -804,14 +975,24 @@ function Screen:_handle_win_pos(grid, win, startrow, startcol, width, height)
startrow = startrow,
startcol = startcol,
width = width,
- height = height
+ height = height,
}
self.float_pos[grid] = nil
end
-function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol, linecount, scroll_delta)
+function Screen:_handle_win_viewport(
+ grid,
+ win,
+ topline,
+ botline,
+ curline,
+ curcol,
+ linecount,
+ scroll_delta
+)
-- accumulate scroll delta
- local last_scroll_delta = self.win_viewport[grid] and self.win_viewport[grid].sum_scroll_delta or 0
+ local last_scroll_delta = self.win_viewport[grid] and self.win_viewport[grid].sum_scroll_delta
+ or 0
self.win_viewport[grid] = {
win = win,
topline = topline,
@@ -819,18 +1000,18 @@ function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curco
curline = curline,
curcol = curcol,
linecount = linecount,
- sum_scroll_delta = scroll_delta + last_scroll_delta
+ sum_scroll_delta = scroll_delta + last_scroll_delta,
}
end
function Screen:_handle_win_float_pos(grid, ...)
self.win_position[grid] = nil
- self.float_pos[grid] = {...}
+ self.float_pos[grid] = { ... }
end
function Screen:_handle_win_external_pos(grid)
self.win_position[grid] = nil
- self.float_pos[grid] = {external=true}
+ self.float_pos[grid] = { external = true }
end
function Screen:_handle_win_hide(grid)
@@ -846,7 +1027,7 @@ function Screen:_handle_win_extmark(grid, ...)
if self._grid_win_extmarks[grid] == nil then
self._grid_win_extmarks[grid] = {}
end
- table.insert(self._grid_win_extmarks[grid], {...})
+ table.insert(self._grid_win_extmarks[grid], { ... })
end
function Screen:_handle_busy_start()
@@ -866,7 +1047,7 @@ function Screen:_handle_mouse_off()
end
function Screen:_handle_mode_change(mode, idx)
- assert(mode == self._mode_info[idx+1].name)
+ assert(mode == self._mode_info[idx + 1].name)
self.mode = mode
end
@@ -882,17 +1063,24 @@ function Screen:_handle_scroll(count)
local bot = self._scroll_region.bot
local left = self._scroll_region.left
local right = self._scroll_region.right
- self:_handle_grid_scroll(1, top-1, bot, left-1, right, count, 0)
+ self:_handle_grid_scroll(1, top - 1, bot, left - 1, right, count, 0)
end
+--- @param g any
+--- @param top integer
+--- @param bot integer
+--- @param left integer
+--- @param right integer
+--- @param rows integer
+--- @param cols integer
function Screen:_handle_grid_scroll(g, top, bot, left, right, rows, cols)
- top = top+1
- left = left+1
+ top = top + 1
+ left = left + 1
assert(cols == 0)
local grid = self._grids[g]
+ --- @type integer, integer, integer
local start, stop, step
-
if rows > 0 then
start = top
stop = bot - rows
@@ -921,11 +1109,13 @@ function Screen:_handle_grid_scroll(g, top, bot, left, right, rows, cols)
end
function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
- self._attr_table[id] = {rgb_attrs, cterm_attrs}
+ self._attr_table[id] = { rgb_attrs, cterm_attrs }
self._hl_info[id] = info
self._new_attrs = true
end
+--- @param name string
+--- @param id integer
function Screen:_handle_hl_group_set(name, id)
self.hl_groups[name] = id
end
@@ -933,9 +1123,8 @@ end
function Screen:get_hl(val)
if self._options.ext_newgrid then
return self._attr_table[val][1]
- else
- return val
end
+ return val
end
function Screen:_handle_highlight_set(attrs)
@@ -951,14 +1140,18 @@ function Screen:_handle_put(str)
self._cursor.col = self._cursor.col + 1
end
+--- @param grid integer
+--- @param row integer
+--- @param col integer
+--- @param items integer[][]
function Screen:_handle_grid_line(grid, row, col, items)
assert(self._options.ext_linegrid)
assert(#items > 0)
- local line = self._grids[grid].rows[row+1]
- local colpos = col+1
+ local line = self._grids[grid].rows[row + 1]
+ local colpos = col + 1
local hl_id = 0
- for _,item in ipairs(items) do
- local text, hl_id_cell, count = unpack(item)
+ for _, item in ipairs(items) do
+ local text, hl_id_cell, count = item[1], item[2], item[3]
if hl_id_cell ~= nil then
hl_id = hl_id_cell
end
@@ -966,7 +1159,7 @@ function Screen:_handle_grid_line(grid, row, col, items)
local cell = line[colpos]
cell.text = text
cell.hl_id = hl_id
- colpos = colpos+1
+ colpos = colpos + 1
end
end
end
@@ -981,11 +1174,11 @@ end
function Screen:_handle_default_colors_set(rgb_fg, rgb_bg, rgb_sp, cterm_fg, cterm_bg)
self.default_colors = {
- rgb_fg=rgb_fg,
- rgb_bg=rgb_bg,
- rgb_sp=rgb_sp,
- cterm_fg=cterm_fg,
- cterm_bg=cterm_bg
+ rgb_fg = rgb_fg,
+ rgb_bg = rgb_bg,
+ rgb_sp = rgb_sp,
+ cterm_fg = cterm_fg,
+ cterm_bg = cterm_bg,
}
end
@@ -1021,8 +1214,12 @@ function Screen:_handle_option_set(name, value)
self.options[name] = value
end
+function Screen:_handle_chdir(path)
+ self.pwd = vim.fs.normalize(path, { expand_env = false })
+end
+
function Screen:_handle_popupmenu_show(items, selected, row, col, grid)
- self.popupmenu = {items=items, pos=selected, anchor={grid, row, col}}
+ self.popupmenu = { items = items, pos = selected, anchor = { grid, row, col } }
end
function Screen:_handle_popupmenu_select(selected)
@@ -1034,9 +1231,15 @@ function Screen:_handle_popupmenu_hide()
end
function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level)
- if firstc == '' then firstc = nil end
- if prompt == '' then prompt = nil end
- if indent == 0 then indent = nil end
+ if firstc == '' then
+ firstc = nil
+ end
+ if prompt == '' then
+ prompt = nil
+ end
+ if indent == 0 then
+ indent = nil
+ end
-- check position is valid #10000
local len = 0
@@ -1045,8 +1248,13 @@ function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level
end
assert(pos <= len)
- self.cmdline[level] = {content=content, pos=pos, firstc=firstc,
- prompt=prompt, indent=indent}
+ self.cmdline[level] = {
+ content = content,
+ pos = pos,
+ firstc = firstc,
+ prompt = prompt,
+ indent = indent,
+ }
end
function Screen:_handle_cmdline_hide(level)
@@ -1055,7 +1263,7 @@ end
function Screen:_handle_cmdline_special_char(char, shift, level)
-- cleared by next cmdline_show on the same level
- self.cmdline[level].special = {char, shift}
+ self.cmdline[level].special = { char, shift }
end
function Screen:_handle_cmdline_pos(pos, level)
@@ -1067,7 +1275,7 @@ function Screen:_handle_cmdline_block_show(block)
end
function Screen:_handle_cmdline_block_append(item)
- self.cmdline_block[#self.cmdline_block+1] = item
+ self.cmdline_block[#self.cmdline_block + 1] = item
end
function Screen:_handle_cmdline_block_hide()
@@ -1091,7 +1299,7 @@ function Screen:_handle_msg_show(kind, chunks, replace_last)
if not replace_last or pos == 0 then
pos = pos + 1
end
- self.messages[pos] = {kind=kind, content=chunks}
+ self.messages[pos] = { kind = kind, content = chunks }
end
function Screen:_handle_msg_clear()
@@ -1140,19 +1348,23 @@ function Screen:_row_repr(gridnr, rownr, attr_state, cursor)
local has_windows = self._options.ext_multigrid and gridnr == 1
local row = self._grids[gridnr].rows[rownr]
if has_windows and self.msg_grid and self.msg_grid_pos < rownr then
- return '['..self.msg_grid..':'..string.rep('-',#row)..']'
+ return '[' .. self.msg_grid .. ':' .. string.rep('-', #row) .. ']'
end
while i <= #row do
local did_window = false
if has_windows then
- for id,pos in pairs(self.win_position) do
- if i-1 == pos.startcol and pos.startrow <= rownr-1 and rownr-1 < pos.startrow + pos.height then
+ for id, pos in pairs(self.win_position) do
+ if
+ i - 1 == pos.startcol
+ and pos.startrow <= rownr - 1
+ and rownr - 1 < pos.startrow + pos.height
+ then
if current_attr_id then
-- close current attribute bracket
table.insert(rv, '}')
current_attr_id = nil
end
- table.insert(rv, '['..id..':'..string.rep('-',pos.width)..']')
+ table.insert(rv, '[' .. id .. ':' .. string.rep('-', pos.width) .. ']')
i = i + pos.width
did_window = true
end
@@ -1183,7 +1395,7 @@ function Screen:_row_repr(gridnr, rownr, attr_state, cursor)
end
-- return the line representation, but remove empty attribute brackets and
-- trailing whitespace
- return table.concat(rv, '')--:gsub('%s+$', '')
+ return table.concat(rv, '') --:gsub('%s+$', '')
end
function Screen:_extstate_repr(attr_state)
@@ -1201,29 +1413,29 @@ function Screen:_extstate_repr(attr_state)
local messages = {}
for i, entry in ipairs(self.messages) do
- messages[i] = {kind=entry.kind, content=self:_chunks_repr(entry.content, attr_state)}
+ messages[i] = { kind = entry.kind, content = self:_chunks_repr(entry.content, attr_state) }
end
local msg_history = {}
for i, entry in ipairs(self.msg_history) do
- msg_history[i] = {kind=entry[1], content=self:_chunks_repr(entry[2], attr_state)}
+ msg_history[i] = { kind = entry[1], content = self:_chunks_repr(entry[2], attr_state) }
end
local win_viewport = (next(self.win_viewport) and self.win_viewport) or nil
return {
- popupmenu=self.popupmenu,
- cmdline=cmdline,
- cmdline_block=cmdline_block,
- wildmenu_items=self.wildmenu_items,
- wildmenu_pos=self.wildmenu_pos,
- messages=messages,
- showmode=self:_chunks_repr(self.showmode, attr_state),
- showcmd=self:_chunks_repr(self.showcmd, attr_state),
- ruler=self:_chunks_repr(self.ruler, attr_state),
- msg_history=msg_history,
- float_pos=self.float_pos,
- win_viewport=win_viewport,
+ popupmenu = self.popupmenu,
+ cmdline = cmdline,
+ cmdline_block = cmdline_block,
+ wildmenu_items = self.wildmenu_items,
+ wildmenu_pos = self.wildmenu_pos,
+ messages = messages,
+ showmode = self:_chunks_repr(self.showmode, attr_state),
+ showcmd = self:_chunks_repr(self.showcmd, attr_state),
+ ruler = self:_chunks_repr(self.ruler, attr_state),
+ msg_history = msg_history,
+ float_pos = self.float_pos,
+ win_viewport = win_viewport,
}
end
@@ -1238,14 +1450,14 @@ function Screen:_chunks_repr(chunks, attr_state)
attrs = hl
end
local attr_id = self:_get_attr_id(attr_state, attrs, hl)
- repr_chunks[i] = {text, attr_id}
+ repr_chunks[i] = { text, attr_id }
end
return repr_chunks
end
-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
-- dumps the current screen state in the form of Screen:expect().
--- Use snapshot_util({},true) to generate a text-only (no attributes) test.
+-- Use snapshot_util({}) to generate a text-only (no attributes) test.
--
-- @see Screen:redraw_debug()
function Screen:snapshot_util(attrs, ignore, request_cb)
@@ -1259,7 +1471,7 @@ function Screen:redraw_debug(attrs, ignore, timeout)
assert(method == 'redraw')
for _, update in ipairs(args) do
-- mode_info_set is quite verbose, comment out the condition to debug it.
- if update[1] ~= "mode_info_set" then
+ if update[1] ~= 'mode_info_set' then
print(inspect(update))
end
end
@@ -1273,17 +1485,25 @@ function Screen:redraw_debug(attrs, ignore, timeout)
run_session(self._session, nil, notification_cb, nil, timeout)
end
+--- @param headers boolean
+--- @param attr_state any
+--- @param preview? boolean
+--- @return string[]
function Screen:render(headers, attr_state, preview)
headers = headers and (self._options.ext_multigrid or self._options._debug_float)
local rv = {}
- for igrid,grid in vim.spairs(self._grids) do
+ for igrid, grid in vim.spairs(self._grids) do
if headers then
- local suffix = ""
- if igrid > 1 and self.win_position[igrid] == nil
- and self.float_pos[igrid] == nil and self.msg_grid ~= igrid then
- suffix = " (hidden)"
+ local suffix = ''
+ if
+ igrid > 1
+ and self.win_position[igrid] == nil
+ and self.float_pos[igrid] == nil
+ and self.msg_grid ~= igrid
+ then
+ suffix = ' (hidden)'
end
- table.insert(rv, "## grid "..igrid..suffix)
+ table.insert(rv, '## grid ' .. igrid .. suffix)
end
local height = grid.height
if igrid == self.msg_grid then
@@ -1291,8 +1511,8 @@ function Screen:render(headers, attr_state, preview)
end
for i = 1, height do
local cursor = self._cursor.grid == igrid and self._cursor.row == i
- local prefix = (headers or preview) and " " or ""
- table.insert(rv, prefix..self:_row_repr(igrid, i, attr_state, cursor).."|")
+ local prefix = (headers or preview) and ' ' or ''
+ table.insert(rv, prefix .. self:_row_repr(igrid, i, attr_state, cursor) .. '|')
end
end
return rv
@@ -1301,15 +1521,22 @@ end
-- Returns the current screen state in the form of a screen:expect()
-- keyword-args map.
function Screen:get_snapshot(attrs, ignore)
- attrs = attrs or self._default_attr_ids
if ignore == nil then
ignore = self._default_attr_ignore
end
local attr_state = {
- ids = {},
- ignore = ignore,
- mutable = true, -- allow _row_repr to add missing highlights
+ ids = {},
+ ignore = ignore,
+ mutable = true, -- allow _row_repr to add missing highlights
}
+ if attrs == nil then
+ attrs = self._default_attr_ids
+ elseif isempty(attrs) then
+ attrs = nil
+ attr_state.ids = nil
+ else
+ attr_state.modified = true
+ end
if attrs ~= nil then
for i, a in pairs(attrs) do
@@ -1317,11 +1544,22 @@ function Screen:get_snapshot(attrs, ignore)
end
end
if self._options.ext_linegrid then
- attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids)
+ attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {})
end
local lines = self:render(true, attr_state, true)
+ for i, row in ipairs(lines) do
+ local count = 1
+ while i < #lines and lines[i + 1] == row do
+ count = count + 1
+ table.remove(lines, i + 1)
+ end
+ if count > 1 then
+ lines[i] = lines[i] .. '*' .. count
+ end
+ end
+
local ext_state = self:_extstate_repr(attr_state)
for k, v in pairs(ext_state) do
if isempty(v) then
@@ -1353,33 +1591,50 @@ local function fmt_ext_state(name, state)
return item
end
end
- if name == "win_viewport" then
- local str = "{\n"
- for k,v in pairs(state) do
- str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = "
- ..v.topline..", botline = "..v.botline..", curline = "..v.curline
- ..", curcol = "..v.curcol..", linecount = "..v.linecount..", sum_scroll_delta = "..v.sum_scroll_delta.."};\n")
+ if name == 'win_viewport' then
+ local str = '{\n'
+ for k, v in pairs(state) do
+ str = (
+ str
+ .. ' ['
+ .. k
+ .. '] = {win = '
+ .. v.win
+ .. ', topline = '
+ .. v.topline
+ .. ', botline = '
+ .. v.botline
+ .. ', curline = '
+ .. v.curline
+ .. ', curcol = '
+ .. v.curcol
+ .. ', linecount = '
+ .. v.linecount
+ .. ', sum_scroll_delta = '
+ .. v.sum_scroll_delta
+ .. '};\n'
+ )
end
- return str .. "}"
- elseif name == "float_pos" then
- local str = "{\n"
- for k,v in pairs(state) do
- str = str.." ["..k.."] = {{id = "..v[1].id.."}"
+ return str .. '}'
+ elseif name == 'float_pos' then
+ local str = '{\n'
+ for k, v in pairs(state) do
+ str = str .. ' [' .. k .. '] = {' .. v[1]
for i = 2, #v do
- str = str..", "..inspect(v[i])
+ str = str .. ', ' .. inspect(v[i])
end
- str = str .. "};\n"
+ str = str .. '};\n'
end
- return str .. "}"
+ return str .. '}'
else
-- TODO(bfredl): improve formatting of more states
- return inspect(state,{process=remove_all_metatables})
+ return inspect(state, { process = remove_all_metatables })
end
end
-function Screen:print_snapshot(attrs, ignore)
+function Screen:_print_snapshot(attrs, ignore)
local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore)
- local attrstr = ""
+ local attrstr = ''
if attr_state.modified then
local attrstrs = {}
for i, a in pairs(attr_state.ids) do
@@ -1387,23 +1642,29 @@ function Screen:print_snapshot(attrs, ignore)
if self._options.ext_linegrid then
dict = self:_pprint_hlitem(a)
else
- dict = "{"..self:_pprint_attrs(a).."}"
+ dict = '{' .. self:_pprint_attrs(a) .. '}'
end
- local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
- table.insert(attrstrs, " "..keyval.." = "..dict..";")
+ local keyval = (type(i) == 'number') and '[' .. tostring(i) .. ']' or i
+ table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ';')
end
- attrstr = (", attr_ids={\n"..table.concat(attrstrs, "\n").."\n}")
+ attrstr = (', attr_ids={\n' .. table.concat(attrstrs, '\n') .. '\n}')
+ elseif isempty(attrs) then
+ attrstr = ', attr_ids={}'
end
- print( "\nscreen:expect{grid=[[")
- print(kwargs.grid)
- io.stdout:write( "]]"..attrstr)
+ local result = 'screen:expect{grid=[[\n' .. kwargs.grid .. '\n]]' .. attrstr
for _, k in ipairs(ext_keys) do
- if ext_state[k] ~= nil and not (k == "win_viewport" and not self.options.ext_multigrid) then
- io.stdout:write(", "..k.."="..fmt_ext_state(k, ext_state[k]))
+ if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then
+ result = result .. ', ' .. k .. '=' .. fmt_ext_state(k, ext_state[k])
end
end
- print("}\n")
+ result = result .. '}'
+
+ return result
+end
+
+function Screen:print_snapshot(attrs, ignore)
+ print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n')
io.stdout:flush()
end
@@ -1422,7 +1683,7 @@ function Screen:_insert_hl_id(attr_state, hl_id)
else
info[1] = {}
for k, v in pairs(raw_info[1]) do
- if k ~= "id" then
+ if k ~= 'id' then
info[1][k] = v
end
end
@@ -1432,9 +1693,9 @@ function Screen:_insert_hl_id(attr_state, hl_id)
local entry = self._attr_table[hl_id]
local attrval
if self._rgb_cterm then
- attrval = {entry[1], entry[2], info} -- unpack() doesn't work
+ attrval = { entry[1], entry[2], info } -- unpack() doesn't work
elseif self._options.ext_hlstate then
- attrval = {entry[1], info}
+ attrval = { entry[1], info }
else
attrval = self._options.rgb and entry[1] or entry[2]
end
@@ -1450,17 +1711,17 @@ function Screen:linegrid_check_attrs(attrs)
local iinfo = self._hl_info[i]
local matchinfo = {}
if #iinfo > 1 then
- for k,item in ipairs(iinfo) do
+ for k, item in ipairs(iinfo) do
matchinfo[k] = id_to_index[item.id]
end
else
matchinfo = iinfo
end
- for k,v in pairs(attrs) do
+ for k, v in pairs(attrs) do
local attr, info, attr_rgb, attr_cterm
if self._rgb_cterm then
attr_rgb, attr_cterm, info = unpack(v)
- attr = {attr_rgb, attr_cterm}
+ attr = { attr_rgb, attr_cterm }
info = info or {}
elseif self._options.ext_hlstate then
attr, info = unpack(v)
@@ -1472,12 +1733,12 @@ function Screen:linegrid_check_attrs(attrs)
if #info == #matchinfo then
local match = false
if #info == 1 then
- if self:_equal_info(info[1],matchinfo[1]) then
+ if self:_equal_info(info[1], matchinfo[1]) then
match = true
end
else
match = true
- for j = 1,#info do
+ for j = 1, #info do
if info[j] ~= matchinfo[j] then
match = false
end
@@ -1489,32 +1750,34 @@ function Screen:linegrid_check_attrs(attrs)
end
end
end
- if self:_equal_attr_def(self._rgb_cterm and {{}, {}} or {}, def_attr) and #self._hl_info[i] == 0 then
- id_to_index[i] = ""
+ if
+ self:_equal_attr_def(self._rgb_cterm and { {}, {} } or {}, def_attr)
+ and #self._hl_info[i] == 0
+ then
+ id_to_index[i] = ''
end
end
return id_to_index
end
-
function Screen:_pprint_hlitem(item)
- -- print(inspect(item))
- local multi = self._rgb_cterm or self._options.ext_hlstate
- local cterm = (not self._rgb_cterm and not self._options.rgb)
- local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item, cterm).."}"
- local attrdict2, hlinfo
- local descdict = ""
- if self._rgb_cterm then
- attrdict2 = ", {"..self:_pprint_attrs(item[2], true).."}"
- hlinfo = item[3]
- else
- attrdict2 = ""
- hlinfo = item[2]
- end
- if self._options.ext_hlstate then
- descdict = ", {"..self:_pprint_hlinfo(hlinfo).."}"
- end
- return (multi and "{" or "")..attrdict..attrdict2..descdict..(multi and "}" or "")
+ -- print(inspect(item))
+ local multi = self._rgb_cterm or self._options.ext_hlstate
+ local cterm = (not self._rgb_cterm and not self._options.rgb)
+ local attrdict = '{' .. self:_pprint_attrs(multi and item[1] or item, cterm) .. '}'
+ local attrdict2, hlinfo
+ local descdict = ''
+ if self._rgb_cterm then
+ attrdict2 = ', {' .. self:_pprint_attrs(item[2], true) .. '}'
+ hlinfo = item[3]
+ else
+ attrdict2 = ''
+ hlinfo = item[2]
+ end
+ if self._options.ext_hlstate then
+ descdict = ', {' .. self:_pprint_hlinfo(hlinfo) .. '}'
+ end
+ return (multi and '{' or '') .. attrdict .. attrdict2 .. descdict .. (multi and '}' or '')
end
function Screen:_pprint_hlinfo(states)
@@ -1522,37 +1785,37 @@ function Screen:_pprint_hlinfo(states)
local items = {}
for f, v in pairs(states[1]) do
local desc = tostring(v)
- if type(v) == type("") then
- desc = '"'..desc..'"'
+ if type(v) == type('') then
+ desc = '"' .. desc .. '"'
end
- table.insert(items, f.." = "..desc)
+ table.insert(items, f .. ' = ' .. desc)
end
- return "{"..table.concat(items, ", ").."}"
+ return '{' .. table.concat(items, ', ') .. '}'
else
- return table.concat(states, ", ")
+ return table.concat(states, ', ')
end
end
-
function Screen:_pprint_attrs(attrs, cterm)
- local items = {}
- for f, v in pairs(attrs) do
- local desc = tostring(v)
- if f == "foreground" or f == "background" or f == "special" then
- if Screen.colornames[v] ~= nil then
- desc = "Screen.colors."..Screen.colornames[v]
- elseif cterm then
- desc = tostring(v)
- else
- desc = string.format("tonumber('0x%06x')",v)
- end
+ local items = {}
+ for f, v in pairs(attrs) do
+ local desc = tostring(v)
+ if f == 'foreground' or f == 'background' or f == 'special' then
+ if Screen.colornames[v] ~= nil then
+ desc = 'Screen.colors.' .. Screen.colornames[v]
+ elseif cterm then
+ desc = tostring(v)
+ else
+ desc = string.format("tonumber('0x%06x')", v)
end
- table.insert(items, f.." = "..desc)
end
- return table.concat(items, ", ")
+ table.insert(items, f .. ' = ' .. desc)
+ end
+ return table.concat(items, ', ')
end
-local function backward_find_meaningful(tbl, from) -- luacheck: no unused
+---@diagnostic disable-next-line: unused-local, unused-function
+local function backward_find_meaningful(tbl, from) -- luacheck: no unused
for i = from or #tbl, 1, -1 do
if tbl[i] ~= ' ' then
return i + 1
@@ -1568,7 +1831,7 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
if self._options.ext_linegrid then
local id = attr_state.id_to_index[hl_id]
- if id == "" then -- sentinel for empty it
+ if id == '' then -- sentinel for empty it
return nil
elseif id ~= nil then
return id
@@ -1579,7 +1842,7 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
return id
end
local kind = self._options.rgb and 1 or 2
- return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][kind])
+ return 'UNEXPECTED ' .. self:_pprint_attrs(self._attr_table[hl_id][kind])
else
if self:_equal_attrs(attrs, {}) then
-- ignore this attrs
@@ -1587,49 +1850,57 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
end
for id, a in pairs(attr_state.ids) do
if self:_equal_attrs(a, attrs) then
- return id
- end
+ return id
+ end
end
if attr_state.mutable then
table.insert(attr_state.ids, attrs)
attr_state.modified = true
return #attr_state.ids
end
- return "UNEXPECTED "..self:_pprint_attrs(attrs)
+ return 'UNEXPECTED ' .. self:_pprint_attrs(attrs)
end
end
function Screen:_equal_attr_def(a, b)
if self._rgb_cterm then
- return self:_equal_attrs(a[1],b[1]) and self:_equal_attrs(a[2],b[2])
+ return self:_equal_attrs(a[1], b[1]) and self:_equal_attrs(a[2], b[2])
elseif self._options.rgb then
- return self:_equal_attrs(a,b[1])
+ return self:_equal_attrs(a, b[1])
else
- return self:_equal_attrs(a,b[2])
+ return self:_equal_attrs(a, b[2])
end
end
function Screen:_equal_attrs(a, b)
- return a.bold == b.bold and a.standout == b.standout and
- a.underline == b.underline and a.undercurl == b.undercurl and
- a.underdouble == b.underdouble and a.underdotted == b.underdotted and
- a.underdashed == b.underdashed and a.italic == b.italic and
- a.reverse == b.reverse and a.foreground == b.foreground and
- a.background == b.background and a.special == b.special and a.blend == b.blend and
- a.strikethrough == b.strikethrough and
- a.fg_indexed == b.fg_indexed and a.bg_indexed == b.bg_indexed
+ return a.bold == b.bold
+ and a.standout == b.standout
+ and a.underline == b.underline
+ and a.undercurl == b.undercurl
+ and a.underdouble == b.underdouble
+ and a.underdotted == b.underdotted
+ and a.underdashed == b.underdashed
+ and a.italic == b.italic
+ and a.reverse == b.reverse
+ and a.foreground == b.foreground
+ and a.background == b.background
+ and a.special == b.special
+ and a.blend == b.blend
+ and a.strikethrough == b.strikethrough
+ and a.fg_indexed == b.fg_indexed
+ and a.bg_indexed == b.bg_indexed
+ and a.url == b.url
end
function Screen:_equal_info(a, b)
- return a.kind == b.kind and a.hi_name == b.hi_name and
- a.ui_name == b.ui_name
+ return a.kind == b.kind and a.hi_name == b.hi_name and a.ui_name == b.ui_name
end
function Screen:_attr_index(attrs, attr)
if not attrs then
return nil
end
- for i,a in pairs(attrs) do
+ for i, a in pairs(attrs) do
if self:_equal_attrs(a, attr) then
return i
end