mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge #15440 close 'shell' :terminal automatically
This commit is contained in:
		| @@ -190,6 +190,10 @@ The following changes to existing APIs or features add new behavior. | |||||||
|   supports it, unless |'keywordprg'| was customized before calling |   supports it, unless |'keywordprg'| was customized before calling | ||||||
|   |vim.lsp.start()|. |   |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* | REMOVED FEATURES                                                 *news-removed* | ||||||
|  |  | ||||||
|   | |||||||
| @@ -249,6 +249,10 @@ gx			Opens the current filepath or URL (decided by | |||||||
| 			Fails if changes have been made to the current buffer, | 			Fails if changes have been made to the current buffer, | ||||||
| 			unless 'hidden' is set. | 			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: > | 			To enter |Terminal-mode| automatically: > | ||||||
| 			      autocmd TermOpen * startinsert | 			      autocmd TermOpen * startinsert | ||||||
| < | < | ||||||
|   | |||||||
| @@ -133,6 +133,8 @@ remove them and ":autocmd {group}" to see how they're defined. | |||||||
|  |  | ||||||
| nvim_terminal: | nvim_terminal: | ||||||
| - BufReadCmd: Treats "term://" buffers as |terminal| buffers. |terminal-start| | - 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: | nvim_cmdwin: | ||||||
| - CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|. | - CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|. | ||||||
|   | |||||||
| @@ -1107,13 +1107,26 @@ end | |||||||
|  |  | ||||||
| function vim._init_default_autocmds() | function vim._init_default_autocmds() | ||||||
|   local nvim_terminal_augroup = vim.api.nvim_create_augroup('nvim_terminal', {}) |   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://*', |     pattern = 'term://*', | ||||||
|     group = nvim_terminal_augroup, |     group = nvim_terminal_augroup, | ||||||
|     nested = true, |     nested = true, | ||||||
|     command = "if !exists('b:term_title')|call termopen(matchstr(expand(\"<amatch>\"), '\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), {'cwd': expand(get(matchlist(expand(\"<amatch>\"), '\\c\\mterm://\\(.\\{-}\\)//'), 1, ''))})", |     command = "if !exists('b:term_title')|call termopen(matchstr(expand(\"<amatch>\"), '\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), {'cwd': expand(get(matchlist(expand(\"<amatch>\"), '\\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 = '[:>]', |     pattern = '[:>]', | ||||||
|     group = vim.api.nvim_create_augroup('nvim_cmdwin', {}), |     group = vim.api.nvim_create_augroup('nvim_cmdwin', {}), | ||||||
|     command = 'syntax sync minlines=1 maxlines=1', |     command = 'syntax sync minlines=1 maxlines=1', | ||||||
|   | |||||||
| @@ -103,12 +103,13 @@ describe('autocmd TermClose', function() | |||||||
|  |  | ||||||
|   it('reports the correct <abuf>', function() |   it('reports the correct <abuf>', function() | ||||||
|     command('set hidden') |     command('set hidden') | ||||||
|  |     command('set shellcmdflag=EXE') | ||||||
|     command('autocmd TermClose * let g:abuf = expand("<abuf>")') |     command('autocmd TermClose * let g:abuf = expand("<abuf>")') | ||||||
|     command('edit foo') |     command('edit foo') | ||||||
|     command('edit bar') |     command('edit bar') | ||||||
|     eq(2, eval('bufnr("%")')) |     eq(2, eval('bufnr("%")')) | ||||||
|  |  | ||||||
|     command('terminal') |     command('terminal ls') | ||||||
|     retry(nil, nil, function() eq(3, eval('bufnr("%")')) end) |     retry(nil, nil, function() eq(3, eval('bufnr("%")')) end) | ||||||
|  |  | ||||||
|     command('buffer 1') |     command('buffer 1') | ||||||
|   | |||||||
| @@ -137,23 +137,29 @@ describe(':terminal (with fake shell)', function() | |||||||
|     -- shell-test.c is a fake shell that prints its arguments and exits. |     -- 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', 'shell', testprg('shell-test'), {}) | ||||||
|     nvim('set_option_value', 'shellcmdflag', 'EXE', {}) |     nvim('set_option_value', 'shellcmdflag', 'EXE', {}) | ||||||
|  |     nvim('set_option_value', 'shellxquote', '', {}) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   -- Invokes `:terminal {cmd}` using a fake shell (shell-test.c) which prints |   -- 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) |   local function terminal_with_fake_shell(cmd) | ||||||
|     feed_command("terminal "..(cmd and cmd or "")) |     feed_command("terminal "..(cmd and cmd or "")) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   it('with no argument, acts like termopen()', function() |   it('with no argument, acts like termopen()', function() | ||||||
|     skip(is_os('win')) |     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() |     retry(nil, 4 * screen.timeout, function() | ||||||
|     screen:expect([[ |     screen:expect([[ | ||||||
|       ^ready $                                           | |       ^                                                  | | ||||||
|       [Process exited 0]                                | |       [Process exited 1]                                | | ||||||
|                                                         | |                                                         | | ||||||
|       :terminal                                         | |       :terminal 1                                       | | ||||||
|     ]]) |     ]]) | ||||||
|     end) |     end) | ||||||
|   end) |   end) | ||||||
| @@ -245,12 +251,13 @@ describe(':terminal (with fake shell)', function() | |||||||
|  |  | ||||||
|   it('works with :find', function() |   it('works with :find', function() | ||||||
|     skip(is_os('win')) |     skip(is_os('win')) | ||||||
|     terminal_with_fake_shell() |     nvim('set_option_value', 'shellcmdflag', 'EXIT', {}) | ||||||
|  |     terminal_with_fake_shell(1) | ||||||
|     screen:expect([[ |     screen:expect([[ | ||||||
|       ^ready $                                           | |       ^                                                  | | ||||||
|       [Process exited 0]                                | |       [Process exited 1]                                | | ||||||
|                                                         | |                                                         | | ||||||
|       :terminal                                         | |       :terminal 1                                       | | ||||||
|     ]]) |     ]]) | ||||||
|     eq('term://', string.match(eval('bufname("%")'), "^term://")) |     eq('term://', string.match(eval('bufname("%")'), "^term://")) | ||||||
|     feed([[<C-\><C-N>]]) |     feed([[<C-\><C-N>]]) | ||||||
|   | |||||||
| @@ -514,7 +514,9 @@ describe("'scrollback' option", function() | |||||||
|  |  | ||||||
|     -- _Global_ scrollback=-1 defaults :terminal to 10_000. |     -- _Global_ scrollback=-1 defaults :terminal to 10_000. | ||||||
|     command('setglobal scrollback=-1') |     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', {})) |     eq(10000, meths.get_option_value('scrollback', {})) | ||||||
|  |  | ||||||
|     -- _Local_ scrollback=-1 in :terminal forces the _maximum_. |     -- _Local_ scrollback=-1 in :terminal forces the _maximum_. | ||||||
|   | |||||||
| @@ -2075,26 +2075,26 @@ describe('TUI FocusGained/FocusLost', function() | |||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('in terminal-mode', function() |   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(':set noshowmode laststatus=0\n') | ||||||
|  |  | ||||||
|     feed_data(':terminal\n') |     feed_data(':terminal zia\n') | ||||||
|     -- Wait for terminal to be ready. |     -- Wait for terminal to be ready. | ||||||
|     screen:expect{grid=[[ |     screen:expect{grid=[[ | ||||||
|       {1:r}eady $                                           | |       {1:r}eady $ zia                                       | | ||||||
|  |                                                         | | ||||||
|       [Process exited 0]                                | |       [Process exited 0]                                | | ||||||
|                                                         | |                                                         | | ||||||
|                                                         | |                                                         | | ||||||
|                                                         | |       :terminal zia                                     | | ||||||
|       :terminal                                         | |  | ||||||
|       {3:-- TERMINAL --}                                    | |       {3:-- TERMINAL --}                                    | | ||||||
|     ]]} |     ]]} | ||||||
|  |  | ||||||
|     feed_data('\027[I') |     feed_data('\027[I') | ||||||
|     screen:expect{grid=[[ |     screen:expect{grid=[[ | ||||||
|       {1:r}eady $                                           | |       {1:r}eady $ zia                                       | | ||||||
|       [Process exited 0]                                | |  | ||||||
|                                                         | |                                                         | | ||||||
|  |       [Process exited 0]                                | | ||||||
|                                                         | |                                                         | | ||||||
|                                                         | |                                                         | | ||||||
|       gained                                            | |       gained                                            | | ||||||
| @@ -2103,9 +2103,9 @@ describe('TUI FocusGained/FocusLost', function() | |||||||
|  |  | ||||||
|     feed_data('\027[O') |     feed_data('\027[O') | ||||||
|     screen:expect([[ |     screen:expect([[ | ||||||
|       {1:r}eady $                                           | |       {1:r}eady $ zia                                       | | ||||||
|       [Process exited 0]                                | |  | ||||||
|                                                         | |                                                         | | ||||||
|  |       [Process exited 0]                                | | ||||||
|                                                         | |                                                         | | ||||||
|                                                         | |                                                         | | ||||||
|       lost                                              | |       lost                                              | | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Justin M. Keyes
					Justin M. Keyes