Skip to content

Commit

Permalink
Improve command input recognition
Browse files Browse the repository at this point in the history
Currently, we simply split the input on whitespace and use the first
word as the command name to check if it's a command. But this means that
assigning a local variable which's name is the same as a command will
also be recognized as a command.

For example, in the following case, `info` is recognized as a command:

```
irb(main):001> info = 123
`debug` command is only available when IRB is started with binding.irb
=> nil
```

This commit improves the command input recognition by using more sophis-
ticated regular expressions.
  • Loading branch information
st0012 committed Dec 7, 2023
1 parent a1e431b commit 691fcb7
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
31 changes: 25 additions & 6 deletions lib/irb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -595,13 +595,30 @@ def each_top_level_statement
end
end

SIMPLE_COMMAND_REGEXP = /^(?<cmd_name>\S+)$/
COMMAND_WITH_ARGS_REGEXP = /^(?<cmd_name>\S+) +(?<cmd_arg>[^-]\S*)$/
COMMAND_WITH_FLAGS_REGEXP = /^(?<cmd_name>\S+) +(?<cmd_flag>-\S+( +\S+)*)$/
COMMAND_WITH_ARGS_AND_FLAGS_REGEXP = /^(?<cmd_name>\S+) +(?<cmd_arg>[^-]\S*) +(?<cmd_flag>-\S+( +\S+)*)$/

COMMAND_REGEXP = Regexp.union(
SIMPLE_COMMAND_REGEXP,
COMMAND_WITH_ARGS_REGEXP,
COMMAND_WITH_FLAGS_REGEXP,
COMMAND_WITH_ARGS_AND_FLAGS_REGEXP
)

def build_statement(code)
code.force_encoding(@context.io.encoding)
command_or_alias, arg = code.split(/\s/, 2)
# Transform a non-identifier alias (@, $) or keywords (next, break)
command_name = @context.command_aliases[command_or_alias.to_sym]
command = command_name || command_or_alias
command_class = ExtendCommandBundle.load_command(command)
command_match = COMMAND_REGEXP.match(code.strip)

if command_match
command_or_alias = command_match[:cmd_name]
arg = [command_match[:cmd_arg], command_match[:cmd_flag]].compact.join(' ')
# Transform a non-identifier alias (@, $) or keywords (next, break)
command_name = @context.command_aliases[command_or_alias.to_sym]
command = command_name || command_or_alias
command_class = ExtendCommandBundle.load_command(command)
end

if command_class
Statement::Command.new(code, command, arg, command_class)
Expand All @@ -612,7 +629,9 @@ def build_statement(code)
end

def single_line_command?(code)
command = code.split(/\s/, 2).first
command_match = COMMAND_REGEXP.match(code)
return unless command_match
command = command_match[:cmd_name]
@context.symbol_alias?(command) || @context.transform_args?(command)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/irb/cmd/ls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Ls < Nop
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/)
if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\z/)
args = match[:args]
"#{args}#{',' unless args.chomp.empty?} grep: /#{match[:grep]}/"
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
require_relative "helper"

module TestIRB
class DebugCommandTest < IntegrationTestCase
class DebugIntegrationTest < IntegrationTestCase
def setup
super

Expand Down Expand Up @@ -434,5 +434,22 @@ def test_multi_irb_commands_are_not_available_after_activating_the_debugger
assert_match(/irb\(main\):001> next/, output)
assert_include(output, "Multi-IRB commands are not available when the debugger is enabled.")
end

def test_locals_assignment_not_being_treated_as_debugging_command
write_ruby <<~'ruby'
binding.irb
ruby

output = run_ruby_file do
type "info = 4"
type "info + 1"
type "quit"
end

assert_match(/=> 5/, output)
# Since neither `info = <val>` nor `info + <val>` are debugging commands, debugger should not be activated in this
# session.
assert_not_match(/irb:rdbg/, output)
end
end
end

0 comments on commit 691fcb7

Please sign in to comment.