Fix type function to work better

Stop using getopt to parse flags. It's far more expensive than
necessary, and results in long flags not being parsed on OS X. This also
allows args starting with - after the options list to be properly
interpreted as a value to test.

Print the error message to stderr as is appropriate.

Use the new `command -p` functionality when the -a flag has not been
provided (`command` does not have any equivalent to the -a flag),
instead of using `which`. This is faster and also avoids any possible
disagreement between `which` and what fish thinks is valid.

Stop testing every path to see if it's executable, that test has already
been done by `which` or `command -p`.

The end result is `type -P ls` is roughly 250% faster, according to
profiling, on my OS X machine.
This commit is contained in:
Kevin Ballard 2014-07-09 23:38:33 -07:00
parent 0933e5cab4
commit bfd3a47380

View file

@ -6,37 +6,11 @@ function type --description "Print the type of a command"
set -l mode normal
set -l selection all
#
# Get options
#
set -l options
set -l shortopt tpPafh
if not getopt -T > /dev/null
# GNU getopt
set -l longopt type,path,force-path,all,no-functions,help
set options -o $shortopt -l $longopt --
# Verify options
if not getopt -n type $options $argv >/dev/null
return 1
end
else
# Old getopt, used on OS X
set options $shortopt
# Verify options
if not getopt $options $argv >/dev/null
return 1
end
end
# Do the real getopt invocation
set -l tmp (getopt $options $argv)
# Break tmp up into an array
set -l opt
eval set opt $tmp
for i in $opt
switch $i
# Parse options
set -l names
if test (count $argv) -gt 0
for i in (seq (count $argv))
switch $argv[$i]
case -t --type
set mode type
@ -58,21 +32,21 @@ function type --description "Print the type of a command"
return 0
case --
set names $argv[$i..-1]
set -e names[1]
break
case '*'
set names $argv[$i..-1]
break
end
end
end
# Check all possible types for the remaining arguments
for i in $argv
switch $i
case '-*'
continue
end
for i in $names
# Found will be set to 1 if a match is found
set found 0
set -l found 0
if test $selection != files
@ -119,12 +93,11 @@ function type --description "Print the type of a command"
set -l paths
if test $selection != multi
set paths (which $i ^/dev/null)
set paths (command -p $i)
else
set paths (which -a $i ^/dev/null)
end
for path in $paths
if test -x (echo $path)
set res 0
set found 1
switch $mode
@ -141,10 +114,9 @@ function type --description "Print the type of a command"
continue
end
end
end
if test $found = 0
printf (_ "%s: Could not find '%s'\n") type $i
printf (_ "%s: Could not find '%s'\n") type $i >&2
end
end