ruby_language_server 0.2.10 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +6 -0
- data/Gemfile.lock +22 -1
- data/Makefile +4 -1
- data/README.md +1 -1
- data/exe/ruby_language_server +2 -2
- data/lib/config/initializers/active_record.rb +19 -0
- data/lib/config/initializers/sqlite.rb +3 -0
- data/lib/db/schema.rb +44 -0
- data/lib/ruby_language_server.rb +1 -12
- data/lib/ruby_language_server/application.rb +30 -0
- data/lib/ruby_language_server/code_file.rb +73 -53
- data/lib/ruby_language_server/completion.rb +9 -8
- data/lib/ruby_language_server/io.rb +7 -2
- data/lib/ruby_language_server/location.rb +2 -2
- data/lib/ruby_language_server/project_manager.rb +36 -38
- data/lib/ruby_language_server/scope_data/base.rb +13 -7
- data/lib/ruby_language_server/scope_data/scope.rb +67 -67
- data/lib/ruby_language_server/scope_data/variable.rb +32 -12
- data/lib/ruby_language_server/scope_parser.rb +19 -28
- data/lib/ruby_language_server/server.rb +6 -0
- data/lib/ruby_language_server/version.rb +1 -1
- data/ruby_language_server.gemspec +3 -0
- metadata +34 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 020e4ff18a466c0ca90d360610148699d96e9d983f173499169fe79923c0b201
|
4
|
+
data.tar.gz: abc71a6aa28296af4c53404a74500690e339a9c7b27c563b8699bfedcb0f16fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 441a9f0fad64e0fef21268bc7b4e78ad7c3d966d1b690a53af404c27ae063238c94dca7455eb8ebb1b259d8aec2e3f409cfac28b83973427866f6da3e1e1e00f
|
7
|
+
data.tar.gz: 8010f23f8fd7f24cb2a9e3883fdf86cd9c9401720a005bdef97a8537844edc44b14a311dcca19937c18076efebb454093eed11947cdc4409b37bb7be578ff16c
|
data/CHANGELOG.txt
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ruby_language_server (0.
|
4
|
+
ruby_language_server (0.3.0)
|
5
|
+
activerecord
|
5
6
|
amatch
|
6
7
|
bundler
|
7
8
|
etc
|
@@ -9,16 +10,30 @@ PATH
|
|
9
10
|
json
|
10
11
|
rubocop
|
11
12
|
rubocop-rspec
|
13
|
+
sqlite3
|
12
14
|
|
13
15
|
GEM
|
14
16
|
remote: https://rubygems.org/
|
15
17
|
specs:
|
18
|
+
activemodel (5.2.3)
|
19
|
+
activesupport (= 5.2.3)
|
20
|
+
activerecord (5.2.3)
|
21
|
+
activemodel (= 5.2.3)
|
22
|
+
activesupport (= 5.2.3)
|
23
|
+
arel (>= 9.0)
|
24
|
+
activesupport (5.2.3)
|
25
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
26
|
+
i18n (>= 0.7, < 2)
|
27
|
+
minitest (~> 5.1)
|
28
|
+
tzinfo (~> 1.1)
|
16
29
|
amatch (0.4.0)
|
17
30
|
mize
|
18
31
|
tins (~> 1.0)
|
32
|
+
arel (9.0.0)
|
19
33
|
ast (2.4.0)
|
20
34
|
byebug (11.0.1)
|
21
35
|
coderay (1.1.2)
|
36
|
+
concurrent-ruby (1.1.5)
|
22
37
|
etc (1.0.1)
|
23
38
|
ffi (1.11.1)
|
24
39
|
formatador (0.2.5)
|
@@ -39,6 +54,8 @@ GEM
|
|
39
54
|
guard-rubocop (1.3.0)
|
40
55
|
guard (~> 2.0)
|
41
56
|
rubocop (~> 0.20)
|
57
|
+
i18n (1.6.0)
|
58
|
+
concurrent-ruby (~> 1.0)
|
42
59
|
jaro_winkler (1.5.3)
|
43
60
|
json (2.2.0)
|
44
61
|
listen (3.1.5)
|
@@ -87,8 +104,12 @@ GEM
|
|
87
104
|
sexp_processor (~> 4.9)
|
88
105
|
sexp_processor (4.12.1)
|
89
106
|
shellany (0.0.1)
|
107
|
+
sqlite3 (1.4.1)
|
90
108
|
thor (0.20.3)
|
109
|
+
thread_safe (0.3.6)
|
91
110
|
tins (1.21.1)
|
111
|
+
tzinfo (1.2.5)
|
112
|
+
thread_safe (~> 0.1)
|
92
113
|
unicode-display_width (1.6.0)
|
93
114
|
|
94
115
|
PLATFORMS
|
data/Makefile
CHANGED
@@ -5,9 +5,12 @@ build:
|
|
5
5
|
docker build -t $(PROJECT_NAME) .
|
6
6
|
|
7
7
|
guard: build
|
8
|
-
|
8
|
+
echo > active_record.log
|
9
|
+
docker run -it --rm $(LOCAL_LINK) -e LOG_LEVEL=DEBUG $(PROJECT_NAME) bundle exec guard
|
10
|
+
echo > active_record.log
|
9
11
|
|
10
12
|
continuous_development: build
|
13
|
+
docker build -t local_ruby_language_server .
|
11
14
|
echo "You are going to want to set the ide-ruby 'Image Name' to local_ruby_language_server"
|
12
15
|
sleep 15
|
13
16
|
while (true) ; \
|
data/README.md
CHANGED
data/exe/ruby_language_server
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection(
|
4
|
+
adapter: 'sqlite3',
|
5
|
+
database: 'file::memory:?cache=shared',
|
6
|
+
# database: '/database',
|
7
|
+
pool: 5, # does not seem to help
|
8
|
+
checkout_timeout: 30.seconds # does not seem to help
|
9
|
+
)
|
10
|
+
|
11
|
+
if ENV['LOG_LEVEL'] == 'DEBUG'
|
12
|
+
begin
|
13
|
+
warn('Turning on active record logging')
|
14
|
+
ActiveRecord::Base.logger = Logger.new(File.open('active_record.log', 'w'))
|
15
|
+
rescue Exception => e
|
16
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
17
|
+
ActiveRecord::Base.logger.error(e)
|
18
|
+
end
|
19
|
+
end
|
data/lib/db/schema.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ActiveRecord::Schema.define do
|
4
|
+
def write(*args)
|
5
|
+
RubyLanguageServer.logger.debug(args)
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :scopes, force: true do |t|
|
9
|
+
t.references :code_file
|
10
|
+
t.integer :parent_id
|
11
|
+
t.integer :top_line # first line
|
12
|
+
t.integer :bottom_line # last line
|
13
|
+
t.integer :column
|
14
|
+
t.string :name, default: ''
|
15
|
+
t.string :superclass_name
|
16
|
+
t.string :path
|
17
|
+
t.string :class_type, null: false
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :scopes, :name
|
21
|
+
add_index :scopes, :path
|
22
|
+
add_index :scopes, :code_file
|
23
|
+
|
24
|
+
create_table :variables, force: true do |t|
|
25
|
+
t.references :code_file
|
26
|
+
t.references :scope
|
27
|
+
t.integer :line
|
28
|
+
t.integer :column
|
29
|
+
t.string :name
|
30
|
+
t.string :path
|
31
|
+
t.string :variable_type
|
32
|
+
end
|
33
|
+
|
34
|
+
add_index :variables, :name
|
35
|
+
add_index :variables, :code_file
|
36
|
+
|
37
|
+
create_table :code_files, force: true do |t|
|
38
|
+
t.string :uri
|
39
|
+
t.boolean :refresh_root_scope, default: true
|
40
|
+
t.text :text
|
41
|
+
end
|
42
|
+
|
43
|
+
add_index :code_files, :uri
|
44
|
+
end
|
data/lib/ruby_language_server.rb
CHANGED
@@ -1,14 +1,3 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'ruby_language_server/
|
4
|
-
require_relative 'ruby_language_server/version'
|
5
|
-
require_relative 'ruby_language_server/gem_installer'
|
6
|
-
require_relative 'ruby_language_server/io'
|
7
|
-
require_relative 'ruby_language_server/location'
|
8
|
-
require_relative 'ruby_language_server/code_file'
|
9
|
-
require_relative 'ruby_language_server/scope_parser'
|
10
|
-
require_relative 'ruby_language_server/good_cop'
|
11
|
-
require_relative 'ruby_language_server/project_manager'
|
12
|
-
require_relative 'ruby_language_server/server'
|
13
|
-
require_relative 'ruby_language_server/line_context'
|
14
|
-
require_relative 'ruby_language_server/completion'
|
3
|
+
require_relative 'ruby_language_server/application'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
require_relative 'logger' # do this first!
|
6
|
+
require_relative '../config/initializers/sqlite'
|
7
|
+
require_relative '../config/initializers/active_record'
|
8
|
+
require_relative '../db/schema'
|
9
|
+
|
10
|
+
require_relative 'version'
|
11
|
+
require_relative 'gem_installer'
|
12
|
+
require_relative 'io'
|
13
|
+
require_relative 'location'
|
14
|
+
require_relative 'code_file'
|
15
|
+
require_relative 'scope_parser'
|
16
|
+
require_relative 'good_cop'
|
17
|
+
require_relative 'project_manager'
|
18
|
+
require_relative 'server'
|
19
|
+
require_relative 'line_context'
|
20
|
+
require_relative 'completion'
|
21
|
+
|
22
|
+
module RubyLanguageServer
|
23
|
+
class Application
|
24
|
+
def start
|
25
|
+
update_mutex = Monitor.new
|
26
|
+
server = RubyLanguageServer::Server.new(update_mutex)
|
27
|
+
RubyLanguageServer::IO.new(server, update_mutex)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,32 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_record'
|
4
|
+
|
3
5
|
require_relative 'scope_data/base'
|
4
6
|
require_relative 'scope_data/scope'
|
5
7
|
require_relative 'scope_data/variable'
|
6
8
|
|
7
9
|
module RubyLanguageServer
|
8
|
-
class CodeFile
|
9
|
-
|
10
|
-
|
10
|
+
class CodeFile < ActiveRecord::Base
|
11
|
+
has_many :scopes, class_name: 'RubyLanguageServer::ScopeData::Scope', dependent: :destroy do
|
12
|
+
def root_scope
|
13
|
+
where(class_type: RubyLanguageServer::ScopeData::Scope::TYPE_ROOT).first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
has_many :variables, class_name: 'RubyLanguageServer::ScopeData::Variable', dependent: :destroy
|
17
|
+
|
11
18
|
attr_accessor :diagnostics
|
12
19
|
|
13
|
-
def
|
20
|
+
def self.build(uri, text)
|
14
21
|
RubyLanguageServer.logger.debug("CodeFile initialize #{uri}")
|
15
|
-
@uri = uri
|
16
|
-
@text = text
|
17
|
-
@refresh_root_scope = true
|
18
|
-
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
if @text == new_text
|
23
|
-
RubyLanguageServer.logger.debug('IT WAS THE SAME!!!!!!!!!!!!')
|
24
|
-
return
|
25
|
-
end
|
26
|
-
@text = new_text
|
27
|
-
@refresh_root_scope = true
|
23
|
+
new_code_file = create!(uri: uri, text: text)
|
24
|
+
new_code_file
|
28
25
|
end
|
29
26
|
|
27
|
+
# def text=(new_text)
|
28
|
+
# RubyLanguageServer.logger.debug("text= for #{uri}")
|
29
|
+
# if @text == new_text
|
30
|
+
# RubyLanguageServer.logger.debug('IT WAS THE SAME!!!!!!!!!!!!')
|
31
|
+
# return
|
32
|
+
# end
|
33
|
+
# @text = new_text
|
34
|
+
# update_attribute(:refresh_root_scope, true)
|
35
|
+
# root_scope
|
36
|
+
# end
|
37
|
+
#
|
30
38
|
SYMBOL_KIND = {
|
31
39
|
file: 1,
|
32
40
|
'module': 5, # 2,
|
@@ -53,46 +61,44 @@ module RubyLanguageServer
|
|
53
61
|
def ancestor_scope_name(scope)
|
54
62
|
return_scope = scope
|
55
63
|
while (return_scope = return_scope.parent)
|
56
|
-
return return_scope.name unless return_scope.name.nil?
|
64
|
+
return return_scope.name unless return_scope.name.nil? || return_scope.block_scope?
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
60
68
|
def tags
|
61
69
|
RubyLanguageServer.logger.debug("Asking about tags for #{uri}")
|
62
|
-
|
70
|
+
@tags ||= [{}]
|
71
|
+
return @tags if text.nil?
|
72
|
+
return @tags = [{}] if text == ''
|
73
|
+
|
74
|
+
refresh_scopes_if_needed # cause root scope to reset
|
75
|
+
return @tags if scopes.reload.count <= 1 # just the root
|
63
76
|
|
64
|
-
tags =
|
65
|
-
|
66
|
-
next if scope.
|
77
|
+
tags = scopes.reload.map do |scope|
|
78
|
+
next if scope.class_type == ScopeData::Base::TYPE_BLOCK
|
79
|
+
next if scope.root_scope?
|
67
80
|
|
68
|
-
|
69
|
-
kind =
|
70
|
-
kind = 9 if name == 'initialize' # Magical special case
|
81
|
+
kind = SYMBOL_KIND[scope.class_type.to_sym] || 7
|
82
|
+
kind = 9 if scope.name == 'initialize' # Magical special case
|
71
83
|
scope_hash = {
|
72
|
-
name: name,
|
84
|
+
name: scope.name,
|
73
85
|
kind: kind,
|
74
86
|
location: Location.hash(uri, scope.top_line)
|
75
87
|
}
|
76
88
|
container_name = ancestor_scope_name(scope)
|
77
|
-
scope_hash[:containerName] = container_name
|
78
|
-
|
79
|
-
|
80
|
-
scope.variables.each do |variable|
|
81
|
-
name = variable.name
|
82
|
-
# We only care about counstants
|
83
|
-
next unless name =~ /^[A-Z]/
|
84
|
-
|
85
|
-
variable_hash = {
|
86
|
-
name: name,
|
87
|
-
kind: SYMBOL_KIND[:constant],
|
88
|
-
location: Location.hash(uri, variable.line),
|
89
|
-
containerName: scope.name
|
90
|
-
}
|
91
|
-
tags << variable_hash
|
92
|
-
end
|
89
|
+
scope_hash[:containerName] = container_name unless container_name.blank?
|
90
|
+
scope_hash
|
93
91
|
end
|
94
|
-
|
95
|
-
|
92
|
+
tags += variables.constant_variables.reload.map do |variable|
|
93
|
+
name = variable.name
|
94
|
+
{
|
95
|
+
name: name,
|
96
|
+
kind: SYMBOL_KIND[:constant],
|
97
|
+
location: Location.hash(uri, variable.line - 1),
|
98
|
+
containerName: variable.scope.name
|
99
|
+
}
|
100
|
+
end
|
101
|
+
tags = tags.compact.reject { |tag| tag[:name].nil? || tag[:name] == RubyLanguageServer::ScopeData::Scope::TYPE_BLOCK }
|
96
102
|
# RubyLanguageServer.logger.debug("Raw tags for #{uri}: #{tags}")
|
97
103
|
# If you don't reverse the list then atom? won't be able to find the
|
98
104
|
# container and containers will get duplicated.
|
@@ -106,18 +112,32 @@ module RubyLanguageServer
|
|
106
112
|
@tags
|
107
113
|
end
|
108
114
|
|
109
|
-
def
|
110
|
-
|
111
|
-
if
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
+
def update_text(new_text)
|
116
|
+
RubyLanguageServer.logger.debug("update_text for #{uri}")
|
117
|
+
return true if new_text == text
|
118
|
+
|
119
|
+
RubyLanguageServer.logger.debug('Changed!')
|
120
|
+
update(text: new_text, refresh_root_scope: true)
|
121
|
+
end
|
122
|
+
|
123
|
+
def refresh_scopes_if_needed
|
124
|
+
return unless refresh_root_scope
|
115
125
|
|
116
|
-
|
117
|
-
|
118
|
-
|
126
|
+
RubyLanguageServer.logger.debug("Asking about root_scope for #{uri}")
|
127
|
+
RubyLanguageServer::ScopeData::Variable.where(code_file_id: self).scoping do
|
128
|
+
RubyLanguageServer::ScopeData::Scope.where(code_file_id: self).scoping do
|
129
|
+
self.class.transaction do
|
130
|
+
scopes.clear
|
131
|
+
variables.clear
|
132
|
+
new_root = ScopeParser.new(text).root_scope
|
133
|
+
RubyLanguageServer.logger.debug("new_root.children #{new_root.children.as_json}") if new_root&.children
|
134
|
+
raise ActiveRecord::Rollback if new_root.nil? || new_root.children.blank?
|
135
|
+
|
136
|
+
update_attribute(:refresh_root_scope, false)
|
137
|
+
new_root
|
138
|
+
end
|
139
|
+
end
|
119
140
|
end
|
120
|
-
@root_scope
|
121
141
|
end
|
122
142
|
|
123
143
|
# Returns the context of what is being typed in the given line
|
@@ -25,10 +25,10 @@ module RubyLanguageServer
|
|
25
25
|
|
26
26
|
class << self
|
27
27
|
def completion(context, context_scope, scopes)
|
28
|
-
RubyLanguageServer.logger.debug("completion(#{context}, #{
|
28
|
+
RubyLanguageServer.logger.debug("completion(#{context}, #{scopes.map(&:name)})")
|
29
29
|
completions =
|
30
30
|
if context.length < 2
|
31
|
-
scope_completions(context.last,
|
31
|
+
scope_completions(context.last, scopes)
|
32
32
|
else
|
33
33
|
scope_completions_in_target_context(context, context_scope, scopes)
|
34
34
|
end
|
@@ -44,12 +44,13 @@ module RubyLanguageServer
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def scope_with_name(name, scopes)
|
47
|
+
return scopes.where(name: name).first if scopes.respond_to?(:where)
|
48
|
+
|
47
49
|
scopes.detect { |scope| scope.name == name }
|
48
50
|
end
|
49
51
|
|
50
52
|
def scope_completions_in_target_context(context, context_scope, scopes)
|
51
|
-
|
52
|
-
context_word = working_array[-2]
|
53
|
+
context_word = context[-2]
|
53
54
|
if context_word.match?(/^[A-Z]/)
|
54
55
|
scope = scope_with_name(context_word, scopes)
|
55
56
|
else
|
@@ -59,22 +60,22 @@ module RubyLanguageServer
|
|
59
60
|
end
|
60
61
|
scope ||= context_scope
|
61
62
|
RubyLanguageServer.logger.debug("scope: #{scope}")
|
62
|
-
scope_completions(context.last, scope.
|
63
|
+
scope_completions(context.last, [scope] + scopes.includes(:variables))
|
63
64
|
end
|
64
65
|
|
65
66
|
def scope_completions(word, scopes)
|
66
67
|
words = {}
|
67
68
|
scopes.each_with_object(words) do |scope, words_hash|
|
68
|
-
scope.children.
|
69
|
+
scope.children.method_scopes.each do |method_scope|
|
69
70
|
words_hash[method_scope.name] ||= {
|
70
71
|
depth: scope.depth,
|
71
|
-
type: method_scope.
|
72
|
+
type: method_scope.class_type
|
72
73
|
}
|
73
74
|
end
|
74
75
|
scope.variables.each do |variable|
|
75
76
|
words_hash[variable.name] ||= {
|
76
77
|
depth: scope.depth,
|
77
|
-
type: variable.
|
78
|
+
type: variable.variable_type
|
78
79
|
}
|
79
80
|
end
|
80
81
|
end
|
@@ -4,8 +4,9 @@ require 'json'
|
|
4
4
|
|
5
5
|
module RubyLanguageServer
|
6
6
|
class IO
|
7
|
-
def initialize(server)
|
7
|
+
def initialize(server, mutex)
|
8
8
|
@server = server
|
9
|
+
@mutex = mutex
|
9
10
|
server.io = self
|
10
11
|
loop do
|
11
12
|
(id, response) = process_request(STDIN)
|
@@ -57,7 +58,11 @@ module RubyLanguageServer
|
|
57
58
|
params = request_json['params']
|
58
59
|
method_name = "on_#{method_name.gsub(/[^\w]/, '_')}"
|
59
60
|
if @server.respond_to? method_name
|
60
|
-
|
61
|
+
RubyLanguageServer.logger.debug 'Locking io'
|
62
|
+
response = @mutex.synchronize do
|
63
|
+
@server.send(method_name, params)
|
64
|
+
end
|
65
|
+
RubyLanguageServer.logger.debug 'UNLocking io'
|
61
66
|
exit(true) if response == 'EXIT'
|
62
67
|
return id, response
|
63
68
|
else
|
@@ -3,14 +3,14 @@
|
|
3
3
|
module RubyLanguageServer
|
4
4
|
# Hash factories for the language server
|
5
5
|
module Location
|
6
|
-
def self.hash(uri, start_line, start_character =
|
6
|
+
def self.hash(uri, start_line, start_character = 0, end_line = nil, end_character = nil)
|
7
7
|
{
|
8
8
|
uri: uri,
|
9
9
|
range: position_hash(start_line, start_character, end_line, end_character)
|
10
10
|
}
|
11
11
|
end
|
12
12
|
|
13
|
-
def self.position_hash(start_line, start_character =
|
13
|
+
def self.position_hash(start_line, start_character = 0, end_line = nil, end_character = nil)
|
14
14
|
end_line ||= start_line
|
15
15
|
end_character ||= start_character
|
16
16
|
{
|
@@ -49,13 +49,8 @@ module RubyLanguageServer
|
|
49
49
|
|
50
50
|
@root_uri = "file://#{path}"
|
51
51
|
# This is {uri: code_file} where content stuff is like
|
52
|
-
@uri_code_file_hash = {}
|
53
|
-
@update_mutext = Mutex.new
|
54
|
-
|
55
52
|
@additional_gems_installed = false
|
56
53
|
@additional_gem_mutex = Mutex.new
|
57
|
-
|
58
|
-
scan_all_project_files
|
59
54
|
end
|
60
55
|
|
61
56
|
def diagnostics_ready?
|
@@ -90,13 +85,14 @@ module RubyLanguageServer
|
|
90
85
|
end
|
91
86
|
|
92
87
|
def all_scopes
|
93
|
-
|
88
|
+
RubyLanguageServer::ScopeData::Scope.all
|
94
89
|
end
|
95
90
|
|
96
91
|
# Return the list of scopes [deepest, parent, ..., Object]
|
97
92
|
def scopes_at(uri, position)
|
98
|
-
|
99
|
-
|
93
|
+
code_file = code_file_for_uri(uri)
|
94
|
+
code_file.refresh_scopes_if_needed
|
95
|
+
code_file.scopes.for_line(position.line).where.not(path: nil).by_path_length
|
100
96
|
end
|
101
97
|
|
102
98
|
def completion_at(uri, position)
|
@@ -104,11 +100,12 @@ module RubyLanguageServer
|
|
104
100
|
relative_position.character = relative_position.character # To get before the . or ::
|
105
101
|
# RubyLanguageServer.logger.debug("relative_position #{relative_position}")
|
106
102
|
RubyLanguageServer.logger.debug("scopes_at(uri, position) #{scopes_at(uri, position).map(&:name)}")
|
107
|
-
|
103
|
+
position_scopes = scopes_at(uri, position) || RubyLanguageServer::ScopeData::Scope.where(id: root_scope_for(uri).id)
|
104
|
+
context_scope = position_scopes.first
|
108
105
|
context = context_at_location(uri, relative_position)
|
109
106
|
return {} if context.nil? || context == ''
|
110
107
|
|
111
|
-
RubyLanguageServer::Completion.completion(context, context_scope,
|
108
|
+
RubyLanguageServer::Completion.completion(context, context_scope, position_scopes)
|
112
109
|
end
|
113
110
|
|
114
111
|
# interface CompletionItem {
|
@@ -185,29 +182,37 @@ module RubyLanguageServer
|
|
185
182
|
# data?: any
|
186
183
|
# }
|
187
184
|
|
188
|
-
def scan_all_project_files
|
185
|
+
def scan_all_project_files(mutex)
|
189
186
|
project_ruby_files = Dir.glob("#{self.class.root_path}**/*.rb")
|
190
187
|
Thread.new do
|
188
|
+
RubyLanguageServer.logger.error('Threading up!')
|
191
189
|
project_ruby_files.each do |container_path|
|
190
|
+
# Let's not preload spec/test or vendor - yet..
|
191
|
+
next if container_path.match?(/^(.?spec|test|vendor)/)
|
192
|
+
|
192
193
|
text = File.read(container_path)
|
193
194
|
relative_path = container_path.delete_prefix(self.class.root_path)
|
194
195
|
host_uri = @root_uri + relative_path
|
195
|
-
|
196
|
+
RubyLanguageServer.logger.debug "Locking scan for #{container_path}"
|
197
|
+
mutex.synchronize do
|
198
|
+
RubyLanguageServer.logger.debug("Threading #{host_uri}")
|
199
|
+
update_document_content(host_uri, text)
|
200
|
+
code_file_for_uri(host_uri).refresh_scopes_if_needed
|
201
|
+
end
|
202
|
+
RubyLanguageServer.logger.debug "Unlocking scan for #{container_path}"
|
196
203
|
end
|
197
204
|
end
|
198
205
|
end
|
199
206
|
|
200
207
|
# returns diagnostic info (if possible)
|
201
208
|
def update_document_content(uri, text)
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
diagnostics_ready? ? updated_diagnostics_for_codefile(code_file) : []
|
210
|
-
end
|
209
|
+
RubyLanguageServer.logger.debug("update_document_content: #{uri}")
|
210
|
+
# RubyLanguageServer.logger.error("@root_path: #{@root_path}")
|
211
|
+
code_file = code_file_for_uri(uri)
|
212
|
+
return code_file.diagnostics if code_file.text == text
|
213
|
+
|
214
|
+
code_file.update_text(text)
|
215
|
+
diagnostics_ready? ? updated_diagnostics_for_codefile(code_file) : []
|
211
216
|
end
|
212
217
|
|
213
218
|
def updated_diagnostics_for_codefile(code_file)
|
@@ -224,19 +229,19 @@ module RubyLanguageServer
|
|
224
229
|
end
|
225
230
|
|
226
231
|
def word_at_location(uri, position)
|
227
|
-
context_at_location(uri, position)
|
232
|
+
context_at_location(uri, position)&.last
|
228
233
|
end
|
229
234
|
|
230
235
|
def possible_definitions(uri, position)
|
231
236
|
name = word_at_location(uri, position)
|
232
|
-
return {} if name
|
237
|
+
return {} if name.blank?
|
233
238
|
|
234
239
|
name = 'initialize' if name == 'new'
|
235
240
|
scope = scopes_at(uri, position).first
|
236
241
|
results = scope_definitions_for(name, scope, uri)
|
237
242
|
return results unless results.empty?
|
238
243
|
|
239
|
-
project_definitions_for(name
|
244
|
+
project_definitions_for(name)
|
240
245
|
end
|
241
246
|
|
242
247
|
def scope_definitions_for(name, scope, uri)
|
@@ -244,7 +249,7 @@ module RubyLanguageServer
|
|
244
249
|
return_array = []
|
245
250
|
while check_scope
|
246
251
|
scope.variables.each do |variable|
|
247
|
-
return_array << Location.hash(uri, variable.line) if variable.name == name
|
252
|
+
return_array << Location.hash(uri.delete_prefix(self.class.root_uri), variable.line - 1) if variable.name == name
|
248
253
|
end
|
249
254
|
check_scope = check_scope.parent
|
250
255
|
end
|
@@ -252,25 +257,18 @@ module RubyLanguageServer
|
|
252
257
|
return_array.uniq
|
253
258
|
end
|
254
259
|
|
255
|
-
def project_definitions_for(name
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
match_tags = tags.select { |tag| tag[:name] == name }
|
262
|
-
match_tags.each do |tag|
|
263
|
-
ary << Location.hash(uri, tag[:location][:range][:start][:line] + 1)
|
264
|
-
end
|
260
|
+
def project_definitions_for(name)
|
261
|
+
scopes = RubyLanguageServer::ScopeData::Scope.where(name: name)
|
262
|
+
variables = RubyLanguageServer::ScopeData::Variable.constant_variables.where(name: name)
|
263
|
+
(scopes + variables).map do |thing|
|
264
|
+
Location.hash(thing.code_file.uri.delete_prefix(self.class.root_uri), thing.top_line)
|
265
265
|
end
|
266
|
-
return_array
|
267
266
|
end
|
268
267
|
|
269
268
|
private
|
270
269
|
|
271
270
|
def code_file_for_uri(uri)
|
272
|
-
code_file =
|
273
|
-
code_file = @uri_code_file_hash[uri] = CodeFile.new(uri, nil) if code_file.nil?
|
271
|
+
code_file = CodeFile.find_by_uri(uri) || CodeFile.build(uri, nil)
|
274
272
|
code_file
|
275
273
|
end
|
276
274
|
|
@@ -1,14 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_record'
|
4
|
+
|
3
5
|
module RubyLanguageServer
|
4
6
|
module ScopeData
|
5
|
-
class Base
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
class Base < ActiveRecord::Base
|
8
|
+
self.abstract_class = true
|
9
|
+
|
10
|
+
TYPE_MODULE = 'module'
|
11
|
+
TYPE_CLASS = 'class'
|
12
|
+
TYPE_METHOD = 'method'
|
13
|
+
TYPE_BLOCK = 'block'
|
14
|
+
TYPE_ROOT = 'root'
|
15
|
+
TYPE_VARIABLE = 'variable'
|
16
|
+
|
17
|
+
BLOCK_NAME = 'block'
|
12
18
|
|
13
19
|
JoinHash = {
|
14
20
|
TYPE_MODULE => '::',
|
@@ -1,103 +1,103 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_record'
|
4
|
+
|
3
5
|
module RubyLanguageServer
|
4
6
|
module ScopeData
|
5
7
|
# The Scope class is basically a container with context.
|
6
8
|
# It is used to track top & bottom line, variables in this scope, constants, and children - which could be functions, classes, blocks, etc. Anything that adds scope.
|
7
9
|
class Scope < Base
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
attr_accessor :depth # how many parent scopes
|
13
|
-
attr_accessor :parent # parent scope
|
14
|
-
attr_accessor :variables # variables declared in this scope
|
15
|
-
attr_accessor :constants # constants declared in this scope
|
16
|
-
attr_accessor :children # child scopes
|
17
|
-
attr_accessor :name # method
|
18
|
-
attr_accessor :superclass_name # superclass name
|
19
|
-
|
20
|
-
def initialize(parent = nil, type = TYPE_ROOT, name = '', top_line = 1, _column = 1)
|
21
|
-
super()
|
22
|
-
@parent = parent
|
23
|
-
@type = type
|
24
|
-
@name = name
|
25
|
-
@top_line = top_line
|
26
|
-
@depth = parent.nil? ? 0 : parent.depth + 1
|
27
|
-
if type == TYPE_ROOT
|
28
|
-
@full_name = nil
|
29
|
-
else
|
30
|
-
@full_name = [parent ? parent.full_name : nil, @name].compact.join(JoinHash[type])
|
31
|
-
end
|
32
|
-
@children = []
|
33
|
-
@variables = []
|
34
|
-
@constants = []
|
35
|
-
end
|
10
|
+
has_many :variables, dependent: :destroy
|
11
|
+
belongs_to :code_file
|
12
|
+
belongs_to :parent, class_name: 'Scope', optional: true
|
13
|
+
has_many :children, class_name: 'Scope', foreign_key: :parent_id
|
36
14
|
|
37
|
-
|
38
|
-
|
39
|
-
|
15
|
+
scope :method_scopes, -> { where(class_type: TYPE_METHOD) }
|
16
|
+
scope :for_line, ->(line) { where('top_line <= ? AND bottom_line >= ?', line, line).or(where(parent_id: nil)) }
|
17
|
+
scope :by_path_length, -> { order('length(path) DESC') }
|
18
|
+
# attr_accessor :top_line # first line
|
19
|
+
# attr_accessor :bottom_line # last line
|
20
|
+
# attr_accessor :parent # parent scope
|
21
|
+
# attr_accessor :constants # constants declared in this scope
|
22
|
+
# attr_accessor :name # method
|
23
|
+
# attr_accessor :superclass_name # superclass name
|
40
24
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
25
|
+
def self.build(parent = nil, type = TYPE_ROOT, name = '', top_line = 1, column = 1)
|
26
|
+
full_name = [parent ? parent.full_name : nil, name].compact.join(JoinHash[type])
|
27
|
+
create!(
|
28
|
+
parent: parent,
|
29
|
+
top_line: top_line,
|
30
|
+
column: column,
|
31
|
+
name: name,
|
32
|
+
path: full_name,
|
33
|
+
class_type: type
|
34
|
+
)
|
51
35
|
end
|
52
36
|
|
53
37
|
def full_name
|
54
|
-
@full_name || @name
|
38
|
+
path # @full_name || @name
|
55
39
|
end
|
56
40
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
41
|
+
def depth
|
42
|
+
return 0 if path.blank?
|
43
|
+
|
44
|
+
scope_parts.count
|
61
45
|
end
|
62
46
|
|
63
47
|
# Return the deepest child scopes of this scope - and on up.
|
64
48
|
# Not done recuresively because we don't really need to.
|
65
49
|
# Normally called on a root scope.
|
66
|
-
def scopes_at(position)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
deepest_scope = matching_scopes.max_by(&:depth)
|
74
|
-
deepest_scope.self_and_ancestors
|
75
|
-
end
|
76
|
-
|
77
|
-
def each
|
78
|
-
self_and_descendants.each { |member| yield member }
|
79
|
-
end
|
50
|
+
# def scopes_at(position)
|
51
|
+
# line = position.line
|
52
|
+
# matching_scopes = self_and_descendants.where('top_line <= ?', line).where('bottom_line >= ?', line)
|
53
|
+
# deepest_scope = matching_scopes.max_by(&:depth)
|
54
|
+
# deepest_scope&.self_and_ancestors || []
|
55
|
+
# end
|
80
56
|
|
81
57
|
# Self and all descendents flattened into array
|
82
58
|
def self_and_descendants
|
83
|
-
|
59
|
+
return Scope.all if root_scope?
|
60
|
+
|
61
|
+
Scope.where('path like ?', "#{path}%")
|
84
62
|
end
|
85
63
|
|
86
64
|
def descendants
|
87
|
-
|
65
|
+
Scope.where('path like ?', "#{path}_%")
|
88
66
|
end
|
89
67
|
|
90
68
|
# [self, parent, parent.parent...]
|
91
|
-
def self_and_ancestors
|
92
|
-
|
93
|
-
|
69
|
+
# def self_and_ancestors
|
70
|
+
# return [self] if path.blank?
|
71
|
+
# remaining_path = path.dup
|
72
|
+
# ancestor_paths = scope_parts.inject([]) do |ary, scope_part|
|
73
|
+
# ary << remaining_path
|
74
|
+
# remaining_path =
|
75
|
+
# ary
|
76
|
+
# end
|
77
|
+
# [self, parent&.self_and_ancestors].flatten.compact
|
78
|
+
# end
|
94
79
|
|
95
80
|
def set_superclass_name(partial)
|
96
81
|
if partial.start_with?('::')
|
97
|
-
|
82
|
+
self.superclass_name = partial.gsub(/^::/, '')
|
98
83
|
else
|
99
|
-
|
84
|
+
self.superclass_name = [parent ? parent.full_name : nil, partial].compact.join(JoinHash[class_type])
|
100
85
|
end
|
86
|
+
save!
|
87
|
+
end
|
88
|
+
|
89
|
+
def root_scope?
|
90
|
+
class_type == TYPE_ROOT
|
91
|
+
end
|
92
|
+
|
93
|
+
def block_scope?
|
94
|
+
class_type == TYPE_BLOCK
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def scope_parts
|
100
|
+
path&.split(/#{JoinHash.values.reject(&:blank?).uniq.join('|')}/)
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -1,24 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_record'
|
4
|
+
|
3
5
|
module RubyLanguageServer
|
4
6
|
module ScopeData
|
5
7
|
class Variable < Base
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
belongs_to :code_file
|
9
|
+
belongs_to :scope
|
10
|
+
|
11
|
+
scope :constant_variables, -> { where("SUBSTR(name, 1, 1) between ('A') and ('Z')") }
|
12
|
+
|
13
|
+
# attr_accessor :line # line
|
14
|
+
# attr_accessor :column # column
|
15
|
+
# attr_accessor :name # name
|
16
|
+
# attr_accessor :path # Module::Class name
|
10
17
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
def self.build(scope, name, line = 1, column = 1, type = TYPE_VARIABLE)
|
19
|
+
path = [scope.full_name, name].join(JoinHash[TYPE_VARIABLE])
|
20
|
+
create!(
|
21
|
+
line: line,
|
22
|
+
column: column,
|
23
|
+
name: name,
|
24
|
+
path: path,
|
25
|
+
variable_type: type
|
26
|
+
)
|
27
|
+
# @name = name
|
28
|
+
# @line = line
|
29
|
+
# @column = column
|
30
|
+
# @full_name =
|
31
|
+
# @type = type
|
32
|
+
# raise "bogus variable #{inspect}" unless @name.instance_of? String
|
18
33
|
end
|
19
34
|
|
20
35
|
def constant?
|
21
|
-
|
36
|
+
!name&.match(/^[A-Z]/).nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Convenience for tags
|
40
|
+
def top_line
|
41
|
+
line
|
22
42
|
end
|
23
43
|
end
|
24
44
|
end
|
@@ -28,7 +28,7 @@ module RubyLanguageServer
|
|
28
28
|
def root_scope
|
29
29
|
return @root_scope unless @root_scope.nil?
|
30
30
|
|
31
|
-
@root_scope =
|
31
|
+
@root_scope = ScopeData::Scope.where(path: nil, class_type: ScopeData::Scope::TYPE_ROOT).first_or_create!
|
32
32
|
@current_scope = @root_scope
|
33
33
|
process(@sexp)
|
34
34
|
@root_scope
|
@@ -117,13 +117,14 @@ module RubyLanguageServer
|
|
117
117
|
# add_scope(args, rest, ScopeData::Scope::TYPE_BLOCK)
|
118
118
|
unless @current_scope == scope
|
119
119
|
scope.bottom_line = [scope&.bottom_line, @current_scope.bottom_line].compact.max
|
120
|
+
scope.save!
|
120
121
|
pop_scope
|
121
122
|
end
|
122
123
|
end
|
123
124
|
|
124
125
|
def on_do_block(args, rest)
|
125
126
|
((_, ((_, (_, (_, _name, (line, column))))))) = args
|
126
|
-
push_scope(ScopeData::Scope::TYPE_BLOCK,
|
127
|
+
push_scope(ScopeData::Scope::TYPE_BLOCK, 'block', line, column, false)
|
127
128
|
process(args)
|
128
129
|
process(rest)
|
129
130
|
pop_scope
|
@@ -268,17 +269,22 @@ module RubyLanguageServer
|
|
268
269
|
private
|
269
270
|
|
270
271
|
def add_variable(name, line, column, scope = @current_scope)
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
272
|
+
scope.variables.where(name: name).first_or_create(line: line, column: column)
|
273
|
+
if scope.top_line.blank?
|
274
|
+
scope.top_line = line
|
275
|
+
scope.save!
|
276
|
+
end
|
277
|
+
# new_variable = ScopeData::Variable.build(scope, name, line, column)
|
278
|
+
# # blocks don't declare their first line in the parser
|
279
|
+
# scope.top_line ||= line
|
280
|
+
# scope.variables << new_variable unless scope.has_variable_or_constant?(new_variable)
|
275
281
|
end
|
276
282
|
|
277
283
|
def add_ivar(name, line, column)
|
278
284
|
scope = @current_scope
|
279
285
|
unless scope == root_scope
|
280
286
|
ivar_scope_types = [ScopeData::Base::TYPE_CLASS, ScopeData::Base::TYPE_MODULE]
|
281
|
-
while !ivar_scope_types.include?(scope.
|
287
|
+
while !ivar_scope_types.include?(scope.class_type) && !scope.parent.nil?
|
282
288
|
scope = scope.parent
|
283
289
|
end
|
284
290
|
end
|
@@ -299,20 +305,9 @@ module RubyLanguageServer
|
|
299
305
|
|
300
306
|
def push_scope(type, name, top_line, column, close_siblings = true)
|
301
307
|
close_sibling_scopes(top_line) if close_siblings
|
302
|
-
|
303
|
-
# But if we're adding a class, we don't care that it's in Object.
|
304
|
-
new_scope =
|
305
|
-
if (type_is_class_or_module(type) && (@current_scope == root_scope))
|
306
|
-
ScopeData::Scope.new(nil, type, name, top_line, column)
|
307
|
-
else
|
308
|
-
ScopeData::Scope.new(@current_scope, type, name, top_line, column)
|
309
|
-
end
|
308
|
+
new_scope = ScopeData::Scope.build(@current_scope, type, name, top_line, column)
|
310
309
|
new_scope.bottom_line = @lines
|
311
|
-
|
312
|
-
root_scope.children << new_scope
|
313
|
-
else
|
314
|
-
@current_scope.children << new_scope
|
315
|
-
end
|
310
|
+
new_scope.save!
|
316
311
|
@current_scope = new_scope
|
317
312
|
end
|
318
313
|
|
@@ -320,19 +315,15 @@ module RubyLanguageServer
|
|
320
315
|
# The notion is that when you start the next scope, all the previous peers and unclosed descendents of the previous peer should be closed.
|
321
316
|
def close_sibling_scopes(line)
|
322
317
|
parent_scope = @current_scope
|
323
|
-
parent_scope&.descendants&.each
|
318
|
+
parent_scope&.descendants&.each do |scope|
|
319
|
+
scope.bottom_line = [scope.bottom_line, line - 1].compact.min
|
320
|
+
scope.save!
|
321
|
+
end
|
324
322
|
end
|
325
323
|
|
326
324
|
def pop_scope
|
327
325
|
@current_scope = @current_scope.parent || root_scope # in case we are leaving a root class/module
|
328
326
|
end
|
329
|
-
|
330
|
-
def new_root_scope
|
331
|
-
ScopeData::Scope.new.tap do |scope|
|
332
|
-
scope.type = ScopeData::Scope::TYPE_ROOT
|
333
|
-
scope.name = nil
|
334
|
-
end
|
335
|
-
end
|
336
327
|
end
|
337
328
|
|
338
329
|
# This class builds on Ripper's sexp processor to add ruby and rails magic.
|
@@ -7,11 +7,17 @@ module RubyLanguageServer
|
|
7
7
|
class Server
|
8
8
|
attr_accessor :io
|
9
9
|
|
10
|
+
def initialize(mutex)
|
11
|
+
@mutex = mutex
|
12
|
+
end
|
13
|
+
|
10
14
|
def on_initialize(params)
|
11
15
|
RubyLanguageServer.logger.info("on_initialize: #{params}")
|
16
|
+
RubyLanguageServer::CodeFile.all # Just to warm up active_record.
|
12
17
|
root_path = params['rootPath']
|
13
18
|
root_uri = params['rootUri']
|
14
19
|
@project_manager = ProjectManager.new(root_path, root_uri)
|
20
|
+
@project_manager.scan_all_project_files(@mutex)
|
15
21
|
gem_string = ENV.fetch('ADDITIONAL_GEMS') {}
|
16
22
|
gem_array = (gem_string.split(',').compact.map(&:strip).reject { |string| string == '' } if gem_string && !gem_string.empty?)
|
17
23
|
@project_manager.install_additional_gems(gem_array)
|
@@ -45,6 +45,9 @@ Gem::Specification.new do |spec|
|
|
45
45
|
spec.add_dependency 'amatch' # in c
|
46
46
|
spec.add_dependency 'fuzzy_match' # completion matching
|
47
47
|
|
48
|
+
spec.add_dependency 'activerecord'
|
49
|
+
spec.add_dependency 'sqlite3'
|
50
|
+
|
48
51
|
spec.add_development_dependency 'guard'
|
49
52
|
spec.add_development_dependency 'guard-minitest'
|
50
53
|
spec.add_development_dependency 'guard-rubocop'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_language_server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kurt Werle
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,6 +108,34 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: activerecord
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sqlite3
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
111
139
|
- !ruby/object:Gem::Dependency
|
112
140
|
name: guard
|
113
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -256,8 +284,12 @@ files:
|
|
256
284
|
- bin/console
|
257
285
|
- bin/setup
|
258
286
|
- exe/ruby_language_server
|
287
|
+
- lib/config/initializers/active_record.rb
|
288
|
+
- lib/config/initializers/sqlite.rb
|
289
|
+
- lib/db/schema.rb
|
259
290
|
- lib/resources/fallback_rubocop.yml
|
260
291
|
- lib/ruby_language_server.rb
|
292
|
+
- lib/ruby_language_server/application.rb
|
261
293
|
- lib/ruby_language_server/code_file.rb
|
262
294
|
- lib/ruby_language_server/completion.rb
|
263
295
|
- lib/ruby_language_server/gem_installer.rb
|