#!/usr/bin/env rc flag e + fn usage { echo 'usage: bm [-f|--full] [-l|--ls] [name]' >[1=2] echo ' bm add [-n|--name name] [path]' >[1=2] echo ' bm rm [-f|--full] [-l|--ls] [name]' >[1=2] echo ' bm list [-f|--full]' >[1=2] } fn fail { echo bm: $"* >[1=2] exit 1 } fn bookmark_path { cat $store/$1 } fn validate_name { if(~ $1 () add rm list -*) fail $1 is reserved if(~ $1 .* */* *' '*) fail invalid bookmark name: $1 } fn list_bookmarks { for(file in $store/*) { if(test -f $file) { name=`` $nl {basename $file} dir=`` $nl {cat $file} if(~ $full 1) printf '%s\t%s\n' $name $dir if(! ~ $full 1) printf '%s\n' $name } } } fn choose_bookmark { if(! command -v fzf >/dev/null >[2=1]) fail fzf is required candidates=`` $nl {mktemp -t bm.XXXXXXXX} for(file in $store/*) { if(test -f $file) { name=`` $nl {basename $file} dir=`` $nl {cat $file} contents=() if(~ $show_ls 1) contents=`` $nl {ls -A -1 $dir | tr '\n' ' '} printf '%s\t%s\t%s\n' $name $dir $"contents >>$candidates } } nth=1 if(~ $full 1) nth=1,2 selection=`` $nl {fzf --delimiter '\t' --nth $nth --with-nth 1,2,3 <$candidates} status=$status rm -f $candidates if(~ $status 130 1) return if(! ~ $status 0) exit $status printf '%s\n' $selection } if(~ $XDG_DATA_HOME ()) data_home=$HOME/.local/share if(! ~ $XDG_DATA_HOME ()) data_home=$XDG_DATA_HOME store=$data_home/bm/bookmarks mkdir -p $store if(~ $1 --path) shift command=go if(~ $1 add rm list) { command=$1 shift } switch($command) { case add name=() dir=() while(! ~ $#* 0) { switch($1) { case -n --name shift if(~ $#* 0) fail missing name name=$1 case -h --help usage exit case -* fail unknown option: $1 case * if(! ~ $dir ()) fail too many paths dir=$1 } shift } if(~ $dir ()) dir=$PWD if(! test -d $dir) fail not a directory: $dir dir=`` $nl {cd $dir && pwd -P} if(~ $name ()) name=`` $nl {basename $dir} validate_name $name tmp=`` $nl {mktemp $store/.tmp.XXXXXXXX} printf '%s\n' $dir >$tmp mv -f $tmp $store/$name echo $dir >[1=2] case rm full=0 show_ls=0 name=() while(! ~ $#* 0) { switch($1) { case -f --full full=1 case -l --ls show_ls=1 case -h --help usage exit case -* fail unknown option: $1 case * if(! ~ $name ()) fail too many bookmark names name=$1 } shift } if(~ $name ()) { selection=`` $nl {choose_bookmark} if(~ $selection ()) exit name=`` $nl {printf '%s\n' $selection | cut -f1} } if(! test -f $store/$name) fail no such bookmark: $name rm -f $store/$name case list full=0 while(! ~ $#* 0) { switch($1) { case -f --full full=1 case -h --help usage exit case * fail unknown option: $1 } shift } list_bookmarks case go full=0 show_ls=0 name=() while(! ~ $#* 0) { switch($1) { case -f --full full=1 case -l --ls show_ls=1 case -h --help usage exit case -* fail unknown option: $1 case * if(! ~ $name ()) fail too many bookmark names name=$1 } shift } if(~ $name ()) { selection=`` $nl {choose_bookmark} if(~ $selection ()) exit name=`` $nl {printf '%s\n' $selection | cut -f1} } if(! test -f $store/$name) fail no such bookmark: $name dir=`` $nl {bookmark_path $name} if(! test -d $dir) fail bookmark is not a directory: $dir printf '%s\n' $dir }