2016-09-13 21:40:14 +00:00
|
|
|
//go:generate gen/docstring.sh
|
|
|
|
|
|
|
|
/*
|
|
|
|
lf is a terminal file manager.
|
|
|
|
|
2016-09-14 23:18:50 +00:00
|
|
|
Source code can be found in the repository at https://github.com/gokcehan/lf.
|
2016-09-13 21:40:14 +00:00
|
|
|
|
2016-09-14 23:18:50 +00:00
|
|
|
This documentation can either be read from terminal using "lf -doc" or online
|
|
|
|
at https://godoc.org/github.com/gokcehan/lf.
|
|
|
|
|
|
|
|
Reference
|
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
The following commands are provided by lf with default keybindings:
|
|
|
|
|
|
|
|
up (default "k" and "<up>")
|
|
|
|
half-up (default "<c-u>")
|
|
|
|
page-up (default "<c-b>")
|
|
|
|
down (default "j" and "<down>")
|
|
|
|
half-down (default "<c-d>")
|
|
|
|
page-down (default "<c-f>")
|
|
|
|
updir (default "h" and "<left>")
|
|
|
|
open (default "l" and "<right>")
|
|
|
|
quit (default "q")
|
|
|
|
bot (default "G")
|
|
|
|
top (default "gg")
|
|
|
|
read (default ":")
|
|
|
|
read-shell (default "$")
|
|
|
|
read-shell-wait (default "!")
|
|
|
|
read-shell-async (default "&")
|
|
|
|
search (default "/")
|
|
|
|
search-back (default "?")
|
|
|
|
toggle (default "<space>")
|
|
|
|
invert (default "v")
|
|
|
|
yank (default "y")
|
|
|
|
clear (default "c")
|
|
|
|
delete (default "d")
|
|
|
|
put (default "p")
|
|
|
|
renew (default "<c-l>")
|
|
|
|
|
|
|
|
The following commands are provided by lf without default keybindings:
|
|
|
|
|
|
|
|
sync synchronizes yanked/deleted files with server
|
|
|
|
echo prints its arguments to the message line
|
|
|
|
cd changes working directory to its argument
|
|
|
|
push simulate key pushes given in its argument
|
|
|
|
|
|
|
|
The following options can be used to customize the behavior of lf:
|
|
|
|
|
|
|
|
dirfirst bool (default on)
|
|
|
|
hidden bool (default off)
|
|
|
|
preview bool (default on)
|
|
|
|
scrolloff int (default 0)
|
|
|
|
tabstop int (default 8)
|
|
|
|
ifs string (default "") (not exported if empty)
|
|
|
|
previewer string (default "") (not filtered if empty)
|
|
|
|
shell string (default "$SHELL")
|
|
|
|
showinfo string (default "none")
|
|
|
|
sortby string (default "natural")
|
|
|
|
timefmt string (default "Mon Jan _2 15:04:05 2006")
|
|
|
|
ratios string (default "1:2:3")
|
|
|
|
|
|
|
|
The following variables are exported for shell commands:
|
|
|
|
|
|
|
|
$f current file
|
|
|
|
$fs marked file(s) separated with ':'
|
|
|
|
$fx current file or marked file(s) if any
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-09-15 14:08:05 +00:00
|
|
|
Configuration
|
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
The configuration file should be located at:
|
|
|
|
|
|
|
|
$XDG_CONFIG_HOME/lf/lfrc"
|
|
|
|
|
|
|
|
If "$XDG_CONFIG_HOME" is not set, it defaults to "$HOME/.config" so the
|
|
|
|
location should be:
|
|
|
|
|
|
|
|
~/.config/lf/lfrc
|
|
|
|
|
|
|
|
A sample configuration file can be found at
|
2016-09-14 23:18:50 +00:00
|
|
|
https://github.com/gokcehan/lf/blob/master/etc/lfrc.example.
|
|
|
|
|
|
|
|
Prefixes
|
|
|
|
|
|
|
|
The following command prefixes are used by lf:
|
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
: read (default) built-in command
|
|
|
|
$ read-shell shell command
|
|
|
|
! read-shell-wait shell command waiting for key press
|
|
|
|
& read-shell-async asynchronous shell command
|
|
|
|
/ search search file in current directory
|
|
|
|
? search-back search file in the reverse order
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
The same evaluator is used for the command line and the configuration file. The
|
|
|
|
difference is that prefixes are not necessary in the command line. Instead
|
|
|
|
different modes are provided to read corresponding commands. Note that by
|
|
|
|
default these modes are mapped to the prefix keys above.
|
|
|
|
|
|
|
|
Syntax
|
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
Characters from "#" to "\n" are comments and ignored:
|
|
|
|
|
|
|
|
# comments start with '#'
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
There are three special commands for configuration.
|
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
"set" is used to set an option which could be boolean, integer, or string:
|
|
|
|
|
|
|
|
set hidden # boolean on
|
|
|
|
set nohidden # boolean off
|
|
|
|
set hidden! # boolean toggle
|
|
|
|
set scrolloff 10 # integer value
|
|
|
|
set sortby time # string value w/o quotes
|
|
|
|
|
|
|
|
"map" is used to bind a key to a command which could be built-in command,
|
|
|
|
custom command, or shell command:
|
|
|
|
|
|
|
|
map gh cd ~ # built-in command
|
|
|
|
map D trash # custom command
|
|
|
|
map i $less "$f" # shell command
|
|
|
|
map u !du -h . # waiting shell command
|
|
|
|
|
|
|
|
You can delete an existing binding by leaving the expression empty:
|
|
|
|
|
|
|
|
map gh # deletes 'gh' mapping
|
|
|
|
|
|
|
|
"cmd" is used to define a custom command
|
|
|
|
|
|
|
|
cmd usage $du -h . | less
|
|
|
|
|
|
|
|
You can delete an existing command by leaving the expression empty:
|
|
|
|
|
|
|
|
cmd trash # deletes trash command
|
|
|
|
|
|
|
|
If there is no prefix then ":" is assumed:
|
|
|
|
|
|
|
|
map zt set showinfo time
|
|
|
|
|
|
|
|
An explicit ":" could be provided to group statements until a "\n" occurs which
|
|
|
|
is especially useful for "map" and "cmd" commands:
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
map st :set sortby time; set showinfo time
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
If you need multiline you can wrap statements in "{{" and "}}" after the proper
|
|
|
|
prefix.
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
map st :{{
|
|
|
|
set sortby time
|
|
|
|
set showinfo time
|
|
|
|
}}
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-09-18 16:21:24 +00:00
|
|
|
Mappings
|
|
|
|
|
|
|
|
The usual way to map a key sequence is to assign it to a named or unnamed
|
|
|
|
command. While this provides a clean way to remap builtin keys as well as other
|
|
|
|
commands, it can be limiting at times. For this reason "push" command is
|
|
|
|
provided by lf. This command is used to simulate key pushes given as its
|
|
|
|
arguments. You can "map" a key to a "push" command with an argument to create
|
|
|
|
various keybindings.
|
|
|
|
|
|
|
|
This is mainly useful for two purposes. First, it can be used to map a command
|
2016-12-19 21:19:07 +00:00
|
|
|
with a command count:
|
2016-09-18 16:21:24 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
map <c-j> push 10j
|
2016-09-18 16:21:24 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
Second, it can be used to avoid typing the name when a command takes arguments:
|
2016-09-18 16:21:24 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
map r push :rename<space>
|
2016-09-18 16:21:24 +00:00
|
|
|
|
|
|
|
One thing to be careful is that since "push" command works with keys instead of
|
2016-12-19 21:19:07 +00:00
|
|
|
commands it is possible to accidentally create recursive bindings:
|
2016-09-18 16:21:24 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
map j push 2j
|
2016-09-18 16:21:24 +00:00
|
|
|
|
|
|
|
These types of bindings create a deadlock when executed.
|
|
|
|
|
|
|
|
Commands
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-09-15 14:08:05 +00:00
|
|
|
For demonstration let us write a shell command to move selected file(s) to
|
|
|
|
trash.
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
A first attempt to write such a command may look like this:
|
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd trash ${{
|
|
|
|
mkdir -p ~/.trash
|
|
|
|
if [ -z $fs ]; then
|
|
|
|
mv --backup=numbered "$f" $HOME/.trash
|
|
|
|
else
|
|
|
|
IFS=':'; mv --backup=numbered $fs $HOME/.trash
|
|
|
|
fi
|
|
|
|
}}
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
We check "$fs" to see if there are any marked files. Otherwise we just delete
|
|
|
|
the current file. Since this is such a common pattern, a separate "$fx"
|
2016-12-19 21:19:07 +00:00
|
|
|
variable is provided. We can use this variable to get rid of the conditional:
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd trash ${{
|
|
|
|
mkdir -p ~/.trash
|
|
|
|
IFS=':'; mv --backup=numbered $fx $HOME/.trash
|
|
|
|
}}
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
The trash directory is checked each time the command is executed. We can move
|
2016-12-19 21:19:07 +00:00
|
|
|
it outside of the command so it would only run once at startup:
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
${{ mkdir -p ~/.trash }}
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd trash ${{ IFS=':'; mv --backup=numbered $fx $HOME/.trash }}
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
Since these are one liners, we can drop "{{" and "}}":
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
$mkdir -p ~/.trash
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd trash $IFS=':'; mv --backup=numbered $fx $HOME/.trash
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
Finally note that we set "IFS" variable accordingly in the command. Instead we
|
|
|
|
could use the "ifs" option to set it for all commands (e.g. "set ifs ':'").
|
|
|
|
This could be especially useful for interactive use (e.g. "rm $fs" would simply
|
|
|
|
work). This option is not set by default as things may behave unexpectedly at
|
|
|
|
other places.
|
|
|
|
|
2016-09-15 14:08:05 +00:00
|
|
|
File Operations
|
|
|
|
|
|
|
|
lf uses the underlying "cp" and "mv" shell commands for file operations. For
|
|
|
|
this purpose, when you "yank" (i.e. copy) a file, it doesn't actually copy the
|
|
|
|
file on the disk, but only records its name to memory. The actual file
|
2016-11-06 15:09:18 +00:00
|
|
|
operation takes place when you do the "put" in which case the "cp" command is
|
2016-09-15 14:08:05 +00:00
|
|
|
used. Similarly the "mv" command is used for "delete" (i.e. cut or kill)
|
2016-11-06 15:09:18 +00:00
|
|
|
followed by "put". These traditional names (e.g. "yank", "delete", and "put")
|
|
|
|
are picked instead of the other common convention (e.g. copy and cut) to
|
|
|
|
resemble the default keybinds for these operations.
|
2016-09-15 14:08:05 +00:00
|
|
|
|
2016-09-14 23:18:50 +00:00
|
|
|
Opening Files
|
|
|
|
|
|
|
|
You can use "open-file" command to open a file. This is a special command
|
|
|
|
called by "open" when the current file is not a directory. Normally a user maps
|
|
|
|
the "open" command to a key (default "l") and customize "open-file" command as
|
2016-12-19 21:19:07 +00:00
|
|
|
desired. You can define it just as you would define any other command:
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd open-file $IFS=':'; vim $fx
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
It is possible to use different command types:
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd open-file &xdg-open "$f"
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
You may want to use either file extensions or mime types from "file" command:
|
2016-09-14 23:18:50 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
cmd open-file ${{
|
|
|
|
case $(file --mime-type "$f" -b) in
|
|
|
|
text/*) IFS=':'; vim $fx;;
|
|
|
|
*) IFS=':'; for f in $fx; do xdg-open "$f" &> /dev/null & done;;
|
|
|
|
esac
|
|
|
|
}}
|
2016-09-14 23:18:50 +00:00
|
|
|
|
|
|
|
lf does not come bundled with a file opener. You can use any of the existing
|
|
|
|
file openers as you like. Possible options are "open" (for Mac OS X only),
|
|
|
|
"xdg-utils" (executable name is "xdg-open"), "libfile-mimeinfo-perl"
|
|
|
|
(executable name is "mimeopen"), "rifle" (ranger's default file opener), or
|
|
|
|
"mimeo" to name a few.
|
2016-09-15 18:44:06 +00:00
|
|
|
|
|
|
|
Previewing Files
|
|
|
|
|
|
|
|
lf previews files on the preview pane by printing the file until the end or the
|
|
|
|
preview pane is filled. This output can be enhanced by providing a custom
|
|
|
|
preview script for filtering. This can be used to highlight source codes, list
|
|
|
|
contents of archive files or view pdf or image files as text to name few. For
|
|
|
|
coloring lf recognizes ansi escape codes.
|
|
|
|
|
|
|
|
In order to use this feature you need to set the value of "previewer" option to
|
|
|
|
the path of an executable file. lf passes the current file name as the first
|
|
|
|
argument and the height of the preview pane as the second argument when running
|
|
|
|
this file. Output of the execution is printed in the preview pane. You may want
|
2016-12-19 21:19:07 +00:00
|
|
|
to use the same script in your pager mapping as well if any:
|
2016-09-15 18:44:06 +00:00
|
|
|
|
2016-12-19 21:19:07 +00:00
|
|
|
set previewer ~/.config/lf/pv.sh
|
|
|
|
map i $~/.config/lf/pv.sh "$f" | less -R
|
2016-09-15 18:44:06 +00:00
|
|
|
|
|
|
|
Since this script is called for each file selection change it needs to be as
|
|
|
|
efficient as possible and this responsibility is left to the user. You may use
|
|
|
|
file extensions to determine the type of file more efficiently compared to
|
|
|
|
obtaining mime types from "file" command. Extensions can then be used to match
|
2016-12-19 21:19:07 +00:00
|
|
|
cleanly within a conditional:
|
|
|
|
|
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
case "$1" in
|
|
|
|
*.tar*) tar tf "$1";;
|
|
|
|
*.zip) unzip -l "$1";;
|
|
|
|
*.rar) unrar l "$1";;
|
|
|
|
*.7z) 7z l "$1";;
|
|
|
|
*.pdf) pdftotext "$1" -;;
|
|
|
|
*) highlight -O ansi "$1" || cat "$1";;
|
|
|
|
esac
|
2016-09-15 18:44:06 +00:00
|
|
|
|
|
|
|
Another important consideration for efficiency is the use of programs with
|
|
|
|
short startup times for preview. For this reason, "highlight" is recommended
|
|
|
|
over "pygmentize" for syntax highlighting. Besides, it is also important that
|
|
|
|
the application is processing the file on the fly rather than first reading it
|
|
|
|
to the memory and then do the processing afterwards. This is especially
|
|
|
|
relevant for big files. lf automatically closes the previewer script output
|
|
|
|
pipe with a SIGPIPE when enough lines are read. When everything else fails, you
|
|
|
|
can make use of the height argument to only feed the first portion of the file
|
|
|
|
to a program for preview.
|
2016-09-13 21:40:14 +00:00
|
|
|
*/
|
|
|
|
package main
|