Home

Awesome

tfm.nvim

Neovim plugin for Terminal File Manager integration.

<!-- markdownlint-disable --> <details> <summary><strong>Supported Terminal File Managers</strong></summary> <!-- markdownlint-enable --> <!-- markdownlint-disable MD013 --> </details>

Demo video

Introduction

When I discovered ranger.nvim, it ended up replacing nvim-tree for me, which was great. My only issue was that I wasn't such a huge fan of ranger itself. In trying to find an alternative, I was having to switch plugins entirely for each new one I wanted to try out, which was not ideal and inspired me to create this.

With this plugin, you can simply change which TFM you wish to use (from the supported ones) in your configuration and you're good to go. It should also allow you to replace netrw.

I am using this plugin full time but I don't use all the different file managers and modes available so if you find any issues please let me know and I'll do my best to address it.

Configuration

The setup function is completely optional. However, please note that by default this plugin does not set any keymaps or create any commands, so it is recommended to do so in your configuration.

The below example configurations are given for lazy.nvim but feel free to use your desired plugin manager.

Minimal

{
    "rolv-apneseth/tfm.nvim",
    config = function()
        -- Set keymap so you can open the default terminal file manager (yazi)
        vim.api.nvim_set_keymap("n", "<leader>e", "", {
            noremap = true,
            callback = require("tfm").open,
        })
    end,
}

Full

{
    "rolv-apneseth/tfm.nvim",
    lazy = false,
    opts = {
        -- TFM to use
        -- Possible choices: "ranger" | "nnn" | "lf" | "vifm" | "yazi" (default)
        file_manager = "yazi",
        -- Replace netrw entirely
        -- Default: false
        replace_netrw = true,
        -- Enable creation of commands
        -- Default: false
        -- Commands:
        --   Tfm: selected file(s) will be opened in the current window
        --   TfmSplit: selected file(s) will be opened in a horizontal split
        --   TfmVsplit: selected file(s) will be opened in a vertical split
        --   TfmTabedit: selected file(s) will be opened in a new tab page
        enable_cmds = false, 
        -- Custom keybindings only applied within the TFM buffer
        -- Default: {}
        keybindings = {
            ["<ESC>"] = "q",
            -- Override the open mode (i.e. vertical/horizontal split, new tab)
            -- Tip: you can add an extra `<CR>` to the end of these to immediately open the selected file(s) (assuming the TFM uses `enter` to finalise selection)
            ["<C-v>"] = "<C-\\><C-O>:lua require('tfm').set_next_open_mode(require('tfm').OPEN_MODE.vsplit)<CR>",
            ["<C-x>"] = "<C-\\><C-O>:lua require('tfm').set_next_open_mode(require('tfm').OPEN_MODE.split)<CR>",
            ["<C-t>"] = "<C-\\><C-O>:lua require('tfm').set_next_open_mode(require('tfm').OPEN_MODE.tabedit)<CR>",
        },
        -- Customise UI. The below options are the default
        ui = {
            border = "rounded",
            height = 1,
            width = 1,
            x = 0.5,
            y = 0.5,
        },
    },
    keys = {
        -- Make sure to change these keybindings to your preference,
        -- and remove the ones you won't use
        {
            "<leader>e",
            ":Tfm<CR>",
            desc = "TFM",
        },
        {
            "<leader>mh",
            ":TfmSplit<CR>",
            desc = "TFM - horizontal split",
        },
        {
            "<leader>mv",
            ":TfmVsplit<CR>",
            desc = "TFM - vertical split",
        },
        {
            "<leader>mt",
            ":TfmTabedit<CR>",
            desc = "TFM - new tab",
        },
    },
}

Configuration - UI

KeyTypeDefaultValue
borderstring"none"See :h nvim_open_win.
heightnumber1From 0 to 1 (0 = 0% of screen and 1 = 100% of screen).
widthnumber1From 0 to 1 (0 = 0% of screen and 1 = 100% of screen).
xnumber0.5From 0 to 1 (0 = left most of screen and 1 = right most of screen).
ynumber0.5From 0 to 1 (0 = top most of screen and 1 = bottom most of screen).

API

open()

Opens the TFM, focusing the file from the current buffer, and falling back to the CWD if that is not possible.

open(path_to_open, open_mode)

Opens the TFM at the given destination. If the path is a file, focuses that file. Selected file(s) will be opened with the given mode.

select_file_manager(file_manager)

Changes the selected file manager. This is not persistent so the change will be lost when restarting Neovim.

set_next_open_mode(open_mode)

Changes the next mode with which to open/edit selected files. Can be run while the terminal window is open.

enum OPEN_MODE

Enum to configure modes with which to open/edit selected files.

VariantAction
vsplitOpen files in vertical split
splitOpen files in horizontal split
tabeditOpen files in tab

Extras

Image previews

Image previews depend entirely on the terminal emulator + TFM combo you are using, as well as Neovim's support for the protocol being used. Any issues related to image previews are probably not related to this plugin as all this is doing is opening a terminal window in Neovim and running the TFM.

In the demo video, the combo being used is Wezterm + Yazi, using ueberzugpp.

Pure Lua keybindings

If you don't want to enable the commands, you can just use pure Lua keybindings:

    keys = {
        {
            "<leader>e",
            function()
                require("tfm").open()
            end,
            desc = "TFM",
        },
        {
            "<leader>mh",
            function()
                local tfm = require("tfm")
                tfm.open(nil, tfm.OPEN_MODE.split)
            end,
            desc = "TFM - horizontal split",
        },
        {
            "<leader>mv",
            function()
                local tfm = require("tfm")
                tfm.open(nil, tfm.OPEN_MODE.vsplit)
            end,
            desc = "TFM - vertical split",
        },
        {
            "<leader>mt",
            function()
                local tfm = require("tfm")
                tfm.open(nil, tfm.OPEN_MODE.tabedit)
            end,
            desc = "TFM - new tab",
        },
    },

Keybind to switch file manager

{
    "<leader>mc",
    function()
        require("tfm").select_file_manager(vim.fn.input("Change file manager: "))
    end,
    desc = "TFM - change selected file manager",
},

Contributing

Feel free let me know how I can improve this plugin by opening an issue. PRs are also welcome.

Credit

Other similar plugins