summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/irb.rb6
-rw-r--r--lib/irb/cmd/backtrace.rb21
-rw-r--r--lib/irb/cmd/break.rb21
-rw-r--r--lib/irb/cmd/catch.rb21
-rw-r--r--lib/irb/cmd/continue.rb17
-rw-r--r--lib/irb/cmd/debug.rb12
-rw-r--r--lib/irb/cmd/delete.rb17
-rw-r--r--lib/irb/cmd/finish.rb17
-rw-r--r--lib/irb/cmd/info.rb31
-rw-r--r--lib/irb/cmd/irb_info.rb34
-rw-r--r--lib/irb/cmd/next.rb17
-rw-r--r--lib/irb/cmd/step.rb18
-rw-r--r--lib/irb/context.rb16
-rw-r--r--lib/irb/extend-command.rb37
-rw-r--r--lib/irb/init.rb5
-rw-r--r--lib/irb/ruby-lex.rb4
16 files changed, 258 insertions, 36 deletions
diff --git a/lib/irb.rb b/lib/irb.rb
index 0a856d3929..2db99bcd43 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -96,6 +96,8 @@ require_relative "irb/easter-egg"
# * Show the source code around binding.irb again.
# * debug
# * Start the debugger of debug.gem.
+# * break, delete, next, step, continue, finish, backtrace, info, catch
+# * Start the debugger of debug.gem and run the command on it.
#
# == Configuration
#
@@ -470,10 +472,6 @@ module IRB
def initialize(workspace = nil, input_method = nil)
@context = Context.new(self, workspace, input_method)
@context.main.extend ExtendCommandBundle
- @context.command_aliases.each do |alias_name, cmd_name|
- next if @context.symbol_alias(alias_name)
- @context.main.install_alias_method(alias_name, cmd_name)
- end
@signal_status = :IN_IRB
@scanner = RubyLex.new
end
diff --git a/lib/irb/cmd/backtrace.rb b/lib/irb/cmd/backtrace.rb
new file mode 100644
index 0000000000..ac4f0e0e7e
--- /dev/null
+++ b/lib/irb/cmd/backtrace.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Backtrace < Debug
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["backtrace", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/break.rb b/lib/irb/cmd/break.rb
new file mode 100644
index 0000000000..2c82413f6a
--- /dev/null
+++ b/lib/irb/cmd/break.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Break < Debug
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(args = nil)
+ super(pre_cmds: "break #{args}")
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/catch.rb b/lib/irb/cmd/catch.rb
new file mode 100644
index 0000000000..8c9e086a9c
--- /dev/null
+++ b/lib/irb/cmd/catch.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Catch < Debug
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["catch", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/continue.rb b/lib/irb/cmd/continue.rb
new file mode 100644
index 0000000000..94696e4b6c
--- /dev/null
+++ b/lib/irb/cmd/continue.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Continue < Debug
+ def execute(*args)
+ super(do_cmds: ["continue", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/debug.rb b/lib/irb/cmd/debug.rb
index d43e060c67..9e2c096107 100644
--- a/lib/irb/cmd/debug.rb
+++ b/lib/irb/cmd/debug.rb
@@ -11,7 +11,7 @@ module IRB
].map { |file| /\A#{Regexp.escape(file)}:\d+:in `irb'\z/ }
IRB_DIR = File.expand_path('..', __dir__)
- def execute(*args)
+ def execute(pre_cmds: nil, do_cmds: nil)
unless binding_irb?
puts "`debug` command is only available when IRB is started with binding.irb"
return
@@ -25,11 +25,19 @@ module IRB
return
end
+ options = { oneshot: true, hook_call: false }
+ if pre_cmds || do_cmds
+ options[:command] = ['irb', pre_cmds, do_cmds]
+ end
+ if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
+ options[:skip_src] = true
+ end
+
# To make debugger commands like `next` or `continue` work without asking
# the user to quit IRB after that, we need to exit IRB first and then hit
# a TracePoint on #debug_break.
file, lineno = IRB::Irb.instance_method(:debug_break).source_location
- DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, oneshot: true, hook_call: false)
+ DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
# exit current Irb#run call
throw :IRB_EXIT
end
diff --git a/lib/irb/cmd/delete.rb b/lib/irb/cmd/delete.rb
new file mode 100644
index 0000000000..3810ae414e
--- /dev/null
+++ b/lib/irb/cmd/delete.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Delete < Debug
+ def execute(*args)
+ super(pre_cmds: ["delete", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/finish.rb b/lib/irb/cmd/finish.rb
new file mode 100644
index 0000000000..de4b4f12cf
--- /dev/null
+++ b/lib/irb/cmd/finish.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Finish < Debug
+ def execute(*args)
+ super(do_cmds: ["finish", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/info.rb b/lib/irb/cmd/info.rb
index 37ecd762ff..413c286429 100644
--- a/lib/irb/cmd/info.rb
+++ b/lib/irb/cmd/info.rb
@@ -1,31 +1,18 @@
-# frozen_string_literal: false
+# frozen_string_literal: true
-require_relative "nop"
+require_relative "debug"
module IRB
# :stopdoc:
module ExtendCommand
- class Info < Nop
- def execute
- Class.new {
- def inspect
- str = "Ruby version: #{RUBY_VERSION}\n"
- str += "IRB version: #{IRB.version}\n"
- str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
- str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
- str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
- str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
- str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
- str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
- str += "Code page: #{codepage}\n"
- end
- str
- end
- alias_method :to_s, :inspect
- }.new
+ class Info < Debug
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["info", *args].join(" "))
end
end
end
diff --git a/lib/irb/cmd/irb_info.rb b/lib/irb/cmd/irb_info.rb
new file mode 100644
index 0000000000..8a4e1bd603
--- /dev/null
+++ b/lib/irb/cmd/irb_info.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: false
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class IrbInfo < Nop
+ def execute
+ Class.new {
+ def inspect
+ str = "Ruby version: #{RUBY_VERSION}\n"
+ str += "IRB version: #{IRB.version}\n"
+ str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
+ str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
+ str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
+ str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
+ str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
+ str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
+ codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
+ str += "Code page: #{codepage}\n"
+ end
+ str
+ end
+ alias_method :to_s, :inspect
+ }.new
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/next.rb b/lib/irb/cmd/next.rb
new file mode 100644
index 0000000000..2943a753fb
--- /dev/null
+++ b/lib/irb/cmd/next.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Next < Debug
+ def execute(*args)
+ super(do_cmds: ["next", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/step.rb b/lib/irb/cmd/step.rb
new file mode 100644
index 0000000000..dbd59806f8
--- /dev/null
+++ b/lib/irb/cmd/step.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Step < Debug
+ def execute(*args)
+ # Run `next` first to move out of binding.irb
+ super(pre_cmds: "next", do_cmds: ["step", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index c5d98772b8..91fbb2fcf1 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -486,9 +486,9 @@ module IRB
@workspace.local_variable_set(:_, exception)
end
- # Transform a non-identifier alias (ex: @, $)
+ # Transform a non-identifier alias (@, $) or keywords (next, break)
command, args = line.split(/\s/, 2)
- if original = symbol_alias(command)
+ if original = command_aliases[command.to_sym]
line = line.gsub(/\A#{Regexp.escape(command)}/, original.to_s)
command = original
end
@@ -545,10 +545,16 @@ module IRB
workspace.binding.local_variables
end
- # Return a command name if it's aliased from the argument and it's not an identifier.
- def symbol_alias(command)
+ # Return true if it's aliased from the argument and it's not an identifier.
+ def symbol_alias?(command)
return nil if command.match?(/\A\w+\z/)
- command_aliases[command.to_sym]
+ command_aliases.key?(command.to_sym)
+ end
+
+ # Return true if the command supports transforming args
+ def transform_args?(command)
+ command = command_aliases.fetch(command.to_sym, command)
+ ExtendCommandBundle.load_command(command)&.respond_to?(:transform_args)
end
end
end
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
index 7e120cf510..802c9aa6dc 100644
--- a/lib/irb/extend-command.rb
+++ b/lib/irb/extend-command.rb
@@ -125,12 +125,47 @@ module IRB # :nodoc:
[:edit, NO_OVERRIDE],
],
[
+ :irb_break, :Break, "cmd/break",
+ ],
+ [
+ :irb_catch, :Catch, "cmd/catch",
+ ],
+ [
+ :irb_next, :Next, "cmd/next",
+ ],
+ [
+ :irb_delete, :Delete, "cmd/delete",
+ [:delete, NO_OVERRIDE],
+ ],
+ [
+ :irb_step, :Step, "cmd/step",
+ [:step, NO_OVERRIDE],
+ ],
+ [
+ :irb_continue, :Continue, "cmd/continue",
+ [:continue, NO_OVERRIDE],
+ ],
+ [
+ :irb_finish, :Finish, "cmd/finish",
+ [:finish, NO_OVERRIDE],
+ ],
+ [
+ :irb_backtrace, :Backtrace, "cmd/backtrace",
+ [:backtrace, NO_OVERRIDE],
+ [:bt, NO_OVERRIDE],
+ ],
+ [
+ :irb_debug_info, :Info, "cmd/info",
+ [:info, NO_OVERRIDE],
+ ],
+
+ [
:irb_help, :Help, "cmd/help",
[:help, NO_OVERRIDE],
],
[
- :irb_info, :Info, "cmd/info"
+ :irb_info, :IrbInfo, "cmd/irb_info"
],
[
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index 831d7d811a..dd888f3727 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -160,8 +160,13 @@ module IRB # :nodoc:
@CONF[:AT_EXIT] = []
@CONF[:COMMAND_ALIASES] = {
+ # Symbol aliases
:'$' => :show_source,
:'@' => :whereami,
+ # Keyword aliases
+ :break => :irb_break,
+ :catch => :irb_catch,
+ :next => :irb_next,
}
end
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index 28029bbf4c..85b336fbe1 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -65,9 +65,9 @@ class RubyLex
false
end
else
- # Accept any single-line input starting with a non-identifier alias (ex: @, $)
+ # Accept any single-line input for symbol aliases or commands that transform args
command = code.split(/\s/, 2).first
- if context.symbol_alias(command)
+ if context.symbol_alias?(command) || context.transform_args?(command)
next true
end