From 54d1d98e3973a57f618e8c3f18ecb1b98f7f5368 Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Wed, 23 Sep 2015 13:28:32 +0200 Subject: Fix aliases with whitespace And document how that stuff works. Fixes #2220 Also, the string stuff is cool. --- doc_src/alias.txt | 6 +++ share/functions/alias.fish | 115 ++++++++++++++++++++++----------------------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/doc_src/alias.txt b/doc_src/alias.txt index 028277a3..cbb9508e 100644 --- a/doc_src/alias.txt +++ b/doc_src/alias.txt @@ -18,6 +18,8 @@ alias NAME=DEFINITION You cannot create an alias to a function with the same name. +Note that spaces need to be escaped in the call to alias just like in the commandline _even inside the quotes_. + \subsection alias-example Example @@ -31,4 +33,8 @@ alias rmi "rm -i" function rmi rm -i $argv end + +# This needs to have the spaces escaped or "Chrome.app..." will be seen as an argument to "/Applications/Google": + +alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome banana' \endfish diff --git a/share/functions/alias.fish b/share/functions/alias.fish index 2dc86b1b..11fdd164 100644 --- a/share/functions/alias.fish +++ b/share/functions/alias.fish @@ -1,70 +1,65 @@ +function alias --description 'Legacy function for creating shellscript functions using an alias-like syntax' + if count $argv > /dev/null + switch $argv[1] + case -h --h --he --hel --help + __fish_print_help alias + return 0 + end + end -function alias --description "Legacy function for creating shellscript functions using an alias-like syntax" + set -l name + set -l body + set -l prefix + set -l first_word + switch (count $argv) - if count $argv >/dev/null - switch $argv[1] - case -h --h --he --hel --help - __fish_print_help alias - return 0 - end - end + case 0 + echo "Fish implements aliases using functions. Use 'functions' builtin to see list of functions and 'functions function_name' to see function definition, type 'help alias' for more information." + return 1 + case 1 + set -l tmp (string replace -r "=" '\n' -- $argv) "" + set name $tmp[1] + set body $tmp[2] - set -l name - set -l body - set -l prefix - set -l first_word - switch (count $argv) + case 2 + set name $argv[1] + set body $argv[2] - case 0 - echo "Fish implements aliases using functions. Use 'functions' builtin to see list of functions and 'functions function_name' to see function definition, type 'help alias' for more information." - return 1 - case 1 - # Some seds (e.g. on Mac OS X), don't support \n in the RHS - # Use a literal newline instead - # http://sed.sourceforge.net/sedfaq4.html#s4.1 - # The extra '' at the end is so $tmp[2] is guaranteed to work - set -l tmp (echo $argv|sed -e 's/\([^=]\{0,1\}\)=/\1\ -/') '' - set name $tmp[1] - set body $tmp[2] + case \* + printf ( _ "%s: Expected one or two arguments, got %d\n") alias (count $argv) + return 1 + end - case 2 - set name $argv[1] - set body $argv[2] + # sanity check + if test -z "$name" + printf ( _ "%s: Name cannot be empty\n") alias + return 1 + else if test -z "$body" + printf ( _ "%s: Body cannot be empty\n") alias + return 1 + end - case \* - printf ( _ "%s: Expected one or two arguments, got %d\n") alias (count $argv) - return 1 - end + # Extract the first command from the body + # This is supposed to replace all non-escaped (i.e. preceded by an odd number of `\`) spaces with a newline + # so it splits on them + set -l tmp (string replace -ra "([^\\\ ])((\\\\\\\)*) " '$1\n' $body) + set first_word (string trim $tmp[1]) + if set -q tmp[2] + set body $tmp[2..-1] + else + set body + end - # sanity check - if test -z "$name" - printf ( _ "%s: Name cannot be empty\n") alias - return 1 - else if test -z "$body" - printf ( _ "%s: Body cannot be empty\n") alias - return 1 - end + # Prevent the alias from immediately running into an infinite recursion if + # $body starts with the same command as $name. - # Extract the first command from the body - switch $body - case \*\ \* \*\t\* - # note: strip leading spaces if present - set first_word (echo $body|sed -e 's/^[[:space:]]\{1,\}//;s/[[:space:]].*//;q') - case '*' - set first_word $body + if test $first_word = $name + if contains $name (builtin --names) + set prefix builtin + else + set prefix command end - - # Prevent the alias from immediately running into an infinite recursion if - # $body starts with the same command as $name. - - if test $first_word = $name - if contains $name (builtin --names) - set prefix builtin - else - set prefix command - end - end - - eval "function $name --wraps $first_word; $prefix $body \$argv; end" + end + eval "function $name --wraps $first_word; $prefix $first_word $body \$argv; end" end + -- cgit v1.2.3