solargraph 0.18.2 → 0.18.3
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/solargraph.rb +33 -28
- data/lib/solargraph/api_map.rb +997 -1044
- data/lib/solargraph/api_map/source_to_yard.rb +4 -3
- data/lib/solargraph/diagnostics/rubocop.rb +4 -3
- data/lib/solargraph/language_server/host.rb +140 -70
- data/lib/solargraph/language_server/message/base.rb +1 -0
- data/lib/solargraph/language_server/message/client.rb +6 -2
- data/lib/solargraph/language_server/message/text_document/completion.rb +34 -39
- data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/did_close.rb +1 -0
- data/lib/solargraph/language_server/message/text_document/did_save.rb +1 -3
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/hover.rb +25 -30
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +1 -1
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +8 -7
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +1 -1
- data/lib/solargraph/language_server/transport/socket.rb +15 -17
- data/lib/solargraph/library.rb +34 -16
- data/lib/solargraph/node_methods.rb +96 -96
- data/lib/solargraph/pin.rb +1 -0
- data/lib/solargraph/pin/base.rb +2 -1
- data/lib/solargraph/pin/base_variable.rb +45 -5
- data/lib/solargraph/pin/block_parameter.rb +5 -2
- data/lib/solargraph/pin/method.rb +22 -0
- data/lib/solargraph/pin/namespace.rb +32 -2
- data/lib/solargraph/pin/reference.rb +21 -0
- data/lib/solargraph/pin/yard_object.rb +9 -0
- data/lib/solargraph/shell.rb +136 -136
- data/lib/solargraph/source.rb +134 -188
- data/lib/solargraph/source/change.rb +70 -0
- data/lib/solargraph/source/fragment.rb +120 -66
- data/lib/solargraph/source/position.rb +41 -0
- data/lib/solargraph/source/updater.rb +48 -0
- data/lib/solargraph/version.rb +3 -3
- data/lib/solargraph/workspace/config.rb +4 -9
- data/lib/solargraph/yard_map/core_docs.rb +0 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 249d94c36b0d3d32bd9c7d06933aa5b886b3c73e
|
4
|
+
data.tar.gz: 7229efdede3aee37cca5da7ed160f378c5cee95e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d46fb7bbec935080b31fe33d9219c5189c0a5d475e4be2329bed3ac502f0a195b6c320438470289aaacc643086f213a472cd38408e168ce20fc29b33225593d2
|
7
|
+
data.tar.gz: 5023b4965a27c1e60f52537ee8a2cc72eafbde90eab78f7bbbd3d71dff412034d86f4f53b638d74a7542357024e8d12943b71b1797e02de10573922a03178e05
|
data/lib/solargraph.rb
CHANGED
@@ -1,28 +1,33 @@
|
|
1
|
-
require 'solargraph/version'
|
2
|
-
require 'rubygems/package'
|
3
|
-
require 'yard-solargraph'
|
4
|
-
|
5
|
-
module Solargraph
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
14
|
-
autoload :
|
15
|
-
autoload :
|
16
|
-
autoload :
|
17
|
-
autoload :
|
18
|
-
autoload :
|
19
|
-
autoload :
|
20
|
-
autoload :
|
21
|
-
autoload :
|
22
|
-
autoload :
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
1
|
+
require 'solargraph/version'
|
2
|
+
require 'rubygems/package'
|
3
|
+
require 'yard-solargraph'
|
4
|
+
|
5
|
+
module Solargraph
|
6
|
+
class InvalidOffsetError < RangeError; end
|
7
|
+
class DiagnosticsError < RuntimeError; end
|
8
|
+
class FileNotFoundError < Exception; end
|
9
|
+
class SourceNotAvailableError < StandardError; end
|
10
|
+
'—'
|
11
|
+
autoload :Shell, 'solargraph/shell'
|
12
|
+
autoload :Source, 'solargraph/source'
|
13
|
+
autoload :ApiMap, 'solargraph/api_map'
|
14
|
+
autoload :NodeMethods, 'solargraph/node_methods'
|
15
|
+
autoload :Suggestion, 'solargraph/suggestion'
|
16
|
+
autoload :Server, 'solargraph/server'
|
17
|
+
autoload :YardMap, 'solargraph/yard_map'
|
18
|
+
autoload :Pin, 'solargraph/pin'
|
19
|
+
autoload :LiveMap, 'solargraph/live_map'
|
20
|
+
autoload :ServerMethods, 'solargraph/server_methods'
|
21
|
+
autoload :Plugin, 'solargraph/plugin'
|
22
|
+
autoload :CoreFills, 'solargraph/core_fills'
|
23
|
+
autoload :LanguageServer, 'solargraph/language_server'
|
24
|
+
autoload :Workspace, 'solargraph/workspace'
|
25
|
+
autoload :Page, 'solargraph/page'
|
26
|
+
autoload :Library, 'solargraph/library'
|
27
|
+
autoload :Diagnostics, 'solargraph/diagnostics'
|
28
|
+
|
29
|
+
YARDOC_PATH = File.join(File.realpath(File.dirname(__FILE__)), '..', 'yardoc')
|
30
|
+
YARD_EXTENSION_FILE = File.join(File.realpath(File.dirname(__FILE__)), 'yard-solargraph.rb')
|
31
|
+
end
|
32
|
+
|
33
|
+
Solargraph::YardMap::CoreDocs.require_minimum
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -1,1044 +1,997 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'set'
|
3
|
-
require 'time'
|
4
|
-
|
5
|
-
module Solargraph
|
6
|
-
class ApiMap
|
7
|
-
autoload :Cache, 'solargraph/api_map/cache'
|
8
|
-
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
9
|
-
autoload :Completion, 'solargraph/api_map/completion'
|
10
|
-
|
11
|
-
include
|
12
|
-
include
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
workspace = Solargraph::Workspace.new(
|
24
|
-
workspace =
|
25
|
-
|
26
|
-
|
27
|
-
@
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
#
|
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
|
-
@
|
76
|
-
@
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
source
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
#
|
91
|
-
#
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
@sources
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
namespace_map[
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
|
125
|
-
|
126
|
-
return true if
|
127
|
-
return true if @stime
|
128
|
-
return true if
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
#
|
134
|
-
#
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
#
|
153
|
-
#
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
#
|
161
|
-
#
|
162
|
-
# @param
|
163
|
-
# @
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
#
|
185
|
-
#
|
186
|
-
|
187
|
-
|
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
|
-
|
225
|
-
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
def
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
end
|
319
|
-
|
320
|
-
end
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
# @return [
|
357
|
-
def
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
end
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
end
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
#
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
end
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
end
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
if type.
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
scope = :instance
|
999
|
-
if parts[1].nil?
|
1000
|
-
result = type
|
1001
|
-
else
|
1002
|
-
subns, subsc = extract_namespace_and_scope(type)
|
1003
|
-
result = inner_infer_signature_type(parts[1], subns, subsc, call_node, false)
|
1004
|
-
end
|
1005
|
-
end
|
1006
|
-
end
|
1007
|
-
else
|
1008
|
-
return inner_infer_signature_type(parts[1], type, :class, call_node, false)
|
1009
|
-
end
|
1010
|
-
# @todo Assuming `self` only works at the top level
|
1011
|
-
# result = type if result == 'self'
|
1012
|
-
unless result.nil?
|
1013
|
-
if scope == :class
|
1014
|
-
nstype = get_namespace_type(result)
|
1015
|
-
result = "#{nstype == :class ? 'Class<' : 'Module<'}#{result}>"
|
1016
|
-
end
|
1017
|
-
end
|
1018
|
-
cache.set_signature_type signature, namespace, scope, result
|
1019
|
-
result
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
# @todo call_node might be superfluous here. We're already past looking for local variables.
|
1023
|
-
def inner_infer_signature_pins signature, namespace, scope, call_node, top
|
1024
|
-
base, rest = signature.split('.', 2)
|
1025
|
-
type = nil
|
1026
|
-
if rest.nil?
|
1027
|
-
visibility = [:public]
|
1028
|
-
visibility.push :private, :protected if top
|
1029
|
-
methods = []
|
1030
|
-
methods.concat get_methods(namespace, visibility: visibility, scope: scope).select{|pin| pin.name == base}
|
1031
|
-
methods.concat get_methods('Kernel', scope: :instance).select{|pin| pin.name == base} if top
|
1032
|
-
return methods
|
1033
|
-
else
|
1034
|
-
type = inner_infer_signature_type base, namespace, scope, call_node, top
|
1035
|
-
nxt_ns, nxt_scope = extract_namespace_and_scope(type)
|
1036
|
-
return inner_infer_signature_pins rest, nxt_ns, nxt_scope, call_node, false
|
1037
|
-
end
|
1038
|
-
end
|
1039
|
-
|
1040
|
-
def current_workspace_sources
|
1041
|
-
@sources - [@virtual_source]
|
1042
|
-
end
|
1043
|
-
end
|
1044
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'set'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Solargraph
|
6
|
+
class ApiMap
|
7
|
+
autoload :Cache, 'solargraph/api_map/cache'
|
8
|
+
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
9
|
+
autoload :Completion, 'solargraph/api_map/completion'
|
10
|
+
|
11
|
+
include Solargraph::ApiMap::SourceToYard
|
12
|
+
include CoreFills
|
13
|
+
|
14
|
+
# The workspace to analyze and process.
|
15
|
+
#
|
16
|
+
# @return [Solargraph::Workspace]
|
17
|
+
attr_reader :workspace
|
18
|
+
|
19
|
+
# @param workspace [Solargraph::Workspace]
|
20
|
+
def initialize workspace = nil
|
21
|
+
# @todo Deprecate strings for the workspace parameter
|
22
|
+
workspace = Solargraph::Workspace.new(workspace) if workspace.kind_of?(String)
|
23
|
+
workspace = Solargraph::Workspace.new(nil) if workspace.nil?
|
24
|
+
@workspace = workspace
|
25
|
+
require_extensions
|
26
|
+
@virtual_source = nil
|
27
|
+
@yard_stale = true
|
28
|
+
process_maps
|
29
|
+
yard_map
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.load directory
|
33
|
+
self.new(Solargraph::Workspace.new(directory))
|
34
|
+
end
|
35
|
+
|
36
|
+
# An array of required paths in the workspace.
|
37
|
+
#
|
38
|
+
# @return [Array<String>]
|
39
|
+
def required
|
40
|
+
@required ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Get a YardMap associated with the current workspace.
|
44
|
+
#
|
45
|
+
# @return [Solargraph::YardMap]
|
46
|
+
def yard_map
|
47
|
+
# refresh
|
48
|
+
if @yard_map.nil? || @yard_map.required.to_set != required.to_set
|
49
|
+
@yard_map = Solargraph::YardMap.new(required: required, workspace: workspace)
|
50
|
+
end
|
51
|
+
@yard_map
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get a LiveMap associated with the current workspace.
|
55
|
+
#
|
56
|
+
# @return [Solargraph::LiveMap]
|
57
|
+
def live_map
|
58
|
+
@live_map ||= Solargraph::LiveMap.new(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Declare a virtual source that will be included in the map regardless of
|
62
|
+
# whether it's in the workspace.
|
63
|
+
#
|
64
|
+
# If the source is in the workspace, virtualizing it has no effect. Only
|
65
|
+
# one source can be virtualized at a time.
|
66
|
+
#
|
67
|
+
# @param source [Solargraph::Source]
|
68
|
+
def virtualize source
|
69
|
+
eliminate @virtual_source unless @virtual_source.nil?
|
70
|
+
if workspace.has_source?(source)
|
71
|
+
@sources = workspace.sources
|
72
|
+
@virtual_source = nil
|
73
|
+
else
|
74
|
+
@virtual_source = source
|
75
|
+
@sources = workspace.sources
|
76
|
+
unless @virtual_source.nil?
|
77
|
+
@sources.push @virtual_source
|
78
|
+
process_virtual
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @todo Candidate for deprecation
|
84
|
+
def append_source code, filename = nil
|
85
|
+
source = Source.load_string(code, filename)
|
86
|
+
virtualize source
|
87
|
+
end
|
88
|
+
|
89
|
+
# Refresh the ApiMap.
|
90
|
+
#
|
91
|
+
# @param force [Boolean] Perform a refresh even if the map is not "stale."
|
92
|
+
def refresh force = false
|
93
|
+
return unless @force or changed?
|
94
|
+
if force
|
95
|
+
process_maps
|
96
|
+
else
|
97
|
+
current_workspace_sources.reject{|s| workspace.sources.include?(s)}.each do |source|
|
98
|
+
eliminate source
|
99
|
+
end
|
100
|
+
@sources = workspace.sources
|
101
|
+
@sources.push @virtual_source unless @virtual_source.nil?
|
102
|
+
cache.clear
|
103
|
+
namespace_map.clear
|
104
|
+
@sources.each do |s|
|
105
|
+
s.namespaces.each do |n|
|
106
|
+
namespace_map[n] ||= []
|
107
|
+
namespace_map[n].concat s.namespace_pins(n)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
@sources.each do |source|
|
111
|
+
if @stime.nil? or source.stime > @stime
|
112
|
+
eliminate source
|
113
|
+
map_source source
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
@stime = Time.new
|
118
|
+
end
|
119
|
+
|
120
|
+
# True if a workspace file has been created, modified, or deleted since
|
121
|
+
# the last time the map was processed.
|
122
|
+
#
|
123
|
+
# @return [Boolean]
|
124
|
+
def changed?
|
125
|
+
return true if current_workspace_sources.length != workspace.sources.length
|
126
|
+
return true if @stime.nil?
|
127
|
+
return true if workspace.stime > @stime
|
128
|
+
return true if !@virtual_source.nil? and @virtual_source.stime > @stime
|
129
|
+
false
|
130
|
+
end
|
131
|
+
|
132
|
+
# An array of suggestions based on Ruby keywords (`if`, `end`, etc.).
|
133
|
+
#
|
134
|
+
# @return [Array<Solargraph::Pin::Keyword>]
|
135
|
+
def self.keywords
|
136
|
+
@keyword_suggestions ||= KEYWORDS.map{ |s|
|
137
|
+
Pin::Keyword.new(s)
|
138
|
+
}.freeze
|
139
|
+
end
|
140
|
+
|
141
|
+
# An array of namespace names defined in the ApiMap.
|
142
|
+
#
|
143
|
+
# @return [Array<String>]
|
144
|
+
def namespaces
|
145
|
+
# refresh
|
146
|
+
namespace_map.keys
|
147
|
+
end
|
148
|
+
|
149
|
+
# True if the namespace exists.
|
150
|
+
#
|
151
|
+
# @param name [String] The namespace to match
|
152
|
+
# @param root [String] The context to search
|
153
|
+
# @return [Boolean]
|
154
|
+
def namespace_exists? name, root = ''
|
155
|
+
!find_fully_qualified_namespace(name, root).nil?
|
156
|
+
end
|
157
|
+
|
158
|
+
# Get suggestions for constants in the specified namespace. The result
|
159
|
+
# may contain both constant and namespace pins.
|
160
|
+
#
|
161
|
+
# @param fqns [String] The fully qualified namespace
|
162
|
+
# @param visibility [Array<Symbol>] :public and/or :private
|
163
|
+
# @return [Array<Solargraph::Pin::Base>]
|
164
|
+
def get_constants namespace, context = ''
|
165
|
+
namespace ||= ''
|
166
|
+
skip = []
|
167
|
+
result = []
|
168
|
+
bases = context.split('::')
|
169
|
+
while bases.length > 0
|
170
|
+
built = bases.join('::')
|
171
|
+
fqns = find_fully_qualified_namespace(namespace, built)
|
172
|
+
visibility = [:public]
|
173
|
+
visibility.push :private if fqns == context
|
174
|
+
result.concat inner_get_constants(fqns, visibility, skip)
|
175
|
+
bases.pop
|
176
|
+
end
|
177
|
+
fqns = find_fully_qualified_namespace(namespace, '')
|
178
|
+
visibility = [:public]
|
179
|
+
visibility.push :private if fqns == context
|
180
|
+
result.concat inner_get_constants(fqns, visibility, skip)
|
181
|
+
result
|
182
|
+
end
|
183
|
+
|
184
|
+
# Get a fully qualified namespace name. This method will start the search
|
185
|
+
# in the specified root until it finds a match for the name.
|
186
|
+
#
|
187
|
+
# @param name [String] The namespace to match
|
188
|
+
# @param root [String] The context to search
|
189
|
+
# @return [String]
|
190
|
+
def find_fully_qualified_namespace name, root = '', skip = []
|
191
|
+
# refresh
|
192
|
+
return nil if name.nil?
|
193
|
+
return nil if skip.include?(root)
|
194
|
+
skip.push root
|
195
|
+
if name == ''
|
196
|
+
if root == ''
|
197
|
+
return ''
|
198
|
+
else
|
199
|
+
return find_fully_qualified_namespace(root, '', skip)
|
200
|
+
end
|
201
|
+
else
|
202
|
+
if (root == '')
|
203
|
+
return name unless namespace_map[name].nil?
|
204
|
+
im = @namespace_includes['']
|
205
|
+
unless im.nil?
|
206
|
+
im.each do |i|
|
207
|
+
i.resolve self
|
208
|
+
return i.name unless i.name.nil?
|
209
|
+
end
|
210
|
+
end
|
211
|
+
else
|
212
|
+
roots = root.to_s.split('::')
|
213
|
+
while roots.length > 0
|
214
|
+
fqns = roots.join('::') + '::' + name
|
215
|
+
return fqns unless namespace_map[fqns].nil?
|
216
|
+
roots.pop
|
217
|
+
end
|
218
|
+
return name unless namespace_map[name].nil?
|
219
|
+
im = @namespace_includes['']
|
220
|
+
unless im.nil?
|
221
|
+
im.each do |i|
|
222
|
+
i.resolve self
|
223
|
+
return i.name unless i.name.nil?
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
result = yard_map.find_fully_qualified_namespace(name, root)
|
229
|
+
if result.nil?
|
230
|
+
result = live_map.get_fqns(name, root)
|
231
|
+
end
|
232
|
+
result
|
233
|
+
end
|
234
|
+
|
235
|
+
# Get an array of instance variable pins defined in specified namespace
|
236
|
+
# and scope.
|
237
|
+
#
|
238
|
+
# @param namespace [String] A fully qualified namespace
|
239
|
+
# @param scope [Symbol] :instance or :class
|
240
|
+
# @return [Array<Solargraph::Pin::InstanceVariable>]
|
241
|
+
def get_instance_variable_pins(namespace, scope = :instance)
|
242
|
+
raw = @ivar_pins[namespace]
|
243
|
+
return [] if raw.nil?
|
244
|
+
# @todo This is a crazy workaround because instance variables in the
|
245
|
+
# global namespace might be in either scope
|
246
|
+
pins = prefer_non_nil_variables(raw)
|
247
|
+
return pins if namespace.empty?
|
248
|
+
pins.select{ |pin| pin.scope == scope }
|
249
|
+
end
|
250
|
+
|
251
|
+
# Get an array of class variable pins for a namespace.
|
252
|
+
#
|
253
|
+
# @param namespace [String] A fully qualified namespace
|
254
|
+
# @return [Array<Solargraph::Pin::ClassVariable>]
|
255
|
+
def get_class_variable_pins(namespace)
|
256
|
+
prefer_non_nil_variables(@cvar_pins[namespace] || [])
|
257
|
+
end
|
258
|
+
|
259
|
+
# @return [Array<Solargraph::Pin::Base>]
|
260
|
+
def get_symbols
|
261
|
+
# refresh
|
262
|
+
@symbol_pins
|
263
|
+
end
|
264
|
+
|
265
|
+
# Find a class, instance, or global variable by name in the provided
|
266
|
+
# namespace and scope.
|
267
|
+
#
|
268
|
+
# @param name [String] The variable name, e.g., `@foo`, `@@bar`, or `$baz`
|
269
|
+
# @param fqns [String] The fully qualified namespace
|
270
|
+
# @param scope [Symbol] :class or :instance
|
271
|
+
# @return [Solargraph::Pin::BaseVariable]
|
272
|
+
def find_variable_pin name, fqns, scope
|
273
|
+
var = nil
|
274
|
+
return nil if name.nil?
|
275
|
+
if name.start_with?('@@')
|
276
|
+
# class variable
|
277
|
+
var = get_class_variable_pins(fqns).select{|pin| pin.name == name}.first
|
278
|
+
return nil if var.nil?
|
279
|
+
elsif name.start_with?('@')
|
280
|
+
# instance variable
|
281
|
+
var = get_instance_variable_pins(fqns, scope).select{|pin| pin.name == name}.first
|
282
|
+
return nil if var.nil?
|
283
|
+
elsif name.start_with?('$')
|
284
|
+
# global variable
|
285
|
+
var = get_global_variable_pins.select{|pin| pin.name == name}.first
|
286
|
+
return nil if var.nil?
|
287
|
+
end
|
288
|
+
var
|
289
|
+
end
|
290
|
+
|
291
|
+
def find_namespace_pin fqns
|
292
|
+
crawl_constants fqns, '', [:public, :private]
|
293
|
+
end
|
294
|
+
|
295
|
+
def crawl_constants name, fqns, visibility
|
296
|
+
return nil if name.nil?
|
297
|
+
chain = name.split('::')
|
298
|
+
cursor = chain.shift
|
299
|
+
return nil if cursor.nil?
|
300
|
+
unless fqns.empty?
|
301
|
+
bases = fqns.split('::')
|
302
|
+
result = nil
|
303
|
+
until bases.empty?
|
304
|
+
built = bases.join('::')
|
305
|
+
result = get_constants(built, '').select{|pin| pin.name == cursor and visibility.include?(pin.visibility)}.first
|
306
|
+
break unless result.nil?
|
307
|
+
bases.pop
|
308
|
+
visibility -= [:private]
|
309
|
+
end
|
310
|
+
return nil if result.nil?
|
311
|
+
end
|
312
|
+
result = get_constants(fqns, '').select{|pin| pin.name == cursor and visibility.include?(pin.visibility)}.first
|
313
|
+
visibility -= [:private]
|
314
|
+
until chain.empty? or result.nil?
|
315
|
+
fqns = result.path
|
316
|
+
cursor = chain.shift
|
317
|
+
result = get_constants(fqns, '').select{|pin| pin.name == cursor and visibility.include?(pin.visibility)}.first
|
318
|
+
end
|
319
|
+
result
|
320
|
+
end
|
321
|
+
|
322
|
+
# This method checks the signature from the namespace's internal context,
|
323
|
+
# i.e., the first word in the signature can be a private or protected
|
324
|
+
# method, a private constant, an instance variable, or a class variable.
|
325
|
+
# Local variables are not accessible.
|
326
|
+
#
|
327
|
+
# @return [String]
|
328
|
+
def infer_type signature, namespace = '', scope: :instance
|
329
|
+
context = combine_type(namespace, scope)
|
330
|
+
parts = signature.split('.')
|
331
|
+
base = parts.shift
|
332
|
+
return nil if base.nil?
|
333
|
+
type = infer_word_type(base, context, true)
|
334
|
+
return nil if type.nil?
|
335
|
+
until parts.empty?
|
336
|
+
word = parts.shift
|
337
|
+
type = infer_method_type(word, type)
|
338
|
+
return nil if type.nil?
|
339
|
+
end
|
340
|
+
type
|
341
|
+
end
|
342
|
+
|
343
|
+
# @return [Solargraph::Pin::Base]
|
344
|
+
def tail_pins signature, fqns, scope, visibility
|
345
|
+
return [] if signature.nil?
|
346
|
+
type = combine_type(fqns, scope)
|
347
|
+
return infer_word_pins(signature, type, true) unless signature.include?('.')
|
348
|
+
parts = signature.split('.')
|
349
|
+
last = parts.pop
|
350
|
+
base = parts.join('.')
|
351
|
+
type = infer_type(base, fqns, scope: scope)
|
352
|
+
return [] if type.nil?
|
353
|
+
infer_word_pins(last, type, true)
|
354
|
+
end
|
355
|
+
|
356
|
+
# @return [Solargraph::Pin::Base]
|
357
|
+
def tail_pin signature, fqns, scope, visibility
|
358
|
+
tail_pins(signature, fqns, scope, visibility).first
|
359
|
+
end
|
360
|
+
|
361
|
+
# Get an array of pins for a word in the provided context. A word can be
|
362
|
+
# a constant, a global variable, or a method name. Private and protected
|
363
|
+
# words are excluded by default. Set the `internal` parameter to `true` to
|
364
|
+
# to include private and protected methods, private constants, instance
|
365
|
+
# variables, and class variables.
|
366
|
+
#
|
367
|
+
# @param word [String]
|
368
|
+
# @param base_type [String]
|
369
|
+
# @param internal [Boolean]
|
370
|
+
# @return [Array<Solargraph::Pin::Base>]
|
371
|
+
def infer_word_pins word, base_type, internal = false
|
372
|
+
pins = []
|
373
|
+
namespace, scope = extract_namespace_and_scope(base_type)
|
374
|
+
if word == 'self' and internal
|
375
|
+
context = (internal ? namespace.split('::')[0..-2].join(';;') : '')
|
376
|
+
fqns = find_fully_qualified_namespace(namespace, context)
|
377
|
+
pins.concat get_path_suggestions(fqns) unless fqns.nil?
|
378
|
+
return pins
|
379
|
+
end
|
380
|
+
fqns = find_fully_qualified_namespace(word, namespace)
|
381
|
+
unless fqns.nil?
|
382
|
+
pins.concat get_path_suggestions(fqns) unless fqns.nil?
|
383
|
+
return pins
|
384
|
+
end
|
385
|
+
if internal
|
386
|
+
if word.start_with?('@@')
|
387
|
+
pins.concat get_class_variable_pins(namespace).select{|pin| pin.name == word}
|
388
|
+
return pins
|
389
|
+
elsif word.start_with?('@')
|
390
|
+
pins.concat get_instance_variable_pins(namespace, scope).select{|pin| pin.name == word}
|
391
|
+
return pins
|
392
|
+
end
|
393
|
+
end
|
394
|
+
if word.start_with?('$')
|
395
|
+
pins.concat get_global_variable_pins.select{|pin| pin.name == word}
|
396
|
+
return pins
|
397
|
+
end
|
398
|
+
pins.concat get_constants(namespace, (internal ? namespace : '')).select{|pin| pin.name == word}
|
399
|
+
if pins.empty?
|
400
|
+
pins.concat get_type_methods(base_type, (internal ? base_type : '')).select{|pin| pin.name == word}
|
401
|
+
pins.concat get_type_methods('Kernel').select{|pin| pin.name == word}
|
402
|
+
end
|
403
|
+
pins
|
404
|
+
end
|
405
|
+
|
406
|
+
# @return [Solargraph::Pin::Base]
|
407
|
+
def infer_word_pin word, base_type, internal = false
|
408
|
+
infer_word_pins(word, base_type, internal).first
|
409
|
+
end
|
410
|
+
|
411
|
+
# @return [String]
|
412
|
+
def infer_word_type word, base_type, internal = false
|
413
|
+
return base_type if word == 'self' and internal
|
414
|
+
if word == 'new'
|
415
|
+
namespace, scope = extract_namespace_and_scope(base_type)
|
416
|
+
return namespace if scope == :class
|
417
|
+
end
|
418
|
+
pin = infer_word_pin(word, base_type, internal)
|
419
|
+
return nil if pin.nil?
|
420
|
+
pin.resolve self
|
421
|
+
pin.return_type
|
422
|
+
end
|
423
|
+
|
424
|
+
# Get an array of pins for a method name in the provided context. Private
|
425
|
+
# and protected methods are excluded by default. Set the `internal`
|
426
|
+
# parameter to `true` to include all methods.
|
427
|
+
#
|
428
|
+
# @param method_name [String] The name of the method
|
429
|
+
# @param base_type [String] The context type (e.g., `String` or `Class<String>`)
|
430
|
+
# @param internal [Boolean] True if the call came from inside the base type
|
431
|
+
# @return [Array<Solargraph::Pin::Base>]
|
432
|
+
def infer_method_pins method_name, base_type, internal = false
|
433
|
+
get_type_methods(base_type, (internal ? base_type : '')).select{|pin| pin.name == method_name}
|
434
|
+
end
|
435
|
+
|
436
|
+
# Get the first pin that matches a method name in the provided context.
|
437
|
+
# Private and protected methods are excluded by default. Set the `internal`
|
438
|
+
# parameter to `true` to include all methods.
|
439
|
+
#
|
440
|
+
# @param method_name [String] The name of the method
|
441
|
+
# @param base_type [String] The context type (e.g., `String` or `Class<String>`)
|
442
|
+
# @param internal [Boolean] True if the call came from inside the base type
|
443
|
+
# @return [Solargraph::Pin::Base]
|
444
|
+
def infer_method_pin method_name, base_type, internal = false
|
445
|
+
infer_method_pins(method_name, base_type, internal).first
|
446
|
+
end
|
447
|
+
|
448
|
+
# Infer the type returned by a method in the provided context. Private and
|
449
|
+
# protected methods are excluded by default. Set the `internal` parameter
|
450
|
+
# to `true` to include all methods.
|
451
|
+
#
|
452
|
+
# @param method_name [String] The name of the method
|
453
|
+
# @param base_type [String] The context type (e.g., `String` or `Class<String>`)
|
454
|
+
# @param internal [Boolean] True if the call came from inside the base type
|
455
|
+
# @return [String]
|
456
|
+
def infer_method_type method_name, base_type, internal = false
|
457
|
+
namespace, scope = extract_namespace_and_scope(base_type)
|
458
|
+
method = infer_method_pin(method_name, base_type, internal)
|
459
|
+
return nil if method.nil?
|
460
|
+
method.resolve self
|
461
|
+
return namespace if method.name == 'new' and scope == :class
|
462
|
+
return base_type if method.return_type == 'self'
|
463
|
+
method.return_type
|
464
|
+
end
|
465
|
+
|
466
|
+
def infer_deep_signature_type chain, base_type
|
467
|
+
return nil if base_type.nil?
|
468
|
+
internal = true
|
469
|
+
until chain.empty?
|
470
|
+
base = chain.shift
|
471
|
+
base_type = infer_method_type(base, base_type, internal)
|
472
|
+
return nil if base_type.nil?
|
473
|
+
internal = false
|
474
|
+
end
|
475
|
+
base_type
|
476
|
+
end
|
477
|
+
|
478
|
+
# @return [Array<Solargraph::Pin::GlobalVariable>]
|
479
|
+
def get_global_variable_pins
|
480
|
+
globals = []
|
481
|
+
@sources.each do |s|
|
482
|
+
globals.concat s.global_variable_pins
|
483
|
+
end
|
484
|
+
globals
|
485
|
+
end
|
486
|
+
|
487
|
+
def get_type_methods type, context = ''
|
488
|
+
return [] if type.nil?
|
489
|
+
namespace, scope = extract_namespace_and_scope(type)
|
490
|
+
base = extract_namespace(context)
|
491
|
+
fqns = find_fully_qualified_namespace(namespace, base)
|
492
|
+
return [] if fqns.nil?
|
493
|
+
visibility = [:public]
|
494
|
+
visibility.push :private, :protected if fqns == base
|
495
|
+
get_methods fqns, scope: scope, visibility: visibility
|
496
|
+
end
|
497
|
+
|
498
|
+
def get_methods fqns, scope: :instance, visibility: [:public], deep: true
|
499
|
+
result = []
|
500
|
+
skip = []
|
501
|
+
if fqns == ''
|
502
|
+
result.concat inner_get_methods(fqns, :class, visibility, deep, skip)
|
503
|
+
result.concat inner_get_methods(fqns, :instance, visibility, deep, skip)
|
504
|
+
result.concat inner_get_methods('Kernel', :instance, visibility, deep, skip)
|
505
|
+
else
|
506
|
+
result.concat inner_get_methods(fqns, scope, visibility, deep, skip)
|
507
|
+
end
|
508
|
+
result
|
509
|
+
end
|
510
|
+
|
511
|
+
# @param fragment [Solargraph::Source::Fragment]
|
512
|
+
# @return [ApiMap::Completion]
|
513
|
+
def complete fragment
|
514
|
+
return Completion.new([], fragment.whole_word_range) if fragment.string? or fragment.comment? or fragment.calculated_signature.start_with?('.')
|
515
|
+
result = []
|
516
|
+
if !fragment.signature.include?('.')
|
517
|
+
if fragment.signature.start_with?('@@')
|
518
|
+
result.concat get_class_variable_pins(fragment.namespace)
|
519
|
+
elsif fragment.signature.start_with?('@')
|
520
|
+
result.concat get_instance_variable_pins(fragment.namespace, fragment.scope)
|
521
|
+
elsif fragment.signature.start_with?('$')
|
522
|
+
result.concat get_global_variable_pins
|
523
|
+
elsif fragment.signature.start_with?(':') and !fragment.signature.start_with?('::')
|
524
|
+
result.concat get_symbols
|
525
|
+
else
|
526
|
+
unless fragment.signature.include?('::')
|
527
|
+
result.concat prefer_non_nil_variables(fragment.local_variable_pins)
|
528
|
+
result.concat get_type_methods(combine_type(fragment.namespace, fragment.scope), fragment.namespace)
|
529
|
+
result.concat get_type_methods('Kernel')
|
530
|
+
result.concat ApiMap.keywords
|
531
|
+
end
|
532
|
+
result.concat get_constants(fragment.base, fragment.namespace)
|
533
|
+
end
|
534
|
+
else
|
535
|
+
if fragment.signature.include?('::') and !fragment.signature.include?('.')
|
536
|
+
result.concat get_constants(fragment.calculated_base, fragment.namespace)
|
537
|
+
else
|
538
|
+
if fragment.calculated_signature.end_with?('.')
|
539
|
+
rest = fragment.calculated_signature.split('.')
|
540
|
+
else
|
541
|
+
rest = fragment.calculated_base.split('.')
|
542
|
+
end
|
543
|
+
base = rest.shift
|
544
|
+
type = infer_word_type(base, fragment.namespace, scope: fragment.scope)
|
545
|
+
unless type.nil?
|
546
|
+
rest.each do |m|
|
547
|
+
type = infer_method_type(m, type)
|
548
|
+
next if type.nil?
|
549
|
+
end
|
550
|
+
result.concat get_type_methods(type) unless type.nil?
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
filtered = result.uniq(&:identifier).select{|s| s.kind != Solargraph::LanguageServer::CompletionItemKinds::METHOD or s.name.match(/^[a-z0-9_]*(\!|\?|=)?$/i)}.sort_by.with_index{ |x, idx| [x.name, idx] }
|
555
|
+
Completion.new(filtered, fragment.whole_word_range)
|
556
|
+
end
|
557
|
+
|
558
|
+
# @param fragment [Solargraph::Source::Fragment]
|
559
|
+
# @return [Array<Solargraph::Pin::Base>]
|
560
|
+
def define fragment
|
561
|
+
return [] if fragment.string? or fragment.comment?
|
562
|
+
tail_pins fragment.whole_signature, fragment.namespace, fragment.scope, [:public, :private, :protected]
|
563
|
+
end
|
564
|
+
|
565
|
+
def infer_fragment_type fragment
|
566
|
+
parts = fragment.whole_signature.split('.')
|
567
|
+
base = parts.shift
|
568
|
+
type = nil
|
569
|
+
lvar = prefer_non_nil_variables(fragment.local_variable_pins(base)).first
|
570
|
+
unless lvar.nil?
|
571
|
+
lvar.resolve self
|
572
|
+
type = lvar.return_type
|
573
|
+
return nil if type.nil?
|
574
|
+
end
|
575
|
+
type = infer_word_type(base, fragment.namespace, fragment.scope) if type.nil?
|
576
|
+
return nil if type.nil?
|
577
|
+
until parts.empty?
|
578
|
+
meth = parts.shift
|
579
|
+
type = infer_word_type(meth, type)
|
580
|
+
return nil if type.nil?
|
581
|
+
end
|
582
|
+
type
|
583
|
+
end
|
584
|
+
|
585
|
+
# @param fragment [Solargraph::Source::Fragment]
|
586
|
+
def signify fragment
|
587
|
+
return [] unless fragment.argument?
|
588
|
+
return [] if fragment.recipient.whole_signature.nil? or fragment.recipient.whole_signature.empty?
|
589
|
+
base, rest = fragment.recipient.whole_signature.split('.', 2)
|
590
|
+
return infer_word_pins(base, fragment.recipient.namespace, true) if rest.nil?
|
591
|
+
type = nil
|
592
|
+
lvar = prefer_non_nil_variables(fragment.local_variable_pins(base)).first
|
593
|
+
unless lvar.nil?
|
594
|
+
lvar.resolve self
|
595
|
+
type = lvar.return_type
|
596
|
+
return [] if type.nil?
|
597
|
+
end
|
598
|
+
type = infer_word_type(base, fragment.namespace, fragment.scope) if type.nil?
|
599
|
+
return [] if type.nil?
|
600
|
+
ns, sc = extract_namespace_and_scope(type)
|
601
|
+
tail_pins(rest, ns, sc, [:public, :private, :protected])
|
602
|
+
end
|
603
|
+
|
604
|
+
# Get the namespace's type (Class or Module).
|
605
|
+
#
|
606
|
+
# @param [String] A fully qualified namespace
|
607
|
+
# @return [Symbol] :class, :module, or nil
|
608
|
+
def get_namespace_type fqns
|
609
|
+
pin = @namespace_path_pins[fqns]
|
610
|
+
return yard_map.get_namespace_type(fqns) if pin.nil?
|
611
|
+
pin.first.type
|
612
|
+
end
|
613
|
+
|
614
|
+
# Convert a namespace and scope into a type.
|
615
|
+
#
|
616
|
+
# @example
|
617
|
+
# combine_type('String', :instance) => 'String'
|
618
|
+
# combine_type('String', :class) => 'Class<String>'
|
619
|
+
#
|
620
|
+
# @param namespace [String]
|
621
|
+
# @param scope [Symbol] :class or :instance
|
622
|
+
def combine_type namespace, scope
|
623
|
+
return '' if namespace.empty?
|
624
|
+
if scope == :instance
|
625
|
+
namespace
|
626
|
+
else
|
627
|
+
type = get_namespace_type(namespace)
|
628
|
+
"#{type == :class ? 'Class' : 'Module'}<#{namespace}>"
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
# Get an array of all suggestions that match the specified path.
|
633
|
+
#
|
634
|
+
# @param path [String] The path to find
|
635
|
+
# @return [Array<Solargraph::Pin::Base>]
|
636
|
+
def get_path_suggestions path
|
637
|
+
return [] if path.nil?
|
638
|
+
# refresh
|
639
|
+
result = []
|
640
|
+
if path.include?('#')
|
641
|
+
# It's an instance method
|
642
|
+
parts = path.split('#')
|
643
|
+
result = get_methods(parts[0], visibility: [:public, :private, :protected]).select{|s| s.name == parts[1]}
|
644
|
+
elsif path.include?('.')
|
645
|
+
# It's a class method
|
646
|
+
parts = path.split('.')
|
647
|
+
result = get_methods(parts[0], scope: :class, visibility: [:public, :private, :protected]).select{|s| s.name == parts[1]}
|
648
|
+
else
|
649
|
+
# It's a class or module
|
650
|
+
parts = path.split('::')
|
651
|
+
np = @namespace_pins[parts[0..-2].join('::')]
|
652
|
+
unless np.nil?
|
653
|
+
result.concat np.select{|p| p.name == parts.last}
|
654
|
+
end
|
655
|
+
result.concat yard_map.objects(path)
|
656
|
+
end
|
657
|
+
# @todo Resolve the pins?
|
658
|
+
result.map{|pin| pin.resolve(self); pin}
|
659
|
+
# result
|
660
|
+
end
|
661
|
+
|
662
|
+
# Get a list of documented paths that match the query.
|
663
|
+
#
|
664
|
+
# @example
|
665
|
+
# api_map.query('str') # Results will include `String` and `Struct`
|
666
|
+
#
|
667
|
+
# @param query [String] The text to match
|
668
|
+
# @return [Array<String>]
|
669
|
+
def search query
|
670
|
+
rake_yard(@sources) if @yard_stale
|
671
|
+
@yard_stale = false
|
672
|
+
found = []
|
673
|
+
code_object_paths.each do |k|
|
674
|
+
if found.empty? or (query.include?('.') or query.include?('#')) or !(k.include?('.') or k.include?('#'))
|
675
|
+
found.push k if k.downcase.include?(query.downcase)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
found.concat(yard_map.search(query)).uniq.sort
|
679
|
+
end
|
680
|
+
|
681
|
+
# Get YARD documentation for the specified path.
|
682
|
+
#
|
683
|
+
# @example
|
684
|
+
# api_map.document('String#split')
|
685
|
+
#
|
686
|
+
# @param path [String] The path to find
|
687
|
+
# @return [Array<YARD::CodeObject::Base>]
|
688
|
+
def document path
|
689
|
+
rake_yard(@sources) if @yard_stale
|
690
|
+
@yard_stale = false
|
691
|
+
docs = []
|
692
|
+
docs.push code_object_at(path) unless code_object_at(path).nil?
|
693
|
+
docs.concat yard_map.document(path)
|
694
|
+
docs
|
695
|
+
end
|
696
|
+
|
697
|
+
def query_symbols query
|
698
|
+
result = []
|
699
|
+
@sources.each do |s|
|
700
|
+
result.concat s.query_symbols(query)
|
701
|
+
end
|
702
|
+
result
|
703
|
+
end
|
704
|
+
|
705
|
+
def superclass_of fqns
|
706
|
+
found = @superclasses[fqns]
|
707
|
+
return nil if found.nil?
|
708
|
+
found.resolve self
|
709
|
+
found.name
|
710
|
+
end
|
711
|
+
|
712
|
+
def locate_pin location
|
713
|
+
@sources.each do |source|
|
714
|
+
pin = source.locate_pin(location)
|
715
|
+
unless pin.nil?
|
716
|
+
pin.resolve self
|
717
|
+
return pin
|
718
|
+
end
|
719
|
+
end
|
720
|
+
nil
|
721
|
+
end
|
722
|
+
|
723
|
+
private
|
724
|
+
|
725
|
+
# @return [Hash]
|
726
|
+
def namespace_map
|
727
|
+
@namespace_map ||= {}
|
728
|
+
end
|
729
|
+
|
730
|
+
def process_maps
|
731
|
+
@sources = workspace.sources
|
732
|
+
@sources.push @virtual_source unless @virtual_source.nil?
|
733
|
+
cache.clear
|
734
|
+
@ivar_pins = {}
|
735
|
+
@cvar_pins = {}
|
736
|
+
@const_pins = {}
|
737
|
+
@method_pins = {}
|
738
|
+
@symbol_pins = []
|
739
|
+
@attr_pins = {}
|
740
|
+
@namespace_includes = {}
|
741
|
+
@namespace_extends = {}
|
742
|
+
@superclasses = {}
|
743
|
+
@namespace_pins = {}
|
744
|
+
@namespace_path_pins = {}
|
745
|
+
namespace_map.clear
|
746
|
+
@required = workspace.config.required.clone
|
747
|
+
@sources.each do |s|
|
748
|
+
s.namespaces.each do |n|
|
749
|
+
namespace_map[n] ||= []
|
750
|
+
namespace_map[n].concat s.namespace_pins(n)
|
751
|
+
end
|
752
|
+
end
|
753
|
+
@sources.each do |s|
|
754
|
+
map_source s
|
755
|
+
end
|
756
|
+
@required.uniq!
|
757
|
+
live_map.refresh
|
758
|
+
@yard_stale = true
|
759
|
+
@stime = Time.now
|
760
|
+
end
|
761
|
+
|
762
|
+
def rebuild_local_yardoc
|
763
|
+
return if workspace.nil? or !File.exist?(File.join(workspace, '.yardoc'))
|
764
|
+
STDERR.puts "Rebuilding local yardoc for #{workspace}"
|
765
|
+
Dir.chdir(workspace) { Process.spawn('yardoc') }
|
766
|
+
end
|
767
|
+
|
768
|
+
def process_virtual
|
769
|
+
unless @virtual_source.nil?
|
770
|
+
cache.clear
|
771
|
+
namespace_map.clear
|
772
|
+
@sources.each do |s|
|
773
|
+
s.namespace_pins.each do |pin|
|
774
|
+
namespace_map[pin.path] ||= []
|
775
|
+
namespace_map[pin.path].push pin
|
776
|
+
end
|
777
|
+
end
|
778
|
+
map_source @virtual_source
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
def eliminate source
|
783
|
+
[@ivar_pins.values, @cvar_pins.values, @const_pins.values, @method_pins.values, @attr_pins.values, @namespace_pins.values].each do |pinsets|
|
784
|
+
pinsets.each do |pins|
|
785
|
+
pins.delete_if{|pin| pin.filename == source.filename}
|
786
|
+
end
|
787
|
+
end
|
788
|
+
[@namespace_includes.values, @namespace_extends.values].each do |refsets|
|
789
|
+
refsets.each do |refs|
|
790
|
+
refs.delete_if{|ref| ref.pin.filename == source.filename}
|
791
|
+
end
|
792
|
+
end
|
793
|
+
@superclasses.delete_if{|key, ref| ref.pin.filename == source.filename}
|
794
|
+
@symbol_pins.delete_if{|pin| pin.filename == source.filename}
|
795
|
+
end
|
796
|
+
|
797
|
+
# @param [Solargraph::Source]
|
798
|
+
def map_source source
|
799
|
+
source.method_pins.each do |pin|
|
800
|
+
@method_pins[pin.namespace] ||= []
|
801
|
+
@method_pins[pin.namespace].push pin
|
802
|
+
end
|
803
|
+
source.attribute_pins.each do |pin|
|
804
|
+
@attr_pins[pin.namespace] ||= []
|
805
|
+
@attr_pins[pin.namespace].push pin
|
806
|
+
end
|
807
|
+
source.instance_variable_pins.each do |pin|
|
808
|
+
@ivar_pins[pin.namespace] ||= []
|
809
|
+
@ivar_pins[pin.namespace].push pin
|
810
|
+
end
|
811
|
+
source.class_variable_pins.each do |pin|
|
812
|
+
@cvar_pins[pin.namespace] ||= []
|
813
|
+
@cvar_pins[pin.namespace].push pin
|
814
|
+
end
|
815
|
+
source.constant_pins.each do |pin|
|
816
|
+
@const_pins[pin.namespace] ||= []
|
817
|
+
@const_pins[pin.namespace].push pin
|
818
|
+
end
|
819
|
+
source.symbol_pins.each do |pin|
|
820
|
+
@symbol_pins.push pin
|
821
|
+
end
|
822
|
+
source.namespace_pins.each do |pin|
|
823
|
+
@namespace_path_pins[pin.path] ||= []
|
824
|
+
@namespace_path_pins[pin.path].push pin
|
825
|
+
@namespace_pins[pin.namespace] ||= []
|
826
|
+
@namespace_pins[pin.namespace].push pin
|
827
|
+
# @todo Determine whether references should be resolve here or
|
828
|
+
# dynamically during queries
|
829
|
+
unless pin.superclass_reference.nil?
|
830
|
+
@superclasses[pin.path] = pin.superclass_reference
|
831
|
+
# pin.superclass_reference.resolve self
|
832
|
+
end
|
833
|
+
pin.include_references.each do |ref|
|
834
|
+
@namespace_includes[pin.path] ||= []
|
835
|
+
@namespace_includes[pin.path].push ref
|
836
|
+
# ref.resolve self
|
837
|
+
end
|
838
|
+
pin.extend_references.each do |ref|
|
839
|
+
@namespace_extends[pin.path] ||= []
|
840
|
+
@namespace_extends[pin.path].push ref
|
841
|
+
# ref.resolve self
|
842
|
+
end
|
843
|
+
end
|
844
|
+
path_macros.merge! source.path_macros
|
845
|
+
source.required.each do |r|
|
846
|
+
required.push r
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
# @return [Solargraph::ApiMap::Cache]
|
851
|
+
def cache
|
852
|
+
@cache ||= Cache.new
|
853
|
+
end
|
854
|
+
|
855
|
+
def inner_get_methods fqns, scope, visibility, deep, skip
|
856
|
+
reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
|
857
|
+
return [] if skip.include?(reqstr)
|
858
|
+
skip.push reqstr
|
859
|
+
result = []
|
860
|
+
if scope == :instance
|
861
|
+
aps = @attr_pins[fqns]
|
862
|
+
result.concat aps unless aps.nil?
|
863
|
+
end
|
864
|
+
mps = @method_pins[fqns]
|
865
|
+
result.concat mps.select{|pin| (pin.scope == scope or fqns == '') and visibility.include?(pin.visibility)} unless mps.nil?
|
866
|
+
if fqns != '' and scope == :class and !result.map(&:path).include?("#{fqns}.new")
|
867
|
+
# Create a [Class].new method pin from [Class]#initialize
|
868
|
+
init = inner_get_methods(fqns, :instance, [:private], deep, skip - [fqns]).select{|pin| pin.name == 'initialize'}.first
|
869
|
+
unless init.nil?
|
870
|
+
result.unshift Solargraph::Pin::Directed::Method.new(init.source, init.node, init.namespace, :class, :public, init.docstring, 'new', init.namespace)
|
871
|
+
end
|
872
|
+
end
|
873
|
+
if deep
|
874
|
+
scref = @superclasses[fqns]
|
875
|
+
unless scref.nil?
|
876
|
+
sc_visi = [:public]
|
877
|
+
sc_visi.push :protected if visibility.include?(:protected)
|
878
|
+
# sc_fqns = find_fully_qualified_namespace(sc, fqns)
|
879
|
+
scref.resolve self
|
880
|
+
result.concat inner_get_methods(scref.name, scope, sc_visi, true, skip) unless scref.name.nil?
|
881
|
+
end
|
882
|
+
if scope == :instance
|
883
|
+
im = @namespace_includes[fqns]
|
884
|
+
unless im.nil?
|
885
|
+
im.each do |i|
|
886
|
+
i.resolve self
|
887
|
+
result.concat inner_get_methods(i.name, scope, visibility, deep, skip) unless i.name.nil?
|
888
|
+
end
|
889
|
+
end
|
890
|
+
result.concat yard_map.get_instance_methods(fqns, visibility: visibility)
|
891
|
+
result.concat inner_get_methods('Object', :instance, [:public], deep, skip) unless fqns == 'Object'
|
892
|
+
else
|
893
|
+
em = @namespace_extends[fqns]
|
894
|
+
unless em.nil?
|
895
|
+
em.each do |e|
|
896
|
+
e.resolve self
|
897
|
+
result.concat inner_get_methods(e.name, :instance, visibility, deep, skip) unless e.name.nil?
|
898
|
+
end
|
899
|
+
end
|
900
|
+
result.concat yard_map.get_methods(fqns, '', visibility: visibility)
|
901
|
+
type = get_namespace_type(fqns)
|
902
|
+
if type == :class
|
903
|
+
result.concat inner_get_methods('Class', :instance, [:public], deep, skip)
|
904
|
+
else
|
905
|
+
result.concat inner_get_methods('Module', :instance, [:public], deep, skip)
|
906
|
+
end
|
907
|
+
end
|
908
|
+
end
|
909
|
+
result
|
910
|
+
end
|
911
|
+
|
912
|
+
def inner_get_constants fqns, visibility, skip
|
913
|
+
return [] if skip.include?(fqns)
|
914
|
+
skip.push fqns
|
915
|
+
result = []
|
916
|
+
result.concat @const_pins[fqns] if @const_pins.has_key?(fqns)
|
917
|
+
result.concat @namespace_pins[fqns] if @namespace_pins.has_key?(fqns)
|
918
|
+
result.keep_if{|pin| !pin.name.empty? and visibility.include?(pin.visibility)}
|
919
|
+
result.concat yard_map.get_constants(fqns)
|
920
|
+
is = @namespace_includes[fqns]
|
921
|
+
unless is.nil?
|
922
|
+
is.each do |i|
|
923
|
+
i.resolve self
|
924
|
+
result.concat inner_get_constants(i.name, [:public], skip) unless i.name.nil?
|
925
|
+
end
|
926
|
+
end
|
927
|
+
result
|
928
|
+
end
|
929
|
+
|
930
|
+
# Extract a namespace from a type.
|
931
|
+
#
|
932
|
+
# @example
|
933
|
+
# extract_namespace('String') => 'String'
|
934
|
+
# extract_namespace('Class<String>') => 'String'
|
935
|
+
#
|
936
|
+
# @return [String]
|
937
|
+
def extract_namespace type
|
938
|
+
extract_namespace_and_scope(type)[0]
|
939
|
+
end
|
940
|
+
|
941
|
+
# Extract a namespace and a scope (:instance or :class) from a type.
|
942
|
+
#
|
943
|
+
# @example
|
944
|
+
# extract_namespace('String') #=> ['String', :instance]
|
945
|
+
# extract_namespace('Class<String>') #=> ['String', :class]
|
946
|
+
# extract_namespace('Module<Enumerable') #=> ['Enumberable', :class]
|
947
|
+
#
|
948
|
+
# @return [Array] The namespace (String) and scope (Symbol).
|
949
|
+
def extract_namespace_and_scope type
|
950
|
+
scope = :instance
|
951
|
+
result = type.to_s.gsub(/<.*$/, '')
|
952
|
+
if (result == 'Class' or result == 'Module') and type.include?('<')
|
953
|
+
result = type.match(/<([a-z0-9:_]*)/i)[1]
|
954
|
+
scope = :class
|
955
|
+
end
|
956
|
+
[result, scope]
|
957
|
+
end
|
958
|
+
|
959
|
+
def require_extensions
|
960
|
+
Gem::Specification.all_names.select{|n| n.match(/^solargraph\-[a-z0-9_\-]*?\-ext\-[0-9\.]*$/)}.each do |n|
|
961
|
+
STDERR.puts "Loading extension #{n}"
|
962
|
+
require n.match(/^(solargraph\-[a-z0-9_\-]*?\-ext)\-[0-9\.]*$/)[1]
|
963
|
+
end
|
964
|
+
end
|
965
|
+
|
966
|
+
# @return [Array<Solargraph::Pin::Base>]
|
967
|
+
def prefer_non_nil_variables pins
|
968
|
+
result = []
|
969
|
+
nil_pins = []
|
970
|
+
pins.each do |pin|
|
971
|
+
if pin.nil_assignment? and pin.return_type.nil?
|
972
|
+
nil_pins.push pin
|
973
|
+
else
|
974
|
+
result.push pin
|
975
|
+
end
|
976
|
+
end
|
977
|
+
result + nil_pins
|
978
|
+
end
|
979
|
+
|
980
|
+
# @todo DRY this method. It's duplicated in CodeMap
|
981
|
+
def get_subtypes type
|
982
|
+
return [] if type.nil?
|
983
|
+
match = type.match(/<([a-z0-9_:, ]*)>/i)
|
984
|
+
return [] if match.nil?
|
985
|
+
match[1].split(',').map(&:strip)
|
986
|
+
end
|
987
|
+
|
988
|
+
# @return [Hash]
|
989
|
+
def path_macros
|
990
|
+
@path_macros ||= {}
|
991
|
+
end
|
992
|
+
|
993
|
+
def current_workspace_sources
|
994
|
+
@sources - [@virtual_source]
|
995
|
+
end
|
996
|
+
end
|
997
|
+
end
|