Module: SyntaxSuggest
- Defined in:
- lib/syntax_suggest/api.rb,
lib/syntax_suggest/cli.rb,
lib/syntax_suggest/lex_all.rb,
lib/syntax_suggest/version.rb,
lib/syntax_suggest/core_ext.rb,
lib/syntax_suggest/code_line.rb,
lib/syntax_suggest/lex_value.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/ripper_errors.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/left_right_lex_count.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/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, LeftRightLexCount, LexAll, LexValue, MiniStringIO, ParseBlocksFromIndentLine, PathnameFromMessage, PriorityEngulfQueue, PriorityQueue, RipperErrors, ScanHistory, UnvisitedLines
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 =
"2.0.2"
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
-
.module_for_detailed_message ⇒ Object
SyntaxSuggest.module_for_detailed_message [Private].
-
.record_dir(dir) ⇒ Object
SyntaxSuggest.record_dir [Private].
-
.use_prism_parser? ⇒ Boolean
SyntaxSuggest.use_prism_parser? [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
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/syntax_suggest/api.rb', line 91 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`).
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/syntax_suggest/api.rb', line 68 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
160 161 162 163 164 165 |
# File 'lib/syntax_suggest/api.rb', line 160 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
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 45 46 |
# File 'lib/syntax_suggest/core_ext.rb', line 9 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
116 117 118 119 120 121 122 123 124 125 |
# File 'lib/syntax_suggest/api.rb', line 116 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 |
.use_prism_parser? ⇒ Boolean
SyntaxSuggest.use_prism_parser? [Private]
Tells us if the prism parser is available for use or if we should fallback to ‘Ripper`
42 43 44 |
# File 'lib/syntax_suggest/api.rb', line 42 def self.use_prism_parser? defined?(Prism) 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.
211 212 213 |
# File 'lib/syntax_suggest/api.rb', line 211 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
146 147 148 149 150 151 152 153 154 |
# File 'lib/syntax_suggest/api.rb', line 146 def self.valid_without?(without_lines:, code_lines:) lines = code_lines - Array(without_lines).flatten if lines.empty? true else valid?(lines) end end |