class Solargraph::Source::SourceChainer


results for completion and definition queries.
location is inside a string or comment. ApiMaps use Fragments to provide
and signature, literal values at the base of signatures, and whether the
Information about a location in a source, including the location’s word

def chain source, position

Returns:
  • (Source::Chain) -

Parameters:
  • position (Position) --
  • source (Source) --
def chain source, position
  raise "Not a source" unless source.is_a?(Source)
  new(source, position).chain
end

def chain

Returns:
  • (Source::Chain) -
def chain
  return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
  # return Chain.new([Chain::UNDEFINED_CALL]) unless infer_literal_node_type(source.node_at(position.line, position.column)).nil?
  begin
    return Chain.new([]) if phrase.end_with?('..')
    if !source.repaired? && source.parsed?
      node = source.node_at(position.line, position.column)
    else
      node = nil
      node = source.node_at(fixed_position.line, fixed_position.column) unless source.error_ranges.any?{|r| r.include?(fixed_position)}
      node = Source.parse(fixed_phrase) if node.nil?
    end
  rescue Parser::SyntaxError
    return Chain.new([Chain::UNDEFINED_CALL])
  end
  return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
  chain = NodeChainer.chain(node, source.filename)
  if source.repaired? || !source.parsed?
    if end_of_phrase.strip == '.'
      chain.links.push Chain::UNDEFINED_CALL
    elsif end_of_phrase.strip == '::'
      chain.links.push Chain::UNDEFINED_CONSTANT
    end
  end
  chain
end

def character

Returns:
  • (Integer) -
def character
  @column
end

def end_of_phrase

Returns:
  • (String) -
def end_of_phrase
  @end_of_phrase ||= begin
    match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
    if match
      match[0]
    else
      ''
    end
  end
end

def fixed_phrase

Returns:
  • (String) -
def fixed_phrase
  @fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
end

def fixed_position

Returns:
  • (Position) -
def fixed_position
  @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
end

def get_offset line, column

Returns:
  • (Integer) -

Parameters:
  • column (Integer) --
  • line (Integer) --
def get_offset line, column
  Position.line_char_to_offset(@source.code, line, column)
end

def get_signature_data_at index

def get_signature_data_at index
  brackets = 0
  squares = 0
  parens = 0
  signature = ''
  index -=1
  in_whitespace = false
  while index >= 0
    pos = Position.from_offset(@source.code, index)
    break if index > 0 and @source.comment_at?(pos)
    unless !in_whitespace and string?
      break if brackets > 0 or parens > 0 or squares > 0
      char = @source.code[index, 1]
      break if char.nil? # @todo Is this the right way to handle this?
      if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
        in_whitespace = true
      else
        if brackets.zero? and parens.zero? and squares.zero? and in_whitespace
          unless char == '.' or @source.code[index+1..-1].strip.start_with?('.')
            old = @source.code[index+1..-1]
            nxt = @source.code[index+1..-1].lstrip
            index += (@source.code[index+1..-1].length - @source.code[index+1..-1].lstrip.length)
            break
          end
        end
        if char == ')'
          parens -=1
        elsif char == ']'
          squares -=1
        elsif char == '}'
          brackets -= 1
        elsif char == '('
          parens += 1
        elsif char == '{'
          brackets += 1
        elsif char == '['
          squares += 1
          signature = ".[]#{signature}" if parens.zero? and brackets.zero? and squares.zero? and @source.code[index-2] != '%'
        end
        if brackets.zero? and parens.zero? and squares.zero?
          break if ['"', "'", ',', ';', '%'].include?(char)
          signature = char + signature if char.match(/[a-z0-9:\._@\$\?\!]/i) and @source.code[index - 1] != '%'
          break if char == '$'
          if char == '@'
            signature = "@#{signature}" if @source.code[index-1, 1] == '@'
            break
          end
        elsif parens == 1 || brackets == 1 || squares == 1
          break
        end
        in_whitespace = false
      end
    end
    index -= 1
  end
  # @todo Smelly exceptional case for integer literals
  # match = signature.match(/^[0-9]+/)
  # if match
  #   index += match[0].length
  #   signature = signature[match[0].length..-1].to_s
  #   @base_literal = 'Integer'
  # # @todo Smelly exceptional case for array literals
  # elsif signature.start_with?('.[]')
  #   index += 2
  #   signature = signature[3..-1].to_s
  #   @base_literal = 'Array'
  # elsif signature.start_with?('.')
  #   pos = Position.from_offset(@source.code, index)
  #   node = @source.node_at(pos.line, pos.character)
  #   lit = infer_literal_node_type(node)
  #   unless lit.nil?
  #     signature = signature[1..-1].to_s
  #     index += 1
  #     @base_literal = lit
  #   end
  # end
  [index + 1, signature]
end

def initialize source, position

Parameters:
  • position (Position) --
  • source (Source) --
def initialize source, position
  @source = source
  # @source.code = source.code
  @position = position
  # @todo Get rid of line/column
  @line = position.line
  @column = position.column
  @calculated_literal = false
end

def offset

Returns:
  • (Integer) -
def offset
  @offset ||= get_offset(line, column)
end

def phrase

Returns:
  • (String) -
def phrase
  @phrase ||= source.code[signature_data[0]..offset-1]
end

def signature_data

def signature_data
  @signature_data ||= get_signature_data_at(offset)
end

def string?

Returns:
  • (Boolean) -
def string?
  # @string ||= (node.type == :str or node.type == :dstr)
  @string ||= @source.string_at?(position)
end