yoda-language-server 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/tomoasleep/yoda.svg?branch=master)](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
|