Module: SyntaxSuggest
- Defined in:
- lib/syntax_suggest/api.rb,
lib/syntax_suggest/cli.rb,
lib/syntax_suggest/token.rb,
lib/syntax_suggest/version.rb,
lib/syntax_suggest/visitor.rb,
lib/syntax_suggest/core_ext.rb,
lib/syntax_suggest/code_line.rb,
lib/syntax_suggest/code_block.rb,
lib/syntax_suggest/code_search.rb,
lib/syntax_suggest/block_expand.rb,
lib/syntax_suggest/scan_history.rb,
lib/syntax_suggest/code_frontier.rb,
lib/syntax_suggest/mini_stringio.rb,
lib/syntax_suggest/clean_document.rb,
lib/syntax_suggest/explain_syntax.rb,
lib/syntax_suggest/priority_queue.rb,
lib/syntax_suggest/unvisited_lines.rb,
lib/syntax_suggest/around_block_scan.rb,
lib/syntax_suggest/capture_code_context.rb,
lib/syntax_suggest/capture_code_context.rb,
lib/syntax_suggest/pathname_from_message.rb,
lib/syntax_suggest/priority_engulf_queue.rb,
lib/syntax_suggest/display_invalid_blocks.rb,
lib/syntax_suggest/left_right_token_count.rb,
lib/syntax_suggest/capture/falling_indent_lines.rb,
lib/syntax_suggest/parse_blocks_from_indent_line.rb,
lib/syntax_suggest/display_code_with_line_numbers.rb,
lib/syntax_suggest/capture/before_after_keyword_ends.rb
Defined Under Namespace
Modules: Capture Classes: AroundBlockScan, BlockExpand, CaptureCodeContext, CleanDocument, Cli, CodeBlock, CodeFrontier, CodeLine, CodeSearch, DisplayCodeWithLineNumbers, DisplayInvalidBlocks, Error, ExplainSyntax, GetParseErrors, LeftRightTokenCount, MiniStringIO, ParseBlocksFromIndentLine, PathnameFromMessage, PriorityEngulfQueue, PriorityQueue, ScanHistory, Token, UnvisitedLines, Visitor
Constant Summary collapse
- DEFAULT_VALUE =
Used to indicate a default value that cannot be confused with another input.
Object.new.freeze
- TIMEOUT_DEFAULT =
ENV.fetch("SYNTAX_SUGGEST_TIMEOUT", 1).to_i
- VERSION =
"3.0.0"
Class Method Summary collapse
-
.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: DEFAULT_VALUE, timeout: TIMEOUT_DEFAULT, io: $stderr) ⇒ Object
SyntaxSuggest.call [Private].
-
.handle_error(e, re_raise: true, io: $stderr) ⇒ Object
SyntaxSuggest.handle_error [Public].
-
.invalid?(source) ⇒ Boolean
SyntaxSuggest.invalid? [Private].
-
.module_for_detailed_message ⇒ Object
SyntaxSuggest.module_for_detailed_message [Private].
-
.record_dir(dir) ⇒ Object
SyntaxSuggest.record_dir [Private].
-
.valid?(source) ⇒ Boolean
SyntaxSuggest.valid? [Private].
-
.valid_without?(without_lines:, code_lines:) ⇒ Boolean
SyntaxSuggest.valid_without? [Private].
Class Method Details
.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: DEFAULT_VALUE, timeout: TIMEOUT_DEFAULT, io: $stderr) ⇒ Object
SyntaxSuggest.call [Private]
Main private interface
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/syntax_suggest/api.rb', line 66 def self.call(source:, filename: DEFAULT_VALUE, terminal: DEFAULT_VALUE, record_dir: DEFAULT_VALUE, timeout: TIMEOUT_DEFAULT, io: $stderr) search = nil filename = nil if filename == DEFAULT_VALUE Timeout.timeout(timeout) do record_dir ||= ENV["DEBUG"] ? "tmp" : nil search = CodeSearch.new(source, record_dir: record_dir).call end blocks = search.invalid_blocks DisplayInvalidBlocks.new( io: io, blocks: blocks, filename: filename, terminal: terminal, code_lines: search.code_lines ).call rescue Timeout::Error => e io.puts "Search timed out SYNTAX_SUGGEST_TIMEOUT=#{timeout}, run with SYNTAX_SUGGEST_DEBUG=1 for more info" io.puts e.backtrace.first(3).join($/) end |
.handle_error(e, re_raise: true, io: $stderr) ⇒ Object
SyntaxSuggest.handle_error [Public]
Takes a SyntaxError exception, uses the
error message to locate the file. Then the file
will be analyzed to find the location of the syntax
error and emit that location to stderr.
Example:
begin
require 'bad_file'
rescue => e
SyntaxSuggest.handle_error(e)
end
By default it will re-raise the exception unless
re_raise: false. The message output location
can be configured using the io: $stderr input.
If a valid filename cannot be determined, the original
exception will be re-raised (even with
re_raise: false).
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/syntax_suggest/api.rb', line 43 def self.handle_error(e, re_raise: true, io: $stderr) unless e.is_a?(SyntaxError) io.puts("SyntaxSuggest: Must pass a SyntaxError, got: #{e.class}") raise e end file = PathnameFromMessage.new(e., io: io).call.name raise e unless file io.sync = true call( io: io, source: file.read, filename: file ) raise e if re_raise end |
.invalid?(source) ⇒ Boolean
SyntaxSuggest.invalid? [Private]
Opposite of SyntaxSuggest.valid?
130 131 132 133 134 135 |
# File 'lib/syntax_suggest/api.rb', line 130 def self.invalid?(source) source = source.join if source.is_a?(Array) source = source.to_s Prism.parse(source).failure? end |
.module_for_detailed_message ⇒ Object
SyntaxSuggest.module_for_detailed_message [Private]
Used to monkeypatch SyntaxError via Module.prepend
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/syntax_suggest/core_ext.rb', line 7 def self. Module.new { def (highlight: true, syntax_suggest: true, **kwargs) return super unless syntax_suggest require "syntax_suggest/api" unless defined?(SyntaxSuggest::DEFAULT_VALUE) = super if path file = Pathname.new(path) io = SyntaxSuggest::MiniStringIO.new SyntaxSuggest.call( io: io, source: file.read, filename: file, terminal: highlight ) annotation = io.string annotation += "\n" unless annotation.end_with?("\n") annotation + else end rescue => e if ENV["SYNTAX_SUGGEST_DEBUG"] $stderr.warn(e.) $stderr.warn(e.backtrace) end # Ignore internal errors end } end |
.record_dir(dir) ⇒ Object
SyntaxSuggest.record_dir [Private]
Used to generate a unique directory to record search steps for debugging
91 92 93 94 95 96 97 98 99 100 |
# File 'lib/syntax_suggest/api.rb', line 91 def self.record_dir(dir) time = Time.now.strftime("%Y-%m-%d-%H-%M-%s-%N") dir = Pathname(dir) dir.join(time).tap { |path| path.mkpath alias_dir = dir.join("last") FileUtils.rm_rf(alias_dir) if alias_dir.exist? FileUtils.ln_sf(time, alias_dir) } end |
.valid?(source) ⇒ Boolean
SyntaxSuggest.valid? [Private]
Returns truthy if a given input source is valid syntax
SyntaxSuggest.valid?(<<~EOM) # => true
def foo
end
EOM
SyntaxSuggest.valid?(<<~EOM) # => false
def foo
def bar # Syntax error here
end
EOM
You can also pass in an array of lines and they'll be joined before evaluating
SyntaxSuggest.valid?(
[
"def foo\n",
"end\n"
]
) # => true
SyntaxSuggest.valid?(
[
"def foo\n",
" def bar\n", # Syntax error here
"end\n"
]
) # => false
As an FYI the CodeLine class instances respond to to_s
so passing a CodeLine in as an object or as an array
will convert it to it's code representation.
173 174 175 |
# File 'lib/syntax_suggest/api.rb', line 173 def self.valid?(source) !invalid?(source) end |
.valid_without?(without_lines:, code_lines:) ⇒ Boolean
SyntaxSuggest.valid_without? [Private]
This will tell you if the code_lines would be valid
if you removed the without_lines. In short it's a
way to detect if we've found the lines with syntax errors
in our document yet.
code_lines = [
CodeLine.new(line: "def foo\n", index: 0)
CodeLine.new(line: " def bar\n", index: 1)
CodeLine.new(line: "end\n", index: 2)
]
SyntaxSuggest.valid_without?(
without_lines: code_lines[1],
code_lines: code_lines
) # => true
SyntaxSuggest.valid?(code_lines) # => false
121 122 123 124 125 |
# File 'lib/syntax_suggest/api.rb', line 121 def self.valid_without?(without_lines:, code_lines:) lines = code_lines - Array(without_lines).flatten lines.empty? || valid?(lines) end |