solargraph 0.18.2 → 0.18.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|