From c2249f6abf719407cf9bbeecb16a3c1a7d79264d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 9 Dec 2023 19:03:07 +0800 Subject: [PATCH 1/4] test: allow avoiding repeated screen lines in expected states Allow a "*count" suffix in a screen line to repeat the screen line for "count" times. The change is made to Screen:expect() and Screen:get_snapshot() instead of Screen:render() so that screen expectations generated using code can still work and test failures can still be readable. A snapshot is now also printed on failure so that there is no need to run the test again with Screen:snapshot_util(). --- test/functional/ui/screen.lua | 59 ++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index be7c2f291c..74035fc79d 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -259,6 +259,7 @@ local ext_keys = { -- row. Last character of each row (typically "|") is stripped. -- Common indentation is stripped. -- "{MATCH:x}" in a line is matched against Lua pattern `x`. +-- "*count" at the end of a line means it repeats `count` times. -- 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 @@ -375,14 +376,26 @@ function Screen:expect(expected, attr_ids, ...) end if grid ~= nil then - local err_msg, msg_expected_rows = nil, {} + for i, row in ipairs(expected_rows) do + local count + 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 .. '.' 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 if actual_rows[i] and row ~= actual_rows[i] then local after = row @@ -399,7 +412,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.' @@ -409,10 +422,10 @@ function Screen:expect(expected, attr_ids, ...) 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'..[[ + ..'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 @@ -619,7 +632,7 @@ between asynchronous (feed(), nvim_input()) and synchronous API calls. if err then if eof then err = err..'\n\n'..eof[2] end - busted.fail(err, 3) + busted.fail(err .. '\n\nSnapshot:\n' .. self:_print_snapshot(), 3) elseif did_warn then if eof then print(eof[2]) end local tb = debug.traceback() @@ -1295,7 +1308,6 @@ 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 @@ -1304,6 +1316,11 @@ function Screen:get_snapshot(attrs, ignore) ignore = ignore, mutable = true, -- allow _row_repr to add missing highlights } + if attrs == nil then + attrs = self._default_attr_ids + else + attr_state.modified = true + end if attrs ~= nil then for i, a in pairs(attrs) do @@ -1316,6 +1333,17 @@ function Screen:get_snapshot(attrs, ignore) 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 @@ -1371,7 +1399,7 @@ local function fmt_ext_state(name, state) 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 = "" if attr_state.modified then @@ -1389,16 +1417,19 @@ function Screen:print_snapshot(attrs, ignore) attrstr = (", attr_ids={\n"..table.concat(attrstrs, "\n").."\n}") 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])) + result = result .. ', ' .. k .. '=' .. fmt_ext_state(k, ext_state[k]) end end - print("}\n") - io.stdout:flush() + result = result .. '}' + + return result +end + +function Screen:print_snapshot(attrs, ignore) + print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n') end function Screen:_insert_hl_id(attr_state, hl_id) From 20bd03f166a80c6e17ab9a828edf481df0fb4876 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 10 Dec 2023 07:06:48 +0800 Subject: [PATCH 2/4] test: make text-only snapshots work --- test/functional/ui/screen.lua | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 74035fc79d..6382fe1f92 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -259,12 +259,13 @@ local ext_keys = { -- row. Last character of each row (typically "|") is stripped. -- Common indentation is stripped. -- "{MATCH:x}" in a line is matched against Lua pattern `x`. --- "*count" at the end of a line means it repeats `count` times. +-- "*n" at the end of a line means it repeats `n` times. -- 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 an empty table for a text-only (no attributes) expectation. -- Use screen:set_default_attr_ids() to define attributes for many -- expect() calls. -- extmarks: Expected win_extmarks accumulated for the grids. For each grid, @@ -344,8 +345,11 @@ function Screen:expect(expected, attr_ids, ...) 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 @@ -1252,7 +1256,7 @@ 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) @@ -1312,12 +1316,15 @@ function Screen:get_snapshot(attrs, ignore) 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 @@ -1328,7 +1335,7 @@ 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) @@ -1415,6 +1422,8 @@ function Screen:_print_snapshot(attrs, ignore) table.insert(attrstrs, " "..keyval.." = "..dict..";") end attrstr = (", attr_ids={\n"..table.concat(attrstrs, "\n").."\n}") + elseif isempty(attrs) then + attrstr = ', attr_ids={}' end local result = 'screen:expect{grid=[[\n' .. kwargs.grid .. '\n]]' .. attrstr @@ -1430,6 +1439,7 @@ end function Screen:print_snapshot(attrs, ignore) print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n') + io.stdout:flush() end function Screen:_insert_hl_id(attr_state, hl_id) From ea748157e1580acf2a262ad38e0b71222feed665 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 18 Dec 2023 10:15:23 +0800 Subject: [PATCH 3/4] fix(options): setting 'scroll' with resized grid --- src/nvim/option.c | 7 +++---- test/functional/ui/multigrid_spec.lua | 6 ++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/nvim/option.c b/src/nvim/option.c index 44a4ec2843..d5a5b6c3dd 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2626,8 +2626,7 @@ static const char *set_num_option(int opt_idx, char *varp, long value, char *err } if ((curwin->w_p_scr <= 0 - || (curwin->w_p_scr > curwin->w_height - && curwin->w_height > 0)) + || (curwin->w_p_scr > curwin->w_height_inner && curwin->w_height_inner > 0)) && full_screen) { if (pp == &(curwin->w_p_scr)) { if (curwin->w_p_scr != 0) { @@ -2637,8 +2636,8 @@ static const char *set_num_option(int opt_idx, char *varp, long value, char *err } else if (curwin->w_p_scr <= 0) { // If 'scroll' became invalid because of a side effect silently adjust it. curwin->w_p_scr = 1; - } else { // curwin->w_p_scr > curwin->w_height - curwin->w_p_scr = curwin->w_height; + } else { // curwin->w_p_scr > curwin->w_height_inner + curwin->w_p_scr = curwin->w_height_inner; } } if ((p_sj < -100 || p_sj >= Rows) && full_screen) { diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index d755bcb76a..26494968b4 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -886,6 +886,12 @@ describe('ext_multigrid', function() eq(20, win_info.height) end) + it("'scroll' option works properly", function() + eq(10, meths.get_option_value('scroll', { win = 0 })) + meths.set_option_value('scroll', 15, { win = 0 }) + eq(15, meths.get_option_value('scroll', { win = 0 })) + end) + it('gets written till grid width', function() insert(('a'):rep(60).."\n") screen:expect{grid=[[ From c6d127f3a4a7f754e69ded315c5c137f9e44beed Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 20 Dec 2023 21:53:30 +0800 Subject: [PATCH 4/4] ci(release): create version tag after "stable" tag --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53110461c8..5bb638d9b8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -200,10 +200,10 @@ jobs: DEBUG: api run: | envsubst < "$GITHUB_WORKSPACE/.github/workflows/notes.md" > "$RUNNER_TEMP/notes.md" - gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos/* nvim-linux64/* appimage/* nvim-win64/* if [ "$TAG_NAME" != "nightly" ]; then gh release create stable $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos/* nvim-linux64/* appimage/* nvim-win64/* fi + gh release create $TAG_NAME $PRERELEASE --notes-file "$RUNNER_TEMP/notes.md" --title "$SUBJECT" --target $GITHUB_SHA nvim-macos/* nvim-linux64/* appimage/* nvim-win64/* publish-winget: needs: publish