diff options
author | Takashi Kokubun <takashikkbn@gmail.com> | 2019-05-31 06:03:18 +0900 |
---|---|---|
committer | Takashi Kokubun <takashikkbn@gmail.com> | 2019-05-31 06:54:00 +0900 |
commit | cb40a21da0687b5dd3cd251c9e66bb0edf67f2b9 (patch) | |
tree | a442d7f71100bd7547bb341371cb7d51e645bb33 /lib/irb/color.rb | |
parent | 6e052817f95095217b67256aff48cedbd57717cf (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.rb | 52 |
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 |