Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluate each toplevel statement #220

Merged
merged 1 commit into from
Apr 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions lib/irb/input-method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,7 @@ def gets
Reline.output = @stdout
Reline.prompt_proc = @prompt_proc
Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc

l = readmultiline(@prompt, false) do |line|
next false if Reline::IOGate.in_pasting?
@check_termination_proc.call(line)
end

if l
if l = readmultiline(@prompt, false, &@check_termination_proc)
HISTORY.push(l) if !l.empty?
@line[@line_no += 1] = l + "\n"
else
Expand Down
69 changes: 64 additions & 5 deletions lib/irb/ruby-lex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,26 @@ def set_input(io, p = nil, &block)
@io = io
if @io.respond_to?(:check_termination)
@io.check_termination do |code|
code.gsub!(/\s*\z/, '').concat("\n")
ltype, indent, continue, code_block_open = check_state(code)
if ltype or indent > 0 or continue or code_block_open
false
if Reline::IOGate.in_pasting?
lex = RubyLex.new
rest = lex.check_termination_in_prev_line(code)
if rest
Reline.delete_text
rest.bytes.reverse_each do |c|
Reline.ungetc(c)
end
true
else
false
end
else
true
code.gsub!(/\s*\z/, '').concat("\n")
ltype, indent, continue, code_block_open = check_state(code)
if ltype or indent > 0 or continue or code_block_open
false
else
true
end
end
end
end
Expand Down Expand Up @@ -739,5 +753,50 @@ def process_literal_type(tokens = @tokens)
nil
end
end

def check_termination_in_prev_line(code)
tokens = self.class.ripper_lex_without_warning(code)
past_first_newline = false
index = tokens.rindex do |t|
# traverse first token before last line
if past_first_newline
if t.tok.include?("\n")
true
end
elsif t.tok.include?("\n")
past_first_newline = true
false
else
false
end
end
if index
first_token = nil
last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
last_line_tokens.each do |t|
unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
first_token = t
break
end
end
if first_token.nil?
return false
elsif first_token && first_token.state == Ripper::EXPR_DOT
return false
else
tokens_without_last_line = tokens[0..index]
ltype = process_literal_type(tokens_without_last_line)
indent = process_nesting_level(tokens_without_last_line)
continue = process_continue(tokens_without_last_line)
code_block_open = check_code_block(tokens_without_last_line.map(&:tok).join(''), tokens_without_last_line)
if ltype or indent > 0 or continue or code_block_open
return false
else
return last_line_tokens.map(&:tok).join('')
end
end
end
false
end
end
# :startdoc:
96 changes: 86 additions & 10 deletions test/irb/yamatanooroti/test_rendering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def test_multiline_paste
start_terminal(25, 80, %W{ruby -I#{@pwd}/lib -I#{@pwd}/../reline/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
write(<<~EOC)
class A
def inspect; '#<A>'; end
def a; self; end
def b; true; end
end
Expand All @@ -63,17 +64,92 @@ def b; true; end
assert_screen(<<~EOC)
start IRB
irb(main):001:1* class A
irb(main):002:1* def a; self; end
irb(main):003:1* def b; true; end
irb(main):004:0> end
irb(main):005:0*
irb(main):006:0> a = A.new
irb(main):007:0*
irb(main):008:0> a
irb(main):009:0> .a
irb(main):010:0> .b
irb(main):002:1* def inspect; '#<A>'; end
irb(main):003:1* def a; self; end
irb(main):004:1* def b; true; end
irb(main):005:0> end
=> :b
irb(main):006:0>
irb(main):007:0> a = A.new
=> #<A>
irb(main):008:0>
irb(main):009:0> a
irb(main):010:0> .a
irb(main):011:0> .b
=> true
irb(main):011:0>
irb(main):012:0>
EOC
end

def test_evaluate_each_toplevel_statement_by_multiline_paste
write_irbrc <<~'LINES'
puts 'start IRB'
LINES
start_terminal(40, 80, %W{ruby -I#{@pwd}/lib -I#{@pwd}/../reline/lib #{@pwd}/exe/irb}, startup_message: 'start IRB')
write(<<~EOC)
class A
def inspect; '#<A>'; end
def b; self; end
def c; true; end
end

a = A.new

a
.b
# aaa
.c

(a)
&.b()


class A def b; self; end; def c; true; end; end;
a = A.new
a
.b
# aaa
.c
(a)
&.b()
EOC
close
assert_screen(<<~EOC)
start IRB
irb(main):001:1* class A
irb(main):002:1* def inspect; '#<A>'; end
irb(main):003:1* def b; self; end
irb(main):004:1* def c; true; end
irb(main):005:0> end
=> :c
irb(main):006:0>
irb(main):007:0> a = A.new
=> #<A>
irb(main):008:0>
irb(main):009:0> a
irb(main):010:0> .b
irb(main):011:0> # aaa
irb(main):012:0> .c
=> true
irb(main):013:0>
irb(main):014:0> (a)
irb(main):015:0> &.b()
=> #<A>
irb(main):016:0>
irb(main):017:0>
irb(main):018:0> class A def b; self; end; def c; true; end; end;
=> :c
irb(main):019:0> a = A.new
=> #<A>
irb(main):020:0> a
irb(main):021:0> .b
irb(main):022:0> # aaa
irb(main):023:0> .c
=> true
irb(main):024:0> (a)
irb(main):025:0> &.b()
=> #<A>
irb(main):026:0>
EOC
end

Expand Down