class SyntaxSuggest::BlockExpand

此类负责获取一个位于较远缩进处的代码块,然后迭代地增加该代码块,使其捕获同一缩进块内的所有内容。

def dog
  puts "bow"
  puts "wow"
end

block = BlockExpand.new(code_lines: code_lines)

.call(CodeBlock.new(lines: code_lines[1]))

puts block.to_s # => puts “bow”

puts "wow"

一旦代码块捕获了给定缩进级别的所有内容,它将扩展以捕获周围的缩进。

block = BlockExpand.new(code_lines: code_lines)

.call(block)

block.to_s # => def dog

  puts "bow"
  puts "wow"
end

公共类方法

new(code_lines:) 点击以切换源代码
# File syntax_suggest/block_expand.rb, line 34
def initialize(code_lines:)
  @code_lines = code_lines
end

公共实例方法

call(block) 点击以切换源代码

主要接口。扩展当前缩进,然后再扩展到较低的缩进

# File syntax_suggest/block_expand.rb, line 40
def call(block)
  if (next_block = expand_neighbors(block))
    next_block
  else
    expand_indent(block)
  end
end
expand_indent(block) 点击以切换源代码

将代码扩展到下一个最低缩进

例如

1 def dog
2   print "dog"
3 end

如果一个代码块从第 2 行开始,那么它已经捕获了它所有的“邻居”(相同或更高缩进处的代码)。要继续扩展,这个代码块必须捕获位于不同缩进级别的第一行和第三行。

此方法允许完全扩展的代码块降低其缩进级别(以便它们可以扩展以捕获更多上下代码)。它会保守地执行此操作,因为没有撤消操作(目前)。

# File syntax_suggest/block_expand.rb, line 63
def expand_indent(block)
  now = AroundBlockScan.new(code_lines: @code_lines, block: block)
    .force_add_hidden
    .stop_after_kw
    .scan_adjacent_indent

  now.lookahead_balance_one_line

  now.code_block
end
expand_neighbors(block) 点击以切换源代码

邻居是位于当前缩进线或以上的代码。

首先,我们构建一个包含所有邻居的代码块。如果我们无法进一步扩展,那么我们会降低缩进阈值并通过缩进扩展,即 `expand_indent`。

处理两种一般情况。

## 情况 1:检查方法/类/等等内部的代码

需要注意的是,即使给定缩进级别中的所有内容是有效代码的一部分,也并非所有内容都可以解析为有效的代码。例如

1 hash = {
2   name: "richard",
3   dog: "cinco",
4 }

在这种情况下,第 2 行和第 3 行将是邻居,但在对其调用 `expand_indent` 之前,它们是无效的。

当我们在方法或类(在相同的缩进级别)中添加代码时,使用空行来表示程序员预期的逻辑块。停止并检查每一个。例如

1 def dog
2   print "dog"
3
4   hash = {
5 end

如果我们不在空换行符处停止解析,那么代码块可能会错误地捕获所有内容(第 2、3 和 4 行),并将其报告为存在问题,而不是仅报告第 4 行。

## 情况 2:扩展/获取其他逻辑块

一旦搜索算法将给定缩进处的所有行转换为代码块,它将接着执行 `expand_indent`。一旦生成的代码块作为邻居扩展,我们开始看到邻居是其他的逻辑块,即代码块的邻居可能是另一个方法或类(带有关键字/结束符)。

例如

1 def bark
2
3 end
4
5 def sit
6 end

在这种情况下,如果第 4、5 和 6 行在一个代码块中,当它尝试扩展邻居时,它将向上扩展。如果它在第 2 或 3 行后停止,可能会导致问题,因为存在有效的 kw/end 对,但是将在不包含它的情况下检查代码块。

我们尝试通过下面的 `lookahead_balance_one_line` 来解决这种边缘情况。

# File syntax_suggest/block_expand.rb, line 130
def expand_neighbors(block)
  now = AroundBlockScan.new(code_lines: @code_lines, block: block)

  # Initial scan
  now
    .force_add_hidden
    .stop_after_kw
    .scan_neighbors_not_empty

  # Slurp up empties
  now
    .scan_while { |line| line.empty? }

  # If next line is kw and it will balance us, take it
  expanded_lines = now
    .lookahead_balance_one_line
    .lines

  # Don't allocate a block if it won't be used
  #
  # If nothing was taken, return nil to indicate that status
  # used in `def call` to determine if
  # we need to expand up/out (`expand_indent`)
  if block.lines == expanded_lines
    nil
  else
    CodeBlock.new(lines: expanded_lines)
  end
end
inspect() 点击以切换源代码

可管理的 rspec 错误

# File syntax_suggest/block_expand.rb, line 161
def inspect
  "#<SyntaxSuggest::CodeBlock:0x0000123843lol >"
end