Winix.Less
0.4.0
Prefix Reserved
dotnet tool install --global Winix.Less --version 0.4.0
dotnet new tool-manifest
dotnet tool install --local Winix.Less --version 0.4.0
#tool dotnet:?package=Winix.Less&version=0.4.0
nuke :add-package Winix.Less --version 0.4.0
less
Native terminal pager with ANSI colour passthrough, search, follow mode, and modern defaults.
less replacement with sane defaults on every platform. Passes ANSI escape codes through unchanged, so coloured output from tools like man, files, and treex renders correctly.
Install
Scoop (Windows)
scoop bucket add winix https://github.com/Yortw/winix
scoop install winix/less
Winget (Windows, stable releases)
winget install Winix.Less
.NET Tool (cross-platform)
dotnet tool install -g Winix.Less
Direct Download
Download native binaries from GitHub Releases.
Usage
less [options] [+command] [file]
Displays file content (or stdin) one screen at a time. When no file is given, reads from stdin. Currently accepts at most one file argument — for concatenated paging of multiple files, use cat file1 file2 | less. Multi-file paging with :n / :p navigation is tracked for a future release.
Examples
# Page a file
less somefile.txt
# Page piped input (colour passes through by default)
man timeit | less
# Show line numbers
less -N somefile.txt
# Chop long lines instead of wrapping
less -S somefile.txt
# Follow a growing file (like tail -f)
less +F logfile.log
# Jump to end of file on open
less +G somefile.txt
# Open with an initial search
less +/error logfile.log
# Force exit if output fits on one screen
less -F somefile.txt
Options
| Option | Description |
|---|---|
-N |
Show line numbers |
-S |
Chop long lines (don't wrap) |
-F |
Quit immediately if output fits on one screen |
-R |
Pass raw ANSI colour codes through (default: on) |
-X |
Don't clear the screen on exit |
-i |
Case-insensitive search (ignored if pattern has uppercase) |
-I |
Case-insensitive search always |
+F |
Start in follow mode (like tail -f) |
+G |
Jump to end of file on open |
+/pattern |
Start with an initial forward search for pattern |
--help |
Show help and exit |
--version |
Show version and exit |
--color[=auto\|always\|never] |
Coloured output: auto (default when omitted), always, or never. |
--no-color |
Disable coloured output |
Key Bindings
| Key | Action |
|---|---|
q |
Quit |
j / Down |
Scroll down one line |
k / Up |
Scroll up one line |
| Space / PgDn | Scroll down one screen |
| PgUp | Scroll up one screen |
Home / g |
Jump to beginning |
End / G |
Jump to end |
/ |
Forward search |
? |
Backward search |
n |
Next search match |
N |
Previous search match |
F |
Enter follow mode (press q to exit) |
-N |
Toggle line numbers |
-S |
Toggle line chopping |
LESS Environment Variable
The LESS environment variable controls default options. Three states are distinguished:
- Unset — Winix
lessuses modern defaults:FRX(quit-if-one-screen, raw colour, no-init). This gives sensible out-of-the-box behaviour without configuring anything. - Set to a non-empty value — replaces the defaults entirely. The value is parsed as a list of options (e.g.
LESS=-NiR). Unknown flags in the value are ignored. - Set to an empty string (
LESS=) — disables all defaults. NoFRX, no built-ins. Useful when you want every option to come from CLI flags.
This matches the behaviour of traditional less implementations. (Pre-v0.3.0, "unset" and "empty" were conflated and both gave defaults; the empty-disables semantics is now correctly honoured.)
Wildcards on Windows
cmd.exe and PowerShell don't expand */? wildcards before starting programs, so
less expands them itself on Windows — less *.log works the same as in bash.
* and ? work in any path segment. [...] is matched literally (brackets are legal
Windows filename characters), and ** is rejected with an error — less has no
recursive mode; use files to find files recursively. A pattern that matches nothing
is passed through unchanged, so you get the normal "not found" error. In cmd, quoting
a pattern ("*.log") suppresses expansion; PowerShell removes quotes before less sees
them, so use --% there if you need a literal. On Linux/macOS your shell expands
wildcards as usual and less does nothing extra. Note less accepts a single file, so
a pattern must resolve to exactly one match — two or more matches exit 2 with a usage
error (the same thing happens in bash when the shell expands).
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Normal exit |
| 1 | Error (file not found, read error) |
| 2 | Usage error (bad arguments) |
Colour
- ANSI escape codes are passed through by default (
-Ris on unlessNO_COLORis set) --colorforces colour on (overridesNO_COLOR)--no-colordisables colour passthrough; raw escape sequences are shown as text- Respects the
NO_COLORenvironment variable (no-color.org)
Part of Winix
less is part of the Winix CLI toolkit.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.4.0 | 143 | 6/13/2026 |
| 0.3.0 | 126 | 5/26/2026 |
| 0.3.0-rc2 | 108 | 5/10/2026 |
| 0.2.0 | 121 | 4/16/2026 |
| 0.2.0-test4 | 113 | 4/15/2026 |
## [0.3.0] - 2026-05-09
### Changed (BREAKING)
- Multi-file paging removed. Pre-fix the binary silently overwrote `filePath` with each subsequent positional, opening only the LAST one. README and man both claimed "Multiple files are paged in sequence." Now `less file1 file2` exits with usage error 2 and a clear message. For concatenated paging, use `cat file1 file2 | less`. True multi-file paging with `:n` / `:p` navigation is tracked for v0.5+.
- Usage errors now exit with **2** (POSIX-traditional, matches GNU `less`) instead of ShellKit's suite-default 125. Deliberate suite divergence per `feedback_match_established_tool_conventions.md` since less is a POSIX-replacement.
### Fixed
- `LESS=NiR less file.txt` (or any `LESS` value without `F`) no longer crashes with `IOException: The handle is invalid` on redirected stdout. Pager now detects non-tty up front via `Pager.SelectDumpStrategy` and dumps content directly to stdout when not a terminal — matches GNU `less` behaviour. Plus belt-and-braces try/catch around the pager loop catches mid-loop terminal failures and falls back to a viewport-preserving direct dump.
- `NO_COLOR` env var, `--color`, and `--no-color` flags are now honoured. Pre-fix all three were silently ignored — ANSI passthrough was unconditional. Now `result.ResolveColor()` drives `LessOptions.StripAnsi`, which strips ANSI escapes from rendered output and the dump path. Matches Winix suite-wide `NO_COLOR` policy and aligns with ripgrep / fd / bat (diverges from GNU less which doesn't honour `NO_COLOR`).
- Bare `-` argument is now accepted as the POSIX explicit-stdin marker. Pre-fix ShellKit consumed `-` as an unknown short option and failed with exit 125. `less -` and `less - file.txt` both work; explicit `-` wins over the file argument per POSIX precedence.
- Directory path argument now reports "Is a directory" via `IOException` instead of the misleading "File not found".
- File-load now catches `IOException` and `UnauthorizedAccessException` in addition to the previously-only-caught `FileNotFoundException`. Pre-fix a path-too-long, locked-for-exclusive-write file, or permission-denied target crashed with a stack trace. `UnauthorizedAccessException` emits a tool-supplied English message to avoid leaking SR resource keys under InvariantGlobalization.
- `LESS=` (empty) now correctly disables all defaults. Pre-fix code conflated null and empty via `string.IsNullOrEmpty`, so the documented "set LESS= explicitly to empty to disable defaults" contract was unreachable.
- Console-handle lifecycle cleanup hardened across `Pager`, `Screen`, and `ConsoleInput.ReattachUnix`. `Pager.Run` now catches both `IOException` AND `InvalidOperationException` (the latter fires when `Console.ReadKey` runs after a failed reattach — common on `git diff | less +F`). `Screen.Dispose` guards each terminal write against `IOException` so unwind doesn't compound the original failure. `ConsoleInput.ReattachUnix` narrows from a bare `catch { }` to typed catches with a one-shot stderr diagnostic. The crash-fallback `DumpFromViewport` preserves the user's current viewport position rather than re-emitting content scrolled past.
- `--version` output no longer carries the `+gitsha` SourceLink suffix. Users see plain `less 0.3.0`, matching the suite-wide convention.
### Added
- Library seam `Winix.Less.Cli.Run` for orchestration testing without process spawning or entering the interactive Pager.Run loop.
- `Pager.DumpFromViewport(lines, startIndex)` internal helper for the crash-fallback path; `DumpAllLines` delegates to `DumpFromViewport(lines, 0)` for the small-content path.
See full changelog at https://github.com/Yortw/winix/blob/main/src/less/CHANGELOG.md