класс SyntaxSuggest::CaptureCodeContext
Преобразует «некорректный(ые) блок(и)» в полезный контекст
В алгоритме есть три основные фазы:
-
Сантизация/форматирование исходного кода
-
Поиск некорректных блоков
-
Форматирование некорректных блоков в осмысленную форму
Этот класс обрабатывает третью часть.
Алгоритм хорошо справляется с захватом всей ошибки синтаксиса в одном блоке в пункте 2, однако результаты могут содержать неоднозначности. Люди хорошо умеют распознавать закономерности и фильтровать, и могут мысленно удалять ненужные данные, но они не могут добавлять дополнительные данные, которых нет.
В случае известных неоднозначных случаев, этот класс добавляет контекст к неоднозначности, чтобы программист имел полную информацию.
Помимо обработки этих неоднозначностей, он также захватывает информацию о контексте окружающего кода:
puts block.to_s # => "def bark"
context = CaptureCodeContext.new(
blocks: block,
code_lines: code_lines
)
lines = context.call.map(&:original)
puts lines.join
# =>
class Dog
def bark
end Атрибуты
Общедоступные методы класса
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 51 def initialize(blocks:, code_lines:) @blocks = Array(blocks) @code_lines = code_lines @visible_lines = @blocks.map(&:visible_lines).flatten @lines_to_output = @visible_lines.dup end
Общедоступные методы экземпляра
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 58
def call
@blocks.each do |block|
capture_first_kw_end_same_indent(block)
capture_last_end_same_indent(block)
capture_before_after_kws(block)
capture_falling_indent(block)
end
sorted_lines
end Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 127
def capture_before_after_kws(block)
return unless block.visible_lines.count == 1
around_lines = Capture::BeforeAfterKeywordEnds.new(
code_lines: @code_lines,
block: block
).call
around_lines -= block.lines
@lines_to_output.concat(around_lines)
end Отображает окружающие пары ключевых слов/end
Цель отображения этих дополнительных пар заключается в случаях неоднозначности, когда совпадает только одна видимая строка.
Например:
1 class Dog 2 def bark 4 def eat 5 end 6 end
В этом случае либо в строке 2 отсутствует ‘end`, либо в строке 4 была добавлена лишняя строка (это случается).
Когда мы обнаруживаем указанную выше проблему, отображается информация о проблеме, как будто она только в строке 2
2 def bark
Отображение пар ключевых слов «соседних» пар обеспечивает дополнительный контекст:
2 def bark 4 def eat 5 end
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 91
def capture_falling_indent(block)
Capture::FallingIndentLines.new(
block: block,
code_lines: @code_lines
).call do |line|
@lines_to_output << line
end
end Отображает контекст вокруг кода, предоставленного «падающим» отступом
Преобразует:
it "foo" do
в:
class OH
def hello
it "foo" do
end
end Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 221
def capture_first_kw_end_same_indent(block)
return if block.visible_lines.length != 1
return unless block.visible_lines.first.is_end?
visible_line = block.visible_lines.first
lines = @code_lines[block.lines.first.index..visible_line.index]
matching_kw = lines.reverse.detect { |line| line.indent == block.current_indent && line.is_kw? }
return unless matching_kw
@lines_to_output << matching_kw
kw_count = 0
end_count = 0
orphan_end = @code_lines[matching_kw.index..visible_line.index].detect do |line|
kw_count += 1 if line.is_kw?
end_count += 1 if line.is_end?
end_count >= kw_count
end
return unless orphan_end
@lines_to_output << orphan_end
end Логическое обратное значение ‘capture_last_end_same_indent`
Когда в некорректном блоке отсутствует ключевое слово «end» сразу после другого `end`, неясно, какое end отсутствует ключевое слово.
Рассмотрим этот пример:
class Dog # 1
puts "woof" # 2
end # 3
end # 4 Проблемная строка будет распознана как:
> end # 4
Это происходит потому, что строки 1, 2 и 3 являются технически корректным кодом и расширяются в первую очередь, считаются корректными и скрываются. Нам нужно отобразить соответствующее ключевое слово в строке 1. Также необходимо работать в обратном направлении и, если есть несоответствие end, отобразить его тоже
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 161
def capture_last_end_same_indent(block)
return if block.visible_lines.length != 1
return unless block.visible_lines.first.is_kw?
visible_line = block.visible_lines.first
lines = @code_lines[visible_line.index..block.lines.last.index]
# Find first end with same indent
# (this would return line 4)
#
# end # 4
matching_end = lines.detect { |line| line.indent == block.current_indent && line.is_end? }
return unless matching_end
@lines_to_output << matching_end
# Work backwards from the end to
# see if there are mis-matched
# keyword/end pairs
#
# Return the first mis-matched keyword
# this would find line 2
#
# def bark # 2
# puts "woof" # 3
# end # 4
end_count = 0
kw_count = 0
kw_line = @code_lines[visible_line.index..matching_end.index].reverse.detect do |line|
end_count += 1 if line.is_end?
kw_count += 1 if line.is_kw?
!kw_count.zero? && kw_count >= end_count
end
return unless kw_line
@lines_to_output << kw_line
end Когда в некорректном блоке отсутствует ключевое слово, за которым сразу следует end, неясно, какое ключевое слово отсутствует.
Рассмотрим этот пример:
class Dog # 1
def bark # 2
puts "woof" # 3
end # 4 Однако из-за github.com/ruby/syntax_suggest/issues/32 проблемная строка будет распознана как:
> class Dog # 1
Потому что строки 2, 3 и 4 являются технически корректным кодом и расширяются в первую очередь, считаются корректными и скрываются. Нам нужно отобразить соответствующий конец в строке 4. Также необходимо работать в обратном направлении и, если есть несоответствие ключевого слова, отобразить его тоже
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 69 def sorted_lines @lines_to_output.select!(&:not_empty?) @lines_to_output.uniq! @lines_to_output.sort! @lines_to_output end
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.