summaryrefslogtreecommitdiff
path: root/lib/irb/color.rb
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2019-05-31 06:03:18 +0900
committerTakashi Kokubun <takashikkbn@gmail.com>2019-05-31 06:54:00 +0900
commitcb40a21da0687b5dd3cd251c9e66bb0edf67f2b9 (patch)
treea442d7f71100bd7547bb341371cb7d51e645bb33 /lib/irb/color.rb
parent6e052817f95095217b67256aff48cedbd57717cf (diff)
Warn compile_error only when input is finished
Let's say we are in progress to write `"foo"`: ``` irb> "fo ``` at this moment, nothing is wrong. It would be just a normal way to write `"foo"`. Prior to this commit, the `fo` part was warned because of 5b64d7ac6e7cbf759b859428f125539e58bac0bd. But I think warning such a normal input is not valuable for users. However, we'd like to warn `:@1` or `@@1` which is also a syntax error. Then this commit switches the syntax highlight based on whether the input text is finished or not. When it's not finished yet, it does not warn compile_error.
Diffstat (limited to 'lib/irb/color.rb')
-rw-r--r--lib/irb/color.rb52
1 files changed, 35 insertions, 17 deletions
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index 41b559bc6b..4c83a9be25 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -98,14 +98,17 @@ module IRB # :nodoc:
"#{seq}#{text}#{clear}"
end
- def colorize_code(code)
+ # If `complete` is false (code is incomplete), this does not warm compile_error.
+ # This option is needed to avoid warning a user when the compile_error is happening
+ # because the input is not wrong but just incomplete.
+ def colorize_code(code, complete: true)
return code unless colorable?
symbol_state = SymbolState.new
colored = +''
length = 0
- scan(code) do |token, str, expr|
+ scan(code, detect_compile_error: complete) do |token, str, expr|
in_symbol = symbol_state.scan_token(token)
str.each_line do |line|
line = Reline::Unicode.escape_for_print(line)
@@ -127,23 +130,29 @@ module IRB # :nodoc:
private
- def scan(code)
- pos = [1, 0]
-
- Ripper::Lexer.new(code).scan.each do |elem|
- str = elem.tok
- next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0
-
- str.each_line do |line|
- if line.end_with?("\n")
- pos[0] += 1
- pos[1] = 0
- else
- pos[1] += line.bytesize
+ def scan(code, detect_compile_error:)
+ if detect_compile_error
+ pos = [1, 0]
+
+ Ripper::Lexer.new(code).scan.each do |elem|
+ str = elem.tok
+ next if ([elem.pos[0], elem.pos[1] + str.bytesize] <=> pos) <= 0
+
+ str.each_line do |line|
+ if line.end_with?("\n")
+ pos[0] += 1
+ pos[1] = 0
+ else
+ pos[1] += line.bytesize
+ end
end
- end
- yield(elem.event, str, elem.state)
+ yield(elem.event, str, elem.state)
+ end
+ else
+ ParseErrorLexer.new(code).parse.sort_by(&:pos).each do |elem|
+ yield(elem.event, elem.tok, elem.state)
+ end
end
end
@@ -162,6 +171,15 @@ module IRB # :nodoc:
end
end
+ class ParseErrorLexer < Ripper::Lexer
+ if method_defined?(:token)
+ def on_parse_error(mesg)
+ @buf.push Elem.new([lineno(), column()], __callee__, token(), state())
+ end
+ end
+ end
+ private_constant :ParseErrorLexer
+
# A class to manage a state to know whether the current token is for Symbol or not.
class SymbolState
def initialize