feat(cmdwin): implement cmdwin as a normal buf+win

Problem:

cmdwin (the `:q` cmdline buffer) has various limitations which require
special-casing all over the codebase.

Besides complicating the code, it also breaks async plugins if they try
to create buffers/windows after some work is done, if the user happens
to open cmdwin at the wrong the moment:

    Lua callback: …/guh.nvim/lua/guh/util.lua:531:
    E11: Invalid in command-line window; <CR> executes, CTRL-C quits
    stack traceback:
        [C]: in function 'nvim_buf_delete'
        …/guh.nvim/lua/guh/util.lua:531: in function <…/guh.nvim/lua/guh/util.lua:526>

Solution:

Just say no to "inception". Reimplement cmdwin as a normal buffer+window.

All of the cmdwin contortions (in both core, and innocent plugins) exist
literally only to support "inception": recursive
cmdwin-in-cmdline-things, like `<c-r>=`, `/`, search-during-substitute,
`:input()`, etc. So we just won't support that (though I have
a potential plan for that later, which I call "modal parking lot").

The benefit is that plugins, and core, no longer have to care about
cmdwin.

BONUS:
- mouse-drag on vertical separators works (it only worked for
  horizontal/statusline before)
- inccommand-in-cmdwin now works correctly, for free (thus don't need
  #40077).

POTENTIAL FOLLOWUPS
- Drop `CHECK_CMDWIN` ("E11: Invalid in command-line window"), allow chaos.
- Unify `BUFLOCK_OK` / `LOCK_OK` ?

DESIGN:
- Eliminate lots of C globals, `EX_CMDWIN`, etc.
- `text_locked()` no longer reports true for cmdwin.
- cmdwin = a normal window with 'winfixbuf', 'bufhidden=wipe',
  'buftype=nofile'. Invariants come from those options rather than
  special cases throughout the codebase.
- `nv_record` for q:/q//q? calls Lua
  `nlua_call_vimfn("vim._core.cmdwin", …)`. No `K_CMDWIN`
  / cmdline-reader detour.
- `cedit_key` (`c_CTRL-F`) schedules a deferred event that calls
  `vim._core.cmdwin.open(type, content, pos)` and returns `Ctrl_C` so
  the in-flight cmdline cancels. Reader state is not serialized; instead
  the captured `(type, line, col)` is replayed via
  `nvim_feedkeys(type..line.."<CR>", "nt", …)` after user confirms.
- On confirm/cancel: `<CR>` / `<C-C>` calls into Lua which closes the
  window and re-feeds the cmdline.

BREAKING CHANGES:
- Expression-register cmdline (`<C-R>=` from insert-mode) no longer
  supports cmdwin. Same applies to `input()` / `inputlist()` (already
  covered by `text_locked`).
- Usage of cmdwin in macros/mappings will probably break (assuming they
  ever worked).
This commit is contained in:
Justin M. Keyes committed 2026-06-25 18:36:24 +02:00
1 parent 122be61ed2
commit b2bf7bcfb1
67 files changed
+1005 -1645

No files matched your search

+17 -7
View File
@@ -609,9 +609,6 @@ nvim_create_buf({listed}, {scratch}) *nvim_create_buf()*
Return: ~
(`integer`) Buffer id, or 0 on error
See also: ~
• buf_open_scratch
nvim_del_current_line() *nvim_del_current_line()*
Deletes the current line.
@@ -1489,7 +1486,7 @@ nvim_set_current_buf({buf}) *nvim_set_current_buf()*
Sets the current window's buffer to `buf`.
Attributes: ~
not allowed when |textlock| is active or in the |cmdwin|
not allowed when |textlock| is active
Since: 0.1.0
Parameters: ~
@@ -1518,7 +1515,7 @@ nvim_set_current_tabpage({tabpage}) *nvim_set_current_tabpage()*
Sets the current tabpage.
Attributes: ~
not allowed when |textlock| is active or in the |cmdwin|
not allowed when |textlock| is active
Since: 0.1.0
Parameters: ~
@@ -1528,7 +1525,7 @@ nvim_set_current_win({win}) *nvim_set_current_win()*
Navigates to the given window (and tabpage, implicitly).
Attributes: ~
not allowed when |textlock| is active or in the |cmdwin|
not allowed when |textlock| is active
Since: 0.1.0
Parameters: ~
@@ -1711,6 +1708,19 @@ nvim__chan_set_detach({detach}) *nvim__chan_set_detach()*
Parameters: ~
• {detach} (`boolean`) New detach value for the channel.
nvim__cmdwin_set({type}, {buf}) *nvim__cmdwin_set()*
WARNING: This feature is experimental/unstable.
Records the cmdwin scratchbuf and type, or clears both when type="" /
buf=0. Internal use only.
Attributes: ~
Since: 0.12.0
Parameters: ~
• {type} (`string`) ':', '/', '?' (first char only); empty to clear.
• {buf} (`integer`) cmdwin buffer id, or 0 to clear.
nvim__complete_set({index}, {opts}) *nvim__complete_set()*
WARNING: This feature is experimental/unstable.
@@ -2493,7 +2503,7 @@ nvim_buf_delete({buf}, {opts}) *nvim_buf_delete()*
<
Attributes: ~
not allowed when |textlock| is active or in the |cmdwin|
not allowed when |textlock| is active
Since: 0.5.0
Parameters: ~
+37 -47
View File
@@ -1188,72 +1188,65 @@ Also see |`=|.
==============================================================================
7. Command-line window *cmdline-window* *cmdwin*
*command-line-window*
In the command-line window the command line can be edited just like editing
text in any window. It is a special kind of window, because you cannot leave
it in a normal way.
The command-line window ("cmdwin") is a buffer+window in which the command
line can be edited.
OPEN *c_CTRL-F* *q:* *q/* *q?*
There are two ways to open the command-line window:
1. From Command-line mode, use the key specified with the 'cedit' option.
1. From Command-line mode, use <C-F> (or the 'cedit' key).
- Not supported from the expr-register cmdline (|c_CTRL-R_=| |i_CTRL-R_=|).
2. From Normal mode, use the "q:", "q/" or "q?" command.
This starts editing an Ex command-line ("q:") or search string ("q/" or
"q?"). Note that this is not possible while recording is in progress (the
"q" stops recording then).
When the window opens it is filled with the command-line history. The last
line contains the command as typed so far. The left column will show a
character that indicates the type of command-line being edited, see
|cmdwin-char|.
When the window opens it is filled with the command-line history. The editor
opens in Normal mode. The last line contains the command as typed so far. The
|cmdwin-char| is shown in 'statuscolumn', indicating the type of command-line.
The window height is decided by 'cmdwinheight' (if there is room). The window
is full width and is positioned just above the command-line.
Vim will be in Normal mode when the editor is opened.
*E1292*
Once a command-line window is open it is not possible to open another one.
The height of the window is specified with 'cmdwinheight' (or smaller if there
is no room). The window is always full width and is positioned just above the
command-line.
Only one command-line window can be open at a time.
EDIT
You can now use commands to move around and edit the text in the window. Both
in Normal mode and Insert mode.
You can use any commands to move around and edit the text in the window, both
in Normal and Insert mode.
It is possible to use ":", "/" and other commands that use the command-line,
but it's not possible to open another command-line window then. There is no
but it's not possible to open another cmdwin from there. There is no
nesting.
*E11* *E1188*
The command-line window is not a normal window. It is not possible to move to
another window or edit another buffer. All commands that would do this are
disabled in the command-line window. Of course it _is_ possible to execute
any command that you entered in the command-line window. Other text edits are
discarded when closing the window.
*E11*
|CTRL-W| navigation/split commands and some operations (e.g. |:terminal|) emit
E11. But mouse clicks may focus other windows. The cmdwin buffer is pinned by
'winfixbuf', so the window cannot switch to a different buffer.
CLOSE *E199*
CLOSE
There are several ways to leave the command-line window:
<CR> Execute the command-line under the cursor. Works both in
Insert and in Normal mode.
CTRL-C Continue in Command-line mode. The command-line under the
cursor is used as the command-line. Works both in Insert and
in Normal mode. There is no redraw, thus the window will
remain visible.
cursor is pre-filled in the command-line. Works both in
Insert and in Normal mode.
:quit Discard the command line and go back to Normal mode.
":close", CTRL-W c, ":exit", ":xit" and CTRL-\ CTRL-N also
work.
:qall Quit Vim, unless there are changes in some buffer.
:qall! Quit Vim, discarding changes to any buffer.
:qall Quit Nvim, unless there are changes in some buffer.
:qall! Quit Nvim, discarding changes to any buffer.
Once the command-line window is closed the old window sizes are restored. The
executed command applies to the window and buffer where the command-line was
started from. This works as if the command-line window was not there, except
that there will be an extra screen redraw.
The buffer used for the command-line window is deleted. Any changes to lines
other than the one that is executed with <CR> are lost.
When the cmdwin closes, focus returns to the window where the command-line
was started from (if possible). The cmdwin scratch buffer is destroyed
(`bufhidden=wipe`). Any text edits other than the line executed by
<CR> are lost.
If you would like to execute the command under the cursor and then have the
command-line window open again, you may find this mapping useful: >
@@ -1263,16 +1256,15 @@ command-line window open again, you may find this mapping useful: >
VARIOUS
The command-line window cannot be used when there already is a command-line
window (no nesting).
Some options are set when the command-line window is opened:
'filetype' "vim", when editing an Ex command-line; this starts Vim syntax
highlighting if it was enabled
'rightleft' off
'modifiable' on
Buffer and window options set on cmdwin open:
'bufhidden' "wipe"
'buflisted' off
'buftype' "nofile"
'filetype' "vim" (only for ":" type)
'foldenable' off
'statuscolumn' shows the |cmdwin-char|
'swapfile' off
'winfixbuf' on
It is allowed to write the buffer contents to a file. This is an easy way to
save the command-line history and read it back later.
@@ -1289,10 +1281,8 @@ If you don't want these mappings, disable them with: >
au CmdwinEnter [:>] nunmap <buffer> <Tab>
You could put these lines in your vimrc file.
While in the command-line window you cannot use the mouse to put the cursor in
another window, or drag statuslines of other windows. You can drag the
statusline of the command-line window itself and the statusline above it.
Thus you can resize the command-line window, but not others.
The mouse works as in any window: clicks focus other windows, and statuslines
and vertical separators can be dragged to resize.
The |getcmdwintype()| function returns the type of the command-line being
edited as described in |cmdwin-char|.
+13 -1
View File
@@ -81,8 +81,12 @@ DIAGNOSTICS
EDITOR
• On Windows, the |trust| db now stores paths with "/" slashes. This means the
trust store will be reset.
trust store will be reset (one time).
• `stdpath("log")` moved to `stdpath("state")/logs`.
• |cmdwin| (|q:|, |q/|, |q?|, |c_CTRL-F|):
• Only supports one "cmdline level", not "infinite recursion".
• Expr-register (|i_CTRL-R_=|, |c_CTRL-R_=|) no longer supports opening
cmdwin via |c_CTRL-F|.
EVENTS
@@ -164,6 +168,14 @@ EDITOR
• |:command-completion-customlist| can return a list of dictionaries with
kind/menu/info/abbr for the popup menu.
• |cmdwin| (|q:|, |q/|, |q?|, |c_CTRL-F|) is implemented as a "normal"
buffer+window instead of a nested-state modal loop:
• 'inccommand' works in cmdwin!
• API calls (e.g. |nvim_buf_delete()|) that previously failed with
"E11: Invalid in command-line window" while cmdwin was open, now work
normally. Async plugins no longer need special |CmdwinLeave| workarounds.
• Removed most cmdwin-specific |E11| guards, except for window navigation.
• The |cmdwin-char| is shown via 'statuscolumn'.
• |gf| and |<cfile>| support `file://…` URIs.
• |:log| opens log files.
• |ZR| restarts Nvim (|:restart|).
+4
View File
@@ -304,6 +304,9 @@ Command-line:
- (Experimental) *g:Nvim_color_cmdline* Command-line (|:|) is colored by
callback defined in `g:Nvim_color_cmdline` (this callback is for testing
only, and will be removed in the future).
- |cmdwin| (|q:|, |q/|, |q?|, |c_CTRL-F|) is a "normal" buffer+window, instead
of a nested modal loop. API and Lua callbacks can run without |E11| while it
is open. The |cmdwin-char| is shown via 'statuscolumn'.
Commands:
- |:checkhealth|
@@ -761,6 +764,7 @@ Compile-time features:
- X11 integration (see |x11-selection|)
Editor:
- |c_CTRL-F| cannot enter |cmdwin| from the |expr-register| prompt.
- *cscope* support was removed in favour of plugin-based solutions such as:
https://github.com/dhananjaylatkar/cscope_maps.nvim
- *popup-window* : Use |floating-windows| instead.
+168
View File
@@ -0,0 +1,168 @@
--- @brief Command-line window (q:, q/, q?, c_CTRL-F).
---
--- Implements cmdwin as a normal window+buffer, instead of the legacy nested `state_enter` loop.
--- - On confirm, curline is fed back through the cmdline via |nvim_feedkeys()|.
--- - On cancel, curline is pre-filled in the ":" cmdline.
local M = {}
--- @class vim._core.cmdwin.State
--- @field type string ':', '/', '?'
--- @field win integer cmdwin window id
--- @field buf integer cmdwin buffer id
--- @field caller_win integer Window to return-to on close
--- @type vim._core.cmdwin.State?
local state = nil
local cmdwin_types = { [':'] = true, ['/'] = true, ['?'] = true }
--- Fills the cmdwin buffer with the cmdline history.
local function fill_history(buf, type)
local histname = type == ':' and 'cmd' or (type == '/' or type == '?') and 'search' or nil
assert(histname, 'cmdwin: unknown type: ' .. tostring(type))
local n = vim.fn.histnr(histname)
if n <= 0 then -- May be -1 if history is empty.
return
end
local lines = {} --- @type string[]
for i = 1, n do
local h = vim.fn.histget(histname, i)
if h ~= '' then
-- One cmdwin line = one cmdline. Entry may have embedded newlines (e.g. via feedkeys or :execute).
lines[#lines + 1] = (h:gsub('\n', '\0'))
end
end
if #lines > 0 then
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
end
end
--- Open the command-line window.
---
--- @param type? string ':', '/', '?'. Default ':'.
--- @param init_line? string Pre-fill the last line (the "live" cmdline).
--- @param init_col? integer 1-based cursor column in the last line.
function M.open(type, init_line, init_col)
type = type or ':'
assert(cmdwin_types[type], 'cmdwin: unknown type: ' .. tostring(type))
if state ~= nil then
vim.api.nvim_echo(
{ { 'E1292: Command-line window is already open', 'ErrorMsg' } },
true,
{ err = true }
)
return
end
local caller = vim.api.nvim_get_current_win()
-- Split a horizontal window at the bottom, sized by 'cmdwinheight'.
local ok, err = pcall(function()
vim.cmd(('botright %dnew'):format(vim.o.cmdwinheight))
end)
if not ok then
vim.api.nvim_echo({ { tostring(err), 'ErrorMsg' } }, true, { err = true })
return
end
local win = vim.api.nvim_get_current_win()
local buf = vim.api.nvim_get_current_buf()
vim.bo[buf].buftype = 'nofile'
vim.bo[buf].bufhidden = 'wipe'
vim.bo[buf].swapfile = false
vim.bo[buf].buflisted = false
vim.wo[win][0].winfixbuf = true
vim.wo[win][0].foldenable = false
-- Show cmdwin-char via 'statuscolumn'.
vim.wo[win][0].statuscolumn = '%#NonText#' .. type .. ' '
fill_history(buf, type)
-- Append the in-flight cmdline (or empty placeholder) as the last line.
vim.api.nvim_buf_set_lines(buf, -1, -1, false, { init_line or '' })
local last = vim.api.nvim_buf_line_count(buf)
vim.api.nvim_win_set_cursor(win, { last, math.max(0, (init_col or 1) - 1) })
pcall(vim.api.nvim_buf_set_name, buf, '[Command Line]')
if type == ':' then
vim.bo[buf].filetype = 'vim'
end
vim.api.nvim__cmdwin_set(type, buf) -- Update the C-side globals.
state = {
type = type,
win = win,
buf = buf,
caller_win = caller,
}
-- Buffer-local mappings.
vim.keymap.set(
{ 'n', 'i' },
'<CR>',
[[<C-\><C-N><Cmd>lua require'vim._core.cmdwin'.confirm()<CR>]],
{ buffer = buf, silent = true, desc = 'cmdwin: execute' }
)
vim.keymap.set(
{ 'n', 'i', 'x' },
'<C-C>',
[[<C-\><C-N><Cmd>lua require'vim._core.cmdwin'.cancel()<CR>]],
{ buffer = buf, silent = true, desc = 'cmdwin: cancel' }
)
-- Clean up if the window is closed by other means (`:q`, `:close`, etc.).
vim.api.nvim_create_autocmd({ 'WinClosed' }, {
buffer = buf,
once = true,
callback = function()
if state ~= nil then
M._cleanup()
end
end,
})
vim.api.nvim_exec_autocmds('CmdwinEnter', { pattern = type, modeline = false })
end
--- @private
function M._cleanup()
if state == nil then
return
end
local s = state
state = nil
pcall(vim.api.nvim__cmdwin_set, '', 0) -- Clear the C-side globals.
pcall(vim.api.nvim_exec_autocmds, 'CmdwinLeave', { pattern = s.type, modeline = false })
if vim.api.nvim_win_is_valid(s.win) then
pcall(vim.api.nvim_win_close, s.win, true)
end
if vim.api.nvim_win_is_valid(s.caller_win) then
pcall(vim.api.nvim_set_current_win, s.caller_win)
end
end
local function _confirm()
if state == nil then
return
end
local line = vim.api.nvim_get_current_line()
local type = state.type
M._cleanup()
return line, type
end
--- Confirm and execute the current line as a cmdline.
function M.confirm()
local line, type = _confirm()
vim.api.nvim_feedkeys(type .. line .. vim.keycode('<CR>'), 'nt', false)
end
--- Cancel: close the cmdwin and re-enter cmdline mode with the line pre-filled (no execute).
function M.cancel()
local line, type = _confirm()
vim.api.nvim_feedkeys(type .. line, 'nt', false)
end
return M
+8 -2
View File
@@ -24,6 +24,14 @@ function vim.api.nvim__buf_debug_extmarks(buf, keys, dot) end
--- @return table<string,any>
function vim.api.nvim__buf_stats(buf) end
--- WARNING: This feature is experimental/unstable.
---
--- Records the cmdwin scratchbuf and type, or clears both when type="" / buf=0. Internal use only.
---
--- @param type string ':', '/', '?' (first char only); empty to clear.
--- @param buf integer cmdwin buffer id, or 0 to clear.
function vim.api.nvim__cmdwin_set(type, buf) end
--- WARNING: This feature is experimental/unstable.
---
--- Sets info for the completion item at the given index. If the info text was shown in a window,
@@ -967,12 +975,10 @@ function vim.api.nvim_create_autocmd(event, opts) end
--- Creates a new, empty, unnamed buffer.
---
--- @see buf_open_scratch
--- @param listed boolean Sets 'buflisted'
--- @param scratch boolean Creates a "throwaway" `scratch-buffer` for temporary work
--- (always 'nomodified'). Also sets 'nomodeline' on the buffer.
--- @return integer # Buffer id, or 0 on error
---
function vim.api.nvim_create_buf(listed, scratch) end
--- Creates a new namespace or gets an existing one. [namespace]()
-2
View File
@@ -26,7 +26,6 @@
--- @field noexport true?
--- @field remote_only true?
--- @field lua_only true?
--- @field textlock_allow_cmdwin true?
--- @field textlock true?
--- @field remote_impl true?
--- @field compositor_impl true?
@@ -198,7 +197,6 @@ local fattr = (
+ attr('FUNC_API_NOEXPORT', 'noexport')
+ attr('FUNC_API_REMOTE_ONLY', 'remote_only')
+ attr('FUNC_API_LUA_ONLY', 'lua_only')
+ attr('FUNC_API_TEXTLOCK_ALLOW_CMDWIN', 'textlock_allow_cmdwin')
+ attr('FUNC_API_TEXTLOCK', 'textlock')
+ attr('FUNC_API_REMOTE_IMPL', 'remote_impl')
+ attr('FUNC_API_COMPOSITOR_IMPL', 'compositor_impl')
-1
View File
@@ -175,7 +175,6 @@ local function process_proto(item, state)
'remote_only',
'lua_only',
'textlock',
'textlock_allow_cmdwin',
}) do
if item[a] then
cur_obj.attrs = cur_obj.attrs or {}
-12
View File
@@ -567,11 +567,6 @@ for i = 1, #functions do
output:write('\n api_set_error(error, kErrorTypeException, "%s", get_text_locked_msg());')
output:write('\n goto cleanup;')
output:write('\n }\n')
elseif fn.textlock_allow_cmdwin then
output:write('\n if (textlock != 0 || expr_map_locked()) {')
output:write('\n api_set_error(error, kErrorTypeException, "%s", e_textlock);')
output:write('\n goto cleanup;')
output:write('\n }\n')
end
-- function call
@@ -759,13 +754,6 @@ local function process_function(fn)
goto exit_0;
}
]])
elseif fn.textlock_allow_cmdwin then
write_shifted_output([[
if (textlock != 0 || expr_map_locked()) {
api_set_error(&err, kErrorTypeException, "%%s", e_textlock);
goto exit_0;
}
]])
end
local cparams = ''
+6
View File
@@ -116,6 +116,12 @@ for _, cmd in ipairs(defs) do
string.format('ex_cmds.lua:%s: Missing preview_func\n', cmd.command)
)
end
if bit.band(cmd.flags, flags.BUFLOCK_OK) == flags.BUFLOCK_OK then
assert(
bit.band(cmd.flags, flags.LOCK_OK) == flags.LOCK_OK,
string.format('ex_cmds.lua:%s: BUFLOCK_OK implies LOCK_OK\n', cmd.command)
)
end
local enumname = cmd.enum or ('CMD_' .. cmd.command)
local byte_cmd = cmd.command:sub(1, 1):byte()
if byte_a <= byte_cmd and byte_cmd <= byte_z then
+1 -2
View File
@@ -981,8 +981,7 @@ local function render_fun(fun, classes, cfg)
table.insert(ret, '\n Attributes: ~\n')
for _, attr in ipairs(fun.attrs) do
local attr_str = ({
textlock = 'not allowed when |textlock| is active or in the |cmdwin|',
textlock_allow_cmdwin = 'not allowed when |textlock| is active',
textlock = 'not allowed when |textlock| is active',
fast = '|api-fast|',
remote_only = '|RPC| only',
lua_only = 'Lua |vim.api| only',
+2 -2
View File
@@ -325,7 +325,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buf, Integer start, Integer
Boolean strict_indexing, ArrayOf(String) replacement, Arena *arena,
Error *err)
FUNC_API_SINCE(1)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
buf_T *b = api_buf_ensure_loaded(buf, err);
@@ -485,7 +485,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buf, Integer start_row, Integ
Integer end_row, Integer end_col, ArrayOf(String) replacement, Arena *arena,
Error *err)
FUNC_API_SINCE(7)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
MAXSIZE_TEMP_ARRAY(scratch, 1);
if (replacement.size == 0) {
+1 -5
View File
@@ -200,17 +200,13 @@ Boolean nvim_tabpage_is_valid(Tabpage tabpage)
/// @param[out] err Error details, if any
/// @return |tab-ID| of the new tabpage
Tabpage nvim_open_tabpage(Buffer buf, Boolean enter, Dict(tabpage_config) *config, Error *err)
FUNC_API_SINCE(14) FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_SINCE(14) FUNC_API_TEXTLOCK
{
#define HAS_KEY_X(d, key) HAS_KEY(d, tabpage_config, key)
buf_T *b = find_buffer_by_handle(buf, err);
if (b == NULL) {
return 0;
}
if ((cmdwin_type != 0 && enter) || b == cmdwin_buf) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return 0;
}
int after = -1; // Default to after current tabpage
if (HAS_KEY_X(config, after)) {
+29 -9
View File
@@ -720,7 +720,7 @@ String nvim_get_current_line(Arena *arena, Error *err)
/// @param[out] err Error details, if any
void nvim_set_current_line(String line, Arena *arena, Error *err)
FUNC_API_SINCE(1)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, arena, err);
}
@@ -730,7 +730,7 @@ void nvim_set_current_line(String line, Arena *arena, Error *err)
/// @param[out] err Error details, if any
void nvim_del_current_line(Arena *arena, Error *err)
FUNC_API_SINCE(1)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, arena, err);
}
@@ -1042,8 +1042,6 @@ void nvim_set_current_win(Window win, Error *err)
/// (always 'nomodified'). Also sets 'nomodeline' on the buffer.
/// @param[out] err Error details, if any
/// @return Buffer id, or 0 on error
///
/// @see buf_open_scratch
Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
FUNC_API_SINCE(6)
{
@@ -1153,15 +1151,16 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
/// @return Channel id, or 0 on error
Integer nvim_open_term(Buffer buf, Dict(open_term) *opts, Error *err)
FUNC_API_SINCE(7)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
buf_T *b = api_buf_ensure_loaded(buf, err);
if (!b) {
return 0;
}
if (b == cmdwin_buf) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
// Refuse to repurpose the cmdwin buffer.
if (bt_cmdwin(b)) {
api_set_error(err, kErrorTypeException, "%s", _(e_cmdwin));
return 0;
}
@@ -1376,7 +1375,7 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
Boolean nvim_paste(uint64_t channel_id, String data, Boolean crlf, Integer phase, Arena *arena,
Error *err)
FUNC_API_SINCE(6)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
static bool cancelled = false;
@@ -1438,7 +1437,7 @@ theend:
void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, Arena *arena,
Error *err)
FUNC_API_SINCE(6)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
yankreg_T reg[1] = { 0 };
VALIDATE_S((prepare_yankreg_from_object(reg, type, lines.size)), "type", type.data, {
@@ -1775,6 +1774,27 @@ void nvim__chan_set_detach(uint64_t channel_id, Boolean detach, Error *err)
chan->detach = (bool)detach;
}
/// Records the cmdwin scratchbuf and type, or clears both when type="" / buf=0. Internal use only.
///
/// @param type ':', '/', '?' (first char only); empty to clear.
/// @param buf cmdwin buffer id, or 0 to clear.
/// @param[out] err Error details, if any.
void nvim__cmdwin_set(String type, Buffer buf, Error *err)
FUNC_API_SINCE(14)
{
if (type.size == 0 || buf == 0) {
cmdwin_type = 0;
cmdwin_buf = NULL;
return;
}
buf_T *b = find_buffer_by_handle(buf, err);
if (ERROR_SET(err)) {
return;
}
cmdwin_type = (uint8_t)type.data[0];
cmdwin_buf = b;
}
/// Gets information about a channel.
///
/// See |nvim_list_uis()| for an example of how to get channel info.
+1 -10
View File
@@ -201,16 +201,12 @@
///
/// @return |window-ID|, or 0 on error
Window nvim_open_win(Buffer buf, Boolean enter, Dict(win_config) *config, Error *err)
FUNC_API_SINCE(6) FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_SINCE(6) FUNC_API_TEXTLOCK
{
buf_T *b = find_buffer_by_handle(buf, err);
if (!b) {
return 0;
}
if ((cmdwin_type != 0 && enter) || b == cmdwin_buf) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return 0;
}
bool is_split = HAS_KEY_X(config, split) || HAS_KEY_X(config, vertical);
WinConfig fconfig = WIN_CONFIG_INIT;
@@ -411,11 +407,6 @@ static bool win_can_move_tp(win_T *wp, tabpage_T *tp, Error *err)
api_set_error(err, kErrorTypeException, "Cannot move autocmd window to another tabpage");
return false;
}
// Can't move the cmdwin or its old curwin to a different tabpage.
if (wp == cmdwin_win || wp == cmdwin_old_curwin) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return false;
}
return true;
}
+7 -9
View File
@@ -54,7 +54,7 @@ Buffer nvim_win_get_buf(Window win, Error *err)
/// @param[out] err Error details, if any
void nvim_win_set_buf(Window win, Buffer buf, Error *err)
FUNC_API_SINCE(5)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
win_T *w = find_window_by_handle(win, err);
buf_T *b = find_buffer_by_handle(buf, err);
@@ -62,10 +62,8 @@ void nvim_win_set_buf(Window win, Buffer buf, Error *err)
return;
}
if (w == cmdwin_win || w == cmdwin_old_curwin || b == cmdwin_buf) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return;
}
// 'winfixbuf' on the cmdwin window prevents replacing its buffer; no
// separate cmdwin guard needed.
win_set_buf(w, b, err);
}
@@ -352,10 +350,10 @@ Boolean nvim_win_is_valid(Window win)
/// @param[out] err Error details, if any
void nvim_win_hide(Window win, Error *err)
FUNC_API_SINCE(7)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
win_T *w = find_window_by_handle(win, err);
if (!w || !can_close_in_cmdwin(w, err)) {
if (!w) {
return;
}
@@ -381,10 +379,10 @@ void nvim_win_hide(Window win, Error *err)
/// @param[out] err Error details, if any
void nvim_win_close(Window win, Boolean force, Error *err)
FUNC_API_SINCE(6)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
FUNC_API_TEXTLOCK
{
win_T *w = find_window_by_handle(win, err);
if (!w || !can_close_in_cmdwin(w, err)) {
if (!w) {
return;
}
-4
View File
@@ -1064,10 +1064,6 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
assert(firstwin != NULL); // satisfy coverity
if (cmdwin_type != 0) {
emsg(_(e_cmdwin));
return;
}
if (ARGCOUNT <= 0) {
// Don't give an error message. We don't want it when the ":all"
// command is in the .vimrc.
+8 -29
View File
@@ -3631,6 +3631,13 @@ bool bt_prompt(buf_T *buf)
return buf != NULL && buf->b_p_bt[0] == 'p';
}
/// @return true if "buf" is the |cmdwin| scratch buffer.
bool bt_cmdwin(const buf_T *buf)
FUNC_ATTR_PURE
{
return buf != NULL && buf == cmdwin_buf;
}
/// Open a window for a number of buffers.
void ex_buffer_all(exarg_T *eap)
{
@@ -4092,7 +4099,7 @@ char *buf_spname(buf_T *buf)
if (buf->b_fname != NULL) {
return buf->b_fname;
}
if (buf == cmdwin_buf) {
if (bt_cmdwin(buf)) {
return _("[Command Line]");
}
if (bt_prompt(buf)) {
@@ -4203,34 +4210,6 @@ void wipe_buffer(buf_T *buf, bool aucmd)
}
}
/// Creates or switches to a scratch buffer. :h special-buffers
/// Scratch buffer is:
/// - buftype=nofile bufhidden=hide noswapfile
/// - Always considered 'nomodified'
///
/// @param bufnr Buffer to switch to, or 0 to create a new buffer.
/// @param bufname Buffer name, or NULL.
///
/// @see curbufIsChanged()
///
/// @return FAIL for failure, OK otherwise
int buf_open_scratch(handle_T bufnr, char *bufname)
{
if (do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL) == FAIL) {
return FAIL;
}
if (bufname != NULL) {
apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
setfname(curbuf, bufname, NULL, true);
apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
}
set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
set_option_value_give_err(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
set_option_value_give_err(kOptSwapfile, BOOLEAN_OPTVAL(false), OPT_LOCAL);
RESET_BINDING(curwin);
return OK;
}
bool buf_is_empty(buf_T *buf)
{
return buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, 1) == NUL;
-22
View File
@@ -262,25 +262,3 @@ void end_batch_changes(void)
set_clipboard(NUL, get_y_previous());
}
}
int save_batch_count(void)
{
int save_count = batch_change_count;
batch_change_count = 0;
clipboard_delay_update = false;
if (clipboard_needs_update) {
clipboard_needs_update = false;
// unnamed ("implicit" clipboard)
set_clipboard(NUL, get_y_previous());
}
return save_count;
}
void restore_batch_count(int save_count)
{
assert(batch_change_count == 0);
batch_change_count = save_count;
if (batch_change_count > 0) {
clipboard_delay_update = true;
}
}
+1 -9
View File
@@ -1401,7 +1401,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, b
statuscol.sattrs = wlv.sattrs;
statuscol.lnum = lnum;
statuscol.foldinfo = foldinfo;
statuscol.width = win_col_off(wp) - (wp == cmdwin_win);
statuscol.width = win_col_off(wp);
statuscol.sign_cul_id = use_cursor_line_highlight(wp, lnum) ? wlv.sign_cul_attr : 0;
} else if (wlv.sign_cul_attr > 0) {
wlv.sign_cul_attr = use_cursor_line_highlight(wp, lnum) ? syn_id2attr(wlv.sign_cul_attr) : 0;
@@ -1758,14 +1758,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, b
assert(wlv.off == 0);
if (wp == cmdwin_win) {
// Draw the cmdline character.
draw_col_fill(&wlv,
schar_from_ascii(wlv.row == wlv.startrow ? cmdwin_type : ' '),
1,
wlv.row == wlv.startrow ? win_hl_attr(wp, HLF_AT) : 0);
}
if (wlv.filler_todo > 0) {
// nvim_buf_set_extmark: virt_lines_overflow
int virt_rows_todo = wlv.filler_todo - (wlv.filler_lines - wlv.n_virt_lines);
-12
View File
@@ -740,13 +740,6 @@ static int insert_handle_key(InsertState *s)
FALLTHROUGH;
case Ctrl_C: // End input mode
if (s->c == Ctrl_C && cmdwin_type != 0) {
// Close the cmdline window.
cmdwin_result = K_IGNORE;
got_int = false; // don't stop executing autocommands et al
s->nomove = true;
return 0; // exit insert mode
}
if (s->c == Ctrl_C && bt_prompt(curbuf)) {
if (invoke_prompt_interrupt()) {
if (!bt_prompt(curbuf)) {
@@ -1107,11 +1100,6 @@ static int insert_handle_key(InsertState *s)
}
break;
}
if (cmdwin_type != 0) {
// Execute the command in the cmdline window.
cmdwin_result = CAR;
return 0;
}
if ((mod_mask & MOD_MASK_SHIFT) == 0 && bt_prompt(curbuf)) {
prompt_invoke_callback();
if (!bt_prompt(curbuf)) {
+1 -1
View File
@@ -584,7 +584,7 @@ static dict_T *get_buffer_info(buf_T *buf)
tv_dict_add_nr(dict, S_LEN("changed"), bufIsChanged(buf));
tv_dict_add_nr(dict, S_LEN("changedtick"), buf_get_changedtick(buf));
tv_dict_add_nr(dict, S_LEN("hidden"), buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
tv_dict_add_nr(dict, S_LEN("command"), buf == cmdwin_buf);
tv_dict_add_nr(dict, S_LEN("command"), bt_cmdwin(buf));
// Get a reference to buffer variables
tv_dict_add_dict(dict, S_LEN("variables"), buf->b_vars);
+5
View File
@@ -3602,6 +3602,11 @@ void f_jobstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
shell_free_argv(argv);
return;
}
if (bt_cmdwin(curbuf)) {
emsg(_(e_cmdwin));
shell_free_argv(argv);
return;
}
if (curbuf->b_changed) {
emsg(_("jobstart(...,{term=true}) requires unmodified buffer"));
shell_free_argv(argv);
+1 -1
View File
@@ -776,7 +776,7 @@ void f_win_gettype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_string = xstrdup("preview");
} else if (wp->w_floating) {
rettv->vval.v_string = xstrdup("popup");
} else if (wp == cmdwin_win) {
} else if (bt_cmdwin(wp->w_buffer)) {
rettv->vval.v_string = xstrdup("command");
} else if (bt_quickfix(wp->w_buffer)) {
rettv->vval.v_string = xstrdup((wp->w_llist_ref != NULL ? "loclist" : "quickfix"));
-18
View File
@@ -2553,20 +2553,6 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
// If the current buffer was empty and has no file name, curbuf
// is returned by buflist_new(), nothing to do here.
if (buf != curbuf) {
// Should only be possible to get here if the cmdwin is closed, or
// if it's opening and its buffer hasn't been set yet (the new
// buffer is for it).
assert(cmdwin_buf == NULL);
const int save_cmdwin_type = cmdwin_type;
win_T *const save_cmdwin_win = cmdwin_win;
win_T *const save_cmdwin_old_curwin = cmdwin_old_curwin;
// BufLeave applies to the old buffer.
cmdwin_type = 0;
cmdwin_win = NULL;
cmdwin_old_curwin = NULL;
// Be careful: The autocommands may delete any buffer and change
// the current buffer.
// - If the buffer we are going to edit is deleted, give up.
@@ -2582,10 +2568,6 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
set_bufref(&au_new_curbuf, buf);
apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
cmdwin_type = save_cmdwin_type;
cmdwin_win = save_cmdwin_win;
cmdwin_old_curwin = save_cmdwin_old_curwin;
if (!bufref_valid(&au_new_curbuf)) {
// New buffer has been deleted.
delbuf_msg(new_name); // Frees new_name.
+322 -309
View File
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -54,12 +54,12 @@
#define EX_BUFUNL 0x10000U // accepts unlisted buffer too
#define EX_ARGOPT 0x20000U // allow "++opt=val" argument
#define EX_SBOXOK 0x40000U // allowed in the sandbox
#define EX_CMDWIN 0x80000U // allowed in cmdline window
#define EX_BUFLOCK_OK 0x80000U // Command is allowed when curbuf is `b_ro_locked` (e.g. during
// a quickfix or diff critical section). Legacy name: EX_CMDWIN.
// Implies EX_LOCK_OK.
#define EX_MODIFY 0x100000U // forbidden in non-'modifiable' buffer
#define EX_FLAGS 0x200000U // allow flags after count in argument
#define EX_LOCK_OK 0x1000000U // command can be executed when textlock is
// set; when missing disallows editing another
// buffer when curbuf->b_ro_locked is set
#define EX_LOCK_OK 0x1000000U // Command allowed when |textlock| is set. EX_BUFLOCK_OK is per-buffer.
#define EX_KEEPSCRIPT 0x4000000U // keep sctx of where command was invoked
#define EX_PREVIEW 0x8000000U // allow incremental command preview
#define EX_ARGSPACE 0x40000000U // completion: keep spaces in arg lead
+4 -41
View File
@@ -1831,11 +1831,6 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
goto end;
}
if (!IS_USER_CMDIDX(eap->cmdidx)) {
if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) {
// Command not allowed in the command line window
errormsg = _(e_cmdwin);
goto end;
}
if (text_locked() && !(eap->argt & EX_LOCK_OK)) {
// Command not allowed when text is locked
errormsg = _(get_text_locked_msg());
@@ -1846,7 +1841,7 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview)
// Do allow ":checktime" (it is postponed).
// Do allow ":edit" (check for an argument later).
// Do allow ":file" with no arguments
if (!(eap->argt & EX_CMDWIN)
if (!(eap->argt & EX_BUFLOCK_OK)
&& eap->cmdidx != CMD_checktime
&& eap->cmdidx != CMD_edit
&& !(eap->cmdidx == CMD_file && *eap->arg == NUL)
@@ -2226,11 +2221,6 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
}
if (!IS_USER_CMDIDX(ea.cmdidx)) {
if (cmdwin_type != 0 && !(ea.argt & EX_CMDWIN)) {
// Command not allowed in the command line window
errormsg = _(e_cmdwin);
goto doend;
}
if (text_locked() && !(ea.argt & EX_LOCK_OK)) {
// Command not allowed when text is locked
errormsg = _(get_text_locked_msg());
@@ -2242,7 +2232,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
// Do allow ":checktime" (it is postponed).
// Do allow ":edit" (check for an argument later).
// Do allow ":file" with no arguments (check for an argument later).
if (!(ea.argt & EX_CMDWIN)
if (!(ea.argt & EX_BUFLOCK_OK)
&& ea.cmdidx != CMD_checktime
&& ea.cmdidx != CMD_edit
&& ea.cmdidx != CMD_file
@@ -4875,10 +4865,6 @@ bool before_quit_autocmds(win_T *wp, bool quit_all, bool forceit)
/// ":{nr}quit": quit window {nr}
static void ex_quit(exarg_T *eap)
{
if (cmdwin_type != 0) {
cmdwin_result = Ctrl_C;
return;
}
// Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
@@ -4951,13 +4937,6 @@ static void ex_cquit(exarg_T *eap)
/// Returns FAIL when quitting should be aborted.
int before_quit_all(exarg_T *eap)
{
if (cmdwin_type != 0) {
cmdwin_result = eap->forceit
? K_XF1 // open_cmdwin() takes care of this
: K_XF2;
return FAIL;
}
// Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
@@ -5221,9 +5200,7 @@ static void ex_close(exarg_T *eap)
{
win_T *win = NULL;
int winnr = 0;
if (cmdwin_type != 0) {
cmdwin_result = Ctrl_C;
} else if (!text_locked() && !curbuf_locked()) {
if (!text_locked() && !curbuf_locked()) {
if (eap->addr_count == 0) {
ex_win_close(eap->forceit, curwin, NULL);
} else {
@@ -5298,11 +5275,6 @@ void ex_win_close(int forceit, win_T *win, tabpage_T *tp)
/// ":tabclose N": close tab page N.
static void ex_tabclose(exarg_T *eap)
{
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
return;
}
if (first_tabpage->tp_next == NULL) {
emsg(_("E784: Cannot close last tab page"));
return;
@@ -5333,11 +5305,6 @@ static void ex_tabclose(exarg_T *eap)
/// ":tabonly": close all tab pages except the current one
static void ex_tabonly(exarg_T *eap)
{
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
return;
}
if (first_tabpage->tp_next == NULL) {
msg(_("Already only one tab page"), 0);
return;
@@ -5513,10 +5480,6 @@ static void ex_stop(exarg_T *eap)
/// ":exit", ":xit" and ":wq": Write file and quit the current window.
static void ex_exit(exarg_T *eap)
{
if (cmdwin_type != 0) {
cmdwin_result = Ctrl_C;
return;
}
// Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
@@ -6182,7 +6145,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
redraw_all_later(UPD_NOT_VALID);
pending_exmode_active = true;
normal_enter(false, true);
normal_enter(true);
pending_exmode_active = false;
RedrawingDisabled = save_rd;
+64 -300
View File
@@ -32,6 +32,9 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/vars.h"
#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
@@ -46,7 +49,9 @@
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/map_defs.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
@@ -226,9 +231,6 @@ static int cedit_key = -1; ///< key value of 'cedit' option
static handle_T cmdpreview_bufnr = 0;
static int cmdpreview_ns = 0;
static const char e_active_window_or_buffer_changed_or_deleted[]
= N_("E199: Active window or buffer changed or deleted");
static void trigger_cmd_autocmd(int typechar, event_T evt)
{
char typestr[2] = { (char)typechar, NUL };
@@ -1480,11 +1482,10 @@ static int command_line_execute(VimState *state, int key)
}
}
if (s->c == cedit_key || s->c == K_CMDWIN) {
// TODO(vim): why is ex_normal_busy checked here?
if ((s->c == K_CMDWIN || ex_normal_busy == 0)
&& got_int == false) {
// Open a window to edit the command line (and history).
if (s->c == cedit_key) {
// c_CTRL-F: Open cmdwin. Return Ctrl_C so the current cmdline cancels; when the user
// confirms/cancels cmdwin, it will reopen cmdline with the command pre-filled.
if (ex_normal_busy == 0 && got_int == false) {
s->c = open_cmdwin();
s->some_key_typed = true;
}
@@ -3116,9 +3117,6 @@ int check_opt_wim(void)
/// another window or buffer. True when editing the command line etc.
bool text_locked(void)
{
if (cmdwin_type != 0) {
return true;
}
if (expr_map_locked()) {
return true;
}
@@ -3134,11 +3132,7 @@ void text_locked_msg(void)
const char *get_text_locked_msg(void)
{
if (cmdwin_type != 0) {
return e_cmdwin;
} else {
return e_textlock;
}
return e_textlock;
}
/// Check for text, window or buffer locked.
@@ -3726,10 +3720,8 @@ void cmdline_screen_cleared(void)
CmdlineInfo *line = ccline.prev_ccline;
while (prev_level > 0 && line) {
if (line->level == prev_level) {
// don't redraw a cmdline already shown in the cmdline window
if (prev_level != cmdwin_level) {
line->redraw_state = kCmdRedrawAll;
}
// Always redraw (cmdwin is not special since #40312).
line->redraw_state = kCmdRedrawAll;
prev_level--;
}
line = line->prev_ccline;
@@ -4579,292 +4571,64 @@ const char *did_set_cedit(optset_T *args)
return NULL;
}
/// Open a window on the current command line and history. Allow editing in
/// the window. Returns when the window is closed.
/// Returns:
/// CR if the command is to be executed
/// Ctrl_C if it is to be abandoned
/// K_IGNORE if editing continues
static int open_cmdwin(void)
typedef struct {
int firstc;
char *content; // owned
int pos;
} CmdwinOpenArgs;
/// Deferred event: opens cmdwin after the current cmdline-reader exits. (Can't use vim.schedule,
/// where the event could fire _during typeahead_; revisit after #40380).
static void open_cmdwin_event(void **argv)
{
bufref_T old_curbuf;
bufref_T bufref;
win_T *old_curwin = curwin;
int i;
garray_T winsizes;
int save_restart_edit = restart_edit;
int save_State = State;
bool save_exmode = exmode_active;
bool save_cmdmsg_rl = cmdmsg_rl;
// Can't do this when text or buffer is locked.
// Can't do this recursively. Can't do it when typing a password.
if (text_or_buf_locked() || cmdwin_type != 0 || cmdline_star > 0) {
beep_flush();
return K_IGNORE;
}
set_bufref(&old_curbuf, curbuf);
// Save current window sizes.
win_size_save(&winsizes);
// When using completion in Insert mode with <C-R>=<C-F> one can open the
// command line window, but we don't want the popup menu then.
pum_undisplay(true);
// don't use a new tab page
cmdmod.cmod_tab = 0;
cmdmod.cmod_flags |= CMOD_NOSWAPFILE;
// Create a window for the command-line buffer.
if (win_split((int)p_cwh, WSP_BOT) == FAIL) {
beep_flush();
ga_clear(&winsizes);
return K_IGNORE;
}
// win_split() autocommands may have messed with the old window or buffer.
// Treat it as abandoning this command-line.
if (!win_valid(old_curwin) || curwin == old_curwin || !bufref_valid(&old_curbuf)
|| old_curwin->w_buffer != old_curbuf.br_buf) {
beep_flush();
ga_clear(&winsizes);
return Ctrl_C;
}
// Don't let quitting the More prompt make this fail.
got_int = false;
// Set "cmdwin_..." variables before any autocommands may mess things up.
cmdwin_type = get_cmdline_type();
cmdwin_level = ccline.level;
cmdwin_win = curwin;
cmdwin_old_curwin = old_curwin;
// Create empty command-line buffer. Be especially cautious of BufLeave
// autocommands from do_ecmd(), as cmdwin restrictions do not apply to them!
const int newbuf_status = buf_open_scratch(0, NULL);
const bool cmdwin_valid = win_valid(cmdwin_win);
if (newbuf_status == FAIL || !cmdwin_valid || curwin != cmdwin_win || !win_valid(old_curwin)
|| !bufref_valid(&old_curbuf) || old_curwin->w_buffer != old_curbuf.br_buf) {
if (newbuf_status == OK) {
set_bufref(&bufref, curbuf);
}
if (cmdwin_valid && !last_window(cmdwin_win)) {
win_close(cmdwin_win, true, false);
}
// win_close() autocommands may have already deleted the buffer.
if (newbuf_status == OK && bufref_valid(&bufref) && bufref.br_buf != curbuf) {
close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false, false, false);
}
cmdwin_type = 0;
cmdwin_level = 0;
cmdwin_win = NULL;
cmdwin_old_curwin = NULL;
beep_flush();
ga_clear(&winsizes);
return Ctrl_C;
}
cmdwin_buf = curbuf;
// Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer.
set_option_value_give_err(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL);
curbuf->b_p_ma = true;
curwin->w_p_fen = false;
curwin->w_p_rl = cmdmsg_rl;
cmdmsg_rl = false;
// Don't allow switching to another buffer.
curbuf->b_ro_locked++;
// Showing the prompt may have set need_wait_return, reset it.
need_wait_return = false;
const int histtype = hist_char2type(cmdwin_type);
if (histtype == HIST_CMD || histtype == HIST_DEBUG) {
if (p_wc == TAB) {
add_map("<Tab>", "<C-X><C-V>", MODE_INSERT, true);
add_map("<Tab>", "a<C-X><C-V>", MODE_NORMAL, true);
}
set_option_value_give_err(kOptFiletype, STATIC_CSTR_AS_OPTVAL("vim"), OPT_LOCAL);
}
curbuf->b_ro_locked--;
// Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
// sets 'textwidth' to 78).
curbuf->b_p_tw = 0;
// Fill the buffer with the history.
init_history();
if (get_hislen() > 0 && histtype != HIST_INVALID) {
i = *get_hisidx(histtype);
if (i >= 0) {
linenr_T lnum = 0;
do {
if (++i == get_hislen()) {
i = 0;
}
if (get_histentry(histtype)[i].hisstr != NULL) {
ml_append(lnum++, get_histentry(histtype)[i].hisstr, 0, false);
}
} while (i != *get_hisidx(histtype));
}
}
// Replace the empty last line with the current command-line and put the
// cursor there.
ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, true);
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
curwin->w_cursor.col = ccline.cmdpos;
changed_line_abv_curs();
invalidate_botline_win(curwin);
ui_ext_cmdline_hide(false);
redraw_later(curwin, UPD_SOME_VALID);
// No Ex mode here!
exmode_active = false;
State = MODE_NORMAL;
check_cursor(curwin);
setmouse();
clear_showcmd();
// Reset here so it can be set by a CmdwinEnter autocommand.
cmdwin_result = 0;
// Trigger CmdwinEnter autocommands.
trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINENTER);
if (restart_edit != 0) { // autocmd with ":startinsert"
stuffcharReadbuff(K_NOP);
}
i = RedrawingDisabled;
RedrawingDisabled = 0;
int save_count = save_batch_count();
// Call the main loop until <CR> or CTRL-C is typed.
normal_enter(true, false);
RedrawingDisabled = i;
restore_batch_count(save_count);
const bool save_KeyTyped = KeyTyped;
// Trigger CmdwinLeave autocommands.
trigger_cmd_autocmd(cmdwin_type, EVENT_CMDWINLEAVE);
// Restore KeyTyped in case it is modified by autocommands
KeyTyped = save_KeyTyped;
cmdwin_type = 0;
cmdwin_level = 0;
cmdwin_buf = NULL;
cmdwin_win = NULL;
cmdwin_old_curwin = NULL;
exmode_active = save_exmode;
// Safety check: The old window or buffer was changed or deleted: It's a bug
// when this happens!
if (!win_valid(old_curwin) || !bufref_valid(&old_curbuf)
|| old_curwin->w_buffer != old_curbuf.br_buf) {
cmdwin_result = Ctrl_C;
emsg(_(e_active_window_or_buffer_changed_or_deleted));
} else {
win_T *wp;
// autocmds may abort script processing
if (aborting() && cmdwin_result != K_IGNORE) {
cmdwin_result = Ctrl_C;
}
// Set the new command line from the cmdline buffer.
dealloc_cmdbuff();
if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed
const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
size_t plen = (cmdwin_result == K_XF2) ? 2 : 3;
if (histtype == HIST_CMD) {
// Execute the command directly.
ccline.cmdbuff = xmemdupz(p, plen);
ccline.cmdlen = (int)plen;
ccline.cmdbufflen = (int)plen + 1;
cmdwin_result = CAR;
} else {
// First need to cancel what we were doing.
stuffcharReadbuff(':');
stuffReadbuff(p);
stuffcharReadbuff(CAR);
}
} else if (cmdwin_result == Ctrl_C) {
// :q or :close, don't execute any command
// and don't modify the cmd window.
ccline.cmdbuff = NULL;
} else {
ccline.cmdlen = get_cursor_line_len();
ccline.cmdbufflen = ccline.cmdlen + 1;
ccline.cmdbuff = xstrnsave(get_cursor_line_ptr(), (size_t)ccline.cmdlen);
}
if (ccline.cmdbuff == NULL) {
ccline.cmdbuff = xmemdupz("", 0);
ccline.cmdlen = 0;
ccline.cmdbufflen = 1;
ccline.cmdpos = 0;
cmdwin_result = Ctrl_C;
} else {
ccline.cmdpos = curwin->w_cursor.col;
// If the cursor is on the last character, it probably should be after it.
if (ccline.cmdpos == ccline.cmdlen - 1 || ccline.cmdpos > ccline.cmdlen) {
ccline.cmdpos = ccline.cmdlen;
}
if (cmdwin_result == K_IGNORE) {
ccline.cmdspos = cmd_screencol(ccline.cmdpos);
redrawcmd();
}
}
// Avoid command-line window first character being concealed.
curwin->w_p_cole = 0;
// First go back to the original window.
wp = curwin;
set_bufref(&bufref, curbuf);
skip_win_fix_cursor = true;
win_goto(old_curwin);
// win_goto() may trigger an autocommand that already closes the
// cmdline window.
if (win_valid(wp) && wp != curwin) {
win_close(wp, true, false);
}
// win_close() may have already wiped the buffer when 'bh' is
// set to 'wipe', autocommands may have closed other windows
if (bufref_valid(&bufref) && bufref.br_buf != curbuf) {
close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false, false, false);
}
// Restore window sizes.
win_size_restore(&winsizes);
skip_win_fix_cursor = false;
}
ga_clear(&winsizes);
restart_edit = save_restart_edit;
cmdmsg_rl = save_cmdmsg_rl;
State = save_State;
may_trigger_modechanged();
setmouse();
setcursor();
return cmdwin_result;
CmdwinOpenArgs *a = argv[0];
char fc[2] = { (char)a->firstc, 0 };
typval_T tv_args[] = {
{ .v_type = VAR_STRING, .vval.v_string = fc },
{ .v_type = VAR_STRING, .vval.v_string = a->content ? a->content : "" },
{ .v_type = VAR_NUMBER, .vval.v_number = a->pos + 1 },
{ .v_type = VAR_UNKNOWN },
};
nlua_call_vimfn("vim._core.cmdwin", "open", tv_args, NULL);
xfree(a->content);
xfree(a);
}
/// @return true if in the cmdwin, not editing the command line.
/// Schedules cmdwin to open after the current cmdline-reader returns. Returns Ctrl_C so the cmdline
/// input loop unwinds, then `vim._core.cmdwin` does its work after typeahead. #40312
static int open_cmdwin(void)
{
// Disallow during textlock or when typing a password.
if (text_locked() || cmdline_star > 0) {
beep_flush();
return K_IGNORE;
}
// Already open (also guarded in `vim._core.cmdwin`, but check here to avoid scheduling).
if (cmdwin_buf != NULL) {
beep_flush();
return K_IGNORE;
}
// Disallow for expr-register and input()/inputlist(): no reentrant return path. #40407
int ft = get_cmdline_type();
if (ft != ':' && ft != '/' && ft != '?') {
beep_flush();
return K_IGNORE;
}
CmdwinOpenArgs *a = xmalloc(sizeof(*a));
a->firstc = ft;
a->content = ccline.cmdbuff ? xstrnsave(ccline.cmdbuff, (size_t)ccline.cmdlen) : NULL;
a->pos = ccline.cmdpos;
// Intentionally not using vim.scheduled, see note on `open_cmdwin_event`.
loop_schedule_deferred(&main_loop, event_create(open_cmdwin_event, a));
return Ctrl_C;
}
/// @return true if curbuf is the cmdwin and we're not editing the command line.
bool is_in_cmdwin(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return cmdwin_type != 0 && get_cmdline_type() == NUL;
return bt_cmdwin(curbuf) && get_cmdline_type() == NUL;
}
/// Get script string
-2
View File
@@ -222,8 +222,6 @@
# define FUNC_API_LUA_ONLY
/// API function fails during textlock.
# define FUNC_API_TEXTLOCK
/// API function fails during textlock, but allows cmdwin.
# define FUNC_API_TEXTLOCK_ALLOW_CMDWIN
/// API function introduced at the given API level.
# define FUNC_API_SINCE(X)
/// API function deprecated since the given API level.
+2 -8
View File
@@ -735,12 +735,8 @@ EXTERN char *last_chdir_reason INIT( = NULL);
EXTERN bool km_stopsel INIT( = false);
EXTERN bool km_startsel INIT( = false);
EXTERN int cmdwin_type INIT( = 0); ///< type of cmdline window or 0
EXTERN int cmdwin_result INIT( = 0); ///< result of cmdline window or 0
EXTERN int cmdwin_level INIT( = 0); ///< cmdline recursion level
EXTERN buf_T *cmdwin_buf INIT( = NULL); ///< buffer of cmdline window or NULL
EXTERN win_T *cmdwin_win INIT( = NULL); ///< window of cmdline window or NULL
EXTERN win_T *cmdwin_old_curwin INIT( = NULL); ///< curwin before opening cmdline window or NULL
EXTERN int cmdwin_type INIT( = 0); ///< |cmdwin| type (':', '/', '?') or 0.
EXTERN buf_T *cmdwin_buf INIT( = NULL); ///< |cmdwin| scratch buffer, or NULL.
EXTERN win_T *cmdline_win INIT( = NULL); ///< window in use by ext_cmdline
EXTERN char no_lines_msg[] INIT( = N_("--No lines in buffer--"));
@@ -801,8 +797,6 @@ EXTERN char windowsVersion[20] INIT( = { 0 });
/// overrules p_magic. Otherwise set to OPTION_MAGIC_NOT_SET.
EXTERN optmagic_T magic_overruled INIT( = OPTION_MAGIC_NOT_SET);
/// Skip win_fix_cursor() call for 'splitkeep' when cmdwin is closed.
EXTERN bool skip_win_fix_cursor INIT( = false);
/// Skip win_fix_scroll() call for 'splitkeep' when closing tab page.
EXTERN bool skip_win_fix_scroll INIT( = false);
/// Skip update_topline() call while executing win_fix_scroll().
+1 -1
View File
@@ -2753,7 +2753,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
compl_num_bests = 0;
compl_ins_end_col = 0;
if (c == Ctrl_C && cmdwin_type != 0) {
if (c == Ctrl_C && bt_cmdwin(curbuf)) {
// Avoid the popup menu remains displayed when leaving the
// command line window.
update_screen();
+1 -2
View File
@@ -195,7 +195,7 @@ enum key_extra {
// KE_CSI = 81, // Nvim doesn't need escaping CSI
KE_SNR = 82, // <SNR>
KE_PLUG = 83, // <Plug>
KE_CMDWIN = 84, // open command-line window from Command-line Mode
// KE_CMDWIN = 84, // Nvim "cmdwin" is not special. #40312
KE_C_LEFT = 85, // control-left
KE_C_RIGHT = 86, // control-right
@@ -448,7 +448,6 @@ enum key_extra {
#define K_SNR TERMCAP2KEY(KS_EXTRA, KE_SNR)
#define K_PLUG TERMCAP2KEY(KS_EXTRA, KE_PLUG)
#define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN)
#define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP)
+1 -1
View File
@@ -684,7 +684,7 @@ int main(int argc, char **argv)
ILOG("starting main loop");
// Main loop: never returns.
normal_enter(false, false);
normal_enter(false);
#if defined(MSWIN) && !defined(MAKE_LIB)
xfree(argv);
+2 -10
View File
@@ -543,7 +543,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent)
}
// click in a tab selects that tab page
if (is_click && cmdwin_type == 0 && mouse_col < Columns) {
if (is_click && mouse_col < Columns) {
int tabnr = tab_page_click_defs[mouse_col].tabnr;
in_tab_line = true;
@@ -1415,19 +1415,11 @@ retnomove:
&& !sep_line_offset
&& (wp->w_p_rl
? col < wp->w_view_width - fdc
: col >= fdc + (wp != cmdwin_win ? 0 : 1))
: col >= fdc)
&& (flags & MOUSE_MAY_STOP_VIS)))) {
end_visual_mode();
redraw_curbuf_later(UPD_INVERTED); // delete the inversion
}
if (cmdwin_type != 0 && wp != cmdwin_win) {
// A click outside the command-line window: Use modeless
// selection if possible. Allow dragging the status lines.
sep_line_offset = 0;
row = 0;
col += wp->w_wincol;
wp = cmdwin_win;
}
// Only change window focus when not clicking on or dragging the
// status line. Do change focus when releasing the mouse button
// (MOUSE_FOCUS was set above if we dragged first).
-1
View File
@@ -814,7 +814,6 @@ int win_col_off(win_T *wp)
{
return ((wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc != NUL)
? (number_width(wp) + (*wp->w_p_stc == NUL)) : 0)
+ ((wp != cmdwin_win) ? 0 : 1)
+ win_fdccol_count(wp) + (wp->w_scwidth * SIGN_WIDTH);
}
+15 -36
View File
@@ -49,6 +49,7 @@
#include "nvim/highlight_defs.h"
#include "nvim/indent_c.h"
#include "nvim/keycodes.h"
#include "nvim/lua/executor.h"
#include "nvim/macros_defs.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
@@ -100,7 +101,6 @@ typedef struct {
bool need_flushbuf;
bool set_prevcount;
bool previous_got_int; // `got_int` was true
bool cmdwin; // command-line window normal mode
bool noexmode; // true if the normal mode was pushed from
// ex mode (:global or :visual for example)
bool toplevel; // top-level normal mode
@@ -505,21 +505,19 @@ bool op_pending(void)
/// Normal state entry point. This is called on:
///
/// - Startup, In this case the function never returns.
/// - The command-line window is opened (`q:`). Returns when `cmdwin_result` != 0.
/// - The :visual command is called from :global in ex mode, `:global/PAT/visual`
/// for example. Returns when re-entering ex mode (because ex mode recursion is
/// not allowed)
///
/// This used to be called main_loop() on main.c
void normal_enter(bool cmdwin, bool noexmode)
void normal_enter(bool noexmode)
{
NormalState state;
normal_state_init(&state);
oparg_T *prev_oap = current_oap;
current_oap = &state.oa;
state.cmdwin = cmdwin;
state.noexmode = noexmode;
state.toplevel = (!cmdwin || cmdwin_result == 0) && !noexmode;
state.toplevel = !noexmode;
state_enter(&state.state);
current_oap = prev_oap;
}
@@ -1479,7 +1477,7 @@ static int normal_check(VimState *state)
// Dict internally somewhere.
// "may_garbage_collect" is reset in vgetc() which is invoked through
// do_exmode() and normal_cmd().
may_garbage_collect = !s->cmdwin && !s->noexmode;
may_garbage_collect = !s->noexmode;
// Update w_curswant if w_set_curswant has been set.
// Postponed until here to avoid computing w_virtcol too often.
@@ -1493,11 +1491,6 @@ static int normal_check(VimState *state)
return -1;
}
if (s->cmdwin && cmdwin_result != 0) {
// command-line window and cmdwin_result is set
return 0;
}
normal_prepare(s);
return 1;
}
@@ -3870,11 +3863,8 @@ static void nv_down(cmdarg_T *cap)
// Quickfix window only: view the result under the cursor.
qf_view_result(false);
} else {
// In the cmdline window a <CR> executes the command.
if (cmdwin_type != 0 && cap->cmdchar == CAR) {
cmdwin_result = CAR;
} else if (bt_prompt(curbuf) && cap->cmdchar == CAR
&& curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
if (bt_prompt(curbuf) && cap->cmdchar == CAR
&& curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
// In a prompt buffer a <CR> in the last line invokes the callback.
prompt_invoke_callback();
if (restart_edit == 0) {
@@ -6167,9 +6157,6 @@ static void nv_normal(cmdarg_T *cap)
clear_cmdline = true; // unshow mode later
}
restart_edit = 0;
if (cmdwin_type != 0) {
cmdwin_result = Ctrl_C;
}
if (VIsual_active) {
end_visual_mode(); // stop Visual
redraw_curbuf_later(UPD_INVERTED);
@@ -6189,7 +6176,7 @@ static void nv_esc(cmdarg_T *cap)
&& cap->oap->regname == 0);
if (cap->arg) { // true for CTRL-C
if (restart_edit == 0 && cmdwin_type == 0 && !VIsual_active && no_reason) {
if (restart_edit == 0 && !bt_cmdwin(curbuf) && !VIsual_active && no_reason) {
if (anyBufIsChanged()) {
msg(_("Type :qa! and press <Enter> to abandon all changes"
" and exit Nvim"), 0);
@@ -6203,18 +6190,6 @@ static void nv_esc(cmdarg_T *cap)
}
restart_edit = 0;
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
got_int = false; // don't stop executing autocommands et al.
return;
}
} else if (cmdwin_type != 0 && ex_normal_busy && typebuf_was_empty) {
// When :normal runs out of characters while in the command line window
// vgetorpeek() will repeatedly return ESC. Exit the cmdline window to
// break the loop.
cmdwin_result = K_IGNORE;
return;
}
if (VIsual_active) {
@@ -6412,7 +6387,7 @@ static void nv_object(cmdarg_T *cap)
}
/// "q" command: Start/stop recording.
/// "q:", "q/", "q?": edit command-line in command-line window.
/// "q:", "q/", "q?": cmdwin.
static void nv_record(cmdarg_T *cap)
{
if (cap->oap->op_type == OP_FORMAT) {
@@ -6428,12 +6403,16 @@ static void nv_record(cmdarg_T *cap)
}
if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') {
if (cmdwin_type != 0) {
if (cmdwin_buf != NULL) {
emsg(_(e_cmdline_window_already_open));
return;
}
stuffcharReadbuff(cap->nchar);
stuffcharReadbuff(K_CMDWIN);
char fc[2] = { (char)cap->nchar, 0 };
typval_T tv_args[] = {
{ .v_type = VAR_STRING, .vval.v_string = fc },
{ .v_type = VAR_UNKNOWN },
};
nlua_call_vimfn("vim._core.cmdwin", "open", tv_args, NULL);
} else {
// (stop) recording into a named register, unless executing a
// register.
+1 -1
View File
@@ -1137,7 +1137,7 @@ static bool pum_set_selected(int n, int repeat)
&& (Rows > 10)
&& (repeat <= 1)
&& (cur_cot_flags & (kOptCotFlagPreview | kOptCotFlagPopup))
&& !((cur_cot_flags & kOptCotFlagPreview) && cmdwin_type != 0)) {
&& !((cur_cot_flags & kOptCotFlagPreview) && cmdwin_buf != NULL)) {
win_T *curwin_save = curwin;
tabpage_T *curtab_save = curtab;
-3
View File
@@ -761,9 +761,6 @@ int comp_textwidth(bool ff)
// The width is the window width minus 'wrapmargin' minus all the
// things that add to the margin.
textwidth = curwin->w_view_width - (int)curbuf->b_p_wm;
if (curbuf == cmdwin_buf) {
textwidth -= 1;
}
textwidth -= win_fdccol_count(curwin);
textwidth -= curwin->w_scwidth;
+3 -23
View File
@@ -273,7 +273,7 @@ void do_window(int nchar, int Prenum, int xchar)
#define CHECK_CMDWIN \
do { \
if (cmdwin_type != 0) { \
if (cmdwin_buf != NULL) { \
emsg(_(e_cmdwin)); \
return; \
} \
@@ -2694,23 +2694,6 @@ static bool can_close_floating_windows(tabpage_T *tp)
return true;
}
/// @return true if, considering the cmdwin, `win` is safe to close.
/// If false and `win` is the cmdwin, it is closed; otherwise, `err` is set.
bool can_close_in_cmdwin(win_T *win, Error *err)
FUNC_ATTR_NONNULL_ALL
{
if (cmdwin_type != 0) {
if (win == cmdwin_win) {
cmdwin_result = Ctrl_C;
return false;
} else if (win == cmdwin_old_curwin) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return false;
}
}
return true;
}
/// Close the possibly last window in a tab page.
///
/// @param win window to close
@@ -3384,8 +3367,6 @@ void win_free_all(void)
// avoid an error for switching tabpage with the cmdline window open
cmdwin_type = 0;
cmdwin_buf = NULL;
cmdwin_win = NULL;
cmdwin_old_curwin = NULL;
while (first_tabpage->tp_next != NULL) {
tabpage_close(true);
@@ -4517,7 +4498,7 @@ tabpage_T *win_new_tabpage(int after, char *filename, bool enter, win_T **first)
{
tabpage_T *old_curtab = curtab;
if (enter && cmdwin_type != 0) {
if (enter && cmdwin_buf != NULL) {
emsg(_(e_cmdwin));
return NULL;
}
@@ -6897,8 +6878,7 @@ static void win_fix_cursor(bool normal)
{
win_T *wp = curwin;
if (skip_win_fix_cursor
|| !wp->w_do_win_fix_cursor
if (!wp->w_do_win_fix_cursor
|| wp->w_buffer->b_ml.ml_line_count < wp->w_view_height) {
return;
}
-16
View File
@@ -79,22 +79,6 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
|| (win_tp != curtab && win_tp->tp_firstwin == wp && lastwin_nofloating(win_tp) == wp)) {
api_set_error(err, kErrorTypeException, "Cannot change last window into float");
return NULL;
} else if (cmdwin_win != NULL && !cmdwin_win->w_floating) {
// cmdwin can't become the only non-float. Check for others.
bool other_nonfloat = false;
FOR_ALL_WINDOWS_IN_TAB(wp2, win_tp) {
if (wp2->w_floating) {
break;
}
if (wp2 != wp && wp2 != cmdwin_win) {
other_nonfloat = true;
break;
}
}
if (!other_nonfloat) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return NULL;
}
}
tabpage_T *tp = win_tp == curtab ? NULL : win_tp;
int dir;
-1
View File
@@ -3748,7 +3748,6 @@ set CLASS_COLON FUNC_API_REMOTE_ONLY
set CLASS_COLON FUNC_API_RET_ALLOC
set CLASS_COLON FUNC_API_SINCE
set CLASS_COLON FUNC_API_TEXTLOCK
set CLASS_COLON FUNC_API_TEXTLOCK_ALLOW_CMDWIN
set CLASS_COLON FUNC_ATTR_ALWAYS_INLINE
set CLASS_COLON FUNC_ATTR_CONST
set CLASS_COLON FUNC_ATTR_MALLOC
+6 -32
View File
@@ -93,44 +93,18 @@ describe('api/tabpage', function()
)
end)
it('checks textlock, cmdwin restrictions', function()
it('checks textlock restrictions', function()
command('autocmd TextYankPost * ++once call nvim_open_tabpage(0, 0, {})')
matches('E565:', pcall_err(command, 'yank'))
eq(1, fn.tabpagenr('$'))
local other_buf = api.nvim_get_current_buf()
feed('q:')
-- OK when not entering and not opening a tabpage with the cmdwin's buffer.
matches('E11:', pcall_err(api.nvim_open_tabpage, 0, false, {}))
eq(1, fn.tabpagenr('$'))
matches('E11:', pcall_err(api.nvim_open_tabpage, other_buf, true, {}))
eq(1, fn.tabpagenr('$'))
local tp = api.nvim_open_tabpage(other_buf, false, {})
eq(other_buf, api.nvim_win_get_buf(api.nvim_tabpage_get_win(tp)))
eq('command', fn.win_gettype())
end)
it('does not switch window when textlocked or in the cmdwin', function()
local target_win = api.nvim_get_current_win()
feed('q:')
local cur_win = api.nvim_get_current_win()
eq(
'Vim:E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_tabpage_set_win, 0, target_win)
)
eq(cur_win, api.nvim_get_current_win())
command('quit!')
exec(([[
exec([[
new
call setline(1, 'foo')
setlocal debug=throw indentexpr=nvim_tabpage_set_win(0,%d)
]]):format(target_win))
cur_win = api.nvim_get_current_win()
eq(
'Vim(normal):E5555: API call: Vim:E565: Not allowed to change text or change window',
pcall_err(command, 'normal! ==')
)
setlocal debug=throw indentexpr=nvim_tabpage_set_win(0,win_getid())
]])
local cur_win = api.nvim_get_current_win()
matches('E565: Not allowed to change text or change window', pcall_err(command, 'normal! =='))
eq(cur_win, api.nvim_get_current_win())
end)
end)
+28 -276
View File
@@ -55,7 +55,7 @@ describe('API/win', function()
eq('Invalid window id: 23', pcall_err(api.nvim_win_set_buf, 23, api.nvim_get_current_buf()))
end)
it('disallowed in cmdwin if win=cmdwin_{old_cur}win or buf=cmdwin_buf', function()
it('in cmdwin #40312', function()
local new_buf = api.nvim_create_buf(true, true)
local old_win = api.nvim_get_current_win()
local new_win = api.nvim_open_win(new_buf, false, {
@@ -66,52 +66,16 @@ describe('API/win', function()
height = 10,
})
feed('q:')
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_buf, 0, new_buf)
)
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_buf, old_win, new_buf)
)
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_buf, new_win, 0)
)
matches(
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
pcall_err(
exec_lua,
[[
local cmdwin_buf = vim.api.nvim_get_current_buf()
local new_win, new_buf = ...
vim._with({buf = new_buf}, function()
vim.api.nvim_win_set_buf(new_win, cmdwin_buf)
end)
]],
new_win,
new_buf
)
)
matches(
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
pcall_err(
exec_lua,
[[
local cmdwin_win = vim.api.nvim_get_current_win()
local new_win, new_buf = ...
vim._with({win = new_win}, function()
vim.api.nvim_win_set_buf(cmdwin_win, new_buf)
end)
]],
new_win,
new_buf
)
)
n.poke_eventloop()
-- Replacing the cmdwin's own buffer is blocked by 'winfixbuf'.
matches('winfixbuf', pcall_err(api.nvim_win_set_buf, 0, new_buf))
-- But other windows can be touched freely.
local next_buf = api.nvim_create_buf(true, true)
api.nvim_win_set_buf(new_win, next_buf)
eq(next_buf, api.nvim_win_get_buf(new_win))
-- Doesn't matter that old_win was the caller; no cmdwin guard.
api.nvim_win_set_buf(old_win, new_buf)
eq(new_buf, api.nvim_win_get_buf(old_win))
end)
describe("with 'autochdir'", function()
@@ -640,11 +604,9 @@ describe('API/win', function()
eq({ newwin }, api.nvim_list_wins())
end)
it('in cmdline-window #9767', function()
it('in cmdwin #9767', function()
command('split')
eq(2, #api.nvim_list_wins())
local oldbuf = api.nvim_get_current_buf()
local oldwin = api.nvim_get_current_win()
local otherwin = api.nvim_open_win(0, false, {
relative = 'editor',
row = 10,
@@ -652,62 +614,17 @@ describe('API/win', function()
width = 10,
height = 10,
})
-- Open cmdline-window.
feed('q:')
n.poke_eventloop()
eq(4, #api.nvim_list_wins())
eq(':', fn.getcmdwintype())
-- Not allowed to close previous window from cmdline-window.
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_close, oldwin, true)
)
-- Closing other windows is fine.
-- Closing other windows still works.
api.nvim_win_close(otherwin, true)
eq(false, api.nvim_win_is_valid(otherwin))
-- Close cmdline-window.
api.nvim_win_close(0, true)
eq(2, #api.nvim_list_wins())
eq('', fn.getcmdwintype())
-- Closing curwin in context of a different window shouldn't close cmdwin.
otherwin = api.nvim_open_win(0, false, {
relative = 'editor',
row = 10,
col = 10,
width = 10,
height = 10,
})
feed('q:')
exec_lua(
[[
vim._with({win = ...}, function()
vim.api.nvim_win_close(0, true)
end)
]],
otherwin
)
eq(false, api.nvim_win_is_valid(otherwin))
eq(':', fn.getcmdwintype())
-- Closing cmdwin in context of a non-previous window is still OK.
otherwin = api.nvim_open_win(oldbuf, false, {
relative = 'editor',
row = 10,
col = 10,
width = 10,
height = 10,
})
exec_lua(
[[
local otherwin, cmdwin = ...
vim._with({win = otherwin}, function()
vim.api.nvim_win_close(cmdwin, true)
end)
]],
otherwin,
api.nvim_get_current_win()
)
eq('', fn.getcmdwintype())
eq(true, api.nvim_win_is_valid(otherwin))
end)
it('closing current (float) window of another tabpage #15313', function()
@@ -804,69 +721,11 @@ describe('API/win', function()
eq({ oldwin }, api.nvim_list_wins())
eq({ oldbuf }, api.nvim_list_bufs())
end)
it('in the cmdwin', function()
it('in cmdwin', function()
feed('q:')
-- Can close the cmdwin.
n.poke_eventloop()
api.nvim_win_hide(0)
eq('', fn.getcmdwintype())
local old_buf = api.nvim_get_current_buf()
local old_win = api.nvim_get_current_win()
local other_win = api.nvim_open_win(0, false, {
relative = 'win',
row = 3,
col = 3,
width = 12,
height = 3,
})
feed('q:')
-- Cannot close the previous window.
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_hide, old_win)
)
-- Can close other windows.
api.nvim_win_hide(other_win)
eq(false, api.nvim_win_is_valid(other_win))
-- Closing curwin in context of a different window shouldn't close cmdwin.
other_win = api.nvim_open_win(old_buf, false, {
relative = 'editor',
row = 10,
col = 10,
width = 10,
height = 10,
})
exec_lua(
[[
vim._with({win = ...}, function()
vim.api.nvim_win_hide(0)
end)
]],
other_win
)
eq(false, api.nvim_win_is_valid(other_win))
eq(':', fn.getcmdwintype())
-- Closing cmdwin in context of a non-previous window is still OK.
other_win = api.nvim_open_win(old_buf, false, {
relative = 'editor',
row = 10,
col = 10,
width = 10,
height = 10,
})
exec_lua(
[[
local otherwin, cmdwin = ...
vim._with({win = otherwin}, function()
vim.api.nvim_win_hide(cmdwin)
end)
]],
other_win,
api.nvim_get_current_win()
)
eq('', fn.getcmdwintype())
eq(true, api.nvim_win_is_valid(other_win))
end)
end)
@@ -1453,54 +1312,19 @@ describe('API/win', function()
end)
describe('open_win', function()
it('disallowed in cmdwin if enter=true or buf=cmdwin_buf', function()
it('works while cmdwin is open #40312', function()
-- Legacy cmdwin blocked nvim_open_win with E11; now there is no such restriction.
local new_buf = api.nvim_create_buf(true, true)
feed('q:')
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_open_win, new_buf, true, {
relative = 'editor',
row = 5,
col = 5,
width = 5,
height = 5,
})
)
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_open_win, 0, false, {
relative = 'editor',
row = 5,
col = 5,
width = 5,
height = 5,
})
)
matches(
'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
pcall_err(
exec_lua,
[[
local cmdwin_buf = vim.api.nvim_get_current_buf()
vim._with({buf = vim.api.nvim_create_buf(false, true)}, function()
vim.api.nvim_open_win(cmdwin_buf, false, {
relative='editor', row=5, col=5, width=5, height=5,
})
end)
]]
)
)
eq(
new_buf,
api.nvim_win_get_buf(api.nvim_open_win(new_buf, false, {
relative = 'editor',
row = 5,
col = 5,
width = 5,
height = 5,
}))
)
n.poke_eventloop()
local new_win = api.nvim_open_win(new_buf, false, {
relative = 'editor',
row = 5,
col = 5,
width = 5,
height = 5,
})
eq(new_buf, api.nvim_win_get_buf(new_win))
end)
it('aborts if buffer is invalid', function()
@@ -3099,74 +2923,10 @@ describe('API/win', function()
try_move_t2_wins_to_t1()
end)
it('handles cmdwin and textlock restrictions', function()
it('handles textlock', function()
command('tabnew')
local t2 = api.nvim_get_current_tabpage()
local t2_win = api.nvim_get_current_win()
command('tabfirst')
local t1_move_win = api.nvim_get_current_win()
command('split')
-- Can't move the cmdwin, or its old curwin to a different tabpage.
local old_curwin = api.nvim_get_current_win()
feed('q:')
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_config, 0, { split = 'left', win = t2_win })
)
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_config, old_curwin, { split = 'left', win = t2_win })
)
-- But we can move other windows.
api.nvim_win_set_config(t1_move_win, { split = 'left', win = t2_win })
eq(t2, api.nvim_win_get_tabpage(t1_move_win))
command('quit!')
-- Can't configure windows such that the cmdwin would become the only non-float.
command('only!')
feed('q:')
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(
api.nvim_win_set_config,
old_curwin,
{ relative = 'editor', row = 0, col = 0, width = 5, height = 5 }
)
)
-- old_curwin is now no longer the only other non-float, so we can make it floating now.
local t1_new_win = api.nvim_open_win(
api.nvim_create_buf(true, true),
false,
{ split = 'left', win = old_curwin }
)
api.nvim_win_set_config(
old_curwin,
{ relative = 'editor', row = 0, col = 0, width = 5, height = 5 }
)
eq('editor', api.nvim_win_get_config(old_curwin).relative)
-- ...which means we shouldn't be able to also make the new window floating too!
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(
api.nvim_win_set_config,
t1_new_win,
{ relative = 'editor', row = 0, col = 0, width = 5, height = 5 }
)
)
-- Nothing ought to stop us from making the cmdwin itself floating, though...
api.nvim_win_set_config(0, { relative = 'editor', row = 0, col = 0, width = 5, height = 5 })
eq('editor', api.nvim_win_get_config(0).relative)
-- We can't make our new window from before floating too, as it's now the only non-float.
eq(
'Cannot change last window into float',
pcall_err(
api.nvim_win_set_config,
t1_new_win,
{ relative = 'editor', row = 0, col = 0, width = 5, height = 5 }
)
)
command('quit!')
exec(([[
new
@@ -3732,21 +3492,13 @@ describe('API/win', function()
eq({ false, 'Cannot move autocmd window to another tabpage' }, { float_ok, float_err })
end)
it('cannot move cmdwin between tabpages', function()
it('can move cmdwin between tabpages #40312', function()
local other_tp_win = api.nvim_get_current_win()
command('tabnew')
local old_curwin = api.nvim_get_current_win()
feed('q:')
n.poke_eventloop()
eq('command', fn.win_gettype())
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_config, 0, { win = other_tp_win, split = 'right' })
)
-- Shouldn't move the old curwin from before we entered the cmdwin either.
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_win_set_config, old_curwin, { win = other_tp_win, split = 'right' })
)
api.nvim_win_set_config(0, { win = other_tp_win, split = 'right' })
end)
it('minimal style persists through float-to-split and buffer change #37067', function()
+7 -12
View File
@@ -157,27 +157,22 @@ describe('cmdline autocommands', function()
]])
end)
it('works with nested cmdline', function()
it('with nested cmdline', function()
-- Cmdwin is not supported in expr-register (<C-R>=) cmdline. #40312
feed(':')
eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 1 } } }, next_msg())
feed('<c-r>=')
eq({ 'notification', 'CmdlineEnter', { { cmdtype = '=', cmdlevel = 2 } } }, next_msg())
feed('<c-f>')
eq({ 'notification', 'CmdwinEnter', { {} } }, next_msg())
feed(':')
eq({ 'notification', 'CmdlineEnter', { { cmdtype = ':', cmdlevel = 3 } } }, next_msg())
feed('<c-c>')
eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 3, abort = true } } },
next_msg()
)
feed('<c-c>')
eq({ 'notification', 'CmdwinLeave', { {} } }, next_msg())
feed('1+2<cr>')
eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = '=', cmdlevel = 2, abort = false } } },
next_msg()
)
feed('<cr>')
eq(
{ 'notification', 'CmdlineLeave', { { cmdtype = ':', cmdlevel = 1, abort = false } } },
next_msg()
)
end)
it('no crash with recursive use of v:event #19484', function()
+6 -11
View File
@@ -618,7 +618,7 @@ describe('tabpage/previous', function()
-- it('does not switch to previous via :tabn #<CR> after entering operator pending',
-- does_not_switch_to_previous_after_entering_operator_pending(':tabn #<CR>'))
local function cmdline_win_prevents_tab_switch(characters, completion_visible)
local function cmdwin_prevents_tab_switch(characters, completion_visible)
return function()
-- Add three tabs for a total of four
command('tabnew')
@@ -647,16 +647,11 @@ describe('tabpage/previous', function()
eq(3, eval("tabpagenr('#')"))
end
end
it('cmdline-win prevents tab switch via g<Tab>', cmdline_win_prevents_tab_switch('g<Tab>', 0))
it(
'cmdline-win prevents tab switch via <C-W>g<Tab>',
cmdline_win_prevents_tab_switch('<C-W>g<Tab>', 1)
)
it('cmdline-win prevents tab switch via <C-Tab>', cmdline_win_prevents_tab_switch('<C-Tab>', 0))
it(
'cmdline-win prevents tab switch via :tabn #<CR>',
cmdline_win_prevents_tab_switch(':tabn #<CR>', 0)
)
it('cmdwin prevents tab switch via g<Tab>', cmdwin_prevents_tab_switch('g<Tab>', 0))
it('cmdwin prevents tab switch via <C-W>g<Tab>', cmdwin_prevents_tab_switch('<C-W>g<Tab>', 0))
it('cmdwin prevents tab switch via <C-Tab>', cmdwin_prevents_tab_switch('<C-Tab>', 0))
it('cmdwin prevents tab switch via :tabn #<CR>', cmdwin_prevents_tab_switch(':tabn #<CR>', 0))
it(':tabs indicates correct prevtab curwin', function()
-- Add three tabs for a total of four
+1
View File
@@ -220,6 +220,7 @@ describe('vim._core', function()
)
local expected = {
'vim.F',
'vim._core.cmdwin',
'vim._core.defaults',
'vim._core.editor',
'vim._core.ex_cmd',
+115
View File
@@ -0,0 +1,115 @@
-- Tests for non-blocking cmdwin. #40312
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local feed = n.feed
local api = n.api
local fn = n.fn
local exec_lua = n.exec_lua
local eq = t.eq
describe('cmdwin', function()
before_each(n.clear)
it('q: opens cmdwin', function()
feed('q:')
eq(':', fn.getcmdwintype())
eq('[Command Line]', vim.fs.basename(api.nvim_buf_get_name(0)))
-- cmdwin-char is shown in window-local 'statuscolumn'.
eq('%#NonText#: ', api.nvim_get_option_value('statuscolumn', { win = 0 }))
eq('nofile', api.nvim_get_option_value('buftype', { buf = 0 }))
eq('wipe', api.nvim_get_option_value('bufhidden', { buf = 0 }))
eq(false, api.nvim_get_option_value('swapfile', { buf = 0 }))
eq(true, api.nvim_get_option_value('winfixbuf', { win = 0 }))
-- <CR> executes the cmdline
feed('ilet g:cmdwin_result = 42<Esc>')
feed('<CR>')
eq(42, api.nvim_get_var('cmdwin_result'))
eq('', fn.getcmdwintype())
end)
it('q/ opens cmdwin with search history', function()
feed('q/')
eq('/', fn.getcmdwintype())
end)
it('c_CTRL-F opens cmdwin pre-filled with current cmdline', function()
feed(':echo "hi"<C-F>')
n.poke_eventloop()
eq(':', fn.getcmdwintype())
eq('echo "hi"', api.nvim_get_current_line())
end)
it('<C-C> in normal mode cancels without executing', function()
feed('q:')
feed('iecho "nope"<Esc>')
feed('<C-C>')
eq('', fn.getcmdwintype())
-- v:errmsg should not contain a successful echo from the cancelled line.
end)
it('async API calls work while cmdwin is open #40312', function()
feed('q:')
eq(':', fn.getcmdwintype())
local ok, err = pcall(function()
local b = api.nvim_create_buf(true, false)
api.nvim_buf_delete(b, { force = true })
end)
eq(true, ok, 'buf_delete unexpectedly failed: ' .. tostring(err))
end)
it('textlock does not include cmdwin #40312', function()
feed('q:')
-- Setting an option from API used to fail with E11 in cmdwin.
api.nvim_set_option_value('wildignore', '*.tmp', {})
end)
it('E1292 cannot nest cmdwin', function()
feed('q:')
eq(':', fn.getcmdwintype())
feed('q:')
-- Still just one cmdwin.
eq(':', fn.getcmdwintype())
local nwin = 0
for _, w in ipairs(api.nvim_list_wins()) do
if api.nvim_get_option_value('winfixbuf', { win = w }) then
nwin = nwin + 1
end
end
eq(1, nwin)
end)
it(':quit closes cmdwin', function()
feed('q:')
eq(':', fn.getcmdwintype())
feed(':q<CR>')
eq('', fn.getcmdwintype())
end)
it(':messages from inside cmdwin works #40312', function()
-- Before #40312, this raised E11 because text_locked() returned true for cmdwin.
exec_lua([[vim.api.nvim_echo({{'hello from history'}}, true, {})]])
feed('q:')
eq(':', fn.getcmdwintype())
n.command('messages') -- Previously E11; now actually runs.
end)
it('CmdwinEnter/CmdwinLeave events', function()
exec_lua([[
_G.events = {}
vim.api.nvim_create_autocmd('CmdwinEnter', {
callback = function(a) table.insert(_G.events, 'enter:'..a.match) end,
})
vim.api.nvim_create_autocmd('CmdwinLeave', {
callback = function(a) table.insert(_G.events, 'leave:'..a.match) end,
})
]])
feed('q:')
n.poke_eventloop() -- Ensure q: is processed before the <C-C> mapping fires.
feed('<C-C>')
eq({ 'enter::', 'leave::' }, exec_lua('return _G.events'))
end)
end)
+11 -11
View File
@@ -1046,8 +1046,9 @@ describe('completion', function()
screen:expect([[
|
{2:[No Name] }|
{1::}foo faa fee f^ |
{1:~ }|*3
{1:: } |
{1:: }foo faa fee f^ |
{1:~ }|*2
{3:[Command Line] }|
{5:-- INSERT --} |
]])
@@ -1055,20 +1056,19 @@ describe('completion', function()
screen:expect([[
|
{2:[No Name] }|
{1::}foo faa fee foo^ |
{1:~ }{12: foo }{1: }|
{1:~ }{4: faa }{1: }|
{1:~ }{4: fee }{1: }|
{3:[Command Line] }|
{1:: } |
{1:: }foo faa fee foo^ |
{1:~ }{12: foo }{1: }|
{1:~ }{4: faa }{1: }|
{3:[Command Line}{4: fee }{3: }|
{5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} |
]])
feed('<c-c>')
-- Non-blocking cmdwin (#40312): <C-C> closes the cmdwin and drops back
-- into ":" cmdline mode pre-filled with the line under the cursor.
screen:expect([[
|
{2:[No Name] }|
{1::}foo faa fee foo |
{1:~ }|*3
{3:[Command Line] }|
{1:~ }|*6
:foo faa fee foo^ |
]])
end)
+1 -19
View File
@@ -7,7 +7,6 @@ local dedent = t.dedent
local exec = n.exec
local feed = n.feed
local clear = n.clear
local fn = n.fn
local command = n.command
local api = n.api
@@ -33,30 +32,13 @@ local cmdtest = function(cmd, prep, ret1)
feed(':' .. cmd .. '\nabc\ndef\n.\n')
eq(ret1, buffer_contents())
end)
-- This used to crash since that commit as well.
it('opens empty cmdline window', function()
local hisline = '" Some comment to be stored in history'
feed(':' .. hisline .. '<CR>')
feed(':' .. cmd .. '<CR>abc<CR>def<C-f>')
eq({ 'def' }, buffer_contents())
eq(hisline, fn.histget(':', -2))
eq(cmd, fn.histget(':'))
-- Test that command-line window was launched
eq('nofile', api.nvim_get_option_value('buftype', {}))
eq('n', fn.mode(1))
feed('<CR>')
eq('c', fn.mode(1))
feed('.<CR>')
eq('n', fn.mode(1))
eq(ret1, buffer_contents())
end)
end)
end
cmdtest('insert', ' before', { 'abc', 'def', 'foo', 'bar', 'baz' })
cmdtest('append', ' after', { 'foo', 'abc', 'def', 'bar', 'baz' })
cmdtest('change', '', { 'abc', 'def', 'bar', 'baz' })
describe('the first line is redrawn correctly after inserting text in an empty buffer', function()
describe('first line is redrawn correctly after :append/:insert in an empty buffer', function()
local screen
before_each(function()
clear()
-97
View File
@@ -1,97 +0,0 @@
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local clear = n.clear
local command = n.command
local feed = n.feed
describe('cmdwin', function()
before_each(clear)
-- oldtest: Test_cmdwin_interrupted()
it('still uses a new buffer when interrupting more prompt on open', function()
local screen = Screen.new(30, 16)
command('set more')
command('autocmd WinNew * highlight')
feed('q:')
screen:expect({ any = vim.pesc('{6:-- More --}^') })
feed('q')
screen:expect([[
|
{1:~ }|*5
{2:[No Name] }|
{1::}^ |
{1:~ }|*6
{3:[Command Line] }|
|
]])
feed([[aecho 'done']])
screen:expect([[
|
{1:~ }|*5
{2:[No Name] }|
{1::}echo 'done'^ |
{1:~ }|*6
{3:[Command Line] }|
{5:-- INSERT --} |
]])
feed('<CR>')
screen:expect([[
^ |
{1:~ }|*14
done |
]])
end)
-- oldtest: Test_cmdwin_showcmd()
it('has correct showcmd', function()
local screen = Screen.new(60, 18)
command('set showcmd')
for _, keys in ipairs({ 'q:', ':<C-F>' }) do
feed(keys)
local fmt = [[
|
{1:~ }|*7
{2:[No Name] }|
{1::}^ |
{1:~ }|*6
{3:[Command Line] }|
: %s |
]]
screen:expect(fmt:format(' '))
feed('"')
screen:expect(fmt:format('" '))
feed('x')
screen:expect(fmt:format('"x '))
feed('y')
screen:expect(fmt:format('"xy '))
feed('y')
screen:expect(fmt:format(' '))
feed('<C-C>')
n.poke_eventloop()
feed('<C-C>')
screen:expect([[
^ |
{1:~ }|*16
|
]])
end
end)
-- oldtest: Test_cmdwin_no_prefix_on_wrapped_line()
it('prefix char is not drawn on wrapped screen line', function()
local screen = Screen.new(40, 12)
local cmd = 'echo "' .. ('a'):rep(40 - 8) .. '"XYZ'
feed(':' .. cmd .. '<C-F>')
screen:expect([[
|
{1:~ }|
{2:[No Name] }|
{1::}echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"|
XY^Z |
{1:~ }|*5
{3:[Command Line] }|
|
]])
end)
end)
+15 -35
View File
@@ -240,7 +240,7 @@ local function test_cmdline(linegrid)
]])
end)
it('works with cmdline window', function()
it('with cmdwin', function()
feed(':make')
screen:expect {
grid = [[
@@ -255,25 +255,22 @@ local function test_cmdline(linegrid)
screen:expect([[
|
{2:[No Name] }|
{1::}mak^e |
{1:: }mak^e |
{3:[Command Line] }|
|
]])
-- nested cmdline
-- cmdwin is a plain window so `:yank` opens a top-level cmdline. No nesting allowed. #40312
feed(':yank')
screen:expect {
grid = [[
|
{2:[No Name] }|
{1::}mak^e |
{1:: }mak^e |
{3:[Command Line] }|
|
]],
cmdline = {
nil,
{ firstc = ':', content = { { 'yank' } }, pos = 4 },
},
cmdline = { { firstc = ':', content = { { 'yank' } }, pos = 4 } },
}
command('mode')
@@ -281,14 +278,11 @@ local function test_cmdline(linegrid)
grid = [[
|
{2:[No Name] }|
{1::}mak^e |
{1:: }mak^e |
{3:[Command Line] }|
|
]],
cmdline = {
nil,
{ firstc = ':', content = { { 'yank' } }, pos = 4 },
},
cmdline = { { firstc = ':', content = { { 'yank' } }, pos = 4 } },
reset = true,
}
@@ -297,26 +291,14 @@ local function test_cmdline(linegrid)
grid = [[
|
{2:[No Name] }|
{1::}mak^e |
{1:: }mak^e |
{3:[Command Line] }|
|
]],
cmdline = { [2] = { abort = true } },
cmdline = { { abort = true } },
}
feed('<c-c>')
screen:expect {
grid = [[
^ |
{2:[No Name] }|
{1::}make |
{3:[Command Line] }|
|
]],
cmdline = { { firstc = ':', content = { { 'make' } }, pos = 4 } },
}
command('redraw!')
screen:expect {
grid = [[
^ |
@@ -918,20 +900,18 @@ describe('cmdline redraw', function()
|
{1:~ }|*3
{2:[No Name] }|
{1::}^a{17:bc} |
{1:~ }|*2
{1:: } |
{1:: }^a{17:bc} |
{1:~ }|
{3:[Command Line] }|
{5:-- VISUAL --} |
]])
-- Ctrl-C closes cmdwin and drops back into pre-filled cmdline. #40312
feed('<C-C>')
screen:expect([[
|
{1:~ }|*3
{2:[No Name] }|
{1::}a{17:bc} |
{1:~ }|*2
{3:[Command Line] }|
:^abc |
{1:~ }|*8
:abc^ |
]])
end)
-149
View File
@@ -1184,155 +1184,6 @@ describe('folded lines', function()
end
end)
it('in cmdline window', function()
feed_command('set foldmethod=manual foldcolumn=1')
feed_command('let x = 1')
feed_command('/alpha')
feed_command('/omega')
feed('<cr>q:')
if multigrid then
screen:expect([[
## grid 1
[2:---------------------------------------------]|
{2:[No Name] }|
[4:---------------------------------------------]|*4
{3:[Command Line] }|
[3:---------------------------------------------]|
## grid 2
{7: } |
## grid 3
: |
## grid 4
{1::}{7: }set foldmethod=manual foldcolumn=1 |
{1::}{7: }let x = 1 |
{1::}{7: }^ |
{1:~ }|
]])
else
screen:expect([[
{7: } |
{2:[No Name] }|
{1::}{7: }set foldmethod=manual foldcolumn=1 |
{1::}{7: }let x = 1 |
{1::}{7: }^ |
{1:~ }|
{3:[Command Line] }|
: |
]])
end
feed('kzfk')
if multigrid then
screen:expect([[
## grid 1
[2:---------------------------------------------]|
{2:[No Name] }|
[4:---------------------------------------------]|*4
{3:[Command Line] }|
[3:---------------------------------------------]|
## grid 2
{7: } |
## grid 3
: |
## grid 4
{1::}{7:+}{13:^+-- 2 lines: set foldmethod=manual foldcol}|
{1::}{7: } |
{1:~ }|*2
]])
else
screen:expect([[
{7: } |
{2:[No Name] }|
{1::}{7:+}{13:^+-- 2 lines: set foldmethod=manual foldcol}|
{1::}{7: } |
{1:~ }|*2
{3:[Command Line] }|
: |
]])
end
feed('<cr>')
if multigrid then
screen:expect([[
## grid 1
[2:---------------------------------------------]|*7
[3:---------------------------------------------]|
## grid 2
{7: }^ |
{1:~ }|*6
## grid 3
: |
]])
else
screen:expect([[
{7: }^ |
{1:~ }|*6
: |
]])
end
feed('/<c-f>')
if multigrid then
screen:expect([[
## grid 1
[2:---------------------------------------------]|
{2:[No Name] }|
[5:---------------------------------------------]|*4
{3:[Command Line] }|
[3:---------------------------------------------]|
## grid 2
{7: } |
## grid 3
/ |
## grid 5
{1:/}{7: }alpha |
{1:/}{7: }{10:omega} |
{1:/}{7: }^ |
{1:~ }|
]])
else
screen:expect([[
{7: } |
{2:[No Name] }|
{1:/}{7: }alpha |
{1:/}{7: }{10:omega} |
{1:/}{7: }^ |
{1:~ }|
{3:[Command Line] }|
/ |
]])
end
feed('ggzfG')
if multigrid then
screen:expect([[
## grid 1
[2:---------------------------------------------]|
{2:[No Name] }|
[5:---------------------------------------------]|*4
{3:[Command Line] }|
[3:---------------------------------------------]|
## grid 2
{7: } |
## grid 3
/ |
## grid 5
{1:/}{7:+}{13:^+-- 3 lines: alpha························}|
{1:~ }|*3
]])
else
screen:expect([[
{7: } |
{2:[No Name] }|
{1:/}{7:+}{13:^+-- 3 lines: alpha························}|
{1:~ }|*3
{3:[Command Line] }|
/ |
]])
end
end)
it('foldcolumn autoresize', function()
fn.setline(1, 'line 1')
fn.setline(2, 'line 2')
+32 -21
View File
@@ -205,45 +205,55 @@ describe('messages2', function()
]])
feed(':<C-F>')
screen:expect([[
foo |*5
{1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1::}^ |
x |
{1:~ }|*3
─────────────────────────────────────────────────────|
{1:: }echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1:: }^ |
{1:~ }|*5
{3:[Command Line] 2,0-1 All}|
|
]])
command('wincmd +')
screen:expect([[
foo |*4
{1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1::}^ |
x |
{1:~ }|*2
─────────────────────────────────────────────────────|
{1:: }echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1:: }^ |
{1:~ }|*6
{3:[Command Line] 2,0-1 All}|
|
]])
command('echo "foo"')
screen:expect([[
foo |*4
{1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1::}^ |
x |
{1:~ }|*2
─────────────────────────────────────────────────────|
{1:: }echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1:: }^ |
{1:~ }|*6
{3:[Command Line] 2,0-1 All}|
foo |
]])
-- <C-C> closes the cmdwin and drops back into pre-filled cmdline. The pager remains visible.
feed('<C-C>')
screen:expect([[
foo |*12
x |
{1:~ }|*11
{3:[Pager] 1,1 Top}|
{16::}^ |
]])
-- Can enter pager from cmdwin.
feed('<Esc>qq:')
feed('<Esc><Esc>')
-- Can enter pager from cmdwin (use cmdwin.open() since "q" is consumed by the pager on_key
-- callback before nv_record can read it).
exec_lua([[require('vim._core.cmdwin').open(':')]])
screen:expect([[
x |
{1:~ }|*3
─────────────────────────────────────────────────────|
{1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1::}^ |
{1:: }echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1:: }^ |
{1:~ }|*5
{3:[Command Line] 2,0-1 All}|
|
@@ -251,9 +261,10 @@ describe('messages2', function()
feed(':messages<CR>')
screen:expect([[
^foo |
foo |*11
foo |*4
{1:~ }|*7
{3:[Pager] 1,1 Top}|
|
{16::}{15:messages} |
]])
-- Cmdwin is restored after pager is closed.
feed('q')
@@ -261,12 +272,12 @@ describe('messages2', function()
x |
{1:~ }|*3
─────────────────────────────────────────────────────|
{1::}echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1::}messages |
{1::}^ |
{1:: }echo "foo" | echo "bar\nbaz\n"->repeat(&lines) |
{1:: }messages |
{1:: }^ |
{1:~ }|*4
{3:[Command Line] 3,0-1 All}|
|
{16::}{15:messages} |
]])
-- Configured maximum height.
command('quit | lua require("vim._core.ui2").enable({msg = {pager = {height = 2 } } })')
@@ -278,7 +289,7 @@ describe('messages2', function()
^foo |
foo |
{3:[Pager] 1,1 Top}|
|
{16::}{15:messages} |
]])
end)
+5 -10
View File
@@ -4528,17 +4528,12 @@ describe('builtin popupmenu', function()
:sign definex^ |
]])
-- When the popup is open, entering the cmdline window should close the popup
-- When the popup is open, entering cmdwin should close the popup.
feed('<C-U>sign <Tab><C-F>')
screen:expect([[
|
{2:[No Name] }|
{1::}sign define |
{1::}sign defin^e |
{1:~ }|*4
{3:[Command Line] }|
:sign define |
]])
t.retry(nil, 2000, function()
eq(':', n.fn.getcmdwintype())
end)
eq(0, n.fn.pumvisible())
feed(':q<CR>')
-- After the last popup menu item, <C-N> should show the original string
+4 -3
View File
@@ -962,6 +962,7 @@ describe('statuscolumn', function()
end)
it('works with cmdwin', function()
-- The cmdwin sets its own window-local 'statuscolumn' (cmdwin-char).
feed(':set stc=%l<CR>q:k$')
screen:expect([[
{8: 7}aaaaa |
@@ -969,11 +970,11 @@ describe('statuscolumn', function()
{8: 9}aaaaa |
{8:10}aaaaa |
{2:[No Name] [+] }|
{1::}{8:1}set stc=%^l |
{1::}{8:2} |
{1:: }set stc=%^l |
{1:: } |
{1:~ }|*5
{3:[Command Line] }|
: |
:set stc=%l |
]])
end)
@@ -10,7 +10,6 @@ local insert, pcall_err = n.insert, t.pcall_err
local matches = t.matches
local api = n.api
local feed = n.feed
local command = n.command
describe('eval-API', function()
before_each(clear)
@@ -91,16 +90,22 @@ describe('eval-API', function()
api.nvim_get_vvar('errmsg')
)
-- Some functions checking textlock (usually those that may change the current window or buffer)
-- also ought to not be usable in the cmdwin.
-- cmdwin behavior (changed since #40312).
local old_win = api.nvim_get_current_win()
feed('q:')
local cmdwin_win = api.nvim_get_current_win()
eq(
'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
'Vim:E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
pcall_err(api.nvim_set_current_win, old_win)
)
eq(old_win, api.nvim_get_current_win())
-- TODO(justinmk): awkward: E11 is raised but the focus switch happens anyway; inherited bug in
-- goto_tabpage_win (calls win_enter unconditionally even when goto_tabpage_tp's CHECK_CMDWIN
-- emsg'd). We should probably just remove CHECK_CMDWIN from goto_tabpage_tp. #40407
pcall(api.nvim_set_current_win, cmdwin_win)
eq(cmdwin_win, api.nvim_get_current_win())
-- But others, like nvim_buf_set_lines(), which just changes text, is OK.
-- nvim_buf_set_lines() in the cmdwin buffer is OK.
api.nvim_buf_set_lines(0, 0, -1, 1, { 'wow!' })
eq({ 'wow!' }, api.nvim_buf_get_lines(0, 0, -1, 1))
+1
View File
@@ -623,6 +623,7 @@ endfunc
" Test for ":all" not working when in the cmdline window
func Test_all_not_allowed_from_cmdwin()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
au BufEnter * all
next x
" Use try/catch here, somehow assert_fails() doesn't work on MS-Windows
+7
View File
@@ -3911,6 +3911,9 @@ endfunc
" Fuzzer found some strange combination that caused a crash.
func Test_autocmd_normal_mess()
" Uses `q/` (cmdwin) in autocmd; with non-blocking cmdwin (#40312) the
" expected E1159 path now hits E1513 (winfixbuf) instead.
throw 'Skipped: Nvim supports cmdwin freedom #40312'
" For unknown reason this hangs on MS-Windows
CheckNotMSWindows
@@ -3930,6 +3933,7 @@ func Test_autocmd_normal_mess()
endfunc
func Test_autocmd_closing_cmdwin()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
" For unknown reason this hangs on MS-Windows
CheckNotMSWindows
@@ -4082,6 +4086,9 @@ endfunc
" Test for ModeChanged pattern
func Test_mode_changes()
" Asserts `n -> c -> n` mode transitions for `q:<C-C>`, but with the
" non-blocking cmdwin (#40312) `q:` enters cmdwin normal mode, not cmdline.
throw 'Skipped: Nvim supports cmdwin freedom #40312'
let g:index = 0
let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'noV', 'n', 'V', 'v', 's', 'n']
func! TestMode()
+9
View File
@@ -1722,6 +1722,7 @@ func Test_getcmdtype_getcmdprompt()
endfunc
func Test_getcmdwintype()
throw "Skipped: Nvim supports cmdwin freedom #40312"
call feedkeys("q/:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
call assert_equal('/', a)
@@ -1738,6 +1739,7 @@ func Test_getcmdwintype()
endfunc
func Test_getcmdwin_autocmd()
throw "Skipped: Nvim supports cmdwin freedom #40312"
let s:seq = []
augroup CmdWin
au WinEnter * call add(s:seq, 'WinEnter ' .. win_getid())
@@ -1854,6 +1856,7 @@ func Test_cmdline_overstrike()
endfunc
func Test_cmdwin_bug()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
let winid = win_getid()
sp
try
@@ -1955,6 +1958,7 @@ func Test_buffers_lastused()
endfunc
func Test_cmdwin_feedkeys()
throw "Skipped: Nvim supports cmdwin freedom #40312"
" This should not generate E488
call feedkeys("q:\<CR>", 'x')
" Using feedkeys with q: only should automatically close the cmd window
@@ -1966,6 +1970,7 @@ endfunc
" Tests for the issues fixed in 7.4.441.
" When 'cedit' is set to Ctrl-C, opening the command window hangs Vim
func Test_cmdwin_cedit()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
exe "set cedit=\<C-c>"
normal! :
call assert_equal(1, winnr('$'))
@@ -2044,6 +2049,7 @@ func Test_cmdline_expand_special()
endfunc
func Test_cmdwin_jump_to_win()
throw "Skipped: Nvim supports cmdwin freedom #40312"
call assert_fails('call feedkeys("q:\<C-W>\<C-W>\<CR>", "xt")', 'E11:')
new
set modified
@@ -2060,6 +2066,7 @@ func Test_cmdwin_jump_to_win()
endfunc
func Test_cmdwin_tabpage()
throw "Skipped: Nvim supports cmdwin freedom #40312"
tabedit
call assert_fails("silent norm q/g :I\<Esc>", 'E11:')
tabclose!
@@ -2553,6 +2560,7 @@ endfunc
" Test for normal mode commands not supported in the cmd window
func Test_cmdwin_blocked_commands()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
call assert_fails('call feedkeys("q:\<C-T>\<CR>", "xt")', 'E11:')
call assert_fails('call feedkeys("q:\<C-]>\<CR>", "xt")', 'E11:')
call assert_fails('call feedkeys("q:\<C-^>\<CR>", "xt")', 'E11:')
@@ -2584,6 +2592,7 @@ endfunc
" Close the Cmd-line window in insert mode using CTRL-C
func Test_cmdwin_insert_mode_close()
throw "Skipped: Nvim supports cmdwin freedom #40312"
%bw!
let s = ''
exe "normal q:a\<C-C>let s='Hello'\<CR>"
+6
View File
@@ -24,12 +24,14 @@ endfunc
" Check that a :normal command can be used to stop Visual mode without side
" effects.
func Test_normal_escape()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
call feedkeys("q:i\" foo\<Esc>:normal! \<C-V>\<Esc>\<CR>:\" bar\<CR>", 'ntx')
call assert_equal('" bar', @:)
endfunc
" This was using a pointer to a freed buffer
func Test_cmdwin_freed_buffer_ptr()
throw "Skipped: Nvim supports cmdwin freedom #40312"
" this does not work on MS-Windows because renaming an open file fails
CheckNotMSWindows
@@ -94,6 +96,7 @@ func Test_cmdwin_restore_heights()
endfunc
func Test_cmdwin_temp_curwin()
throw "Skipped: Nvim supports cmdwin freedom #40312"
func CheckWraps(expect_wrap)
setlocal textwidth=0 wrapmargin=1
@@ -128,6 +131,7 @@ func Test_cmdwin_temp_curwin()
endfunc
func Test_cmdwin_interrupted()
throw "Skipped: Nvim supports cmdwin freedom #40312"
func CheckInterrupted()
call feedkeys("q::call assert_equal('', getcmdwintype())\<CR>:call assert_equal('', getcmdtype())\<CR>:q<CR>", 'ntx')
endfunc
@@ -193,6 +197,7 @@ func Test_cmdwin_interrupted()
endfunc
func Test_cmdwin_existing_bufname()
throw "Skipped: Nvim supports cmdwin freedom #40312"
func CheckName()
call assert_equal(1, getbufinfo('')[0].command)
call assert_equal(0, getbufinfo('[Command Line]')[0].command)
@@ -235,6 +240,7 @@ func Test_cmdwin_showcmd()
endfunc
func Test_cmdwin_cursor_position()
throw "Skipped: Nvim supports cmdwin freedom #40312"
" When the cmdline fills the screen width exactly, pressing CTRL-F to open
" the cmdwin should place the cursor on the last character, not past it.
let cmd = 'echo "' .. repeat('a', &columns - 8) .. '"'
+1
View File
@@ -22,6 +22,7 @@ func Test_load_menu()
endfunc
func Test_buffer_menu_special_buffers()
throw "Skipped: Nvim supports cmdwin freedom #40312"
" Load in runtime menus
try
source $VIMRUNTIME/menu.vim
+3
View File
@@ -3081,6 +3081,9 @@ endfunc
" Test for CTRL-\ commands
func Test_normal40_ctrl_bsl()
" Nvim #40312: includes a cmdwin assertion that doesn't translate
" (cmdwin is now a normal window so CTRL-\ CTRL-N is a no-op there).
throw 'Skipped: Nvim supports cmdwin freedom #40312'
new
call append(0, 'here are some words')
exe "norm! 1gg0a\<C-\>\<C-N>"
+1
View File
@@ -2296,6 +2296,7 @@ endfunc
" Test that Vim does not crash when completion inside cmdwin opens a 'info'
" preview window.
func Test_popup_complete_cmdwin_preview()
throw "Skipped: Nvim supports cmdwin freedom #40312"
func! CompleteWithPreview(findstart, base)
if a:findstart
return getline('.')->strpart(0, col('.') - 1)
+1
View File
@@ -711,6 +711,7 @@ endfunc
" Test for closing the tab page from a command window
func Test_tabpage_close_cmdwin()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
tabnew
call feedkeys("q/:tabclose\<CR>\<Esc>", 'xt')
call assert_equal(2, tabpagenr('$'))
+1
View File
@@ -836,6 +836,7 @@ endfunc
" Test for using buffer-local user command from cmdwin.
func Test_buflocal_usercmd_cmdwin()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
new
command -buffer TestCmd edit Test
" This used to crash Vim
+4
View File
@@ -1313,6 +1313,7 @@ func Run_noroom_for_newwindow_test(dir_arg)
endfunc
func Test_split_cmds_with_no_room()
throw "Skipped: Nvim supports cmdwin freedom #40312"
call Run_noroom_for_newwindow_test('h')
call Run_noroom_for_newwindow_test('v')
endfunc
@@ -1765,6 +1766,7 @@ endfunc
" tabline, for each possible value of 'laststatus', 'scrolloff',
" 'equalalways', and with the cursor at the top, middle and bottom.
func Test_splitkeep_options()
throw "Skipped: Nvim supports cmdwin freedom #40312"
" disallow window resizing
" let save_WS = &t_WS
" set t_WS=
@@ -1894,6 +1896,7 @@ func Test_splitkeep_options()
endfunc
func Test_splitkeep_cmdwin_cursor_position()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
set splitkeep=screen
call setline(1, range(&lines))
@@ -2205,6 +2208,7 @@ func Test_autocmd_window_force_room()
endfunc
func Test_win_gotoid_splitmove_textlock_cmdwin()
throw 'Skipped: Nvim supports cmdwin freedom #40312'
call setline(1, 'foo')
new
let curwin = win_getid()