Class: Solargraph::SourceMap::Clip

Inherits:
Object
  • Object
show all
Defined in:
lib/solargraph/source_map/clip.rb

Overview

A static analysis tool for obtaining definitions, completions, signatures, and type inferences from a cursor.

Instance Method Summary collapse

Constructor Details

#initialize(api_map, cursor) ⇒ Clip

Returns a new instance of Clip.

Parameters:



11
12
13
14
# File 'lib/solargraph/source_map/clip.rb', line 11

def initialize api_map, cursor
  @api_map = api_map
  @cursor = cursor
end

Instance Method Details

#completeCompletion

Returns:



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/solargraph/source_map/clip.rb', line 25

def complete
  return package_completions([]) if !source_map.source.parsed? || cursor.string?
  return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
  return Completion.new([], cursor.range) if cursor.chain.literal? || cursor.comment?
  result = []
  result.concat complete_keyword_parameters
  if cursor.chain.constant? || cursor.start_of_constant?
    full = cursor.chain.links.first.word
    type = if cursor.chain.undefined?
      cursor.chain.base.infer(api_map, context_pin, locals)
    else
      if full.include?('::') && cursor.chain.links.length == 1
        ComplexType.try_parse(full.split('::')[0..-2].join('::'))
      elsif cursor.chain.links.length > 1
        ComplexType.try_parse(full)
      else
        ComplexType::UNDEFINED
      end
    end
    if type.undefined?
      if full.include?('::')
        result.concat api_map.get_constants(full, *gates)
      else
        result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
      end
    else
      result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
    end
  else
    type = cursor.chain.base.infer(api_map, block, locals)
    result.concat api_map.get_complex_type_methods(type, block.binder.namespace, cursor.chain.links.length == 1)
    if cursor.chain.links.length == 1
      if cursor.word.start_with?('@@')
        return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
      elsif cursor.word.start_with?('@')
        return package_completions(api_map.get_instance_variable_pins(block.binder.namespace, block.binder.scope))
      elsif cursor.word.start_with?('$')
        return package_completions(api_map.get_global_variable_pins)
      end
      result.concat locals
      result.concat api_map.get_constants(context_pin.context.namespace, *gates)
      result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
      result.concat api_map.get_methods('Kernel')
      result.concat ApiMap.keywords
      result.concat yielded_self_pins
    end
  end
  package_completions(result)
end

#defineArray<Pin::Base>

Returns:



17
18
19
20
21
22
# File 'lib/solargraph/source_map/clip.rb', line 17

def define
  return [] if cursor.comment? || cursor.chain.literal?
  result = cursor.chain.define(api_map, block, locals)
  result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
  result
end

#gatesObject



102
103
104
# File 'lib/solargraph/source_map/clip.rb', line 102

def gates
  block.gates
end

#in_block?Boolean

Returns:

  • (Boolean)


106
107
108
109
110
111
112
# File 'lib/solargraph/source_map/clip.rb', line 106

def in_block?
  return @in_block unless @in_block.nil?
  @in_block = begin
    tree = cursor.source.tree_at(cursor.position.line, cursor.position.column)
    Parser.is_ast_node?(tree[1]) && [:block, :ITER].include?(tree[1].type)
  end
end

#inferComplexType

Returns:



83
84
85
86
87
# File 'lib/solargraph/source_map/clip.rb', line 83

def infer
  result = cursor.chain.infer(api_map, block, locals)
  return result unless result.tag == 'self'
  ComplexType.try_parse(cursor.chain.base.infer(api_map, block, locals).namespace)
end

#localsArray<Solargraph::Pin::Base>

Get an array of all the locals that are visible from the cursors’s position. Locals can be local variables, method parameters, or block parameters. The array starts with the nearest local pin.

Returns:



94
95
96
97
98
99
100
# File 'lib/solargraph/source_map/clip.rb', line 94

def locals
  loc_pos = context_pin.location.range.contain?(cursor.position) ? cursor.position : context_pin.location.range.ending
  adj_pos = Position.new(loc_pos.line, (loc_pos.column.zero? ? 0 : loc_pos.column - 1))
  @locals ||= source_map.locals.select { |pin|
    pin.visible_from?(block, adj_pos)
  }.reverse
end

#signifyArray<Pin::Base>

Returns:



76
77
78
79
80
# File 'lib/solargraph/source_map/clip.rb', line 76

def signify
  return [] unless cursor.argument?
  chain = Parser.chain(cursor.recipient_node, cursor.filename)
  chain.define(api_map, context_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
end