Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

As soon as output window is opened, vim enters into insert mode #2

Closed
wookayin opened this issue Jun 7, 2022 · 7 comments
Closed

Comments

@wookayin
Copy link
Contributor

wookayin commented Jun 7, 2022

How to reproduce:

  • On a normal mode
  • :lua require("neotest").output.open()
  • The main editor enters insert mode, which should not happen.
@rcarriga
Copy link
Collaborator

rcarriga commented Jun 7, 2022

I'm not seeing the same behaviour. Do you have an autocmd to enter insert mode when a terminal buffer is opened or any thing like that? It might also be something in my setup that is hiding the issue.

I've set noatucomd on the window settings, can you try with the latest commit?

rcarriga added a commit that referenced this issue Jun 7, 2022
@wookayin
Copy link
Contributor Author

wookayin commented Jun 8, 2022

Exactly -- you've got a right hunch.

This is the autocmd I have; disabling this would make the bug not happen.

  " Automatically enter insert mode when entering neovim terminal buffer
  augroup terminal_autoinsert
    autocmd!
    autocmd BufWinEnter,WinEnter *  if &buftype == 'terminal' | startinsert | endif
    autocmd TermOpen * startinsert
  augroup END

However the latest commit (after fcc2337) still doesn't fix the issue. You could probably reproduce the bug with the autocmd settings above. What's strange is the startinsert option is supposed to work on the terminal buffer, but it affects the editor window.

@stevearc
Copy link
Contributor

stevearc commented Jun 8, 2022

This happens because the TermOpen autocmd fires when a terminal is opened, regardless of if it's the current window or not. You can demonstrate this by sourcing this file:

-- test.lua  :source % will enter insert mode
  local buf = async.api.nvim_create_buf(false, true)
  local chan = async.api.nvim_open_term(buf, {})

Since that is exactly what output.open() is doing, it's going to hit your autocmd and startinsert.

You can fix this on your end by adding a guard (optionally with a delay). My config looks like this:

vim.api.nvim_create_autocmd("TermOpen", {
  desc = "Auto enter insert mode when opening a terminal",
  pattern = "*",
  callback = function()
    -- Wait briefly just in case we immediately switch out of the buffer
    vim.defer_fn(function()
      if vim.api.nvim_buf_get_option(0, 'buftype') == 'terminal' then
        vim.cmd([[startinsert]])
      end
    end, 100)
  end,
})

On the neotest side, you may want to do something to work around this. We expect this autocmd to be relatively popular because it's literally in the neovim help docs (see :help :terminal):

To enter |Terminal-mode| automatically:  
      autocmd TermOpen * startinsert

One possibility (that is still a gross hack to be sure) is the code below.

  local mode = vim.api.nvim_get_mode().mode
  
  -- Open terminal here

  vim.defer_fn(function()
    local new_mode = vim.api.nvim_get_mode().mode
    if new_mode ~= mode then
      if string.find(new_mode, "i") == 1 then
        vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<ESC>", true, true, true), "n", false)
        -- Optionally restore visual selection if we came from visual mode (is this common?)
        if string.find(mode, "v") == 1 or string.find(mode, "V") == 1 then
          vim.cmd([[normal! gv]])
        end
      end
    end
  end, 10)

@rcarriga
Copy link
Collaborator

rcarriga commented Jun 8, 2022

Ah yes the TermOpen command is not affectted by the nouatocmd setting. I'm not really a fan of introducing a hacky solution. This is not unique to neotest (I use it in nvim-dap-ui, nvim-dap also uses it), it's much easier to fix the autocmd. I'll leave it up to users to adjust their config.

I'd recommend changing the autocmd to something like this

autocmd TermOpen * lua if vim.startswith(vim.api.nvim_buf_get_name(0), "term://") then vim.cmd("startinsert") end

which should then behave how you want it to

@wookayin
Copy link
Contributor Author

wookayin commented Jun 8, 2022

Thanks for the comments. I thought this is something that can be addressed by the plugin, but I agree that user's custom autocmd config is more responsible for the behavior. The startinsert autocmd were implictly assuming the terminal is opened in the current window (or focus is gained), but this assumption is not necessarily true in some cases.

I'd recommend changing the autocmd to something like this

autocmd TermOpen * lua if vim.startswith(vim.api.nvim_buf_get_name(0), "term://") then vim.cmd("startinsert") end

which should then behave how you want it to

Can confirm this works as expected. Or a non-lua version if someone would care the backward compatibility:

autocmd TermOpen *  if nvim_buf_get_name(0) =~# '^term://.*' | startinsert | endif

@rcarriga
Copy link
Collaborator

rcarriga commented Jun 8, 2022

Perfect I'll close this so 👍 Perhaps an update to neovim docs would be good, will open a PR when I get a chance if no else has

@rcarriga rcarriga closed this as completed Jun 8, 2022
wookayin added a commit to wookayin/dotfiles that referenced this issue Jun 14, 2022
When a terminal buffer is opened (TermOpen), for example, by `:term`,
we would want to automatically enter the insert mode. However,
the existing autocmd may result in the non-terminal buffer unwantedly
entering the insert mode when a new terminal buffer is opened on a
floating window. To prevent this, we can enter the insert mode
only if the current window has the terminal buffer being opened.

See nvim-neotest/neotest#2 for reference.
@exosyphon
Copy link

exosyphon commented Nov 16, 2023

I just ran into this with a TermOpen autocommand as well that looks like this:

-- start terminal in insert mode
vim.api.nvim_create_autocmd("TermOpen", {
  group   = "custom_buffer",
  pattern = "*",
  command = "startinsert | set winfixheight"
})

I implemented what @stevearc suggested as a workaround. Is there a more preferred solution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants