syntax_suggest 1.0.2 → 1.0.3
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 +4 -4
- data/.rspec +0 -1
- data/CHANGELOG.md +7 -1
- data/Gemfile.lock +1 -1
- data/README.md +13 -2
- data/bin/rake +6 -0
- data/bin/rspec +6 -0
- data/lib/syntax_suggest/api.rb +3 -1
- data/lib/syntax_suggest/around_block_scan.rb +172 -19
- data/lib/syntax_suggest/block_expand.rb +93 -8
- data/lib/syntax_suggest/capture_code_context.rb +0 -1
- data/lib/syntax_suggest/clean_document.rb +4 -2
- data/lib/syntax_suggest/code_line.rb +3 -5
- data/lib/syntax_suggest/core_ext.rb +4 -0
- data/lib/syntax_suggest/parse_blocks_from_indent_line.rb +2 -2
- data/lib/syntax_suggest/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20590130dde6c0a40a17b7d01ad9fca063c7044c83d7f04609f9d75df564f9ce
|
4
|
+
data.tar.gz: 73bed388644be5a7a71fe5ab892c8925d50f9dbcad5d918ca07512ffd85188af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42a28115779d75b9ff89e58b2a26a9c4807e834a91f8671ffdb2725f9dea954b017310c3b67a9bfe7b97ea6bdbb28e84c59f8bf5c951b0692e99f74ab3e9a5a3
|
7
|
+
data.tar.gz: 51c04529ff19c2181b7f025ff04165f436afaf22e7c9daffb23767176b48b8216006a9fd669b96a435abd8c9886b046224212e9f6c50435008a8ef677477f771
|
@@ -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@v3.
|
16
|
+
- uses: actions/checkout@v3.3.0
|
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,7 +9,7 @@ jobs:
|
|
9
9
|
runs-on: ubuntu-latest
|
10
10
|
steps:
|
11
11
|
- name: Checkout code
|
12
|
-
uses: actions/checkout@v3.
|
12
|
+
uses: actions/checkout@v3.3.0
|
13
13
|
- name: Set up Ruby
|
14
14
|
uses: ruby/setup-ruby@v1
|
15
15
|
with:
|
@@ -29,16 +29,16 @@ jobs:
|
|
29
29
|
- 2.7
|
30
30
|
- '3.0'
|
31
31
|
- 3.1
|
32
|
-
-
|
32
|
+
- 3.2
|
33
33
|
- head
|
34
34
|
steps:
|
35
35
|
- name: Checkout code
|
36
|
-
uses: actions/checkout@v3.
|
36
|
+
uses: actions/checkout@v3.3.0
|
37
37
|
- name: Set up Ruby
|
38
38
|
uses: ruby/setup-ruby@v1
|
39
39
|
with:
|
40
40
|
ruby-version: ${{ matrix.ruby }}
|
41
41
|
bundler-cache: true
|
42
42
|
- name: test
|
43
|
-
run:
|
43
|
+
run: bin/rake test
|
44
44
|
continue-on-error: ${{ matrix.ruby == 'head' }}
|
data/.rspec
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
## HEAD (unreleased)
|
2
2
|
|
3
|
+
## 1.0.3
|
4
|
+
|
5
|
+
- Output improvement: Handle methods with only newlines or comments in them (https://github.com/ruby/syntax_suggest/pull/179)
|
6
|
+
- No longer shows the detail of monkey patch as the document (https://github.com/ruby/syntax_suggest/pull/174)
|
7
|
+
- Drop CI for Ruby 3.2.0-rc1, now that 3.2.0 is available (https://github.com/ruby/syntax_suggest/pull/172)
|
8
|
+
|
3
9
|
## 1.0.2
|
4
10
|
|
5
|
-
- Drop support
|
11
|
+
- Drop support for Ruby 3.2.0 preview, now that 3.2.0-rc1 is available (https://github.com/ruby/syntax_suggest/pull/165)
|
6
12
|
- Native support of `SyntaxError#path`, support 3.2.0-preview3 will be dropped with the release of 3.2.0-preview4 (https://github.com/ruby/syntax_suggest/pull/164)
|
7
13
|
- Added dependabot for GitHub Actions (https://github.com/ruby/syntax_suggest/pull/160)
|
8
14
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -180,9 +180,20 @@ Any other entrypoints are subject to change without warning. If you want to use
|
|
180
180
|
|
181
181
|
## Development
|
182
182
|
|
183
|
-
|
183
|
+
### Handling conflicts with the default gem
|
184
184
|
|
185
|
-
|
185
|
+
Because `syntax_suggest` is a default gem you can get conflicts when working on this project with Ruby 3.2+. To fix conflicts you can disable loading `syntax_suggest` as a default gem by using then environment variable `RUBYOPT` with the value `--disable=syntax_suggest`. The `RUBYOPT` environment variable works the same as if we had entered those flags directly in the ruby cli (i.e. `ruby --disable=syntax_suggest` is the same as `RUBYOPT="--disable=syntax_suggest" ruby`). It's needed because we don't always directly execute Ruby and RUBYOPT will be picked up when other commands load ruby (`rspec`, `rake`, or `bundle` etc.).
|
186
|
+
|
187
|
+
There are some binstubs that already have this done for you. Instead of running `bundle exec rake` you can run `bin/rake`. Binstubs provided:
|
188
|
+
|
189
|
+
- `bin/rake`
|
190
|
+
- `bin/rspec`
|
191
|
+
|
192
|
+
### Installation
|
193
|
+
|
194
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
195
|
+
|
196
|
+
To install this gem onto your local machine, run `bin/rake install`. To release a new version, update the version number in `version.rb`, and then run `bin/rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
186
197
|
|
187
198
|
### How to debug changes to output display
|
188
199
|
|
data/bin/rake
ADDED
data/bin/rspec
ADDED
data/lib/syntax_suggest/api.rb
CHANGED
@@ -91,7 +91,9 @@ module SyntaxSuggest
|
|
91
91
|
dir = Pathname(dir)
|
92
92
|
dir.join(time).tap { |path|
|
93
93
|
path.mkpath
|
94
|
-
|
94
|
+
alias_dir = dir.join("last")
|
95
|
+
FileUtils.rm_rf(alias_dir) if alias_dir.exist?
|
96
|
+
FileUtils.ln_sf(time, alias_dir)
|
95
97
|
}
|
96
98
|
end
|
97
99
|
|
@@ -38,36 +38,64 @@ module SyntaxSuggest
|
|
38
38
|
@before_array = []
|
39
39
|
@stop_after_kw = false
|
40
40
|
|
41
|
-
@
|
42
|
-
@
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
@force_add_hidden = false
|
42
|
+
@force_add_empty = false
|
43
|
+
end
|
44
|
+
|
45
|
+
# When using this flag, `scan_while` will
|
46
|
+
# bypass the block it's given and always add a
|
47
|
+
# line that responds truthy to `CodeLine#hidden?`
|
48
|
+
#
|
49
|
+
# Lines are hidden when they've been evaluated by
|
50
|
+
# the parser as part of a block and found to contain
|
51
|
+
# valid code.
|
52
|
+
def force_add_hidden
|
53
|
+
@force_add_hidden = true
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
# When using this flag, `scan_while` will
|
58
|
+
# bypass the block it's given and always add a
|
59
|
+
# line that responds truthy to `CodeLine#empty?`
|
60
|
+
#
|
61
|
+
# Empty lines contain no code, only whitespace such
|
62
|
+
# as leading spaces a newline.
|
63
|
+
def force_add_empty
|
64
|
+
@force_add_empty = true
|
54
65
|
self
|
55
66
|
end
|
56
67
|
|
68
|
+
# Tells `scan_while` to look for mismatched keyword/end-s
|
69
|
+
#
|
70
|
+
# When scanning up, if we see more keywords then end-s it will
|
71
|
+
# stop. This might happen when scanning outside of a method body.
|
72
|
+
# the first scan line up would be a keyword and this setting would
|
73
|
+
# trigger a stop.
|
74
|
+
#
|
75
|
+
# When scanning down, stop if there are more end-s than keywords.
|
57
76
|
def stop_after_kw
|
58
77
|
@stop_after_kw = true
|
59
78
|
self
|
60
79
|
end
|
61
80
|
|
81
|
+
# Main work method
|
82
|
+
#
|
83
|
+
# The scan_while method takes a block that yields lines above and
|
84
|
+
# below the block. If the yield returns true, the @before_index
|
85
|
+
# or @after_index are modified to include the matched line.
|
86
|
+
#
|
87
|
+
# In addition to yielding individual lines, the internals of this
|
88
|
+
# object give a mini DSL to handle common situations such as
|
89
|
+
# stopping if we've found a keyword/end mis-match in one direction
|
90
|
+
# or the other.
|
62
91
|
def scan_while
|
63
92
|
stop_next = false
|
64
|
-
|
65
93
|
kw_count = 0
|
66
94
|
end_count = 0
|
67
95
|
index = before_lines.reverse_each.take_while do |line|
|
68
96
|
next false if stop_next
|
69
|
-
next true if @
|
70
|
-
next true if @
|
97
|
+
next true if @force_add_hidden && line.hidden?
|
98
|
+
next true if @force_add_empty && line.empty?
|
71
99
|
|
72
100
|
kw_count += 1 if line.is_kw?
|
73
101
|
end_count += 1 if line.is_end?
|
@@ -87,8 +115,8 @@ module SyntaxSuggest
|
|
87
115
|
end_count = 0
|
88
116
|
index = after_lines.take_while do |line|
|
89
117
|
next false if stop_next
|
90
|
-
next true if @
|
91
|
-
next true if @
|
118
|
+
next true if @force_add_hidden && line.hidden?
|
119
|
+
next true if @force_add_empty && line.empty?
|
92
120
|
|
93
121
|
kw_count += 1 if line.is_kw?
|
94
122
|
end_count += 1 if line.is_end?
|
@@ -105,6 +133,33 @@ module SyntaxSuggest
|
|
105
133
|
self
|
106
134
|
end
|
107
135
|
|
136
|
+
# Shows surrounding kw/end pairs
|
137
|
+
#
|
138
|
+
# The purpose of showing these extra pairs is due to cases
|
139
|
+
# of ambiguity when only one visible line is matched.
|
140
|
+
#
|
141
|
+
# For example:
|
142
|
+
#
|
143
|
+
# 1 class Dog
|
144
|
+
# 2 def bark
|
145
|
+
# 4 def eat
|
146
|
+
# 5 end
|
147
|
+
# 6 end
|
148
|
+
#
|
149
|
+
# In this case either line 2 could be missing an `end` or
|
150
|
+
# line 4 was an extra line added by mistake (it happens).
|
151
|
+
#
|
152
|
+
# When we detect the above problem it shows the issue
|
153
|
+
# as only being on line 2
|
154
|
+
#
|
155
|
+
# 2 def bark
|
156
|
+
#
|
157
|
+
# Showing "neighbor" keyword pairs gives extra context:
|
158
|
+
#
|
159
|
+
# 2 def bark
|
160
|
+
# 4 def eat
|
161
|
+
# 5 end
|
162
|
+
#
|
108
163
|
def capture_neighbor_context
|
109
164
|
lines = []
|
110
165
|
kw_count = 0
|
@@ -146,6 +201,20 @@ module SyntaxSuggest
|
|
146
201
|
lines
|
147
202
|
end
|
148
203
|
|
204
|
+
# Shows the context around code provided by "falling" indentation
|
205
|
+
#
|
206
|
+
# Converts:
|
207
|
+
#
|
208
|
+
# it "foo" do
|
209
|
+
#
|
210
|
+
# into:
|
211
|
+
#
|
212
|
+
# class OH
|
213
|
+
# def hello
|
214
|
+
# it "foo" do
|
215
|
+
# end
|
216
|
+
# end
|
217
|
+
#
|
149
218
|
def on_falling_indent
|
150
219
|
last_indent = @orig_indent
|
151
220
|
before_lines.reverse_each do |line|
|
@@ -166,18 +235,79 @@ module SyntaxSuggest
|
|
166
235
|
end
|
167
236
|
end
|
168
237
|
|
169
|
-
|
238
|
+
# Scanning is intentionally conservative because
|
239
|
+
# we have no way of rolling back an agressive block (at this time)
|
240
|
+
#
|
241
|
+
# If a block was stopped for some trivial reason, (like an empty line)
|
242
|
+
# but the next line would have caused it to be balanced then we
|
243
|
+
# can check that condition and grab just one more line either up or
|
244
|
+
# down.
|
245
|
+
#
|
246
|
+
# For example, below if we're scanning up, line 2 might cause
|
247
|
+
# the scanning to stop. This is because empty lines might
|
248
|
+
# denote logical breaks where the user intended to chunk code
|
249
|
+
# which is a good place to stop and check validity. Unfortunately
|
250
|
+
# it also means we might have a "dangling" keyword or end.
|
251
|
+
#
|
252
|
+
# 1 def bark
|
253
|
+
# 2
|
254
|
+
# 3 end
|
255
|
+
#
|
256
|
+
# If lines 2 and 3 are in the block, then when this method is
|
257
|
+
# run it would see it is unbalanced, but that acquiring line 1
|
258
|
+
# would make it balanced, so that's what it does.
|
259
|
+
def lookahead_balance_one_line
|
260
|
+
kw_count = 0
|
261
|
+
end_count = 0
|
262
|
+
lines.each do |line|
|
263
|
+
kw_count += 1 if line.is_kw?
|
264
|
+
end_count += 1 if line.is_end?
|
265
|
+
end
|
266
|
+
|
267
|
+
return self if kw_count == end_count # nothing to balance
|
268
|
+
|
269
|
+
# More ends than keywords, check if we can balance expanding up
|
270
|
+
if (end_count - kw_count) == 1 && next_up
|
271
|
+
return self unless next_up.is_kw?
|
272
|
+
return self unless next_up.indent >= @orig_indent
|
273
|
+
|
274
|
+
@before_index = next_up.index
|
275
|
+
|
276
|
+
# More keywords than ends, check if we can balance by expanding down
|
277
|
+
elsif (kw_count - end_count) == 1 && next_down
|
278
|
+
return self unless next_down.is_end?
|
279
|
+
return self unless next_down.indent >= @orig_indent
|
280
|
+
|
281
|
+
@after_index = next_down.index
|
282
|
+
end
|
283
|
+
self
|
284
|
+
end
|
285
|
+
|
286
|
+
# Finds code lines at the same or greater indentation and adds them
|
287
|
+
# to the block
|
288
|
+
def scan_neighbors_not_empty
|
170
289
|
scan_while { |line| line.not_empty? && line.indent >= @orig_indent }
|
171
290
|
end
|
172
291
|
|
292
|
+
# Returns the next line to be scanned above the current block.
|
293
|
+
# Returns `nil` if at the top of the document already
|
173
294
|
def next_up
|
174
295
|
@code_lines[before_index.pred]
|
175
296
|
end
|
176
297
|
|
298
|
+
# Returns the next line to be scanned below the current block.
|
299
|
+
# Returns `nil` if at the bottom of the document already
|
177
300
|
def next_down
|
178
301
|
@code_lines[after_index.next]
|
179
302
|
end
|
180
303
|
|
304
|
+
# Scan blocks based on indentation of next line above/below block
|
305
|
+
#
|
306
|
+
# Determines indentaion of the next line above/below the current block.
|
307
|
+
#
|
308
|
+
# Normally this is called when a block has expanded to capture all "neighbors"
|
309
|
+
# at the same (or greater) indentation and needs to expand out. For example
|
310
|
+
# the `def/end` lines surrounding a method.
|
181
311
|
def scan_adjacent_indent
|
182
312
|
before_after_indent = []
|
183
313
|
before_after_indent << (next_up&.indent || 0)
|
@@ -189,6 +319,16 @@ module SyntaxSuggest
|
|
189
319
|
self
|
190
320
|
end
|
191
321
|
|
322
|
+
# TODO: Doc or delete
|
323
|
+
#
|
324
|
+
# I don't remember why this is needed, but it's called in code_context.
|
325
|
+
# It's related to the implementation of `capture_neighbor_context` somehow
|
326
|
+
# and that display improvement is only triggered when there's one visible line
|
327
|
+
#
|
328
|
+
# I think the primary purpose is to not include the current line in the
|
329
|
+
# logic evaluation of `capture_neighbor_context`. If that's true, then
|
330
|
+
# we should fix that method to handle this logic instead of only using
|
331
|
+
# it in one place and together.
|
192
332
|
def start_at_next_line
|
193
333
|
before_index
|
194
334
|
after_index
|
@@ -197,26 +337,39 @@ module SyntaxSuggest
|
|
197
337
|
self
|
198
338
|
end
|
199
339
|
|
340
|
+
# Return the currently matched lines as a `CodeBlock`
|
341
|
+
#
|
342
|
+
# When a `CodeBlock` is created it will gather metadata about
|
343
|
+
# itself, so this is not a free conversion. Avoid allocating
|
344
|
+
# more CodeBlock's than needed
|
200
345
|
def code_block
|
201
346
|
CodeBlock.new(lines: lines)
|
202
347
|
end
|
203
348
|
|
349
|
+
# Returns the lines matched by the current scan as an
|
350
|
+
# array of CodeLines
|
204
351
|
def lines
|
205
352
|
@code_lines[before_index..after_index]
|
206
353
|
end
|
207
354
|
|
355
|
+
# Gives the index of the first line currently scanned
|
208
356
|
def before_index
|
209
357
|
@before_index ||= @orig_before_index
|
210
358
|
end
|
211
359
|
|
360
|
+
# Gives the index of the last line currently scanned
|
212
361
|
def after_index
|
213
362
|
@after_index ||= @orig_after_index
|
214
363
|
end
|
215
364
|
|
365
|
+
# Returns an array of all the CodeLines that exist before
|
366
|
+
# the currently scanned block
|
216
367
|
private def before_lines
|
217
368
|
@code_lines[0...before_index] || []
|
218
369
|
end
|
219
370
|
|
371
|
+
# Returns an array of all the CodeLines that exist after
|
372
|
+
# the currently scanned block
|
220
373
|
private def after_lines
|
221
374
|
@code_lines[after_index.next..-1] || []
|
222
375
|
end
|
@@ -35,30 +35,115 @@ module SyntaxSuggest
|
|
35
35
|
@code_lines = code_lines
|
36
36
|
end
|
37
37
|
|
38
|
+
# Main interface. Expand current indentation, before
|
39
|
+
# expanding to a lower indentation
|
38
40
|
def call(block)
|
39
41
|
if (next_block = expand_neighbors(block))
|
40
|
-
|
42
|
+
next_block
|
43
|
+
else
|
44
|
+
expand_indent(block)
|
41
45
|
end
|
42
|
-
|
43
|
-
expand_indent(block)
|
44
46
|
end
|
45
47
|
|
48
|
+
# Expands code to the next lowest indentation
|
49
|
+
#
|
50
|
+
# For example:
|
51
|
+
#
|
52
|
+
# 1 def dog
|
53
|
+
# 2 print "dog"
|
54
|
+
# 3 end
|
55
|
+
#
|
56
|
+
# If a block starts on line 2 then it has captured all it's "neighbors" (code at
|
57
|
+
# the same indentation or higher). To continue expanding, this block must capture
|
58
|
+
# lines one and three which are at a different indentation level.
|
59
|
+
#
|
60
|
+
# This method allows fully expanded blocks to decrease their indentation level (so
|
61
|
+
# they can expand to capture more code up and down). It does this conservatively
|
62
|
+
# as there's no undo (currently).
|
46
63
|
def expand_indent(block)
|
47
64
|
AroundBlockScan.new(code_lines: @code_lines, block: block)
|
48
|
-
.
|
65
|
+
.force_add_hidden
|
49
66
|
.stop_after_kw
|
50
67
|
.scan_adjacent_indent
|
51
68
|
.code_block
|
52
69
|
end
|
53
70
|
|
71
|
+
# A neighbor is code that is at or above the current indent line.
|
72
|
+
#
|
73
|
+
# First we build a block with all neighbors. If we can't go further
|
74
|
+
# then we decrease the indentation threshold and expand via indentation
|
75
|
+
# i.e. `expand_indent`
|
76
|
+
#
|
77
|
+
# Handles two general cases.
|
78
|
+
#
|
79
|
+
# ## Case #1: Check code inside of methods/classes/etc.
|
80
|
+
#
|
81
|
+
# It's important to note, that not everything in a given indentation level can be parsed
|
82
|
+
# as valid code even if it's part of valid code. For example:
|
83
|
+
#
|
84
|
+
# 1 hash = {
|
85
|
+
# 2 name: "richard",
|
86
|
+
# 3 dog: "cinco",
|
87
|
+
# 4 }
|
88
|
+
#
|
89
|
+
# In this case lines 2 and 3 will be neighbors, but they're invalid until `expand_indent`
|
90
|
+
# is called on them.
|
91
|
+
#
|
92
|
+
# When we are adding code within a method or class (at the same indentation level),
|
93
|
+
# use the empty lines to denote the programmer intended logical chunks.
|
94
|
+
# Stop and check each one. For example:
|
95
|
+
#
|
96
|
+
# 1 def dog
|
97
|
+
# 2 print "dog"
|
98
|
+
# 3
|
99
|
+
# 4 hash = {
|
100
|
+
# 5 end
|
101
|
+
#
|
102
|
+
# If we did not stop parsing at empty newlines then the block might mistakenly grab all
|
103
|
+
# the contents (lines 2, 3, and 4) and report them as being problems, instead of only
|
104
|
+
# line 4.
|
105
|
+
#
|
106
|
+
# ## Case #2: Expand/grab other logical blocks
|
107
|
+
#
|
108
|
+
# Once the search algorithm has converted all lines into blocks at a given indentation
|
109
|
+
# it will then `expand_indent`. Once the blocks that generates are expanded as neighbors
|
110
|
+
# we then begin seeing neighbors being other logical blocks i.e. a block's neighbors
|
111
|
+
# may be another method or class (something with keywords/ends).
|
112
|
+
#
|
113
|
+
# For example:
|
114
|
+
#
|
115
|
+
# 1 def bark
|
116
|
+
# 2
|
117
|
+
# 3 end
|
118
|
+
# 4
|
119
|
+
# 5 def sit
|
120
|
+
# 6 end
|
121
|
+
#
|
122
|
+
# In this case if lines 4, 5, and 6 are in a block when it tries to expand neighbors
|
123
|
+
# it will expand up. If it stops after line 2 or 3 it may cause problems since there's a
|
124
|
+
# valid kw/end pair, but the block will be checked without it.
|
125
|
+
#
|
126
|
+
# We try to resolve this edge case with `lookahead_balance_one_line` below.
|
54
127
|
def expand_neighbors(block)
|
55
|
-
|
56
|
-
.
|
128
|
+
neighbors = AroundBlockScan.new(code_lines: @code_lines, block: block)
|
129
|
+
.force_add_hidden
|
57
130
|
.stop_after_kw
|
58
|
-
.
|
59
|
-
|
131
|
+
.scan_neighbors_not_empty
|
132
|
+
|
133
|
+
# Slurp up empties
|
134
|
+
with_empties = neighbors
|
135
|
+
.scan_while { |line| line.empty? }
|
136
|
+
|
137
|
+
# If next line is kw and it will balance us, take it
|
138
|
+
expanded_lines = with_empties
|
139
|
+
.lookahead_balance_one_line
|
60
140
|
.lines
|
61
141
|
|
142
|
+
# Don't allocate a block if it won't be used
|
143
|
+
#
|
144
|
+
# If nothing was taken, return nil to indicate that status
|
145
|
+
# used in `def call` to determine if
|
146
|
+
# we need to expand up/out (`expand_indent`)
|
62
147
|
if block.lines == expanded_lines
|
63
148
|
nil
|
64
149
|
else
|
@@ -110,7 +110,7 @@ module SyntaxSuggest
|
|
110
110
|
@document.join
|
111
111
|
end
|
112
112
|
|
113
|
-
# Remove comments
|
113
|
+
# Remove comments
|
114
114
|
#
|
115
115
|
# replace with empty newlines
|
116
116
|
#
|
@@ -155,8 +155,10 @@ module SyntaxSuggest
|
|
155
155
|
# ).to eq(2)
|
156
156
|
#
|
157
157
|
def clean_sweep(source:)
|
158
|
+
# Match comments, but not HEREDOC strings with #{variable} interpolation
|
159
|
+
# https://rubular.com/r/HPwtW9OYxKUHXQ
|
158
160
|
source.lines.map do |line|
|
159
|
-
if line.match?(/^\s
|
161
|
+
if line.match?(/^\s*#([^{].*|)$/)
|
160
162
|
$/
|
161
163
|
else
|
162
164
|
line
|
@@ -48,12 +48,10 @@ module SyntaxSuggest
|
|
48
48
|
strip_line = line.dup
|
49
49
|
strip_line.lstrip!
|
50
50
|
|
51
|
-
if strip_line.empty?
|
52
|
-
|
53
|
-
@indent = 0
|
51
|
+
@indent = if (@empty = strip_line.empty?)
|
52
|
+
line.length - 1 # Newline removed from strip_line is not "whitespace"
|
54
53
|
else
|
55
|
-
|
56
|
-
@indent = line.length - strip_line.length
|
54
|
+
line.length - strip_line.length
|
57
55
|
end
|
58
56
|
|
59
57
|
set_kw_end
|
@@ -66,9 +66,13 @@ if SyntaxError.method_defined?(:detailed_message)
|
|
66
66
|
else
|
67
67
|
autoload :Pathname, "pathname"
|
68
68
|
|
69
|
+
#--
|
69
70
|
# Monkey patch kernel to ensure that all `require` calls call the same
|
70
71
|
# method
|
72
|
+
#++
|
71
73
|
module Kernel
|
74
|
+
# :stopdoc:
|
75
|
+
|
72
76
|
module_function
|
73
77
|
|
74
78
|
alias_method :syntax_suggest_original_require, :require
|
@@ -36,8 +36,8 @@ module SyntaxSuggest
|
|
36
36
|
# Builds blocks from bottom up
|
37
37
|
def each_neighbor_block(target_line)
|
38
38
|
scan = AroundBlockScan.new(code_lines: code_lines, block: CodeBlock.new(lines: target_line))
|
39
|
-
.
|
40
|
-
.
|
39
|
+
.force_add_empty
|
40
|
+
.force_add_hidden
|
41
41
|
.scan_while { |line| line.indent >= target_line.indent }
|
42
42
|
|
43
43
|
neighbors = scan.code_block.lines
|
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: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- schneems
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-17 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
|
@@ -33,6 +33,8 @@ files:
|
|
33
33
|
- README.md
|
34
34
|
- Rakefile
|
35
35
|
- bin/console
|
36
|
+
- bin/rake
|
37
|
+
- bin/rspec
|
36
38
|
- bin/setup
|
37
39
|
- exe/syntax_suggest
|
38
40
|
- lib/syntax_suggest.rb
|
@@ -82,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
84
|
- !ruby/object:Gem::Version
|
83
85
|
version: '0'
|
84
86
|
requirements: []
|
85
|
-
rubygems_version: 3.4.
|
87
|
+
rubygems_version: 3.4.6
|
86
88
|
signing_key:
|
87
89
|
specification_version: 4
|
88
90
|
summary: Find syntax errors in your source in a snap
|