akinsho / toggleterm.nvim

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

Integration with Terminal File Managers #66

Closed is0n closed 3 years ago

is0n commented 3 years ago

Question

How could one go on about integrating this plugin with programs such as joshuto, nnn, lf, and ranger?

Acknowledgments

I know that this is already somewhat possible as you can open a terminal that runs the program on startup and then just open the file from there, however, I have found that this does not work.

What is expected is that when you open a file with your terminal file manager, it opens a new buffer with the selected file, however, what actually happens is that the terminal uses a new instance of neovim within itself and edits the file there.

Example:

Reality

Goal

Create a template that can be used to easily integrate terminal file managers with neovim using this plugin.

akinsho commented 3 years ago

@is0n I'm not entirely sure if I understand this issue but if it's primarily about opening a file in a terminal file manager and that opening a buffer in the already existing neovim instance then neovim doesn't natively internally support this, but it has been planned for years. There is a solution, though, built by an nvim maintainer called nvr.

Since nvr is a separate program and terminal file managers vary, I won't include anything which tries to automagically link these since it will be brittle and frankly is beyond the scope of this plugin. It's definitely already possible, though as I use lazygit with nvr, and I'm able to open buffers from that program in my running nvim instance.

EDIT: just to be clear nvr also requires setup and configuration inside a user init.lua and potentially shell rc file so is definitely not something this plugin can configure for you

is0n commented 3 years ago

@akinsho Thank you for the fast and helpful response!

Surprisingly enough, just using "nvr" as the "open_with" command sort of works.

Example w/ the plugin and function:

JoshutoToggle

Code sourced in init.lua:

function Joshuto_Toggle()
  local Terminal = require("toggleterm.terminal").Terminal
  local joshuto = Terminal:new { cmd = "joshuto", hidden = true, direction = "float" }
  joshuto:toggle()
end

Result:

A remaining floating terminal (direction doesn't matter as this occurs with all types of terminals) that displays the current file and a buffer with the file opened, however, this buffer has no line numbers nor does it have the sign column.

Example w/ :term:

Terminal

Result:

New buffer is created and focused with the selected file.

Question:

Is this a problem with neovim-remote or nvim-toggleterm?

I assume that this has to do with nvim-toggleterm and/or the function* as this bug doesn't occur when using neovim's built-in terminal.

*I doubt that this has to do with the function as the bug still occurs when manually entering "joshuto" into a new toggleterm.

akinsho commented 3 years ago

@is0n the issue you are seeing is because you are trying to re-use the exact same window as toggleterm was in. So when toggle term is created it hides the numbers and signcolumn for that window in your case you must have nvr set to re-use the window where it was triggered from so the buffer inherits the same behaviour. Tbh I don't think this can be solved because there is no way I can see to fix this. A much better solution would be to create a new window from nvr rather than use the one that toggleterm was using. For example if you did this with a float it's likely it would just attempt to re-use the float window as well which I assume would also be undesirable.

is0n commented 3 years ago

I'll be closing this issue as implementing this feature seems to go beyond this plugin's capabilities.

fattymembrane commented 3 years ago

@is0n I've managed to get this working with lf in a way that duplicates what I was previously using FloaTerm to do (use lf as a file picker for a new buffer). I know absolutely nothing about Lua or VimScript - I just copy/pasted my way to this solution, so it can no doubt be improved quite a bit. It looks like there's an io.tmpfile() function in Lua that would likely be a much better option than my janky temp file solution, but I couldn't get it to work properly (user error, I'm sure).

Getting the path of the selected file requires passing the '-selection-path' option to lf and specifying a file where the path name will be stored. When passed that option, lf exits and saves the path to the specified file instead of opening it.

-- lf file picker
local temp_path = "/tmp/lfpickerpath"
local Terminal  = require('toggleterm.terminal').Terminal
local lfpicker = Terminal:new({
  cmd = "lf -selection-path " .. temp_path,
  direction = "float",
  on_close = function(term)
    local file = io.open(temp_path, "r")
    if file~=nil
      then
        vim.cmd("tabe " .. file:read("*a"))
        file:close()
        os.remove(temp_path)
    end
  end
})

function _lfpicker_toggle()
  lfpicker:toggle()
end

-- Map to a shortcut (I'm using LunarVim)
lvim.keys.normal_mode["<Leader>|"] = "<cmd>lua _lfpicker_toggle()<CR>"
is0n commented 3 years ago

I've actually been working on a plugin that does this! I just made it public and it can be found at fm-nvim. You can try it out yourself, however, it is far from finished as opening files only sort of works.

illia-danko commented 1 year ago

a little bit updated version above which uses lf file manager. It occupies the full win capacity and uses the edit command over tabedit:

  local toggleterm_float_opts = function()
    return {
      border = "none",
      width = vim.o.columns,
      height = vim.o.lines - 1,
    }
  end

  vim.g.lf_netrw = 1
  vim.g.lf_replace_netrw = 1 -- use lf over netrw

  vim.keymap.set("n", "-", function()
    local lf_temp_path = "/tmp/lfpickerpath"
    local lfpicker = Terminal:new({
      cmd = "lf -selection-path " .. lf_temp_path,
      count = 101, -- use high value to no intersect with regular OpenTerm cmd
      direction = "float",
      float_opts = toggleterm_float_opts(),
      on_close = function(term)
        local file = io.open(lf_temp_path, "r")
        if file == nil then
          return
        end
        local name = file:read("*a")
        file:close()
        os.remove(lf_temp_path)
        local timer = vim.loop.new_timer()
        timer:start(
          0,
          0,
          vim.schedule_wrap(function()
            vim.cmd("edit " .. name)
          end)
        )
      end,
    })

    lfpicker:toggle()
  end, { desc = "lf" })
JohanChane commented 9 months ago

It works.

      -- ## file manager
      local function feedkeys(keys)
        local key_termcode = vim.api.nvim_replace_termcodes(keys, true, true, true)
        vim.api.nvim_feedkeys(key_termcode, 'n', false)
      end

      local edit_cmd = ""
      local fm_tmpfile = vim.fn.tempname()
      local Terminal = require("toggleterm.terminal").Terminal
      local fm = Terminal:new({
        direction = "float",
        hidden = true,
        on_open = function(term)
          edit_cmd = "edit"
          vim.keymap.set("t", "<C-t>", function()
              edit_cmd = "tabedit"
              feedkeys("l")
            end,
            { noremap = true, silent = true, buffer = term.bufnr })
          vim.keymap.set("t", "<C-s>", function()
              edit_cmd = "split"
              feedkeys("l")
            end,
            { noremap = true, silent = true, buffer = term.bufnr })
          vim.keymap.set("t", "<C-v>", function()
              edit_cmd = "vsplit"
              feedkeys("l")
            end,
            { noremap = true, silent = true, buffer = term.bufnr })
        end,
        on_exit = function(term)
          local file = io.open(fm_tmpfile, "r")
          if file ~= nil
          then
            local file_name = file:read("*a")
            file:close()
            os.remove(fm_tmpfile)
            local timer = vim.uv.new_timer()
            timer:start(0, 0, vim.schedule_wrap(function()
                vim.cmd(edit_cmd .. " " .. file_name)
              end))
          end
        end,
      })
      function _fm_toggle()
        --local fm_cmd = 'ranger --choosefiles="' .. fm_tmpfile .. '"'
        local fm_cmd = 'joshuto --file-chooser --output-file="' .. fm_tmpfile .. '"'
        fm.cmd = fm_cmd
        fm.dir = vim.fn.expand("%:p:h")
        fm:toggle()
      end
      vim.api.nvim_set_keymap("n", "<M-f>", "<cmd>lua _fm_toggle()<CR>", { noremap = true, silent = true })