akinsho / toggleterm.nvim

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

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

Open jemag opened 12 months ago

jemag commented 12 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 11 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 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.

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