Note: :warning: As of version 2.0.0, moar has been renamed to
moor, but is otherwise
the same tool.
Moor is a pager. It reads and displays UTF-8 encoded text from files or pipes.
moor is designed to just do the right thing without any configuration:
!Moor displaying its own source code
The intention is that Moor should be trivial to get into if you have previously been using Less. If you come from Less and find Moor confusing or hard to migrate to, please report it!
Doing the right thing includes:
- Syntax highlight source code by default using
- Search is incremental / find-as-you-type just like in
- Filtering is incremental: Press & to filter the input
- Search becomes case sensitive if you add any UPPER CASE characters
- Deduplicated search history persists across
moorinvocations - Snappy UI even on slow / large input by reading input in the background
- Supports displaying ANSI color coded texts (like the output from
git diff | riff for example)
- Supports UTF-8 input and output
- Transparent decompression when viewing compressed text
.gz, .bz2, .xz, .zst, .zstd) or streams
- The position in the file is always shown
- Supports word wrapping (on actual word boundaries) if requested using
--wrap or by pressing w
just like tail -f
- Renders terminal
- Mouse Scrolling works out of the box (but
Moor is used as the default pager by:
riff, a diff filter highlighting which line parts have changedpx/ptop,psandtopfor human beingsftop, atopimplementation that embeds
moor
using the embedding API
Environment
MOOR: moor will read extra command line options from here.
PAGER_WRAP_COLUMNS: If set to a positive number, this limits the maximum
width for wrapping long lines.
PAGER_LABEL: Other programs can set this to tell moor what name to show for
standard input.
For compatibility reasons, moor
uses the formats declared in these environment variables if present:
LESS_TERMCAP_md: Man page boldLESS_TERMCAP_us: Man page underlineLESS_TERMCAP_so: Status bar and search hits
LESS_TERMCAP_* values, both actual escape characters and the word ESC in
caps are interpreted as escape characters. Example value: ESC[1m.
Setting LESSSECURE to 1 will prevent moor from launching external programs
or opening new files [as required by systemctl(1)][systemctlLessSecure]. In
secure mode, the v command for opening the current file in an editor
is disabled.
Installing
Using Homebrew
Both macOS and Linux users can use Homebrew to install. See below for distro specific instructions.
brew install moor
Then whenever you want to upgrade to the latest release:
brew upgrade
Using Debian
On Debian Forky and newer, as well as on Ubuntu 26.04 Resolute and newer:
sudo apt install moor
Using MacPorts
sudo port install moor
More info here.
Using Gentoo
emerge --ask --verbose sys-apps/moor
More info here.
Using Arch Linux
pacman -S moor
More info here.
Manual Install
Using go
This will install
moor into $GOPATH/bin>)
:
go install github.com/walles/moor/v2/cmd/moor@latest
NOTE: If you got here because there is no binary for your platform,
please consider packaging moor.
Downloading binaries
- Download
moorfor your platform from
chmod a+x moor---*sudo mv moor---* /usr/local/bin/moor
moor from the prompt!
Try moor --help to see options.
Configuring
Do moor --help for an up to date list of options.
Environment variable MOOR can be used to set default options.
For example:
export MOOR='--statusbar=bold --no-linenumbers'
Setting moor as your default pager
Set it as your default pager by adding...
export PAGER=/usr/local/bin/moor
... to your .bashrc.
Issues
Issues are tracked here, or
you can send questions to
Packaging
If you package moor, do include the man page in your package.
Comparison with bat
moor and bat do different things. moor is a pager. bat is a file
preprocessor that sometimes pipes to a pager (like moor). So comparing them
directly is not possible.
What bat does is:
- Looks at its input and preprocesses it or not
- Pipes to a pager or not. This pager can be
mooror something else.
bat's preprocessing overlaps with what moor provides internally
(like syntax highlighting and JSON formatting).
But some moor features like fast interactive search is moor specific and not
something bat can simulate through preprocessing.
To use moor as your bat pager, set BAT_PAGER=moor in your environment.
Or, to use moor instead of bat, set PAGER=moor.
Embedding moor in your app
API Reference: https://pkg.go.dev/github.com/walles/moor/v2/pkg/moor
For a quick start, first fetch your dependency:
go get github.com/walles/moor/v2
Then, here's how you can use the API:
package main
import (
"github.com/walles/moor/v2/pkg/moor"
)
func main() {
err := moor.PageFromString("Hello, world!", moor.Options{})
if err != nil {
// Handle paging problems
panic(err)
}
}
After both go get is done and you have calls to moor in your code, you may
have to:
go mod tidy
You can also PageFromStream() or PageFromFile().
Developing
moor draws to the terminal screen using
twin, a standalone library originally built
for moor and also usable on its own for building terminal UIs.
You need the go tools.
Testing
Run tests:
./test.sh
Launch the manual test suite:
./manual-test.sh
To run tests in 32 bit mode, either do GOARCH=386 ./test.sh if you're on
Linux, or docker build . -f Dockerfile-test-386 (tested on macOS).
Both ./test.sh and ./moor.sh enable the race detector. Detected races end up
in moor-race-report.* files in the repo root, see RACES.md.
Benchmarking
Run microbenchmarks:
go test -benchmem -run='^$' -bench=. ./...
Telling a real speed difference from luck takes more than one run of each. Use benchstat, which reports the difference with a p-value:
go install golang.org/x/perf/cmd/benchstat@latest
BENCH='go test -benchmem -run=^$ -bench=^BenchmarkReadLongLine$ -count=10 ./internal/reader'
$BENCH >before.txt
... make your change ...
$BENCH >after.txt
benchstat before.txt after.txt
Profiling
Profiling BenchmarkPlainTextSearch(). Try replacing -alloc_objects with
-alloc_space or change the -focus function:
go test -memprofilerate=1 -memprofile=profile.out -benchmem -run='^$' -bench '^BenchmarkPlainTextSearch$' ./internal && go tool pprof -alloc_objects -focus findFirstHit -relative_percentages -web profile.out
Or to get a CPU profile:
go test -cpuprofile=profile.out -benchmem -run='^$' -bench '^BenchmarkRenderLines$' ./internal && go tool pprof -focus renderLines -relative_percentages -web profile.out
Building
Build + run:
./moor.sh ...
Install (into /usr/local/bin) from source:
./install.sh
Making a new Release
Make sure that screenshot.png matches moor's current UI. If it doesn't, scale a window to 81x16 characters and make a new one.
Execute release.sh and follow instructions.
TODO
- Enable exiting using ^c (without restoring the screen).
- Enable suspending using ^z, followed by resuming using
fg.
- Underline the file name in the status bar while viewing. The point is to make
- Retain the search string when pressing / to search a second time.
Done
- Add
>markers at the end of lines being cut because they are too long
- Doing moor on an arbitrary binary (like
/bin/ls) should put all
- Make sure search hits are highlighted even when we have to scroll right
- Change out-of-file visualization to writing
---after the end of the file
- Exit search on pressing up / down / pageup / pagedown keys and
- Remedy all FIXMEs in this README file
- Release the
goversion as the newmoor, replacing the previous Ruby
- Add licensing information (same as for the Ruby branch)
- Make sure
git grepoutput gets highlighted properly.
- Handle all kinds of line endings.
- Make sure version information is printed if there are warnings.
- Add spinners while file is still loading
- Make
tail -f /dev/nullexit properly, fix
- Showing unicode search hits should highlight the correct chars
- Arrow keys up / down while in line wrapping mode should scroll by screen line,
- Define 'g' to prompt for a line number to go to.
- Handle search hits to the right of the right screen edge when searching
- Handle search hits to the right of the right screen edge when searching
[systemctlLessSecure]: https://github.com/systemd/systemd/blob/ee3cd7890d81744efa9513b739e5ff03c9e7649b/man/common-variables.xml#L193-L194