This post is about combination of skim, ripgrep and fd that generalizes common ways of using terminal. Let me show you some examples.
Notes keeping system
Being bitten a few times by device or vendor lock offs, I formulated for myself this rules:
- Life without keeping notes educate own memory worse than it could
- Life after notes loss is possible and can be even better than before
- Notes keeping system should follow KISS and be portable
Thus, my current system consists mostly of FS trees and plain markdown files. Directory name represents major interest category, names of the files are often thought as a cloud of tags. Since it's so simple, the real overall structure of notes keeping place are volatile, and depends on how often new strings appears there and how often renaming occures.
Below you can see bash
function m
(short for "memory") runs sk
changing to the root dir of all notes. Then you'll see list of files narrowed by shell
query. Right side is a split preview window rendering content that can be scrolled to better get what is looked for. Since no files matched with xargs
, I switched with tab to "grep mode" and prepend query with '
(single quote) to discard default fuzziness of skim
. There preview window points attention to the concrete line with matched word. Afterall, file opened with nvim
.
Personal web archive
Slight variation of previous idea. Gif starts from picking up URL to archive page locally. wa
is another bash
function. It wraps wget
to download page fully when called with argumens, or runs same machinery as above to navigate all web archive store. It also shows, that preview can display images as ASCII blocks with help of viu (this is tmux
restriction) or, additionally, open them, in my case, with Quick Look.
Code navigation
In addition to two modes—files and grep—switching between each other with tab, vim extends them with outline mode (pipe in current buffer to the ctags
and massage its output back with awk
), and buffers mode (show loaded files and allow to close'em). This is not something new to those already using fzf
or skim
as a daily driver. Maybe just good integration with skim
previewer and seamless mode switching without the need to close skim
window and hitting another binding keys for next function.
Setup tips
Keep as most options as you can in environment variable
Even though varables values would look extremely cryptic, this lets hold important defaults in a single place. I've found that I can't use the only options for all the use cases, but always trying hard to put sane defaults here.
export SKIM_DEFAULT_COMMAND="fd --type file --follow --hidden --exclude .git --color=always || find ."
export SKIM_DEFAULT_OPTIONS="
--ansi \
--reverse \
--color=16 \
--delimiter=: \
--preview-window='right:65%:hidden:+{2}-/2' \
--preview='
case \`file -bL --mime-type {1}\` in
text/html) w3m {1} ;;
text/troff) man {1} ;;
text/*) bat --style=numbers --color=always --highlight-line {2}:+0 {1} ;;
image/*) viu {1} ;;
application/pdf) pdftotext -layout -nopgbrk {1} - ;;
*) hexyl --bytes=4KiB --color=always --border=none {1} ;;
esac
'
--bind='\
ctrl-d:half-page-down,\
ctrl-u:half-page-up,\
?:toggle-preview,\
alt-/:execute-silent(ql {}),\
alt-space:execute-silent(ql {})+down,\
alt-j:preview-down,\
alt-k:preview-up,\
alt-h:preview-left,\
alt-l:preview-right,\
alt-d:preview-page-down,\
alt-u:preview-page-up,'\
"
Here you can see key bindings modifications --bind=
that mimic those in vim. --preview
expects string that will be passed to $SHELL -c
, so value is basically a map of MIME type to the helper tool.
Wrap sk
with shell function
This make possible emulate mode switching from fd
to rg
and back again. It is also use euristics or conventions when selected item has been picked up.
sk() {
# stdin is not a tty means data has been piped into skim
if [ ! -t 0 ]; then
command sk "$@"
return $?
fi
local qry key sel mod res
__fd() {
command sk \
--prompt="Fls> " \
--header=" " \
--no-multi \
--cmd='fd --color=always --type file --follow' \
--expect=enter,alt-enter,ctrl-m,alt-m,ctrl-c,esc,tab \
--print-query \
--query="$1"
}
__rg() {
command sk \
--prompt="Rgp> " \
--header=" " \
--no-multi \
--cmd='rg --color=always --ignore-case --line-number "{}"' \
--delimiter=: \
--nth="3.." \
--expect=enter,alt-enter,ctrl-m,alt-m,ctrl-c,esc,tab \
--print-query \
--query="$1"
}
mod="__fd"
qry="$@"
while true; do
res=$(eval '$mod' '$qry')
qry=$(echo "$res" | sed -n 1p)
key=$(echo "$res" | sed -n 2p)
sel=$(echo "$res" | sed -n 3p)
[ "$key" != "tab" ] && break
if [ "$mod" = "__rg" ]; then
mod="__fd"
else
mod="__rg"
fi
done
case "$key" in
ctrl-m | enter)
if [ -z "$sel" ]; then
$EDITOR "${qry#\'}"
elif [ "$mod" = "__fd" ]; then
$EDITOR "$sel"
else
$EDITOR $(echo "$sel" | cut -f1,2 -d':' | sed 's/:/ \+/g')
fi
;;
alt-m | alt-enter)
echo "${sel:-$qry}"
;;
ctrl-c | esc | *)
return 0
;;
esac
}
Use that wrapped function as a basis for other workflows
Here is my m
:
m() {
trap "cd `pwd`" EXIT
cd $HOME/mem
sk "$@"
}
And wa
:
wa() {
trap "cd `pwd`" EXIT
cd $HOME/warc
if [ -z "$1" ]; then
EDITOR="open" sk "$@"
return $?
fi
wget \
--page-requisites \
--convert-links \
--adjust-extension \
--compression=auto \
--reject-regex='/search|/rss' \
--no-if-modified-since \
--no-check-certificate \
--user-agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64)' \
"$@"
}
If you're vim user, write some extra commands
Mad looking? Definitely true. This is an example of outline mode.
command! -nargs=? Otln
\ call skim#run({
\ 'source': "ctags -f - --sort=foldcase --file-scope=no --all-kinds=* --fields=Kn " . expand('%:p') .
\ ' | grep -F "/;\""'.
\ " | awk -F $'\t' ".
\ "'".
\ ' BEGIN { OFS=FS }'.
\ ' {'.
\ ' gsub(/implementation/, "impl", $4);'.
\ ' gsub(/\/\^[ ]*/, "", $3);'.
\ ' gsub(/[; {]*\$\/;"$/, "", $3);'.
\ ' gsub(/line:/, "", $5);'.
\ ' printf "%d\t%12s %-31s\t%s\n", $5, $4, $1, $3;'.
\ " }'".
\ " | sort -bk2,2",
\ 'sink*': function('s:OpenUp', ['Otln']),
\ 'options': ['--header= ', '--layout=reverse',
\ '--no-sort',
\ '--query=' . <q-args>,
\ '--expect=tab',
\ '--print-query',
\ '--delimiter=\t', '--nth=3',
\ '--color=16', '--inline-info', '--prompt=Otln> ',
\ '--cycle',
\ '--preview-window=right:65%:hidden:+{1}-/2',
\ '--preview=bat --style=numbers --color=always --highlight-line={1} ' . expand('%:p')] })
More can be found at dotfiles repo.