class SyntaxSuggest::CodeSearch
Searches code for a syntax error
There are three main phases in the algorithm:
Sanitize/format input source
Search for invalid blocks
Format invalid blocks into something meaninful
This class handles the part.
The bulk of the heavy lifting is done in:
- CodeFrontier (Holds information for generating blocks and determining if we can stop searching)- ParseBlocksFromLine (Creates blocks into the frontier)- BlockExpand (Expands existing blocks to search more code)
## Syntax error detection
When the frontier holds the syntax error, we can stop searching
search =CodeSearch.new(<<~EOM) def dog def lol endEOMsearch.callsearch.invalid_blocks.map(&:to_s)# =># => ["def lol\n"]
Attributes
Public Class Methods
Source
# File lib/syntax_suggest/code_search.rb, line 44definitialize(source,record_dir:DEFAULT_VALUE)record_dir =ifrecord_dir==DEFAULT_VALUE (ENV["SYNTAX_SUGGEST_RECORD_DIR"]||ENV["SYNTAX_SUGGEST_DEBUG"])?"tmp":nilelserecord_direndifrecord_dir@record_dir =SyntaxSuggest.record_dir(record_dir)@write_count =0end@tick =0@source =source@name_tick =Hash.new {|hash,k|hash[k] =0 }@invalid_blocks = []@code_lines =CleanDocument.new(source:source).call.lines@frontier =CodeFrontier.new(code_lines:@code_lines)@block_expand =BlockExpand.new(code_lines:@code_lines)@parse_blocks_from_indent_line =ParseBlocksFromIndentLine.new(code_lines:@code_lines)end
Public Instance Methods
Source
# File lib/syntax_suggest/code_search.rb, line 123defcalluntilfrontier.holds_all_syntax_errors?@tick+=1iffrontier.expand?expand_existingelsecreate_blocks_from_untracked_linesendend@invalid_blocks.concat(frontier.detect_invalid_blocks)@invalid_blocks.sort_by! {|block|block.starts_at }selfend
Main search loop
Source
# File lib/syntax_suggest/code_search.rb, line 100defcreate_blocks_from_untracked_linesmax_indent =frontier.next_indent_line&.indentwhile (line =frontier.next_indent_line)&& (line.indent==max_indent)@parse_blocks_from_indent_line.each_neighbor_block(frontier.next_indent_line)do|block|push(block,name:"add")endendend
Parses the most indented lines into blocks that are marked and added to the frontier
Source
# File lib/syntax_suggest/code_search.rb, line 112defexpand_existingblock =frontier.popreturnunlessblockrecord(block:block,name:"before-expand")block =@block_expand.call(block)push(block,name:"expand")end
Given an already existing block in the frontier, expand it to see if it contains our invalid syntax
Source
# File lib/syntax_suggest/code_search.rb, line 91defpush(block,name:)record(block:block,name:name)block.mark_invisibleifblock.valid?frontier<<blockend
Source
# File lib/syntax_suggest/code_search.rb, line 69defrecord(block:,name:"record")returnunless@record_dir@name_tick[name]+=1filename ="#{@write_count += 1}-#{name}-#{@name_tick[name]}-(#{block.starts_at}__#{block.ends_at}).txt"ifENV["SYNTAX_SUGGEST_DEBUG"]puts"\n\n==== #{filename} ===="puts"\n```#{block.starts_at}..#{block.ends_at}"putsblockputs"```"puts" block indent: #{block.current_indent}"end@record_dir.join(filename).open(mode:"a")do|f|document =DisplayCodeWithLineNumbers.new(lines:@code_lines.select(&:visible?),terminal:false,highlight_lines:block.lines ).callf.write(" Block lines: #{block.starts_at..block.ends_at} (#{name}) \n\n#{document}")endend
Used for debugging