I think I already established that Vim makes an excellent pager. Let me take it one step further: Vim is a customizable, programmable pager. (!)
There are plenty of cases where you want to pick one (1) thing out of a list. Vim can easily be made into a list picker.
A few examples
- pick a deep directory under the current directory (pick from find . -type d)
- pick a GNU screen session out of many (pick from screen -ls)
- pick a process to kill (pick from ps)
There are basically 2 components to these examples:
- what command will generate the list
- what command to run on the selection
The Code
Here’s the PickerMode plugin (put in ~/.vim/plugin/picker.vim)
function PickerMode()
set cursorline
nmap <buffer> <CR> V:w! ~/.picked<CR>:qa!<CR>
endfunction
command –nargs=0 PickerMode :call PickerMode()
Comments:
- cursorline highlight the line the cursor is on
- return saves the current line to ~/.picked
Here’s the bash code to invoke vim and execute a command on the selection:
# start vim in PAGER mode, with PickerMode plugin
function vim_picker() {
vim -c "PickerMode" -R –
}
# 1st parameter is command to generate a list
# 2nd parameter is command to run on selection
# 3rd (optional) parameter is DIRECT selection, bypassing VIM
function pick_with_vim() {
if [ -e ~/.picked ]; then
rm ~/.picked
fi
if [ -n "$3" ]; then
eval "$1" | sed -n $3p > ~/.picked
else
eval "$1" | vim_picker
fi
if [ -e ~/.picked ]; then
$2 "`cat ~/.picked`"
fi
}
Comments:
- the selection is written to a file called ~/.picked
- the existence of the file ~/.picked proves that you selected something
- functional programming in bash (!)
Using pick_with_vim
pick a deep directory under the current directory:
# pick from a list of directories (recursive) and cd into it
function c() {
pick_with_vim "find . -type d" "cd"
}
how to pick from screen:
function screen_r_x() {
screen -r $1 || screen -x $1
}
function sc() {
pick_with_vim "screen -ls | awk ‘/^\t/ {print \$1}’" "screen_r_x"
}
Here’s a much simpler rewrite of “go” (my directory bookmark miniapp)
# pick from directories in $HOME/.gorc and cd into it
function go() {
if [ ! -f $HOME/.gorc ]; then
echo "$HOME/.gorc does not exist…"
return 1
fi
pick_with_vim "cat $HOME/.gorc" "cd" $1
}
What now?
This code is available as part of my dotfiles on github. (though it is mixed with the rest)