Skip to content

Commit bc1b1d8

Browse files
committed
Evaluate each toplevel statement
1 parent e95df06 commit bc1b1d8

File tree

3 files changed

+151
-22
lines changed

3 files changed

+151
-22
lines changed

lib/irb/input-method.rb

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,7 @@ def gets
316316
Reline.output = @stdout
317317
Reline.prompt_proc = @prompt_proc
318318
Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
319-
320-
l = readmultiline(@prompt, false) do |line|
321-
next false if Reline::IOGate.in_pasting?
322-
@check_termination_proc.call(line)
323-
end
324-
325-
if l
319+
if l = readmultiline(@prompt, false, &@check_termination_proc)
326320
HISTORY.push(l) if !l.empty?
327321
@line[@line_no += 1] = l + "\n"
328322
else

lib/irb/ruby-lex.rb

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,26 @@ def set_input(io, p = nil, &block)
4747
@io = io
4848
if @io.respond_to?(:check_termination)
4949
@io.check_termination do |code|
50-
code.gsub!(/\s*\z/, '').concat("\n")
51-
ltype, indent, continue, code_block_open = check_state(code)
52-
if ltype or indent > 0 or continue or code_block_open
53-
false
50+
if Reline::IOGate.in_pasting?
51+
lex = RubyLex.new
52+
rest = lex.check_termination_in_prev_line(code)
53+
if rest
54+
Reline.delete_text
55+
rest.bytes.reverse_each do |c|
56+
Reline.ungetc(c)
57+
end
58+
true
59+
else
60+
false
61+
end
5462
else
55-
true
63+
code.gsub!(/\s*\z/, '').concat("\n")
64+
ltype, indent, continue, code_block_open = check_state(code)
65+
if ltype or indent > 0 or continue or code_block_open
66+
false
67+
else
68+
true
69+
end
5670
end
5771
end
5872
end
@@ -739,5 +753,50 @@ def process_literal_type(tokens = @tokens)
739753
nil
740754
end
741755
end
756+
757+
def check_termination_in_prev_line(code)
758+
tokens = self.class.ripper_lex_without_warning(code)
759+
past_first_newline = false
760+
index = tokens.rindex do |t|
761+
# traverse first token before last line
762+
if past_first_newline
763+
if t.tok.include?("\n")
764+
true
765+
end
766+
elsif t.tok.include?("\n")
767+
past_first_newline = true
768+
false
769+
else
770+
false
771+
end
772+
end
773+
if index
774+
first_token = nil
775+
last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
776+
last_line_tokens.each do |t|
777+
unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
778+
first_token = t
779+
break
780+
end
781+
end
782+
if first_token.nil?
783+
return false
784+
elsif first_token && first_token.state == Ripper::EXPR_DOT
785+
return false
786+
else
787+
tokens_without_last_line = tokens[0..index]
788+
ltype = process_literal_type(tokens_without_last_line)
789+
indent = process_nesting_level(tokens_without_last_line)
790+
continue = process_continue(tokens_without_last_line)
791+
code_block_open = check_code_block(tokens_without_last_line.map(&:tok).join(''), tokens_without_last_line)
792+
if ltype or indent > 0 or continue or code_block_open
793+
return false
794+
else
795+
return last_line_tokens.map(&:tok).join('')
796+
end
797+
end
798+
end
799+
false
800+
end
742801
end
743802
# :startdoc:

test/irb/yamatanooroti/test_rendering.rb

Lines changed: 86 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def test_multiline_paste
4949
start_terminal(25, 80, %W{ruby -I#{@pwd}/lib -I#{@pwd}/../reline/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
5050
write(<<~EOC)
5151
class A
52+
def inspect; '#<A>'; end
5253
def a; self; end
5354
def b; true; end
5455
end
@@ -63,17 +64,92 @@ def b; true; end
6364
assert_screen(<<~EOC)
6465
start IRB
6566
irb(main):001:1* class A
66-
irb(main):002:1* def a; self; end
67-
irb(main):003:1* def b; true; end
68-
irb(main):004:0> end
69-
irb(main):005:0*
70-
irb(main):006:0> a = A.new
71-
irb(main):007:0*
72-
irb(main):008:0> a
73-
irb(main):009:0> .a
74-
irb(main):010:0> .b
67+
irb(main):002:1* def inspect; '#<A>'; end
68+
irb(main):003:1* def a; self; end
69+
irb(main):004:1* def b; true; end
70+
irb(main):005:0> end
71+
=> :b
72+
irb(main):006:0>
73+
irb(main):007:0> a = A.new
74+
=> #<A>
75+
irb(main):008:0>
76+
irb(main):009:0> a
77+
irb(main):010:0> .a
78+
irb(main):011:0> .b
7579
=> true
76-
irb(main):011:0>
80+
irb(main):012:0>
81+
EOC
82+
end
83+
84+
def test_evaluate_each_toplevel_statement_by_multiline_paste
85+
write_irbrc <<~'LINES'
86+
puts 'start IRB'
87+
LINES
88+
start_terminal(40, 80, %W{ruby -I#{@pwd}/lib -I#{@pwd}/../reline/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
89+
write(<<~EOC)
90+
class A
91+
def inspect; '#<A>'; end
92+
def b; self; end
93+
def c; true; end
94+
end
95+
96+
a = A.new
97+
98+
a
99+
.b
100+
# aaa
101+
.c
102+
103+
(a)
104+
&.b()
105+
106+
107+
class A def b; self; end; def c; true; end; end;
108+
a = A.new
109+
a
110+
.b
111+
# aaa
112+
.c
113+
(a)
114+
&.b()
115+
EOC
116+
close
117+
assert_screen(<<~EOC)
118+
start IRB
119+
irb(main):001:1* class A
120+
irb(main):002:1* def inspect; '#<A>'; end
121+
irb(main):003:1* def b; self; end
122+
irb(main):004:1* def c; true; end
123+
irb(main):005:0> end
124+
=> :c
125+
irb(main):006:0>
126+
irb(main):007:0> a = A.new
127+
=> #<A>
128+
irb(main):008:0>
129+
irb(main):009:0> a
130+
irb(main):010:0> .b
131+
irb(main):011:0> # aaa
132+
irb(main):012:0> .c
133+
=> true
134+
irb(main):013:0>
135+
irb(main):014:0> (a)
136+
irb(main):015:0> &.b()
137+
=> #<A>
138+
irb(main):016:0>
139+
irb(main):017:0>
140+
irb(main):018:0> class A def b; self; end; def c; true; end; end;
141+
=> :c
142+
irb(main):019:0> a = A.new
143+
=> #<A>
144+
irb(main):020:0> a
145+
irb(main):021:0> .b
146+
irb(main):022:0> # aaa
147+
irb(main):023:0> .c
148+
=> true
149+
irb(main):024:0> (a)
150+
irb(main):025:0> &.b()
151+
=> #<A>
152+
irb(main):026:0>
77153
EOC
78154
end
79155

0 commit comments

Comments
 (0)