clean up how help works, pull cmd_reload up so all module types can use it
git-svn-id: file:///home/svn/framework3/trunk@11658 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
1af730148f
commit
a7b5e831f7
|
@ -94,6 +94,10 @@ module ModuleCommandDispatcher
|
|||
|
||||
include Msf::Ui::Console::CommandDispatcher
|
||||
|
||||
def commands
|
||||
{ "reload" => "Reload the current module from disk" }
|
||||
end
|
||||
|
||||
#
|
||||
# The active driver module, if any.
|
||||
#
|
||||
|
@ -108,6 +112,49 @@ module ModuleCommandDispatcher
|
|||
self.driver.active_module = m
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads the active module
|
||||
#
|
||||
def cmd_reload(*args)
|
||||
begin
|
||||
reload
|
||||
rescue
|
||||
log_error("Failed to reload: #{$!}")
|
||||
end
|
||||
end
|
||||
|
||||
def cmd_reload_help
|
||||
print_line "Usage: reload [-k]"
|
||||
print_line
|
||||
print_line "Reloads the current module."
|
||||
print @@reload_opts.usage
|
||||
end
|
||||
|
||||
#
|
||||
# Reload the current module, optionally stopping existing job
|
||||
#
|
||||
def reload(should_stop_job=false)
|
||||
if should_stop_job and mod.job_id
|
||||
print_status('Stopping existing job...')
|
||||
|
||||
framework.jobs.stop_job(mod.job_id)
|
||||
mod.job_id = nil
|
||||
end
|
||||
|
||||
print_status('Reloading module...')
|
||||
|
||||
omod = self.mod
|
||||
self.mod = framework.modules.reload_module(mod)
|
||||
|
||||
if(not self.mod)
|
||||
print_status("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
|
||||
self.mod = omod
|
||||
return
|
||||
end
|
||||
|
||||
self.mod.init_ui(driver.input, driver.output)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end end end
|
||||
|
|
|
@ -25,13 +25,13 @@ class Auxiliary
|
|||
# Returns the hash of commands specific to auxiliary modules.
|
||||
#
|
||||
def commands
|
||||
{
|
||||
super.update({
|
||||
"run" => "Launches the auxiliary module",
|
||||
"rerun" => "Reloads and launches the auxiliary module",
|
||||
"exploit" => "This is an alias for the run command",
|
||||
"rexploit" => "This is an alias for the rerun command",
|
||||
"reload" => "Reloads the auxiliary module"
|
||||
}.merge( (mod ? mod.auxiliary_commands : {}) )
|
||||
}).merge( (mod ? mod.auxiliary_commands : {}) )
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -56,58 +56,16 @@ class Auxiliary
|
|||
"Auxiliary"
|
||||
end
|
||||
|
||||
#
|
||||
# This is an alias for 'rerun'
|
||||
#
|
||||
def cmd_rexploit(*args)
|
||||
cmd_rerun(*args)
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads an auxiliary module
|
||||
#
|
||||
def cmd_reload(*args)
|
||||
begin
|
||||
omod = self.mod
|
||||
self.mod = framework.modules.reload_module(mod)
|
||||
if(not self.mod)
|
||||
print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
|
||||
self.mod = omod
|
||||
end
|
||||
rescue
|
||||
log_error("Failed to reload: #{$!}")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads an auxiliary module and executes it
|
||||
#
|
||||
def cmd_rerun(*args)
|
||||
if mod.job_id
|
||||
print_status("Stopping existing job...")
|
||||
|
||||
framework.jobs.stop_job(mod.job_id)
|
||||
mod.job_id = nil
|
||||
end
|
||||
|
||||
omod = self.mod
|
||||
self.mod = framework.modules.reload_module(mod)
|
||||
|
||||
if(not self.mod)
|
||||
print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
|
||||
self.mod = omod
|
||||
return
|
||||
end
|
||||
reload(true)
|
||||
|
||||
cmd_run(*args)
|
||||
end
|
||||
|
||||
#
|
||||
# This is an alias for 'run'
|
||||
#
|
||||
def cmd_exploit(*args)
|
||||
cmd_run(*args)
|
||||
end
|
||||
alias cmd_rexploit cmd_rerun
|
||||
|
||||
#
|
||||
# Executes an auxiliary module
|
||||
|
@ -131,10 +89,7 @@ class Auxiliary
|
|||
when '-q'
|
||||
quiet = true
|
||||
when '-h'
|
||||
print(
|
||||
"Usage: run [options]\n\n" +
|
||||
"Launches an auxiliary module.\n" +
|
||||
@@auxiliary_opts.usage)
|
||||
cmd_run_help
|
||||
return false
|
||||
end
|
||||
}
|
||||
|
@ -177,6 +132,17 @@ class Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
alias cmd_exploit cmd_run
|
||||
|
||||
def cmd_run_help
|
||||
print_line "Usage: run [options]"
|
||||
print_line
|
||||
print_line "Launches an auxiliary module."
|
||||
print @@auxiliary_opts.usage
|
||||
end
|
||||
|
||||
alias cmd_exploit_help cmd_run_help
|
||||
|
||||
end
|
||||
|
||||
end end end end
|
||||
|
|
|
@ -284,9 +284,7 @@ class Core
|
|||
#
|
||||
def cmd_connect(*args)
|
||||
if args.length < 2 or args.include?("-h")
|
||||
print( "Usage: connect [options] <host> <port>\n\n" +
|
||||
"Communicate with a host, similar to interacting via netcat.\n" +
|
||||
@@connect_opts.usage)
|
||||
cmd_connect_help
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -460,6 +458,14 @@ class Core
|
|||
true
|
||||
end
|
||||
|
||||
def cmd_connect_help
|
||||
print_line "Usage: connect [options] <host> <port>"
|
||||
print_line
|
||||
print_line "Communicate with a host, similar to interacting via netcat, taking advantage of"
|
||||
print_line "any configured session pivoting."
|
||||
print @@connect_opts.usage
|
||||
end
|
||||
|
||||
#
|
||||
# Instructs the driver to stop executing.
|
||||
#
|
||||
|
@ -485,44 +491,6 @@ class Core
|
|||
Rex::ThreadSafe.sleep(args[0].to_f)
|
||||
end
|
||||
|
||||
#
|
||||
# Displays the command help banner or an individual command's help banner
|
||||
# if we can figure out how to invoke it.
|
||||
#
|
||||
def cmd_help(*args)
|
||||
if args and args.length > 0 and commands.include?(args[0])
|
||||
if self.respond_to? "cmd_"+ args[0] + "_help"
|
||||
self.send("cmd_"+ args[0] + "_help")
|
||||
else
|
||||
#
|
||||
# This part is done in a hackish way because not all of the
|
||||
# usage info is available from self.commands() or @@*_opts, so
|
||||
# we check @@<cmd>_opts for "-h". It's non-optimal because
|
||||
# several commands have usage info, but don't use -h to invoke
|
||||
# it.
|
||||
begin
|
||||
opts = eval("@@" + args[0] + "_opts")
|
||||
rescue
|
||||
end
|
||||
if opts and opts.include?("-h")
|
||||
self.send("cmd_" + args[0], "-h")
|
||||
else
|
||||
print_line("No help available for #{args[0]}")
|
||||
end
|
||||
end
|
||||
else
|
||||
print(driver.help_to_s)
|
||||
end
|
||||
end
|
||||
def cmd_help_tabs(str, words)
|
||||
return [] if words.length > 1
|
||||
|
||||
return commands.keys
|
||||
end
|
||||
|
||||
|
||||
alias cmd_? cmd_help
|
||||
|
||||
#
|
||||
# Displays information about one or more module.
|
||||
#
|
||||
|
@ -620,10 +588,7 @@ class Core
|
|||
dump_info = true
|
||||
job_id = val
|
||||
when "-h"
|
||||
print(
|
||||
"Usage: jobs [options]\n\n" +
|
||||
"Active job manipulation and interaction.\n" +
|
||||
@@jobs_opts.usage())
|
||||
cmd_jobs_help
|
||||
return false
|
||||
end
|
||||
}
|
||||
|
@ -670,6 +635,13 @@ class Core
|
|||
[]
|
||||
end
|
||||
|
||||
def cmd_jobs_help
|
||||
print_line "Usage: jobs [options]"
|
||||
print_line
|
||||
print_line "Active job manipulation and interaction."
|
||||
print @@jobs_opts.usage()
|
||||
end
|
||||
|
||||
def cmd_kill(*args)
|
||||
cmd_jobs("-k", *args)
|
||||
end
|
||||
|
@ -679,6 +651,13 @@ class Core
|
|||
framework.jobs.keys
|
||||
end
|
||||
|
||||
def cmd_kill_help
|
||||
print_line "Usage: kill <job1> [job2 ...]"
|
||||
print_line
|
||||
print_line "Equivalent to 'jobs -k job1 -k job2 ...'"
|
||||
print @@jobs_opts.usage()
|
||||
end
|
||||
|
||||
#
|
||||
# Displays and manages running background threads
|
||||
#
|
||||
|
@ -725,10 +704,7 @@ class Core
|
|||
dump_info = true
|
||||
thread_id = val.to_i
|
||||
when "-h"
|
||||
print(
|
||||
"Usage: threads [options]\n\n" +
|
||||
"Background thread management.\n" +
|
||||
@@threads_opts.usage())
|
||||
cmd_threads_help
|
||||
return false
|
||||
end
|
||||
}
|
||||
|
@ -800,6 +776,13 @@ class Core
|
|||
[]
|
||||
end
|
||||
|
||||
def cmd_threads_help
|
||||
print(
|
||||
"Usage: threads [options]\n\n" +
|
||||
"Background thread management.\n" +
|
||||
@@threads_opts.usage())
|
||||
end
|
||||
|
||||
# Loads a plugin from the supplied path. If no absolute path is supplied,
|
||||
# the framework root plugin directory is used.
|
||||
#
|
||||
|
@ -1132,8 +1115,8 @@ class Core
|
|||
def cmd_loadpath(*args)
|
||||
defanged?
|
||||
|
||||
if (args.length == 0)
|
||||
print_error("No search paths were provided.")
|
||||
if (args.length == 0 or args.include? "-h")
|
||||
cmd_loadpath_help
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -1205,6 +1188,13 @@ class Core
|
|||
return paths
|
||||
end
|
||||
|
||||
def cmd_loadpath_help
|
||||
print_line "Usage: loadpath /path/to/modules"
|
||||
print_line
|
||||
print_line "Loads modules from the given directory which should contain subdirectories for"
|
||||
print_line "module types, e.g. /path/to/modules/exploits"
|
||||
end
|
||||
|
||||
#
|
||||
# Searches modules (name and description) for specified regex
|
||||
#
|
||||
|
@ -1216,8 +1206,7 @@ class Core
|
|||
@@search_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when "-h"
|
||||
print_line("Usage: search [options] [regex]")
|
||||
print(@@search_opts.usage)
|
||||
cmd_search_help
|
||||
return
|
||||
when "-t"
|
||||
section = val
|
||||
|
@ -1284,12 +1273,18 @@ class Core
|
|||
when "-r"
|
||||
return RankingName.sort.map{|r| r[1]}
|
||||
when "-t"
|
||||
return %w{auxiliary encoder exploit nop payload}
|
||||
return %w{auxiliary encoder exploit nop payload post}
|
||||
end
|
||||
|
||||
[]
|
||||
end
|
||||
|
||||
def cmd_search_help
|
||||
print_line "Usage: search [options] [regex]"
|
||||
print_line
|
||||
print @@search_opts.usage
|
||||
end
|
||||
|
||||
#
|
||||
# Provides an interface to the sessions currently active in the framework.
|
||||
#
|
||||
|
@ -1359,10 +1354,7 @@ class Core
|
|||
|
||||
# Display help banner
|
||||
when "-h"
|
||||
print(
|
||||
"Usage: sessions [options]\n\n" +
|
||||
"Active session manipulation and interaction.\n" +
|
||||
@@sessions_opts.usage())
|
||||
cmd_sessions_help
|
||||
return false
|
||||
else
|
||||
extra << val
|
||||
|
@ -1568,6 +1560,13 @@ class Core
|
|||
[]
|
||||
end
|
||||
|
||||
def cmd_sessions_help
|
||||
print_line "Usage: sessions [options]"
|
||||
print_line
|
||||
print_line "Active session manipulation and interaction."
|
||||
print(@@sessions_opts.usage())
|
||||
end
|
||||
|
||||
#
|
||||
# Sets a name to a value in a context aware environment.
|
||||
#
|
||||
|
@ -1736,21 +1735,7 @@ class Core
|
|||
args.each { |type|
|
||||
case type
|
||||
when '-h'
|
||||
global_opts = %w{all encoders nops exploits payloads auxiliary plugins options}
|
||||
opts = ''
|
||||
global_opts.each { |el|
|
||||
opts << ', ' if opts.length > 0
|
||||
opts << el
|
||||
}
|
||||
print_status("Valid parameters for the \"show\" command are: #{opts}")
|
||||
module_opts = %w{ advanced evasion targets actions }
|
||||
opts = ''
|
||||
module_opts.each { |el|
|
||||
opts << ', ' if opts.length > 0
|
||||
opts << el
|
||||
}
|
||||
print_status("Additional module-specific parameters are: #{opts}")
|
||||
|
||||
cmd_show_help
|
||||
when 'all'
|
||||
show_encoders
|
||||
show_nops
|
||||
|
@ -1835,6 +1820,14 @@ class Core
|
|||
return res
|
||||
end
|
||||
|
||||
def cmd_show_help
|
||||
global_opts = %w{all encoders nops exploits payloads auxiliary plugins options}
|
||||
print_status("Valid parameters for the \"show\" command are: #{global_opts.join(", ")}")
|
||||
|
||||
module_opts = %w{ advanced evasion targets actions }
|
||||
print_status("Additional module-specific parameters are: #{module_opts.join(", ")}")
|
||||
end
|
||||
|
||||
#
|
||||
# Unloads a plugin by its name.
|
||||
#
|
||||
|
@ -1891,11 +1884,7 @@ class Core
|
|||
|
||||
# No arguments? No cookie.
|
||||
if (args.length == 0)
|
||||
print(
|
||||
"Usage: unset var1 var2 var3 ...\n\n" +
|
||||
"The unset command is used to unset one or more variables.\n" +
|
||||
"To flush all entires, specify 'all' as the variable name\n")
|
||||
|
||||
cmd_unset_help
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -1934,6 +1923,14 @@ class Core
|
|||
datastore.keys
|
||||
end
|
||||
|
||||
def cmd_unset_help
|
||||
print_line "Usage: unset [-g] var1 var2 var3 ..."
|
||||
print_line
|
||||
print_line "The unset command is used to unset one or more variables."
|
||||
print_line "To flush all entires, specify 'all' as the variable name."
|
||||
print_line "With -g, operates on global datastore variables."
|
||||
end
|
||||
|
||||
#
|
||||
# Unsets variables in the global data store.
|
||||
#
|
||||
|
@ -1950,6 +1947,8 @@ class Core
|
|||
self.framework.datastore.keys
|
||||
end
|
||||
|
||||
alias cmd_unsetg_help cmd_unset_help
|
||||
|
||||
#
|
||||
# Uses a module.
|
||||
#
|
||||
|
|
|
@ -31,13 +31,13 @@ class Exploit
|
|||
# Returns the hash of exploit module specific commands.
|
||||
#
|
||||
def commands
|
||||
{
|
||||
super.update({
|
||||
"check" => "Check to see if a target is vulnerable",
|
||||
"exploit" => "Launch an exploit attempt",
|
||||
"rcheck" => "Reloads the module and checks if the target is vulnerable",
|
||||
"rexploit" => "Reloads the module and launches an exploit attempt",
|
||||
"reload" => "Just reloads the module"
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -124,10 +124,7 @@ class Exploit
|
|||
when '-z'
|
||||
bg = true
|
||||
when '-h'
|
||||
print(
|
||||
"Usage: exploit [options]\n\n" +
|
||||
"Launches an exploitation attempt.\n" +
|
||||
@@exploit_opts.usage)
|
||||
cmd_exploit_help
|
||||
return false
|
||||
end
|
||||
}
|
||||
|
@ -203,6 +200,13 @@ class Exploit
|
|||
end
|
||||
end
|
||||
|
||||
def cmd_exploit_help
|
||||
print_line "Usage: exploit [options]"
|
||||
print_line
|
||||
print_line "Launches an exploitation attempt."
|
||||
print @@exploit_opts.usage
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads an exploit module and checks the target to see if it's
|
||||
# vulnerable.
|
||||
|
@ -210,68 +214,28 @@ class Exploit
|
|||
def cmd_rcheck(*args)
|
||||
reload()
|
||||
|
||||
self.mod.init_ui(driver.input, driver.output)
|
||||
cmd_check(*args)
|
||||
end
|
||||
|
||||
#
|
||||
# Reload an exploit module, optionally stopping existing job
|
||||
#
|
||||
def reload(should_stop_job=false)
|
||||
|
||||
if should_stop_job and mod.job_id
|
||||
print_status('Stopping existing job...')
|
||||
|
||||
framework.jobs.stop_job(mod.job_id)
|
||||
mod.job_id = nil
|
||||
end
|
||||
|
||||
|
||||
print_status('Reloading module...')
|
||||
|
||||
omod = self.mod
|
||||
self.mod = framework.modules.reload_module(mod)
|
||||
|
||||
if(not self.mod)
|
||||
print_status("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
|
||||
self.mod = omod
|
||||
return
|
||||
end
|
||||
|
||||
self.mod.init_ui(driver.input, driver.output)
|
||||
end
|
||||
|
||||
#
|
||||
# Handles the command to reload an exploit module.
|
||||
#
|
||||
def cmd_reload(*args)
|
||||
# By default, do not stop the existing job
|
||||
stop_existing = false
|
||||
|
||||
@@reload_opts.parse(args) { |opt, idx, val|
|
||||
case opt
|
||||
when '-k'
|
||||
stop_existing = true
|
||||
when '-h'
|
||||
print_line "Usage: reload [-k]\n\nReloads the current module."
|
||||
print_line @@reload_opts.usage
|
||||
return
|
||||
end
|
||||
}
|
||||
|
||||
reload(stop_existing)
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads an exploit module and launches an exploit.
|
||||
#
|
||||
def cmd_rexploit(*args)
|
||||
return cmd_rexploit_help if args.include? "-h"
|
||||
|
||||
# Stop existing job and reload the module
|
||||
reload(true)
|
||||
# Delegate to the exploit command
|
||||
cmd_exploit(*args)
|
||||
end
|
||||
|
||||
def cmd_rexploit_help
|
||||
print_line "Usage: rexploit [options]"
|
||||
print_line
|
||||
print_line "Reloads a module, stopping any associated job, and launches an exploitation attempt."
|
||||
print @@exploit_opts.usage
|
||||
end
|
||||
|
||||
#
|
||||
# Picks a reasonable payload and minimally configures it
|
||||
#
|
||||
|
|
|
@ -24,9 +24,9 @@ class Nop
|
|||
# Returns the hash of supported commands.
|
||||
#
|
||||
def commands
|
||||
{
|
||||
super.update({
|
||||
"generate" => "Generates a NOP sled",
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -39,9 +39,9 @@ class Payload
|
|||
# Returns the hash of commands specific to payload modules.
|
||||
#
|
||||
def commands
|
||||
{
|
||||
super.update({
|
||||
"generate" => "Generates a payload",
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -24,20 +24,18 @@ class Post
|
|||
# Returns the hash of commands specific to post modules.
|
||||
#
|
||||
def commands
|
||||
{
|
||||
super.update({
|
||||
"run" => "Launches the post exploitation module",
|
||||
"rerun" => "Reloads and launches the module",
|
||||
"exploit" => "This is an alias for the run command",
|
||||
"rexploit" => "This is an alias for the rerun command",
|
||||
"reload" => "Reloads the post exploitation module"
|
||||
}.merge( (mod ? mod.post_commands : {}) )
|
||||
}).merge( (mod ? mod.post_commands : {}) )
|
||||
end
|
||||
|
||||
#
|
||||
# Allow modules to define their own commands
|
||||
#
|
||||
def method_missing(meth, *args)
|
||||
$stdout.puts("Post#method_missing")
|
||||
if (mod and mod.respond_to?(meth.to_s))
|
||||
|
||||
# Initialize user interaction
|
||||
|
@ -63,22 +61,6 @@ class Post
|
|||
cmd_rerun(*args)
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads an auxiliary module
|
||||
#
|
||||
def cmd_reload(*args)
|
||||
begin
|
||||
omod = self.mod
|
||||
self.mod = framework.modules.reload_module(mod)
|
||||
if(not self.mod)
|
||||
print_error("Failed to reload module: #{framework.modules.failed[omod.file_path]}")
|
||||
self.mod = omod
|
||||
end
|
||||
rescue
|
||||
log_error("Failed to reload: #{$!}")
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Reloads an auxiliary module and executes it
|
||||
#
|
||||
|
@ -102,12 +84,7 @@ class Post
|
|||
cmd_run(*args)
|
||||
end
|
||||
|
||||
#
|
||||
# This is an alias for 'run'
|
||||
#
|
||||
def cmd_exploit(*args)
|
||||
cmd_run(*args)
|
||||
end
|
||||
alias cmd_rexploit cmd_rerun
|
||||
|
||||
#
|
||||
# Executes an auxiliary module
|
||||
|
@ -175,6 +152,15 @@ class Post
|
|||
end
|
||||
end
|
||||
|
||||
def cmd_run_help
|
||||
print_line "Usage: run [options]"
|
||||
print_line
|
||||
print_line "Launches a post module."
|
||||
print @@auxiliary_opts.usage
|
||||
end
|
||||
|
||||
alias cmd_exploit_help cmd_run_help
|
||||
|
||||
end
|
||||
|
||||
end end end end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
require 'rex/ui'
|
||||
require 'pp'
|
||||
|
||||
module Rex
|
||||
module Ui
|
||||
|
@ -79,6 +80,54 @@ module DispatcherShell
|
|||
shell.update_prompt(prompt)
|
||||
end
|
||||
|
||||
#
|
||||
# Displays the help banner. With no arguments, this is just a list of
|
||||
# all commands grouped by dispatcher. Otherwise, tries to use a method
|
||||
# named cmd_#{+cmd+}_help for the first dispatcher that has a command
|
||||
# named +cmd+.
|
||||
#
|
||||
def cmd_help(cmd=nil, *ignored)
|
||||
if cmd
|
||||
help_found = false
|
||||
cmd_found = false
|
||||
shell.dispatcher_stack.each do |dispatcher|
|
||||
next unless dispatcher.respond_to?(:commands)
|
||||
next if (dispatcher.commands.nil?)
|
||||
next if (dispatcher.commands.length == 0)
|
||||
|
||||
if dispatcher.respond_to?("cmd_#{cmd}")
|
||||
cmd_found = true
|
||||
break unless dispatcher.respond_to? "cmd_#{cmd}_help"
|
||||
dispatcher.send("cmd_#{cmd}_help")
|
||||
help_found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
print_error("No help for #{cmd}, try -h") if cmd_found and not help_found
|
||||
print_error("No such command") if not cmd_found
|
||||
else
|
||||
print(driver.help_to_s)
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Tab completion for the help command
|
||||
#
|
||||
# By default just returns a list of all commands in all dispatchers.
|
||||
#
|
||||
def cmd_help_tabs(str, words)
|
||||
return [] if words.length > 1
|
||||
|
||||
tabs = []
|
||||
shell.dispatcher_stack.each { |dispatcher|
|
||||
tabs += dispatcher.commands.keys
|
||||
}
|
||||
return tabs
|
||||
end
|
||||
|
||||
alias cmd_? cmd_help
|
||||
|
||||
|
||||
#
|
||||
# No tab completion items by default
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue