avante.nvim icon indicating copy to clipboard operation
avante.nvim copied to clipboard

bug: After opening a new panel in tmux and returning to nvim, two Ask areas appear in avante.nvim

Open griffinqiu opened this issue 6 months ago • 2 comments

Describe the bug

https://github.com/user-attachments/assets/b2247a14-14ec-48f6-8927-d5bfb29a190c

After opening a new panel in tmux and returning to nvim, two Ask areas appear in avante.nvim

To reproduce

  1. Open tmux
  2. Open nvim and avante.nvim
  3. Open a new panel with tmux
  4. Return to nvim and find two ask blocks

No response

Expected behavior

No response

Installation method

Use lazy.nvim:

{
  "yetone/avante.nvim",
  event = "VeryLazy",
  lazy = false,
  version = false, -- set this if you want to always pull the latest change
  opts = {
    -- add any opts here
  },
  -- if you want to build from source then do `make BUILD_FROM_SOURCE=true`
  build = "make",
  -- build = "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false" -- for windows
  dependencies = {
    "nvim-treesitter/nvim-treesitter",
    "stevearc/dressing.nvim",
    "nvim-lua/plenary.nvim",
    "MunifTanjim/nui.nvim",
  },
}

Environment

MacOS, NeoVim, Tmux

Repro

vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()

require("lazy.minit").repro({
  spec = {
    -- add any other plugins here
  },
})

griffinqiu avatar May 26 '25 08:05 griffinqiu

I have similar issue also in Kitty, if I change my window and come back there are two output, or two input window

DanRioDev avatar May 28 '25 17:05 DanRioDev

Also everytime I open another horizontal window the ask moves itself to the uper half of the screen squeezing output and files window

DanRioDev avatar May 28 '25 17:05 DanRioDev

Please take a look, we would be very grateful if you can fix it. @yetone

griffinqiu avatar Jun 11 '25 03:06 griffinqiu

Please have a look, thank you very much. @yetone

griffinqiu avatar Jun 23 '25 06:06 griffinqiu

https://github.com/user-attachments/assets/24a4f62e-6dae-44b9-9fb4-4583ed528c88

Sorry, I couldn't reproduce this issue.

yetone avatar Jun 23 '25 18:06 yetone

@yetone I use the LazyVim to setup nvim.

I have reproduced the issue with mini LazyVim setup with avante.nvim.

https://www.lazyvim.org/installation

griffinqiu avatar Jun 26 '25 02:06 griffinqiu

@DanRioDev Do you also use the LazyVim ?

griffinqiu avatar Jun 26 '25 02:06 griffinqiu

Indeed I do @griffinqiu, chances are it's either folke's Noice or Snakck's Window management from LazyVim defaults.

DanRioDev avatar Jun 26 '25 18:06 DanRioDev

@DanRioDev Should we file an issue with LazyVim?

griffinqiu avatar Jul 02 '25 05:07 griffinqiu

return {
  {
    "yetone/avante.nvim",
    enabled = vim.g.ai_partner == "avante",
    opts = function(_, opts)
      -- Only apply fix in tmux environment
      if not vim.env.TMUX then
        return opts
      end

      -- Track avante's internal state
      local in_resize = false
      local original_cursor_win = nil
      local avante_filetypes = { "Avante", "AvanteInput", "AvanteAsk", "AvanteSelectedFiles" }

      -- Check if current window is avante
      local function is_in_avante_window()
        local win = vim.api.nvim_get_current_win()
        local buf = vim.api.nvim_win_get_buf(win)
        local ft = vim.api.nvim_buf_get_option(buf, "filetype")

        for _, avante_ft in ipairs(avante_filetypes) do
          if ft == avante_ft then
            return true, win, ft
          end
        end
        return false
      end

      -- Temporarily move cursor away from avante during resize
      local function temporarily_leave_avante()
        local is_avante, avante_win, avante_ft = is_in_avante_window()
        if is_avante and not in_resize then
          in_resize = true
          original_cursor_win = avante_win

          -- Find a non-avante window to switch to
          local target_win = nil
          for _, win in ipairs(vim.api.nvim_list_wins()) do
            local buf = vim.api.nvim_win_get_buf(win)
            local ft = vim.api.nvim_buf_get_option(buf, "filetype")

            local is_avante_ft = false
            for _, aft in ipairs(avante_filetypes) do
              if ft == aft then
                is_avante_ft = true
                break
              end
            end

            if not is_avante_ft and vim.api.nvim_win_is_valid(win) then
              target_win = win
              break
            end
          end

          -- Switch to non-avante window if found
          if target_win then
            vim.api.nvim_set_current_win(target_win)
            return true
          end
        end
        return false
      end

      -- Restore cursor to original avante window
      local function restore_cursor_to_avante()
        if in_resize and original_cursor_win and vim.api.nvim_win_is_valid(original_cursor_win) then
          -- Small delay to ensure resize is complete
          vim.defer_fn(function()
            pcall(vim.api.nvim_set_current_win, original_cursor_win)
            in_resize = false
            original_cursor_win = nil
          end, 50)
        end
      end

      -- Override avante's refresh/resize methods if possible
      local avante_setup_done = false
      local function patch_avante_resize()
        if avante_setup_done then
          return
        end

        -- Try to access avante's sidebar module
        local ok, avante = pcall(require, "avante")
        if ok and avante then
          local sidebar_ok, sidebar = pcall(require, "avante.sidebar")
          if sidebar_ok and sidebar.Sidebar then
            -- Wrap the resize method
            local original_resize = sidebar.Sidebar.resize
            if original_resize then
              sidebar.Sidebar.resize = function(self, ...)
                if in_resize then
                  -- Skip resize during our resize handling
                  return
                end
                return original_resize(self, ...)
              end
              avante_setup_done = true
            end
          end
        end
      end

      -- Create autocmd group
      vim.api.nvim_create_augroup("AvanteTmuxFix", { clear = true })

      -- Main resize handler
      vim.api.nvim_create_autocmd({ "VimResized" }, {
        group = "AvanteTmuxFix",
        callback = function()
          -- Try to patch avante if not done yet
          patch_avante_resize()

          -- Move cursor away from avante before resize processing
          local moved = temporarily_leave_avante()

          if moved then
            -- Let resize happen, then restore cursor
            vim.defer_fn(function()
              restore_cursor_to_avante()
              -- Force a clean redraw
              vim.cmd("redraw!")
            end, 100)
          end
        end,
      })

      -- Alternative approach: prevent avante from responding to certain events
      vim.api.nvim_create_autocmd({ "WinScrolled", "WinResized" }, {
        group = "AvanteTmuxFix",
        pattern = "*",
        callback = function(args)
          local buf = args.buf
          if buf and vim.api.nvim_buf_is_valid(buf) then
            local ft = vim.api.nvim_buf_get_option(buf, "filetype")

            for _, avante_ft in ipairs(avante_filetypes) do
              if ft == avante_ft then
                -- Prevent event propagation for avante buffers during resize
                if in_resize then
                  return true -- This should stop the event
                end
                break
              end
            end
          end
        end,
      })

      -- Prevent duplicate Select Files panels
      local function cleanup_duplicate_avante_windows()
        local seen_filetypes = {}
        local windows_to_close = {}

        for _, win in ipairs(vim.api.nvim_list_wins()) do
          local buf = vim.api.nvim_win_get_buf(win)
          local ft = vim.api.nvim_buf_get_option(buf, "filetype")

          -- Special handling for Select Files panel
          if ft == "AvanteSelectedFiles" then
            if seen_filetypes[ft] then
              -- Found duplicate, mark for closing
              table.insert(windows_to_close, win)
            else
              seen_filetypes[ft] = win
            end
          end
        end

        -- Close duplicate windows
        for _, win in ipairs(windows_to_close) do
          if vim.api.nvim_win_is_valid(win) then
            pcall(vim.api.nvim_win_close, win, true)
          end
        end
      end

      -- Handle focus events in tmux
      vim.api.nvim_create_autocmd("FocusGained", {
        group = "AvanteTmuxFix",
        callback = function()
          -- Reset resize state on focus gain
          in_resize = false
          original_cursor_win = nil
          -- Clean up any duplicate windows
          vim.defer_fn(cleanup_duplicate_avante_windows, 100)
        end,
      })

      -- Additional cleanup after resize
      vim.api.nvim_create_autocmd("VimResized", {
        group = "AvanteTmuxFix",
        callback = function()
          -- Cleanup duplicates after resize completes
          vim.defer_fn(cleanup_duplicate_avante_windows, 200)
        end,
      })

      -- Disable some avante auto-behaviors during resize
      if opts.behaviour then
        -- Store original values
        local original_auto_set_highlight = opts.behaviour.auto_set_highlight_group
        local original_auto_set_keymaps = opts.behaviour.auto_set_keymaps

        -- Create wrapper that checks resize state
        vim.api.nvim_create_autocmd("BufEnter", {
          group = "AvanteTmuxFix",
          callback = function()
            if in_resize then
              -- Temporarily disable during resize
              if opts.behaviour then
                opts.behaviour.auto_set_highlight_group = false
                opts.behaviour.auto_set_keymaps = false
              end
            else
              -- Restore original values
              if opts.behaviour then
                opts.behaviour.auto_set_highlight_group = original_auto_set_highlight
                opts.behaviour.auto_set_keymaps = original_auto_set_keymaps
              end
            end
          end,
        })
      end

      return opts
    end,
  },
}

@DanRioDev @yetone I have use this to fixed it.

griffinqiu avatar Jul 03 '25 16:07 griffinqiu

      {
        "<leader>ar",
        function()
          -- 重置avante窗口高度的函数
          local function reset_avante_windows()
            -- 获取所有窗口
            local wins = vim.api.nvim_list_wins()
            local ask_win = nil
            local sidebar_win = nil

            -- 查找avante相关窗口
            for _, win in ipairs(wins) do
              local buf = vim.api.nvim_win_get_buf(win)
              local buf_name = vim.api.nvim_buf_get_name(buf)
              local filetype = vim.bo[buf].filetype

              -- 检查是否是ask窗口 (通常是输入窗口)
              if filetype == "AvanteInput" or buf_name:match("Avante.*Input") then
                ask_win = win
              -- 检查是否是sidebar窗口 (回复窗口)
              elseif filetype == "Avante" or buf_name:match("Avante") then
                sidebar_win = win
              end
            end

            -- 获取编辑器总高度
            local total_height = vim.o.lines - vim.o.cmdheight - 1 -- 减去命令行和状态栏

            -- 设置ask窗口高度为固定值 (12行)
            if ask_win then
              vim.api.nvim_win_set_height(ask_win, 12)
              print("Ask window height reset to 12 lines")
            end

            -- 设置sidebar窗口高度为尽可能大
            if sidebar_win then
              -- 计算可用高度 (总高度减去ask窗口高度和一些边距)
              local available_height = total_height - 10 -- 为ask窗口和边距预留空间
              if available_height > 20 then -- 确保有最小高度
                vim.api.nvim_win_set_height(sidebar_win, available_height)

                -- 移动光标到回复窗口底部
                vim.api.nvim_set_current_win(sidebar_win)
                local buf = vim.api.nvim_win_get_buf(sidebar_win)
                local line_count = vim.api.nvim_buf_line_count(buf)
                vim.api.nvim_win_set_cursor(sidebar_win, { line_count, 0 })

                print("Sidebar window height reset and cursor moved to bottom")
              end
            end

            if not ask_win and not sidebar_win then
              print("No Avante windows found")
            end
          end

          reset_avante_windows()
        end,
        mode = "n",
        desc = "Reset Avante windows height",
      },

I also add this to reset the height. It very useful

griffinqiu avatar Jul 03 '25 16:07 griffinqiu

I have the same issue - not using Lazyvim, just copy paste from the repo with some keys definitions (also kitty+tmux)

orlevit avatar Aug 08 '25 14:08 orlevit

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] avatar Sep 08 '25 02:09 github-actions[bot]

This issue was closed because it has been stalled for 5 days with no activity.

github-actions[bot] avatar Sep 15 '25 02:09 github-actions[bot]