yoda-language-server 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +5 -3
  3. data/README.md +50 -48
  4. data/client/atom/main.js +13 -3
  5. data/client/vscode/.vscode/launch.json +7 -4
  6. data/client/vscode/package-lock.json +585 -1454
  7. data/client/vscode/package.json +10 -7
  8. data/client/vscode/src/extension.ts +3 -3
  9. data/client/vscode/src/test/completion.test.ts +39 -0
  10. data/client/vscode/src/test/helper.ts +38 -0
  11. data/client/vscode/src/test/index.ts +5 -3
  12. data/client/vscode/testFixture/completion.rb +1 -0
  13. data/exe/yoda +1 -20
  14. data/lib/yoda.rb +2 -1
  15. data/lib/yoda/commands.rb +34 -0
  16. data/lib/yoda/commands/base.rb +10 -0
  17. data/lib/yoda/commands/complete.rb +36 -0
  18. data/lib/yoda/commands/file_cursor_parsable.rb +29 -0
  19. data/lib/yoda/{runner → commands}/infer.rb +4 -9
  20. data/lib/yoda/commands/setup.rb +37 -0
  21. data/lib/yoda/errors.rb +34 -0
  22. data/lib/yoda/evaluation/evaluator.rb +2 -0
  23. data/lib/yoda/server.rb +60 -15
  24. data/lib/yoda/server/completion_provider.rb +8 -8
  25. data/lib/yoda/server/definition_provider.rb +8 -8
  26. data/lib/yoda/server/hover_provider.rb +6 -6
  27. data/lib/yoda/server/initialization_provider.rb +85 -0
  28. data/lib/yoda/server/{client_info.rb → session.rb} +6 -2
  29. data/lib/yoda/server/signature_provider.rb +6 -6
  30. data/lib/yoda/store/actions.rb +3 -1
  31. data/lib/yoda/store/actions/build_core_index.rb +44 -0
  32. data/lib/yoda/store/actions/import_core_library.rb +14 -9
  33. data/lib/yoda/store/actions/import_gem.rb +98 -0
  34. data/lib/yoda/store/actions/import_std_library.rb +35 -0
  35. data/lib/yoda/store/adapters.rb +1 -0
  36. data/lib/yoda/store/adapters/memory_adapter.rb +81 -0
  37. data/lib/yoda/store/objects.rb +4 -0
  38. data/lib/yoda/store/objects/addressable.rb +0 -12
  39. data/lib/yoda/store/objects/base.rb +4 -14
  40. data/lib/yoda/store/objects/merger.rb +4 -4
  41. data/lib/yoda/store/objects/patchable.rb +19 -0
  42. data/lib/yoda/store/objects/project_status.rb +169 -0
  43. data/lib/yoda/store/objects/serializable.rb +39 -0
  44. data/lib/yoda/store/project.rb +28 -114
  45. data/lib/yoda/store/project/cache.rb +79 -0
  46. data/lib/yoda/store/project/library_doc_loader.rb +102 -0
  47. data/lib/yoda/store/query/find_constant.rb +2 -1
  48. data/lib/yoda/store/registry.rb +15 -0
  49. data/lib/yoda/store/yard_importer.rb +58 -28
  50. data/lib/yoda/typing/evaluator.rb +8 -5
  51. data/lib/yoda/version.rb +1 -1
  52. data/package.json +32 -11
  53. data/scripts/benchmark.rb +1 -1
  54. data/yoda-language-server.gemspec +1 -0
  55. metadata +37 -7
  56. data/client/vscode/src/test/extension.test.ts +0 -22
  57. data/lib/yoda/runner/setup.rb +0 -26
  58. data/lib/yoda/store/actions/import_gems.rb +0 -91
@@ -0,0 +1,35 @@
1
+ module Yoda
2
+ module Store
3
+ module Actions
4
+ class ImportStdLibrary
5
+ # @return [Registry]
6
+ attr_reader :registry
7
+
8
+ class << self
9
+ # @return [true, false]
10
+ def run(registry)
11
+ new(registry).run
12
+ end
13
+ end
14
+
15
+ def initialize(registry)
16
+ @registry = registry
17
+ end
18
+
19
+ # @return [true, false]
20
+ def run
21
+ return false unless File.exist?(doc_path)
22
+ patch = YardImporter.import(doc_path)
23
+ registry.add_patch(patch)
24
+ true
25
+ end
26
+
27
+ private
28
+
29
+ def doc_path
30
+ File.expand_path("~/.yoda/sources/ruby-#{RUBY_VERSION}/.yardoc-stdlib")
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -4,6 +4,7 @@ module Yoda
4
4
  require 'yoda/store/adapters/base'
5
5
  require 'yoda/store/adapters/leveldb_adapter'
6
6
  require 'yoda/store/adapters/lmdb_adapter'
7
+ require 'yoda/store/adapters/memory_adapter'
7
8
 
8
9
  # @return [Base.class]
9
10
  def self.default_adapter_class
@@ -0,0 +1,81 @@
1
+ require 'json'
2
+
3
+ module Yoda
4
+ module Store
5
+ module Adapters
6
+ # An adapter implementation to store object in memory.
7
+ # This implementation losts data on exit and we recommend to use this adapter only for test.
8
+ class MemoryAdapter < Base
9
+ class << self
10
+ def for(path)
11
+ @pool ||= {}
12
+ @pool[path] || (@pool[path] = new(path))
13
+ end
14
+
15
+ def type
16
+ :memory
17
+ end
18
+ end
19
+
20
+ # @return [Hash{String => String}]
21
+ attr_reader :db
22
+
23
+ # @param path [String, nil] represents the path to store db.
24
+ def initialize(path = nil)
25
+ @path = path
26
+ @db = {}
27
+ end
28
+
29
+ # @param address [String]
30
+ # @return [any]
31
+ def get(address)
32
+ JSON.load(db[address.to_s], symbolize_names: true)
33
+ end
34
+
35
+ # @param data [Enumerator<(String, Object)>]
36
+ # @param bar [ProgressBar, nil]
37
+ def batch_write(data, bar)
38
+ data.each do |(k, v)|
39
+ put(k, v)
40
+ bar&.increment
41
+ end
42
+ end
43
+
44
+ # @param address [String]
45
+ # @param object [Object]
46
+ # @return [void]
47
+ def put(address, object)
48
+ db[address.to_s] = object.to_json
49
+ end
50
+
51
+ # @param address [String]
52
+ # @return [void]
53
+ def delete(address)
54
+ db.delete(address.to_s)
55
+ end
56
+
57
+ # @param address [String]
58
+ # @return [true, false]
59
+ def exist?(address)
60
+ db.member?(address.to_s)
61
+ end
62
+
63
+ # @return [Array<String>]
64
+ def keys
65
+ db.keys
66
+ end
67
+
68
+ def stats
69
+ "No stats"
70
+ end
71
+
72
+ def clear
73
+ db.clear
74
+ end
75
+
76
+ def sync
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -4,6 +4,9 @@ module Yoda
4
4
  VALUE_REGEXP = /\A[0-9a-z]/
5
5
  MODULE_TAIL_PATTERN = /(?:::(\w+)|^(\w+))$/
6
6
 
7
+ require 'yoda/store/objects/serializable'
8
+ require 'yoda/store/objects/addressable'
9
+ require 'yoda/store/objects/patchable'
7
10
  require 'yoda/store/objects/base'
8
11
  require 'yoda/store/objects/namespace_object'
9
12
  require 'yoda/store/objects/class_object'
@@ -16,6 +19,7 @@ module Yoda
16
19
  require 'yoda/store/objects/patch'
17
20
  require 'yoda/store/objects/patch_set'
18
21
  require 'yoda/store/objects/tag'
22
+ require 'yoda/store/objects/project_status'
19
23
 
20
24
  class << self
21
25
  # @param hsh [Hash]
@@ -2,23 +2,11 @@ module Yoda
2
2
  module Store
3
3
  module Objects
4
4
  module Addressable
5
- # @abstract
6
- # @return [Symbol]
7
- def kind
8
- fail NotImplementedError
9
- end
10
-
11
5
  # @abstract
12
6
  # @return [String]
13
7
  def address
14
8
  fail NotImplementedError
15
9
  end
16
-
17
- # @abstract
18
- # @return [Hash]
19
- def to_hash
20
- fail NotImplementedError
21
- end
22
10
  end
23
11
  end
24
12
  end
@@ -3,16 +3,11 @@ module Yoda
3
3
  module Objects
4
4
  # @abstract
5
5
  class Base
6
- class << self
7
- def json_creatable?
8
- true
9
- end
10
-
11
- # @param params [Hash]
12
- def json_create(params)
13
- new(params.map { |k, v| [k.to_sym, v] }.to_h)
14
- end
6
+ include Addressable
7
+ include Serializable
8
+ include Patchable
15
9
 
10
+ class << self
16
11
  # @return [Array<Symbol>]
17
12
  def attr_names
18
13
  %i(path document tag_list sources primary_source)
@@ -74,11 +69,6 @@ module Yoda
74
69
  }
75
70
  end
76
71
 
77
- # @return [String]
78
- def to_json
79
- to_h.merge(json_class: self.class.name).to_json
80
- end
81
-
82
72
  # @param another [self]
83
73
  # @return [self]
84
74
  def merge(another)
@@ -48,11 +48,11 @@ module Yoda
48
48
  tag_list: one[:tag_list] + another[:tag_list],
49
49
  sources: one[:sources] + another[:sources],
50
50
  primary_source: one[:primary_source] || another[:primary_source],
51
- instance_method_addresses: one[:instance_method_addresses] + another[:instance_method_addresses],
52
- mixin_addresses: one[:mixin_addresses] + another[:mixin_addresses],
53
- constant_addresses: one[:constant_addresses] + another[:constant_addresses],
51
+ instance_method_addresses: (one[:instance_method_addresses] + another[:instance_method_addresses]).uniq,
52
+ mixin_addresses: (one[:mixin_addresses] + another[:mixin_addresses]).uniq,
53
+ constant_addresses: (one[:constant_addresses] + another[:constant_addresses]).uniq,
54
54
  visibility: one[:visibility] || another[:visibility],
55
- parameters: one[:parameters].empty? ? another[:parameters] : one[:parameters],
55
+ parameters: one[:parameters].empty? ? another[:parameters] : one[:parameters],
56
56
  overloads: one[:overloads] + another[:overloads],
57
57
  superclass_path: select_superclass(one, another),
58
58
  value: one[:value] || another[:value],
@@ -0,0 +1,19 @@
1
+ module Yoda
2
+ module Store
3
+ module Objects
4
+ module Patchable
5
+ # @abstract
6
+ # @return [Symbol]
7
+ def kind
8
+ fail NotImplementedError
9
+ end
10
+
11
+ # @abstract
12
+ # @return [Hash]
13
+ def to_h
14
+ fail NotImplementedError
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,169 @@
1
+ module Yoda
2
+ module Store
3
+ module Objects
4
+ class ProjectStatus
5
+ include Serializable
6
+
7
+ # @return [Integer]
8
+ attr_reader :version
9
+
10
+ # @return [BundleStatus]
11
+ attr_reader :bundle
12
+
13
+ # @param specs [Array<Bundler::LazySpecification>]
14
+ # @return [BundleStatus]
15
+ def self.initial_build(specs:)
16
+ new(bundle: BundleStatus.initial_build(specs), version: Registry::REGISTRY_VERSION)
17
+ end
18
+
19
+ # @param bundle [BundleStatus]
20
+ # @param version [Integer] the version number of registry
21
+ def initialize(bundle:, version:)
22
+ @bundle = bundle
23
+ @version = version
24
+ end
25
+
26
+ def to_h
27
+ { bundle: bundle, version: version }
28
+ end
29
+
30
+ # Remember gem dependencies and loaded gems
31
+ class BundleStatus
32
+ include Serializable
33
+
34
+ # @return [Array<GemStatus>]
35
+ attr_reader :gem_statuses
36
+
37
+ # @return [StdStatus]
38
+ attr_reader :std_status
39
+
40
+ # @param specs [Array<Bundler::LazySpecification>]
41
+ # @return [BundleStatus]
42
+ def self.initial_build(specs)
43
+ gem_statuses = specs.map { |spec| ProjectStatus::GemStatus.initial_build(spec) }
44
+ std_status = StdStatus.initial_build
45
+ new(gem_statuses: gem_statuses, std_status: std_status)
46
+ end
47
+
48
+ # @param gem_statuses [Array<GemStatus>]
49
+ # @param std_status [StdStatus]
50
+ def initialize(gem_statuses:, std_status:)
51
+ @gem_statuses = gem_statuses
52
+ @std_status = std_status
53
+ end
54
+
55
+ def to_h
56
+ { gem_statuses: gem_statuses, std_status: std_status }
57
+ end
58
+
59
+ # @param name [String]
60
+ # @return [GemStatus, nil]
61
+ def [](name)
62
+ dictionary[name]
63
+ end
64
+
65
+ # @return [true, false]
66
+ def all_present?
67
+ gem_statuses.all?(&:present?) && std_status.all_present?
68
+ end
69
+
70
+ # @return [Array<GemStatus>]
71
+ def present_gems
72
+ gem_statuses.select(&:present?)
73
+ end
74
+
75
+ # @return [Array<GemStatus>]
76
+ def not_present_gems
77
+ gem_statuses.reject(&:present?)
78
+ end
79
+
80
+ private
81
+
82
+ # @return [Hash{String => GemStatus}]
83
+ def dictionary
84
+ @dictionary ||= gem_statuses.map do |gem_status|
85
+ [gem_status.name, gem_status]
86
+ end.to_h
87
+ end
88
+ end
89
+
90
+ # Remember ruby core and standard library state
91
+ class StdStatus
92
+ include Serializable
93
+ # @return [String]
94
+ attr_reader :version
95
+
96
+ # @return [true, false]
97
+ attr_reader :core_present, :std_present
98
+
99
+ # @return [StdStatus]
100
+ def self.initial_build
101
+ new(version: RUBY_VERSION, core_present: false, std_present: false)
102
+ end
103
+
104
+ # @param version [String]
105
+ # @param core_present [true, false] represents the flag if core's index file is present.
106
+ # @param std_present [true, false] represents the flag if standard library's index file is present.
107
+ def initialize(version:, core_present:, std_present:)
108
+ @version = version
109
+ @core_present = core_present
110
+ @std_present = std_present
111
+ end
112
+
113
+ # @return [true, false]
114
+ def all_present?
115
+ core_present? && std_present?
116
+ end
117
+
118
+ # @return [true, false]
119
+ def core_present?
120
+ core_present
121
+ end
122
+
123
+ # @return [true, false]
124
+ def std_present?
125
+ std_present
126
+ end
127
+
128
+ def to_h
129
+ { version: version, core_present: core_present, std_present: std_present }
130
+ end
131
+ end
132
+
133
+ # Remember each gem state
134
+ class GemStatus
135
+ include Serializable
136
+ # @return [String]
137
+ attr_reader :name, :version
138
+
139
+ # @return [true, false]
140
+ attr_reader :present
141
+
142
+ # @param gem [Bundler::LazySpecification]
143
+ # @return [GemStatus]
144
+ def self.initial_build(gem)
145
+ new(name: gem.name, version: gem.version, present: false)
146
+ end
147
+
148
+ # @param name [String]
149
+ # @param version [String]
150
+ # @param present [true, false] represents the flag if the specified gem's index file is present.
151
+ def initialize(name:, version:, present:)
152
+ @name = name
153
+ @version = version
154
+ @present = present
155
+ end
156
+
157
+ def to_h
158
+ { name: name, version: version, present: present }
159
+ end
160
+
161
+ # @return [true, false]
162
+ def present?
163
+ !!present
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,39 @@
1
+ module Yoda
2
+ module Store
3
+ module Objects
4
+ module Serializable
5
+ module ClassMethods
6
+ def json_creatable?
7
+ true
8
+ end
9
+
10
+ # @param params [Hash]
11
+ def json_create(params)
12
+ new(params.reject { |k, _v| k.to_sym == :json_class }.map { |k, v| [k.to_sym, v] }.to_h)
13
+ end
14
+ end
15
+
16
+ def self.included(klass)
17
+ klass.extend(ClassMethods)
18
+ end
19
+
20
+ # @abstract
21
+ # @return [Hash]
22
+ def to_h
23
+ fail NotImplementedError
24
+ end
25
+
26
+ # @return [String]
27
+ def to_json(*options)
28
+ to_h.merge(json_class: self.class.name).to_json
29
+ end
30
+
31
+ # Create a new instance which has the original parameters and overrided parameters.
32
+ # @param params [Hash{Symbol => Object}] parameters to override
33
+ def derive(params = {})
34
+ self.class.new(to_h.merge(params))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end