diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 3aacf1e8ee..e9c493479c 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -190,6 +190,10 @@ The following changes to existing APIs or features add new behavior. supports it, unless |'keywordprg'| was customized before calling |vim.lsp.start()|. +• Terminal buffers started with no arguments (and use 'shell') close + automatically if the job exited without error, eliminating the (often + unwanted) "[Process exited 0]" message. + ============================================================================== REMOVED FEATURES *news-removed* diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 52e8f4d86c..33f57580c7 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -249,6 +249,10 @@ gx Opens the current filepath or URL (decided by Fails if changes have been made to the current buffer, unless 'hidden' is set. + If {cmd} is omitted, and the 'shell' job exits with no + error, the buffer is closed automatically + |default-autocmds|. + To enter |Terminal-mode| automatically: > autocmd TermOpen * startinsert < diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 9569c38b85..d288f31828 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -133,6 +133,8 @@ remove them and ":autocmd {group}" to see how they're defined. nvim_terminal: - BufReadCmd: Treats "term://" buffers as |terminal| buffers. |terminal-start| +- TermClose: A |terminal| buffer started with no arguments (which thus uses + 'shell') and which exits with no error is closed automatically. nvim_cmdwin: - CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|. diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 58fbc923e1..8c10cc7da3 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -1107,13 +1107,26 @@ end function vim._init_default_autocmds() local nvim_terminal_augroup = vim.api.nvim_create_augroup('nvim_terminal', {}) - vim.api.nvim_create_autocmd({ 'bufreadcmd' }, { + vim.api.nvim_create_autocmd({ 'BufReadCmd' }, { pattern = 'term://*', group = nvim_terminal_augroup, nested = true, command = "if !exists('b:term_title')|call termopen(matchstr(expand(\"\"), '\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), {'cwd': expand(get(matchlist(expand(\"\"), '\\c\\mterm://\\(.\\{-}\\)//'), 1, ''))})", }) - vim.api.nvim_create_autocmd({ 'cmdwinenter' }, { + vim.api.nvim_create_autocmd({ 'TermClose' }, { + group = nvim_terminal_augroup, + desc = 'Automatically close terminal buffers when started with no arguments and exiting without an error', + callback = function(args) + if vim.v.event.status == 0 then + local info = vim.api.nvim_get_chan_info(vim.bo[args.buf].channel) + local argv = info.argv or {} + if #argv == 1 and argv[1] == vim.o.shell then + vim.cmd({ cmd = 'bdelete', args = { args.buf }, bang = true }) + end + end + end, + }) + vim.api.nvim_create_autocmd({ 'CmdwinEnter' }, { pattern = '[:>]', group = vim.api.nvim_create_augroup('nvim_cmdwin', {}), command = 'syntax sync minlines=1 maxlines=1', diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index 359203f945..802020494b 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -103,12 +103,13 @@ describe('autocmd TermClose', function() it('reports the correct ', function() command('set hidden') + command('set shellcmdflag=EXE') command('autocmd TermClose * let g:abuf = expand("")') command('edit foo') command('edit bar') eq(2, eval('bufnr("%")')) - command('terminal') + command('terminal ls') retry(nil, nil, function() eq(3, eval('bufnr("%")')) end) command('buffer 1') diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 5204b61f57..6020a12ddb 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -137,23 +137,29 @@ describe(':terminal (with fake shell)', function() -- shell-test.c is a fake shell that prints its arguments and exits. nvim('set_option_value', 'shell', testprg('shell-test'), {}) nvim('set_option_value', 'shellcmdflag', 'EXE', {}) + nvim('set_option_value', 'shellxquote', '', {}) end) -- Invokes `:terminal {cmd}` using a fake shell (shell-test.c) which prints - -- the {cmd} and exits immediately . + -- the {cmd} and exits immediately. + -- When no argument is given and the exit code is zero, the terminal buffer + -- closes automatically. local function terminal_with_fake_shell(cmd) feed_command("terminal "..(cmd and cmd or "")) end it('with no argument, acts like termopen()', function() skip(is_os('win')) - terminal_with_fake_shell() + -- Use the EXIT subcommand to end the process with a non-zero exit code to + -- prevent the buffer from closing automatically + nvim('set_option_value', 'shellcmdflag', 'EXIT', {}) + terminal_with_fake_shell(1) retry(nil, 4 * screen.timeout, function() screen:expect([[ - ^ready $ | - [Process exited 0] | + ^ | + [Process exited 1] | | - :terminal | + :terminal 1 | ]]) end) end) @@ -245,12 +251,13 @@ describe(':terminal (with fake shell)', function() it('works with :find', function() skip(is_os('win')) - terminal_with_fake_shell() + nvim('set_option_value', 'shellcmdflag', 'EXIT', {}) + terminal_with_fake_shell(1) screen:expect([[ - ^ready $ | - [Process exited 0] | + ^ | + [Process exited 1] | | - :terminal | + :terminal 1 | ]]) eq('term://', string.match(eval('bufname("%")'), "^term://")) feed([[]]) diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index d20f5177b8..ba0b663285 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -514,7 +514,9 @@ describe("'scrollback' option", function() -- _Global_ scrollback=-1 defaults :terminal to 10_000. command('setglobal scrollback=-1') - command('terminal') + -- Pass a command to prevent the terminal buffer from automatically + -- closing. The ':' command is just a no-op. + command('terminal :') eq(10000, meths.get_option_value('scrollback', {})) -- _Local_ scrollback=-1 in :terminal forces the _maximum_. diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index e8e65d18fa..1958281592 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2075,26 +2075,26 @@ describe('TUI FocusGained/FocusLost', function() end) it('in terminal-mode', function() - feed_data(':set shell='..testprg('shell-test')..'\n') + feed_data(':set shell='..testprg('shell-test')..' shellcmdflag=EXE\n') feed_data(':set noshowmode laststatus=0\n') - feed_data(':terminal\n') + feed_data(':terminal zia\n') -- Wait for terminal to be ready. screen:expect{grid=[[ - {1:r}eady $ | + {1:r}eady $ zia | + | [Process exited 0] | | | - | - :terminal | + :terminal zia | {3:-- TERMINAL --} | ]]} feed_data('\027[I') screen:expect{grid=[[ - {1:r}eady $ | - [Process exited 0] | + {1:r}eady $ zia | | + [Process exited 0] | | | gained | @@ -2103,9 +2103,9 @@ describe('TUI FocusGained/FocusLost', function() feed_data('\027[O') screen:expect([[ - {1:r}eady $ | - [Process exited 0] | + {1:r}eady $ zia | | + [Process exited 0] | | | lost |