dotfiles/.config/fish/functions/to.fish
2023-07-16 18:24:42 +02:00

290 lines
7.2 KiB
Fish

# Display general usage
function __to_usage
echo 'Usage:'
echo ' to (BOOKMARK|DIR) Go to BOOKMARK or DIR'
echo ' to add [BOOKMARK] [DEST] Create a BOOKMARK for DEST'
echo ' Default BOOKMARK: name of current directory'
echo ' Default DEST: path to current directory'
echo ' to add DEST Create a bookmark for DEST if it is a directory'
echo ' to ls List all bookmarks'
echo ' to mv OLD NEW Change the name of a bookmark from OLD to NEW'
echo ' to rm BOOKMARK Remove BOOKMARK'
echo ' to clean Remove bookmarks that have a missing destination'
echo ' to resolve BOOKMARK Print the destination of a bookmark'
echo ' to help Show this message'
echo
echo "Bookmarks are stored in: $TO_DIR"
echo 'To change, run: set -U TO_DIR <dir>'
return 1
end
# https://github.com/fish-shell/fish-shell/issues/6173#issuecomment-1067114363
function is_empty_dir
test -d "$argv"
or return 1 # not a directory, so not an empty directory
# count counts how many arguments it received
# if this glob doesn't match, it won't get arguments
# and so it will return 1
# because we *want* an empty directory, turn that around.
# the `{.*,*}` ensures it matches hidden files as well.
not count $argv/{.*,*} >/dev/null
end
function __to_dir
if test -n "$TO_DIR"
echo $TO_DIR
return
end
set -l dir
if test -d "$HOME/.tofish" && not is_empty_dir $HOME/.tofish
set dir $HOME/.tofish
else if test -n "$XDG_DATA_HOME"
set dir $XDG_DATA_HOME/to-fish
else
set dir $HOME/.local/share/to-fish
end
set -U TO_DIR $dir
echo $TO_DIR
end
function __to_bm_path
echo (__to_dir)/$argv
end
function __to_resolve
readlink (__to_bm_path $argv) 2>/dev/null
end
function __to_print
__to_resolve $argv | string replace -r "^$HOME" "~" | string replace -r '^~$' $HOME
end
function __to_ls
for l in (__to_dir)/*
basename $l
end
end
function __to_rm
command rm -v (__to_bm_path $argv[1]); or return $status
__to_update_bookmark_completions
end
function __to_add -a bm dest
# if there are no arguments
if test -z "$bm"
# use the current directory
set dest (pwd)
set bm (basename $dest)
else
# if there are two arguments
if test -n "$dest"
# use them as bookmark name and destination
set dest (realpath $dest)
# if there is only one argument
else
# if the argument is a directory
if string match -q '*/*' $bm && test -d "$bm"
# use it as the destination
set dest (realpath $bm)
set bm (basename $dest)
else
# if not a directory
# use it as the bookmark name
set dest (pwd)
end
end
end
if __to_resolve $bm > /dev/null
echo "ERROR: Bookmark exists: $bm -> "(__to_print $bm) >&2
return 1
end
if not test -d "$dest"
echo "ERROR: Destination does not exist: $dest" >&2
return 1
end
if string match -q '*/*' $bm
echo "ERROR: Bookmark name cannot contain '/': $bm" >&2
return 1
end
switch (uname)
case Darwin
command ln -s $dest (__to_bm_path $bm); or return $status
case '*'
command ln -sT $dest (__to_bm_path $bm); or return $status
end
echo $bm "->" (__to_print $bm)
__to_update_bookmark_completions
end
function __to_complete_directories
set -l cl (commandline -ct | string split -m 1 /)
set -l bm $cl[1]
set -l bmdir (__to_resolve $bm)
if test -z "$bmdir"
__fish_complete_directories
else
set -e cl[1]
if test -z "$cl"
__fish_complete_directories $bmdir/ | string replace -r 'Directory$' $bm
else
__fish_complete_directories $bmdir/$cl | string replace -r 'Directory$' $bm
end
end
end
function __to_update_bookmark_completions
complete -e -c to
complete -c to -k -x -s h -l help -d 'Show help'
# Subcommands
complete -c to -k -n '__fish_use_subcommand' -f -a 'help' -d 'Show help'
complete -c to -k -n '__fish_use_subcommand' -x -a 'resolve' -d 'Print bookmark destination'
complete -c to -k -n '__fish_use_subcommand' -x -a 'clean' -d 'Remove bad bookmarks'
complete -c to -k -n '__fish_use_subcommand' -x -a 'mv' -d 'Rename bookmark'
complete -c to -k -n '__fish_use_subcommand' -x -a 'rm' -d 'Remove bookmark'
complete -c to -k -n '__fish_use_subcommand' -f -a 'ls' -d 'List bookmarks'
complete -c to -k -n '__fish_use_subcommand' -x -a 'add' -d 'Create bookmark'
# Directories
complete -c to -k -n '__fish_use_subcommand' -r -a '(__to_complete_directories)'
# Bookmarks
for bm in (__to_ls | sort -r)
complete -c to -k -n '__fish_use_subcommand; or __fish_seen_subcommand_from rm mv resolve' -r -a (echo $bm | string escape) -d (__to_print $bm)
end
end
function to -d 'Bookmarking tool'
set -l dir (__to_dir)
# Create tofish directory
if not test -d "$dir"
if command mkdir $dir
echo "Created bookmark directory: $dir"
else
echo "Failed to Create bookmark directory: $dir"
return 1
end
end
# Catch usage errors
set -l cmd $argv[1]
set -l numargs (count $argv)
switch $cmd
# subcommands that don't take an argument
case ls help clean
if not test $numargs -eq 1
echo "Usage: to $cmd"
return 1
end
# subcommands that require an argument
case rm resolve
if not test $numargs -eq 2
echo "Usage: to $cmd BOOKMARK"
return 1
end
# add has 2 optional arguments
case add
if not test $numargs -ge 1 -a $numargs -le 3
echo 'Usage: to add [BOOKMARK] [DEST]'
echo ' to add DEST'
return 1
end
# subcommands that require 2 arguments
case mv
if not test $numargs -eq 3
echo 'Usage: to mv OLD NEW'
return 1
end
end
switch $cmd
# Add a bookmark
case add
__to_add $argv[2..-1]
return $status
# Remove a bookmark
case rm
__to_rm $argv[2]
return $status
# List all bookmarks
case ls
for bm in (__to_ls)
echo "$bm -> "(__to_print $bm)
end
return 0
# Rename a bookmark
case mv
set -l old $argv[2]
if not __to_resolve $old > /dev/null
echo "ERROR: Bookmark not found: $old"
return 1
end
set -l new $argv[3]
__to_add $new (__to_resolve $old); or return $status
__to_rm $old; or return $status
return 0
# Clean
case clean
for bm in (__to_ls)
if not test -d (__to_resolve $bm)
__to_rm $bm
end
end
return 0
# Resolve
case resolve
__to_resolve $argv[2]
return $status
# Help
case -h --help help
__to_usage
return 0
# Default
case '*'
set -l name $argv[1]
if test -z "$name"
__to_usage
return 1
end
set -l dest (__to_resolve $name)
if test -z "$dest"
if test -d "$name"
echo "cd \"$name\"" | source -
else
echo "to: No such bookmark “$name" >&2
return 1
end
else if test -d "$dest"
echo "cd \"$dest\"" | source -
else
echo "to: Destination for bookmark “$name” does not exist: $dest" >&2
return 1
end
end
end