File browser, command runner and editor toolkit for Vim/Neovim.

Installation

vim-plug
Plug 'mefardales/neofinder'
One-liner
curl -fsSL https://raw.githubusercontent.com/mefardales/neofinder/main/install.sh | bash
Vim 8+ native
git clone https://github.com/mefardales/neofinder.git ~/.vim/pack/plugins/start/neofinder
Neovim
git clone https://github.com/mefardales/neofinder.git ~/.local/share/nvim/site/pack/plugins/start/neofinder

Palette

Open with :Neo or <Leader>fp. Everything starts here:

Browse          :ff   file browser
Favorites       :fv   bookmarked directories
Buffers         :fb   open buffers
Tags            :fg   tagged file groups
Terminal        :fR   open terminal
Run             :fr   execute commands
Commands        :fe   edit/create commands
Config          :fc   config.toml

Keybindings

Palette & Navigation

<Leader>fpPalette
<Leader>ffFile browser
<Leader>fvFavorites
<Leader>fbBuffers
<Leader>fgTag groups
<Leader>ftTag file
<Leader>fuUntag file
<Leader>frRun commands
<Leader>feEdit commands
<Leader>fcConfig

Inside the Finder

EnterOpen / enter dir
BackspaceGo up / back
Ctrl-VVertical split
Ctrl-XHorizontal split
Ctrl-TTag file
Ctrl-DUntag / delete
Ctrl-BBuffer list
Ctrl-RRefresh cache
TabFinder ↔ editor
Ctrl-W +/-Resize panel
EscClose

Search Modes

The mode is detected automatically by what you type:

QueryMode
mainFuzzy match
*.pyGlob filter
test_*Glob filter
QueryMode
~/Navigate to home
/etc/Navigate to /etc
../Go up one level

File Browser

Open with <Leader>ff. Lists current directory. Type to search.

Fuzzy & Glob

Type letters for fuzzy match. Use *.py or test_* for glob patterns.

Path Navigation

Type ~/, /etc/, or ../ to jump to any directory.

Cached & Indexed

Listings are cached. Python indexes the full tree on first search (lazy, non-blocking).

Auto-cd

Set autochdir = true in config. cwd follows the active file.

Tags & Favorites

Tags

Bookmark files into named groups.

<Leader>ftTag current file
<Leader>fuUntag current file
<Leader>fgBrowse groups
Ctrl-TTag in finder
Ctrl-DUntag in finder

Stored in ~/.neofinder/tags:

servers:/etc/nginx/nginx.conf
dotfiles:/home/user/.bashrc

Favorites

Bookmark directories for quick access.

<Leader>fvOpen favorites
Enter on [+]Add current dir
EnterOpen browser there
Ctrl-DRemove favorite

Stored in ~/.neofinder/favorites, one dir per line.

Windows & Buffers

Windows

<Leader>svVertical split
<Leader>shHorizontal split
<Leader>scClose window
Shift+TabCycle windows
Shift+ArrowResize

Buffers & Terminal

<Leader>bnNext buffer
<Leader>bpPrevious buffer
<Leader>fbBuffer list
Shift+TabTerminal → editor
PageUp/DownScroll terminal

Command System

Every command is a .toml handler + .py logic. The TOML declares the contract (inputs, validation, output), the .py focuses on logic. Shell-only commands need no .py at all.

net_scan.toml (full handler)
name = "NetScan"
desc = "Ping sweep or port check"
deps = ["input", "output", "shell"]
out = "[Scan ${host}]"
filetype = "log"

[in]
host = "Host/IP: "

[validate]
commands = ["ping"]

[header]
show = true
separator = "="
width = 50
info = ["host"]

[error]
empty = "Host unreachable"
net_scan.py (pure logic)
# host is auto-injected from [in]
# header is auto-printed from [header]

stdout, stderr, rc = nf.sh(
    "ping -c 3 %s" % host
)
STDOUT.write(stdout.splitlines())

if rc != 0:
    STDERR.print("Host unreachable")
disk_usage.toml (shell-only, no .py)
name = "DiskUsage"
desc = "Disk usage summary"
deps = ["output", "shell"]
out = "[Disk Usage]"

[shell]
cmd = "df -h"

Handler fields

FieldTypeDescription
namestringCommand name (PascalCase)
descstringDescription in palette
depsarrayinput, output, shell, buffer, tags
outstringOutput buffer title. Supports ${var}
filetypestringSyntax highlight for output buffer (log, git, etc.)
timeoutintKill after N seconds
platformstringRestrict to OS: "linux,darwin"
silentboolIf true, don't open output buffer
pipestring"buffer" loads current buffer into STDIN

Input [in]

FormatExampleDescription
Simplehost = "Host: "String prompt
Defaultport = { prompt = "Port: ", default = "80" }Pre-filled value
Optionsmode = { prompt = "Mode: ", options = ["fast", "full"] }Select from list
Confirmok = { prompt = "Continue?", type = "confirm" }Yes/no dialog
Filepath = { prompt = "File: ", type = "file" }Path with tab completion

Sections

[validate]

commands = ["git"] require binaries
filetype = ["python"] restrict filetypes
min_lines = 1 buffer must have content

[env]

Auto-injected variables (no prompt):
timestamp = "datetime.now()..."
cwd = "nf.dir"

[header]

show = true auto-print header
separator = "=" width = 50
info = ["host"] show input vars

[shell]

Run shell cmd without .py:
cmd = "df -h"
Supports ${var} interpolation

[error]

empty = "No results" when STDOUT empty
fail = "Failed" on non-zero exit

[in] + [env] + [shell]

Combine them for powerful shell-only commands that ask input, validate, and run without any Python.

Pipeline

Chain steps like Airflow DAGs: a >> b >> c >> d. Each step's STDOUT flows as STDIN to the next.

Named steps (a >> b >> c)
[pipeline]
chain = "scan >> filter >> sort"
on_fail = "stop"

[pipeline.steps]
scan   = { type = "shell", cmd = "lsof -i -nP" }
filter = { type = "shell", cmd = "grep LISTEN" }
sort   = { type = "shell", cmd = "sort -k2" }
Step options
# Step types:
#   shell   = run shell command
#   command = run NeoFinder command
#   python  = eval python code

# on_fail per step or global:
#   stop     = abort pipeline
#   continue = keep going
#   skip     = skip, pass prev output
Pipeline output shows execution status per step with pass/fail indicators and a summary with final output.

Standard I/O

STDIN

.text .lines .varname
Input from handler [in] or pipe

STDOUT / STDERR

.print() .write()
STDOUT → output buffer. STDERR → error messages.

Python API

Available as nf.* inside every command.

Context

nf.file        # full path
nf.filename    # name only
nf.dir         # cwd
nf.line        # current line
nf.filetype
nf.theme

Shell

out, err, rc = nf.sh("cmd")
nf.sh_output("cmd")
nf.sh_lines("cmd")

Input

nf.input("prompt")
nf.confirm("sure?")
nf.select(["a", "b"])

Buffer

nf.buf.lines / .text / .name
nf.buf.line / .line_number
nf.buf.selection
nf.buf.write(x)
nf.buf.append(x)
nf.buf.clear()
nf.buf[0] = "x"

Files & Tags

nf.open(p) / .vsplit(p)
nf.split(p) / .scratch(lines)
nf.buffers()
nf.tags.groups()
nf.tags.files("group")
nf.tags.add(path, "group")

Messages

nf.echo("msg")
nf.warn("msg")
nf.error("msg")

Built-in Commands

CommandDescription
HelloWorldSystem check
HelloDemoAPI reference
RunHereRun shell command
GitLogGit commits
GrepHereGrep in cwd
CommandDescription
SortBufferSort buffer lines
TaggedFilesTags by group
NetInfoNetwork info
NetScanPort scan
NetConnsConnections

Configuration

All settings in ~/.neofinder/config.toml. Open with <Leader>fc. Save to apply instantly.

Theme & Finder
[theme]
name = "matrix"
brightness = 0           # -40 to 40
background = ""          # "" or "#1a1a2e"
bold_keywords = true
italic_comments = true
transparent_bg = false
guifont = ""             # "JetBrains Mono:h12"

[finder]
height = 15
preview = true
max_files = 50000
show_hidden = true
sort_by = "name"         # "name", "modified", "size"

[statusline]
enabled = true
show_clock = true
show_branch = true
Editor
[editor]
line_numbers = false
tabstop = 4
expandtab = true
autochdir = true
hidden = true
swapfile = false
undofile = true
splitright = true
mouse = "a"
Search & Save
[search]
ignorecase = true
smartcase = true
hlsearch = true

[on_save]
trim_whitespace = true
final_newline = true
Keybindings
[keybindings]
enabled = true

[keybindings.map]
Ctrl+s = ":w<CR>"
F5 = ":!python3 %<CR>"

# Single letter = <Leader>nf + letter
[keybindings.commands]
a = "NetInfo"
b = "NetScan"

Themes

matrix

Green on black (default)

Custom themes: ~/.neofinder/themes/<name>.vim. Set name = "matrix" under [theme] in config.

Project Structure

neofinder/
├── plugin/neofinder.vim            Commands, mappings, startup
├── autoload/neofinder.vim          Palette, browse, backend
├── autoload/neofinder/
│   ├── core.vim                    Finder UI, fuzzy/glob filter
│   ├── config.vim                  TOML config loader
│   ├── python.vim                  Command system (.py + .toml)
│   ├── tags.vim                    Tags, favorites
│   ├── actions.vim                 Open, split, tag, execute
│   ├── sources.vim                 Data gathering
│   ├── theme.vim                   Matrix theme + customizations
│   ├── statusline.vim              Powerline statusline
│   ├── preview.vim                 File preview
│   ├── buffers.vim                 Buffer manager, terminal
│   ├── indexer.vim + .py           Fast file indexer
│   ├── runtime.py                  Python runtime (nf.*)
│   ├── toml_parser.py              TOML parser
│   └── commands/                   Built-in .toml + .py pairs
├── docs/index.html                 This page
├── install.sh
└── README.md

Help

neofinder.txt For Vim/Neovim Last change: 2025 Jun 01
*neofinder.txt*    File browser, command runner and editor toolkit

Author:  mefardales
License: MIT
Repo:    https://github.com/mefardales/neofinder

CONTENTS                                            *neofinder-contents*

    1. Overview .............. |neofinder-overview|
    2. Quick start ........... |neofinder-quickstart|
    3. Mappings .............. |neofinder-mappings|
    4. Commands .............. |neofinder-commands|
    5. Configuration ......... |neofinder-config|

1. OVERVIEW                                          *neofinder-overview*

NeoFinder is a file browser with fuzzy/glob search, a tag
system, a command runner with Python scripting, and split/buffer
management.  Everything is accessed through a single palette.

2. QUICK START                                       *neofinder-quickstart*

Install with your plugin manager and run:
>
    :Neo
<
This opens the palette.  From there:

    :ff   file browser      :fv   favorites
    :fb   buffers           :fg   tag groups
    :fr   run command       :fe   edit commands
    :fc   config            :fR   terminal

3. MAPPINGS                                          *neofinder-mappings*

    <Leader>fp    Open palette
    <Leader>ff    File browser
    <Leader>fv    Favorites
    <Leader>fb    Buffers
    <Leader>fg    Tag groups
    <Leader>ft    Tag current file
    <Leader>fu    Untag current file

    Inside finder:

    <CR>          Open file / enter directory
    <BS>          Go up / back
    <C-v>         Open in vertical split
    <C-x>         Open in horizontal split
    <C-t>         Tag file
    <C-d>         Untag / delete
    <Tab>         Toggle finder / editor
    <Esc>         Close finder

4. COMMANDS                                          *neofinder-commands*

Commands are .toml + .py pairs in ~/.neofinder/commands/.

    :NeoRun {name}     Run a command by name
    :NeoEdit {name}    Edit a command
    :NeoNew            Create new command

The Python runtime exposes nf.* for shell, buffers, I/O:
>
    out, err, rc = nf.sh("ls -la")
    nf.buf.append(out.splitlines())
    nf.echo("Done")
<

5. CONFIGURATION                                     *neofinder-config*

All settings live in ~/.neofinder/config.toml.
Open with <Leader>fc and save to apply.
>
    [theme]
    name = "matrix"      " only theme: matrix

    [finder]
    height = 15
    preview = true

    [editor]
    tabstop = 4
    expandtab = true
<

vim:tw=78:ts=8:ft=help:norl: