class Solargraph::SourceMap::Clip
A static analysis tool for obtaining definitions, Completions, signatures, and type inferences from a Cursor.
Attributes
@return [ApiMap]
@return [Source::Cursor]
Public Class Methods
Source
# File lib/solargraph/source_map/clip.rb, line 11 def initialize api_map, cursor @api_map = api_map @cursor = cursor closure_pin = closure closure_pin.rebind(api_map) if closure_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(closure_pin.receiver).contain?(cursor.range.start) end
@param api_map [ApiMap] @param cursor [Source::Cursor]
Public Instance Methods
Source
# File lib/solargraph/source_map/clip.rb, line 33 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? if cursor.comment? tag_complete else code_complete end end
@return [Completion]
Source
# File lib/solargraph/source_map/clip.rb, line 19 def define return [] if cursor.comment? || cursor.chain.literal? result = cursor.chain.define(api_map, closure, locals) result.concat file_global_methods 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
@return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor’s position
Source
# File lib/solargraph/source_map/clip.rb, line 74 def gates closure.gates end
@return [::Array<String>]
Source
# File lib/solargraph/source_map/clip.rb, line 52 def infer result = cursor.chain.infer(api_map, closure, locals) if result.tag == 'Class' # HACK: Exception to return BasicObject from Class#new dfn = cursor.chain.define(api_map, closure, locals).first return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new' end # should receive result with selfs resolved from infer() Solargraph.assert_or_log(:clip_infer_self, 'Received selfy inference') if result.selfy? result end
@return [ComplexType]
Source
# File lib/solargraph/source_map/clip.rb, line 69 def locals @locals ||= source_map.locals_at(location) end
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.
@return [::Array<Solargraph::Pin::LocalVariable>]
Source
# File lib/solargraph/source_map/clip.rb, line 45 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
@return [Array<Pin::Method>]
Source
# File lib/solargraph/source_map/clip.rb, line 80 def translate phrase chain = Parser.chain(Parser.parse(phrase)) chain.define(api_map, closure, locals) end
@param phrase [String] @return [Array<Solargraph::Pin::Base>]
Source
# File lib/solargraph/source_map/clip.rb, line 28 def types infer.namespaces.map { |namespace| api_map.get_path_pins(namespace) }.flatten end
@return [Array<Pin::Base>]
Private Instance Methods
Source
# File lib/solargraph/source_map/clip.rb, line 104 def closure @closure ||= source_map.locate_closure_pin(cursor.node_position.line, cursor.node_position.character) end
@return [Solargraph::Pin::Closure]
Source
# File lib/solargraph/source_map/clip.rb, line 170 def code_complete 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, closure, locals) result.concat api_map.get_complex_type_methods(type, closure.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(closure.binder.namespace, closure.binder.scope)) elsif cursor.word.start_with?('$') return package_completions(api_map.get_global_variable_pins) end result.concat locals result.concat file_global_methods unless closure.binder.namespace.empty? result.concat api_map.get_constants(context_pin.context.namespace, *gates) result.concat api_map.get_methods(closure.binder.namespace, scope: closure.binder.scope, visibility: [:public, :private, :protected]) result.concat api_map.get_methods('Kernel') result.concat api_map.keyword_pins.to_a end end package_completions(result) end
@return [Completion]
Source
# File lib/solargraph/source_map/clip.rb, line 116 def complete_keyword_parameters return [] unless cursor.argument? && cursor.chain.links.one? && cursor.word =~ /^[a-z0-9_]*:?$/ pins = signify result = [] done = [] pins.each do |pin| pin.parameters.each do |param| next if done.include?(param.name) done.push param.name next unless param.keyword? result.push Pin::KeywordParam.new(pin.location, "#{param.name}:") end if !pin.parameters.empty? && pin.parameters.last.kwrestarg? pin.docstring.tags(:param).each do |tag| next if done.include?(tag.name) done.push tag.name result.push Pin::KeywordParam.new(pin.location, "#{tag.name}:") end end end result end
@return [Array<Pin::KeywordParam>]
Source
# File lib/solargraph/source_map/clip.rb, line 111 def context_pin @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character) end
The context at the current position.
@return [Pin::Base]
Source
# File lib/solargraph/source_map/clip.rb, line 218 def file_global_methods return [] if cursor.word.empty? source_map.pins.select do |pin| pin.is_a?(Pin::Method) && pin.namespace == '' && pin.name.start_with?(cursor.word) end end
@return [Array<Pin::Base>]
Source
# File lib/solargraph/source_map/clip.rb, line 99 def location Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position)) end
@return [Location]
Source
# File lib/solargraph/source_map/clip.rb, line 141 def package_completions result frag_start = cursor.start_of_word.to_s.downcase filtered = result.uniq(&:name).select { |s| s.name.downcase.start_with?(frag_start) && (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i)) } Completion.new(filtered, cursor.range) end
@param result [Enumerable<Pin::Base>] @return [Completion]
Source
# File lib/solargraph/source_map/clip.rb, line 94 def source_map @source_map ||= api_map.source_map(cursor.filename) end
@return [SourceMap]
Source
# File lib/solargraph/source_map/clip.rb, line 151 def tag_complete result = [] match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i) if match full = match[1] if full.include?('::') if full.end_with?('::') result.concat api_map.get_constants(full[0..-3], *gates) else result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates) end else result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) } end end package_completions(result) end
@return [Completion]