hind 0.1.6 → 0.1.8
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 +4 -4
- data/lib/hind/cli.rb +43 -161
- data/lib/hind/lsif/generator.rb +96 -82
- data/lib/hind/lsif/global_state.rb +4 -81
- data/lib/hind/lsif/visitors/declaration_visitor.rb +0 -170
- data/lib/hind/lsif/visitors/reference_visitor.rb +0 -159
- data/lib/hind/lsif.rb +0 -1
- data/lib/hind/version.rb +1 -1
- metadata +1 -2
- data/lib/hind/lsif/visitor.rb +0 -255
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: debf085e96a2d5683f8aac3870ab5c06ce0b28adc8dfa960227fb0a763defcee
|
4
|
+
data.tar.gz: 475b21bdbc4502c445a24be086e131c511f53972f113e7dda6e2b52eb03b16b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da48ed207a58c99a9a544c2f5f2d0b3c88aecd7fa36ef7fc348064f925033ae33b7702c04d1147970a583b27a2031c5de7ca89b4b9d0aefb731ae0b3ffa93ce7
|
7
|
+
data.tar.gz: 88f86b97957a68ab50d153311d6d07a0ab0d99f39dfabe2409039ef86fc22af6f162419ddb926de58c938ebc9de165291c30e33556ac25db0d467ec1c450e610
|
data/lib/hind/cli.rb
CHANGED
@@ -4,59 +4,30 @@ require 'thor'
|
|
4
4
|
require 'json'
|
5
5
|
require 'pathname'
|
6
6
|
require 'fileutils'
|
7
|
-
require 'yaml'
|
8
7
|
|
9
8
|
module Hind
|
10
9
|
class CLI < Thor
|
11
10
|
class_option :verbose, type: :boolean, aliases: '-v', desc: 'Enable verbose output'
|
12
|
-
class_option :config, type: :string, aliases: '-c', desc: 'Path to configuration file'
|
13
11
|
|
14
|
-
desc 'lsif', 'Generate LSIF index'
|
12
|
+
desc 'lsif', 'Generate LSIF index for Ruby classes, modules, and constants'
|
15
13
|
method_option :directory, type: :string, aliases: '-d', default: '.', desc: 'Root directory to process'
|
16
14
|
method_option :output, type: :string, aliases: '-o', default: 'dump.lsif', desc: 'Output file path'
|
17
15
|
method_option :glob, type: :string, aliases: '-g', default: '**/*.rb', desc: 'File pattern to match'
|
18
16
|
method_option :force, type: :boolean, aliases: '-f', desc: 'Overwrite output file if it exists'
|
19
17
|
method_option :exclude, type: :array, aliases: '-e', desc: 'Patterns to exclude'
|
20
|
-
method_option :workers, type: :numeric, aliases: '-w', default: 1, desc: 'Number of parallel workers'
|
21
18
|
def lsif
|
22
|
-
|
23
|
-
|
19
|
+
validate_directory(options[:directory])
|
20
|
+
validate_output_file(options[:output], options[:force])
|
24
21
|
|
25
|
-
|
26
|
-
|
22
|
+
files = find_files(options[:directory], options[:glob], options[:exclude])
|
23
|
+
abort "No files found matching pattern '#{options[:glob]}'" if files.empty?
|
27
24
|
|
28
|
-
files
|
29
|
-
abort "No files found matching pattern '#{opts[:glob]}'" if files.empty?
|
30
|
-
|
31
|
-
say "Found #{files.length} files to process", :green if opts[:verbose]
|
25
|
+
say "Found #{files.length} files to process", :green if options[:verbose]
|
32
26
|
|
33
27
|
begin
|
34
|
-
generate_lsif(files,
|
35
|
-
say "\nLSIF data has been written to: #{
|
36
|
-
rescue
|
37
|
-
handle_error(e, opts[:verbose])
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
desc 'check', 'Check LSIF dump file for validity and provide insights'
|
42
|
-
method_option :file, type: :string, aliases: '-f', default: 'dump.lsif', desc: 'LSIF dump file to check'
|
43
|
-
method_option :json, type: :boolean, desc: 'Output results in JSON format'
|
44
|
-
method_option :strict, type: :boolean, desc: 'Treat warnings as errors'
|
45
|
-
def check
|
46
|
-
abort "Error: File '#{options[:file]}' does not exist" unless File.exist?(options[:file])
|
47
|
-
|
48
|
-
begin
|
49
|
-
checker = Hind::LSIF::Checker.new(options[:file])
|
50
|
-
results = checker.check
|
51
|
-
|
52
|
-
if options[:json]
|
53
|
-
puts JSON.pretty_generate(results)
|
54
|
-
else
|
55
|
-
print_check_results(results)
|
56
|
-
end
|
57
|
-
|
58
|
-
exit(1) if !results[:valid] || (options[:strict] && results[:warnings].any?)
|
59
|
-
rescue StandardError => e
|
28
|
+
generate_lsif(files, options)
|
29
|
+
say "\nLSIF data has been written to: #{options[:output]}", :green if options[:verbose]
|
30
|
+
rescue => e
|
60
31
|
handle_error(e, options[:verbose])
|
61
32
|
end
|
62
33
|
end
|
@@ -66,18 +37,6 @@ module Hind
|
|
66
37
|
say "Hind version #{Hind::VERSION}"
|
67
38
|
end
|
68
39
|
|
69
|
-
desc 'init', 'Initialize Hind configuration file'
|
70
|
-
method_option :force, type: :boolean, aliases: '-f', desc: 'Overwrite existing configuration'
|
71
|
-
def init
|
72
|
-
config_file = '.hind.yml'
|
73
|
-
if File.exist?(config_file) && !options[:force]
|
74
|
-
abort "Configuration file already exists. Use --force to overwrite."
|
75
|
-
end
|
76
|
-
|
77
|
-
create_default_config(config_file)
|
78
|
-
say "Created configuration file: #{config_file}", :green
|
79
|
-
end
|
80
|
-
|
81
40
|
private
|
82
41
|
|
83
42
|
def generate_lsif(files, options)
|
@@ -95,41 +54,56 @@ module Hind
|
|
95
54
|
files.each do |file|
|
96
55
|
absolute_path = File.expand_path(file)
|
97
56
|
relative_path = Pathname.new(absolute_path)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
57
|
+
.relative_path_from(Pathname.new(generator.metadata[:projectRoot]))
|
58
|
+
.to_s
|
59
|
+
|
60
|
+
begin
|
61
|
+
file_contents[relative_path] = File.read(absolute_path)
|
62
|
+
rescue => e
|
63
|
+
warn "Warning: Failed to read file '#{file}': #{e.message}"
|
64
|
+
next
|
65
|
+
end
|
104
66
|
end
|
105
67
|
|
106
68
|
File.open(options[:output], 'w') do |output_file|
|
107
|
-
say
|
69
|
+
say 'First pass: Collecting declarations...', :cyan if options[:verbose]
|
70
|
+
|
71
|
+
# Write initial LSIF data (metadata and project vertices)
|
72
|
+
initial_data = generator.get_initial_data
|
73
|
+
if initial_data&.any?
|
74
|
+
say 'Writing initial LSIF data...', :cyan if options[:verbose]
|
75
|
+
output_file.puts(initial_data.map(&:to_json).join("\n"))
|
76
|
+
end
|
108
77
|
|
109
78
|
# First pass: Process all files to collect declarations
|
110
79
|
declaration_data = generator.collect_declarations(file_contents)
|
111
80
|
|
112
|
-
say "Found #{declaration_data[:declarations].size} declarations", :cyan if options[:verbose]
|
113
|
-
|
81
|
+
say "Found #{declaration_data[:declarations].size} declarations (classes, modules, constants)", :cyan if options[:verbose]
|
82
|
+
|
83
|
+
# Write declaration LSIF data next
|
84
|
+
if declaration_data[:lsif_data]&.any?
|
85
|
+
output_file.puts(declaration_data[:lsif_data].map(&:to_json).join("\n"))
|
86
|
+
end
|
87
|
+
|
88
|
+
say 'Processing files for references...', :cyan if options[:verbose]
|
114
89
|
|
115
|
-
# Second pass: Process each file
|
90
|
+
# Second pass: Process each file for references
|
116
91
|
file_contents.each do |relative_path, content|
|
117
92
|
if options[:verbose]
|
118
93
|
say "Processing file: #{relative_path}", :cyan
|
119
94
|
end
|
120
95
|
|
121
|
-
|
96
|
+
reference_lsif_data = generator.process_file(
|
122
97
|
content: content,
|
123
98
|
uri: relative_path
|
124
99
|
)
|
125
|
-
|
126
|
-
output_file.puts(lsif_data.map(&:to_json).join("\n"))
|
100
|
+
output_file.puts(reference_lsif_data.map(&:to_json).join("\n"))
|
127
101
|
end
|
128
102
|
|
129
|
-
#
|
130
|
-
say
|
131
|
-
|
132
|
-
output_file.puts(
|
103
|
+
# Finalize and write cross-file references
|
104
|
+
say 'Processing cross-file references...', :cyan if options[:verbose]
|
105
|
+
final_references = generator.finalize_references
|
106
|
+
output_file.puts(final_references.map(&:to_json).join("\n"))
|
133
107
|
end
|
134
108
|
end
|
135
109
|
|
@@ -150,109 +124,17 @@ module Hind
|
|
150
124
|
pattern = File.join(directory, glob)
|
151
125
|
files = Dir.glob(pattern)
|
152
126
|
|
153
|
-
|
154
|
-
|
155
|
-
files.reject! { |f| File.fnmatch?(exclude, f) }
|
156
|
-
end
|
127
|
+
exclude_patterns&.each do |exclude|
|
128
|
+
files.reject! { |f| File.fnmatch?(exclude, f) }
|
157
129
|
end
|
158
130
|
|
159
131
|
files
|
160
132
|
end
|
161
133
|
|
162
|
-
def load_config(config_path)
|
163
|
-
return {} unless config_path && File.exist?(config_path)
|
164
|
-
|
165
|
-
begin
|
166
|
-
YAML.load_file(config_path) || {}
|
167
|
-
rescue StandardError => e
|
168
|
-
abort "Error loading config file: #{e.message}"
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def create_default_config(config_file)
|
173
|
-
config = {
|
174
|
-
'directory' => '.',
|
175
|
-
'output' => 'dump.lsif',
|
176
|
-
'glob' => '**/*.rb',
|
177
|
-
'exclude' => [
|
178
|
-
'test/**/*',
|
179
|
-
'spec/**/*',
|
180
|
-
'vendor/**/*'
|
181
|
-
],
|
182
|
-
'workers' => 1
|
183
|
-
}
|
184
|
-
|
185
|
-
File.write(config_file, config.to_yaml)
|
186
|
-
end
|
187
|
-
|
188
|
-
def print_check_results(results)
|
189
|
-
print_check_status(results[:valid])
|
190
|
-
print_check_errors(results[:errors])
|
191
|
-
print_check_warnings(results[:warnings])
|
192
|
-
print_check_statistics(results[:statistics])
|
193
|
-
end
|
194
|
-
|
195
|
-
def print_check_status(valid)
|
196
|
-
status = valid ? "✅ LSIF dump is valid" : "❌ LSIF dump contains errors"
|
197
|
-
say(status, valid ? :green : :red)
|
198
|
-
puts
|
199
|
-
end
|
200
|
-
|
201
|
-
def print_check_errors(errors)
|
202
|
-
return if errors.empty?
|
203
|
-
|
204
|
-
say "Errors:", :red
|
205
|
-
errors.each do |error|
|
206
|
-
say " • #{error}", :red
|
207
|
-
end
|
208
|
-
puts
|
209
|
-
end
|
210
|
-
|
211
|
-
def print_check_warnings(warnings)
|
212
|
-
return if warnings.empty?
|
213
|
-
|
214
|
-
say "Warnings:", :yellow
|
215
|
-
warnings.each do |warning|
|
216
|
-
say " • #{warning}", :yellow
|
217
|
-
end
|
218
|
-
puts
|
219
|
-
end
|
220
|
-
|
221
|
-
def print_check_statistics(stats)
|
222
|
-
say "Statistics:", :cyan
|
223
|
-
say " Total Elements: #{stats[:total_elements]}"
|
224
|
-
say " Vertices: #{stats[:vertices][:total]}"
|
225
|
-
say " Edges: #{stats[:edges][:total]}"
|
226
|
-
say " Vertex/Edge Ratio: #{stats[:vertex_to_edge_ratio]}"
|
227
|
-
puts
|
228
|
-
|
229
|
-
say " Documents: #{stats[:documents]}"
|
230
|
-
say " Ranges: #{stats[:ranges]}"
|
231
|
-
say " Definitions: #{stats[:definitions]}"
|
232
|
-
say " References: #{stats[:references]}"
|
233
|
-
say " Hovers: #{stats[:hovers]}"
|
234
|
-
puts
|
235
|
-
|
236
|
-
say " Vertex Types:", :cyan
|
237
|
-
stats[:vertices][:by_type].each do |type, count|
|
238
|
-
say " #{type}: #{count}"
|
239
|
-
end
|
240
|
-
puts
|
241
|
-
|
242
|
-
say " Edge Types:", :cyan
|
243
|
-
stats[:edges][:by_type].each do |type, count|
|
244
|
-
say " #{type}: #{count}"
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
134
|
def handle_error(error, verbose)
|
249
135
|
message = "Error: #{error.message}"
|
250
136
|
message += "\n#{error.backtrace.join("\n")}" if verbose
|
251
137
|
abort message
|
252
138
|
end
|
253
|
-
|
254
|
-
def symbolize_keys(hash)
|
255
|
-
hash.transform_keys(&:to_sym)
|
256
|
-
end
|
257
139
|
end
|
258
140
|
end
|
data/lib/hind/lsif/generator.rb
CHANGED
@@ -24,8 +24,10 @@ module Hind
|
|
24
24
|
|
25
25
|
@global_state = GlobalState.new
|
26
26
|
@document_ids = {}
|
27
|
+
@current_document_id = nil
|
27
28
|
@lsif_data = []
|
28
29
|
@current_uri = nil
|
30
|
+
@last_vertex_id = @vertex_id
|
29
31
|
|
30
32
|
initialize_project if metadata[:initial]
|
31
33
|
end
|
@@ -33,30 +35,82 @@ module Hind
|
|
33
35
|
def collect_declarations(files)
|
34
36
|
files.each do |path, content|
|
35
37
|
@current_uri = path
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
@document_id = nil
|
39
|
+
@current_document_id = nil
|
40
|
+
|
41
|
+
begin
|
42
|
+
ast = Parser.new(content).parse
|
43
|
+
setup_document
|
44
|
+
visitor = DeclarationVisitor.new(self, path)
|
45
|
+
visitor.visit(ast)
|
46
|
+
finalize_document_state
|
47
|
+
rescue => e
|
48
|
+
warn "Warning: Failed to collect declarations from '#{path}': #{e.message}"
|
49
|
+
end
|
39
50
|
end
|
40
51
|
|
41
|
-
|
52
|
+
# Store the last used vertex ID and reset reference index
|
53
|
+
@last_vertex_id = @vertex_id
|
54
|
+
@last_reference_index = @lsif_data.length
|
55
|
+
|
56
|
+
{
|
57
|
+
declarations: @global_state.declarations,
|
58
|
+
lsif_data: @lsif_data
|
59
|
+
}
|
42
60
|
end
|
43
61
|
|
44
62
|
def process_file(params)
|
45
|
-
content = params[:content]
|
46
63
|
@current_uri = params[:uri]
|
64
|
+
content = params[:content]
|
65
|
+
|
66
|
+
# Restore vertex ID from last declaration pass
|
67
|
+
@vertex_id = @last_vertex_id
|
68
|
+
|
69
|
+
@document_id = nil
|
70
|
+
@current_document_id = nil
|
47
71
|
|
48
72
|
setup_document
|
49
73
|
ast = Parser.new(content).parse
|
50
74
|
|
51
|
-
# Process declarations first to update any missing ones
|
52
|
-
visitor = DeclarationVisitor.new(self, @current_uri)
|
53
|
-
visitor.visit(ast)
|
54
|
-
|
55
|
-
# Then process references
|
56
75
|
visitor = ReferenceVisitor.new(self, @current_uri)
|
57
76
|
visitor.visit(ast)
|
58
77
|
|
59
|
-
|
78
|
+
finalize_document_state
|
79
|
+
|
80
|
+
# Update last vertex ID
|
81
|
+
@last_vertex_id = @vertex_id
|
82
|
+
|
83
|
+
# Return only the new LSIF data since last call
|
84
|
+
result = @lsif_data[@last_reference_index..]
|
85
|
+
@last_reference_index = @lsif_data.length
|
86
|
+
result
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_initial_data
|
90
|
+
@initial_data
|
91
|
+
end
|
92
|
+
|
93
|
+
def finalize_references
|
94
|
+
# Restore vertex ID
|
95
|
+
@vertex_id = @last_vertex_id
|
96
|
+
# Process all references to create definition results
|
97
|
+
@global_state.references.each do |qualified_name, references|
|
98
|
+
declaration = @global_state.declarations[qualified_name]
|
99
|
+
next unless declaration && declaration[:result_set_id]
|
100
|
+
|
101
|
+
# Create reference result for this symbol
|
102
|
+
ref_result_id = emit_vertex('referenceResult')
|
103
|
+
emit_edge('textDocument/references', declaration[:result_set_id], ref_result_id)
|
104
|
+
|
105
|
+
# Group references by document
|
106
|
+
references_by_doc = references.group_by { |ref| ref[:document_id] }
|
107
|
+
|
108
|
+
# Create item edges for each document's references
|
109
|
+
references_by_doc.each do |doc_id, refs|
|
110
|
+
emit_edge('item', ref_result_id, refs.map { |r| r[:range_id] }, 'references', doc_id)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
60
114
|
@lsif_data
|
61
115
|
end
|
62
116
|
|
@@ -64,6 +118,10 @@ module Hind
|
|
64
118
|
return unless @current_uri && declaration[:node]
|
65
119
|
|
66
120
|
qualified_name = declaration[:name]
|
121
|
+
|
122
|
+
setup_document if @document_id.nil?
|
123
|
+
current_doc_id = @document_id
|
124
|
+
|
67
125
|
range_id = create_range(declaration[:node].location, declaration[:node].location)
|
68
126
|
return unless range_id
|
69
127
|
|
@@ -72,7 +130,8 @@ module Hind
|
|
72
130
|
|
73
131
|
def_result_id = emit_vertex('definitionResult')
|
74
132
|
emit_edge('textDocument/definition', result_set_id, def_result_id)
|
75
|
-
|
133
|
+
|
134
|
+
emit_edge('item', def_result_id, [range_id], 'definitions', current_doc_id)
|
76
135
|
|
77
136
|
hover_content = generate_hover_content(declaration)
|
78
137
|
hover_id = emit_vertex('hoverResult', {
|
@@ -88,74 +147,28 @@ module Hind
|
|
88
147
|
scope: declaration[:scope],
|
89
148
|
file: @current_uri,
|
90
149
|
range_id: range_id,
|
91
|
-
result_set_id: result_set_id
|
150
|
+
result_set_id: result_set_id,
|
151
|
+
document_id: current_doc_id
|
92
152
|
}.merge(declaration))
|
153
|
+
|
154
|
+
result_set_id
|
93
155
|
end
|
94
156
|
|
95
157
|
def register_reference(reference)
|
96
158
|
return unless @current_uri && reference[:node]
|
97
159
|
return unless @global_state.has_declaration?(reference[:name])
|
98
160
|
|
161
|
+
setup_document if @document_id.nil?
|
162
|
+
current_doc_id = @document_id
|
163
|
+
|
99
164
|
range_id = create_range(reference[:node].location, reference[:node].location)
|
100
165
|
return unless range_id
|
101
166
|
|
102
167
|
declaration = @global_state.declarations[reference[:name]]
|
103
|
-
|
104
|
-
emit_edge('next', range_id, declaration[:result_set_id])
|
105
|
-
end
|
168
|
+
return unless declaration[:result_set_id]
|
106
169
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
@global_state.references.each do |qualified_name, references|
|
111
|
-
declaration = @global_state.declarations[qualified_name]
|
112
|
-
next unless declaration
|
113
|
-
|
114
|
-
result_set_id = declaration[:result_set_id]
|
115
|
-
next unless result_set_id
|
116
|
-
|
117
|
-
ref_result_id = emit_vertex('referenceResult')
|
118
|
-
emit_edge('textDocument/references', result_set_id, ref_result_id)
|
119
|
-
|
120
|
-
# Collect all reference range IDs
|
121
|
-
all_refs = references.map { |ref| ref[:range_id] }
|
122
|
-
all_refs << declaration[:range_id] if declaration[:range_id]
|
123
|
-
|
124
|
-
# Group references by document
|
125
|
-
references.group_by { |ref| ref[:file] }.each do |file_path, file_refs|
|
126
|
-
document_id = @document_ids[file_path]
|
127
|
-
next unless document_id
|
128
|
-
|
129
|
-
cross_ref_data << {
|
130
|
-
id: @vertex_id,
|
131
|
-
type: 'edge',
|
132
|
-
label: 'item',
|
133
|
-
outV: ref_result_id,
|
134
|
-
inVs: all_refs,
|
135
|
-
document: document_id,
|
136
|
-
property: 'references'
|
137
|
-
}
|
138
|
-
@vertex_id += 1
|
139
|
-
end
|
140
|
-
|
141
|
-
# Handle document containing the definition
|
142
|
-
def_file = declaration[:file]
|
143
|
-
def_document_id = @document_ids[def_file]
|
144
|
-
if def_document_id && references.none? { |ref| ref[:file] == def_file }
|
145
|
-
cross_ref_data << {
|
146
|
-
id: @vertex_id,
|
147
|
-
type: 'edge',
|
148
|
-
label: 'item',
|
149
|
-
outV: ref_result_id,
|
150
|
-
inVs: all_refs,
|
151
|
-
document: def_document_id,
|
152
|
-
property: 'references'
|
153
|
-
}
|
154
|
-
@vertex_id += 1
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
cross_ref_data
|
170
|
+
@global_state.add_reference(reference[:name], @current_uri, range_id, current_doc_id)
|
171
|
+
emit_edge('next', range_id, declaration[:result_set_id])
|
159
172
|
end
|
160
173
|
|
161
174
|
private
|
@@ -171,10 +184,11 @@ module Hind
|
|
171
184
|
}
|
172
185
|
})
|
173
186
|
|
174
|
-
@global_state.project_id = emit_vertex('project', {
|
187
|
+
@global_state.project_id = emit_vertex('project', {kind: 'ruby'})
|
175
188
|
end
|
176
189
|
|
177
190
|
def setup_document
|
191
|
+
return if @document_id
|
178
192
|
return unless @current_uri
|
179
193
|
|
180
194
|
file_path = File.join(@metadata[:projectRoot], @current_uri)
|
@@ -183,17 +197,19 @@ module Hind
|
|
183
197
|
uri: path_to_uri(file_path),
|
184
198
|
languageId: 'ruby'
|
185
199
|
})
|
200
|
+
|
186
201
|
@document_ids[@current_uri] = @document_id
|
202
|
+
@current_document_id = @document_id
|
187
203
|
|
188
204
|
emit_edge('contains', @global_state.project_id, [@document_id]) if @global_state.project_id
|
189
205
|
end
|
190
206
|
|
191
|
-
def
|
192
|
-
return unless @current_uri
|
207
|
+
def finalize_document_state
|
208
|
+
return unless @current_uri && @document_id
|
193
209
|
|
194
210
|
ranges = @global_state.get_ranges_for_file(@current_uri)
|
195
211
|
if ranges&.any?
|
196
|
-
emit_edge('contains', @document_id, ranges)
|
212
|
+
emit_edge('contains', @document_id, ranges, nil, @document_id)
|
197
213
|
end
|
198
214
|
end
|
199
215
|
|
@@ -235,7 +251,7 @@ module Hind
|
|
235
251
|
@vertex_id - 1
|
236
252
|
end
|
237
253
|
|
238
|
-
def emit_edge(label, out_v, in_v, property = nil)
|
254
|
+
def emit_edge(label, out_v, in_v, property = nil, doc_id = nil)
|
239
255
|
return unless out_v && valid_in_v?(in_v)
|
240
256
|
|
241
257
|
edge = {
|
@@ -251,8 +267,10 @@ module Hind
|
|
251
267
|
edge[:inV] = in_v
|
252
268
|
end
|
253
269
|
|
254
|
-
|
255
|
-
|
270
|
+
if label == 'item'
|
271
|
+
edge[:document] = doc_id || @current_document_id
|
272
|
+
edge[:property] = property if property
|
273
|
+
end
|
256
274
|
|
257
275
|
@lsif_data << edge
|
258
276
|
@vertex_id += 1
|
@@ -261,11 +279,6 @@ module Hind
|
|
261
279
|
|
262
280
|
def generate_hover_content(declaration)
|
263
281
|
case declaration[:type]
|
264
|
-
when :method
|
265
|
-
sig = []
|
266
|
-
sig << "def #{declaration[:name]}"
|
267
|
-
sig << "(#{declaration[:params]})" if declaration[:params]
|
268
|
-
sig.join
|
269
282
|
when :class
|
270
283
|
hover = ["class #{declaration[:name]}"]
|
271
284
|
hover << " < #{declaration[:superclass]}" if declaration[:superclass]
|
@@ -273,7 +286,8 @@ module Hind
|
|
273
286
|
when :module
|
274
287
|
"module #{declaration[:name]}"
|
275
288
|
when :constant
|
276
|
-
"#{declaration[:
|
289
|
+
value_info = declaration[:node].value ? " = #{declaration[:node].value.inspect}" : ''
|
290
|
+
"#{declaration[:name]}#{value_info}"
|
277
291
|
else
|
278
292
|
declaration[:name].to_s
|
279
293
|
end
|
@@ -301,7 +315,7 @@ module Hind
|
|
301
315
|
|
302
316
|
def path_to_uri(path)
|
303
317
|
return nil unless path
|
304
|
-
normalized_path = path.
|
318
|
+
normalized_path = path.tr('\\', '/')
|
305
319
|
normalized_path = normalized_path.sub(%r{^file://}, '')
|
306
320
|
absolute_path = File.expand_path(normalized_path)
|
307
321
|
"file://#{absolute_path}"
|