syntax_suggest 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/check_changelog.yml +1 -1
- data/.github/workflows/ci.yml +31 -11
- data/.standard.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +53 -35
- data/README.md +2 -2
- data/lib/syntax_suggest/api.rb +41 -6
- data/lib/syntax_suggest/clean_document.rb +6 -6
- data/lib/syntax_suggest/code_block.rb +1 -1
- data/lib/syntax_suggest/code_frontier.rb +1 -1
- data/lib/syntax_suggest/code_line.rb +12 -5
- data/lib/syntax_suggest/code_search.rb +2 -2
- data/lib/syntax_suggest/core_ext.rb +1 -1
- data/lib/syntax_suggest/display_invalid_blocks.rb +1 -1
- data/lib/syntax_suggest/explain_syntax.rb +18 -4
- data/lib/syntax_suggest/lex_all.rb +29 -10
- data/lib/syntax_suggest/pathname_from_message.rb +1 -1
- data/lib/syntax_suggest/ripper_errors.rb +4 -1
- data/lib/syntax_suggest/scan_history.rb +1 -1
- data/lib/syntax_suggest/version.rb +1 -1
- data/syntax_suggest.gemspec +2 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b3d83011e29784a7ea97dcae359b654ec8be6382c9fda7a5114353050ef5bf2
|
4
|
+
data.tar.gz: a2452866035aa4751948ac4f30cb7699352bc0778fb4b5bcae3ce3f421b901de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52168116c672ee83619f59d1f158101adb64c650770424c3bd855fafb71131f72663c8afd060f8512bbe908fae2ecb8dea5a65c9384b980843c89901f70e202a
|
7
|
+
data.tar.gz: 5edfacbb66e7b37dc36f1b57de325ffea4656102b3a4638249577fb8c12460c2e05a3f7761675966e845214db891c83f5b51eef963d35da506478af7f0837874
|
@@ -13,7 +13,7 @@ jobs:
|
|
13
13
|
!contains(github.event.pull_request.body, '[skip ci]') &&
|
14
14
|
!contains(github.event.pull_request.labels.*.name, 'skip changelog')
|
15
15
|
steps:
|
16
|
-
- uses: actions/checkout@
|
16
|
+
- uses: actions/checkout@v4.1.1
|
17
17
|
- name: Check that CHANGELOG is touched
|
18
18
|
run: |
|
19
19
|
git fetch origin ${{ github.base_ref }} --depth 1 && \
|
data/.github/workflows/ci.yml
CHANGED
@@ -9,31 +9,32 @@ jobs:
|
|
9
9
|
runs-on: ubuntu-latest
|
10
10
|
steps:
|
11
11
|
- name: Checkout code
|
12
|
-
uses: actions/checkout@
|
12
|
+
uses: actions/checkout@v4.1.1
|
13
13
|
- name: Set up Ruby
|
14
14
|
uses: ruby/setup-ruby@v1
|
15
15
|
with:
|
16
|
-
ruby-version:
|
16
|
+
ruby-version: ruby
|
17
17
|
bundler-cache: true
|
18
18
|
- name: Linting
|
19
19
|
run: bundle exec standardrb
|
20
|
+
env:
|
21
|
+
RUBYOPT: --disable=syntax_suggest
|
22
|
+
|
23
|
+
ruby-versions:
|
24
|
+
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
|
25
|
+
with:
|
26
|
+
engine: cruby
|
20
27
|
|
21
28
|
test:
|
29
|
+
needs: ruby-versions
|
22
30
|
runs-on: ubuntu-latest
|
23
31
|
strategy:
|
24
32
|
fail-fast: false
|
25
33
|
matrix:
|
26
|
-
ruby:
|
27
|
-
- 2.5
|
28
|
-
- 2.6
|
29
|
-
- 2.7
|
30
|
-
- '3.0'
|
31
|
-
- 3.1
|
32
|
-
- 3.2
|
33
|
-
- head
|
34
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
34
35
|
steps:
|
35
36
|
- name: Checkout code
|
36
|
-
uses: actions/checkout@
|
37
|
+
uses: actions/checkout@v4.1.1
|
37
38
|
- name: Set up Ruby
|
38
39
|
uses: ruby/setup-ruby@v1
|
39
40
|
with:
|
@@ -42,3 +43,22 @@ jobs:
|
|
42
43
|
- name: test
|
43
44
|
run: bin/rake test
|
44
45
|
continue-on-error: ${{ matrix.ruby == 'head' }}
|
46
|
+
|
47
|
+
test-disable-prism:
|
48
|
+
needs: ruby-versions
|
49
|
+
runs-on: ubuntu-latest
|
50
|
+
strategy:
|
51
|
+
fail-fast: false
|
52
|
+
matrix:
|
53
|
+
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
|
54
|
+
steps:
|
55
|
+
- name: Checkout code
|
56
|
+
uses: actions/checkout@v4.1.1
|
57
|
+
- name: Set up Ruby
|
58
|
+
uses: ruby/setup-ruby@v1
|
59
|
+
with:
|
60
|
+
ruby-version: ${{ matrix.ruby }}
|
61
|
+
bundler-cache: true
|
62
|
+
- name: test
|
63
|
+
run: SYNTAX_SUGGEST_DISABLE_PRISM=1 bin/rake test
|
64
|
+
continue-on-error: ${{ matrix.ruby == 'head' }}
|
data/.standard.yml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby_version:
|
1
|
+
ruby_version: 3.0.0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## HEAD (unreleased)
|
2
2
|
|
3
|
+
## 2.0.0
|
4
|
+
|
5
|
+
- Changed: No longer supports EOL versions of Ruby. (https://github.com/ruby/syntax_suggest/pull/210)
|
6
|
+
- Added: Support prism parser (https://github.com/ruby/syntax_suggest/pull/208).
|
7
|
+
- Added: Handle Ruby 3.3 new eval source location format (https://github.com/ruby/syntax_suggest/pull/200).
|
8
|
+
|
3
9
|
## 1.1.0
|
4
10
|
|
5
11
|
- Handle if/else with comment or empty line in branch (https://github.com/ruby/syntax_suggest/pull/193)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,61 +1,79 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_suggest (
|
4
|
+
syntax_suggest (2.0.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.4.2)
|
10
|
-
benchmark-ips (2.
|
11
|
-
diff-lcs (1.
|
12
|
-
|
13
|
-
|
10
|
+
benchmark-ips (2.12.0)
|
11
|
+
diff-lcs (1.5.0)
|
12
|
+
json (2.7.0)
|
13
|
+
language_server-protocol (3.17.0.3)
|
14
|
+
lint_roller (1.1.0)
|
15
|
+
parallel (1.23.0)
|
16
|
+
parser (3.2.2.4)
|
14
17
|
ast (~> 2.4.1)
|
15
|
-
|
18
|
+
racc
|
19
|
+
prism (0.18.0)
|
20
|
+
racc (1.7.3)
|
21
|
+
rainbow (3.1.1)
|
16
22
|
rake (12.3.3)
|
17
|
-
regexp_parser (2.
|
18
|
-
rexml (3.2.
|
19
|
-
rspec (3.
|
20
|
-
rspec-core (~> 3.
|
21
|
-
rspec-expectations (~> 3.
|
22
|
-
rspec-mocks (~> 3.
|
23
|
-
rspec-core (3.
|
24
|
-
rspec-support (~> 3.
|
25
|
-
rspec-expectations (3.
|
23
|
+
regexp_parser (2.8.3)
|
24
|
+
rexml (3.2.6)
|
25
|
+
rspec (3.12.0)
|
26
|
+
rspec-core (~> 3.12.0)
|
27
|
+
rspec-expectations (~> 3.12.0)
|
28
|
+
rspec-mocks (~> 3.12.0)
|
29
|
+
rspec-core (3.12.2)
|
30
|
+
rspec-support (~> 3.12.0)
|
31
|
+
rspec-expectations (3.12.3)
|
26
32
|
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
-
rspec-support (~> 3.
|
28
|
-
rspec-mocks (3.
|
33
|
+
rspec-support (~> 3.12.0)
|
34
|
+
rspec-mocks (3.12.6)
|
29
35
|
diff-lcs (>= 1.2.0, < 2.0)
|
30
|
-
rspec-support (~> 3.
|
31
|
-
rspec-support (3.
|
32
|
-
rubocop (1.
|
36
|
+
rspec-support (~> 3.12.0)
|
37
|
+
rspec-support (3.12.1)
|
38
|
+
rubocop (1.57.2)
|
39
|
+
json (~> 2.3)
|
40
|
+
language_server-protocol (>= 3.17.0)
|
33
41
|
parallel (~> 1.10)
|
34
|
-
parser (>= 3.
|
42
|
+
parser (>= 3.2.2.4)
|
35
43
|
rainbow (>= 2.2.2, < 4.0)
|
36
44
|
regexp_parser (>= 1.8, < 3.0)
|
37
|
-
rexml
|
38
|
-
rubocop-ast (>= 1.
|
45
|
+
rexml (>= 3.2.5, < 4.0)
|
46
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
39
47
|
ruby-progressbar (~> 1.7)
|
40
|
-
unicode-display_width (>=
|
41
|
-
rubocop-ast (1.
|
42
|
-
parser (>= 3.
|
43
|
-
rubocop-performance (1.
|
48
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
49
|
+
rubocop-ast (1.30.0)
|
50
|
+
parser (>= 3.2.1.0)
|
51
|
+
rubocop-performance (1.19.1)
|
44
52
|
rubocop (>= 1.7.0, < 2.0)
|
45
53
|
rubocop-ast (>= 0.4.0)
|
46
|
-
ruby-prof (1.
|
47
|
-
ruby-progressbar (1.
|
48
|
-
stackprof (0.2.
|
49
|
-
standard (1.
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
ruby-prof (1.6.3)
|
55
|
+
ruby-progressbar (1.13.0)
|
56
|
+
stackprof (0.2.25)
|
57
|
+
standard (1.32.1)
|
58
|
+
language_server-protocol (~> 3.17.0.2)
|
59
|
+
lint_roller (~> 1.0)
|
60
|
+
rubocop (~> 1.57.2)
|
61
|
+
standard-custom (~> 1.0.0)
|
62
|
+
standard-performance (~> 1.2)
|
63
|
+
standard-custom (1.0.2)
|
64
|
+
lint_roller (~> 1.0)
|
65
|
+
rubocop (~> 1.50)
|
66
|
+
standard-performance (1.2.1)
|
67
|
+
lint_roller (~> 1.1)
|
68
|
+
rubocop-performance (~> 1.19.1)
|
69
|
+
unicode-display_width (2.5.0)
|
53
70
|
|
54
71
|
PLATFORMS
|
55
72
|
ruby
|
56
73
|
|
57
74
|
DEPENDENCIES
|
58
75
|
benchmark-ips
|
76
|
+
prism
|
59
77
|
rake (~> 12.0)
|
60
78
|
rspec (~> 3.0)
|
61
79
|
ruby-prof
|
@@ -64,4 +82,4 @@ DEPENDENCIES
|
|
64
82
|
syntax_suggest!
|
65
83
|
|
66
84
|
BUNDLED WITH
|
67
|
-
2.
|
85
|
+
2.4.21
|
data/README.md
CHANGED
@@ -122,7 +122,7 @@ Unmatched `(', missing `)' ?
|
|
122
122
|
5 end
|
123
123
|
```
|
124
124
|
|
125
|
-
- Any ambiguous or unknown errors will be annotated by the original
|
125
|
+
- Any ambiguous or unknown errors will be annotated by the original parser error output:
|
126
126
|
|
127
127
|
<!--
|
128
128
|
class Dog
|
@@ -133,7 +133,7 @@ end
|
|
133
133
|
-->
|
134
134
|
|
135
135
|
```
|
136
|
-
|
136
|
+
Expected an expression after the operator
|
137
137
|
|
138
138
|
1 class Dog
|
139
139
|
2 def meals_last_month
|
data/lib/syntax_suggest/api.rb
CHANGED
@@ -5,9 +5,28 @@ require_relative "version"
|
|
5
5
|
require "tmpdir"
|
6
6
|
require "stringio"
|
7
7
|
require "pathname"
|
8
|
-
require "ripper"
|
9
8
|
require "timeout"
|
10
9
|
|
10
|
+
# We need Ripper loaded for `Prism.lex_compat` even if we're using Prism
|
11
|
+
# for lexing and parsing
|
12
|
+
require "ripper"
|
13
|
+
|
14
|
+
# Prism is the new parser, replacing Ripper
|
15
|
+
#
|
16
|
+
# We need to "dual boot" both for now because syntax_suggest
|
17
|
+
# supports older rubies that do not ship with syntax suggest.
|
18
|
+
#
|
19
|
+
# We also need the ability to control loading of this library
|
20
|
+
# so we can test that both modes work correctly in CI.
|
21
|
+
if (value = ENV["SYNTAX_SUGGEST_DISABLE_PRISM"])
|
22
|
+
warn "Skipping loading prism due to SYNTAX_SUGGEST_DISABLE_PRISM=#{value}"
|
23
|
+
else
|
24
|
+
begin
|
25
|
+
require "prism"
|
26
|
+
rescue LoadError
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
11
30
|
module SyntaxSuggest
|
12
31
|
# Used to indicate a default value that cannot
|
13
32
|
# be confused with another input.
|
@@ -16,6 +35,14 @@ module SyntaxSuggest
|
|
16
35
|
class Error < StandardError; end
|
17
36
|
TIMEOUT_DEFAULT = ENV.fetch("SYNTAX_SUGGEST_TIMEOUT", 1).to_i
|
18
37
|
|
38
|
+
# SyntaxSuggest.use_prism_parser? [Private]
|
39
|
+
#
|
40
|
+
# Tells us if the prism parser is available for use
|
41
|
+
# or if we should fallback to `Ripper`
|
42
|
+
def self.use_prism_parser?
|
43
|
+
defined?(Prism)
|
44
|
+
end
|
45
|
+
|
19
46
|
# SyntaxSuggest.handle_error [Public]
|
20
47
|
#
|
21
48
|
# Takes a `SyntaxError` exception, uses the
|
@@ -129,11 +156,20 @@ module SyntaxSuggest
|
|
129
156
|
# SyntaxSuggest.invalid? [Private]
|
130
157
|
#
|
131
158
|
# Opposite of `SyntaxSuggest.valid?`
|
132
|
-
|
133
|
-
|
134
|
-
|
159
|
+
if defined?(Prism)
|
160
|
+
def self.invalid?(source)
|
161
|
+
source = source.join if source.is_a?(Array)
|
162
|
+
source = source.to_s
|
135
163
|
|
136
|
-
|
164
|
+
Prism.parse(source).failure?
|
165
|
+
end
|
166
|
+
else
|
167
|
+
def self.invalid?(source)
|
168
|
+
source = source.join if source.is_a?(Array)
|
169
|
+
source = source.to_s
|
170
|
+
|
171
|
+
Ripper.new(source).tap(&:parse).error?
|
172
|
+
end
|
137
173
|
end
|
138
174
|
|
139
175
|
# SyntaxSuggest.valid? [Private]
|
@@ -191,7 +227,6 @@ require_relative "lex_all"
|
|
191
227
|
require_relative "code_line"
|
192
228
|
require_relative "code_block"
|
193
229
|
require_relative "block_expand"
|
194
|
-
require_relative "ripper_errors"
|
195
230
|
require_relative "priority_queue"
|
196
231
|
require_relative "unvisited_lines"
|
197
232
|
require_relative "around_block_scan"
|
@@ -47,9 +47,9 @@ module SyntaxSuggest
|
|
47
47
|
# ## Heredocs
|
48
48
|
#
|
49
49
|
# A heredoc is an way of defining a multi-line string. They can cause many
|
50
|
-
# problems. If left as a single line,
|
50
|
+
# problems. If left as a single line, the parser would try to parse the contents
|
51
51
|
# as ruby code rather than as a string. Even without this problem, we still
|
52
|
-
# hit an issue with indentation
|
52
|
+
# hit an issue with indentation:
|
53
53
|
#
|
54
54
|
# 1 foo = <<~HEREDOC
|
55
55
|
# 2 "Be yourself; everyone else is already taken.""
|
@@ -224,7 +224,7 @@ module SyntaxSuggest
|
|
224
224
|
#
|
225
225
|
def join_consecutive!
|
226
226
|
consecutive_groups = @document.select(&:ignore_newline_not_beg?).map do |code_line|
|
227
|
-
take_while_including(code_line.index
|
227
|
+
take_while_including(code_line.index..) do |line|
|
228
228
|
line.ignore_newline_not_beg?
|
229
229
|
end
|
230
230
|
end
|
@@ -245,7 +245,7 @@ module SyntaxSuggest
|
|
245
245
|
# expect(lines[1].to_s).to eq("")
|
246
246
|
def join_trailing_slash!
|
247
247
|
trailing_groups = @document.select(&:trailing_slash?).map do |code_line|
|
248
|
-
take_while_including(code_line.index
|
248
|
+
take_while_including(code_line.index..) { |x| x.trailing_slash? }
|
249
249
|
end
|
250
250
|
join_groups(trailing_groups)
|
251
251
|
self
|
@@ -279,7 +279,7 @@ module SyntaxSuggest
|
|
279
279
|
)
|
280
280
|
|
281
281
|
# Hide the rest of the lines
|
282
|
-
lines[1
|
282
|
+
lines[1..].each do |line|
|
283
283
|
# The above lines already have newlines in them, if add more
|
284
284
|
# then there will be double newline, use an empty line instead
|
285
285
|
@document[line.index] = CodeLine.new(line: "", index: line.index, lex: [])
|
@@ -293,7 +293,7 @@ module SyntaxSuggest
|
|
293
293
|
# Like `take_while` except when it stops
|
294
294
|
# iterating, it also returns the line
|
295
295
|
# that caused it to stop
|
296
|
-
def take_while_including(range = 0
|
296
|
+
def take_while_including(range = 0..)
|
297
297
|
take_next_and_stop = false
|
298
298
|
@document[range].take_while do |line|
|
299
299
|
next if take_next_and_stop
|
@@ -81,7 +81,7 @@ module SyntaxSuggest
|
|
81
81
|
# lines then the result cannot be invalid
|
82
82
|
#
|
83
83
|
# That means there's no reason to re-check all
|
84
|
-
# lines with
|
84
|
+
# lines with the parser (which is expensive).
|
85
85
|
# Benchmark in commit message
|
86
86
|
@valid = if lines.all? { |l| l.hidden? || l.empty? }
|
87
87
|
true
|
@@ -180,12 +180,19 @@ module SyntaxSuggest
|
|
180
180
|
# EOM
|
181
181
|
# expect(lines.first.trailing_slash?).to eq(true)
|
182
182
|
#
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
183
|
+
if SyntaxSuggest.use_prism_parser?
|
184
|
+
def trailing_slash?
|
185
|
+
last = @lex.last
|
186
|
+
last&.type == :on_tstring_end
|
187
|
+
end
|
188
|
+
else
|
189
|
+
def trailing_slash?
|
190
|
+
last = @lex.last
|
191
|
+
return false unless last
|
192
|
+
return false unless last.type == :on_sp
|
187
193
|
|
188
|
-
|
194
|
+
last.token == TRAILING_SLASH
|
195
|
+
end
|
189
196
|
end
|
190
197
|
|
191
198
|
# Endless method detection
|
@@ -43,7 +43,7 @@ module SyntaxSuggest
|
|
43
43
|
|
44
44
|
def initialize(source, record_dir: DEFAULT_VALUE)
|
45
45
|
record_dir = if record_dir == DEFAULT_VALUE
|
46
|
-
ENV["SYNTAX_SUGGEST_RECORD_DIR"] || ENV["SYNTAX_SUGGEST_DEBUG"] ? "tmp" : nil
|
46
|
+
(ENV["SYNTAX_SUGGEST_RECORD_DIR"] || ENV["SYNTAX_SUGGEST_DEBUG"]) ? "tmp" : nil
|
47
47
|
else
|
48
48
|
record_dir
|
49
49
|
end
|
@@ -73,7 +73,7 @@ module SyntaxSuggest
|
|
73
73
|
if ENV["SYNTAX_SUGGEST_DEBUG"]
|
74
74
|
puts "\n\n==== #{filename} ===="
|
75
75
|
puts "\n```#{block.starts_at}..#{block.ends_at}"
|
76
|
-
puts block
|
76
|
+
puts block
|
77
77
|
puts "```"
|
78
78
|
puts " block indent: #{block.current_indent}"
|
79
79
|
end
|
@@ -21,7 +21,7 @@ if SyntaxError.method_defined?(:detailed_message)
|
|
21
21
|
attr_reader :string
|
22
22
|
end
|
23
23
|
|
24
|
-
# SyntaxSuggest.
|
24
|
+
# SyntaxSuggest.module_for_detailed_message [Private]
|
25
25
|
#
|
26
26
|
# Used to monkeypatch SyntaxError via Module.prepend
|
27
27
|
def self.module_for_detailed_message
|
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
require_relative "left_right_lex_count"
|
4
4
|
|
5
|
+
if !SyntaxSuggest.use_prism_parser?
|
6
|
+
require_relative "ripper_errors"
|
7
|
+
end
|
8
|
+
|
5
9
|
module SyntaxSuggest
|
10
|
+
class GetParseErrors
|
11
|
+
def self.errors(source)
|
12
|
+
if SyntaxSuggest.use_prism_parser?
|
13
|
+
Prism.parse(source).errors.map(&:message)
|
14
|
+
else
|
15
|
+
RipperErrors.new(source).call.errors
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
6
20
|
# Explains syntax errors based on their source
|
7
21
|
#
|
8
22
|
# example:
|
@@ -15,8 +29,8 @@ module SyntaxSuggest
|
|
15
29
|
# # => "Unmatched keyword, missing `end' ?"
|
16
30
|
#
|
17
31
|
# When the error cannot be determined by lexical counting
|
18
|
-
# then
|
19
|
-
# errors returned.
|
32
|
+
# then the parser is run against the input and the raw
|
33
|
+
# errors are returned.
|
20
34
|
#
|
21
35
|
# Example:
|
22
36
|
#
|
@@ -91,10 +105,10 @@ module SyntaxSuggest
|
|
91
105
|
# Returns an array of syntax error messages
|
92
106
|
#
|
93
107
|
# If no missing pairs are found it falls back
|
94
|
-
# on the original
|
108
|
+
# on the original error messages
|
95
109
|
def errors
|
96
110
|
if missing.empty?
|
97
|
-
return
|
111
|
+
return GetParseErrors.errors(@code_lines.map(&:original).join).uniq
|
98
112
|
end
|
99
113
|
|
100
114
|
missing.map { |miss| why(miss) }
|
@@ -3,34 +3,53 @@
|
|
3
3
|
module SyntaxSuggest
|
4
4
|
# Ripper.lex is not guaranteed to lex the entire source document
|
5
5
|
#
|
6
|
-
# lex
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# This class guarantees the whole document is lex-ed by iteratively
|
7
|
+
# lexing the document where ripper stopped.
|
8
|
+
#
|
9
|
+
# Prism likely doesn't have the same problem. Once ripper support is removed
|
10
|
+
# we can likely reduce the complexity here if not remove the whole concept.
|
11
|
+
#
|
12
|
+
# Example usage:
|
13
|
+
#
|
14
|
+
# lex = LexAll.new(source: source)
|
15
|
+
# lex.each do |value|
|
16
|
+
# puts value.line
|
17
|
+
# end
|
10
18
|
class LexAll
|
11
19
|
include Enumerable
|
12
20
|
|
13
21
|
def initialize(source:, source_lines: nil)
|
14
|
-
@lex =
|
15
|
-
lineno = @lex.last
|
22
|
+
@lex = self.class.lex(source, 1)
|
23
|
+
lineno = @lex.last[0][0] + 1
|
16
24
|
source_lines ||= source.lines
|
17
25
|
last_lineno = source_lines.length
|
18
26
|
|
19
27
|
until lineno >= last_lineno
|
20
|
-
lines = source_lines[lineno
|
28
|
+
lines = source_lines[lineno..]
|
21
29
|
|
22
30
|
@lex.concat(
|
23
|
-
|
31
|
+
self.class.lex(lines.join, lineno + 1)
|
24
32
|
)
|
25
|
-
|
33
|
+
|
34
|
+
lineno = @lex.last[0].first + 1
|
26
35
|
end
|
27
36
|
|
28
37
|
last_lex = nil
|
29
38
|
@lex.map! { |elem|
|
30
|
-
last_lex = LexValue.new(elem.
|
39
|
+
last_lex = LexValue.new(elem[0].first, elem[1], elem[2], elem[3], last_lex)
|
31
40
|
}
|
32
41
|
end
|
33
42
|
|
43
|
+
if SyntaxSuggest.use_prism_parser?
|
44
|
+
def self.lex(source, line_number)
|
45
|
+
Prism.lex_compat(source, line: line_number).value.sort_by { |values| values[0] }
|
46
|
+
end
|
47
|
+
else
|
48
|
+
def self.lex(source, line_number)
|
49
|
+
Ripper::Lexer.new(source, "-", line_number).parse.sort_by(&:pos)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
34
53
|
def to_a
|
35
54
|
@lex
|
36
55
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SyntaxSuggest
|
4
|
-
# Capture parse errors from
|
4
|
+
# Capture parse errors from Ripper
|
5
|
+
#
|
6
|
+
# Prism returns the errors with their messages, but Ripper
|
7
|
+
# does not. To get them we must make a custom subclass.
|
5
8
|
#
|
6
9
|
# Example:
|
7
10
|
#
|
@@ -118,7 +118,7 @@ module SyntaxSuggest
|
|
118
118
|
# Returns an array of all the CodeLines that exist after
|
119
119
|
# the currently scanned block
|
120
120
|
private def after_lines
|
121
|
-
@code_lines[@after_index.next
|
121
|
+
@code_lines[@after_index.next..] || []
|
122
122
|
end
|
123
123
|
|
124
124
|
private def current
|
data/syntax_suggest.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.description = 'When you get an "unexpected end" in your syntax this gem helps you find it'
|
17
17
|
spec.homepage = "https://github.com/ruby/syntax_suggest.git"
|
18
18
|
spec.license = "MIT"
|
19
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
19
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
|
20
20
|
|
21
21
|
spec.metadata["homepage_uri"] = spec.homepage
|
22
22
|
spec.metadata["source_code_uri"] = "https://github.com/ruby/syntax_suggest.git"
|
@@ -27,6 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
|
28
28
|
end
|
29
29
|
spec.bindir = "exe"
|
30
|
-
spec.executables =
|
30
|
+
spec.executables = ["syntax_suggest"]
|
31
31
|
spec.require_paths = ["lib"]
|
32
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: syntax_suggest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- schneems
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: When you get an "unexpected end" in your syntax this gem helps you find
|
14
14
|
it
|
@@ -81,14 +81,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version:
|
84
|
+
version: 3.0.0
|
85
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
requirements: []
|
91
|
-
rubygems_version: 3.
|
91
|
+
rubygems_version: 3.4.22
|
92
92
|
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: Find syntax errors in your source in a snap
|