HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //home/ubuntu/neovim/test/functional/ui/embed_spec.lua
local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local Screen = require('test.functional.ui.screen')
local uv = vim.uv

local api = n.api
local feed = n.feed
local eq = t.eq
local neq = t.neq
local clear = n.clear
local ok = t.ok
local fn = n.fn
local nvim_prog = n.nvim_prog
local retry = t.retry
local write_file = t.write_file
local assert_log = t.assert_log
local check_close = n.check_close
local is_os = t.is_os

local testlog = 'Xtest-embed-log'

local function test_embed(ext_linegrid)
  local screen
  local function startup(...)
    clear { args_rm = { '--headless' }, args = { ... } }

    -- attach immediately after startup, for early UI
    screen = Screen.new(60, 8)
    screen:attach { ext_linegrid = ext_linegrid }
    screen:set_default_attr_ids({
      [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
      [2] = { bold = true, foreground = Screen.colors.SeaGreen4 },
      [3] = { bold = true, foreground = Screen.colors.Blue1 },
      [4] = { bold = true, foreground = Screen.colors.Green },
      [5] = { bold = true, reverse = true },
      [6] = { foreground = Screen.colors.NvimLightGrey3, background = Screen.colors.NvimDarkGrey3 },
      [7] = { foreground = Screen.colors.NvimDarkRed },
      [8] = { foreground = Screen.colors.NvimDarkCyan },
    })
  end

  it('can display errors', function()
    startup('--cmd', 'echoerr invalid+')
    screen:expect([[
                                                                  |*4
      {6:                                                            }|
      {7:Error detected while processing pre-vimrc command line:}     |
      {7:E121: Undefined variable: invalid}                           |
      {8:Press ENTER or type command to continue}^                     |
    ]])

    feed('<cr>')
    screen:expect([[
      ^                                                            |
      {3:~                                                           }|*6
                                                                  |
    ]])
  end)

  it("doesn't erase output when setting color scheme", function()
    if t.is_os('openbsd') then
      pending('FIXME #10804')
    end
    startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"')
    screen:expect([[
                                                                  |*3
      {6:                                                            }|
      {7:Error detected while processing pre-vimrc command line:}     |
      {7:foo}                                                         |
      {7:bar}                                                         |
      {8:Press ENTER or type command to continue}^                     |
    ]])
  end)

  it("doesn't erase output when setting Normal colors", function()
    startup('--cmd', 'echoerr "foo"', '--cmd', 'hi Normal guibg=Green', '--cmd', 'echoerr "bar"')
    screen:expect {
      grid = [[
                                                                  |*3
      {6:                                                            }|
      {7:Error detected while processing pre-vimrc command line:}     |
      {7:foo}                                                         |
      {7:bar}                                                         |
      {8:Press ENTER or type command to continue}^                     |
    ]],
      condition = function()
        eq(Screen.colors.Green, screen.default_colors.rgb_bg)
      end,
    }
  end)
end

describe('--embed UI on startup (ext_linegrid=true)', function()
  test_embed(true)
end)
describe('--embed UI on startup (ext_linegrid=false)', function()
  test_embed(false)
end)

describe('--embed UI', function()
  after_each(function()
    check_close()
    os.remove(testlog)
  end)

  it('can pass stdin', function()
    local pipe = assert(uv.pipe())

    local writer = assert(uv.new_pipe(false))
    writer:open(pipe.write)

    clear { args_rm = { '--headless' }, io_extra = pipe.read, env = { NVIM_LOG_FILE = testlog } }

    -- attach immediately after startup, for early UI
    local screen = Screen.new(40, 8)
    screen.rpc_async = true -- Avoid hanging. #24888
    screen:attach { stdin_fd = 3 }
    screen:set_default_attr_ids {
      [1] = { bold = true, foreground = Screen.colors.Blue1 },
      [2] = { bold = true },
    }

    writer:write 'hello nvim\nfrom external input\n'
    writer:shutdown(function()
      writer:close()
    end)

    screen:expect [[
      ^hello nvim                              |
      from external input                     |
      {1:~                                       }|*5
                                              |
    ]]

    -- stdin (rpc input) still works
    feed 'o'
    screen:expect [[
      hello nvim                              |
      ^                                        |
      from external input                     |
      {1:~                                       }|*4
      {2:-- INSERT --}                            |
    ]]

    if not is_os('win') then
      assert_log('Failed to get flags on descriptor 3: Bad file descriptor', testlog, 100)
    end
  end)

  it('can pass stdin to -q - #17523', function()
    write_file(
      'Xbadfile.c',
      [[
      /* some file with an error */
      main() {
        functionCall(arg; arg, arg);
        return 666
      }
      ]]
    )
    finally(function()
      os.remove('Xbadfile.c')
    end)

    local pipe = assert(uv.pipe())

    local writer = assert(uv.new_pipe(false))
    writer:open(pipe.write)

    clear { args_rm = { '--headless' }, args = { '-q', '-' }, io_extra = pipe.read }

    -- attach immediately after startup, for early UI
    local screen = Screen.new(60, 8)
    screen.rpc_async = true -- Avoid hanging. #24888
    screen:attach { stdin_fd = 3 }
    screen:set_default_attr_ids {
      [1] = { bold = true, foreground = Screen.colors.Blue1 },
      [2] = { bold = true },
    }

    writer:write [[Xbadfile.c:4:12: error: expected ';' before '}' token]]
    writer:shutdown(function()
      writer:close()
    end)

    screen:expect [[
      /* some file with an error */                               |
      main() {                                                    |
        functionCall(arg; arg, arg);                              |
        return 66^6                                                |
      }                                                           |
      {1:~                                                           }|*2
      (1 of 1): error: expected ';' before '}' token              |
    ]]

    -- stdin (rpc input) still works
    feed 'A'
    screen:expect [[
      /* some file with an error */                               |
      main() {                                                    |
        functionCall(arg; arg, arg);                              |
        return 666^                                                |
      }                                                           |
      {1:~                                                           }|*2
      {2:-- INSERT --}                                                |
    ]]

    eq('-', api.nvim_get_option_value('errorfile', {}))
  end)

  it('only sets background colors once even if overridden', function()
    local screen, current, seen
    local function handle_default_colors_set(_, _, rgb_bg, _, _, _)
      seen[rgb_bg] = true
      current = rgb_bg
    end
    local function startup(...)
      seen = {}
      current = nil
      clear { args_rm = { '--headless' }, args = { ... } }

      -- attach immediately after startup, for early UI
      screen = Screen.new(40, 8)
      screen._handle_default_colors_set = handle_default_colors_set
      screen:attach()
    end

    startup()
    screen:expect {
      condition = function()
        eq(16777215, current)
      end,
    }
    eq({ [16777215] = true }, seen)

    -- NB: by accident how functional/testutil.lua currently handles the default color scheme, the
    -- above is sufficient to test the behavior. But in case that workaround is removed, we need
    -- a test with an explicit override like below, so do it to remain safe.
    startup('--cmd', 'hi NORMAL guibg=#FF00FF')
    screen:expect {
      condition = function()
        eq(16711935, current)
      end,
    }
    eq({ [16711935] = true }, seen) -- we only saw the last one, despite 16777215 was set internally earlier
  end)

  it('updates cwd of attached UI #21771', function()
    clear { args_rm = { '--headless' } }

    local screen = Screen.new(40, 8)
    screen:attach()

    screen:expect {
      condition = function()
        eq(t.paths.test_source_path, screen.pwd)
      end,
    }

    -- Change global cwd
    n.command(string.format('cd %s/src/nvim', t.paths.test_source_path))

    screen:expect {
      condition = function()
        eq(string.format('%s/src/nvim', t.paths.test_source_path), screen.pwd)
      end,
    }

    -- Split the window and change the cwd in the split
    n.command('new')
    n.command(string.format('lcd %s/test', t.paths.test_source_path))

    screen:expect {
      condition = function()
        eq(string.format('%s/test', t.paths.test_source_path), screen.pwd)
      end,
    }

    -- Move to the original window
    n.command('wincmd p')

    screen:expect {
      condition = function()
        eq(string.format('%s/src/nvim', t.paths.test_source_path), screen.pwd)
      end,
    }

    -- Change global cwd again
    n.command(string.format('cd %s', t.paths.test_source_path))

    screen:expect {
      condition = function()
        eq(t.paths.test_source_path, screen.pwd)
      end,
    }
  end)
end)

describe('--embed --listen UI', function()
  it('waits for connection on listening address', function()
    t.skip(t.is_os('win'))
    clear()
    local child_server = assert(n.new_pipename())
    fn.jobstart({
      nvim_prog,
      '--embed',
      '--listen',
      child_server,
      '--clean',
      '--cmd',
      'colorscheme vim',
    })
    retry(nil, nil, function()
      neq(nil, uv.fs_stat(child_server))
    end)

    local child_session = n.connect(child_server)

    local info_ok, api_info = child_session:request('nvim_get_api_info')
    ok(info_ok)
    eq(2, #api_info)
    ok(api_info[1] > 2, 'channel_id > 2', api_info[1])

    child_session:request(
      'nvim_exec2',
      [[
      let g:evs = []
      autocmd UIEnter * call add(g:evs, $"UIEnter:{v:event.chan}")
      autocmd VimEnter * call add(g:evs, "VimEnter")
    ]],
      {}
    )

    -- VimEnter and UIEnter shouldn't be triggered until after attach
    local var_ok, var = child_session:request('nvim_get_var', 'evs')
    ok(var_ok)
    eq({}, var)

    local child_screen = Screen.new(40, 6)
    child_screen:attach(nil, child_session)
    child_screen:expect {
      grid = [[
      ^                                        |
      {1:~                                       }|*3
      {2:[No Name]             0,0-1          All}|
                                              |
    ]],
      attr_ids = {
        [1] = { foreground = Screen.colors.Blue, bold = true },
        [2] = { reverse = true, bold = true },
      },
    }

    -- VimEnter and UIEnter should now be triggered
    var_ok, var = child_session:request('nvim_get_var', 'evs')
    ok(var_ok)
    eq({ 'VimEnter', ('UIEnter:%d'):format(api_info[1]) }, var)
  end)
end)