method_missing for command shell?

R

Roger Pack

Hi all. My bash-fu is a little bit lacking, so here's my question.

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?
Thanks.
-r
 
M

Mario Camou

[Note: parts of this message were removed to make it a legal post.]

Try zsh
-Mario.
 
R

Roger Pack

Mario said:

Interesting. Seeing the syntax that zsh uses makes me want to rewrite
the whole thing just so I can use ruby for command completions LOL :)

-r
 
C

cldwalker

Hi all.  My bash-fu is a little bit lacking, so here's my question.

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?

I'm writing a ruby command/task execution gem which could allow for
easy ruby wrapping of system commands and method_missing-fu for
subcommands: http://github.com/cldwalker/boson

I already do subcommand method_missing with boson, not for guessing
but for smart aliasing: http://github.com/cldwalker/irbfiles/blob/master/boson/commands/boson_method_missing.rb#L10-25

Here's how you could define a simple Boson library that wraps git
subcommands:

module Git
%w{add checkout diff rm merge pull push}.each do |e|
define_method(e) do |*args|
system('git', e, *args)
end
end
end

With boson you would be able to execute these subcommands from the
commandline or irb as follows:

bash> boson git.diff
irb>> git.diff

With the above method_missing library you could execute these as git.d
or git.dif

Unfortunately Boson isn't ready yet. Hopefully within the week. In the
mean time you could take that example
module and use it within irb:

def git
@git ||= Object.new.extend Git
end

class << git
def method_missing(meth, *args, &block)
if !(meths = Git.instance_methods.sort.grep(/^#{meth}/)).empty?
send(meths[0].to_sym, *args, &block)
else
super
end
end
end
 
A

Aldric Giacomoni

Roger said:
Interesting. Seeing the syntax that zsh uses makes me want to rewrite
the whole thing just so I can use ruby for command completions LOL :)

-r

You're welcome to write your own shell in Ruby ;-)
 
F

Fabian Streitel

[Note: parts of this message were removed to make it a legal post.]

yeah and let me know when it's done and has the same feature set
as bash, then I'll come over and kiss your feet and pay you a drink
;-)

Greetz!
 
H

Henning Bekel

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)'
 
R

Roger Pack

Here's something I hacked together using the first method. It
...
Not exactly what you asked for (still fails for "git dfif"), and
probably not perfect, but maybe it's a pointer to start from ;)
Nice.


...
yeah and let me know when it's done and has the same feature set as Bash
...

what feature set would you require?


-r
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top