trail-fm 1.11.1

A terminal-first workspace for navigating, inspecting and acting on the filesystem
Documentation
# Trail default configuration.



[general]

editor = "nvim"

# Shell that runs `!<command>` and `:git`: a program, then the flags that make

# it read a command string as one argument.  Empty keeps the platform default

# -- `cmd.exe /C` on Windows, `sh -c` elsewhere -- which is what Trail has

# always used, so leaving this alone changes nothing.

#

# Set it to pick a different interpreter, e.g. `pwsh -NoProfile -Command` on

# Windows so that `./program` and other POSIX-ish spellings resolve (cmd.exe

# reads a leading `/` as a switch and fails on `./program`), or `bash -c` to

# get bash syntax instead of whatever `sh` is on this system.  The trade-off is

# startup cost per command -- pwsh is markedly slower to launch than cmd.exe,

# and `-NoProfile` is what keeps that from getting worse -- and that shell

# builtins stop matching the ones your muscle memory expects.

#

# Whitespace separates tokens; double-quote a program path containing spaces.

# Windows paths need a TOML literal string, e.g.

# shell = '"C:\Program Files\PowerShell\7\pwsh.exe" -NoProfile -Command'

shell = ""

# Whether to wait for Enter after a `!<command>` or `:git` finishes, before

# Trail takes the screen back: always | on_error | never.

#

# A command's output is printed on the normal screen, which Trail covers again

# the moment the command exits -- so without a pause, `!ls` paints its output and

# erases it in the same breath.  The trade-off is a keystroke per command: set

# `on_error` to be held up only when something failed, or `never` if you run

# commands for their effect rather than their output and would rather read them

# in the log.  Opening a file in the editor never pauses whatever this says --

# an editor owns the screen while it runs and leaves nothing behind to read.

shell_pause = "always"

# How much of a file the preview reads, in KiB.  Together with

# `[preview] max_lines` this bounds one preview: max_lines stops an ordinary

# file, this stops one whose lines are enormous -- minified JavaScript, a

# one-line JSON blob -- which would otherwise be loaded whole however few lines

# it has.  Either ceiling marks the pane's footer with a `+`.  Raising it lets

# you scroll further into such a file, at proportionally more worker time and

# memory per preview.  The name is historical: it once chose which files were

# highlighted on the UI thread, which none are now.

text_sync_threshold_kb = 256

# Where `dd` sends an entry: trash | permanent.

#

# `trash` hands it to the platform's recycle bin, so a mistake is recoverable by

# the user without Trail's help -- and `dd` on a directory takes everything under

# it, which is exactly the mistake worth being able to undo.  The trade-offs are

# that deleting no longer frees the space until the bin is emptied, and that a

# path the recycle bin refuses (a network share, a removable volume without one)

# is reported as an error rather than silently deleted anyway.  Use `permanent`

# for the old behaviour, and read the confirmation prompt: it says which one is

# about to happen.

delete_mode = "trash"

# Show Trail's version on the preview pane's top border.

#

# A diagnostic, not decoration: `trail --version` cannot be asked of a session

# that is already running, and on Windows an upgrade leaves older sessions alive

# on the previous binary -- they cannot be overwritten, only renamed aside -- so

# several windows can be running different builds and look identical.  Turn this

# on when that matters; it costs the right-hand end of a border that is drawn

# either way, and it is hidden when a long file name needs the room.

# A dev build reads `v1.10.1-dev.3+f7863b6` (3 commits past v1.10.1, at that

# commit, `.dirty` if built with uncommitted changes) in the git_dirty colour,

# so a build under test is never mistaken for a release.

show_version = false

git_status_enabled = true

fs_watch_debounce_ms = 200



[navigation]

# How the listing is ordered: name | size | modified | extension.

#

# `size` puts the largest first and `modified` the most recent first, the way

# `ls -S` and `ls -t` do -- the end of the range you went looking for.  `name`

# and `extension` run A-Z.  `sort_reverse` flips whichever of those is active.

#

# This seeds the first tab only.  Each tab then owns its order, so `ss` in a

# downloads tab does not re-sort the source tree in the next one, and a new tab

# inherits the order of the tab it was opened from.

sort_by = "name"

sort_reverse = false

# Group directories ahead of files whatever `sort_by` says.  This is an axis of

# its own: `sort_reverse` does not flip it, because reversing a listing is

# asking for the files in the other order, not for the directories to move to

# the bottom.  Set false to rank directories among the files -- though note that

# a directory has no meaningful size, so a size sort keeps them in name order

# either way.

dirs_first = true

# What each row shows beside the name: none | size | modified | both.

#

# The navigation panel is 40% of the screen -- 28 columns on an 80-column

# terminal -- and `both` wants 26 of them, so the column stands down rather than

# crushing names when there is not room for a readable name beside it.  On a

# narrow panel `both` first drops the clock time and keeps the date.  Default is

# `none`: the name is what you navigate by, and the preview pane already shows

# size and modification time for whatever is selected.

entry_details = "none"

# Rows kept between the selection and the top or bottom of the panel while

# scrolling -- vim's `scrolloff`.  The margin gives up at the true ends of the

# listing, so the first entry still reaches the top row and the last entry the

# bottom one.  0 lets the selection ride the edge, which shows the least context

# and scrolls the most.  A value larger than half the panel keeps the selection

# centred.

scroll_margin = 3



[preview]

# Inline-image protocol: auto | kitty | iterm2 | sixel | halfblocks | none

image_protocol = "auto"

# Terminal character cell size in pixels.  0 detects it where the platform will

# say (never on Windows) and otherwise assumes a deliberately small default, so

# that an image errs towards leaving a margin rather than overflowing the pane

# and being dropped by the terminal.  Set a real measurement to fill the pane

# exactly: lower these if images overflow, raise them if images look too small.

image_cell_width = 0

image_cell_height = 0

# How many lines of a text file the preview loads.  The preview scrolls within

# this window (J/K, Shift-arrows, Ctrl-f/Ctrl-b) and its footer marks a file

# that continues past it with a "+".  Raising this lets you scroll further into

# long files, at proportionally more worker time and memory per preview; the

# accepted range is 1 to 100000.

max_lines = 2000



[terminal]

# The terminal panel: real, interactive shells under the file list.  Ctrl-.

# shows and hides it, F12 moves the keyboard between the file list and the

# shell; `:term new [profile]`, `:term close`, `:term <n>` and `:term max` do

# the rest.  Nothing starts until the panel is first opened.

#

# Which profile a new shell runs.  Blank means the first [[terminal.profile]],

# or -- with none configured -- PowerShell 7 if installed, else Windows

# PowerShell (on Linux/macOS: $SHELL).

default_profile = ""

# The panel's height as a percentage of the screen above the status bar, 10-90.

# A screen too short for both the file list and the panel gives the panel all

# of it.  `:term max` fills the screen and restores it.

height = 35

# Whether quitting Trail, and `:term close`, ask before ending shells:

#   when_busy -- only if a shell is running a command (default).  Trail tells by

#                whether the shell has child processes; when it cannot tell, it

#                asks, rather than risk ending a build.

#   always    -- every time there is a shell to end.

#   never     -- end them at once, whatever they are doing.

confirm_quit = "when_busy"

confirm_close = "when_busy"

# Named shells.  `command` is the program and its arguments, run directly (no

# shell parses it, so nothing in it is expanded).  For example:

#

#   [[terminal.profile]]

#   name = "pwsh"

#   command = ["pwsh.exe", "-NoLogo"]

#

#   [[terminal.profile]]

#   name = "gitbash"

#   command = ['C:\Program Files\Git\bin\bash.exe', "--login", "-i"]

#

# Listing profiles in your own config replaces this empty list.

profile = []



[theme]

foreground = "white"

background = "black"

border = "dark_gray"

selection_fg = "black"

selection_bg = "dark_gray"

directory = "blue"

symlink = "cyan"

hidden = "dark_gray"

status_fg = "dark_gray"

error = "red"

search = "yellow"

command = "cyan"

git_clean = "green"

git_dirty = "yellow"



[keymap.navigation]

move_down = "j"

move_up = "k"

jump_bottom = "G"

jump_top = "gg"

enter_or_open = "l"

go_parent = "h"

history_back = "u"

history_forward = "ctrl-r"

# Return from a jump: back to where the last :jump was made from, however far

# you wandered after it landed.  u steps back one directory at a time; U skips

# everything since the jump.

return_from_jump = "U"

refresh = "R"

toggle_hidden = "."

# Listing order, per tab.  `s` is a prefix rather than a binding of its own, so

# the second key picks the field: name, size, time, extension.  `sr` flips the

# order and `sd` toggles directory grouping.

sort_name = "sn"

sort_size = "ss"

sort_time = "st"

sort_extension = "se"

sort_reverse = "sr"

sort_dirs_first = "sd"

# Step the details column through none -> size -> modified -> both -> none.

toggle_details = "m"

copy_absolute_path = "ya"

copy_relative_path = "yr"

copy_filename = "yn"

copy_content = "yc"

delete = "dd"

# Marks survive navigation: mark here, paste somewhere else.  Space marks the

# selection and moves down; Esc clears every mark (it does nothing else in

# Navigation Mode, so nothing is lost by giving it this job).

toggle_mark = "space"

clear_marks = "esc"

# Paste the marked entries into the directory you are looking at.  `p` is a

# prefix: pp copies (the marks stay, so the same set can be pasted again), pm

# moves (the moved entries leave the mark set).  A name already taken here is

# skipped and reported, never overwritten.

paste_copy = "pp"

paste_move = "pm"

# Visual mode: v anchors a range at the selection, and moving extends it.

# Space or v adds the range to the marks, h/l add it and then navigate, dd

# deletes it, Esc abandons it.

enter_visual = "v"

# Repeat the last file operation: a : or ! command, or dd, pp or pm, whichever

# came last (a repeated dd still asks).  Moving and marking never replace it.  @ works

# however your layout types it: Shift+2 on US English, AltGr+Q on Spanish and

# Latin American, AltGr+Q on German.

repeat_command = "@"

enter_search = "/"

enter_command = ":"

quit = "q"

open_with_os = "o"

new_tab = "ctrl-t"

close_tab = "ctrl-w"

switch_tab_next = "tab"

switch_tab_prev = "shift-tab"

# Preview pane scrolling.  Shift-down and Shift-up are built-in aliases for the

# first two, the same way the plain arrows alias move_down/move_up.

preview_scroll_down = "J"

preview_scroll_up = "K"

preview_page_down = "ctrl-f"

preview_page_up = "ctrl-b"

preview_scroll_top = "shift-home"

preview_scroll_bottom = "shift-end"



[keymap.search]

# Search Mode is a typing mode: unmodified characters go into the query, so

# these must be named or modified keys.  Binding a bare letter here is a

# config error -- it would make that letter impossible to search for.

# Ctrl-n / Ctrl-p / Ctrl-h also work as built-in aliases.

exit = "esc"

confirm = "enter"

move_down = "down"

move_up = "up"

delete_char = "backspace"



[keymap.terminal]

# The terminal panel's keys.  Each is one chord -- ctrl-, alt-, shift- plus a

# character or a key name (f1-f12, pageup, pagedown, home, end, insert, delete,

# enter, esc, tab, space, arrows).

#

# toggle and focus work from anywhere.  The other four are taken only while the

# shell has the keyboard, and every key here is one no program in the shell can

# receive -- which is why they avoid everything shells, vim and Windows Terminal

# already use.  F12 in particular is used by none of them.  The four PageUp /

# PageDown keys carry Alt because terminals keep Ctrl- and Shift-PageUp for

# themselves (WezTerm switches tabs and scrolls its own window with them), so

# Trail would never see them.

toggle = "ctrl-."

focus = "f12"

next_shell = "alt-shift-pagedown"

prev_shell = "alt-shift-pageup"

scroll_up = "alt-pageup"

scroll_down = "alt-pagedown"



[plugins]

enabled = []