Crates.io | lsv |
lib.rs | lsv |
version | 0.1.0 |
created_at | 2025-09-14 15:02:00.811886+00 |
updated_at | 2025-09-14 15:02:00.811886+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 | 155,313 |
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 lsv
cargo build
cargo run
LSV_TRACE=1 LSV_TRACE_FILE=/tmp/lsv-trace.log cargo run
lsv loads a Lua config from the first of:
$LSV_CONFIG_DIR/lua/init.lua
$XDG_CONFIG_HOME/lsv/lua/init.lua
~/.config/lsv/lua/init.lua
Top‑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.-- Sample lsv config -- place in $HOME/.config/lsv/lua/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)
-- 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
.