Skip to content

Commit 0e9db41

Browse files
authored
Support repeating debugger input by passing empty input to it (#856)
* Test IRB's behaviour with empty input * Handle empty input and pass it to debugger Since `rdbg` accepts empty input to repeat the previous command, IRB should take empty input in `irb:rdbg` sessions and pass them to the debugger. Currently, IRB simply ignores empty input and does nothing. This commit creates `EmptyInput` to represent empty input so it can fit into the current IRB's input processing flow in `Irb#eval_input`.
1 parent ebffd3d commit 0e9db41

4 files changed

Lines changed: 71 additions & 5 deletions

File tree

‎lib/irb.rb‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,16 +1082,17 @@ def each_top_level_statement
10821082
loop do
10831083
code = readmultiline
10841084
break unless code
1085-
1086-
if code != "\n"
1087-
yield build_statement(code), @line_no
1088-
end
1085+
yield build_statement(code), @line_no
10891086
@line_no += code.count("\n")
10901087
rescue RubyLex::TerminateLineInput
10911088
end
10921089
end
10931090

10941091
def build_statement(code)
1092+
if code.match?(/\A\n*\z/)
1093+
return Statement::EmptyInput.new
1094+
end
1095+
10951096
code.force_encoding(@context.io.encoding)
10961097
command_or_alias, arg = code.split(/\s/, 2)
10971098
# Transform a non-identifier alias (@, $) or keywords (next, break)

‎lib/irb/statement.rb‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,29 @@ def evaluable_code
2020
raise NotImplementedError
2121
end
2222

23+
class EmptyInput < Statement
24+
def is_assignment?
25+
false
26+
end
27+
28+
def suppresses_echo?
29+
true
30+
end
31+
32+
# Debugger takes empty input to repeat the last command
33+
def should_be_handled_by_debugger?
34+
true
35+
end
36+
37+
def code
38+
""
39+
end
40+
41+
def evaluable_code
42+
code
43+
end
44+
end
45+
2346
class Expression < Statement
2447
def initialize(code, is_assignment)
2548
@code = code
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
require_relative "helper"
77

88
module TestIRB
9-
class DebugCommandTest < IntegrationTestCase
9+
class DebuggerIntegrationTest < IntegrationTestCase
1010
def setup
1111
super
1212

@@ -434,5 +434,29 @@ def test_multi_irb_commands_are_not_available_after_activating_the_debugger
434434
assert_match(/irb\(main\):001> next/, output)
435435
assert_include(output, "Multi-IRB commands are not available when the debugger is enabled.")
436436
end
437+
438+
def test_irb_passes_empty_input_to_debugger_to_repeat_the_last_command
439+
write_ruby <<~'ruby'
440+
binding.irb
441+
puts "foo"
442+
puts "bar"
443+
puts "baz"
444+
ruby
445+
446+
output = run_ruby_file do
447+
type "next"
448+
type ""
449+
# Test that empty input doesn't repeat expressions
450+
type "123"
451+
type ""
452+
type "next"
453+
type ""
454+
type ""
455+
end
456+
457+
assert_include(output, "=> 2\| puts \"foo\"")
458+
assert_include(output, "=> 3\| puts \"bar\"")
459+
assert_include(output, "=> 4\| puts \"baz\"")
460+
end
437461
end
438462
end

‎test/irb/test_irb.rb‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ def test_symbol_aliases_dont_affect_ruby_syntax
5858
assert_include output, "=> \"It's a foo\""
5959
assert_include output, "=> \"It's a bar\""
6060
end
61+
62+
def test_empty_input_echoing_behaviour
63+
write_ruby <<~'RUBY'
64+
binding.irb
65+
RUBY
66+
67+
output = run_ruby_file do
68+
type ""
69+
type " "
70+
type "exit"
71+
end
72+
73+
# Input cramped together due to how Reline's Reline::GeneralIO works
74+
assert_include(
75+
output,
76+
"irb(main):001> irb(main):002> irb(main):002> irb(main):002> => nil\r\n"
77+
)
78+
end
6179
end
6280

6381
class IrbIOConfigurationTest < TestCase

0 commit comments

Comments
 (0)