Class: Hind::LSIF::Generator

Inherits:
Object
  • Object
show all
Defined in:
lib/hind/lsif/generator.rb

Constant Summary collapse

LSIF_VERSION =
'0.4.3'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(metadata = {}) ⇒ Generator

Returns a new instance of Generator.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/hind/lsif/generator.rb', line 19

def initialize( = {})
  @vertex_id = [:vertex_id] || 1
  @metadata = {
    language: 'ruby',
    projectRoot: File.expand_path([:projectRoot] || Dir.pwd)
  }.merge()

  # Reset the global state when initializing a new generator
  GlobalState.instance.reset
  @document_ids = {}
  @current_document_id = nil
  @lsif_data = []
  @current_uri = nil
  @last_vertex_id = @vertex_id
  @last_reference_index = 0
  @initial_data = []
  @initial_data_emitted = false
end

Instance Attribute Details

#current_uriObject (readonly)

Returns the value of attribute current_uri.



17
18
19
# File 'lib/hind/lsif/generator.rb', line 17

def current_uri
  @current_uri
end

#document_idObject (readonly)

Returns the value of attribute document_id.



17
18
19
# File 'lib/hind/lsif/generator.rb', line 17

def document_id
  @document_id
end

#metadataObject (readonly)

Returns the value of attribute metadata.



17
18
19
# File 'lib/hind/lsif/generator.rb', line 17

def 
  @metadata
end

Instance Method Details

#collect_file_declarations(content, uri) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/hind/lsif/generator.rb', line 77

def collect_file_declarations(content, uri)
  @current_uri = uri
  result = Prism.parse(content)

  declaration_visitor = DeclarationVisitor.new(self, uri)
  result.value.accept(declaration_visitor)

  {lsif_data: @lsif_data - @initial_data}
ensure
  @current_uri = nil
end

#execute(files, options) ⇒ Object



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
74
75
# File 'lib/hind/lsif/generator.rb', line 38

def execute(files, options)
  # We need to ensure metadata/project vertices are the very first ones.
  # If we collect declarations first, we might emit vertices.
  # So we should initialize project first.

  unless @initial_data_emitted
    initialize_project
    @initial_data_emitted = true
    # Ensure these are at the start of @lsif_data
    # specific logic: if we just added them, they are at the end (idx 0 if empty)
    # but if we called collect_declarations separately?
    # Actually, execute is the main entry point. @lsif_data is empty approx.
  end

  # First pass: Declarations
  files.each do |file|
    @document_id = nil # Reset for each file
    absolute_path = File.join(@metadata[:projectRoot], file)
    next unless File.exist?(absolute_path)

    source = File.read(absolute_path)
    collect_file_declarations(source, file)
  end

  # Second pass: References
  files.each do |file|
    @document_id = nil # Reset for each file
    absolute_path = File.join(@metadata[:projectRoot], file)
    next unless File.exist?(absolute_path)

    source = File.read(absolute_path)
    process_file(content: source, uri: file)
  end

  finalize_document_state

  @lsif_data
end

#get_initial_dataObject



106
107
108
# File 'lib/hind/lsif/generator.rb', line 106

def get_initial_data
  @initial_data
end

#process_file(content:, uri:) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/hind/lsif/generator.rb', line 89

def process_file(content:, uri:)
  @current_uri = uri
  setup_document if @document_id.nil? || @document_ids[uri].nil?
  @document_id = @document_ids[uri]
  @current_document_id = @document_id

  result = Prism.parse(content)

  reference_visitor = ReferenceVisitor.new(self, uri)
  result.value.accept(reference_visitor)

  finalize_document_state
  @lsif_data
ensure
  @current_uri = nil
end

#register_class_declaration(declaration) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/hind/lsif/generator.rb', line 110

def register_class_declaration(declaration)
  return unless @current_uri && declaration[:node]

  qualified_name = declaration[:name]

  setup_document if @document_id.nil?
  current_doc_id = @document_id

  range_location = declaration[:range_location] || declaration[:node].constant_path.location
  range_id = create_range(range_location)
  return unless range_id

  result_set_id = emit_vertex('resultSet')
  emit_edge('next', range_id, result_set_id)

  def_result_id = emit_vertex('definitionResult')
  emit_edge('textDocument/definition', result_set_id, def_result_id)

  emit_edge('item', def_result_id, [range_id], 'definitions', current_doc_id)

  hover_content = generate_class_hover_content(declaration)
  hover_id = emit_vertex('hoverResult', {
    contents: [{
      language: 'ruby',
      value: hover_content
    }]
  })
  emit_edge('textDocument/hover', result_set_id, hover_id)

  declaration[:range_id] = range_id
  declaration[:result_set_id] = result_set_id
  declaration[:document_id] = current_doc_id
  declaration[:file] = @current_uri

  GlobalState.instance.add_class(qualified_name, declaration)

  result_set_id
end

#register_constant_declaration(declaration) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/hind/lsif/generator.rb', line 188

def register_constant_declaration(declaration)
  return unless @current_uri && declaration[:node]

  qualified_name = declaration[:name]

  setup_document if @document_id.nil?
  current_doc_id = @document_id

  range_id = create_range(declaration[:node].name_loc)
  return unless range_id

  result_set_id = emit_vertex('resultSet')
  emit_edge('next', range_id, result_set_id)

  def_result_id = emit_vertex('definitionResult')
  emit_edge('textDocument/definition', result_set_id, def_result_id)

  emit_edge('item', def_result_id, [range_id], 'definitions', current_doc_id)

  hover_content = generate_constant_hover_content(declaration)
  hover_id = emit_vertex('hoverResult', {
    contents: [{
      language: 'ruby',
      value: hover_content
    }]
  })
  emit_edge('textDocument/hover', result_set_id, hover_id)

  declaration[:range_id] = range_id
  declaration[:result_set_id] = result_set_id
  declaration[:document_id] = current_doc_id
  declaration[:file] = @current_uri

  GlobalState.instance.add_constant(qualified_name, declaration)

  result_set_id
end

#register_method_declaration(declaration) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/hind/lsif/generator.rb', line 226

def register_method_declaration(declaration)
  return unless @current_uri && declaration[:node]

  qualified_name = declaration[:name]

  setup_document if @document_id.nil?
  current_doc_id = @document_id

  loc = declaration[:node].respond_to?(:name_loc) ? declaration[:node].name_loc : declaration[:node].location
  range_id = create_range(loc)
  return unless range_id

  result_set_id = emit_vertex('resultSet')
  emit_edge('next', range_id, result_set_id)

  def_result_id = emit_vertex('definitionResult')
  emit_edge('textDocument/definition', result_set_id, def_result_id)

  emit_edge('item', def_result_id, [range_id], 'definitions', current_doc_id)

  hover_id = emit_vertex('hoverResult', {
    contents: [{
      language: 'ruby',
      value: "def #{declaration[:name].split('#').last}"
    }]
  })
  emit_edge('textDocument/hover', result_set_id, hover_id)

  declaration[:range_id] = range_id
  declaration[:result_set_id] = result_set_id
  declaration[:document_id] = current_doc_id
  declaration[:file] = @current_uri

  GlobalState.instance.add_method(qualified_name, declaration)

  result_set_id
end

#register_module_declaration(declaration) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/hind/lsif/generator.rb', line 149

def register_module_declaration(declaration)
  return unless @current_uri && declaration[:node]

  qualified_name = declaration[:name]

  setup_document if @document_id.nil?
  current_doc_id = @document_id

  range_location = declaration[:range_location] || declaration[:node].constant_path.location
  range_id = create_range(range_location)
  return unless range_id

  result_set_id = emit_vertex('resultSet')
  emit_edge('next', range_id, result_set_id)

  def_result_id = emit_vertex('definitionResult')
  emit_edge('textDocument/definition', result_set_id, def_result_id)

  emit_edge('item', def_result_id, [range_id], 'definitions', current_doc_id)

  hover_content = generate_module_hover_content(declaration)
  hover_id = emit_vertex('hoverResult', {
    contents: [{
      language: 'ruby',
      value: hover_content
    }]
  })
  emit_edge('textDocument/hover', result_set_id, hover_id)

  declaration[:range_id] = range_id
  declaration[:result_set_id] = result_set_id
  declaration[:document_id] = current_doc_id
  declaration[:file] = @current_uri

  GlobalState.instance.add_module(qualified_name, declaration)

  result_set_id
end

#register_reference(reference) ⇒ Object



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/hind/lsif/generator.rb', line 264

def register_reference(reference)
  return unless @current_uri && reference[:node]
  return unless GlobalState.instance.has_declaration?(reference[:name])

  setup_document if @document_id.nil?
  current_doc_id = @document_id

  range_id = create_range(reference[:node].location)
  return unless range_id

  # Get the primary declaration for this reference
  declaration = GlobalState.instance.get_declaration(reference[:name])
  return unless declaration && declaration[:result_set_id]

  GlobalState.instance.add_reference(reference[:name], @current_uri, range_id, current_doc_id)
  emit_edge('next', range_id, declaration[:result_set_id])

  reference_result = emit_vertex('referenceResult')
  emit_edge('textDocument/references', declaration[:result_set_id], reference_result)
  emit_edge('item', reference_result, [range_id], 'references', @document_id)
end