mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #8942 from bfredl/attr_state
screen.lua: extend snapshot_util() to work with extension state
This commit is contained in:
commit
7ff63fcdc0
@ -510,12 +510,7 @@ local function test_cmdline(newgrid)
|
|||||||
screen:set_default_attr_ids({
|
screen:set_default_attr_ids({
|
||||||
RBP1={background = Screen.colors.Red},
|
RBP1={background = Screen.colors.Red},
|
||||||
RBP2={background = Screen.colors.Yellow},
|
RBP2={background = Screen.colors.Yellow},
|
||||||
RBP3={background = Screen.colors.Green},
|
|
||||||
RBP4={background = Screen.colors.Blue},
|
|
||||||
EOB={bold = true, foreground = Screen.colors.Blue1},
|
EOB={bold = true, foreground = Screen.colors.Blue1},
|
||||||
ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
|
||||||
SK={foreground = Screen.colors.Blue},
|
|
||||||
PE={bold = true, foreground = Screen.colors.SeaGreen4}
|
|
||||||
})
|
})
|
||||||
feed('<f5>(a(b)a)')
|
feed('<f5>(a(b)a)')
|
||||||
screen:expect{grid=[[
|
screen:expect{grid=[[
|
||||||
|
@ -78,6 +78,12 @@ local request, run, uimeths = helpers.request, helpers.run, helpers.uimeths
|
|||||||
local eq = helpers.eq
|
local eq = helpers.eq
|
||||||
local dedent = helpers.dedent
|
local dedent = helpers.dedent
|
||||||
|
|
||||||
|
local inspect = require('inspect')
|
||||||
|
|
||||||
|
local function isempty(v)
|
||||||
|
return type(v) == 'table' and next(v) == nil
|
||||||
|
end
|
||||||
|
|
||||||
local Screen = {}
|
local Screen = {}
|
||||||
Screen.__index = Screen
|
Screen.__index = Screen
|
||||||
|
|
||||||
@ -200,6 +206,11 @@ function Screen:set_option(option, value)
|
|||||||
self._options[option] = value
|
self._options[option] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- canonical order of ext keys, used to generate asserts
|
||||||
|
local ext_keys = {
|
||||||
|
'popupmenu', 'cmdline', 'cmdline_block', 'wildmenu_items', 'wildmenu_pos'
|
||||||
|
}
|
||||||
|
|
||||||
-- Asserts that the screen state eventually matches an expected state
|
-- Asserts that the screen state eventually matches an expected state
|
||||||
--
|
--
|
||||||
-- This function can either be called with the positional forms
|
-- This function can either be called with the positional forms
|
||||||
@ -246,8 +257,10 @@ function Screen:expect(expected, attr_ids, attr_ignore)
|
|||||||
if type(expected) == "table" then
|
if type(expected) == "table" then
|
||||||
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
|
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
|
||||||
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
|
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
|
||||||
any=true, mode=true, popupmenu=true, cmdline=true,
|
any=true, mode=true}
|
||||||
cmdline_block=true, wildmenu_items=true, wildmenu_pos=true}
|
for _, v in ipairs(ext_keys) do
|
||||||
|
is_key[v] = true
|
||||||
|
end
|
||||||
for k, _ in pairs(expected) do
|
for k, _ in pairs(expected) do
|
||||||
if not is_key[k] then
|
if not is_key[k] then
|
||||||
error("Screen:expect: Unknown keyword argument '"..k.."'")
|
error("Screen:expect: Unknown keyword argument '"..k.."'")
|
||||||
@ -278,11 +291,12 @@ function Screen:expect(expected, attr_ids, attr_ignore)
|
|||||||
table.insert(expected_rows, row)
|
table.insert(expected_rows, row)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local ids = attr_ids or self._default_attr_ids
|
local attr_state = {
|
||||||
local ignore = attr_ignore or self._default_attr_ignore
|
ids = attr_ids or self._default_attr_ids,
|
||||||
local id_to_index
|
ignore = attr_ignore or self._default_attr_ignore,
|
||||||
|
}
|
||||||
if self._options.ext_hlstate then
|
if self._options.ext_hlstate then
|
||||||
id_to_index = self:hlstate_check_attrs(ids or {})
|
attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
|
||||||
end
|
end
|
||||||
self._new_attrs = false
|
self._new_attrs = false
|
||||||
self:wait(function()
|
self:wait(function()
|
||||||
@ -299,13 +313,12 @@ function Screen:expect(expected, attr_ids, attr_ignore)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if self._options.ext_hlstate and self._new_attrs then
|
if self._options.ext_hlstate and self._new_attrs then
|
||||||
id_to_index = self:hlstate_check_attrs(ids or {})
|
attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {})
|
||||||
end
|
end
|
||||||
|
|
||||||
local info = self._options.ext_hlstate and id_to_index or ids
|
|
||||||
local actual_rows = {}
|
local actual_rows = {}
|
||||||
for i = 1, self._height do
|
for i = 1, self._height do
|
||||||
actual_rows[i] = self:_row_repr(self._rows[i], info, ignore)
|
actual_rows[i] = self:_row_repr(self._rows[i], attr_state)
|
||||||
end
|
end
|
||||||
|
|
||||||
if expected.any ~= nil then
|
if expected.any ~= nil then
|
||||||
@ -342,28 +355,18 @@ screen:redraw_debug() to show all intermediate screen states. ]])
|
|||||||
|
|
||||||
-- Extension features. The default expectations should cover the case of
|
-- Extension features. The default expectations should cover the case of
|
||||||
-- the ext_ feature being disabled, or the feature currently not activated
|
-- the ext_ feature being disabled, or the feature currently not activated
|
||||||
-- (for instance no external cmdline visible)
|
-- (for instance no external cmdline visible). Some extensions require
|
||||||
local expected_cmdline = expected.cmdline or {}
|
-- preprocessing to prepresent highlights in a reproducible way.
|
||||||
local actual_cmdline = {}
|
local extstate = self:_extstate_repr(attr_state)
|
||||||
for i, entry in pairs(self.cmdline) do
|
|
||||||
entry = shallowcopy(entry)
|
|
||||||
entry.content = self:_chunks_repr(entry.content, info, ignore)
|
|
||||||
actual_cmdline[i] = entry
|
|
||||||
end
|
|
||||||
|
|
||||||
local expected_block = expected.cmdline_block or {}
|
|
||||||
local actual_block = {}
|
|
||||||
for i, entry in ipairs(self.cmdline_block) do
|
|
||||||
actual_block[i] = self:_chunks_repr(entry, info, ignore)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- convert assertion errors into invalid screen state descriptions
|
-- convert assertion errors into invalid screen state descriptions
|
||||||
local status, res = pcall(function()
|
local status, res = pcall(function()
|
||||||
eq(expected.popupmenu, self.popupmenu, "popupmenu")
|
for _, k in ipairs(ext_keys) do
|
||||||
eq(expected_cmdline, actual_cmdline, "cmdline")
|
-- Empty states is considered the default and need not be mentioned
|
||||||
eq(expected_block, actual_block, "cmdline_block")
|
if not (expected[k] == nil and isempty(extstate[k])) then
|
||||||
eq(expected.wildmenu_items, self.wildmenu_items, "wildmenu_items")
|
eq(expected[k], extstate[k], k)
|
||||||
eq(expected.wildmenu_pos, self.wildmenu_pos, "wildmenu_pos")
|
end
|
||||||
|
end
|
||||||
if expected.mode ~= nil then
|
if expected.mode ~= nil then
|
||||||
eq(expected.mode, self.mode, "mode")
|
eq(expected.mode, self.mode, "mode")
|
||||||
end
|
end
|
||||||
@ -438,7 +441,6 @@ function Screen:_redraw(updates)
|
|||||||
self._on_event(method, update[i])
|
self._on_event(method, update[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- print(self:_current_screen())
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -745,7 +747,7 @@ function Screen:_clear_row_section(rownum, startcol, stopcol)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_row_repr(row, attr_ids, attr_ignore)
|
function Screen:_row_repr(row, attr_state)
|
||||||
local rv = {}
|
local rv = {}
|
||||||
local current_attr_id
|
local current_attr_id
|
||||||
for i = 1, self._width do
|
for i = 1, self._width do
|
||||||
@ -753,7 +755,7 @@ function Screen:_row_repr(row, attr_ids, attr_ignore)
|
|||||||
if self._options.ext_newgrid then
|
if self._options.ext_newgrid then
|
||||||
attrs = attrs[(self._options.rgb and 1) or 2]
|
attrs = attrs[(self._options.rgb and 1) or 2]
|
||||||
end
|
end
|
||||||
local attr_id = self:_get_attr_id(attr_ids, attr_ignore, attrs, row[i].hl_id)
|
local attr_id = self:_get_attr_id(attr_state, attrs, row[i].hl_id)
|
||||||
if current_attr_id and attr_id ~= current_attr_id then
|
if current_attr_id and attr_id ~= current_attr_id then
|
||||||
-- close current attribute bracket, add it before any whitespace
|
-- close current attribute bracket, add it before any whitespace
|
||||||
-- up to the current cell
|
-- up to the current cell
|
||||||
@ -779,7 +781,29 @@ function Screen:_row_repr(row, attr_ids, attr_ignore)
|
|||||||
return table.concat(rv, '')--:gsub('%s+$', '')
|
return table.concat(rv, '')--:gsub('%s+$', '')
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_chunks_repr(chunks, attr_ids, attr_ignore)
|
function Screen:_extstate_repr(attr_state)
|
||||||
|
local cmdline = {}
|
||||||
|
for i, entry in pairs(self.cmdline) do
|
||||||
|
entry = shallowcopy(entry)
|
||||||
|
entry.content = self:_chunks_repr(entry.content, attr_state)
|
||||||
|
cmdline[i] = entry
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmdline_block = {}
|
||||||
|
for i, entry in ipairs(self.cmdline_block) do
|
||||||
|
cmdline_block[i] = self:_chunks_repr(entry, attr_state)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
popupmenu=self.popupmenu,
|
||||||
|
cmdline=cmdline,
|
||||||
|
cmdline_block=cmdline_block,
|
||||||
|
wildmenu_items=self.wildmenu_items,
|
||||||
|
wildmenu_pos=self.wildmenu_pos,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Screen:_chunks_repr(chunks, attr_state)
|
||||||
local repr_chunks = {}
|
local repr_chunks = {}
|
||||||
for i, chunk in ipairs(chunks) do
|
for i, chunk in ipairs(chunks) do
|
||||||
local hl, text = unpack(chunk)
|
local hl, text = unpack(chunk)
|
||||||
@ -789,21 +813,12 @@ function Screen:_chunks_repr(chunks, attr_ids, attr_ignore)
|
|||||||
else
|
else
|
||||||
attrs = hl
|
attrs = hl
|
||||||
end
|
end
|
||||||
local attr_id = self:_get_attr_id(attr_ids, attr_ignore, attrs, hl)
|
local attr_id = self:_get_attr_id(attr_state, attrs, hl)
|
||||||
repr_chunks[i] = {text, attr_id}
|
repr_chunks[i] = {text, attr_id}
|
||||||
end
|
end
|
||||||
return repr_chunks
|
return repr_chunks
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_current_screen()
|
|
||||||
-- get a string that represents the current screen state(debugging helper)
|
|
||||||
local rv = {}
|
|
||||||
for i = 1, self._height do
|
|
||||||
table.insert(rv, "'"..self:_row_repr(self._rows[i]).."'")
|
|
||||||
end
|
|
||||||
return table.concat(rv, '\n')
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
|
-- Generates tests. Call it where Screen:expect() would be. Waits briefly, then
|
||||||
-- dumps the current screen state in the form of Screen:expect().
|
-- 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({},true) to generate a text-only (no attributes) test.
|
||||||
@ -832,82 +847,77 @@ function Screen:redraw_debug(attrs, ignore, timeout)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Screen:print_snapshot(attrs, ignore)
|
function Screen:print_snapshot(attrs, ignore)
|
||||||
|
attrs = attrs or self._default_attr_ids
|
||||||
if ignore == nil then
|
if ignore == nil then
|
||||||
ignore = self._default_attr_ignore
|
ignore = self._default_attr_ignore
|
||||||
end
|
end
|
||||||
local id_to_index = {}
|
local attr_state = {
|
||||||
if attrs == nil then
|
ids = {},
|
||||||
attrs = {}
|
ignore = ignore,
|
||||||
if self._default_attr_ids ~= nil then
|
mutable = true, -- allow _row_repr to add missing highlights
|
||||||
for i, a in pairs(self._default_attr_ids) do
|
}
|
||||||
attrs[i] = a
|
|
||||||
end
|
|
||||||
if self._options.ext_hlstate then
|
|
||||||
id_to_index = self:hlstate_check_attrs(attrs)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if ignore ~= true then
|
if attrs ~= nil then
|
||||||
for i = 1, self._height do
|
for i, a in pairs(attrs) do
|
||||||
local row = self._rows[i]
|
attr_state.ids[i] = a
|
||||||
for j = 1, self._width do
|
|
||||||
if self._options.ext_hlstate then
|
|
||||||
local hl_id = row[j].hl_id
|
|
||||||
if hl_id ~= 0 then
|
|
||||||
self:_insert_hl_id(attrs, id_to_index, hl_id)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local attr = row[j].attrs
|
|
||||||
if self:_attr_index(attrs, attr) == nil and self:_attr_index(ignore, attr) == nil then
|
|
||||||
if not self:_equal_attrs(attr, {}) then
|
|
||||||
table.insert(attrs, attr)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if self._options.ext_hlstate then
|
||||||
|
attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids)
|
||||||
|
end
|
||||||
|
|
||||||
local rv = {}
|
local lines = {}
|
||||||
local info = self._options.ext_hlstate and id_to_index or attrs
|
|
||||||
for i = 1, self._height do
|
for i = 1, self._height do
|
||||||
table.insert(rv, " "..self:_row_repr(self._rows[i], info, ignore).."|")
|
table.insert(lines, " "..self:_row_repr(self._rows[i], attr_state).."|")
|
||||||
end
|
end
|
||||||
local attrstrs = {}
|
|
||||||
local alldefault = true
|
local ext_state = self:_extstate_repr(attr_state)
|
||||||
for i, a in ipairs(attrs) do
|
local keys = false
|
||||||
if self._default_attr_ids == nil or self._default_attr_ids[i] ~= a then
|
for k, v in pairs(ext_state) do
|
||||||
alldefault = false
|
if isempty(v) then
|
||||||
end
|
ext_state[k] = nil -- deleting keys while iterating is ok
|
||||||
local dict
|
|
||||||
if self._options.ext_hlstate then
|
|
||||||
dict = self:_pprint_hlstate(a)
|
|
||||||
else
|
else
|
||||||
dict = "{"..self:_pprint_attrs(a).."}"
|
keys = true
|
||||||
end
|
end
|
||||||
table.insert(attrstrs, "["..tostring(i).."] = "..dict)
|
|
||||||
end
|
end
|
||||||
local attrstr = "{"..table.concat(attrstrs, ", ").."}"
|
|
||||||
print( "\nscreen:expect([[")
|
local attrstr = ""
|
||||||
print( table.concat(rv, '\n'))
|
if attr_state.modified then
|
||||||
if alldefault then
|
local attrstrs = {}
|
||||||
print( "]])\n")
|
for i, a in pairs(attr_state.ids) do
|
||||||
else
|
local dict
|
||||||
print( "]], "..attrstr..")\n")
|
if self._options.ext_hlstate then
|
||||||
|
dict = self:_pprint_hlstate(a)
|
||||||
|
else
|
||||||
|
dict = "{"..self:_pprint_attrs(a).."}"
|
||||||
|
end
|
||||||
|
local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
|
||||||
|
table.insert(attrstrs, " "..keyval.." = "..dict..",")
|
||||||
|
end
|
||||||
|
attrstr = (", "..(keys and "attr_ids=" or "")
|
||||||
|
.."{\n"..table.concat(attrstrs, "\n").."\n}")
|
||||||
end
|
end
|
||||||
|
print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[")
|
||||||
|
print( table.concat(lines, '\n'))
|
||||||
|
io.stdout:write( "]]"..attrstr)
|
||||||
|
for _, k in ipairs(ext_keys) do
|
||||||
|
if ext_state[k] ~= nil then
|
||||||
|
io.stdout:write(", "..k.."="..inspect(ext_state[k]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print((keys and "}" or ")").."\n")
|
||||||
io.stdout:flush()
|
io.stdout:flush()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_insert_hl_id(attrs, id_to_index, hl_id)
|
function Screen:_insert_hl_id(attr_state, hl_id)
|
||||||
if id_to_index[hl_id] ~= nil then
|
if attr_state.id_to_index[hl_id] ~= nil then
|
||||||
return id_to_index[hl_id]
|
return attr_state.id_to_index[hl_id]
|
||||||
end
|
end
|
||||||
local raw_info = self._hl_info[hl_id]
|
local raw_info = self._hl_info[hl_id]
|
||||||
local info = {}
|
local info = {}
|
||||||
if #raw_info > 1 then
|
if #raw_info > 1 then
|
||||||
for i, item in ipairs(raw_info) do
|
for i, item in ipairs(raw_info) do
|
||||||
info[i] = self:_insert_hl_id(attrs, id_to_index, item.id)
|
info[i] = self:_insert_hl_id(attr_state, item.id)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
info[1] = {}
|
info[1] = {}
|
||||||
@ -927,9 +937,9 @@ function Screen:_insert_hl_id(attrs, id_to_index, hl_id)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
table.insert(attrs, attrval)
|
table.insert(attr_state.ids, attrval)
|
||||||
id_to_index[hl_id] = #attrs
|
attr_state.id_to_index[hl_id] = #attr_state.ids
|
||||||
return #attrs
|
return #attr_state.ids
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:hlstate_check_attrs(attrs)
|
function Screen:hlstate_check_attrs(attrs)
|
||||||
@ -1033,28 +1043,39 @@ local function backward_find_meaningful(tbl, from) -- luacheck: no unused
|
|||||||
return from
|
return from
|
||||||
end
|
end
|
||||||
|
|
||||||
function Screen:_get_attr_id(attr_ids, ignore, attrs, hl_id)
|
function Screen:_get_attr_id(attr_state, attrs, hl_id)
|
||||||
if not attr_ids then
|
if not attr_state.ids then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if self._options.ext_hlstate then
|
if self._options.ext_hlstate then
|
||||||
local id = attr_ids[hl_id]
|
local id = attr_state.id_to_index[hl_id]
|
||||||
if id ~= nil or hl_id == 0 then
|
if id ~= nil or hl_id == 0 then
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
if attr_state.mutable then
|
||||||
|
id = self:_insert_hl_id(attr_state, hl_id)
|
||||||
|
attr_state.modified = true
|
||||||
|
return id
|
||||||
|
end
|
||||||
return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
|
return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
|
||||||
else
|
else
|
||||||
for id, a in pairs(attr_ids) do
|
for id, a in pairs(attr_state.ids) do
|
||||||
if self:_equal_attrs(a, attrs) then
|
if self:_equal_attrs(a, attrs) then
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self:_equal_attrs(attrs, {}) or
|
if self:_equal_attrs(attrs, {}) or
|
||||||
ignore == true or self:_attr_index(ignore, attrs) ~= nil then
|
attr_state.ignore == true or
|
||||||
|
self:_attr_index(attr_state.ignore, attrs) ~= nil then
|
||||||
-- ignore this attrs
|
-- ignore this attrs
|
||||||
return nil
|
return nil
|
||||||
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
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user