Roger said:
I'm wondering if anybody knows of a shell that can be programmed
to "guess" what you meant when you type in a command errantly,
like (kind of a bad example, but...)
$ git dif
(it runs git dif, fails, then, in method_missing style, I can
tell it "oh what I always means when I run git dif is git diff"
so it correct its for me and runs it).
Any pointers on where to go there?
Well, kind of. You might use PROMPT_COMMAND in bash to react if
the last command failed (as in the above case of a misspelled
second argument). Or you could use a command_not_found_handle
function (new in bash 4.0, see the manual) as a hook for a
misspelled binary name, and go from there. Maybe both.
Here's something I hacked together using the first method. It
works a bit different from your suggestion in that it uses compgen
to guess the possible corrections for the second argument
(checking first if there is a completion function for this
command), then uses the builtin select command to query the user
for a correction, and then runs the corrected command. So it will
ask you if you meant "git diff" or "git difftool" in the case of
"git dif" failing. (Note that git's completion already asks a "did
you mean" question, so it's a little redundant here...)
Not exactly what you asked for (still fails for "git dfif"), and
probably not perfect, but maybe it's a pointer to start from
So, here's the code to source into bash:
last_commandline () {
# fetch the last commandline from the history
local histtimeformat=$HISTTIMEFORMAT
unset HISTTIMEFORMAT
[[ $(history 1) =~ \ +[0-9]+?\ +(.+?) ]]
local commandline=${BASH_REMATCH[1]}
if [[ "$histtimeformat" != "" ]]; then
HISTTIMEFORMAT=$histtimeformat
fi
echo "$commandline"
}
correct () {
args=($*)
rest="${args[@]:2}" # third to last arg
if type -t "_$1" &>/dev/null; then
# there's a completion function for this command
# get possible completions for the incomplete second argument
comps=($(compgen -W "$(compgen -F _$1 2>/dev/null)" -- $2))
# let the user choose, then run the corrected command
select choice in ${comps[@]}; do
echo "running corrected command: $1 $choice $rest";
$1 $choice $rest
break;
done
fi
}
# we'll use the prompt command as a hook for failed commands
PROMPT_COMMAND='[[ ! $? -eq 0 ]] && correct $(last_commandline)'