mirror of
https://github.com/neovim/neovim.git
synced 2026-10-25 23:20:23 -05:00
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:
1 parent
122be61ed2
commit
b2bf7bcfb1
67 files changed
+1005
-1645
No files matched your search
+17
-7
@@ -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
@@ -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
@@ -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|).
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
Generated
+8
-2
@@ -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]()
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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 = ''
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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().
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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).
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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) .. '"'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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('$'))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user