yoda-language-server 0.4.0 → 0.5.0

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.
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