mirror of
https://github.com/neovim/neovim.git
synced 2026-08-27 09:31:47 +00: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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user