syntax_suggest 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|