Files
neovim/test/functional/legacy/global_spec.lua
Justin M. Keyes 359459dec6 refactor(exmode): Ex-mode as cmdwin + Lua #40991
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
  that can be achieved with `cmdwin`, which also gains extra UX
  benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
  scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
  "Entering Ex mode" message).

Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
  cmdwin" in Lua.
  - "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
  - Drop POSIX Ex-mode quirks.

Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
  pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
  stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
  (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).

Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=>stdout
- -V1=>stderr
- CRLF input
- continue-after-error and exit codes

Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
  waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
  answers: Nvim stops at end-of-input, skipping the rest of the script,
  exit 0. Use ":lua io.read()" instead.
  - If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
  cmdline input from stdin.
2026-07-27 06:25:21 -04:00

47 lines
1.7 KiB
Lua

local n = require('test.functional.testnvim')()
local t = require('test.testutil')
local Screen = require('test.functional.ui.screen')
local describe, it, before_each = t.describe, t.it, t.before_each
local clear = n.clear
local exec = n.exec
local feed = n.feed
local poke_eventloop = n.poke_eventloop
before_each(clear)
describe(':global', function()
-- oldtest: Test_interrupt_global()
it('can be interrupted using Ctrl-C in cmdline mode vim-patch:9.0.0082', function()
local screen = Screen.new(75, 6)
exec([[
set nohlsearch noincsearch
cnoremap ; <Cmd>sleep 10<CR>
call setline(1, repeat(['foo'], 5))
]])
feed(':g/foo/norm :<C-V>;<CR>')
poke_eventloop() -- Wait for :sleep to start
feed('<C-C>')
screen:expect([[
^foo |
foo |*4
{9:Interrupted} |
]])
-- Also test in Ex mode (keep-open cmdwin REPL)
feed('gQg/foo/norm :<C-V>;<CR>')
poke_eventloop() -- Wait for :sleep to start
feed('<C-C>')
screen:expect([[
foo |
{2:[No Name] [+] }|
{1::}" Keyboard interrupt |
{1::}^ |
{3:[Command Line] }|
{5:-- INSERT --} |
]])
end)
end)