Skip to content

Commit 513646b

Browse files
committed
Fix #187 Handle if/else with empty/comment line
Reported in #187 this code: ``` class Foo def foo if cond? foo else # comment end end # ... def bar if @recv end_is_missing_here end end ``` Triggers an incorrect suggestion: ``` Unmatched keyword, missing `end' ? 1 class Foo 2 def foo > 3 if cond? > 5 else 8 end 16 end ``` Part of the issue is that while scanning we're using newlines to determine when to stop and pause. This is useful for determining logically smaller chunks to evaluate but in this case it causes us to pause before grabbing the "end" that is right below the newline. This problem is similar to #179. However in the case of expanding same indentation "neighbors" I want to always grab all empty values at the end of the scan. I don't want to do that when changing indentation levels as it affects scan results. There may be some way to normalize this behavior between the two, but the tests really don't like that change. To fix this issue for expanding against different indentation I needed a way to first try and grab any additional newlines with the ability to rollback that guess. In #192 I experimented with decoupling scanning from the AroundBlockScan logic. It also added the ability to take a snapshot of the current scanner and rollback to prior changes. With this ability in place now we: - Grab extra empties before looking at the above/below line for the matching keyword/end statement - If there's a match, grab it - If there's no match, discard the newlines we picked up in the evaluation That solves the issue.
1 parent ad8487d commit 513646b

File tree

5 files changed

+59
-9
lines changed

5 files changed

+59
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## HEAD (unreleased)
22

3+
- Handle if/else with comment or empty line in branch (https://github.com/ruby/syntax_suggest/pull/193)
34
- Use `SYNTAX_SUGGEST_DEBUG` instead of `DEBUG` env var value in timeout warning message (https://github.com/ruby/syntax_suggest/pull/194)
45
- Reduce line output for increased clarity (https://github.com/ruby/syntax_suggest/pull/190)
56

lib/syntax_suggest/around_block_scan.rb

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def capture_before_after_kws
181181
lines << line if line.is_kw? || line.is_end?
182182
}
183183
)
184-
@scanner.try_rollback
184+
@scanner.stash_changes
185185
lines
186186
end
187187

@@ -240,7 +240,7 @@ def on_falling_indent
240240
true
241241
}
242242
)
243-
@scanner.try_rollback
243+
@scanner.stash_changes
244244
self
245245
end
246246

@@ -275,26 +275,34 @@ def lookahead_balance_one_line
275275

276276
return self if kw_count == end_count # nothing to balance
277277

278+
@scanner.commit_if_changed
279+
scan_while { |line| line.empty? }
280+
278281
# More ends than keywords, check if we can balance expanding up
279282
next_up = @scanner.next_up
280283
next_down = @scanner.next_down
281284
if (end_count - kw_count) == 1 && next_up
282-
if next_up.is_kw? && next_up.indent >= @orig_indent
285+
if next_up.is_kw? && next_up.indent >= @target_indent
283286
@scanner.scan(
284287
up: ->(line, _, _) { line == next_up },
285288
down: ->(line, _, _) { false }
286289
)
290+
@scanner.commit_if_changed
287291
end
288292

289293
# More keywords than ends, check if we can balance by expanding down
290294
elsif (kw_count - end_count) == 1 && next_down
291-
if next_down.is_end? && next_down.indent >= @orig_indent
295+
if next_down.is_end? && next_down.indent >= @target_indent
292296
@scanner.scan(
293297
up: ->(line, _, _) { false },
294-
down: ->(line) { line == next_down }
298+
down: ->(line, _, _) { line == next_down }
295299
)
300+
@scanner.commit_if_changed
296301
end
297302
end
303+
304+
@scanner.stash_changes
305+
298306
self
299307
end
300308

lib/syntax_suggest/block_expand.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,14 @@ def call(block)
6161
# they can expand to capture more code up and down). It does this conservatively
6262
# as there's no undo (currently).
6363
def expand_indent(block)
64-
AroundBlockScan.new(code_lines: @code_lines, block: block)
64+
now = AroundBlockScan.new(code_lines: @code_lines, block: block)
6565
.force_add_hidden
6666
.stop_after_kw
6767
.scan_adjacent_indent
68-
.code_block
68+
69+
now.lookahead_balance_one_line
70+
71+
now.code_block
6972
end
7073

7174
# A neighbor is code that is at or above the current indent line.

lib/syntax_suggest/scan_history.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,20 @@ def initialize(code_lines:, block:)
1717
def commit_if_changed
1818
if changed?
1919
@history << CodeBlock.new(lines: @code_lines[before_index..after_index])
20-
refresh_index
2120
end
2221

2322
self
2423
end
2524

26-
def try_rollback
25+
# Discards any changes that have not been committed
26+
def stash_changes
27+
refresh_index
28+
end
29+
30+
# Discard changes that have not been committed and revert the last commit
31+
#
32+
# Cannot revert the first commit
33+
def revert_last_commit
2734
if @history.length > 1
2835
@history.pop
2936
refresh_index

spec/integration/syntax_suggest_spec.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,36 @@ def bark
204204
> 4 end
205205
EOM
206206
end
207+
208+
it "empty else" do
209+
source = <<~'EOM'
210+
class Foo
211+
def foo
212+
if cond?
213+
foo
214+
else
215+
216+
end
217+
end
218+
219+
# ...
220+
221+
def bar
222+
if @recv
223+
end_is_missing_here
224+
end
225+
end
226+
EOM
227+
228+
io = StringIO.new
229+
SyntaxSuggest.call(
230+
io: io,
231+
source: source
232+
)
233+
out = io.string
234+
expect(out).to include(<<~EOM)
235+
end_is_missing_here
236+
EOM
237+
end
207238
end
208239
end

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy