mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/reline] [ruby/irb] Call ripper only once when generating dynamic prompt
babb122a48
e6dbcb3b42
This commit is contained in:
parent
e76b56f58e
commit
dc61affd67
1 changed files with 46 additions and 41 deletions
|
@ -60,11 +60,19 @@ class RubyLex
|
||||||
@io.dynamic_prompt do |lines|
|
@io.dynamic_prompt do |lines|
|
||||||
lines << '' if lines.empty?
|
lines << '' if lines.empty?
|
||||||
result = []
|
result = []
|
||||||
lines.each_index { |i|
|
tokens = ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join)
|
||||||
c = lines[0..i].map{ |l| l + "\n" }.join
|
code = String.new
|
||||||
ltype, indent, continue, code_block_open = check_state(c)
|
partial_tokens = []
|
||||||
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + i)
|
line_num_offset = 0
|
||||||
}
|
tokens.each do |t|
|
||||||
|
code << t[2]
|
||||||
|
partial_tokens << t
|
||||||
|
if t[2].include?("\n")
|
||||||
|
ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
|
||||||
|
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
|
||||||
|
line_num_offset += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -88,12 +96,9 @@ class RubyLex
|
||||||
|
|
||||||
def ripper_lex_without_warning(code)
|
def ripper_lex_without_warning(code)
|
||||||
verbose, $VERBOSE = $VERBOSE, nil
|
verbose, $VERBOSE = $VERBOSE, nil
|
||||||
tokens = []
|
tokens = nil
|
||||||
self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
|
self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
|
||||||
lexer = Ripper::Lexer.new(inner_code, '-', line_no)
|
tokens = Ripper.lex(inner_code, '-', line_no)
|
||||||
until (ts = lexer.lex).empty?
|
|
||||||
tokens.concat(ts)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
$VERBOSE = verbose
|
$VERBOSE = verbose
|
||||||
tokens
|
tokens
|
||||||
|
@ -124,12 +129,12 @@ class RubyLex
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_state(code)
|
def check_state(code, tokens = nil)
|
||||||
@tokens = ripper_lex_without_warning(code)
|
tokens = ripper_lex_without_warning(code) unless tokens
|
||||||
ltype = process_literal_type
|
ltype = process_literal_type(tokens)
|
||||||
indent = process_nesting_level
|
indent = process_nesting_level(tokens)
|
||||||
continue = process_continue
|
continue = process_continue(tokens)
|
||||||
code_block_open = check_code_block(code)
|
code_block_open = check_code_block(code, tokens)
|
||||||
[ltype, indent, continue, code_block_open]
|
[ltype, indent, continue, code_block_open]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -189,36 +194,36 @@ class RubyLex
|
||||||
code = @line + (line.nil? ? '' : line)
|
code = @line + (line.nil? ? '' : line)
|
||||||
code.gsub!(/\s*\z/, '').concat("\n")
|
code.gsub!(/\s*\z/, '').concat("\n")
|
||||||
@tokens = ripper_lex_without_warning(code)
|
@tokens = ripper_lex_without_warning(code)
|
||||||
@continue = process_continue
|
@continue = process_continue(@tokens)
|
||||||
@code_block_open = check_code_block(code)
|
@code_block_open = check_code_block(code, @tokens)
|
||||||
@indent = process_nesting_level
|
@indent = process_nesting_level(@tokens)
|
||||||
@ltype = process_literal_type
|
@ltype = process_literal_type(@tokens)
|
||||||
line
|
line
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_continue
|
def process_continue(tokens)
|
||||||
# last token is always newline
|
# last token is always newline
|
||||||
if @tokens.size >= 2 and @tokens[-2][1] == :on_regexp_end
|
if tokens.size >= 2 and tokens[-2][1] == :on_regexp_end
|
||||||
# end of regexp literal
|
# end of regexp literal
|
||||||
return false
|
return false
|
||||||
elsif @tokens.size >= 2 and @tokens[-2][1] == :on_semicolon
|
elsif tokens.size >= 2 and tokens[-2][1] == :on_semicolon
|
||||||
return false
|
return false
|
||||||
elsif @tokens.size >= 2 and @tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(@tokens[-2][2])
|
elsif tokens.size >= 2 and tokens[-2][1] == :on_kw and ['begin', 'else', 'ensure'].include?(tokens[-2][2])
|
||||||
return false
|
return false
|
||||||
elsif !@tokens.empty? and @tokens.last[2] == "\\\n"
|
elsif !tokens.empty? and tokens.last[2] == "\\\n"
|
||||||
return true
|
return true
|
||||||
elsif @tokens.size >= 1 and @tokens[-1][1] == :on_heredoc_end # "EOH\n"
|
elsif tokens.size >= 1 and tokens[-1][1] == :on_heredoc_end # "EOH\n"
|
||||||
return false
|
return false
|
||||||
elsif @tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and @tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
|
elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
|
||||||
# end of literal except for regexp
|
# end of literal except for regexp
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_code_block(code)
|
def check_code_block(code, tokens)
|
||||||
return true if @tokens.empty?
|
return true if tokens.empty?
|
||||||
if @tokens.last[1] == :on_heredoc_beg
|
if tokens.last[1] == :on_heredoc_beg
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -290,7 +295,7 @@ class RubyLex
|
||||||
end
|
end
|
||||||
|
|
||||||
if defined?(Ripper::EXPR_BEG)
|
if defined?(Ripper::EXPR_BEG)
|
||||||
last_lex_state = @tokens.last[3]
|
last_lex_state = tokens.last[3]
|
||||||
if last_lex_state.allbits?(Ripper::EXPR_BEG)
|
if last_lex_state.allbits?(Ripper::EXPR_BEG)
|
||||||
return false
|
return false
|
||||||
elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
|
elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
|
||||||
|
@ -309,10 +314,10 @@ class RubyLex
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_nesting_level
|
def process_nesting_level(tokens)
|
||||||
indent = 0
|
indent = 0
|
||||||
in_oneliner_def = nil
|
in_oneliner_def = nil
|
||||||
@tokens.each_with_index { |t, index|
|
tokens.each_with_index { |t, index|
|
||||||
# detecting one-liner method definition
|
# detecting one-liner method definition
|
||||||
if in_oneliner_def.nil?
|
if in_oneliner_def.nil?
|
||||||
if t[3].allbits?(Ripper::EXPR_ENDFN)
|
if t[3].allbits?(Ripper::EXPR_ENDFN)
|
||||||
|
@ -340,10 +345,10 @@ class RubyLex
|
||||||
when :on_rbracket, :on_rbrace, :on_rparen
|
when :on_rbracket, :on_rbrace, :on_rparen
|
||||||
indent -= 1
|
indent -= 1
|
||||||
when :on_kw
|
when :on_kw
|
||||||
next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
|
next if index > 0 and tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME)
|
||||||
case t[2]
|
case t[2]
|
||||||
when 'do'
|
when 'do'
|
||||||
if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
|
if index > 0 and tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG)
|
||||||
# method_with_block do; end
|
# method_with_block do; end
|
||||||
indent += 1
|
indent += 1
|
||||||
else
|
else
|
||||||
|
@ -525,12 +530,12 @@ class RubyLex
|
||||||
corresponding_token_depth
|
corresponding_token_depth
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_string_literal
|
def check_string_literal(tokens)
|
||||||
i = 0
|
i = 0
|
||||||
start_token = []
|
start_token = []
|
||||||
end_type = []
|
end_type = []
|
||||||
while i < @tokens.size
|
while i < tokens.size
|
||||||
t = @tokens[i]
|
t = tokens[i]
|
||||||
case t[1]
|
case t[1]
|
||||||
when :on_tstring_beg
|
when :on_tstring_beg
|
||||||
start_token << t
|
start_token << t
|
||||||
|
@ -540,7 +545,7 @@ class RubyLex
|
||||||
end_type << :on_regexp_end
|
end_type << :on_regexp_end
|
||||||
when :on_symbeg
|
when :on_symbeg
|
||||||
acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
|
acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
|
||||||
if (i + 1) < @tokens.size and acceptable_single_tokens.all?{ |t| @tokens[i + 1][1] != t }
|
if (i + 1) < tokens.size and acceptable_single_tokens.all?{ |t| tokens[i + 1][1] != t }
|
||||||
start_token << t
|
start_token << t
|
||||||
end_type << :on_tstring_end
|
end_type << :on_tstring_end
|
||||||
end
|
end
|
||||||
|
@ -562,8 +567,8 @@ class RubyLex
|
||||||
start_token.last.nil? ? '' : start_token.last
|
start_token.last.nil? ? '' : start_token.last
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_literal_type
|
def process_literal_type(tokens)
|
||||||
start_token = check_string_literal
|
start_token = check_string_literal(tokens)
|
||||||
case start_token[1]
|
case start_token[1]
|
||||||
when :on_tstring_beg
|
when :on_tstring_beg
|
||||||
case start_token[2]
|
case start_token[2]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue