akinsho / toggleterm.nvim

A neovim lua plugin to help easily manage multiple terminal windows
GNU General Public License v3.0
4.21k stars 170 forks source link

[BUG] Calling toggle in quick succession does not respect persist_mode/start_in_insert #522

Open jemag opened 9 months ago

jemag commented 9 months ago

Is there an existing issue for this?

Current Behavior

Calling toggle twice in quick succession will not respect persist_mode/start_in_insert

Expected Behavior

No amount of toggle calling changes the behavior.

Steps To Reproduce

  1. Open neovim with the following minimal config using nvim -u repro.lua somerandomfile:
    
    -- DO NOT change the paths and don't remove the colorscheme
    local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro for , name in ipairs({ "config", "data", "state", "cache" }) do vim.env[("XDG%s_HOME"):format(name:upper())] = root .. "/" .. name end

-- bootstrap lazy local lazypath = root .. "/plugins/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath }) end vim.opt.runtimepath:prepend(lazypath) vim.g.mapleader = " "

-- install plugins local plugins = { "folke/tokyonight.nvim", -- add any other plugins here }

local toggleterm_config = { "akinsho/toggleterm.nvim", config = function() require("toggleterm").setup({ shading_factor = "0", hide_numbers = false, persist_mode = true, start_in_insert = true, direction = "float", size = function(term) if term.direction == "horizontal" then return vim.o.lines 0.5 elseif term.direction == "vertical" then return vim.o.columns 0.5 end end, })

local term = require("toggleterm.terminal").Terminal
vim.keymap.set("n", "<leader>tc", function()
  local t = term:new({
    dir = "%:p:h",
    display_name = vim.fn.expand("%:p:h"),
  })
  t:toggle()
end, { desc = "Term current dir" })
vim.keymap.set("n", "<leader>t;", function()
  local t = term:new({
    display_name = "default",
  })
  t:toggle()
end, { desc = "Create term" })
vim.keymap.set({ "n", "t" }, "<F9>", "<cmd>ToggleTerm<cr>", { desc = "Toggle term" })
vim.keymap.set({ "n", "t" }, "<F8>", function()
  require("toggleterm").toggle(2)
  require("toggleterm").toggle(1)
end, { desc = "Toggle term" })

end, }

table.insert(plugins, toggleterm_config) require("lazy").setup(plugins, { root = root .. "/plugins", })

vim.cmd.colorscheme("tokyonight") -- add anything else here

2. Create 2 terminals using the provided keybinds (in my case, `<leader>tc` followed by `<leader>t;`
3. Once the 2nd terminal is opened, press `<F8>`
4. Notice that while switching back to the first terminal, this terminal will now be in `normal` mode

### Environment

```Markdown
- OS: arch Linux 6.6.3-arch1-1
- neovim version: v0.10.0-dev-38e9875
- Shell: zsh

Anything else?

Here is a video of the Steps to Reproduce section: https://github.com/akinsho/toggleterm.nvim/assets/7985687/a7c5e75d-609a-4c3b-a2ea-f490add9039c Note that this behavior will happen also when calling toggle on the same terminal twice in succession as well, e.g.:

      require("toggleterm").toggle(2)
      require("toggleterm").toggle(2)

It also happens if we call the :{count}ToggleTerm twice in quick succession as well.

Why does that matter?

I think being able to call it in quick succession can be useful for some key bindings. For example. I was trying to setup the following keybinds to cycle through my current floating terminals:

local function get_term_index(current_id, terms)
  local idx
  for i, v in ipairs(terms) do
    if v.id == current_id then
      idx = i
    end
  end
  return idx
end

local function go_prev_term()
  local current_id = vim.b.toggle_number
  if current_id == nil then
    return
  end

  local terms = require("toggleterm.terminal").get_all(true)
  local prev_index

  local index = get_term_index(current_id, terms)
  if index > 1 then
    prev_index = index - 1
  else
    prev_index = #terms
  end
  require("toggleterm").toggle(index)
  require("toggleterm").toggle(prev_index)
end

local function go_next_term()
  local current_id = vim.b.toggle_number
  if current_id == nil then
    return
  end

  local terms = require("toggleterm.terminal").get_all(true)
  local next_index

  local index = get_term_index(current_id, terms)
  if index == #terms then
    next_index = 1
  else
    next_index = index + 1
  end
  require("toggleterm").toggle(index)
  require("toggleterm").toggle(next_index)
end

vim.keymap.set({ "n", "t" }, "<F8>", function()
  go_next_term()
end, { desc = "Toggle term" })

vim.keymap.set({ "n", "t" }, "<F7>", function()
  go_prev_term()
end, { desc = "Toggle term" })
LeFrosch commented 8 months ago

I have a very similar configuration where I can switch between multiple floating terminals and I also have issues with the mode not being consistent. I want every terminal to be back in insert when it is opened. Therefore, I tried calling vim.cmd('startinsert!') in the on_open callback but as far as I can tell this doesn't. As a work around I am using a timer with a very short delay in the callback:

vim.fn.timer_start(1, function()
  vim.cmd('startinsert!')
end)

Maybe this is somehow related.

haug1 commented 5 months ago

I have a very similar configuration where I can switch between multiple floating terminals and I also have issues with the mode not being consistent. I want every terminal to be back in insert when it is opened. Therefore, I tried calling vim.cmd('startinsert!') in the on_open callback but as far as I can tell this doesn't. As a work around I am using a timer with a very short delay in the callback:

vim.fn.timer_start(1, function()
  vim.cmd('startinsert!')
end)

Maybe this is somehow related.

Was struggling with the same thing. Although not ideal, thanks for the workaround.