yoda-language-server 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +17 -9
- data/client/atom/main.js +20 -0
- data/lib/yoda.rb +4 -0
- data/lib/yoda/commands.rb +18 -1
- data/lib/yoda/commands/setup.rb +17 -3
- data/lib/yoda/instrument.rb +113 -0
- data/lib/yoda/logger.rb +68 -0
- data/lib/yoda/server.rb +9 -3
- data/lib/yoda/server/initialization_provider.rb +13 -2
- data/lib/yoda/server/notifier.rb +61 -0
- data/lib/yoda/server/session.rb +4 -1
- data/lib/yoda/store/actions/build_core_index.rb +3 -3
- data/lib/yoda/store/actions/import_gem.rb +13 -13
- data/lib/yoda/store/actions/read_project_files.rb +9 -1
- data/lib/yoda/store/adapters/base.rb +6 -0
- data/lib/yoda/store/adapters/leveldb_adapter.rb +1 -1
- data/lib/yoda/store/adapters/lmdb_adapter.rb +1 -1
- data/lib/yoda/store/adapters/memory_adapter.rb +1 -1
- data/lib/yoda/store/project.rb +6 -5
- data/lib/yoda/store/project/library_doc_loader.rb +27 -16
- data/lib/yoda/store/registry.rb +4 -6
- data/lib/yoda/version.rb +1 -1
- data/yarn.lock +41 -7
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b544f7f3b34a813b4315f584e191ffd2c818dc63bfd24a093eec32fc4521b391
|
4
|
+
data.tar.gz: ba9b8cbc95bdd15d90f23b3921634cf2a3de5c3d61d3a2049e1ea6028d4d880f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa9a0e6cab7d9320eab849a9409706ae3a10ecac15ac5f65d380f07e7fdf5fc89482f327675d0eac4d66764b5198c007504d91ac9a58910677779383084b6f37
|
7
|
+
data.tar.gz: 325f262ab02a095ecc3005b369ffd233b0faa5837de49b9e60a563e192e0fc1cfacd8a80f0863b5a7801a897af34dae02cbe0df075aeb711405aa6cdb4e2379c
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
yoda-language-server (0.
|
4
|
+
yoda-language-server (0.6.0)
|
5
5
|
language_server-protocol (~> 3.7.0.0)
|
6
6
|
leveldb (~> 0.1.9)
|
7
7
|
lmdb (~> 0.4.8)
|
@@ -57,10 +57,10 @@ GEM
|
|
57
57
|
diff-lcs (>= 1.2.0, < 2.0)
|
58
58
|
rspec-support (~> 3.7.0)
|
59
59
|
rspec-support (3.7.1)
|
60
|
-
ruby-progressbar (1.
|
60
|
+
ruby-progressbar (1.10.0)
|
61
61
|
stackprof (0.2.11)
|
62
62
|
thor (0.20.0)
|
63
|
-
yard (0.9.
|
63
|
+
yard (0.9.16)
|
64
64
|
|
65
65
|
PLATFORMS
|
66
66
|
ruby
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
# Yoda
|
1
|
+
# Yoda [](https://travis-ci.org/tomoasleep/yoda)
|
2
2
|
|
3
|
-
Yoda is a Language Server for Ruby and provides autocompletion and code analysis (go-to-definition, code information, etc...).
|
4
|
-
|
3
|
+
Yoda is a Language Server (http://langserver.org/) for Ruby and provides autocompletion and code analysis (go-to-definition, code information, etc...).
|
4
|
+
|
5
|
+
**Note: Yoda is alpha version. Please use with caution. Contributions are welcome!**
|
5
6
|
|
6
7
|
## Instation and Usage
|
7
8
|
|
@@ -27,16 +28,23 @@ $ yoda complete <path-to-your-code>:<line-num>:<char-num> # Show completion at t
|
|
27
28
|
### Atom
|
28
29
|
|
29
30
|
```
|
30
|
-
apm install
|
31
|
+
apm install tomoasleep/yoda
|
31
32
|
```
|
32
33
|
|
33
34
|
### VSCode
|
34
35
|
|
35
36
|
TBW
|
36
37
|
|
37
|
-
### Vim
|
38
|
+
### Vim/NeoVim
|
38
39
|
|
39
|
-
|
40
|
+
Please use language server client such as [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim).
|
41
|
+
Here is a configuration example for LanguageClient-neovim.
|
42
|
+
|
43
|
+
```vim
|
44
|
+
let g:LanguageClient_serverCommands = {
|
45
|
+
\ 'ruby': ['yoda', 'server'],
|
46
|
+
\ }
|
47
|
+
```
|
40
48
|
|
41
49
|
### Emacs
|
42
50
|
|
@@ -46,13 +54,13 @@ TBW
|
|
46
54
|
|
47
55
|
### YARD utilization
|
48
56
|
|
49
|
-
Yoda figures structures of your source codes and library codes with YARD.
|
57
|
+
Yoda figures structures of your source codes and library codes with YARD.
|
50
58
|
Yoda intepret YARD tags such as `@return` tags and `@param` tags and infer code types from these information.
|
51
59
|
|
52
60
|
### Indexing
|
53
61
|
|
54
|
-
Yoda built index files for fast inference under `<your-project-dir>/.yoda` at startup.
|
55
|
-
These index files contains structures of external sources (gems and standard libraries).
|
62
|
+
Yoda built index files for fast inference under `<your-project-dir>/.yoda` at startup.
|
63
|
+
These index files contains structures of external sources (gems and standard libraries).
|
56
64
|
Your project codes are parsed at startup but does not stored in indexes.
|
57
65
|
|
58
66
|
### Supporting Features
|
data/client/atom/main.js
CHANGED
@@ -7,6 +7,26 @@ class YodaClient extends AutoLanguageClient {
|
|
7
7
|
super()
|
8
8
|
}
|
9
9
|
|
10
|
+
preInitialization(connection) {
|
11
|
+
connection.onTelemetryEvent(({ type, phase, message }) => {
|
12
|
+
if (!this.busySignalService) { return; }
|
13
|
+
if (type != 'initialization') { return; }
|
14
|
+
|
15
|
+
if (this.initializationBusyMessage) {
|
16
|
+
this.initializationBusyMessage.setTitle(message);
|
17
|
+
} else {
|
18
|
+
this.initializationBusyMessage = this.busySignalService.reportBusy(message);
|
19
|
+
}
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
postInitialization(_server) {
|
24
|
+
if (this.initializationBusyMessage) {
|
25
|
+
this.initializationBusyMessage.dispose();
|
26
|
+
this.initializationBusyMessage = null;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
10
30
|
getGrammarScopes () { return ['source.ruby', 'source.rb', 'source.ruby.rails'] }
|
11
31
|
getLanguageName () { return 'Ruby' }
|
12
32
|
getServerName () { return 'Yoda' }
|
data/lib/yoda.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Yoda
|
2
2
|
require "yoda/version"
|
3
|
+
require "yoda/logger"
|
4
|
+
require "yoda/instrument"
|
3
5
|
require "yoda/commands"
|
4
6
|
require "yoda/errors"
|
5
7
|
require "yoda/evaluation"
|
@@ -10,3 +12,5 @@ module Yoda
|
|
10
12
|
require "yoda/typing"
|
11
13
|
require "yoda/yard_extensions"
|
12
14
|
end
|
15
|
+
|
16
|
+
YARD::Logger.instance.io = Yoda::Logger.instance.pipeline(tag: 'YARD')
|
data/lib/yoda/commands.rb
CHANGED
@@ -10,25 +10,42 @@ module Yoda
|
|
10
10
|
require 'yoda/commands/complete'
|
11
11
|
|
12
12
|
class Top < Thor
|
13
|
+
class_option :log_level, type: :string, desc: 'Set log level (debug info warn error fatal)'
|
14
|
+
|
13
15
|
desc 'setup', 'Setup indexes for current Ruby version and project gems'
|
16
|
+
option :force_build, type: :boolean, desc: "If enabled, (re)build current project's index forcibly"
|
14
17
|
def setup
|
15
|
-
|
18
|
+
process_class_options
|
19
|
+
Commands::Setup.run(force_build: options[:force_build])
|
16
20
|
end
|
17
21
|
|
18
22
|
desc 'infer POSITION', 'Infer the type of value at the specified position'
|
19
23
|
def infer(position)
|
24
|
+
process_class_options
|
20
25
|
Commands::Infer.run(position)
|
21
26
|
end
|
22
27
|
|
23
28
|
desc 'complete POSITION', 'Provide completion candidates for the specified position'
|
24
29
|
def complete(position)
|
30
|
+
process_class_options
|
25
31
|
Commands::Complete.run(position)
|
26
32
|
end
|
27
33
|
|
28
34
|
desc 'server', 'Start Language Server'
|
29
35
|
def server
|
36
|
+
process_class_options
|
30
37
|
Server.new.run
|
31
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def process_class_options
|
43
|
+
set_log_level
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_log_level
|
47
|
+
Yoda::Logger.log_level = options[:log_level].to_sym if options[:log_level]
|
48
|
+
end
|
32
49
|
end
|
33
50
|
end
|
34
51
|
end
|
data/lib/yoda/commands/setup.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ruby-progressbar'
|
2
|
+
|
1
3
|
module Yoda
|
2
4
|
module Commands
|
3
5
|
class Setup < Base
|
@@ -7,19 +9,25 @@ module Yoda
|
|
7
9
|
# @return [true, false]
|
8
10
|
attr_reader :force_build
|
9
11
|
|
12
|
+
# @return [Hash{ Symbol => ProgressBar }]
|
13
|
+
attr_reader :bars
|
14
|
+
|
10
15
|
# @param dir [String]
|
11
16
|
def initialize(dir: nil, force_build: false)
|
12
17
|
@dir = dir || Dir.pwd
|
13
18
|
@force_build = force_build
|
19
|
+
@bars = {}
|
14
20
|
end
|
15
21
|
|
16
22
|
def run
|
17
23
|
build_core_index
|
18
24
|
if File.exist?(File.expand_path('Gemfile.lock', dir)) || force_build
|
19
|
-
|
20
|
-
|
25
|
+
Logger.info 'Building index for the current project...'
|
26
|
+
Instrument.instance.hear(initialization_progress: method(:on_progress), registry_dump: method(:on_progress)) do
|
27
|
+
force_build ? project.rebuild_cache : project.build_cache
|
28
|
+
end
|
21
29
|
else
|
22
|
-
|
30
|
+
Logger.info 'Skipped building project index because Gemfile.lock is not exist for the current dir'
|
23
31
|
end
|
24
32
|
end
|
25
33
|
|
@@ -32,6 +40,12 @@ module Yoda
|
|
32
40
|
def build_core_index
|
33
41
|
Store::Actions::BuildCoreIndex.run unless Store::Actions::BuildCoreIndex.exists?
|
34
42
|
end
|
43
|
+
|
44
|
+
def on_progress(phase: :save_keys, index: nil, length: nil, **params)
|
45
|
+
return unless index
|
46
|
+
bar = bars[phase] ||= ProgressBar.create(format: "%t: %c/%C |%w>%i| %e ", title: phase.to_s.gsub('_', ' '), starting_at: index, total: length)
|
47
|
+
bar.progress = index if index <= bar.total
|
48
|
+
end
|
35
49
|
end
|
36
50
|
end
|
37
51
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Yoda
|
2
|
+
class Instrument
|
3
|
+
class Subscription
|
4
|
+
# @return [Instrument]
|
5
|
+
attr_reader :instrument
|
6
|
+
|
7
|
+
# @return [String]
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
# @return [#call]
|
11
|
+
attr_reader :callback
|
12
|
+
|
13
|
+
# @param instrument [Instrument]
|
14
|
+
# @param name [String]
|
15
|
+
# @param callback [#call]
|
16
|
+
def initialize(instrument:, name:, callback:)
|
17
|
+
@instrument = instrument
|
18
|
+
@name = name
|
19
|
+
@callback = callback
|
20
|
+
end
|
21
|
+
|
22
|
+
def unsubscribe
|
23
|
+
instrument.unsubscribe(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
def call(params)
|
27
|
+
callback.call(params)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Progress
|
32
|
+
# @return [Integer]
|
33
|
+
attr_reader :length, :index
|
34
|
+
|
35
|
+
# @return [#call]
|
36
|
+
attr_reader :callback
|
37
|
+
|
38
|
+
# @param length [Integer]
|
39
|
+
# @param callback [#call]
|
40
|
+
def initialize(length, &callback)
|
41
|
+
@length = length
|
42
|
+
@index = 0
|
43
|
+
@callback = callback
|
44
|
+
call
|
45
|
+
end
|
46
|
+
|
47
|
+
def increment
|
48
|
+
@index += 1
|
49
|
+
call
|
50
|
+
end
|
51
|
+
|
52
|
+
def call
|
53
|
+
callback.call(length: length, index: index)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Array<Subscription>]
|
58
|
+
attr_reader :subscriptions
|
59
|
+
|
60
|
+
# @return [Instrument]
|
61
|
+
def self.instance
|
62
|
+
@instance ||= new
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize
|
66
|
+
@subscriptions = []
|
67
|
+
end
|
68
|
+
|
69
|
+
# Add subscriptions and eval the given block. these subscriptions are unsubscribed after the block.
|
70
|
+
# @param subscription_hash [Hash{ Symbol, String => #call }]
|
71
|
+
def hear(subscription_hash = {})
|
72
|
+
subscriptions = subscription_hash.map { |key, value| subscribe(key, &value) }
|
73
|
+
value = yield
|
74
|
+
subscriptions.each(&:unsubscribe)
|
75
|
+
value
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param name [String, Symbol]
|
79
|
+
# @param callback [#call]
|
80
|
+
# @return [Subsctiption]
|
81
|
+
def subscribe(name, &callback)
|
82
|
+
Subscription.new(instrument: self, name: name, callback: callback).tap { |subscription| subscriptions.push(subscription) }
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param name [String]
|
86
|
+
# @param [String]
|
87
|
+
def emit(name, params)
|
88
|
+
Logger.trace("#{name}: #{params}")
|
89
|
+
subscriptions.select { |subscription| subscription.name === name }.each { |subscription| subscription.call(params) }
|
90
|
+
end
|
91
|
+
|
92
|
+
# @param subscription [Subscription]
|
93
|
+
def unsubscribe(subscription)
|
94
|
+
subscriptions.delete(subscription)
|
95
|
+
end
|
96
|
+
|
97
|
+
# @!group event_name
|
98
|
+
|
99
|
+
# @param phase [Symbol]
|
100
|
+
# @param message [String]
|
101
|
+
# @param index [Integer, nil]
|
102
|
+
# @param length [Integer, nil]
|
103
|
+
def initialization_progress(phase:, message:, index: nil, length: nil)
|
104
|
+
emit(:initialization_progress, phase: phase, message: message, index: index, length: length)
|
105
|
+
end
|
106
|
+
|
107
|
+
# @param index [Integer, nil]
|
108
|
+
# @param length [Integer, nil]
|
109
|
+
def registry_dump(index: nil, length: nil)
|
110
|
+
emit(:registry_dump, index: index, length: length)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/yoda/logger.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Yoda
|
4
|
+
class Logger
|
5
|
+
LOG_LEVELS = %i(trace debug info warn error fatal).freeze
|
6
|
+
|
7
|
+
class << self
|
8
|
+
extend Forwardable
|
9
|
+
def_delegators :instance, *%i(pipeline trace debug info warn error fatal log_level allow_debug? allow_info? allow_warn? allow_error? allow_fatal? log_level=)
|
10
|
+
|
11
|
+
# @return [Yoda::Logger]
|
12
|
+
def instance
|
13
|
+
@instance ||= Yoda::Logger.new(STDERR)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @!macro [attach]
|
17
|
+
# @!method $1(content, tag: nil)
|
18
|
+
# @param content [String]
|
19
|
+
# @param tag [String, nil]
|
20
|
+
# @!method allow_$1?
|
21
|
+
# @return [true, false]
|
22
|
+
def define_logging_method(level)
|
23
|
+
define_method(level) do |content, tag: nil|
|
24
|
+
return unless public_send("allow_#{level}?")
|
25
|
+
prefix = "[#{level}]#{tag ? ' (' + tag + ')' : '' } "
|
26
|
+
io.puts(prefix + content.to_s.split("\n").join(prefix))
|
27
|
+
end
|
28
|
+
|
29
|
+
define_method("allow_#{level}?") do
|
30
|
+
allowed_log_levels.include?(level)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [IO]
|
36
|
+
attr_accessor :io
|
37
|
+
|
38
|
+
# @return [Hash<Thread>]
|
39
|
+
attr_reader :threads
|
40
|
+
|
41
|
+
# @return [Symbol]
|
42
|
+
attr_accessor :log_level
|
43
|
+
|
44
|
+
LOG_LEVELS.each { |level| define_logging_method(level) }
|
45
|
+
|
46
|
+
def initialize(io)
|
47
|
+
@io = io
|
48
|
+
@threads = {}
|
49
|
+
@log_level = :info
|
50
|
+
end
|
51
|
+
|
52
|
+
def allowed_log_levels
|
53
|
+
LOG_LEVELS.drop_while { |level| level != log_level }
|
54
|
+
end
|
55
|
+
|
56
|
+
def pipeline(tag:)
|
57
|
+
threads[tag] ||= begin
|
58
|
+
r, w = IO.pipe
|
59
|
+
Thread.new do
|
60
|
+
r.each do |content|
|
61
|
+
debug(content.chomp, tag: tag)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
w
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/yoda/server.rb
CHANGED
@@ -3,6 +3,7 @@ require 'securerandom'
|
|
3
3
|
|
4
4
|
module Yoda
|
5
5
|
class Server
|
6
|
+
require 'yoda/server/notifier'
|
6
7
|
require 'yoda/server/completion_provider'
|
7
8
|
require 'yoda/server/signature_provider'
|
8
9
|
require 'yoda/server/hover_provider'
|
@@ -47,6 +48,11 @@ module Yoda
|
|
47
48
|
@after_notifications = []
|
48
49
|
end
|
49
50
|
|
51
|
+
# @return [Notifier]
|
52
|
+
def notifier
|
53
|
+
@notifier ||= Notifier.new(self)
|
54
|
+
end
|
55
|
+
|
50
56
|
def run
|
51
57
|
reader.read do |request|
|
52
58
|
begin
|
@@ -59,8 +65,8 @@ module Yoda
|
|
59
65
|
end
|
60
66
|
process_after_notifications if session&.client_initialized
|
61
67
|
rescue StandardError => ex
|
62
|
-
|
63
|
-
|
68
|
+
Logger.warn ex
|
69
|
+
Logger.warn ex.backtrace
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
@@ -140,7 +146,7 @@ module Yoda
|
|
140
146
|
@signature_provider = SignatureProvider.new(@session)
|
141
147
|
@definition_provider = DefinitionProvider.new(@session)
|
142
148
|
|
143
|
-
(InitializationProvider.new(
|
149
|
+
(InitializationProvider.new(session: session, notifier: notifier).provide || []).each { |notification| after_notifications.push(notification) }
|
144
150
|
|
145
151
|
LSP::Interface::InitializeResult.new(
|
146
152
|
capabilities: LSP::Interface::ServerCapabilities.new(
|
@@ -4,14 +4,21 @@ module Yoda
|
|
4
4
|
# @return [Session]
|
5
5
|
attr_reader :session
|
6
6
|
|
7
|
+
# @return [Notifier]
|
8
|
+
attr_reader :notifier
|
9
|
+
|
7
10
|
# @param session [Session]
|
8
|
-
|
11
|
+
# @param nofitier [Notifier]
|
12
|
+
def initialize(session:, notifier:)
|
9
13
|
@session = session
|
14
|
+
@notifier = notifier
|
10
15
|
end
|
11
16
|
|
12
17
|
# @return [LanguageServer::Protocol::Interface::ShowMessageParams, nil]
|
13
18
|
def provide
|
14
|
-
errors =
|
19
|
+
errors = Instrument.instance.hear(initialization_progress: method(:notify_initialization_progress)) do
|
20
|
+
session.setup
|
21
|
+
end
|
15
22
|
build_complete_message(errors)
|
16
23
|
end
|
17
24
|
|
@@ -80,6 +87,10 @@ module Yoda
|
|
80
87
|
Please execute `yoda setup` with Ruby version #{RUBY_VERSION}.
|
81
88
|
EOS
|
82
89
|
end
|
90
|
+
|
91
|
+
def notify_initialization_progress(phase: nil, message: nil, **params)
|
92
|
+
notifier.event(type: :initialization, phase: phase, message: message)
|
93
|
+
end
|
83
94
|
end
|
84
95
|
end
|
85
96
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Yoda
|
2
|
+
class Server
|
3
|
+
class Notifier
|
4
|
+
# @param server [Server]
|
5
|
+
def initialize(server)
|
6
|
+
@server = server
|
7
|
+
end
|
8
|
+
|
9
|
+
# @param params [Hash]
|
10
|
+
def event(params)
|
11
|
+
server.send_notification(method: 'telemetry/event', params: params)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param type [String, Symbol]
|
15
|
+
# @param message [String]
|
16
|
+
def show_message(type:, message:)
|
17
|
+
server.send_notification(
|
18
|
+
method: 'window/showMessage',
|
19
|
+
params: LanguageServer::Protocol::Interface::ShowMessageParams.new(
|
20
|
+
type: message_type(type),
|
21
|
+
message: message,
|
22
|
+
)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param type [String, Symbol]
|
27
|
+
# @param message [String]
|
28
|
+
def log_message(type:, message:)
|
29
|
+
server.send_notification(
|
30
|
+
method: 'window/logMessage',
|
31
|
+
params: LanguageServer::Protocol::Interface::ShowMessageParams.new(
|
32
|
+
type: message_type(type),
|
33
|
+
message: message,
|
34
|
+
)
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# @param type [String, Symbol]
|
41
|
+
def message_type(type)
|
42
|
+
case type.to_sym
|
43
|
+
when :error
|
44
|
+
LanguageServer::Protocol::Constant::MessageType::ERROR
|
45
|
+
when :warning
|
46
|
+
LanguageServer::Protocol::Constant::MessageType::WARNING
|
47
|
+
when :info
|
48
|
+
LanguageServer::Protocol::Constant::MessageType::INFO
|
49
|
+
when :log
|
50
|
+
LanguageServer::Protocol::Constant::MessageType::LOG
|
51
|
+
else
|
52
|
+
Logger.warn("#{type} is not valie message type")
|
53
|
+
LanguageServer::Protocol::Constant::MessageType::INFO
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Server]
|
58
|
+
attr_reader :server
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/yoda/server/session.rb
CHANGED
@@ -32,7 +32,10 @@ module Yoda
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def setup
|
35
|
-
|
35
|
+
unless Store::Actions::BuildCoreIndex.exists?
|
36
|
+
Instrument.instance.initialization_progress(phase: :core, message: 'Downloading and building core index')
|
37
|
+
Store::Actions::BuildCoreIndex.run
|
38
|
+
end
|
36
39
|
project.build_cache
|
37
40
|
end
|
38
41
|
|
@@ -31,11 +31,11 @@ module Yoda
|
|
31
31
|
|
32
32
|
def build_core_index
|
33
33
|
o, e = Open3.capture2e(script_path)
|
34
|
-
|
34
|
+
Logger.debug o unless o.empty?
|
35
35
|
if e.success?
|
36
|
-
|
36
|
+
Logger.info "Success to build yard index"
|
37
37
|
else
|
38
|
-
|
38
|
+
Logger.warn "Failed to build #{gem_name} #{gem_version}"
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -42,22 +42,22 @@ module Yoda
|
|
42
42
|
|
43
43
|
def create_dependency_doc
|
44
44
|
if yardoc_path
|
45
|
-
|
45
|
+
Logger.info "Gem docs for #{gem_name} #{gem_version} already exist"
|
46
46
|
return true
|
47
47
|
end
|
48
|
-
|
48
|
+
Logger.info "Building gem docs for #{gem_name} #{gem_version}"
|
49
49
|
begin
|
50
50
|
o, e = Open3.capture2e("yard gems #{gem_name} #{gem_version}")
|
51
|
-
|
51
|
+
Logger.debug o unless o.empty?
|
52
52
|
if e.success?
|
53
|
-
|
53
|
+
Logger.info "Done building gem docs for #{gem_name} #{gem_version}"
|
54
54
|
else
|
55
|
-
|
55
|
+
Logger.warn "Failed to build #{gem_name} #{gem_version}"
|
56
56
|
end
|
57
57
|
rescue => ex
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
Logger.debug ex
|
59
|
+
Logger.debug ex.backtrace
|
60
|
+
Logger.warn "Failed to build #{gem_name} #{gem_version}"
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -68,9 +68,9 @@ module Yoda
|
|
68
68
|
begin
|
69
69
|
YardImporter.import(yardoc_file, root_path: gem_source_path)
|
70
70
|
rescue => ex
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
Logger.debug ex
|
72
|
+
Logger.debug ex.backtrace
|
73
|
+
Logger.warn "Failed to load #{yardoc_file}"
|
74
74
|
nil
|
75
75
|
end
|
76
76
|
end
|
@@ -79,8 +79,8 @@ module Yoda
|
|
79
79
|
def yardoc_path
|
80
80
|
YARD::Registry.yardoc_file_for_gem(gem_name, gem_version)
|
81
81
|
rescue Bundler::BundlerError => ex
|
82
|
-
|
83
|
-
|
82
|
+
Logger.debug ex
|
83
|
+
Logger.debug ex.backtrace
|
84
84
|
nil
|
85
85
|
end
|
86
86
|
|
@@ -14,7 +14,15 @@ module Yoda
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def run
|
17
|
-
|
17
|
+
files = project_files
|
18
|
+
progress = Instrument::Progress.new(files.length) do |index:, length:|
|
19
|
+
Instrument.instance.initialization_progress(phase: :load_project_files, message: "Loading current project files (#{index} / #{length})", index: index, length: length)
|
20
|
+
end
|
21
|
+
|
22
|
+
files.each do |file|
|
23
|
+
ReadFile.run(registry, file)
|
24
|
+
progress.increment
|
25
|
+
end
|
18
26
|
end
|
19
27
|
|
20
28
|
private
|
@@ -33,7 +33,7 @@ module Yoda
|
|
33
33
|
end
|
34
34
|
|
35
35
|
# @param data [Enumerator<(String, Object)>]
|
36
|
-
# @param bar [
|
36
|
+
# @param bar [#increment, nil]
|
37
37
|
def batch_write(data, bar)
|
38
38
|
env = LMDB.new(@path, mapsize: @env.info[:mapsize], writemap: true, mapasync: true, nosync: true)
|
39
39
|
db = env.database('main', create: true)
|
data/lib/yoda/store/project.rb
CHANGED
@@ -21,7 +21,6 @@ module Yoda
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def setup
|
24
|
-
YARD::Logger.instance(STDERR)
|
25
24
|
make_dir
|
26
25
|
cache.register_adapter(registry)
|
27
26
|
end
|
@@ -32,17 +31,17 @@ module Yoda
|
|
32
31
|
end
|
33
32
|
|
34
33
|
# @return [Array<BaseError>]
|
35
|
-
def build_cache
|
34
|
+
def build_cache
|
36
35
|
setup
|
37
36
|
loader = LibraryDocLoader.build_for(self)
|
38
|
-
loader.run
|
37
|
+
loader.run
|
39
38
|
load_project_files
|
40
39
|
loader.errors
|
41
40
|
end
|
42
41
|
|
43
|
-
def rebuild_cache
|
42
|
+
def rebuild_cache
|
44
43
|
clear
|
45
|
-
build_cache
|
44
|
+
build_cache
|
46
45
|
end
|
47
46
|
|
48
47
|
def yoda_dir
|
@@ -57,6 +56,8 @@ module Yoda
|
|
57
56
|
private
|
58
57
|
|
59
58
|
def load_project_files
|
59
|
+
Logger.debug('Loading current project files...')
|
60
|
+
Instrument.instance.initialization_progress(phase: :load_project_files, message: 'Loading current project files')
|
60
61
|
Actions::ReadProjectFiles.new(registry, root_path).run
|
61
62
|
end
|
62
63
|
|
@@ -15,8 +15,7 @@ module Yoda
|
|
15
15
|
# @param project [Project]
|
16
16
|
# @return [LibraryDocLoader]
|
17
17
|
def build_for(project)
|
18
|
-
|
19
|
-
new(registry: project.registry, gem_specs: lockfile_parser&.specs || [])
|
18
|
+
new(registry: project.registry, gem_specs: gem_specs(project))
|
20
19
|
end
|
21
20
|
|
22
21
|
private
|
@@ -28,6 +27,13 @@ module Yoda
|
|
28
27
|
Bundler::LockfileParser.new(File.read(gemfile_lock_path))
|
29
28
|
end
|
30
29
|
end
|
30
|
+
|
31
|
+
def gem_specs(project)
|
32
|
+
lockfile_parser = parse_gemfile_lock(project.root_path, Cache.gemfile_lock_path(project.root_path))
|
33
|
+
(lockfile_parser&.specs || []).reject do |spec|
|
34
|
+
spec.source.is_a?(Bundler::Source::Path) && (File.expand_path(spec.source.path) == File.expand_path(project.root_path))
|
35
|
+
end
|
36
|
+
end
|
31
37
|
end
|
32
38
|
|
33
39
|
# @param registry [Registry]
|
@@ -38,9 +44,9 @@ module Yoda
|
|
38
44
|
@errors = []
|
39
45
|
end
|
40
46
|
|
41
|
-
def run
|
47
|
+
def run
|
42
48
|
project_status = registry.project_status || Objects::ProjectStatus.initial_build(specs: gem_specs)
|
43
|
-
new_bundle_status = update_bundle(project_status.bundle
|
49
|
+
new_bundle_status = update_bundle(project_status.bundle)
|
44
50
|
registry.save_project_status(project_status.derive(bundle: new_bundle_status))
|
45
51
|
end
|
46
52
|
|
@@ -48,11 +54,11 @@ module Yoda
|
|
48
54
|
|
49
55
|
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
50
56
|
# @return [Objects::ProjectStatus::BundleStatus]
|
51
|
-
def update_bundle(bundle_status
|
57
|
+
def update_bundle(bundle_status)
|
52
58
|
unless bundle_status.all_present?
|
53
|
-
|
59
|
+
Logger.info 'Constructing database for the current project.'
|
54
60
|
bundle_status = import_deps(bundle_status)
|
55
|
-
registry.compress_and_save
|
61
|
+
registry.compress_and_save
|
56
62
|
end
|
57
63
|
bundle_status
|
58
64
|
end
|
@@ -61,6 +67,7 @@ module Yoda
|
|
61
67
|
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
62
68
|
# @return [Objects::ProjectStatus::BundleStatus]
|
63
69
|
def import_deps(bundle_status)
|
70
|
+
Instrument.instance.initialization_progress(phase: :load_core, message: 'Loading core index')
|
64
71
|
bundle_status = import_core(bundle_status) unless bundle_status.std_status.core_present?
|
65
72
|
bundle_status = import_std(bundle_status) unless bundle_status.std_status.std_present?
|
66
73
|
import_gems(bundle_status)
|
@@ -85,16 +92,20 @@ module Yoda
|
|
85
92
|
# @param bundle_status [Objects::ProjectStatus::BundleStatus]
|
86
93
|
# @return [Objects::ProjectStatus::BundleStatus]
|
87
94
|
def import_gems(bundle_status)
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
result = Actions::ImportGem.run(registry: registry, gem_name: gem_status.name, gem_version: gem_status.version)
|
93
|
-
errors.push(GemImportError.new(name: gem_status.name, version: gem_status.version)) unless result
|
94
|
-
gem_status.derive(present: result)
|
95
|
-
end
|
95
|
+
present_gem_statuses, absent_gem_statuses = bundle_status.gem_statuses.partition { |gem_status| gem_status.present? }
|
96
|
+
|
97
|
+
progress = Instrument::Progress.new(absent_gem_statuses.length) do |index:, length:|
|
98
|
+
Instrument.instance.initialization_progress(phase: :load_gems, message: "Loading gems (#{index} / #{length})", index: index, length: length)
|
96
99
|
end
|
97
|
-
|
100
|
+
|
101
|
+
new_gem_statuses = absent_gem_statuses.map do |gem_status|
|
102
|
+
result = Actions::ImportGem.run(registry: registry, gem_name: gem_status.name, gem_version: gem_status.version)
|
103
|
+
progress.increment
|
104
|
+
errors.push(GemImportError.new(name: gem_status.name, version: gem_status.version)) unless result
|
105
|
+
gem_status.derive(present: result)
|
106
|
+
end
|
107
|
+
|
108
|
+
bundle_status.derive(gem_statuses: present_gem_statuses + new_gem_statuses)
|
98
109
|
end
|
99
110
|
end
|
100
111
|
end
|
data/lib/yoda/store/registry.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'yard'
|
2
|
-
require 'ruby-progressbar'
|
3
2
|
|
4
3
|
module Yoda
|
5
4
|
module Store
|
@@ -56,19 +55,18 @@ module Yoda
|
|
56
55
|
|
57
56
|
# Store patch set data to the database.
|
58
57
|
# old data in the database are discarded.
|
59
|
-
|
60
|
-
def compress_and_save(progress: false)
|
58
|
+
def compress_and_save
|
61
59
|
return unless adapter
|
62
60
|
el_keys = patch_set.keys
|
63
|
-
|
61
|
+
progress = Instrument::Progress.new(el_keys.length) { |length:, index:| Instrument.instance.registry_dump(index: index, length: length) }
|
64
62
|
|
65
63
|
data = Enumerator.new do |yielder|
|
66
64
|
el_keys.each { |key| yielder << [key, patch_set.find(key)] }
|
67
65
|
end
|
68
66
|
|
69
|
-
adapter.batch_write(data,
|
67
|
+
adapter.batch_write(data, progress)
|
70
68
|
adapter.sync
|
71
|
-
|
69
|
+
Logger.info "saved #{el_keys.length} keys."
|
72
70
|
@patch_set = Objects::PatchSet.new
|
73
71
|
end
|
74
72
|
|
data/lib/yoda/version.rb
CHANGED
data/yarn.lock
CHANGED
@@ -2,12 +2,46 @@
|
|
2
2
|
# yarn lockfile v1
|
3
3
|
|
4
4
|
|
5
|
-
atom
|
6
|
-
version "
|
7
|
-
resolved "https://registry.yarnpkg.com/atom
|
5
|
+
"@types/atom@^1.28.0":
|
6
|
+
version "1.28.0"
|
7
|
+
resolved "https://registry.yarnpkg.com/@types/atom/-/atom-1.28.0.tgz#1c80cfa41381b6609e3eac4f84c013cd5069d36d"
|
8
8
|
dependencies:
|
9
|
-
|
9
|
+
"@types/node" "*"
|
10
10
|
|
11
|
-
|
12
|
-
version "
|
13
|
-
resolved "https://registry.yarnpkg.com/
|
11
|
+
"@types/node@*":
|
12
|
+
version "10.9.2"
|
13
|
+
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.2.tgz#f0ab8dced5cd6c56b26765e1c0d9e4fdcc9f2a00"
|
14
|
+
|
15
|
+
"@types/node@^8.0.41":
|
16
|
+
version "8.10.28"
|
17
|
+
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.28.tgz#03bf70dd7f1de7826251331ce57beddf7f9dd253"
|
18
|
+
|
19
|
+
atom-languageclient@^0.9.5:
|
20
|
+
version "0.9.6"
|
21
|
+
resolved "https://registry.yarnpkg.com/atom-languageclient/-/atom-languageclient-0.9.6.tgz#2bbb8fad72ae183c0a7d5ac3cbeea87358ecf260"
|
22
|
+
dependencies:
|
23
|
+
"@types/atom" "^1.28.0"
|
24
|
+
"@types/node" "^8.0.41"
|
25
|
+
fuzzaldrin-plus "^0.6.0"
|
26
|
+
vscode-jsonrpc "^3.6.0"
|
27
|
+
vscode-languageserver-protocol "3.6.0-next.5"
|
28
|
+
vscode-languageserver-types "^3.6.0-next.1"
|
29
|
+
|
30
|
+
fuzzaldrin-plus@^0.6.0:
|
31
|
+
version "0.6.0"
|
32
|
+
resolved "https://registry.yarnpkg.com/fuzzaldrin-plus/-/fuzzaldrin-plus-0.6.0.tgz#832f6489fbe876769459599c914a670ec22947ee"
|
33
|
+
|
34
|
+
vscode-jsonrpc@^3.6.0, vscode-jsonrpc@^3.6.0-next.1:
|
35
|
+
version "3.6.2"
|
36
|
+
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.2.tgz#3b5eef691159a15556ecc500e9a8a0dd143470c8"
|
37
|
+
|
38
|
+
vscode-languageserver-protocol@3.6.0-next.5:
|
39
|
+
version "3.6.0-next.5"
|
40
|
+
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.6.0-next.5.tgz#ed2ec2db759826f753c0a13977dfb2bedc4d31b3"
|
41
|
+
dependencies:
|
42
|
+
vscode-jsonrpc "^3.6.0-next.1"
|
43
|
+
vscode-languageserver-types "^3.6.0-next.1"
|
44
|
+
|
45
|
+
vscode-languageserver-types@^3.6.0-next.1:
|
46
|
+
version "3.12.0"
|
47
|
+
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.12.0.tgz#f96051381b6a050b7175b37d6cb5d2f2eb64b944"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yoda-language-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomoya Chiba
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|
@@ -292,6 +292,8 @@ files:
|
|
292
292
|
- lib/yoda/evaluation/current_node_explain.rb
|
293
293
|
- lib/yoda/evaluation/evaluator.rb
|
294
294
|
- lib/yoda/evaluation/signature_discovery.rb
|
295
|
+
- lib/yoda/instrument.rb
|
296
|
+
- lib/yoda/logger.rb
|
295
297
|
- lib/yoda/model.rb
|
296
298
|
- lib/yoda/model/completion_item.rb
|
297
299
|
- lib/yoda/model/descriptions.rb
|
@@ -362,6 +364,7 @@ files:
|
|
362
364
|
- lib/yoda/server/deserializer.rb
|
363
365
|
- lib/yoda/server/hover_provider.rb
|
364
366
|
- lib/yoda/server/initialization_provider.rb
|
367
|
+
- lib/yoda/server/notifier.rb
|
365
368
|
- lib/yoda/server/session.rb
|
366
369
|
- lib/yoda/server/signature_provider.rb
|
367
370
|
- lib/yoda/store.rb
|