willothy / flatten.nvim

Open files and command output from wezterm, kitty, and neovim terminals in your current neovim instance
https://luarocks.org/modules/willothy/flatten.nvim
MIT License
473 stars 13 forks source link

Option to return to the terminal after closing a file #84

Closed minego closed 7 months ago

minego commented 9 months ago

Is your feature request related to a problem? Please describe. I really like the 'alternate' option, but when I use it I end up accidentally closing the whole window when I'm done with the file.

Example:

  1. Open a terminal
  2. Run 'vi README.md'
  3. Read it, then hit ':q'
  4. The window is gone, instead of returning me to the terminal

Describe the solution you'd like I'd like the option to return to the terminal after closing something that I opened with flatten.

Describe alternatives you've considered I've played with callbacks. It seems that if I could trigger a ':bp' at the right point it would be perfect, but I wasn't able to figure out the right way to do that.

Additional context For now I've just switched to using 'vsplit' instead of 'alternate' which works in my workflow, but isn't nearly as elegant.

willothy commented 9 months ago

Can you share your config? This should be possible - if it's not, I'm happy to add it.

willothy commented 9 months ago

Actually after reading this again I don't think this is currently possible. I don't think it's possible to not close the window when you run :q. But what's definitely possible is returning you to the terminal when the file is closed - just make a BufDelete autocmd in a callback and run :bd instead of :q. You could also use a BufLeave autocmd for this if you don't want to delete the buffer.

minego commented 9 months ago

That's a bit disappointing but it makes sense. I'll try try train my brain to use :bd instead of :q and see how far I get :-)

If you think of a method that would work, please let me know. Despite this not behaving the way I'd like, this plugin is absolutely amazing and wonderful and I can't thank you enough for writing it.

willothy commented 9 months ago

Thanks, I appreciate that :) I wish I could make this work but as far as I know there's no way to avoid the behavior of :q, it's pretty much hardcoded. I think a BufLeave autocmd is the best option. I may also be misunderstanding your request though.

willothy commented 9 months ago

I want to keep this open until I'm totally sure I can't support this. My config currently does this (video below), is this somewhat the behavior you're looking for?

https://github.com/willothy/flatten.nvim/assets/38540736/794530c2-ecb8-438a-9c9c-84a2124abaf4

willothy commented 7 months ago

@minego I managed to get this working! Here's a video (used a clean nvim config to make sure it's reproducible):

The video uses builtin :term, but this will work with toggleterm as well and it will return you to the terminal automatically because of the config.

https://github.com/willothy/flatten.nvim/assets/38540736/cbef61f6-f367-496f-a791-9147b032c473

Here's the config, just a modified version of the config from the readme.

local saved_terminal

require("flatten").setup({
  window = {
    open = "alternate",
  },
  callbacks = {
    should_block = function(argv)
      -- Note that argv contains all the parts of the CLI command, including
      -- Neovim's path, commands, options and files.
      -- See: :help v:argv

      -- In this case, we would block if we find the `-b` flag
      -- This allows you to use `nvim -b file1` instead of
      -- `nvim --cmd 'let g:flatten_wait=1' file1`
      return vim.tbl_contains(argv, "-b")

      -- Alternatively, we can block if we find the diff-mode option
      -- return vim.tbl_contains(argv, "-d")
    end,
    pre_open = function()
      local term = require("toggleterm.terminal")
      local termid = term.get_focused_id()
      saved_terminal = term.get(termid)
    end,
    post_open = function(bufnr, winnr, ft, is_blocking)
      if is_blocking and saved_terminal then
        -- Hide the terminal while it's blocking
        saved_terminal:close()
      else
        -- If it's a normal file, just switch to its window
        vim.api.nvim_set_current_win(winnr)

        -- If we're in a different wezterm pane/tab, switch to the current one
        -- Requires willothy/wezterm.nvim
        -- require("wezterm").switch_pane.id(
        --   tonumber(os.getenv("WEZTERM_PANE"))
        -- )
      end

      -- If the file is a git commit, create one-shot autocmd to delete its buffer on write
      -- If you just want the toggleable terminal integration, ignore this bit
      if ft == "gitcommit" or ft == "gitrebase" then
        vim.api.nvim_create_autocmd("QuitPre", {
          buffer = bufnr,
          once = true,
          callback = vim.schedule_wrap(function()
            vim.cmd.split() -- create a new window (becuase the current one is closing from :q)
            vim.cmd.bprev() -- it will have the same buffer, so :brev to go to the last one
            vim.api.nvim_buf_delete(bufnr, {}) -- delete the buffer (so blocking ends)
          end),
        })
      end
    end,
    block_end = function()
      -- After blocking ends (for a git commit, etc), reopen the terminal
      vim.schedule(function()
        if saved_terminal then
          saved_terminal:open()
          saved_terminal = nil
        end
      end)
    end,
  },
})
minego commented 7 months ago

Oooh! That's exciting! The video looks great.

I'll try this asap and report back my results. Thanks again!

willothy commented 7 months ago

Totally! Glad I could figure it out, I might actually end up using this as opposed to my current setup which is to just use :bd :)

minego commented 7 months ago

Do you have an example that doesn't use toggleterm? I am sure I can adapt it if not.

willothy commented 7 months ago

What do you use? Builtin :term?

minego commented 7 months ago

Yeah On Fri, Jan 26, 2024, at 5:00 PM, Will Hopkins wrote:

What do you use? Builtin :term?

— Reply to this email directly, view it on GitHub https://github.com/willothy/flatten.nvim/issues/84#issuecomment-1912846486, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADSRCA2ROOOWGI3FZCHCOTYQQ7RFAVCNFSM6AAAAABAOVSTMWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMJSHA2DMNBYGY. You are receiving this because you were mentioned.Message ID: @.***>

willothy commented 7 months ago

You can probably just replace all of the toggleterm stuff with getting/setting buffers then.

Like in pre_open check if the current buffer is a terminal and save it if it is, then in block_end you can find a window containing that buffer and switch to it.

I don't have a config readily available that doesn't use toggleterm though, sorry :/

willothy commented 7 months ago

The config I sent totally works without toggleterm tho, the video I sent was using builtin :term

It's just returning to the terminal window that I didn't reimplement

minego commented 7 months ago

I tried as is, and it fails in pre_open on local term = require("toggleterm.terminal")

It looks like it shouldn't be hard to adapt though. I don't have the time to try that tonight, but I will play with it. Thanks again!

willothy commented 7 months ago

I mean yeah, just delete the toggleterm stuff haha

It exists in the config but it did not do anything in the video (no terminal was saved) because I didn't use a toggleterm terminal.

minego commented 7 months ago

Ah, I assumed it was needed there!

willothy commented 7 months ago

Nope, sorry haha

Here's an (untested) config using no toggleterm

local saved_terminal

require("flatten").setup({
  window = {
    open = "alternate",
  },
  callbacks = {
    should_block = function(argv)
      -- Note that argv contains all the parts of the CLI command, including
      -- Neovim's path, commands, options and files.
      -- See: :help v:argv

      -- In this case, we would block if we find the `-b` flag
      -- This allows you to use `nvim -b file1` instead of
      -- `nvim --cmd 'let g:flatten_wait=1' file1`
      return vim.tbl_contains(argv, "-b")

      -- Alternatively, we can block if we find the diff-mode option
      -- return vim.tbl_contains(argv, "-d")
    end,
    pre_open = function()
      local termid = vim.api.nvim_get_current_buf()
      if vim.bo[termid].buftype == "terminal" then
        saved_terminal = termid
      end
    end,
    post_open = function(bufnr, winnr, ft, is_blocking)
      if is_blocking and saved_terminal then
        -- Hide the terminal while it's blocking
        -- saved_terminal:close() -- only for toggleterm since position is saved
      else
        -- If it's a normal file, just switch to its window
        vim.api.nvim_set_current_win(winnr)

        -- If we're in a different wezterm pane/tab, switch to the current one
        -- Requires willothy/wezterm.nvim
        -- require("wezterm").switch_pane.id(
        --   tonumber(os.getenv("WEZTERM_PANE"))
        -- )
      end

      -- If the file is a git commit, create one-shot autocmd to delete its buffer on write
      -- If you just want the toggleable terminal integration, ignore this bit
      if ft == "gitcommit" or ft == "gitrebase" then
        vim.api.nvim_create_autocmd("QuitPre", {
          buffer = bufnr,
          once = true,
          callback = vim.schedule_wrap(function()
            vim.cmd.split() -- create a new window (becuase the current one is closing from :q)
            vim.cmd.bprev() -- it will have the same buffer, so :brev to go to the last one
            vim.api.nvim_buf_delete(bufnr, {}) -- delete the buffer (so blocking ends)
          end),
        })
      end
    end,
    block_end = function()
      -- After blocking ends (for a git commit, etc), reopen the terminal
      vim.schedule(function()
        if saved_terminal then
          for _, win in ipairs(vim.api.nvim_list_wins()) do
            if vim.api.nvim_win_get_buf(win) == saved_terminal then
              vim.api.nvim_set_current__win(win)
              break
            end 
          end
          -- maybe do something if a window wasn't found
          saved_terminal = nil
        end
      end)
    end,
  },
})
minego commented 7 months ago

You're fast!

It looks like that is working in some cases, but I think I'm going to have to experiment a bit to get it just right for my config.

I frequently open a new terminal in a tab, and it is still closing the tab... But that's okay. You've proven the concept, and that's enough!

willothy commented 7 months ago

I made the change in the github comment editor lol

Yeah, assumed it wouldn't work in all cases, but glad it works sometimes! Definitely would have to be modified to work with tabpages.