summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Lo <stan.lo@shopify.com>2022-12-08 19:10:19 +0000
committergit <svn-admin@ruby-lang.org>2022-12-08 19:10:23 +0000
commit3956bb859c2442d34ea171db8f92f3e5895c43d9 (patch)
tree4800d4eb49ceadec321f37e644ab98fb1f597aa6
parent2cea8e014dbbbb68e4e8be367529b2beae564c54 (diff)
[ruby/irb] Add "show_cmds" command to list all commands'
descriptions (https://github.com/ruby/irb/pull/463) https://github.com/ruby/irb/commit/7e857655ac
-rw-r--r--lib/irb/cmd/backtrace.rb2
-rw-r--r--lib/irb/cmd/break.rb2
-rw-r--r--lib/irb/cmd/catch.rb2
-rw-r--r--lib/irb/cmd/chws.rb6
-rw-r--r--lib/irb/cmd/continue.rb2
-rw-r--r--lib/irb/cmd/debug.rb14
-rw-r--r--lib/irb/cmd/delete.rb2
-rw-r--r--lib/irb/cmd/edit.rb3
-rw-r--r--lib/irb/cmd/finish.rb2
-rw-r--r--lib/irb/cmd/help.rb3
-rw-r--r--lib/irb/cmd/info.rb2
-rw-r--r--lib/irb/cmd/irb_info.rb3
-rw-r--r--lib/irb/cmd/load.rb10
-rw-r--r--lib/irb/cmd/ls.rb3
-rw-r--r--lib/irb/cmd/measure.rb3
-rw-r--r--lib/irb/cmd/next.rb2
-rw-r--r--lib/irb/cmd/nop.rb11
-rw-r--r--lib/irb/cmd/pushws.rb9
-rw-r--r--lib/irb/cmd/show_cmds.rb39
-rw-r--r--lib/irb/cmd/show_source.rb3
-rw-r--r--lib/irb/cmd/step.rb2
-rw-r--r--lib/irb/cmd/subirb.rb12
-rw-r--r--lib/irb/cmd/whereami.rb3
-rw-r--r--lib/irb/extend-command.rb49
-rw-r--r--test/irb/test_cmd.rb10
25 files changed, 182 insertions, 17 deletions
diff --git a/lib/irb/cmd/backtrace.rb b/lib/irb/cmd/backtrace.rb
index ac4f0e0e7e..f632894618 100644
--- a/lib/irb/cmd/backtrace.rb
+++ b/lib/irb/cmd/backtrace.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Backtrace < Debug
+ class Backtrace < DebugCommand
def self.transform_args(args)
args&.dump
end
diff --git a/lib/irb/cmd/break.rb b/lib/irb/cmd/break.rb
index 2c82413f6a..df259a90ca 100644
--- a/lib/irb/cmd/break.rb
+++ b/lib/irb/cmd/break.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Break < Debug
+ class Break < DebugCommand
def self.transform_args(args)
args&.dump
end
diff --git a/lib/irb/cmd/catch.rb b/lib/irb/cmd/catch.rb
index 8c9e086a9c..40b62c7533 100644
--- a/lib/irb/cmd/catch.rb
+++ b/lib/irb/cmd/catch.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Catch < Debug
+ class Catch < DebugCommand
def self.transform_args(args)
args&.dump
end
diff --git a/lib/irb/cmd/chws.rb b/lib/irb/cmd/chws.rb
index b28c090686..7c84ba0a4b 100644
--- a/lib/irb/cmd/chws.rb
+++ b/lib/irb/cmd/chws.rb
@@ -19,12 +19,18 @@ module IRB
module ExtendCommand
class CurrentWorkingWorkspace < Nop
+ category "IRB"
+ description "Show the current workspace."
+
def execute(*obj)
irb_context.main
end
end
class ChangeWorkspace < Nop
+ category "IRB"
+ description "Change the current workspace to an object."
+
def execute(*obj)
irb_context.change_workspace(*obj)
irb_context.main
diff --git a/lib/irb/cmd/continue.rb b/lib/irb/cmd/continue.rb
index 94696e4b6c..9136177eef 100644
--- a/lib/irb/cmd/continue.rb
+++ b/lib/irb/cmd/continue.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Continue < Debug
+ class Continue < DebugCommand
def execute(*args)
super(do_cmds: ["continue", *args].join(" "))
end
diff --git a/lib/irb/cmd/debug.rb b/lib/irb/cmd/debug.rb
index 2c09c99cf0..76f17e3c2f 100644
--- a/lib/irb/cmd/debug.rb
+++ b/lib/irb/cmd/debug.rb
@@ -5,6 +5,9 @@ module IRB
module ExtendCommand
class Debug < Nop
+ category "Debugging"
+ description "Start the debugger of debug.gem."
+
BINDING_IRB_FRAME_REGEXPS = [
'<internal:prelude>',
binding.method(:irb).source_location.first,
@@ -108,5 +111,16 @@ module IRB
end
end
end
+
+ class DebugCommand < Debug
+ def self.category
+ "Debugging"
+ end
+
+ def self.description
+ command_name = self.name.split("::").last.downcase
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
+ end
+ end
end
end
diff --git a/lib/irb/cmd/delete.rb b/lib/irb/cmd/delete.rb
index 3810ae414e..aeb26d2572 100644
--- a/lib/irb/cmd/delete.rb
+++ b/lib/irb/cmd/delete.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Delete < Debug
+ class Delete < DebugCommand
def execute(*args)
super(pre_cmds: ["delete", *args].join(" "))
end
diff --git a/lib/irb/cmd/edit.rb b/lib/irb/cmd/edit.rb
index 8d3fab3273..98fa07e49d 100644
--- a/lib/irb/cmd/edit.rb
+++ b/lib/irb/cmd/edit.rb
@@ -6,6 +6,9 @@ module IRB
module ExtendCommand
class Edit < Nop
+ category "Misc"
+ description 'Open a file with the editor command defined with `ENV["EDITOR"]`.'
+
class << self
def transform_args(args)
# Return a string literal as is for backward compatibility
diff --git a/lib/irb/cmd/finish.rb b/lib/irb/cmd/finish.rb
index de4b4f12cf..29f100feb5 100644
--- a/lib/irb/cmd/finish.rb
+++ b/lib/irb/cmd/finish.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Finish < Debug
+ class Finish < DebugCommand
def execute(*args)
super(do_cmds: ["finish", *args].join(" "))
end
diff --git a/lib/irb/cmd/help.rb b/lib/irb/cmd/help.rb
index 0497c57457..3ef59f5eea 100644
--- a/lib/irb/cmd/help.rb
+++ b/lib/irb/cmd/help.rb
@@ -16,6 +16,9 @@ module IRB
module ExtendCommand
class Help < Nop
+ category "Context"
+ description "Enter the mode to look up RI documents."
+
def execute(*names)
require 'rdoc/ri/driver'
opts = RDoc::RI::Driver.process_args([])
diff --git a/lib/irb/cmd/info.rb b/lib/irb/cmd/info.rb
index 413c286429..2c0a32b34f 100644
--- a/lib/irb/cmd/info.rb
+++ b/lib/irb/cmd/info.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Info < Debug
+ class Info < DebugCommand
def self.transform_args(args)
args&.dump
end
diff --git a/lib/irb/cmd/irb_info.rb b/lib/irb/cmd/irb_info.rb
index 8a4e1bd603..da11e8d40b 100644
--- a/lib/irb/cmd/irb_info.rb
+++ b/lib/irb/cmd/irb_info.rb
@@ -7,6 +7,9 @@ module IRB
module ExtendCommand
class IrbInfo < Nop
+ category "IRB"
+ description "Show information about IRB."
+
def execute
Class.new {
def inspect
diff --git a/lib/irb/cmd/load.rb b/lib/irb/cmd/load.rb
index 2c5c01e89c..76368f856c 100644
--- a/lib/irb/cmd/load.rb
+++ b/lib/irb/cmd/load.rb
@@ -20,6 +20,9 @@ module IRB
class Load < Nop
include IrbLoader
+ category "IRB"
+ description "Load a Ruby file."
+
def execute(file_name, priv = nil)
return irb_load(file_name, priv)
end
@@ -28,6 +31,9 @@ module IRB
class Require < Nop
include IrbLoader
+ category "IRB"
+ description "Require a Ruby file."
+
def execute(file_name)
rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
@@ -58,6 +64,10 @@ module IRB
class Source < Nop
include IrbLoader
+
+ category "IRB"
+ description "Loads a given file in the current session."
+
def execute(file_name)
source_file(file_name)
end
diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb
index 735bf17241..b65fae2bf1 100644
--- a/lib/irb/cmd/ls.rb
+++ b/lib/irb/cmd/ls.rb
@@ -9,6 +9,9 @@ module IRB
module ExtendCommand
class Ls < Nop
+ category "Context"
+ description "Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output."
+
def self.transform_args(args)
if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\n\z/)
args = match[:args]
diff --git a/lib/irb/cmd/measure.rb b/lib/irb/cmd/measure.rb
index a97baee9f1..9122e2dac9 100644
--- a/lib/irb/cmd/measure.rb
+++ b/lib/irb/cmd/measure.rb
@@ -5,6 +5,9 @@ module IRB
module ExtendCommand
class Measure < Nop
+ category "Misc"
+ description "`measure` enables the mode to measure processing time. `measure :off` disables it."
+
def initialize(*args)
super(*args)
end
diff --git a/lib/irb/cmd/next.rb b/lib/irb/cmd/next.rb
index 2943a753fb..d29c82e7fc 100644
--- a/lib/irb/cmd/next.rb
+++ b/lib/irb/cmd/next.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Next < Debug
+ class Next < DebugCommand
def execute(*args)
super(do_cmds: ["next", *args].join(" "))
end
diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb
index 881a736722..280bfe4677 100644
--- a/lib/irb/cmd/nop.rb
+++ b/lib/irb/cmd/nop.rb
@@ -14,6 +14,17 @@ module IRB
module ExtendCommand
class Nop
+ class << self
+ def category(category = nil)
+ @category = category if category
+ @category
+ end
+
+ def description(description = nil)
+ @description = description if description
+ @description
+ end
+ end
if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
def self.execute(conf, *opts, **kwargs, &block)
diff --git a/lib/irb/cmd/pushws.rb b/lib/irb/cmd/pushws.rb
index 791d8f8dbb..41d2e705f1 100644
--- a/lib/irb/cmd/pushws.rb
+++ b/lib/irb/cmd/pushws.rb
@@ -18,12 +18,18 @@ module IRB
module ExtendCommand
class Workspaces < Nop
+ category "IRB"
+ description "Show workspaces."
+
def execute(*obj)
irb_context.workspaces.collect{|ws| ws.main}
end
end
class PushWorkspace < Workspaces
+ category "IRB"
+ description "Push an object to the workspace stack."
+
def execute(*obj)
irb_context.push_workspace(*obj)
super
@@ -31,6 +37,9 @@ module IRB
end
class PopWorkspace < Workspaces
+ category "IRB"
+ description "Pop a workspace from the workspace stack."
+
def execute(*obj)
irb_context.pop_workspace(*obj)
super
diff --git a/lib/irb/cmd/show_cmds.rb b/lib/irb/cmd/show_cmds.rb
new file mode 100644
index 0000000000..acced27d48
--- /dev/null
+++ b/lib/irb/cmd/show_cmds.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "stringio"
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class ShowCmds < Nop
+ category "IRB"
+ description "List all available commands and their description."
+
+ def execute(*args)
+ commands_info = IRB::ExtendCommandBundle.all_commands_info
+ commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
+ longest_cmd_name_length = commands_info.map { |c| c[:display_name] }.max { |a, b| a.length <=> b.length }.length
+
+ output = StringIO.new
+
+ commands_grouped_by_categories.each do |category, cmds|
+ output.puts Color.colorize(category, [:BOLD])
+
+ cmds.each do |cmd|
+ output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
+ end
+
+ output.puts
+ end
+
+ puts output.string
+
+ nil
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/show_source.rb b/lib/irb/cmd/show_source.rb
index 03c21b78c7..b68aa257c2 100644
--- a/lib/irb/cmd/show_source.rb
+++ b/lib/irb/cmd/show_source.rb
@@ -9,6 +9,9 @@ module IRB
module ExtendCommand
class ShowSource < Nop
+ category "Context"
+ description "Show the source code of a given method or constant."
+
class << self
def transform_args(args)
# Return a string literal as is for backward compatibility
diff --git a/lib/irb/cmd/step.rb b/lib/irb/cmd/step.rb
index dbd59806f8..d3d0f16291 100644
--- a/lib/irb/cmd/step.rb
+++ b/lib/irb/cmd/step.rb
@@ -6,7 +6,7 @@ module IRB
# :stopdoc:
module ExtendCommand
- class Step < Debug
+ class Step < DebugCommand
def execute(*args)
# Run `next` first to move out of binding.irb
super(pre_cmds: "next", do_cmds: ["step", *args].join(" "))
diff --git a/lib/irb/cmd/subirb.rb b/lib/irb/cmd/subirb.rb
index 4d113c5bd7..43364f1393 100644
--- a/lib/irb/cmd/subirb.rb
+++ b/lib/irb/cmd/subirb.rb
@@ -30,24 +30,36 @@ module IRB
end
class IrbCommand < MultiIRBCommand
+ category "IRB"
+ description "Start a child IRB."
+
def execute(*obj)
IRB.irb(nil, *obj)
end
end
class Jobs < MultiIRBCommand
+ category "IRB"
+ description "List of current sessions."
+
def execute
IRB.JobManager
end
end
class Foreground < MultiIRBCommand
+ category "IRB"
+ description "Switches to the session of the given number."
+
def execute(key)
IRB.JobManager.switch(key)
end
end
class Kill < MultiIRBCommand
+ category "IRB"
+ description "Kills the session with the given number."
+
def execute(*keys)
IRB.JobManager.kill(*keys)
end
diff --git a/lib/irb/cmd/whereami.rb b/lib/irb/cmd/whereami.rb
index b8c7e047fa..8f56ba073d 100644
--- a/lib/irb/cmd/whereami.rb
+++ b/lib/irb/cmd/whereami.rb
@@ -7,6 +7,9 @@ module IRB
module ExtendCommand
class Whereami < Nop
+ category "Context"
+ description "Show the source code around binding.irb again."
+
def execute(*)
code = irb_context.workspace.code_around_binding
if code
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
index 802c9aa6dc..9fa2ce5d86 100644
--- a/lib/irb/extend-command.rb
+++ b/lib/irb/extend-command.rb
@@ -45,14 +45,15 @@ module IRB # :nodoc:
[:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
]
+
@EXTEND_COMMANDS = [
[
:irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
+ [:cwws, NO_OVERRIDE],
+ [:pwws, NO_OVERRIDE],
[:irb_print_working_workspace, OVERRIDE_ALL],
[:irb_cwws, OVERRIDE_ALL],
[:irb_pwws, OVERRIDE_ALL],
- [:cwws, NO_OVERRIDE],
- [:pwws, NO_OVERRIDE],
[:irb_current_working_binding, OVERRIDE_ALL],
[:irb_print_working_binding, OVERRIDE_ALL],
[:irb_cwb, OVERRIDE_ALL],
@@ -60,10 +61,10 @@ module IRB # :nodoc:
],
[
:irb_change_workspace, :ChangeWorkspace, "cmd/chws",
- [:irb_chws, OVERRIDE_ALL],
- [:irb_cws, OVERRIDE_ALL],
[:chws, NO_OVERRIDE],
[:cws, NO_OVERRIDE],
+ [:irb_chws, OVERRIDE_ALL],
+ [:irb_cws, OVERRIDE_ALL],
[:irb_change_binding, OVERRIDE_ALL],
[:irb_cb, OVERRIDE_ALL],
[:cb, NO_OVERRIDE],
@@ -77,16 +78,16 @@ module IRB # :nodoc:
],
[
:irb_push_workspace, :PushWorkspace, "cmd/pushws",
- [:irb_pushws, OVERRIDE_ALL],
[:pushws, NO_OVERRIDE],
+ [:irb_pushws, OVERRIDE_ALL],
[:irb_push_binding, OVERRIDE_ALL],
[:irb_pushb, OVERRIDE_ALL],
[:pushb, NO_OVERRIDE],
],
[
:irb_pop_workspace, :PopWorkspace, "cmd/pushws",
- [:irb_popws, OVERRIDE_ALL],
[:popws, NO_OVERRIDE],
+ [:irb_popws, OVERRIDE_ALL],
[:irb_pop_binding, OVERRIDE_ALL],
[:irb_popb, OVERRIDE_ALL],
[:popb, NO_OVERRIDE],
@@ -131,7 +132,7 @@ module IRB # :nodoc:
:irb_catch, :Catch, "cmd/catch",
],
[
- :irb_next, :Next, "cmd/next",
+ :irb_next, :Next, "cmd/next"
],
[
:irb_delete, :Delete, "cmd/delete",
@@ -187,9 +188,41 @@ module IRB # :nodoc:
:irb_whereami, :Whereami, "cmd/whereami",
[:whereami, NO_OVERRIDE],
],
-
+ [
+ :irb_show_cmds, :ShowCmds, "cmd/show_cmds",
+ [:show_cmds, NO_OVERRIDE],
+ ]
]
+
+ @@commands = []
+
+ def self.all_commands_info
+ return @@commands unless @@commands.empty?
+ user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
+ result[target] ||= []
+ result[target] << alias_name
+ end
+
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
+ require_relative load_file
+ end
+
+ klass = ExtendCommand.const_get(cmd_class, false)
+ aliases = aliases.map { |a| a.first }
+
+ if additional_aliases = user_aliases[cmd_name]
+ aliases += additional_aliases
+ end
+
+ display_name = aliases.shift || cmd_name
+ @@commands << { display_name: display_name, description: klass.description, category: klass.category }
+ end
+
+ @@commands
+ end
+
# Convert a command name to its implementation class if such command exists
def self.load_command(command)
command = command.to_sym
diff --git a/test/irb/test_cmd.rb b/test/irb/test_cmd.rb
index db48e1f1ae..ac0c115339 100644
--- a/test/irb/test_cmd.rb
+++ b/test/irb/test_cmd.rb
@@ -583,6 +583,16 @@ module TestIRB
$bar = nil
end
+ def test_show_cmds
+ out, err = execute_lines(
+ "show_cmds\n"
+ )
+
+ assert_empty err
+ assert_match(/List all available commands and their description/, out)
+ assert_match(/Start the debugger of debug\.gem/, out)
+ end
+
class EditTest < CommandTestCase
def setup
@original_editor = ENV["EDITOR"]