TUI file browsers are overrated

#dev #workflow

20 June 2026


Share

The catalyst

I recently built a Linux config for my Thinkpad - this config is running Debian entirely in the tty, using tmux as its "window manager". I built it for the purpose of increasing my focus whilst writing and coding, as well as developing my understanding of Linux (you can browse the config here)

A certain conundrum

When building a terminal-only config such as mine you may start wondering: "how do I navigate my file-system without a GUI file browser?". The quick answer is: "learn to navigate with the CLI like an adult". The long answer is as follows...

On places such as Youtube and Reddit you often come across people running TUI file browsers, and I wonder why? A CLI will always be faster, always be more portable, and always be easier to configure. One argument I've heard for why one would want to use a TUI file browser such as Yazi is because you get one tool where you can view images (presuming that your terminal supports it), view git diffs, execute bulk-operations on several files, among other things.

TUI file browsers are dumb

My general argument for why one should not use a TUI file browser is that a file browser with tabs, scroll features, mouse drag/drop support, and image support is not necessarily idiomatic to the classic terminal UX meta. As a terminal power-user I love the terminal, but I am also aware of its shortcomings. Whatever GUI file browser your OS is shipped with is already designed for viewing images, navigating with your mouse cursor, perhaps even watch a video or two! So why not use that?

It feels like using a TUI browser can't be justified for efficiency reasons, it more so only feels like a matter of philosophy - some peoples philosophy is that anything that can be done in the terminal should be done in the terminal since it is "faster". Could someone tell me what is "faster" about spending hours and hours configuring (and learning) the latest TUI application that's trending this week, compared to just using your OS file browser to get the job done? Or even better, just use the standard Unix commands, or perhaps fzf and exa if you want to get fancy.

How to navigate your files like a true terminal elitist

With all this said though, I can definitely see the point in getting a more graphical overview of your files sometimes. But for these cases, there are already battle-tested solutions you can use right now.

The main way that I navigate my files is a using exa as mentioned previously, in combination with the standard cd command - the nice thing with exa is its --tree command which gives you a hierarchical view of the current directory!

This is my exa configuration, where the ta command is my bread-and-butter command I use the most and ls has been overridden giving me a more detailed view with dates, file permissions and so on.

alias ta='exa -a --icons -I ".DS_Store|.git|.gitignore"'
alias ls='exa -al --git --sort modified'

Right now, you may be thinking: "Ok, cool, you have a fancy ls command, but in my TUI file browser I can set favorite folders and move between them!". But don't you worry, because I've got this in the CLI too by using fzf scripts!

#!/usr/bin/env bash

# recursive grep in files
g() {
    local query="${*:-}"

    local -a rg_opts=(
        --column
        --line-number
        --no-heading
        --color=never
        --smart-case
        --hidden
        --glob '!.git/'
        --glob '!target/'
        --glob '!node_modules/'
        --glob '!.gitignore'
        --glob '!*.lock'
    )

    local reload_cmd
    reload_cmd="rg $(printf "%q " "${rg_opts[@]}") {q} . 2>/dev/null || true"

    fzf --disabled \
        --query "$query" \
        --delimiter : \
        --preview 'bat --style=numbers --highlight-line {2} {1}' \
        --preview-window '~3,+{2}/2' \
        --bind "start:reload:$reload_cmd" \
        --bind "change:reload:$reload_cmd" \
        --bind 'enter:become(nvim "+call cursor({2},{3})" -- {1})'
    return 0
}

# local search
s() {
    local target
    target=$(fd --type f --type d --hidden | fzf --preview='[[ -d {} ]] && exa -al {} || bat --style=numbers {}') || return
    if [[ -d $target ]]; then
        cd "$target"
    elif [[ -f $target ]]; then
        case "$target" in
            *.pdf)
                mupdf "$target" & disown
                ;;
            *)
                nvim "$target"
                ;;
        esac
    fi
    return 0
}

# global search
ss() {
    local target
    target=$(fd --type f --type d --hidden . ~ | \
        fzf --preview='[[ -d {} ]] && exa -al {} || bat --style=numbers {}') || return
    if [[ -d $target ]]; then
        cd "$target"
    elif [[ -f $target ]]; then
        case "$target" in
            *.pdf)
                mupdf "$target" & disown
                ;;
            *)
                nvim "$target"
                ;;
        esac
    fi
    return 0
}

# favorites
jump() {
    local entries=(
        $'downloads\t'"$HOME/Downloads"
        $'desktop\t'"$HOME/Desktop"
        $'dotfiles\t'"$HOME/dotfiles"
        $'notes\t'"$HOME/notes"
        $'nvim config\t'"$HOME/dotfiles/nvim/.config/nvim"
        $'website\t'"$HOME/dev/rust/website_2027"
        $'development\t'"$HOME/dev"
      )

  local selected label target

  selected="$(
    printf '%s\n' "${entries[@]}" \
      | fzf --prompt=" " \
            --height=40% \
            --reverse \
            --border \
            --delimiter=$'\t' \
            --with-nth=1
  )" || return

  label="${selected%%$'\t'*}"
  target="${selected#*$'\t'}"

  # expand ~
  eval "target=\"$target\""

  if [[ -d "$target" ]]; then
    cd "$target" || return
  elif [[ -f "$target" ]]; then
    nvim "$target"
  else
    printf 'Not found: %s\n' "$target" >&2
    return 1
  fi
}

"$@"

The most notable function out of all these is the jump() command, where I can spawn an fzf instance and jump between either folders or files, opening the chosen favorite in the terminal or in neovim respectively.

The conundrum continues in Neovim

The TUI file browser disease continues in terminal text editors as well, and I am tired of seeing people using oil.nvim and neo-tree.nvim when Neovim/Vim has already given us the glorious netrw.

Here is my netrw config.

local g       = vim.g; local bo = vim.bo
local cmd     = vim.cmd; local map = vim.keymap.set
local autocmd = vim.api.nvim_create_autocmd;

function M.setup()
    g.netrw_altfile        = 1; vim.g.netrw_fastbrowse = 2
    g.netrw_liststyle      = 3; g.netrw_banner = 0; g.netrw_dirhistmax = 0
    g.netrw_preview        = 1; g.netrw_keepdir = 0; bo.bufhidden = "wipe"
    vim.g.netrw_localrmdir = "rm -r"

    map("n", "<leader>f", function()
        local dir = vim.fn.getcwd()
        cmd("Explore " .. vim.fn.fnameescape(dir))
    end)

    autocmd({ "FileType", "BufWinEnter" }, {
        pattern = "netrw",
        callback = function()
            local opts = { buffer = true, noremap = true, silent = true }
            map("n", "n", "h", opts)
            map("n", "e", "j", opts)
            map("n", "o", "k", opts)
            map("n", "i", "l", opts)
            vim.wo.relativenumber = true
            vim.wo.number = true
        end,
    })
end

The two real crucial settings here is to set liststyle to 3 (view as tree hierarchy) as well setting relative line numbers in netrw buffers with an autocommand so that you can jump around files quickly. (And yes, I've remapped all my hjkl bindings because of an alternate keyboard layout! I might make a post about that journey in the future.)

I don't really have a note to end on, and so I will just leave you here! Hope you learned something!


Related posts