# # This file defines various shellscript functions. Most of them are # meant to be used directly by the user, but some of them, typically # the ones whose name start with '__fish_', are only meant to be used # internally by fish. # function contains -d "Test if a key is contained in a set of values" while set -q argv switch $argv[1] case '-h' '--h' '--he' '--hel' '--help' help contains return case '--' # End the loop, the next argument is the key set -e argv[1] break case '-*' echo Unknown option $argv[$i] _contains_help return 1 case '*' # End the loop, we found the key break end set -e argv[1] end if not set -q argv printf (_ "%s: Key not specified\n") contains return 1 end set -- key $argv[1] set -e argv[1] # # Loop through values # printf "%s\n" $argv|grep -Fx -- $key >/dev/null return $status end # # help should use 'open' to find a suitable browser, but only # if there is a mime database _and_ DISPLAY is set, since the # browser will most likely be graphical. Since most systems which # have a mime databe also have the htmlview program, this is mostly a # theoretical problem. # function help -d "Show help for the fish shell" # Declare variables to set correct scope set fish_browser set fish_browser_bg set -l h syntax completion editor job-control todo bugs history killring help set h $h color prompt title variables builtin-overview changes expand set h $h expand-variable expand-home expand-brace expand-wildcard set -l help_topics $h expand-command-substitution expand-process # # Find a suitable browser for viewing the help pages. This is needed # by the help function defined below. # set graphical_browsers htmlview x-www-browser firefox galeon mozilla konqueror epiphany opera netscape set text_browsers htmlview www-browser links elinks lynx w3m if test $BROWSER # User has manualy set a preferred browser, so we respect that set fish_browser $BROWSER # If browser is known to be graphical, put into background if contains -- $BROWSER $graphical_browsers set fish_browser_bg 1 end else # Check for a text-based browser. for i in $text_browsers if which $i 2>/dev/null >/dev/null set fish_browser $i break end end # If we are in a graphical environment, check if there is a graphical # browser to use instead. if test (echo $DISPLAY) -a \( "$XAUTHORITY" = "$HOME/.Xauthority" -o "$XAUTHORITY" = "" \) for i in $graphical_browsers if which $i 2>/dev/null >/dev/null set fish_browser $i set fish_browser_bg 1 break end end end end if test -z $fish_browser printf (_ '%s: Could not find a web browser.\n') help printf (_ 'Please set the variable $BROWSER to a suitable browser and try again\n\n') return 1 end set fish_help_item $argv[1] switch "$fish_help_item" case "" set fish_help_page index.html case "." set fish_help_page "builtins.html\#source" case difference set fish_help_page difference.html case globbing set fish_help_page "index.html\#expand" case (builtin -n) set fish_help_page "builtins.html\#"$fish_help_item case count dirh dirs help mimedb nextd open popd prevd pushd set_color tokenize psub umask type set fish_help_page "commands.html\#"$fish_help_item case $help_topics set fish_help_page "index.html\#"$fish_help_item case "*" if which $fish_help_item >/dev/null ^/dev/null man $fish_help_item return end set fish_help_page "index.html" end if test $fish_browser_bg eval $fish_browser file://$__fish_help_dir/$fish_help_page \& else eval $fish_browser file://$__fish_help_dir/$fish_help_page end end # # Make ls use colors if we are on a system that supports this # if ls --version 1>/dev/null 2>/dev/null # This is GNU ls function ls -d "List contents of directory" command ls --color=auto --indicator-style=classify $argv end else # BSD, OS X and a few more support colors through the -G switch instead if ls / -G 1>/dev/null 2>/dev/null function ls -d "List contents of directory" command ls -G $argv end end end # # These are very common and useful # function ll -d "List contents of directory using long format" ls -lh $argv end function la -d "List contents of directory using long format, showing hidden files" ls -lha $argv end # # This allows us to use 'open FILENAME' to open a given file in the default # application for the file. # function open -d "Open file in default application" mimedb -l -- $argv end # # Print the current working directory. If it is too long, it will be # ellipsised. This function is used by the default prompt command. # function prompt_pwd -d "Print the current working directory, shortend to fit the prompt" set -l wd (pwd) set -l res (echo $wd|sed -e 's-/\([^/]\)\([^/]*\)-/\1-g') if test $wd != '~' set res $res(echo $wd|sed -e 's-.*/[^/]\([^/]*$\)-\1-') end echo $res end # # Make pwd print out the home directory as a tilde. # function pwd -d "Print working directory" command pwd | sed -e "s|^$HOME|~|" end # # This is a neat function, stolen from zsh. It allows you to edit the # value of a variable interactively. # function vared -d "Edit variable value" if test (count $argv) = 1 switch $argv case '-h' '--h' '--he' '--hel' '--help' __vared_help case '-*' printf "vared: Unknown option %s\n" $argv case '*' if test (count $$argv ) -lt 2 set init '' if test $$argv set -- init $$argv end set prompt 'set_color green; echo '$argv'; set_color normal; echo "> "' read -p $prompt -c $init tmp # If variable already exists, do not add any # switches, so we don't change export rules. But # if it does not exist, we make the variable # global, so that it will not die when this # function dies if test $$argv set -- $argv $tmp else set -g -- $argv $tmp end else printf (_ 'vared: %s is an array variable. Use %svared%s %s[n] to edit the n:th element of %s\n') $argv (set_color $fish_color_command) (set_color $fish_color_normal) $argv $argv end end else printf (_ 'vared: Expected exactly one argument, got %s.\n\nSynopsis:\n\t%svared%s VARIABLE\n') (count $argv) (set_color $fish_color_command) (set_color $fish_color_normal) end end function __vared_help -d "Display help for the vared shellscript function" printf "\tvared - Interactively edit the value of an environment variable\n\n" printf "%s\n\t%svared%s VARIABLE\n\n" (__bold Synopsis) (set_color $fish_color_command) (set_color normal) __bold Description printf "\n\n\tvared is used to interactively edit the value of an environment \n" printf "\tvariable. Array variables as a whole can not be edited using vared,\n" printf "\tbut individual array elements can.\n\n" __bold Example printf "\n\n\t"\'"%svared%s PATH[3]"\'" edits the third element of the PATH array.\n\n" (set_color $fish_color_co\mmand) (set_color normal) end # # This function is bound to Alt-L, it is used to list the contents of # the directory under the cursor # function __fish_list_current_token -d "List contents of token under the cursor if it is a directory, otherwise list the contents of the current directory" set val (eval echo (commandline -t)) if test -d $val ls $val else set dir (dirname $val) if test $dir != . -a -d $dir ls $dir else ls end end end function pushd -d "Push directory to stack" # Comment to avoid set completions set -g dirstack (command pwd) $dirstack cd $argv[1] end function popd -d "Pop dir from stack" if test $dirstack[1] cd $dirstack[1] else echo Directory stack is empty... return 1 end set -e dirstack[1] end function dirs -d "Print directory stack" echo -n (command pwd)" " for i in $dirstack echo -n $i" " end echo end # # The following functions add support for a directory history # function cd -d "Change directory" # Skip history in subshells if status --is-command-substitution builtin cd $argv return $status end # Avoid set completions set previous (command pwd) if test $argv[1] = - ^/dev/null if test $__fish_cd_direction = next ^/dev/null nextd else prevd end return $status end builtin cd $argv[1] if test $status = 0 -a (command pwd) != $previous set -g dirprev $dirprev $previous set -e dirnext set -g __fish_cd_direction prev end return $status end function __fish_move_last -d "Move the last element of a directory history from src to dest" set src $argv[1] set dest $argv[2] set size_src (count $$src) if test $size_src = 0 # Cannot make this step printf (_ "Hit end of history...\n") return 1 end # Append current dir to the end of the destination set -g (echo $dest) $$dest (command pwd) set ssrc $$src # Change dir to the last entry in the source dir-hist builtin cd $ssrc[$size_src] # Keep all but the last from the source dir-hist set -e (echo $src)[$size_src] # All ok, return success return 0 end function prevd -d "Move back in the directory history" # Parse arguments set show_hist 0 set times 1 for i in (seq (count $argv)) switch $argv[$i] case '-l' set show_hist 1 continue case '-*' echo Uknown option $argv[$i] return 1 case '*' if test $argv[$i] -ge 0 ^/dev/null set times $argv[$i] else printf (_ "The number of positions to skip must be a non-negative integer\n") return 1 end continue end end # Traverse history set code 1 for i in (seq $times) # Try one step backward if __fish_move_last dirprev dirnext; # We consider it a success if we were able to do at least 1 step # (low expectations are the key to happiness ;) set code 0 else break end end # Show history if needed if test $show_hist = 1 dirh end # Set direction for 'cd -' if test $code = 0 ^/dev/null set -g __fish_cd_direction next end # All done return $code end function nextd -d "Move forward in the directory history" # Parse arguments set show_hist 0 set times 1 for i in (seq (count $argv)) switch $argv[$i] case '-l' set show_hist 1 continue case '-*' echo Uknown option $argv[$i] return 1 case '*' if test $argv[$i] -ge 0 ^/dev/null set times $argv[$i] else echo "The number of positions to skip must be a non-negative integer" return 1 end continue end end # Traverse history set code 1 for i in (seq $times) # Try one step backward if __fish_move_last dirnext dirprev; # We consider it a success if we were able to do at least 1 step # (low expectations are the key to happiness ;) set code 0 else break end end # Show history if needed if test $show_hist = 1 dirh end # Set direction for 'cd -' if test $code = 0 ^/dev/null set -g __fish_cd_direction prev end # All done return $code end function dirh -d "Print the current directory history (the back- and fwd- lists)" # Avoid set comment set current (command pwd) set -- separator " " set -- line_len (echo (count $dirprev) + (echo $dirprev $current $dirnext | wc -m) | bc) if test $line_len -gt $COLUMNS # Print one entry per line if history is long set separator "\n" end for i in $dirprev echo -n -e $i$separator end set_color $fish_color_history_current echo -n -e $current$separator set_color normal for i in (seq (echo (count $dirnext)) -1 1) echo -n -e $dirnext[$i]$separator end echo end function __bold -d "Print argument in bold" set_color --bold printf "%s" $argv[1] set_color normal end function __trap_translate_signal set upper (echo $argv[1]|tr a-z A-Z) if expr $upper : 'SIG.*' >/dev/null echo $upper | cut -c 4- else echo $upper end end function __trap_switch switch $argv[1] case EXIT echo --on-exit %self case '*' echo --on-signal $argv[1] end end function trap -d 'Perform an action when the shell recives a signal' set -l mode set -l cmd set -l sig set -l shortopt set -l longopt set shortopt -o lph if getopt -T >/dev/null set longopt else set longopt -l print,help,list-signals end if not getopt -n type -Q $shortopt $longopt -- $argv return 1 end set -l tmp (getopt $shortopt $longopt -- $argv) eval set opt $tmp while count $opt >/dev/null switch $opt[1] case -h --help help trap return 0 case -p --print set mode print case -l --list-signals set mode list case -- set -e opt[1] break end set -e opt[1] end if not count $mode >/dev/null switch (count $opt) case 0 set mode print case 1 set mode clear case '*' if test opt[1] = - set -e opt[1] set mode clear else set mode set end end end switch $mode case clear for i in $opt set -- sig (__trap_translate_signal $i) if test $sig functions -e __trap_handler_$sig end end case set set -l cmd $opt[1] set -e opt[1] for i in $opt set -l -- sig (__trap_translate_signal $i) set -- sw (__trap_switch $sig) if test $sig eval "function __trap_handler_$sig $sw; $cmd; end" else return 1 end end case print set -l names if count $opt >/dev/null set -- names $opt else set -- names (functions -na|grep "^__trap_handler_"|sed -e 's/__trap_handler_//' ) end for i in $names set -- sig (__trap_translate_signal $i) if test sig functions __trap_handler_$i else return 1 end end case list kill -l end end function type -d "Print the type of a command" # Initialize set status 1 set mode normal set selection all # Get options # set -- shortopt -o tpPafh if getopt -T >/dev/null set longopt else set -- longopt -l type,path,force-path,all,no-functions,help end if not getopt -n type -Q $shortopt $longopt -- $argv return 1 end set -- tmp (getopt $shortopt $longopt -- $argv) eval set -- opt $tmp for i in $opt switch $i case -t --type set mode type case -p --path set mode path case -P --force-path set mode path set selection files case -a --all set selection multi case -f --no-functions set selection files case -h --help help type return 0 case -- break end end # Check all possible types for the remaining arguments for i in $argv switch $i case '-*' continue end # Found will be set to 1 if a match is found set found 0 if test $selection != files if contains -- $i (functions -na) set status 0 set found 1 switch $mode case normal printf (_ '%s is a function with definition\n') $i functions $i case type printf (_ 'function\n') case path echo end if test $selection != multi continue end end if contains -- $i (builtin -n) set status 0 set found 1 switch $mode case normal printf (_ '%s is a builtin\n') $i case type printf (_ 'builtin\n') case path echo end if test $selection != multi continue end end end if which $i ^/dev/null >/dev/null set status 0 set found 1 switch $mode case normal printf (_ '%s is %s\n') $i (which $i) case type printf (_ 'file\n') case path which $i end if test $selection != multi continue end end if test $found = 0 printf (_ "%s: Could not find '%s'") type $i end end return $status end function __fish_umask_parse -d "Parses a file permission specification as into an octal version" # Test if already a valid octal mask, and pad it with zeros if echo $argv | grep -E '^(0|)[0-7]{1,3}$' >/dev/null for i in (seq (echo 5-(echo $argv|wc -c)|bc)); set -- argv 0$argv; end echo $argv else # Test if argument really is a valid symbolic mask if not echo $argv | grep -E '^(((u|g|o|a|)(=|\+|-)|)(r|w|x)*)(,(((u|g|o|a|)(=|\+|-)|)(r|w|x)*))*$' >/dev/null printf (_ "%s: Invalid mask '%s'\n") umask $argv >&2 return 1 end set -e implicit_all # Insert inverted umask into res variable set tmp $umask for i in 1 2 3 set -- tmp (echo $tmp|cut -c 2-) set -- res[$i] (echo 7-(echo $tmp|cut -c 1)|bc) end set -- el (echo $argv|tr , \n) for i in $el switch $i case 'u*' set idx 1 set -- i (echo $i| cut -c 2-) case 'g*' set idx 2 set -- i (echo $i| cut -c 2-) case 'o*' set idx 3 set -- i (echo $i| cut -c 2-) case 'a*' set idx 1 2 3 set -- i (echo $i| cut -c 2-) case '*' set implicit_all 1 set idx 1 2 3 end switch $i case '=*' set mode set set -- i (echo $i| cut -c 2-) case '+*' set mode add set -- i (echo $i| cut -c 2-) case '-*' set mode remove set -- i (echo $i| cut -c 2-) case '*' if not set -q implicit_all echo umask: Invalid mask $argv >&2 return end set mode set end if not echo $perm|grep -E '^(r|w|x)*$' >/dev/null echo umask: Invalid mask $argv >&2 return end set val 0 if echo $i |grep 'r' >/dev/null set val 4 end if echo $i |grep 'w' >/dev/null set val (echo $val + 2|bc) end if echo $i |grep 'x' >/dev/null set val (echo $val + 1|bc) end for j in $idx switch $mode case set set res[$j] $val case add set res[$j] (perl -e 'print( ( '$res[$j]'|'$val[$j]' )."\n" )') case remove set res[$j] (perl -e 'print( ( (7-'$res[$j]')&'$val[$j]' )."\n" )') end end end for i in 1 2 3 set res[$i] (echo 7-$res[$i]|bc) end echo 0$res[1]$res[2]$res[3] end end function __fish_umask_print_symbolic set -l res "" set -l letter a u g o for i in 2 3 4 set res $res,$letter[$i]= set val (echo $umask|cut -c $i) if contains $val 0 1 2 3 set res {$res}r end if contains $val 0 1 4 5 set res {$res}w end if contains $val 0 2 4 6 set res {$res}x end end echo $res|cut -c 2- end function umask -d "Set default file permission mask" set -l as_command 0 set -l symbolic 0 set -- shortopt -o pSh if getopt -T >/dev/null set longopt else set -- longopt -l as-command,symbolic,help end if not getopt -n umask -Q $shortopt $longopt -- $argv return 1 end set tmp -- (getopt $shortopt $longopt -- $argv) eval set -- opt $tmp while count $opt >/dev/null switch $opt[1] case -h --help help umask return 0 case -p --as-command set as_command 1 case -S --symbolic set symbolic 1 case -- set -e opt[1] break end set -e opt[1] end switch (count $opt) case 0 if not set -q umask set -g umask 113 end if test $as_command -eq 1 echo umask $umask else if test $symbolic -eq 1 __fish_umask_print_symbolic $umask else echo $umask end end case 1 set -l parsed (__fish_umask_parse $opt) if test (count $parsed) -eq 1 set -g umask $parsed end case '*' printf (_ '%s: Too many arguments\n') umask >&2 end end function psub -d "Read from stdin into a file and output the filename. Remove the file when the command that calles psub exits." set -l filename set -l funcname if count $argv >/dev/null switch $argv[1] case '-h*' --h --he --hel --help help psub return 0 case '*' printf (_ "%s: Unknown argument '%s'\n") psub $argv[1] return 1 end end if not status --is-command-substitution echo psub: Not inside of command substitution >&2 return end # Find unique file name for writing output to while true set filename /tmp/.psub.(echo %self).(random); if not test -e $filename break; end end # Write output to pipe. This needs to be done in the background so # that the command substitution exits without needing to wait for # all the commands to exit mkfifo $filename cat >$filename & # Write filename to stdout echo $filename # Find unique function name while true set funcname __fish_psub_(random); if not functions $funcname >/dev/null ^/dev/null break; end end # Make sure we erase file when caller exits eval function $funcname --on-job-exit caller\; rm $filename\; functions -e $funcname\; end end function prevd-or-backward-word --key-binding if test -z (commandline) prevd else commandline -f backward-word end end function nextd-or-forward-word --key-binding if test -z (commandline) nextd else commandline -f forward-word end end # # This function deletes a character from the commandline if it is # non-empty, and exits the shell otherwise. Implementing this # functionality has been a longstanding request from various # fish-users. # function delete-or-exit --key-binding if test (commandline) commandline -f delete-char else exit end end