Pistol
Introduction
Pistol is a file previewer for command line file managers such as
Ranger, Lf and
nnn, intended to replace the file previewer shell
script
scope.sh
commonly used with Ranger and other previewing methods.
scope.sh
is a Bash script that uses case
switches and external
programs to decide how to preview every file it encounters. It knows how
to handle every file according to its
MIME type and/or file
extension using case
switches and external programs. This design makes
it hard to configure / maintain and it makes it slow for startup and
heavy when running.
Pistol is a Go program (with (almost) 0 dependencies) and its MIME type
detection is internal. Moreover, it features native preview support for
almost any archive file and for text files along with syntax
highlighting while scope.sh
relies on external programs to do these
basic tasks.
The following table lists Pistol’s native previewing support:
File/MIME Type | Notes on implementation |
---|---|
|
Prints text files with syntax highlighting thanks to
|
Archives |
Prints the contents of archive files using
|
In case Pistol encounters a MIME type it doesn’t know how to handle natively and you haven’t configured a program to handle it, it’ll print a general description of the file type it encountered. For example, the preview for an executable might be:
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=a34861a1ae5358dc1079bc239df9dfe4830a8403, for GNU/Linux 3.2.0, not stripped
This feature is available out of the box just like the previews for the common mime types mentioned above.
See also the WiKi article: Pistol out in the Wild.
A Note on MIME type Detection
Some pure Go libraries provide MIME type detection. Here are the top search results I got using a common web search engine:
Pistol uses the last one which leverages the well known C library libmagic(3). I made this choice after experimenting with the other candidates and due to their lack of an extensive database such as libmagic(3) has, I chose magicmime.
Note that this choice also features compatibility with the standard
command file
which is available by default on most GNU/Linux
distributions.[1]
A Note on Archive Previews
Pistol previews all archive / compression formats supported by the Go
library archiver
. Some formats do
nothing but compression, meaning they operate on 1 file alone and some
files are a combination of archive, compressed in a certain algorithm.
For example, a .gz
file is a single file compressed with gzip
. A
.tar
file is an uncompressed archive (collection) of files. A
.tar.gz
is a .tar
file compressed using gzip
.
When pistol encounters a single file compressed using a known
compression algorithm, it doesn’t know how to handle its content, it
displays the type of the archive. If a known compression algorithm has
compressed a .tar
file, Pistol lists the files themselves.
Install
If someone has packaged Pistol for your distribution, you might find a package for of it linked in the WiKi.
If not, use the following instructions, or grab a statically compiled version
of it from the releases page,
available since version 0.3.1
. The releases assets include also the manual
page pistol.1.gz
.
Warning
|
Currently, Darwin compatible binaries are not available there, but it
should be possible to generate them via CI. All other binaries were cross
compiled from my own x86_64 linux machine, using Nix' superb
cross compilation support.
|
Note
|
For a statically compiled Pistol to be functional, it needs to read a libmagic database
(usually found in /usr/share/misc/magic.mgc ) and the static executable
includes the contents of this database found on Nixpkgs'
file
package. The content of the magic.mgc database is copied to
~/.local/share/pistol/${libmagic-version}.mgc when you first run the executable.
Hence using this executable might not be desirable due to this behaviour which
a regular compilation of pistol does not include. This behaviour is compiled
into pistol if you use go {build,install} with -tags EMBED_MAGIC_DB .
|
From Source
Since Pistol depends on magicmime,
you’ll need a libmagic
package installed. Please refer to
this
section in magicmime’s README
for the appropriate commands for every OS. In
particular, if you installed `libmagic
using brew
on a Darwin system, you
may need to use the CGO_FLAGS
environment variable to compile pistol
. See
#6 for
more details.
Assuming you’ve installed libmagic
properly and you have
setup a Go environment, Use the
following command to install Pistol to $GOPATH/bin/pistol
:
Go 1.16 or later
go install github.com/doronbehar/pistol/cmd/pistol@latest
Go 1.15 or earlier
env CGO_ENABLED=1 GO111MODULE=on go get -u github.com/doronbehar/pistol/cmd/pistol
[3]
Besides libmagic
,
asciidoctor
is also
recommended, in order to compile the README as a manpage and install it. NixOS
For instance, does it like this:
# ...
nativeBuildInputs = [
installShellFiles
asciidoctor
];
postInstall = ''
asciidoctor -b manpage -d manpage README.adoc
installManPage pistol.1
'';
# ...
Link to currently evaluated file on NixOS. Packagers for other distros should do something similar.
Usage
$ pistol --help Usage: pistol OPTIONS <file> [<extras> ...] OPTIONS -V, --version Print version date and exit -c, --config <config file> configuration file to use (defaults to ~/.config/pistol/pistol.conf on Linux) -h, --help print help and exit ARGUMENTS file the file to preview extras extra arguments passed to the command
Integrations
Ranger / Lf
You can use Pistol as a file previewer in
Ranger and
Lf. For Ranger, set your
preview_script
in your rc.conf
as follows:
set preview_script ~/.go/bin/pistol
The same goes for Lf, but in lfrc
:
set previewer ~/.go/bin/pistol
fzf
If you use fzf to search for files, you
can tell it to use pistol
as the previewer. For example, the following
command edits with your $EDITOR
selected python file(s) using pistol
as a previewer:
$EDITOR "$(find -name '*.py' | fzf --preview='pistol {}')"
Configuration
Although Pistol previews files of certain MIME types by default, it
doesn’t force you to use these internal previewers for these MIME types.
You can change this behaviour by writing a configuration file in
~/.config/pistol/pistol.conf
(or $XDG_CONFIG_HOME/pistol/pistol.conf
) On
GNU systems, with the syntax as explained below.
Note
|
On OS X, this location defaults to:
~/Library/Preferences/pistol/pistol.conf , as the XDG specification imposes.
|
Syntax
You can configure preview commands according to file path or mime type
regex. The 1st word may is always interpreted first as a mime type regex
such as: text/*
.
If a line is not matched but the 1st word is exactly fpath
, then the
2nd argument is interpreted as a file path regex, such as:
/var/src/.*/README.md
.
On every line, whether you used fpath
or not, the next arguments are
the command’s arguments, where %pistol-filename%
is substituted by
pistol
to the file at question. You’ll see more examples in the
following sections.
Both regular expressions (for file paths and for mime types) are
interpreted by the built-in
library’s regexp.match
. Please refer to
this link for the full reference
regarding syntax.
Matching Mime Types
You can inspect the MIME type of any file on a GNU/Linux OS and on Mac
OS with the command file --mime-type <file>
.
For example, say you wish to replace Pistol’s internal text previewer
with that of bat’s, you’d put the
following in your pistol.conf
:
text/* bat --paging=never --color=always %pistol-filename%
Naturally, your configuration file overrides the internal previewers.
Here’s another example which features w3m as an HTML previewer:
text/html w3m -T text/html -dump %pistol-filename%
And here’s an example that leverages ls
for printing directories’
contents:
inode/directory ls -l --color %pistol-filename%
Matching File Path
For example, say you wish to preview all files that reside in a certain
./bin
directory with bat’s syntax
highlighting for bash. You could use:
fpath /var/src/my-bash-project/bin/[^/]+$ bat --map-syntax :bash --paging=never --color=always %pistol-filename%
A Note on RegEx matching
When Pistol parses your configuration file, as soon as it finds a match
be it a file path match or a mime type match, it stops parsing it and it
invokes the command written on the rest of the line. Therefor, if you
wish to use the examples from above which use w3m
and bat
, you’ll
need to put w3m
’s line before bat
’s line. Since otherwise,
text/*
will be matched first and text/html
won’t be checked at all.
Similarly, you’d probably want to put fpath
lines at the top.
Of course that this is a mere example, the same may apply to any regular expressions you’d choose to match against.
For a list of the internal regular expressions tested against when
Pistol reverts to its native previewers, read the file
internal_writers/map.go
.
More examples can be found in this WiKi page.
Quoting and Shell Piping
Pistol is pretty dumb when it parses your config, it splits all line by spaces, meaning that e.g:
application/json jq '.' %pistol-filename%
This will result in an error by jq
:
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1: '.' jq: 1 compile error
Indicating that jq
got a literal '.'
. When you run in your shell
jq '.' file.json
you don’t get an error because your shell is
stripping the quotes around .
. However, Pistol is not smarter then
your shell because if you’d try for example:
application/json jq '.[] | .' %pistol-filename%
That would be equivalent to running in the typical shell:
jq "\'.[]" "|" ".'" file.json
That’s because Pistol doesn’t consider your quotes as interesting instructions, it just splits words by spaces. Hence, to overcome this disability, you can use:
application/json sh: jq '.' %pistol-filename%
Thanks to the sh:
keyword at the beginning of the command’s
definition, the rest of the line goes straight as a single argument to
sh -c
.
You can worry not about quoting / escaping the rest of the line - it’s
not like when you run e.g sh -c 'command'
in your shell where you need
to make sure single quotes are escaped or not used at all inside
command
.
More over, with sh:
you can use shell pipes:
fpath .*.md$ sh: bat --paging=never --color=always %pistol-filename% | head -8
Passing arbitrary extra arguments to commands
Pistol is capable of passing extra arguments to commands if the config says so.
The arguments %pistol-extra0%
, %pistol-extra1%
and so on, are substituted
by the extra arguments given to pistol
, if these present in invocation and if
they are present in the config. Example usage:
With this config:
fpath /problematic-bz2/.*.bz2 bzip2 %pistol-filename% %pistol-extra0% fpath /working-bz2/.*.bz2 bzip2 %pistol-filename%
Running:
pistol /problematic-bz2/example.bz2 --test
Will run bzip2 while testing the integrity of the compressed file. However, running:
pistol /working-bz2/example.bz2 --test
Will not pass the --test
argument to bzip
, due to %pistol-extra0
not
present in the config for the files at /working-bz2
. This feature is mainly
present for usage with Lf and
Ranger which can pass width height and x, y
coordinates for image previews.
Here’s an example usage for image previews that works with Lf: [4]
image/.* pv %pistol-filename% %pistol-extra0% %pistol-extra1% %pistol-extra2% %pistol-extra3%
Environmental Variables
Pistol’s internal previewer for text files includes syntax highlighting thanks to the Go library chroma. You can customize Pistol’s syntax highlighting formatting and style through environmental variables.
Chroma Formatters
The term formatter refers to the way the given file is presented in the terminal. These include:
-
terminal
: The default formatter that uses terminal control codes to change colors between every key word. This formatter has 8 colors and it’s the default. -
terminal256
: Same asterminal
but with 256 colors available. -
terminal16m
: Same asterminal
but with 24 Bits colors i.e True-Color.
Other formatters include json
, and html
but I’d be surprised if
you’ll find them useful for Pistol’s purpose.
To tell Pistol to use a specific formatter, set
PISTOL_CHROMA_FORMATTER
in your environment, e.g:
export PISTOL_CHROMA_FORMATTER=terminal16m
Recent versions of Lf support
256 colors in its preview
window. AFAIK, [5], Ranger supports 8
colors and Lf’s color256
isn’t enabled by default.
Therefor, I decided that it’ll be best to keep this variable unset in
your general environment. If you do set color256
in your lfrc
, you
may feel free to set PISTOL_CHROMA_FORMATTER
in your environment.
Chroma Styles
The term style refers to the set of colors used to print a given file. The chroma project documents all styles here and here.
The default style used by Pistol is pygments
. To tell Pistol to use a
specific style set PISTOL_CHROMA_STYLE
in your environment, e.g:
export PISTOL_CHROMA_STYLE=monokai
Debugging
Can’t figure out way does Pistol acts the way he does? You can run pistol with:
env PISTOL_DEBUG=1 pistol test-file
And you should be able to see messages that may give you a clue.
NEWS
See previous releases.
libmagic
for Windows and teach magicmime to use it, please let me know.
env GO111MODULE=on
is needed due to a recent bug / issue with Go, see #6 for more details. CGO_ENABLED=1
is needed for magicmime, see #76.