hind 0.1.15 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67b64fd17d7735528e37b9098db56f71a5332e01e58e9dfd958052da1b68e220
4
- data.tar.gz: 7d5ab4b8b54fd439be53eba3f40df928ea35852d321945f972b09bfad5a4de24
3
+ metadata.gz: ba0a23c04400d06ebf294a87558c5893fb195b0e477acf49772598827f1afdba
4
+ data.tar.gz: a213c39aa228dd18612d45b85a1087aaec375ba3ba2477dc5dd7ff14dd0a094a
5
5
  SHA512:
6
- metadata.gz: 462b167b1073fcdbe74dc9d1731e07b068a5b49c9f13e1204f7a8c58925a972dfef541f28388ed163efa59b8057df2f535f46ced8fdeb0e76308a505e58231fb
7
- data.tar.gz: '035070842f07d55edc194ec60b8210858e01a68b8261f444c4e1c6af5d8418e5436ebc8a8aca071dbf608ba0baabdce3ae6b7d08adbf12e05317eeb0bb4387d7'
6
+ metadata.gz: d806daccb7faa4378c8bd644ff094b6fb8dda612ecaae3536cdf5f2e6e6551ebbdd0d5de35612daa4a7e9727c2e51fee44c6a0fe029882397f19dbbda9a15cae
7
+ data.tar.gz: a0586d0ec3f980ae369138fd712fe670162be4ac6444f495fb8c414253fcfd251df4c4ccec80988305178ff20ddbb93034bbe1b812058b752b8a9fe14e31d66e
data/lib/hind/cli.rb CHANGED
@@ -84,7 +84,7 @@ module Hind
84
84
  def scip(dir = options[:directory] || '.')
85
85
  validate_directory(dir)
86
86
  validate_output_file(options[:output], options[:force])
87
-
87
+
88
88
  files = find_files(dir, options[:glob], options[:exclude])
89
89
  abort "No files found matching pattern '#{options[:glob]}' in #{dir}" if files.empty?
90
90
 
@@ -92,7 +92,7 @@ module Hind
92
92
 
93
93
  generator = Hind::SCIP::Generator.new(File.expand_path(dir))
94
94
  index = generator.execute(files)
95
-
95
+
96
96
  File.write(options[:output], index.to_proto, mode: 'wb')
97
97
  say "SCIP index written to #{options[:output]}", :green
98
98
  end
@@ -143,7 +143,7 @@ module Hind
143
143
  def find_files(directory, glob, exclude_patterns)
144
144
  pattern = File.join(directory, glob)
145
145
  absolute_directory = File.expand_path(directory)
146
-
146
+
147
147
  files = Dir.glob(pattern).map do |file|
148
148
  # Return relative path to the directory for indexing
149
149
  Pathname.new(File.expand_path(file)).relative_path_from(Pathname.new(absolute_directory)).to_s
@@ -39,14 +39,14 @@ module Hind
39
39
  # We need to ensure metadata/project vertices are the very first ones.
40
40
  # If we collect declarations first, we might emit vertices.
41
41
  # So we should initialize project first.
42
-
42
+
43
43
  unless @initial_data_emitted
44
- initialize_project
45
- @initial_data_emitted = true
46
- # Ensure these are at the start of @lsif_data
47
- # specific logic: if we just added them, they are at the end (idx 0 if empty)
48
- # but if we called collect_declarations separately?
49
- # Actually, execute is the main entry point. @lsif_data is empty approx.
44
+ initialize_project
45
+ @initial_data_emitted = true
46
+ # Ensure these are at the start of @lsif_data
47
+ # specific logic: if we just added them, they are at the end (idx 0 if empty)
48
+ # but if we called collect_declarations separately?
49
+ # Actually, execute is the main entry point. @lsif_data is empty approx.
50
50
  end
51
51
 
52
52
  # First pass: Declarations
@@ -54,7 +54,7 @@ module Hind
54
54
  @document_id = nil # Reset for each file
55
55
  absolute_path = File.join(@metadata[:projectRoot], file)
56
56
  next unless File.exist?(absolute_path)
57
-
57
+
58
58
  source = File.read(absolute_path)
59
59
  collect_file_declarations(source, file)
60
60
  end
@@ -64,24 +64,24 @@ module Hind
64
64
  @document_id = nil # Reset for each file
65
65
  absolute_path = File.join(@metadata[:projectRoot], file)
66
66
  next unless File.exist?(absolute_path)
67
-
67
+
68
68
  source = File.read(absolute_path)
69
69
  process_file(content: source, uri: file)
70
70
  end
71
-
71
+
72
72
  finalize_document_state
73
-
73
+
74
74
  @lsif_data
75
75
  end
76
76
 
77
77
  def collect_file_declarations(content, uri)
78
78
  @current_uri = uri
79
79
  result = Prism.parse(content)
80
-
80
+
81
81
  declaration_visitor = DeclarationVisitor.new(self, uri)
82
82
  result.value.accept(declaration_visitor)
83
-
84
- { lsif_data: @lsif_data - @initial_data }
83
+
84
+ {lsif_data: @lsif_data - @initial_data}
85
85
  ensure
86
86
  @current_uri = nil
87
87
  end
@@ -91,17 +91,18 @@ module Hind
91
91
  setup_document if @document_id.nil? || @document_ids[uri].nil?
92
92
  @document_id = @document_ids[uri]
93
93
  @current_document_id = @document_id
94
-
94
+
95
95
  result = Prism.parse(content)
96
-
96
+
97
97
  reference_visitor = ReferenceVisitor.new(self, uri)
98
98
  result.value.accept(reference_visitor)
99
-
99
+
100
100
  finalize_document_state
101
101
  @lsif_data
102
102
  ensure
103
103
  @current_uri = nil
104
104
  end
105
+
105
106
  def get_initial_data
106
107
  @initial_data
107
108
  end
@@ -114,7 +115,8 @@ module Hind
114
115
  setup_document if @document_id.nil?
115
116
  current_doc_id = @document_id
116
117
 
117
- range_id = create_range(declaration[:node].constant_path.location)
118
+ range_location = declaration[:range_location] || declaration[:node].constant_path.location
119
+ range_id = create_range(range_location)
118
120
  return unless range_id
119
121
 
120
122
  result_set_id = emit_vertex('resultSet')
@@ -152,7 +154,8 @@ module Hind
152
154
  setup_document if @document_id.nil?
153
155
  current_doc_id = @document_id
154
156
 
155
- range_id = create_range(declaration[:node].constant_path.location)
157
+ range_location = declaration[:range_location] || declaration[:node].constant_path.location
158
+ range_id = create_range(range_location)
156
159
  return unless range_id
157
160
 
158
161
  result_set_id = emit_vertex('resultSet')
@@ -245,7 +248,7 @@ module Hind
245
248
  private
246
249
 
247
250
  def initialize_project
248
- metadata_vertex = emit_vertex('metaData', {
251
+ emit_vertex('metaData', {
249
252
  version: LSIF_VERSION,
250
253
  projectRoot: path_to_uri(@metadata[:projectRoot]),
251
254
  positionEncoding: 'utf-16',
@@ -294,6 +297,9 @@ module Hind
294
297
  def create_range(location)
295
298
  return nil unless @current_uri && location
296
299
 
300
+ cached_id = GlobalState.instance.find_range_id(@current_uri, location)
301
+ return cached_id if cached_id
302
+
297
303
  range_id = emit_vertex('range', {
298
304
  start: {
299
305
  line: location.start_line - 1, # Convert from 1-based to 0-based numbering
@@ -305,7 +311,7 @@ module Hind
305
311
  }
306
312
  })
307
313
 
308
- GlobalState.instance.add_range(@current_uri, range_id)
314
+ GlobalState.instance.add_range(@current_uri, range_id, location)
309
315
  range_id
310
316
  end
311
317
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'singleton'
3
4
 
4
5
  module Hind
@@ -19,6 +20,7 @@ module Hind
19
20
  @constants = {} # {qualified_name => {node:, scope:, file:, range_id:, result_set_id:, value:}}
20
21
  @references = {} # {qualified_name => [{file:, range_id:, document_id:}, ...]}
21
22
  @ranges = {} # {file_path => [range_ids]}
23
+ @range_cache = {} # {file_path => {[start_line, start_col, end_line, end_col] => range_id}}
22
24
  @result_sets = {} # {qualified_name => result_set_id}
23
25
  @project_id = nil
24
26
  end
@@ -26,7 +28,7 @@ module Hind
26
28
  def add_class(qualified_name, data)
27
29
  # Initialize if this is the first time we're seeing this class
28
30
  if !@classes.key?(qualified_name)
29
- @classes[qualified_name] = { definitions: [] }
31
+ @classes[qualified_name] = {definitions: []}
30
32
  end
31
33
 
32
34
  # Add this definition to the list
@@ -40,7 +42,7 @@ module Hind
40
42
  def add_module(qualified_name, data)
41
43
  # Initialize if this is the first time we're seeing this module
42
44
  if !@modules.key?(qualified_name)
43
- @modules[qualified_name] = { definitions: [] }
45
+ @modules[qualified_name] = {definitions: []}
44
46
  end
45
47
 
46
48
  # Add this definition to the list
@@ -65,15 +67,27 @@ module Hind
65
67
  }
66
68
  end
67
69
 
68
- def add_range(file_path, range_id)
70
+ def add_range(file_path, range_id, location = nil)
69
71
  @ranges[file_path] ||= []
70
72
  @ranges[file_path] << range_id
73
+
74
+ if location
75
+ @range_cache[file_path] ||= {}
76
+ coords = [location.start_line, location.start_column, location.end_line, location.end_column]
77
+ @range_cache[file_path][coords] = range_id
78
+ end
79
+ end
80
+
81
+ def find_range_id(file_path, location)
82
+ return nil unless @range_cache[file_path] && location
83
+ coords = [location.start_line, location.start_column, location.end_line, location.end_column]
84
+ @range_cache[file_path][coords]
71
85
  end
72
86
 
73
87
  def has_declaration?(qualified_name)
74
88
  @classes.key?(qualified_name) ||
75
- @modules.key?(qualified_name) ||
76
- @constants.key?(qualified_name)
89
+ @modules.key?(qualified_name) ||
90
+ @constants.key?(qualified_name)
77
91
  end
78
92
 
79
93
  def get_declaration(qualified_name)
@@ -205,7 +219,7 @@ module Hind
205
219
  # 3. Fall back to the first definition
206
220
 
207
221
  module_name = qualified_name.split('::').last
208
- parent_path = qualified_name.split('::')[0..-2].join('/')
222
+ qualified_name.split('::')[0..-2].join('/')
209
223
 
210
224
  # Rule 1: Check for a file named directly after the module
211
225
  direct_match = definitions.find do |d|
@@ -225,7 +239,7 @@ module Hind
225
239
 
226
240
  # Check if the file is at the module's path root
227
241
  parts.size == qualified_name.split('::').size &&
228
- parts.map(&:downcase).join('/') == qualified_name.gsub('::', '/').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
242
+ parts.map(&:downcase).join('/') == qualified_name.gsub('::', '/').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
229
243
  end
230
244
 
231
245
  return root_match if root_match
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Hind
3
4
  module LSIF
4
5
  class DeclarationVisitor < Prism::Visitor
@@ -13,10 +14,14 @@ module Hind
13
14
  def visit_class_node(node)
14
15
  @current_scope.push(node.constant_path.slice)
15
16
  class_name = current_scope_name
17
+ target_node = node.constant_path
18
+ target_node = target_node.child while target_node.is_a?(Prism::ConstantPathNode)
19
+
16
20
  @generator.register_class_declaration({
17
21
  type: :class,
18
22
  name: class_name,
19
23
  node: node,
24
+ range_location: target_node.location,
20
25
  scope: @current_scope[0..-2].join('::'),
21
26
  superclass: node.superclass&.slice
22
27
  })
@@ -27,10 +32,14 @@ module Hind
27
32
  def visit_module_node(node)
28
33
  @current_scope.push(node.constant_path.slice)
29
34
  module_name = current_scope_name
35
+ target_node = node.constant_path
36
+ target_node = target_node.child while target_node.is_a?(Prism::ConstantPathNode)
37
+
30
38
  @generator.register_module_declaration({
31
39
  type: :module,
32
40
  name: module_name,
33
41
  node: node,
42
+ range_location: target_node.location,
34
43
  scope: @current_scope[0..-2].join('::')
35
44
  })
36
45
  super
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Hind
3
4
  module LSIF
4
5
  class ReferenceVisitor < Prism::Visitor
@@ -9,11 +9,12 @@ module Hind
9
9
  def initialize(project_root)
10
10
  @project_root = project_root
11
11
  @documents = []
12
+ @package_info = detect_package_info
12
13
  end
13
14
 
14
15
  def execute(files)
15
16
  GlobalState.instance.reset
16
-
17
+
17
18
  # Pass 1: Collect all definitions
18
19
  files.each do |file|
19
20
  collect_definitions(file)
@@ -41,6 +42,31 @@ module Hind
41
42
 
42
43
  private
43
44
 
45
+ def detect_package_info
46
+ gemspec = Dir.glob(File.join(@project_root, '*.gemspec')).first
47
+ if gemspec
48
+ begin
49
+ content = File.read(gemspec)
50
+ name = content[/spec\.name\s*=\s*['"]([^'"]+)['"]/, 1]
51
+ version = content[/spec\.version\s*=\s*['"]([^'"]+)['"]/, 1]
52
+
53
+ # If version is a constant like Hind::VERSION, we might not find it easily via regex
54
+ # Let's try to find it via VERSION = '...'
55
+ if version.nil?
56
+ version_file = Dir.glob(File.join(@project_root, 'lib/**/version.rb')).first
57
+ if version_file
58
+ version = File.read(version_file)[/VERSION\s*=\s*['"]([^'"]+)['"]/, 1]
59
+ end
60
+ end
61
+
62
+ return {name: name, version: version || '0.1.0'} if name
63
+ rescue
64
+ # Fallback
65
+ end
66
+ end
67
+ {name: 'hind', version: Hind::VERSION}
68
+ end
69
+
44
70
  def collect_definitions(relative_path)
45
71
  absolute_path = File.join(@project_root, relative_path)
46
72
  return unless File.exist?(absolute_path)
@@ -48,7 +74,7 @@ module Hind
48
74
  source = File.read(absolute_path)
49
75
  result = Prism.parse(source)
50
76
 
51
- visitor = ScipVisitor.new(relative_path, { mode: :index, package_info: { name: 'hind', version: Hind::VERSION } })
77
+ visitor = ScipVisitor.new(relative_path, {mode: :index, package_info: @package_info})
52
78
  result.value.accept(visitor)
53
79
  end
54
80
 
@@ -61,8 +87,8 @@ module Hind
61
87
 
62
88
  occurrences = []
63
89
  symbols = []
64
-
65
- visitor = ScipVisitor.new(relative_path, { mode: :emit, package_info: { name: 'hind', version: Hind::VERSION } })
90
+
91
+ visitor = ScipVisitor.new(relative_path, {mode: :emit, package_info: @package_info})
66
92
  result.value.accept(visitor)
67
93
  occurrences.concat(visitor.occurrences)
68
94
  symbols.concat(visitor.symbols)
@@ -84,13 +110,14 @@ module Hind
84
110
  @occurrences = []
85
111
  @symbols = []
86
112
  @current_scope = []
87
- @package_prefix = "scip-ruby rubygems #{package_info[:name] || 'hind'} #{package_info[:version] || '0.1.0'} "
113
+ @package_prefix = "scip-ruby rubygems #{package_info[:name] || "hind"} #{package_info[:version] || "0.1.0"} "
88
114
  end
89
115
 
90
116
  def visit_class_node(node)
91
- @current_scope.push(node.constant_path.slice)
92
- symbol = "#{@package_prefix}#{@current_scope.join('#')}#"
93
-
117
+ name = scip_name(node.constant_path.slice)
118
+ @current_scope.push(name)
119
+ symbol = "#{@package_prefix}#{@current_scope.join("#")}#"
120
+
94
121
  if @mode == :index
95
122
  GlobalState.instance.add_symbol(current_scope_name, symbol)
96
123
  else
@@ -108,21 +135,25 @@ module Hind
108
135
  syntax_kind: SyntaxKind::Identifier
109
136
  )
110
137
 
111
- @symbols << SymbolInformation.new(
112
- symbol: symbol,
113
- documentation: ["class #{node.constant_path.slice}"],
114
- kind: SymbolInformation::Kind::Class
115
- )
138
+ unless GlobalState.instance.emitted?(symbol)
139
+ @symbols << SymbolInformation.new(
140
+ symbol: symbol,
141
+ documentation: ["class #{node.constant_path.slice}"],
142
+ kind: SymbolInformation::Kind::Class
143
+ )
144
+ GlobalState.instance.mark_emitted(symbol)
145
+ end
116
146
  end
117
147
 
118
148
  super
119
149
  @current_scope.pop
120
150
  end
121
-
151
+
122
152
  def visit_module_node(node)
123
- @current_scope.push(node.constant_path.slice)
124
- symbol = "#{@package_prefix}#{@current_scope.join('#')}#"
125
-
153
+ name = scip_name(node.constant_path.slice)
154
+ @current_scope.push(name)
155
+ symbol = "#{@package_prefix}#{@current_scope.join("#")}#"
156
+
126
157
  if @mode == :index
127
158
  GlobalState.instance.add_symbol(current_scope_name, symbol)
128
159
  else
@@ -139,20 +170,25 @@ module Hind
139
170
  syntax_kind: SyntaxKind::Identifier
140
171
  )
141
172
 
142
- @symbols << SymbolInformation.new(
143
- symbol: symbol,
144
- documentation: ["module #{node.constant_path.slice}"],
145
- kind: SymbolInformation::Kind::Module
146
- )
173
+ unless GlobalState.instance.emitted?(symbol)
174
+ @symbols << SymbolInformation.new(
175
+ symbol: symbol,
176
+ documentation: ["module #{node.constant_path.slice}"],
177
+ kind: SymbolInformation::Kind::Module
178
+ )
179
+ GlobalState.instance.mark_emitted(symbol)
180
+ end
147
181
  end
148
-
182
+
149
183
  super
150
184
  @current_scope.pop
151
185
  end
152
-
186
+
153
187
  def visit_constant_write_node(node)
154
- symbol = "#{@package_prefix}#{@current_scope.join('#')}##{node.name}."
155
-
188
+ name = scip_name(node.name.to_s)
189
+ suffix = @current_scope.empty? ? '' : '#'
190
+ symbol = "#{@package_prefix}#{@current_scope.join("#")}#{suffix}#{name}."
191
+
156
192
  if @mode == :index
157
193
  GlobalState.instance.add_symbol("#{current_scope_name}::#{node.name}", symbol)
158
194
  else
@@ -161,56 +197,64 @@ module Hind
161
197
  node.name_loc.start_column,
162
198
  node.name_loc.end_column
163
199
  ]
164
-
200
+
165
201
  @occurrences << Occurrence.new(
166
202
  range: range,
167
203
  symbol: symbol,
168
204
  symbol_roles: 1,
169
205
  syntax_kind: SyntaxKind::Identifier
170
206
  )
171
-
172
- @symbols << SymbolInformation.new(
173
- symbol: symbol,
174
- documentation: ["constant #{node.name}"],
175
- kind: SymbolInformation::Kind::Package # Or Kind::Constant if we had it, fallback to something
176
- )
207
+
208
+ unless GlobalState.instance.emitted?(symbol)
209
+ @symbols << SymbolInformation.new(
210
+ symbol: symbol,
211
+ documentation: ["constant #{node.name}"],
212
+ kind: SymbolInformation::Kind::Package # fallback
213
+ )
214
+ GlobalState.instance.mark_emitted(symbol)
215
+ end
177
216
  end
178
217
  super
179
218
  end
180
219
 
181
220
  def visit_def_node(node)
182
- symbol = "#{@package_prefix}#{@current_scope.join('#')}##{node.name}."
183
-
184
- if @mode == :index
185
- # Register both qualified and simple name for speculative resolution
186
- GlobalState.instance.add_symbol("#{current_scope_name}##{node.name}", symbol)
187
- GlobalState.instance.add_symbol("##{node.name}", symbol)
188
- else
189
- range = [
221
+ name = scip_name(node.name.to_s)
222
+ suffix = @current_scope.empty? ? '' : '#'
223
+ symbol = "#{@package_prefix}#{@current_scope.join("#")}#{suffix}#{name}."
224
+
225
+ if @mode == :index
226
+ # Register both qualified and simple name for speculative resolution
227
+ GlobalState.instance.add_symbol("#{current_scope_name}##{node.name}", symbol)
228
+ GlobalState.instance.add_symbol("##{node.name}", symbol)
229
+ else
230
+ range = [
190
231
  node.name_loc.start_line - 1,
191
232
  node.name_loc.start_column,
192
233
  node.name_loc.end_column
193
- ]
194
-
195
- @occurrences << Occurrence.new(
196
- range: range,
197
- symbol: symbol,
198
- symbol_roles: 1,
199
- syntax_kind: SyntaxKind::Identifier
200
- )
201
-
202
- @symbols << SymbolInformation.new(
203
- symbol: symbol,
204
- documentation: ["def #{node.name}"],
205
- kind: SymbolInformation::Kind::Method
206
- )
207
- end
208
- super
234
+ ]
235
+
236
+ @occurrences << Occurrence.new(
237
+ range: range,
238
+ symbol: symbol,
239
+ symbol_roles: 1,
240
+ syntax_kind: SyntaxKind::Identifier
241
+ )
242
+
243
+ unless GlobalState.instance.emitted?(symbol)
244
+ @symbols << SymbolInformation.new(
245
+ symbol: symbol,
246
+ documentation: ["def #{node.name}"],
247
+ kind: SymbolInformation::Kind::Method
248
+ )
249
+ GlobalState.instance.mark_emitted(symbol)
250
+ end
251
+ end
252
+ super
209
253
  end
210
254
 
211
255
  def visit_constant_read_node(node)
212
256
  return if @mode == :index
213
-
257
+
214
258
  # Try to resolve constant
215
259
  symbol = GlobalState.instance.find_symbol(node.name.to_s, current_scope_name)
216
260
  if symbol
@@ -219,7 +263,7 @@ module Hind
219
263
  node.location.start_column,
220
264
  node.location.end_column
221
265
  ]
222
-
266
+
223
267
  @occurrences << Occurrence.new(
224
268
  range: range,
225
269
  symbol: symbol,
@@ -237,13 +281,13 @@ module Hind
237
281
 
238
282
  def visit_call_node(node)
239
283
  return if @mode == :index
240
-
284
+
241
285
  # Skip common methods
242
286
  return super if %w[new puts p print].include?(node.name.to_s)
243
287
 
244
288
  # Speculative resolution
245
- symbol = GlobalState.instance.find_symbol("#{current_scope_name}##{node.name}", "") ||
246
- GlobalState.instance.find_symbol("##{node.name}", "")
289
+ symbol = GlobalState.instance.find_symbol("#{current_scope_name}##{node.name}", '') ||
290
+ GlobalState.instance.find_symbol("##{node.name}", '')
247
291
 
248
292
  if symbol
249
293
  loc = node.message_loc || node.location
@@ -252,7 +296,7 @@ module Hind
252
296
  loc.start_column,
253
297
  loc.end_column
254
298
  ]
255
-
299
+
256
300
  @occurrences << Occurrence.new(
257
301
  range: range,
258
302
  symbol: symbol,
@@ -265,8 +309,22 @@ module Hind
265
309
 
266
310
  private
267
311
 
312
+ def scip_name(name)
313
+ # Escape names with special characters using backticks
314
+ # Allowed: alphanumeric, -, +, $, _
315
+ if /^[a-zA-Z0-9\-\+\$_]+$/.match?(name)
316
+ name
317
+ else
318
+ "`#{name}`"
319
+ end
320
+ end
321
+
268
322
  def current_scope_name
269
- @current_scope.join('::')
323
+ # This returns Ruby-style name for GlobalState mapping
324
+ # We don't want escaped names here to keep mapping simple
325
+ # Wait, I should probably store unescaped names in scope
326
+ # Let's adjust visit_* to store unescaped and scip_name for symbol construction
327
+ @current_scope.join('::').delete('`')
270
328
  end
271
329
  end
272
330
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'singleton'
4
+ require 'set'
3
5
 
4
6
  module Hind
5
7
  module SCIP
@@ -12,6 +14,15 @@ module Hind
12
14
 
13
15
  def reset
14
16
  @symbols = {} # {qualified_name => symbol_string}
17
+ @emitted_symbols = Set.new
18
+ end
19
+
20
+ def mark_emitted(symbol)
21
+ @emitted_symbols.add(symbol)
22
+ end
23
+
24
+ def emitted?(symbol)
25
+ @emitted_symbols.include?(symbol)
15
26
  end
16
27
 
17
28
  def add_symbol(name, symbol)
@@ -25,16 +36,16 @@ module Hind
25
36
  def has_symbol?(name)
26
37
  @symbols.key?(name)
27
38
  end
28
-
39
+
29
40
  def find_symbol(name, current_scope)
30
41
  # Reuse LSIF-like scope resolution logic
31
42
  return @symbols[name] if @symbols.key?(name)
32
-
43
+
33
44
  return nil unless current_scope && !current_scope.empty?
34
-
45
+
35
46
  qualified_name = "#{current_scope}::#{name}"
36
47
  return @symbols[qualified_name] if @symbols.key?(qualified_name)
37
-
48
+
38
49
  scope_parts = current_scope.split('::')
39
50
  while scope_parts.size > 0
40
51
  scope_parts.pop
@@ -42,7 +53,7 @@ module Hind
42
53
  qualified_name = prefix.empty? ? name : "#{prefix}::#{name}"
43
54
  return @symbols[qualified_name] if @symbols.key?(qualified_name)
44
55
  end
45
-
56
+
46
57
  nil
47
58
  end
48
59
  end
@@ -3,37 +3,37 @@
3
3
  require 'google/protobuf'
4
4
 
5
5
  Google::Protobuf::DescriptorPool.generated_pool.build do
6
- add_enum "scip.ProtocolVersion" do
6
+ add_enum 'scip.ProtocolVersion' do
7
7
  value :UnspecifiedProtocolVersion, 0
8
8
  end
9
9
 
10
- add_enum "scip.TextEncoding" do
10
+ add_enum 'scip.TextEncoding' do
11
11
  value :UnspecifiedTextEncoding, 0
12
12
  value :UTF8, 1
13
13
  value :UTF16, 2
14
14
  end
15
15
 
16
- add_message "scip.ToolInfo" do
16
+ add_message 'scip.ToolInfo' do
17
17
  optional :name, :string, 1
18
18
  optional :version, :string, 2
19
19
  repeated :arguments, :string, 3
20
20
  end
21
21
 
22
- add_message "scip.Metadata" do
23
- optional :version, :enum, 1, "scip.ProtocolVersion"
24
- optional :tool_info, :message, 2, "scip.ToolInfo"
22
+ add_message 'scip.Metadata' do
23
+ optional :version, :enum, 1, 'scip.ProtocolVersion'
24
+ optional :tool_info, :message, 2, 'scip.ToolInfo'
25
25
  optional :project_root, :string, 3
26
- optional :text_document_encoding, :enum, 4, "scip.TextEncoding"
26
+ optional :text_document_encoding, :enum, 4, 'scip.TextEncoding'
27
27
  end
28
28
 
29
- add_enum "scip.PositionEncoding" do
29
+ add_enum 'scip.PositionEncoding' do
30
30
  value :UnspecifiedPositionEncoding, 0
31
31
  value :UTF8CodeUnitOffsetFromLineStart, 1
32
32
  value :UTF16CodeUnitOffsetFromLineStart, 2
33
33
  value :UTF32CodeUnitOffsetFromLineStart, 3
34
34
  end
35
35
 
36
- add_enum "scip.SyntaxKind" do
36
+ add_enum 'scip.SyntaxKind' do
37
37
  value :UnspecifiedSyntaxKind, 0
38
38
  value :Comment, 1
39
39
  value :Identifier, 41
@@ -41,7 +41,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
41
41
  value :StringLiteral, 49
42
42
  end
43
43
 
44
- add_enum "scip.Severity" do
44
+ add_enum 'scip.Severity' do
45
45
  value :UnspecifiedSeverity, 0
46
46
  value :Error, 1
47
47
  value :Warning, 2
@@ -49,21 +49,21 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
49
49
  value :Hint, 4
50
50
  end
51
51
 
52
- add_enum "scip.DiagnosticTag" do
52
+ add_enum 'scip.DiagnosticTag' do
53
53
  value :UnspecifiedDiagnosticTag, 0
54
54
  value :Unnecessary, 1
55
55
  value :Deprecated, 2
56
56
  end
57
57
 
58
- add_message "scip.Diagnostic" do
59
- optional :severity, :enum, 1, "scip.Severity"
58
+ add_message 'scip.Diagnostic' do
59
+ optional :severity, :enum, 1, 'scip.Severity'
60
60
  optional :code, :string, 2
61
61
  optional :message, :string, 3
62
62
  optional :source, :string, 4
63
- repeated :tags, :enum, 5, "scip.DiagnosticTag"
63
+ repeated :tags, :enum, 5, 'scip.DiagnosticTag'
64
64
  end
65
65
 
66
- add_message "scip.Relationship" do
66
+ add_message 'scip.Relationship' do
67
67
  optional :symbol, :string, 1
68
68
  optional :is_reference, :bool, 2
69
69
  optional :is_implementation, :bool, 3
@@ -71,16 +71,16 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
71
71
  optional :is_definition, :bool, 5
72
72
  end
73
73
 
74
- add_message "scip.Occurrence" do
74
+ add_message 'scip.Occurrence' do
75
75
  repeated :range, :int32, 1
76
76
  optional :symbol, :string, 2
77
77
  optional :symbol_roles, :int32, 3
78
78
  repeated :override_documentation, :string, 4
79
- optional :syntax_kind, :enum, 5, "scip.SyntaxKind"
80
- repeated :diagnostics, :message, 6, "scip.Diagnostic"
79
+ optional :syntax_kind, :enum, 5, 'scip.SyntaxKind'
80
+ repeated :diagnostics, :message, 6, 'scip.Diagnostic'
81
81
  end
82
82
 
83
- add_enum "scip.SymbolInformation.Kind" do
83
+ add_enum 'scip.SymbolInformation.Kind' do
84
84
  value :UnspecifiedKind, 0
85
85
  value :Class, 7
86
86
  value :Method, 26
@@ -88,47 +88,47 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
88
88
  value :Package, 35
89
89
  end
90
90
 
91
- add_message "scip.Document" do
91
+ add_message 'scip.Document' do
92
92
  optional :language, :string, 4
93
93
  optional :relative_path, :string, 1
94
- repeated :occurrences, :message, 2, "scip.Occurrence"
95
- repeated :symbols, :message, 3, "scip.SymbolInformation"
94
+ repeated :occurrences, :message, 2, 'scip.Occurrence'
95
+ repeated :symbols, :message, 3, 'scip.SymbolInformation'
96
96
  optional :text, :string, 5
97
- optional :position_encoding, :enum, 6, "scip.PositionEncoding"
97
+ optional :position_encoding, :enum, 6, 'scip.PositionEncoding'
98
98
  end
99
99
 
100
- add_message "scip.SymbolInformation" do
100
+ add_message 'scip.SymbolInformation' do
101
101
  optional :symbol, :string, 1
102
102
  repeated :documentation, :string, 3
103
- repeated :relationships, :message, 4, "scip.Relationship"
104
- optional :kind, :enum, 5, "scip.SymbolInformation.Kind"
103
+ repeated :relationships, :message, 4, 'scip.Relationship'
104
+ optional :kind, :enum, 5, 'scip.SymbolInformation.Kind'
105
105
  optional :display_name, :string, 6
106
- optional :signature_documentation, :message, 7, "scip.Document"
106
+ optional :signature_documentation, :message, 7, 'scip.Document'
107
107
  optional :snippet, :string, 8
108
108
  end
109
109
 
110
- add_message "scip.Index" do
111
- optional :metadata, :message, 1, "scip.Metadata"
112
- repeated :documents, :message, 2, "scip.Document"
113
- repeated :external_symbols, :message, 3, "scip.SymbolInformation"
110
+ add_message 'scip.Index' do
111
+ optional :metadata, :message, 1, 'scip.Metadata'
112
+ repeated :documents, :message, 2, 'scip.Document'
113
+ repeated :external_symbols, :message, 3, 'scip.SymbolInformation'
114
114
  end
115
115
  end
116
116
 
117
117
  module Hind
118
118
  module SCIP
119
- Index = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Index").msgclass
120
- Metadata = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Metadata").msgclass
121
- ProtocolVersion = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.ProtocolVersion").enummodule
122
- TextEncoding = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.TextEncoding").enummodule
123
- ToolInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.ToolInfo").msgclass
124
- Document = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Document").msgclass
125
- PositionEncoding = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.PositionEncoding").enummodule
126
- Occurrence = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Occurrence").msgclass
127
- SymbolInformation = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.SymbolInformation").msgclass
128
- SymbolInformation::Kind = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.SymbolInformation.Kind").enummodule
129
- Relationship = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Relationship").msgclass
130
- SyntaxKind = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.SyntaxKind").enummodule
131
- Diagnostic = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Diagnostic").msgclass
132
- Severity = Google::Protobuf::DescriptorPool.generated_pool.lookup("scip.Severity").enummodule
119
+ Index = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Index').msgclass
120
+ Metadata = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Metadata').msgclass
121
+ ProtocolVersion = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.ProtocolVersion').enummodule
122
+ TextEncoding = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.TextEncoding').enummodule
123
+ ToolInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.ToolInfo').msgclass
124
+ Document = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Document').msgclass
125
+ PositionEncoding = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.PositionEncoding').enummodule
126
+ Occurrence = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Occurrence').msgclass
127
+ SymbolInformation = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.SymbolInformation').msgclass
128
+ SymbolInformation::Kind = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.SymbolInformation.Kind').enummodule
129
+ Relationship = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Relationship').msgclass
130
+ SyntaxKind = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.SyntaxKind').enummodule
131
+ Diagnostic = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Diagnostic').msgclass
132
+ Severity = Google::Protobuf::DescriptorPool.generated_pool.lookup('scip.Severity').enummodule
133
133
  end
134
134
  end
data/lib/hind/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hind
4
- VERSION = '0.1.15'
4
+ VERSION = '0.1.17'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hind
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.15
4
+ version: 0.1.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aboobacker MK