mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +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