lx β file Lister eXtended
lx ("alex") is a modern file lister for Unix; that is, a replacement for
the standard ls command.
Butβ¦ lx is a file lister with personality! π
Highlights
What makes lx stand out from the crowd?
-
Personalities β named profiles that bundle columns, flags, and settings π
Create symlinks (e.g.
ll,la,du,tree) andlxadapts its behaviour to the name it's invoked as! And all this without a shell alias in sight! -
Fully configurable column layout
Complete control over displayed columns and their order (
--columns=perms,size,user,modified), as well as the ability to define and use named column sets known as "formats". -
"Compounding" flags β flags that compound their effect when repeated
For example: Use
-lfor a long listing,-llfor more detail, and-lllfor even more. No more remembering which combination of-g,-H,-h, and--gityou need! -
Configuration file β optional, obviously
One
lxconfig.tomlreplaces all your shell aliases and environment variables. Define formats, personalities, and more! Runlx --init-configto get started. -
Named colour themes, styles, and file-type classes
The design-conscious power user can define themes, styles, and file-type classes in the config file using human-readable colour names. Everything inherits, composes, and can be overridden. Themes can be applied explicitly with the
--themeflag, but they're designed to be assigned to personalities! -
Unified VCS support β including Jujutsu!
Built-in backends for both Git and Jujutsu. VCS auto-detection supported.
For the design principles behind the CLI, see docs/DESIGN.md.
Quick start
Don't have
lxyet? Jump to Installation to get it, then come back here.
The best way to start using lx is to⦠just start using it. Flags differ from
those of ls, but if you get stuck, --help is your friend!
If you feel lx -lTFZL2 is perhaps a bit much to remember, the time has come
to define a new personality!
Note that
lxis explicitly not a drop-in replacement for POSIXls.
A file lister with personality π
Since time immemorial (or at least since Unix shells supported command
aliasing), Unix users have used shell aliases to call ls with certain
options. For example, it's very common to alias ll to list files in the long
format:
Or la for a long listing that also shows hidden files:
lx embraces the idea of being called by different names. It calls this
"personalities". The idea is pretty simple:
-
Define a personality in
lx's configuration βll, for instance:[] = "long" -
Invoke
lxasllby creating a symlink namedllthat points tolx, for example:
Whenever you invoke lx under a different name and a personality with that
name is defined, lx behaves like that personality. (If no personality with
the given name exists, lx adopts its default personality named lx.)
Personalities can inherit from each other. For instance, you can create an la
personality that behaves just like ll, but shows hidden files as well:
[]
= "ll"
= true
lx ships with some default, built-in personalities. You can redefine these in
the configuration file.
defaultis the base personality used to define default settings, inherited by other personalities. Note that there's nothing magical about the namedefault; you can define your own base personality with a different name.lxislx's standard personality, and is used when no other personality has been invoked.llis a long file listing, likelx -l; it shows VCS information and groups directories firstlais likellbut also shows hidden files (likels -la)lllis an even more expansive file listing with headers, likelx -llltreeis a recursive file listing showing a graphical file tree, with directories firstlsmakeslx's output look more like that of standard POSIXls
You can test personalities with the -p/--personality flag. To see what ll
or tree will look like:
Of course, you can still use shell aliases with lx. Personalities are an
alternative that offer you a more structured way of doing the same thing.
For more on how personalities are configured β including the inheritance tree and all available settings β see Personalities in the Configuration section below.
Configuration
Personalities β and other aspects of lx's behaviour β can be
defined in a configuration file.
Of course the configuration file is optional.
lxis just a file lister after all, and it's designed to work just fine with its compiled-in defaults. The configuration file is a tool for the user who wants more flexibility!
Generate a starter config with:
This creates ~/.lxconfig.toml. The file is self-documenting β prose comments
(starting with ##) explain each section, while commented-out values (starting
with #) show the compiled-in defaults you can customise.
The configuration has five kinds of named section, each controlling
a different aspect of lx's behaviour:
| Section | Purpose | Example |
|---|---|---|
[format] |
Column layouts for long view (flat keys) | long = ["perms", "size", "user", "modified"] |
[personality.NAME] |
Bundles of settings, activated by name | inherits = "lx", format = "long2", sort = "age" |
[theme.NAME] |
UI element colours (directories, dates, etc.) | directory = "bold blue", date = "steelblue" |
[style.NAME] |
File-type colours (by class, glob, or filename) | class.source = "yellow", "*.rs" = "#ff8700" |
[class] |
Named file-type categories (lists of glob patterns) | media = ["*.jpg", "*.png", "*.mp4"] |
These sections compose naturally:
- personalities use formats and themes
- themes use styles
- styles use classes
personality βββ format (column layout)
β
ββββ theme βββββββ style βββββββββ class
(UI colours) (file colours) (pattern lists)
Personalities and themes support inheritance. In other words, a personality can be based on another personality, and a theme can be based on another theme. Styles and classes, by contrast, are simple flat definitions.
For the full reference, see the
lxconfig.toml(5) man page.
Formats
Formats are defined as keys in a [format] section. Each key
is a format name and its value is a list of column names:
[]
= ["perms", "size", "modified"]
= ["perms", "size", "user", "group", "modified", "vcs"]
Available column names:
| Column | Shows |
|---|---|
perms |
Permission bits |
size |
File size |
user |
Owner |
group |
Group |
links |
Hard link count |
inode |
Inode number |
blocks |
Block count |
octal |
Octal permissions |
modified |
Last modified time |
changed |
Last status change time |
accessed |
Last access time |
created |
Creation time |
vcs |
VCS status |
The built-in formats long, long2, and long3 are used by the flags
-l, -ll, and -lll. You can override them by simply redefining them.
[]
= ["perms", "size", "user", "modified"]
= ["perms", "size", "user", "group", "modified", "vcs"]
= ["perms", "links", "size", "blocks", "user", "group",
"modified", "changed", "created", "accessed", "vcs"]
You can explicitly use a format with --format=NAME, but more often
you will want to use formats in personalities by using the format keyword.
Personalities
As described above, a personality
bundles format, columns, and settings under a name. Every CLI flag
has a corresponding config key (e.g. --sort=age becomes
sort = "age").
The built-in personalities form an inheritance tree:
default βββ¬βββ lx βββ¬βββ ll βββ la
β ββββ lll
ββββ tree
ls (standalone β no inherits)
The child's format/columns replace the parent's; settings merge
with the child winning. Define your own and wire them into the tree
however you like:
[] # all files, including hidden
= "ll"
= true
[] # time-sorted long listing
= "ll"
= "age"
[] # recently modified files
= "long"
= "modified"
= true
[] # du replacement: dir sizes
= ["size"]
= true
= true
= 2
= "size"
= true
= true
Upgrading from 0.1 or 0.2: run
lx --upgrade-configto migrate your config file to the current 0.3 format. Both 0.1β0.3 and 0.2β0.3 migrations are supported. A.bakbackup of the original is saved.
Themes, styles, and classes
Colour customisation uses three kinds of config section that work together:
- Themes (
[theme.NAME]) set colours for UI elements: directories, permissions, dates, VCS status, etc. - Styles (
[style.NAME]) set colours for files β either by referencing a named class or by matching a glob pattern / filename. - Classes (
[class]) define named file-type categories as lists of glob patterns:media,source,archive, etc. Once defined, a class can be styled as a unit.
lx provides a built-in theme named "exa", and a built-in style, also named
"exa". These provide sensible defaults out of the box, mirroring the
exa app. You can redefine these, or define
your own.
The "exa" style is provided (commented-out) in the default ~/.lxconfig.toml
created by lx --init-config. The "exa" theme was too large to be included,
but it is documented in the lxconfig.toml(5) man
page.
To define your own theme and/or style:
[]
= "exa" # start from the compiled-in defaults
= "bold dodgerblue"
= "steelblue"
= "bold mediumspringgreen"
= "dev" # reference a named style set
[]
= "#ff8700" # class reference (bare dotted key)
= "sandybrown" # glob pattern (quoted key)
= "bold underline yellow" # exact filename (quoted key)
Classes let you group file types by category in order to style them:
[]
= ["*.rs", "*.py", "*.js", "*.go"]
= ["*.csv", "*.json", "*.xml"]
lx ships with built-in classes for image, video, music,
lossless, crypto, document, compressed, compiled, temp,
and immediate (build/project files). The definitions of these were left out
of the default ~/.lxconfig.toml for the sake of brevity, but you can find
them in the lxconfig.toml(5) man page.
Override any of the defaults by redefining the name in your [class] section.
Or define your own file classes, as in the example above.
Select a theme through a personality or from the command line:
[]
= "ocean" # all personalities inherit this
Colour values accept named ANSI colours ("bold blue"), X11/CSS
names ("tomato", "cornflowerblue"), hex ("#ff8700"),
256-colour ("38;5;208"), and modifiers (bold, dimmed,
italic, underline).
Themes can inherit from other themes. The special name "exa"
refers to the compiled-in default theme and style. Without
inherits, a theme starts from a blank slate.
Curated themes
lx ships with ready-made themes in the themes/ directory:
| theme | filename |
|---|---|
| Catpuccin Mocha | catpuccin-mocha.toml |
| Dracula | dracula.toml |
| Gruvbox Dark | gruvbox-dark.toml |
| Nord | nord.toml |
| Solarized Dark | solarized-dark.toml |
| Solarized Light | solarized-light.toml |
To install a theme, simply copy it to the drop-in configuration directory (See Config file locations below).
Activate a theme on the command line with the --theme flag:
Or associate the theme permanently with a specific personality in your configuration. For instance, to set a theme as default for all personalities that inherit from the default:
[]
= "dracula"
See themes/README.md for instructions for creating your
own.
See lxconfig.toml(5) for the full
list of theme keys, style syntax, and built-in class definitions.
Debugging your configuration
To see the active configuration, use lx --show-config. To extract
copy-pasteable TOML definitions for any config object, use the --dump-*
flags:
Config file locations
lx searches for its config file in this order (first found wins):
$LX_CONFIGβ set this environment variable to point to a config file at any path. Useful for testing or per-project configs.~/.lxconfig.tomlβ the simplest option; just drop a file in your home directory. This is wherelx --init-configwrites by default.$XDG_CONFIG_HOME/lx/config.tomlβ follows the XDG Base Directory specification. Defaults to~/.config/lx/config.tomlif$XDG_CONFIG_HOMEis not set. Preferred on Linux; also used on macOS.~/Library/Application Support/lx/config.tomlβ the standard macOS application configuration location. Only checked on macOS, after the XDG location.
Most users will be fine with option 2 (~/.lxconfig.toml). If you
prefer to keep your dotfiles tidy under ~/.config/, use option 3.
Drop-in directory
After loading the main config, lx looks for a conf.d/ directory
and loads any *.toml files it finds there, in alphabetical order.
Each file is a standalone TOML fragment that can contain theme,
style, class, personality, or format definitions. The drop-in
directory is searched at:
~/.config/lx/conf.d/(or$XDG_CONFIG_HOME/lx/conf.d/)~/Library/Application Support/lx/conf.d/(macOS)
This is how you install themes from the themes/ library β just
copy files in, no editing required.
Installation
Download a pre-compiled binary
lx is just a single binary. You can download pre-built binaries of the latest
release from GitHub, for both Linux and macOS. These binaries all include
jj support.
| OS | CPU architecture | filename |
|---|---|---|
| Linux | ARM 64-bit | lx-aarch64-unknown-linux-gnu |
| Linux | Intel 64-bit | lx-x86_64-unknown-linux-gnu |
| macOS | Apple Silicon | lx-aarch64-apple-darwin |
| macOS | Intel 64-bit | lx-x86_64-apple-darwin |
Just download the file, rename it to lx, and put it somewhere in your
$PATH!
Build from source
lx is built from source using Cargo,
Rust's package manager. lx requires Rust 1.94 or later.
Install Rust if you don't have it already:
|
Install lx from crates.io:
Or install directly from GitHub:
The binary is installed to ~/.cargo/bin/ as lx. Make sure this
directory is on your $PATH.
Alternatively, build lx from a local clone:
The binary is at target/release/lx; copy it somewhere on your $PATH
(e.g. ~/.local/bin/).
Man pages are built from Markdown source using pandoc:
Install them to the standard XDG location:
Note: The crate is published as
lx-lson crates.io (the namelxis taken by an unrelated library). The installed binary is still calledlx.
Installing with just
If you have just installed, the included
Justfile automates building, installing, and setting up personalities:
# to ~/.local/bin and ~/.local/share/man
# in ~/.local/bin
To install with jj support, use the install-jj recipe instead:
# to ~/.local/bin and ~/.local/share/man
Other useful recipes: just test, just test-all, just lint,
just completions. List them all with just -l.
VCS support
lx shows per-file version control status in long view, with built-in
backends for both Git and
Jujutsu (jj).
Jujutsu support is optional and needs to be enabled at compile time β see Installation.
With --vcs=auto (the default), lx probes for a jj workspace first,
then falls back to git β so co-located jj/git repositories are detected
correctly.
The column header (-h/--header) shows which backend is active: Git or
JJ.
Status characters
| Char | Meaning |
|---|---|
- |
Not modified |
M |
Modified |
A |
Added (jj) |
N |
New (git) |
D |
Deleted |
R |
Renamed |
C |
Copied |
I |
Ignored |
U |
Untracked |
! |
Conflicted |
Git vs jj display
The VCS column is one or two characters wide, depending on the status.
Git uses two characters:
- character 1 is the staged status
- character 2 is the unstaged status
When both are the same, lx collapses them to one. For example:
| Column | Meaning |
|---|---|
-M |
Unstaged modification (staged: -, unstaged: M) |
M- |
Staged modification (staged: M, unstaged: -) |
-N |
Untracked file (staged: -, unstaged: N) |
M |
Same in both columns (collapsed to one) |
jj also uses two characters, but with different semantics (jj has no staging area):
- character 1 is the change status (working copy commit vs its parent)
- character 2 is the tracking status β a space for tracked files,
Ufor untracked, orIfor ignored
| Column | Meaning |
|---|---|
A |
Added file, tracked |
M |
Modified, tracked |
- |
Not modified, tracked |
-I |
Not modified, ignored |
-U |
Not modified, untracked |
! |
Merge conflict |
--vcs-ignore works with both backends β it hides files showing I
completely.
More on daily lx usage
Column visibility
Every column has both a positive and negative flag:
Or take full control with --columns:
Or define your own named format in the config file.
Filtering
-I hides files entirely. -P shows the directory (with its size and
metadata) but doesn't recurse into it β perfect for tree views of projects
with large build or dependency directories.
Sorting
With --total-size, -s size sorts by recursive directory size.
Environment variables
| Variable | Purpose |
|---|---|
LX_CONFIG |
Explicit config file path |
LX_COLORS |
Colour theme (overrides LS_COLORS) |
LX_DEBUG |
Enable debug logging (1 or trace) |
LX_GRID_ROWS |
Minimum rows for grid-details view |
LX_ICON_SPACING |
Spaces between icon and filename |
LS_COLORS |
Standard file-type colour scheme |
COLUMNS |
Override terminal width |
TIME_STYLE |
Default timestamp style |
NO_COLOR |
Disable colours (see no-color.org) |
Shell completions
Shell completions are available for bash, zsh, and fish.
Quick activation (current session only)
# bash
# zsh
# fish
|
Permanent installation
Save the completions to the standard location for your shell:
# bash
# zsh (make sure ~/.zfunc is in your $fpath)
# fish
Alternatively, add the source <(lx --completions ...) line to your
shell's rc file (.bashrc, .zshrc) to generate completions on the
fly at shell startup.
Known limitations
-
jj support is an opt-in feature β the
jjfeature flag pulls injj-lib, which adds ~5 MB to the binary and ~550 extra crates to the build. Build withcargo build --features jj(orcargo install lx-ls --features jj) to enable it. Without the feature,--vcs=jjreturns a clear error message. -
0.1 and 0.2 config files need migrating β the 0.3 config format is not backwards-compatible. Run
lx --upgrade-configto convert automatically (a.bakbackup is saved). -
The
lxcrate name on crates.io is taken by an unrelated library. Install from GitHub instead (see Installation). -
lxis an experiment under active development. Literally anything may still change, including the details of the user interface!
Roadmap
What's new in 0.3
- File-type classes (
[class]) β named lists of glob patterns (image,video,music, etc.), with compiled-in defaults that can be overridden in the config. - Unified style system β styles reference classes via bare
dotted TOML keys (
class.NAME = "colour") and file patterns via quoted keys. Compiled-in "exa" style maps classes to default colours. --show-configβ diagnostic flag showing the active personality, theme, style, classes, and formats with their source (compiled-in vs config).lapersonality β compiled-in, inherits fromllwith hidden files shown.- Flat formats β
[format]section is now flat (keys are format names, values are column lists). - Explicit exa chain β default personality β exa theme β exa style, with no magic fallback.
- Config version 0.3 β upgrade tool handles 0.1β0.3 and 0.2β0.3 migrations.
--gitand--git-ignorelegacy flags removed.--group-directories-firstprecedence fixed.
What's new in 0.4
- First-class Jujutsu support β opt-in
jjfeature flag usingjj-libfor direct workspace access (no CLI subprocess):- Two-column VCS display: change status + tracking status
A(added) matches jj's owndiff --summaryoutput--vcs-ignorewith full gitignore support (all layers: global excludes,.git/info/exclude, per-directory.gitignore)- Untracked (
U) and conflicted (!) file detection - Dynamic column header: Git or JJ
- Works with colocated, non-colocated, and external git repos
-F/-Jshort flags for--group-dirs=first/last-oshort flag for--octal-permissions-Ashort flag for--absolute- Canonical column insertion order for individual flags
- Coloured
--show-configoutput
What's new in 0.5
-P/--pruneβ show directories but don't recurse (tree pruning)--time-style=relativeβ "2 hours ago" style timestamps--time-style='+FORMAT'β custom strftime format strings--dump-*flags β copy-pasteable TOML for all config objects--helpreorganised with section headings--total-sizeperformance β ~3x faster on large trees--ignorerenamed from--ignore-glob(alias kept)--octalrenamed from--octal-permissions(alias kept)--dirs-first/--dirs-lastshortened from--group-directories-*--symlinks=show|hide|followβ control symlink display and dereferencing--vcs-reposβ per-directory VCS repo indicator (G/J/-) with git branch name--vcs-ignorenow hides VCS metadata directories (.git,.jj)
What's new in 0.6
- Drop-in config directory (
conf.d/) β install themes and styles by dropping TOML files into~/.config/lx/conf.d/, no editing needed - Curated theme library β Catppuccin Mocha, Dracula, Gruvbox Dark,
Nord, Solarized Dark, Solarized Light (see
themes/) - Icon β class migration β media-type icons now use the
[class]config system; custom class definitions affect icons too --total-sizeparallelised β recursive directory sizing now uses all available cores, making large tree listings significantly faster- Tidier
--helpoutput, clippy cleanup, dead code removal
Planned
- Polish and bug fixes from daily driving
Acknowledgements
lx is my own experiment to test some ideas I have about the user experience
of a Unix file listing utility. As such, being an experiment, it does not try
particularly hard to be compatible with anything else. That said, it stands on
the shoulders of giants!
lx is built on the foundations of
exa by Benjamin Sago (ogham). The core file
system, output rendering, and column system are all his work. Thank you! π
Several features were inspired by
eza, the active community fork
of exa maintained by Christina SΓΈrensen and collaborators. These were
reimplemented from scratch for lx and sometimes differ from their eza
counterparts:
| Feature | eza flag | lx flag |
|---|---|---|
| Recursive directory sizing | --total-size |
--total-size / -Z |
| List only files | --only-files |
--only-files / -f |
| Filename quoting | --no-quotes (default on) |
--quotes (default off) |
| Terminal hyperlinks | --hyperlink |
--hyperlink |
| Explicit terminal width | --width |
--width / -w |
| Absolute paths | --absolute |
--absolute / -A |
| Symlink control | --no-symlinks + --follow-symlinks + -X |
--symlinks=show|hide|follow |
| Per-directory repo status | --git-repos |
--vcs-repos |
Licence
MIT β same as the original exa. See LICENCE.