class Solargraph::Source
A Ruby file that has been parsed into an AST.
Constants
- FOLDING_NODE_TYPES
Attributes
@return [Hash{Integer => String}
@return [Array<Range>]
@return [String, nil]
@return [Parser::AST::Node, nil]
@return [Boolean]
@return [String]
@return [Boolean]
@todo Deprecate? @return [Integer]
Public Class Methods
Source
# File lib/solargraph/source.rb, line 470 def load filename file = File.open(filename) code = file.read file.close Source.load_string(code, filename) end
@param filename [String] @return [Solargraph::Source]
Source
# File lib/solargraph/source.rb, line 481 def load_string code, filename = nil, version = 0 Source.new code, filename, version end
@param code [String] @param filename [String, nil] @param version [Integer] @return [Solargraph::Source]
Source
# File lib/solargraph/source.rb, line 46 def initialize code, filename = nil, version = 0 @code = normalize(code) @repaired = code @filename = filename @version = version end
@param code [String] @param filename [String, nil] @param version [Integer]
Source
# File lib/solargraph/source.rb, line 487 def parse_docstring comments # HACK: Pass a dummy code object to the parser for plugins that # expect it not to be nil YARD::Docstring.parser.parse(comments, YARD::CodeObjects::Base.new(:root, 'stub')) rescue StandardError => e Solargraph.logger.info "YARD failed to parse docstring: [#{e.class}] #{e.message}" Solargraph.logger.debug "Unparsed comment: #{comments}" YARD::Docstring.parser end
@param comments [String] @return [YARD::DocstringParser]
Public Instance Methods
Source
# File lib/solargraph/source.rb, line 236 def associated_comments @associated_comments ||= begin # @type [Hash{Integer => String}] result = {} buffer = String.new('') # @type [Integer, nil] last = nil comments.each_pair do |num, snip| if !last || num == last + 1 buffer.concat "#{snip.text}\n" else result[first_not_empty_from(last + 1)] = buffer.clone buffer.replace "#{snip.text}\n" end last = num end result[first_not_empty_from(last + 1)] = buffer unless buffer.empty? || last.nil? result end end
Get a hash of comments grouped by the line numbers of the associated code.
@return [Hash{Integer => String}]
Source
# File lib/solargraph/source.rb, line 55 def at range from_to range.start.line, range.start.character, range.ending.line, range.ending.character end
@param range [Solargraph::Range] @return [String]
Source
# File lib/solargraph/source.rb, line 22 def code finalize @code end
@return [String]
Source
# File lib/solargraph/source.rb, line 182 def code_for(node) rng = Range.from_node(node) b = Position.line_char_to_offset(code, rng.start.line, rng.start.column) e = Position.line_char_to_offset(code, rng.ending.line, rng.ending.column) frag = code[b..e-1].to_s frag.strip.gsub(/,$/, '') end
@param node [Parser::AST::Node] @return [String]
Source
# File lib/solargraph/source.rb, line 160 def comment_at? position comment_ranges.each do |range| return true if range.include?(position) || (range.ending.line == position.line && range.ending.column < position.column) break if range.ending.line > position.line end false end
@param position [Position] @return [Boolean]
Source
# File lib/solargraph/source.rb, line 34 def comments finalize @comments end
@return [Hash{Integer => Solargraph::Parser::Snippet}]
Source
# File lib/solargraph/source.rb, line 192 def comments_for node rng = Range.from_node(node) stringified_comments[rng.start.line] ||= begin buff = associated_comments[rng.start.line] buff ? stringify_comment_array(buff) : nil end end
@param node [Parser::AST::Node] @return [String, nil]
Source
# File lib/solargraph/source.rb, line 113 def cursor_at position finalize Cursor.new(self, position) end
@param position [Position, Array(Integer, Integer)] @return [Source::Cursor]
Source
# File lib/solargraph/source.rb, line 176 def error_ranges @error_ranges ||= [] end
@return [Array<Range>]
Source
# File lib/solargraph/source.rb, line 220 def folding_ranges @folding_ranges ||= begin result = [] inner_folding_ranges node, result result.concat foldable_comment_block_ranges result end end
Get an array of ranges that can be folded, e.g., the range of a class definition or an if condition.
See FOLDING_NODE_TYPES for the list of node types that can be folded.
@return [Array<Range>]
Source
# File lib/solargraph/source.rb, line 64 def from_to l1, c1, l2, c2 b = Solargraph::Position.line_char_to_offset(code, l1, c1) e = Solargraph::Position.line_char_to_offset(code, l2, c2) code[b..e-1] end
@param l1 [Integer] @param c1 [Integer] @param l2 [Integer] @param c2 [Integer] @return [String]
Source
# File lib/solargraph/source.rb, line 203 def location st = Position.new(0, 0) en = Position.from_offset(code, code.length) range = Range.new(st, en) Location.new(filename, range) end
A location representing the file in its entirety.
@return [Location]
Source
# File lib/solargraph/source.rb, line 28 def node finalize @node end
@return [Parser::AST::Node, nil]
Source
# File lib/solargraph/source.rb, line 75 def node_at(line, column) tree_at(line, column).first end
Get the nearest node that contains the specified index.
@param line [Integer] @param column [Integer] @return [AST::Node]
Source
# File lib/solargraph/source.rb, line 119 def parsed? finalize @parsed end
@return [Boolean]
Source
# File lib/solargraph/source.rb, line 171 def references name Parser.references self, name end
@param name [String] @return [Array<Location>]
Source
# File lib/solargraph/source.rb, line 130 def string_at? position return false if Position.to_offset(code, position) >= code.length string_nodes.each do |node| range = Range.from_node(node) next if range.ending.line < position.line break if range.ending.line > position.line return true if node.type == :str && range.include?(position) && range.start != position return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position if node.type == :dstr inner = node_at(position.line, position.column) next if inner.nil? inner_range = Range.from_node(inner) next unless range.include?(inner_range.ending) return true if inner.type == :str inner_code = at(Solargraph::Range.new(inner_range.start, position)) return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') || (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}')) end break if range.ending.line > position.line end false end
@param position [Position] @return [Boolean]
Source
# File lib/solargraph/source.rb, line 154 def string_ranges @string_ranges ||= Parser.string_ranges(node) end
@return [::Array<Range>]
Source
# File lib/solargraph/source.rb, line 97 def synchronize updater raise 'Invalid synchronization' unless updater.filename == filename real_code = updater.write(@code) if real_code == @code @version = updater.version return self end Source.new(@code, filename, updater.version).tap do |src| src.repaired = @repaired src.error_ranges.concat error_ranges src.changes.concat(changes + updater.changes) end end
Source
# File lib/solargraph/source.rb, line 85 def tree_at(line, column) position = Position.new(line, column) stack = [] inner_tree_at node, position, stack stack end
Get an array of nodes containing the specified index, starting with the nearest node and ending with the root.
@param line [Integer] @param column [Integer] @return [Array<AST::Node>]
Protected Instance Methods
Source
# File lib/solargraph/source.rb, line 380 def changes @changes ||= [] end
@return [Array<Change>]
Source
# File lib/solargraph/source.rb, line 430 def code=(val) @code_lines = nil @finalized = false @code = val end
@param val [String] @return [String]
Source
# File lib/solargraph/source.rb, line 391 def finalize return if @finalized && changes.empty? changes.each do |change| @code = change.write(@code) end @finalized = true begin @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename) @parsed = true @repaired = @code rescue Parser::SyntaxError, EncodingError => e @node = nil @comments = {} @parsed = false ensure @code.freeze end if !@parsed && !changes.empty? changes.each do |change| @repaired = change.repair(@repaired) end error_ranges.concat(changes.map(&:range)) begin @node, @comments = Solargraph::Parser.parse_with_comments(@repaired, filename) @parsed = true rescue Parser::SyntaxError, EncodingError => e @node = nil @comments = {} @parsed = false end elsif @parsed error_ranges.clear end changes.clear end
@return [void]
Source
# File lib/solargraph/source.rb, line 446 def repaired finalize @repaired end
@return [String]
Private Instance Methods
Source
# File lib/solargraph/source.rb, line 463 def code_lines @code_lines ||= code.lines end
@return [Array<String>]
Source
# File lib/solargraph/source.rb, line 322 def comment_ranges @comment_ranges ||= comments.values.map(&:range) end
@return [Array<Solargraph::Range>]
Source
# File lib/solargraph/source.rb, line 261 def first_not_empty_from line cursor = line cursor += 1 while cursor < code_lines.length && code_lines[cursor].strip.empty? cursor = line if cursor > code_lines.length - 1 cursor end
@param line [Integer] @return [Integer]
Source
# File lib/solargraph/source.rb, line 330 def foldable_comment_block_ranges return [] unless synchronized? result = [] grouped = [] comments.keys.each do |l| if grouped.empty? || l == grouped.last + 1 grouped.push l else result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3 grouped = [l] end end result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3 result end
Get an array of foldable comment block ranges. Blocks are excluded if they are less than 3 lines long.
@return [Array<Range>]
Source
# File lib/solargraph/source.rb, line 272 def inner_folding_ranges top, result = [], parent = nil return unless Parser.is_ast_node?(top) if FOLDING_NODE_TYPES.include?(top.type) range = Range.from_node(top) if result.empty? || range.start.line > result.last.start.line result.push range unless range.ending.line - range.start.line < 2 end end top.children.each do |child| inner_folding_ranges(child, result, top.type) end end
@param top [Parser::AST::Node] @param result [Array<Range>] @param parent [Symbol, nil] @return [void]
Source
# File lib/solargraph/source.rb, line 364 def inner_tree_at node, position, stack return if node.nil? here = Range.from_node(node) if here.contain?(position) stack.unshift node node.children.each do |c| next unless Parser.is_ast_node?(c) next if c.loc.expression.nil? inner_tree_at(c, position, stack) end end end
@param node [Parser::AST::Node, nil] @param position [Position] @param stack [Array<Parser::AST::Node>] @return [void]
Source
# File lib/solargraph/source.rb, line 317 def string_nodes @string_nodes ||= string_nodes_in(node) end
@return [Array<Parser::AST::Node>]
Source
# File lib/solargraph/source.rb, line 348 def string_nodes_in n result = [] if Parser.is_ast_node?(n) if n.type == :str || n.type == :dstr || n.type == :STR || n.type == :DSTR result.push n else n.children.each{ |c| result.concat string_nodes_in(c) } end end result end
@param n [Parser::AST::Node, nil] @return [Array<Parser::AST::Node>]
Source
# File lib/solargraph/source.rb, line 312 def stringified_comments @stringified_comments ||= {} end
A hash of line numbers and their associated comments.
@return [Hash{Integer => Array<String>, nil}]
Source
# File lib/solargraph/source.rb, line 289 def stringify_comment_array comments ctxt = String.new('') started = false skip = nil comments.lines.each { |l| # Trim the comment and minimum leading whitespace p = l.force_encoding('UTF-8').encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '') if p.strip.empty? next unless started ctxt.concat p else here = p.index(/[^ \t]/) skip = here if skip.nil? || here < skip ctxt.concat p[skip..-1] end started = true } ctxt end
Get a string representation of an array of comments.
@param comments [String] @return [String]