Class: Kapusta::LSP::WorkspaceIndex

Inherits:
Object
  • Object
show all
Defined in:
lib/kapusta/lsp/workspace_index.rb

Defined Under Namespace

Classes: Entry

Constant Summary collapse

MACRO_MODULE_EXTENSIONS =
%w[kapm kap].freeze
SCAN_EXTENSIONS =
%w[kap kapm].freeze

Instance Method Summary collapse

Constructor Details

#initialize(roots: []) ⇒ WorkspaceIndex

Returns a new instance of WorkspaceIndex.



15
16
17
18
# File 'lib/kapusta/lsp/workspace_index.rb', line 15

def initialize(roots: [])
  @roots = Array(roots)
  @entries = {}
end

Instance Method Details

#constant_definition_with_prefix?(prefix, except_prefix: nil) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
107
108
109
110
111
112
113
# File 'lib/kapusta/lsp/workspace_index.rb', line 104

def constant_definition_with_prefix?(prefix, except_prefix: nil)
  @entries.any? do |_uri, entry|
    entry.walker.bindings.any? do |b|
      next false unless %i[module class].include?(b.kind)
      next false if except_prefix && matches_prefix?(b.sym, except_prefix)

      matches_prefix?(b.sym, prefix)
    end
  end
end

#constant_definitions_with_prefix(prefix) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/kapusta/lsp/workspace_index.rb', line 64

def constant_definitions_with_prefix(prefix)
  result = []
  @entries.each do |uri, entry|
    entry.walker.bindings.each do |b|
      next unless %i[module class].include?(b.kind)

      segs = b.sym.dotted? ? b.sym.segments : [b.sym.name]
      result << [uri, b] if segs == prefix
    end
  end
  result
end

#constant_occurrences(prefix) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/kapusta/lsp/workspace_index.rb', line 145

def constant_occurrences(prefix)
  result = {}
  @entries.each do |uri, entry|
    occs = []
    entry.walker.bindings.each do |b|
      next unless %i[module class].include?(b.kind)

      occs << b if matches_prefix?(b.sym, prefix)
    end
    entry.walker.references.each do |r|
      sym = r.sym
      next unless sym.is_a?(Sym)
      next unless r.target.nil?
      next unless first_segment_capitalized?(sym)

      occs << r if matches_prefix?(sym, prefix)
    end
    result[uri] = occs unless occs.empty?
  end
  result
end

#each_entryObject



115
116
117
# File 'lib/kapusta/lsp/workspace_index.rb', line 115

def each_entry(&)
  @entries.each(&)
end

#entry(uri) ⇒ Object



46
47
48
# File 'lib/kapusta/lsp/workspace_index.rb', line 46

def entry(uri)
  @entries[uri]
end

#entry_countObject



50
51
52
# File 'lib/kapusta/lsp/workspace_index.rb', line 50

def entry_count
  @entries.length
end

#find_macro_definition(importing_uri, module_label, import_key) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/kapusta/lsp/workspace_index.rb', line 119

def find_macro_definition(importing_uri, module_label, import_key)
  target_name = import_key.to_s.tr('_', '-')
  resolve_module_uris(importing_uri, module_label).each do |uri|
    entry = @entries[uri]
    next unless entry

    binding = entry.walker.bindings.find do |b|
      %i[macro toplevel_fn].include?(b.kind) && b.name == target_name
    end
    return [uri, binding] if binding
  end
  nil
end

#import_resolves_to?(importing_uri, module_label, target_uri) ⇒ Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/kapusta/lsp/workspace_index.rb', line 133

def import_resolves_to?(importing_uri, module_label, target_uri)
  resolve_module_uris(importing_uri, module_label).include?(target_uri)
end

#macro_definition_anywhere?(name, except_uri: nil) ⇒ Boolean

Returns:

  • (Boolean)


137
138
139
140
141
142
143
# File 'lib/kapusta/lsp/workspace_index.rb', line 137

def macro_definition_anywhere?(name, except_uri: nil)
  @entries.any? do |uri, entry|
    next false if except_uri && uri == except_uri

    entry.walker.bindings.any? { |b| b.kind == :macro && b.name == name }
  end
end

#refresh(uri, text) ⇒ Object



33
34
35
# File 'lib/kapusta/lsp/workspace_index.rb', line 33

def refresh(uri, text)
  store(uri, text)
end

#remove(uri) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/kapusta/lsp/workspace_index.rb', line 37

def remove(uri)
  path = uri_to_path(uri)
  if path && File.file?(path)
    store(uri, File.read(path))
  else
    @entries.delete(uri)
  end
end

#scan!Object



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/kapusta/lsp/workspace_index.rb', line 20

def scan!
  @roots.each do |root|
    SCAN_EXTENSIONS.each do |ext|
      Dir.glob(File.join(root, '**', "*.#{ext}")).each do |path|
        uri = path_to_uri(path)
        text = File.read(path)
        store(uri, text)
      end
    end
  end
  self
end

#toplevel_definition?(name, except_name: nil) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
96
97
98
99
100
101
102
# File 'lib/kapusta/lsp/workspace_index.rb', line 93

def toplevel_definition?(name, except_name: nil)
  @entries.any? do |_uri, entry|
    entry.walker.bindings.any? do |b|
      next false unless file_toplevel_binding?(b)
      next false if except_name && b.name == except_name

      b.name == name
    end
  end
end

#toplevel_fn_definitions(name) ⇒ Object



54
55
56
57
58
59
60
61
62
# File 'lib/kapusta/lsp/workspace_index.rb', line 54

def toplevel_fn_definitions(name)
  result = []
  @entries.each do |uri, entry|
    entry.walker.bindings.each do |b|
      result << [uri, b] if b.kind == :toplevel_fn && b.name == name
    end
  end
  result
end

#toplevel_fn_occurrences(name) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/kapusta/lsp/workspace_index.rb', line 77

def toplevel_fn_occurrences(name)
  result = {}
  @entries.each do |uri, entry|
    occs = entry.walker.bindings.select do |b|
      b.kind == :toplevel_fn && b.name == name
    end
    occs += entry.walker.references.select do |r|
      next false unless r.sym.is_a?(Sym) && !r.sym.dotted? && r.name == name

      r.target.nil? || (r.target.kind == :toplevel_fn && r.target.name == name)
    end
    result[uri] = occs unless occs.empty?
  end
  result
end