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

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

Closed
minego opened this issue Dec 10, 2023 · 19 comments
Closed

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

minego opened this issue Dec 10, 2023 · 19 comments
Assignees
Labels
enhancement New feature or request

Comments

@minego
Copy link

minego commented Dec 10, 2023

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.

@minego minego added the enhancement New feature or request label Dec 10, 2023
@willothy
Copy link
Owner

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

@willothy
Copy link
Owner

willothy commented Dec 11, 2023

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
Copy link
Author

minego commented Dec 13, 2023

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.

@minego minego closed this as completed Dec 13, 2023
@willothy
Copy link
Owner

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
Copy link
Owner

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?

2023-12-13.06-10-13.mp4

@willothy willothy reopened this Dec 13, 2023
@willothy
Copy link
Owner

willothy commented Jan 26, 2024

@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.

2024-01-26.15-16-08.mp4

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
Copy link
Author

minego commented Jan 26, 2024

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

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

@willothy
Copy link
Owner

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
Copy link
Author

minego commented Jan 26, 2024

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

@willothy
Copy link
Owner

What do you use? Builtin :term?

@minego
Copy link
Author

minego commented Jan 27, 2024 via email

@willothy
Copy link
Owner

willothy commented Jan 27, 2024

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
Copy link
Owner

willothy commented Jan 27, 2024

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
Copy link
Author

minego commented Jan 27, 2024

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
Copy link
Owner

willothy commented Jan 27, 2024

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
Copy link
Author

minego commented Jan 27, 2024

Ah, I assumed it was needed there!

@willothy
Copy link
Owner

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
Copy link
Author

minego commented Jan 27, 2024

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
Copy link
Owner

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.

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

No branches or pull requests

2 participants