mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	fix(process): start pty process eof timer on main thread (#27625)
This commit is contained in:
		@@ -23,6 +23,17 @@ static void CALLBACK pty_process_finish1(void *context, BOOLEAN unused)
 | 
			
		||||
  Process *proc = (Process *)ptyproc;
 | 
			
		||||
 | 
			
		||||
  os_conpty_free(ptyproc->conpty);
 | 
			
		||||
  // NB: pty_process_finish1() is called on a separate thread,
 | 
			
		||||
  // but the timer only works properly if it's started by the main thread.
 | 
			
		||||
  loop_schedule_fast(proc->loop, event_create(start_wait_eof_timer, ptyproc));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void start_wait_eof_timer(void **argv)
 | 
			
		||||
  FUNC_ATTR_NONNULL_ALL
 | 
			
		||||
{
 | 
			
		||||
  PtyProcess *ptyproc = (PtyProcess *)argv[0];
 | 
			
		||||
  Process *proc = (Process *)ptyproc;
 | 
			
		||||
 | 
			
		||||
  uv_timer_init(&proc->loop->uv, &ptyproc->wait_eof_timer);
 | 
			
		||||
  ptyproc->wait_eof_timer.data = (void *)ptyproc;
 | 
			
		||||
  uv_timer_start(&ptyproc->wait_eof_timer, wait_eof_timer_cb, 200, 200);
 | 
			
		||||
 
 | 
			
		||||
@@ -1239,7 +1239,6 @@ describe('pty process teardown', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('does not prevent/delay exit. #4798 #4900', function()
 | 
			
		||||
    skip(is_os('win'))
 | 
			
		||||
    -- Use a nested nvim (in :term) to test without --headless.
 | 
			
		||||
    fn.termopen({
 | 
			
		||||
      helpers.nvim_prog,
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,6 @@ local mkdir = helpers.mkdir
 | 
			
		||||
 | 
			
		||||
local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec'
 | 
			
		||||
 | 
			
		||||
if helpers.skip(helpers.is_os('win')) then
 | 
			
		||||
  return
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe(':mksession', function()
 | 
			
		||||
  local session_file = file_prefix .. '.vim'
 | 
			
		||||
  local tab_dir = file_prefix .. '.d'
 | 
			
		||||
@@ -73,25 +69,22 @@ describe(':mksession', function()
 | 
			
		||||
    eq(expected_buf_count, #api.nvim_list_bufs())
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  it(
 | 
			
		||||
    'do not restore :terminal if not set in sessionoptions, terminal in current window #13078',
 | 
			
		||||
    function()
 | 
			
		||||
      local tmpfile_base = file_prefix .. '-tmpfile'
 | 
			
		||||
      command('edit ' .. tmpfile_base)
 | 
			
		||||
      command('terminal')
 | 
			
		||||
  it('do not restore :terminal if not set in sessionoptions, terminal in curwin #13078', function()
 | 
			
		||||
    local tmpfile_base = file_prefix .. '-tmpfile'
 | 
			
		||||
    command('edit ' .. tmpfile_base)
 | 
			
		||||
    command('terminal')
 | 
			
		||||
 | 
			
		||||
      local buf_count = #api.nvim_list_bufs()
 | 
			
		||||
      eq(2, buf_count)
 | 
			
		||||
    local buf_count = #api.nvim_list_bufs()
 | 
			
		||||
    eq(2, buf_count)
 | 
			
		||||
 | 
			
		||||
      eq('terminal', api.nvim_get_option_value('buftype', {}))
 | 
			
		||||
    eq('terminal', api.nvim_get_option_value('buftype', {}))
 | 
			
		||||
 | 
			
		||||
      test_terminal_session_disabled(2)
 | 
			
		||||
    test_terminal_session_disabled(2)
 | 
			
		||||
 | 
			
		||||
      -- no terminal should be set. As a side effect we end up with a blank buffer
 | 
			
		||||
      eq('', api.nvim_get_option_value('buftype', { buf = api.nvim_list_bufs()[1] }))
 | 
			
		||||
      eq('', api.nvim_get_option_value('buftype', { buf = api.nvim_list_bufs()[2] }))
 | 
			
		||||
    end
 | 
			
		||||
  )
 | 
			
		||||
    -- no terminal should be set. As a side effect we end up with a blank buffer
 | 
			
		||||
    eq('', api.nvim_get_option_value('buftype', { buf = api.nvim_list_bufs()[1] }))
 | 
			
		||||
    eq('', api.nvim_get_option_value('buftype', { buf = api.nvim_list_bufs()[2] }))
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('do not restore :terminal if not set in sessionoptions, terminal hidden #13078', function()
 | 
			
		||||
    command('terminal')
 | 
			
		||||
@@ -173,6 +166,8 @@ describe(':mksession', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('restores CWD for :terminal buffers #11288', function()
 | 
			
		||||
    skip(is_os('win'), 'causes rmdir() to fail')
 | 
			
		||||
 | 
			
		||||
    local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '')
 | 
			
		||||
    cwd_dir = cwd_dir:gsub([[\]], '/') -- :mksession always uses unix slashes.
 | 
			
		||||
    local session_path = cwd_dir .. '/' .. session_file
 | 
			
		||||
 
 | 
			
		||||
@@ -247,7 +247,6 @@ describe(':terminal buffer', function()
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('requires bang (!) to close a running job #15402', function()
 | 
			
		||||
    skip(is_os('win'), 'Test freezes the CI and makes it time out')
 | 
			
		||||
    eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
 | 
			
		||||
    for _, cmd in ipairs({ 'bdelete', '%bdelete', 'bwipeout', 'bunload' }) do
 | 
			
		||||
      matches(
 | 
			
		||||
 
 | 
			
		||||
@@ -170,20 +170,18 @@ local function test_terminal_with_fake_shell(backslash)
 | 
			
		||||
    screen:attach({ rgb = false })
 | 
			
		||||
    api.nvim_set_option_value('shell', shell_path, {})
 | 
			
		||||
    api.nvim_set_option_value('shellcmdflag', 'EXE', {})
 | 
			
		||||
    api.nvim_set_option_value('shellxquote', '', {})
 | 
			
		||||
    api.nvim_set_option_value('shellxquote', '', {}) -- win: avoid extra quotes
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('with no argument, acts like termopen()', function()
 | 
			
		||||
    command('autocmd! nvim_terminal TermClose')
 | 
			
		||||
    feed_command('terminal')
 | 
			
		||||
    retry(nil, 4 * screen.timeout, function()
 | 
			
		||||
      screen:expect([[
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^ready $                                           |
 | 
			
		||||
      [Process exited 0]                                |
 | 
			
		||||
                                                        |
 | 
			
		||||
      :terminal                                         |
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it("with no argument, and 'shell' is set to empty string", function()
 | 
			
		||||
@@ -207,7 +205,6 @@ local function test_terminal_with_fake_shell(backslash)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('executes a given command through the shell', function()
 | 
			
		||||
    command('set shellxquote=') -- win: avoid extra quotes
 | 
			
		||||
    feed_command('terminal echo hi')
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^ready $ echo hi                                   |
 | 
			
		||||
@@ -219,7 +216,6 @@ local function test_terminal_with_fake_shell(backslash)
 | 
			
		||||
 | 
			
		||||
  it("executes a given command through the shell, when 'shell' has arguments", function()
 | 
			
		||||
    api.nvim_set_option_value('shell', shell_path .. ' -t jeff', {})
 | 
			
		||||
    command('set shellxquote=') -- win: avoid extra quotes
 | 
			
		||||
    feed_command('terminal echo hi')
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^jeff $ echo hi                                    |
 | 
			
		||||
@@ -230,7 +226,6 @@ local function test_terminal_with_fake_shell(backslash)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('allows quotes and slashes', function()
 | 
			
		||||
    command('set shellxquote=') -- win: avoid extra quotes
 | 
			
		||||
    feed_command([[terminal echo 'hello' \ "world"]])
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^ready $ echo 'hello' \ "world"                    |
 | 
			
		||||
@@ -287,16 +282,13 @@ local function test_terminal_with_fake_shell(backslash)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('works with gf', function()
 | 
			
		||||
    command('set shellxquote=') -- win: avoid extra quotes
 | 
			
		||||
    feed_command([[terminal echo "scripts/shadacat.py"]])
 | 
			
		||||
    retry(nil, 4 * screen.timeout, function()
 | 
			
		||||
      screen:expect([[
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^ready $ echo "scripts/shadacat.py"                |
 | 
			
		||||
                                                        |
 | 
			
		||||
      [Process exited 0]                                |
 | 
			
		||||
      :terminal echo "scripts/shadacat.py"              |
 | 
			
		||||
    ]])
 | 
			
		||||
    end)
 | 
			
		||||
    feed([[<C-\><C-N>]])
 | 
			
		||||
    eq('term://', string.match(eval('bufname("%")'), '^term://'))
 | 
			
		||||
    feed([[ggf"lgf]])
 | 
			
		||||
@@ -313,6 +305,22 @@ local function test_terminal_with_fake_shell(backslash)
 | 
			
		||||
      terminal]])
 | 
			
		||||
    end
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  describe('exit does not have long delay #27615', function()
 | 
			
		||||
    for _, ut in ipairs({ 5, 50, 500, 5000, 50000, 500000 }) do
 | 
			
		||||
      it(('with updatetime=%d'):format(ut), function()
 | 
			
		||||
        api.nvim_set_option_value('updatetime', ut, {})
 | 
			
		||||
        api.nvim_set_option_value('shellcmdflag', 'EXIT', {})
 | 
			
		||||
        feed_command('terminal 42')
 | 
			
		||||
        screen:expect([[
 | 
			
		||||
          ^                                                  |
 | 
			
		||||
          [Process exited 42]                               |
 | 
			
		||||
                                                            |
 | 
			
		||||
          :terminal 42                                      |
 | 
			
		||||
        ]])
 | 
			
		||||
      end)
 | 
			
		||||
    end
 | 
			
		||||
  end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe(':terminal (with fake shell)', function()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user