Skip to content
 
 

Latest commit

 

History

3,813 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

lez

An alternative for ls written in Rust.

License Rust binary cache Coverage

lez demo


lez is a fast, modern file-listing command-line tool with smart defaults, enhanced file icons, Git integration, and continuous performance improvements.

  • Fast & Lightweight: Written in modern Rust (2024 Edition) with multithreaded directory scanning via Rayon.
  • Rich Visuals: Syntax highlighting, colored CLI help output, Nerd Font icons, and automatic luminance color scaling.
  • Git Integration: View file and repo status (Modified, Untracked, Ignored, etc.) directly in the file listing.
  • Built-in Tree View: Hierarchical directory tree out of the box (lez --tree).
  • Structured Data Export: Full metadata serialization via --json in complete parity with the long view.
  • Archive Inspection: Inspect files inside .tar archives directly in the long view (lez -l --inspect-archives).
  • Lines-of-Code Counter: Comment-aware LOC breakdowns for 100+ programming languages (lez --code).
  • Deep OS Integration: Native macOS Finder color tags, Linux capability decoding (security.capability), and Windows PATHEXT executables.

Performance

Measured on lez v0.28.2 against eza v0.23.5 (the upstream release it forked from) and lsd v1.2.0. Apple M1 Pro, 10 cores, macOS; release builds, warm page cache, minimum of 35 interleaved runs per binary.

Workload lez 0.28.2 eza 0.23.5 lsd 1.2.0 vs eza vs lsd
Grid view, 10,000 files 22.4 ms 77.4 ms 465.1 ms 3.45× 20.7×
Recursive tree, 30,000 files 73.6 ms 205.8 ms 1,217.0 ms 2.80× 16.5×
Directory-grouped, 10,000 entries incl. 3,000 symlinks 49.9 ms 146.5 ms 433.3 ms 2.94× 8.69×
Long view, 10,000 files 158.4 ms 215.5 ms 439.0 ms 1.36× 2.77×
Long view with Git status, this repository 18.3 ms 21.7 ms 20.1 ms 1.19× 1.10×

Where the gains come from: metadata is cached lazily via OnceLock and symlink directory lookups use lock-free atomic memoization, so the grouping sort resolves each entry once instead of on every comparison; sorts above 2,048 entries run in parallel on all cores; syscall amplification is minimized by evaluating in-memory styles before probing disk; and traversal elides redundant heap allocations and stats.

Note also that lez sorts through an ICU collator by default, which orders accents, case, and digit runs correctly and costs more than a byte comparison. --sort=lexicographic opts out of it and is faster still.

Memory Footprint (Peak RSS)

Measured peak resident memory when scanning 10,000 files in a flat directory (/usr/bin/time -l on macOS):

Metric lez 0.28.2 lsd 1.2.0 eza 0.23.5 Memory Savings
Peak Resident Set Size (RAM) ~1.0 MB ~14.0 MB ~27.4 MB 27× lighter than eza (14× vs lsd)

lez eliminates unnecessary heap allocations through zero-copy path streaming and lazily evaluated metadata via OnceLock. On resource-constrained systems (Docker CI runners, low-memory VPS instances, embedded systems), memory overhead remains virtually negligible.

Reproducing

# 10,000 files in one flat directory
mkdir -p /tmp/bench && cd /tmp/bench && seq 1 10000 | xargs -I{} touch file_{}.txt

hyperfine --warmup 3 'lez /tmp/bench' 'eza /tmp/bench' 'lsd /tmp/bench'
hyperfine --warmup 3 'lez -l /tmp/bench' 'eza -l /tmp/bench' 'lsd -l /tmp/bench'
hyperfine --warmup 3 'lez --tree ~/.cargo/registry' 'eza --tree ~/.cargo/registry' 'lsd --tree ~/.cargo/registry'

eza requires --icons=auto where lez accepts a bare --icons; passing a bare --icons to eza before a path makes it reject the path as an invalid value, which produces a misleadingly fast result.


Feature Matrix

Feature / Capability lez eza lsd
Nerd Font Icons & Color Themes
Directory Tree View (--tree)
Hyperlink Support (--hyperlink OSC 8)
Custom Column Order (--blocks)
Classic GNU ls Mode (--classic)
Unicode Emoji Fallback (--icon-theme unicode)
Multithreaded Traversal (Rayon Engine) ⚠️ Limited
Lines-of-Code Counter (--code, --loc) ✅ 100+ langs ✅ 50+ langs
Structured JSON Export (--json)
Archive Inspection (--inspect-archives for .tar)
Time-Window Filtering (--since)
Size Precision Formatting (--size-digits)
Nix Store Hash Abbreviation (--short-nix)
Global & Per-Directory Config Files (config.toml / .lez.toml)
Deep Git Integration (--git, --git-glyphs, --git-repos) ⚠️ Basic
macOS Finder Color Tags (-e, --tags)
File Flags & Attributes (-O, --flags) ⚠️ BSD/Win only
Filesystem Mount Points (-M, --mounts)
Automatic Color Scaling & Heatmap (--color-scale)

Homebrew (macOS & Linux)

Install from the official fxrdhan tap:

brew install fxrdhan/tap/lez

Standalone Shell Installer (Linux & macOS)

Download and install the prebuilt binary to ~/.local/bin in one step:

curl -fsSL https://raw.githubusercontent.com/fxrdhan/lez/main/packaging/install.sh | bash

Cargo / crates.io

Install lez from crates.io:

cargo install lez

Or install precompiled binary quickly with cargo-binstall:

cargo binstall lez

Or track the latest commit on main:

cargo install --git https://github.com/fxrdhan/lez.git

Or build from source:

git clone https://github.com/fxrdhan/lez.git
cd lez
cargo build --release
# Binary available at target/release/lez

Nix

If you already have Nix setup with flake support, you can try out lez with the nix run command:

nix run github:fxrdhan/lez

Nix will build lez and run it.

If you want to pass arguments this way, use e.g. nix run github:fxrdhan/lez -- -la --icons.

Binary Cache

Every commit on main is validated with nix flake check in CI, and the resulting store paths are pushed to a public binary cache on Cachix. Contributors and Nix users can pull prebuilt outputs instead of compiling from scratch:

cachix use lez
nix run github:fxrdhan/lez

Performance & Validation:

Scenario What Happens Duration
Warm Run / Downstream Users Full closure substituted directly from Cachix ~33 s (Instant download)
Cold Build (Building from Source) Single-pass compilation in isolated Nix sandbox ~7 min

Note on Caching: Nix store paths are strictly content-addressed. Builds with modified source code produce a new derivation hash and compile inside the Nix sandbox, while unchanged closures, downstream nix develop environments, and CI runs on main enjoy the ~33 s binary substitution. A weekly cold-build canary keeps the flake honest against upstream bitrot.


Installation

lez is available for macOS, Linux, and Windows. Detailed platform-specific installation instructions can be found in INSTALL.md.


lez’s options are intuitive and familiar. Quick overview:

Display options

Click to expand
  • -1, --oneline: display one entry per line
  • -G, --grid: display entries as a grid (default)
  • -l, --long: display extended details and attributes
  • -R, --recurse: recurse into directories
  • -T, --tree: recurse into directories as a tree
  • --follow-symlinks: drill down into symbolic links that point to directories
  • --code[=MODE]: print lines-of-code summary by language (modes: lines, percent, both)
  • --json: output file listing and metadata as structured JSON
  • -x, --across: sort the grid across, rather than downwards
  • -F, --classify[=(when)]: display type indicator by file names (always, auto, never)
  • --colo[u]r=(when): when to use terminal colours (always, auto, never)
  • --colo[u]r-scale=(fields): highlight levels of fields distinctly (all, age, size)
  • --color-scale-mode=(mode): use gradient or fixed colors in --color-scale (fixed or gradient)
  • --icons[=(when)]: when to display icons (always, auto, never; requires '=' if value provided)
  • --spacing=(spaces): number of spaces between columns in grid views (default: 2, range: 0..=255)
  • --no-symlink-targets: do not show symlink targets (the -> ...)
  • --quotes=(when): when to quote file names (always, auto, never; requires '=' if value provided)
  • --summary: display total summary statistics of entries (directories, files, symlinks, and total)
  • --hyperlink[=(when)]: when to display entries as hyperlinks (always, auto, never; requires '=' if value provided)
  • --absolute=(mode): display entries with their absolute path (on, follow, off)
  • --short-nix: abbreviate Nix store hashes in file names and paths
  • --print-total: print the total number of files and directories listed
  • --mime-types: determine file MIME types to better inform styling decisions (unix only)
  • -w, --width=(columns): set screen width in columns (clamped to 1..65535)

Filtering options

Click to expand
  • -a, --all: show hidden and 'dot' files (use twice to also show . and ..)
  • -A, --almost-all: equivalent to --all; included for compatibility with ls -A
  • --show-dotfiles: show dot-prefixed files without showing other hidden files
  • -d, --treat-dirs-as-files: list directories like regular files
  • -L, --level=(depth): limit the depth of recursion
  • -r, --reverse: reverse the sort order
  • -s, --sort=(field): which field to sort by; the path field accepts the aliases relative-path, relpath, and relative_path (capitalised variants sort uppercase first)
  • -t: sort by modification time, newest first (GNU ls compatibility; shorthand for --sort=age)
  • --group-directories-first: list directories before other files
  • --group-directories-last: list directories after other files
  • -D, --only-dirs: list only directories
  • -f, --only-files: list only files
  • --no-symlinks: don't show symbolic links
  • --show-symlinks: explicitly show links (with --only-dirs and --only-files)
  • --git-ignore: ignore files mentioned in .gitignore
  • -W, --warn-hidden: print a tally of hidden and gitignored entries; give twice to always print it
  • --cachedir-ignore: ignore directories containing a CACHEDIR.TAG file
  • --ignore-submodule-contents: don't list the contents of Git submodules
  • --since=(duration): filter and display only files created or modified within the specified duration window (e.g. 10m, 1h, 2d, 1w)
  • -I, --ignore-glob=(globs): glob patterns (pipe-separated) of files to ignore; patterns containing / match against paths relative to the listing root and the flag may be given multiple times
  • --ignore-glob-ci=(globs): glob patterns (pipe-separated) of files to ignore (case-insensitive)

Long view options

Click to expand

These options are available when running with --long (-l):

  • -b, --binary: list file sizes with binary prefixes (overrides --bytes if passed after)
  • -B, --bytes: list file sizes in bytes, without any prefixes (overrides --binary if passed after)
  • --size-digits=(NUM), --digits=(NUM): number of digits to display for file sizes (1..=8, default: 3; also configurable via LEZ_SIZE_DIGITS)
  • -g, --group: list each file’s group
  • --smart-group: only show group if it has a different name from owner (automatically enables group column)
  • -n, --numeric: show user and group as their numeric IDs
  • -h, --header: add a header row to each column
  • -H, --links: list each file’s number of hard links
  • -i, --inode: list each file’s inode number
  • --loc[=MODE]: display language and lines-of-code columns (modes: lines, percent, both)
  • -m, --modified: use the modified timestamp field
  • -M, --mounts: show mount details (Linux and macOS only)
  • -S, --blocksize: list the allocated size of each file, in bytes
  • --blocks: list the allocated size of each file, in blocks
  • -t, --time=(field): which timestamp field to use (modified [aliases: mod, m], accessed [acc], changed [ch], created [cr])
  • -u, --accessed: use the accessed timestamp field
  • -U, --created: use the created timestamp field
  • --changed: use the changed timestamp field
  • --utc: show timestamps in the UTC timezone
  • -X, --dereference: dereference symlinks for file information and sorting
  • -Z, --context: list each file’s security context
  • -O, --flags: list file flags / attributes (Linux, macOS, BSD, and Windows)
  • -@, --extended: list each file’s extended attributes and sizes
  • --no-extended: don't show the @ marker that a file has extended attributes
  • -e, --tags: list each file's color tags stored in extended attributes (macOS Finder tags)
  • --inspect-archives: list the contents of supported archives (.tar) in long view, with each entry's file name coloured by type
  • --git: list each file’s Git status, if tracked or ignored
  • --git-glyphs: display Git status with Nerd Font glyphs instead of ASCII characters
  • --git-repos: list each directory’s Git status, if tracked
  • --git-repos-no-status: list whether a directory is a Git repository, but not its status (faster)
  • --no-git: suppress all Git fields and .gitignore handling (overrides --git, --git-repos, --git-repos-no-status, --git-ignore)
  • --time-style: how to format timestamps. Valid styles: default, iso, long-iso, full-iso, relative, relative-recent, or custom +<FORMAT> (e.g., +%Y-%m-%d %H:%M; see lez(1) manual page and chrono format).
  • --total-size: show recursive directory size
  • -o, --octal-permissions: list each file's permission in octal format
  • --no-permissions: suppress the permissions field
  • --no-filesize: suppress the filesize field
  • --no-user: suppress the user field
  • --no-time: suppress the time field
  • --no-language: suppress the language field when --loc is enabled
  • --stdin: read file names from stdin
  • --config: load default options from specified configuration file (.toml, .yaml, or .yml)
  • --no-config: do not load any global or per-directory configuration files

Some of the options accept parameters:

  • Valid --colo[u]r options are always, automatic (or auto for short), and never.
  • Valid sort fields are accessed, changed, created, extension, Extension, inode, lexicographic, Lexicographic, modified, name, Name, path, Path, size, block, type, and none. Fields starting with a capital letter sort uppercase before lowercase. The modified field has the aliases date, time, mod, old, and oldest, while its reverse has the aliases age, new, and newest. The block field has the aliases blocks and blocksize. The lexicographic field has the aliases lex and lg, and compares names code point by code point — no natural ordering of digit runs, no locale collation — so Lexicographic matches ls under the C locale.
  • Valid time fields are modified, changed, accessed, and created.
  • Valid time styles are default, iso, long-iso, full-iso, relative, and relative-recent (or recent).

See the man pages for further documentation of usage. They are available:

Configuration Files

Click to expand

lez supports structured configuration files (TOML or YAML) to set default flags without needing cumbersome shell aliases or wrapper scripts.

Discovery & Precedence

  1. CLI Flag: --config <PATH> or --no-config
  2. Environment Variable: LEZ_CONFIG_FILE
  3. Local (per-directory) Config: .lez.toml, .lez.yaml, .lez.yml, .eza.toml, .eza.yaml in the current working directory
  4. Global Config: config.toml, lez.toml, config.yaml in $LEZ_CONFIG_DIR (or $XDG_CONFIG_HOME/lez, ~/.config/lez)
  5. Built-in Defaults

Example config.toml

[display]
header = true
time_style = "relative-recent"

[icons]
icons = "auto"
spacing = 1

[filter]
git_ignore = true

[git]
git_glyphs = true

An annotated sample configuration is provided in docs/config.example.toml.

Environment Variables

Click to expand

lez supports several environment variables to configure default behavior, styles, and integrations:

Variable Description
LEZ_CONFIG_FILE / EZA_CONFIG_FILE Explicit path to a configuration file to load (.toml, .yaml, or .yml).
LEZ_CONFIG_DIR / EZA_CONFIG_DIR Directory containing config.toml and theme.yml (default: $XDG_CONFIG_HOME/lez or ~/.config/lez).
LEZ_COLORS / EZA_COLORS / LS_COLORS Specifies color styles and file extensions styling using standard terminal ANSI escape codes.
LEZ_MIN_LUMINANCE / LEZ_MAX_LUMINANCE Minimum and maximum luminance values (0..=100) for color scaling on dates and sizes.
LEZ_QUOTING_STYLE / EZA_QUOTING_STYLE Default quoting style for filenames with spaces/special characters (always, auto, never).
LEZ_ICON_SPACING / EZA_ICON_SPACING Number of spaces to insert after Nerd Font icons (default: 1).
LEZ_NO_EMPTY_DIR_ICON / EZA_NO_EMPTY_DIR_ICON Set to anything to give every directory the same icon. Distinguishing an empty one costs a filesystem round trip per directory, which is slow on FUSE and network mounts.
LEZ_STDIN_SEPARATOR / EZA_STDIN_SEPARATOR Delimiter for paths read from standard input with --stdin (default: newline \n).
LEZ_SIZE_DIGITS / EZA_SIZE_DIGITS Default number of digits (1..=8) to display for formatted file sizes (default: 3).
LEZ_OVERRIDE_AUTO_COLOR Force automatic color detection behavior.
TIME_STYLE Default timestamp format style (default, iso, long-iso, full-iso, relative, relative-recent, or +<FORMAT>).
NO_COLOR / CLICOLOR / CLICOLOR_FORCE Standard terminal color control flags.

Custom Themes & Schema Validation

Click to expand

lez supports a theme.yml file, where you can customize theme options available for the LS_COLORS, EZA_COLORS, and LEZ_COLORS environment variables, as well as specify custom icons for different file types and extensions.

An example theme file is available in docs/theme.yml, and can be placed in a directory specified by $LEZ_CONFIG_DIR, $EZA_CONFIG_DIR, or looked for by default in $XDG_CONFIG_HOME/lez or $XDG_CONFIG_HOME/eza.

Schema Validation in IDEs

You can enable autocomplete and schema validation in VSCode, Neovim, or Zed by referencing the bundled JSON Schema at the top of your theme.yml:

# yaml-language-server: $schema=https://raw.githubusercontent.com/fxrdhan/lez/main/docs/theme-schema.json

filekinds:
  directory: { foreground: Blue, bold: true }
  symlink: { foreground: Cyan }

Full styling details are available in the lez_colors-explanation(5) man page and lez_colors(5) man page.

Contributing to lez

If you want to contribute to lez, please check out our:


Lineage & Credits

lez is a fork of eza, which is itself a maintained fork of exa by Benjamin Sago. The overwhelming majority of this codebase was written by Benjamin Sago, Christina Sørensen, and the eza contributors, and lez continues to port work from eza's open pull requests and issues.

  • exa — original implementation, by Benjamin Sago (ogham/exa), MIT
  • eza — community fork, maintained by Christina Sørensen (eza-community/eza), EUPL-1.2
  • lez — this fork, by fxrdhan, EUPL-1.2

lez is licensed under the EUPL-1.2, inherited from eza; files originating in exa remain under the MIT license, as recorded in their SPDX headers.

The name

This project was called lsr through v0.24.1, until it turned out rockorager/lsr and the lsr crate already held that name.

About

A modern alternative to ls

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages