| Crates.io | lsv |
| lib.rs | lsv |
| version | 0.1.3 |
| created_at | 2025-09-14 15:02:00.811886+00 |
| updated_at | 2025-09-24 21:11:14.261335+00 |
| description | Three‑pane terminal file viewer (TUI) with preview and Lua configuration |
| homepage | https://github.com/SecretDeveloper/lsv |
| repository | https://github.com/SecretDeveloper/lsv |
| max_upload_size | |
| id | 1838884 |
| size | 206,231 |

lsv is a fast, curses‑based file viewer for the terminal. It presents three panes side by side:
The app is keyboard‑driven, configurable via Lua, and supports rich, ANSI‑colored previews from external tools (e.g., bat, glow).
cargo install lsvSee the documentation overview for setup guides, configuration reference, keybindings, and troubleshooting tips.
Requires the Rust nightly toolchain (repo pins via rust-toolchain.toml). Install with rustup toolchain install nightly if you don't have it yet.
Components rustfmt and clippy are listed in rust-toolchain.toml; rustup installs them automatically when you run the commands below.
Build: cargo build
Run: cargo run
Optional trace logging: LSV_TRACE=1 LSV_TRACE_FILE=/tmp/lsv-trace.log cargo run
lsv loads a Lua config from the first of:
$LSV_CONFIG_DIR/init.lua$XDG_CONFIG_HOME/lsv/init.lua~/.config/lsv/init.luaTop‑level Lua API:
lsv.config({ ... }): core settings (icons, keys, ui, etc.).lsv.set_previewer(function(ctx) ... end): return a shell command to render preview.lsv.map_action(key, description, function(lsv, config) ... end): bind keys to Lua functions.Action helper functions available on lsv inside actions:
lsv.select_item(index): set the current selection to index (0-based).lsv.select_last_item(): select the last item in the current list.lsv.quit(): request the app to exit.lsv.display_output(text, title?): show text in a bottom Output panel.lsv.os_run(cmd): run a shell command and show its captured output in the Output panel. Env includes LSV_PATH, LSV_DIR, LSV_NAME.Context data passed to actions via config.context:
cwd: current working directory.selected_index: current selection index (or a sentinel if none).current_len: number of items in the current list.path: absolute path of the selected entry (falls back to cwd).parent_dir: parent directory of the selected entry (falls back to cwd).name: file name (basename) of the selected entry, when available.-- Sample lsv config — place in $HOME/.config/lsv/init.lua
lsv.config({
config_version = 1,
keys = { sequence_timeout_ms = 0 },
ui = {
panes = { parent = 20, current = 30, preview = 50 },
show_hidden = true,
date_format = "%Y-%m-%d %H:%M",
display_mode = "absolute", -- or "friendly" (affects both dates and sizes)
theme_path = "themes/dark.lua", -- swap to "themes/light.lua" or any palette under themes/
-- Optional row layout: icon/left/middle/right with placeholders
row = {
icon = "{icon} ",
left = "{name}",
middle = "",
right = "{info}",
},
},
})
-- Safe shell quote helper
local function shquote(s)
return "'" .. tostring(s):gsub("'", "'\\''") .. "'"
end
-- Example: bind "gs" to git status of the current directory
lsv.map_action("gs", "Git Status", function(lsv, config)
local dir = (config.context and config.context.cwd) or "."
lsv.os_run("git -C " .. shquote(dir) .. " status")
end)
-- Previewer function (ctx):
-- ctx = {
-- path = absolute file path (string)
-- directory = parent directory (string)
-- extension = file extension without dot (string, may be empty)
-- is_binary = boolean (simple heuristic)
-- height = preview pane height in rows (number)
-- width = preview pane width in columns (number)
-- preview_x = top-left x of preview pane (number)
-- preview_y = top-left y of preview pane (number)
-- }
-- Return a shell command string (placeholders are expanded: {path},{directory},{name},{extension}), or nil to use default head preview.
lsv.set_previewer(function(ctx)
-- Render Markdown with glow, respecting pane width
if ctx.extension == "md" or ctx.extension == "markdown" then
-- You can build a command with placeholders:
return "glow --style=dark --width=" .. tostring(ctx.width) .. " {path}"
end
if
ctx.extension == "jpg"
or ctx.extension == "jpeg"
or ctx.extension == "png"
or ctx.extension == "gif"
or ctx.extension == "bmp"
or ctx.extension == "tiff"
then
-- image preview using viu (needs installation)
return "viu --width '{width}' --height '{height}' '{path}'"
end
-- For non-binary, colorize with bat (first 120 lines, no wrapping)
if not ctx.is_binary then
return "bat --color=always --style=numbers --paging=never --wrap=never --line-range=:120 {path}"
end
-- Fallback to default preview (first N lines)
return nil
end)
lsv.map_action(key, description, function(lsv, config) ... end).config (e.g., config.ui.sort = "size") and using helpers like lsv.select_item(...).Default action bindings
sn (by name), ss (by size), sr (toggle reverse)zn (none), zs (size), zc (created)zf (friendly), za (absolute)gg (top), G (bottom)zm (toggle messages), zo (toggle last output), ? (which‑key)Override example
-- Change the default for "ss" to also show sizes in the info column
lsv.map_action("ss", "Sort by size + show size", function(lsv, config)
config.ui.sort = "size"
config.ui.show = "size"
end)
? to toggle a bottom overlay listing available keys (uses descriptions).ss, zc). The overlay opens automatically when you type a registered prefix.To enable a timeout, set keys.sequence_timeout_ms in your Lua config:
lsv.config({
keys = { sequence_timeout_ms = 600 }, -- 600ms timeout for sequences
})
Configure row sections under ui.row:
{icon}, {name}, {info}.display:absolute uses ui.date_format (default %Y-%m-%d %H:%M); display:friendly uses relative strings (e.g., 3d ago).display:absolute shows raw bytes with B; display:friendly uses human units (KB/MB/...).{path}: absolute file path{directory} (alias {dir}): parent directory{name}: basename of file{extension}: extension without dot{width}, {height}: preview pane size in characters{preview_x}, {preview_y}: preview pane top‑left coordinates$f: shorthand for {path}Environment for external commands:
LSV_PATH (selected file), LSV_DIR (directory), LSV_NAME (basename)--color=always (bat) or set styles (glow). lsv sets FORCE_COLOR=1 and CLICOLOR_FORCE=1 for preview commands.ui.preview_lines lines.LSV_TRACE=1 (default log path: $TMPDIR/lsv-trace.log or /tmp/lsv-trace.log).LSV_TRACE_FILE=/path/to/log.