ruby_language_server 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +10 -0
- data/FAQ_ROADMAP.md +1 -18
- data/Makefile +3 -0
- data/README.md +4 -4
- data/lib/ruby_language_server/code_file.rb +9 -0
- data/lib/ruby_language_server/completion.rb +4 -4
- data/lib/ruby_language_server/good_cop.rb +1 -1
- data/lib/ruby_language_server/line_context.rb +3 -2
- data/lib/ruby_language_server/logger.rb +1 -1
- data/lib/ruby_language_server/project_manager.rb +3 -7
- data/lib/ruby_language_server/scope_data/base.rb +6 -0
- data/lib/ruby_language_server/scope_data/scope.rb +8 -8
- data/lib/ruby_language_server/scope_data/variable.rb +0 -1
- data/lib/ruby_language_server/scope_parser.rb +32 -16
- data/lib/ruby_language_server/server.rb +4 -0
- data/lib/ruby_language_server/version.rb +1 -1
- data/ruby_language_server.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccce6fdef542a593c6ccc3add4e33f24bce0f612ed5969ee24dddc8e5a806a41
|
4
|
+
data.tar.gz: 630857182e42bca93affb6c591de7c1826812242608c541fd3b42a99458fab0c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c81f9f115dc34b0506b2094039943c9bea9e8238817eac3ed4e79dd44ee9a0eeda5c010c1fa52accf516b3243feff86e943f51c80cb3d159362540328971187
|
7
|
+
data.tar.gz: fe0d1a52613afb2a890d3621ec500e8b56d0dedc7b793d2f0f1aba3a5d73a6d2c01b075471d65e337d23b6b9c4d7361f50a090a2e0d9c204c6698deced569224
|
data/CHANGELOG.txt
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
#### 0.2.1 Wed Jan 30 11:46:09 PST 2019
|
4
|
+
|
5
|
+
* Convert to Gem
|
6
|
+
* Bunch of refactoring
|
7
|
+
* More test (fixed stuff)
|
8
|
+
* Better block (and other) line start/end setting
|
9
|
+
* Better block variable handling
|
10
|
+
* Fixed subclass assignment (not that it matters, yet)
|
11
|
+
* Added support for object&.method
|
12
|
+
|
3
13
|
#### 0.2.0 Mon Dec 24 18:19:55 PST 2018
|
4
14
|
|
5
15
|
* Support for rake files
|
data/FAQ_ROADMAP.md
CHANGED
@@ -1,25 +1,7 @@
|
|
1
|
-
# Why docker?
|
2
|
-
|
3
|
-
Docker guarantees me a target environment. I don't have to wonder which version of ruby you have installed or if you can build all the gems. I may also scale this thing to multiple processes and a database and a cache server.
|
4
|
-
|
5
|
-
One requirement: docker.
|
6
|
-
|
7
|
-
# Why not [language_server-ruby](https://github.com/mtsmfm/language_server-ruby)
|
8
|
-
|
9
|
-
My goals are not as high. I just want this stuff working now. I hope some day there will be merging.
|
10
|
-
|
11
|
-
# A little light on tests?
|
12
|
-
|
13
|
-
Oh yeah. Tests are mostly for when you know where you're going. I'm doing a whole lot of this by the seat of my pants. OMG, please write tests.
|
14
|
-
|
15
1
|
# Next?
|
16
2
|
|
17
3
|
* Getting a definition just looks at the tags - but tags do not include parameters passed in a method - which seems like it should. We are functional, right?
|
18
|
-
* Guess a symbol's class.
|
19
|
-
* `def some_method(parent)` should guess that parent is a Parent.
|
20
4
|
* Be smarter about context and completions
|
21
|
-
* `class << self` is busted. Fix it.
|
22
|
-
* Fix the outline. Seriously - why isn't it working as expected?
|
23
5
|
* Symbol pairs. If I have typed 'foo.bar' a thousand times in my project, the next time I type 'foo.' the IDE had damn well ought to show me 'bar' as a completion option.
|
24
6
|
* It makes me very sad that I could not get this working using sockets. Tried and tried and failed.
|
25
7
|
|
@@ -27,4 +9,5 @@ Oh yeah. Tests are mostly for when you know where you're going. I'm doing a wh
|
|
27
9
|
|
28
10
|
* Pay special attention to the project's Gemfile. Install all the gems (we can). Integrate with gem server?
|
29
11
|
* Full scan of installed gems?
|
12
|
+
* Maybe use a database (sqlite?) to store data and do lookups?
|
30
13
|
* Integrate class based scope logic. If I'm in Foo < Bar then I should see Bar's methods at just slightly lower priority than Foo's.
|
data/Makefile
CHANGED
@@ -19,6 +19,9 @@ continuous_development: build
|
|
19
19
|
console: build
|
20
20
|
docker run -it $(LOCAL_LINK) $(PROJECT_NAME) bin/console
|
21
21
|
|
22
|
+
test: build
|
23
|
+
docker run -it $(LOCAL_LINK) $(PROJECT_NAME) rake test && rubocop -c .rubocop_ruby_language_parser.yml
|
24
|
+
|
22
25
|
shell: build
|
23
26
|
docker run -it $(LOCAL_LINK) $(PROJECT_NAME) sh
|
24
27
|
|
data/README.md
CHANGED
@@ -19,9 +19,9 @@ Help wanted.
|
|
19
19
|
|
20
20
|
# Editor Integrations
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
You probably want to use one of the developed integrations:
|
23
|
+
* Atom - https://github.com/kwerle/ide-ruby
|
24
|
+
* Theia - https://github.com/kwerle/theia_ruby_language_server
|
25
25
|
|
26
26
|
# Running
|
27
27
|
|
@@ -32,7 +32,7 @@ Help wanted.
|
|
32
32
|
Clone. I love git [HubFlow](https://datasift.github.io/gitflow/).
|
33
33
|
|
34
34
|
Check out the [Makefile](Makefile). You are going to want to do
|
35
|
-
`make guard` and `make continuous_development
|
35
|
+
`make guard` in one window and `make continuous_development` in another.
|
36
36
|
|
37
37
|
* In Atom: install the ide-ruby.
|
38
38
|
* Settings > Packages > ide-ruby > Image Name > local_ruby_language_server
|
@@ -125,5 +125,14 @@ module RubyLanguageServer
|
|
125
125
|
end
|
126
126
|
@root_scope
|
127
127
|
end
|
128
|
+
|
129
|
+
# Returns the context of what is being typed in the given line
|
130
|
+
def context_at_location(position)
|
131
|
+
lines = text.split("\n")
|
132
|
+
line = lines[position.line]
|
133
|
+
return [] if line.nil? || line.strip.length.zero?
|
134
|
+
|
135
|
+
LineContext.for(line, position.character)
|
136
|
+
end
|
128
137
|
end
|
129
138
|
end
|
@@ -65,10 +65,10 @@ module RubyLanguageServer
|
|
65
65
|
def scope_completions(word, scopes)
|
66
66
|
words = {}
|
67
67
|
scopes.each_with_object(words) do |scope, words_hash|
|
68
|
-
scope.children.each do |
|
69
|
-
words_hash[
|
68
|
+
scope.children.select(&:'method?').each do |method_scope|
|
69
|
+
words_hash[method_scope.name] ||= {
|
70
70
|
depth: scope.depth,
|
71
|
-
type:
|
71
|
+
type: method_scope.type
|
72
72
|
}
|
73
73
|
end
|
74
74
|
scope.variables.each do |variable|
|
@@ -78,7 +78,7 @@ module RubyLanguageServer
|
|
78
78
|
}
|
79
79
|
end
|
80
80
|
end
|
81
|
-
|
81
|
+
words = words.sort_by { |_word, hash| hash[:depth] }.to_h
|
82
82
|
good_words = FuzzyMatch.new(words.keys, threshold: 0.01).find_all(word).slice(0..10) || []
|
83
83
|
words = good_words.map { |w| [w, words[w]] }.to_h
|
84
84
|
end
|
@@ -6,9 +6,9 @@ module RubyLanguageServer
|
|
6
6
|
class GoodCop < RuboCop::Runner
|
7
7
|
CONFIG_PATH = '/project/.rubocop.yml'
|
8
8
|
FALLBACK_PATH = '/app/.rubocop.yml'
|
9
|
-
@initialization_error = nil
|
10
9
|
|
11
10
|
def initialize
|
11
|
+
@initialization_error = nil
|
12
12
|
config_store = RuboCop::ConfigStore.new
|
13
13
|
config_store.options_config =
|
14
14
|
if File.exist?(CONFIG_PATH)
|
@@ -29,8 +29,9 @@ module RubyLanguageServer
|
|
29
29
|
line_start = line[0..(position + match.length - 1)]
|
30
30
|
RubyLanguageServer.logger.debug("line_start: #{line_start}")
|
31
31
|
# Match as much as we can to the end of the line - which is now the end of the word
|
32
|
-
end_match = line_start.partition(/(@{0,2}[
|
33
|
-
matches = end_match.split('
|
32
|
+
end_match = line_start.partition(/(@{0,2}[:&\.\w]+)$/)[1]
|
33
|
+
matches = end_match.split('&.', -1)
|
34
|
+
matches = matches.map { |m| m.length.positive? ? m.split('.', -1) : m }.flatten
|
34
35
|
matches = matches.map { |m| m.length.positive? ? m.split('::', -1) : m }.flatten
|
35
36
|
RubyLanguageServer.logger.debug("matches: #{matches}")
|
36
37
|
matches
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'logger'
|
4
4
|
|
5
5
|
module RubyLanguageServer
|
6
|
-
level_name = ENV.fetch('LOG_LEVEL') { '
|
6
|
+
level_name = ENV.fetch('LOG_LEVEL') { 'error' }.upcase
|
7
7
|
# level_name = 'DEBUG'
|
8
8
|
level = Logger::Severity.const_get(level_name)
|
9
9
|
@logger = ::Logger.new(STDERR, level: level)
|
@@ -175,14 +175,10 @@ module RubyLanguageServer
|
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
178
|
+
# Returns the context of what is being typed in the given line
|
178
179
|
def context_at_location(uri, position)
|
179
|
-
|
180
|
-
|
181
|
-
return [] if line.nil? || line.strip.length.zero?
|
182
|
-
|
183
|
-
contexts = LineContext.for(line, position.character)
|
184
|
-
RubyLanguageServer.logger.debug("LineContext.for(line, position.character): #{contexts}")
|
185
|
-
contexts
|
180
|
+
code_file = code_file_for_uri(uri)
|
181
|
+
code_file&.context_at_location(position)
|
186
182
|
end
|
187
183
|
|
188
184
|
def word_at_location(uri, position)
|
@@ -3,8 +3,7 @@
|
|
3
3
|
module RubyLanguageServer
|
4
4
|
module ScopeData
|
5
5
|
# The Scope class is basically a container with context.
|
6
|
-
# It is used to track top & bottom line, variables in this scope,
|
7
|
-
# Remember, this is scope for a file. It seems reasonabble that this will get used less in the future when we know more about classes.
|
6
|
+
# 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.
|
8
7
|
class Scope < Base
|
9
8
|
include Enumerable
|
10
9
|
|
@@ -15,7 +14,6 @@ module RubyLanguageServer
|
|
15
14
|
attr_accessor :variables # variables declared in this scope
|
16
15
|
attr_accessor :constants # constants declared in this scope
|
17
16
|
attr_accessor :children # child scopes
|
18
|
-
attr_accessor :type # Type of this scope (module, class, block)
|
19
17
|
attr_accessor :name # method
|
20
18
|
attr_accessor :superclass_name # superclass name
|
21
19
|
|
@@ -26,14 +24,18 @@ module RubyLanguageServer
|
|
26
24
|
@name = name
|
27
25
|
@top_line = top_line
|
28
26
|
@depth = parent.nil? ? 0 : parent.depth + 1
|
29
|
-
|
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
|
30
32
|
@children = []
|
31
33
|
@variables = []
|
32
34
|
@constants = []
|
33
35
|
end
|
34
36
|
|
35
37
|
def inspect
|
36
|
-
"Scope: #{@name} (#{@full_name}) #{@top_line}-#{@bottom_line} children: #{@children} vars: #{@variables}"
|
38
|
+
"Scope: #{@name} (#{@full_name} - #{@type}) #{@top_line}-#{@bottom_line} children: #{@children} vars: #{@variables}"
|
37
39
|
end
|
38
40
|
|
39
41
|
def pretty_print(pp) # rubocop:disable Naming/UncommunicativeMethodParamName
|
@@ -87,9 +89,7 @@ module RubyLanguageServer
|
|
87
89
|
|
88
90
|
# [self, parent, parent.parent...]
|
89
91
|
def self_and_ancestors
|
90
|
-
|
91
|
-
|
92
|
-
[self]
|
92
|
+
[self, parent&.self_and_ancestors].flatten.compact
|
93
93
|
end
|
94
94
|
|
95
95
|
def set_superclass_name(partial)
|
@@ -22,6 +22,7 @@ module RubyLanguageServer
|
|
22
22
|
def initialize(sexp, lines = 1)
|
23
23
|
@sexp = sexp
|
24
24
|
@lines = lines
|
25
|
+
@root_scope = nil
|
25
26
|
end
|
26
27
|
|
27
28
|
def root_scope
|
@@ -55,6 +56,8 @@ module RubyLanguageServer
|
|
55
56
|
RubyLanguageServer.logger.debug("We don't do Strings like #{root} with #{args}")
|
56
57
|
when NilClass
|
57
58
|
process(args)
|
59
|
+
when FalseClass
|
60
|
+
process(args)
|
58
61
|
else
|
59
62
|
RubyLanguageServer.logger.warn("We don't respond to the likes of #{root} of class #{root.class}")
|
60
63
|
end
|
@@ -91,11 +94,20 @@ module RubyLanguageServer
|
|
91
94
|
end
|
92
95
|
|
93
96
|
def on_module(args, rest)
|
94
|
-
add_scope(args.last, rest, ScopeData::Scope::TYPE_MODULE)
|
97
|
+
scope = add_scope(args.last, rest, ScopeData::Scope::TYPE_MODULE)
|
98
|
+
assign_subclass(scope, rest)
|
95
99
|
end
|
96
100
|
|
97
101
|
def on_class(args, rest)
|
98
|
-
add_scope(args.last, rest, ScopeData::Scope::TYPE_CLASS)
|
102
|
+
scope = add_scope(args.last, rest, ScopeData::Scope::TYPE_CLASS)
|
103
|
+
assign_subclass(scope, rest)
|
104
|
+
end
|
105
|
+
|
106
|
+
def assign_subclass(scope, sexp)
|
107
|
+
return unless !sexp[0].nil? && sexp[0][0] == :var_ref
|
108
|
+
|
109
|
+
(_, (_, name)) = sexp[0]
|
110
|
+
scope.set_superclass_name(name)
|
99
111
|
end
|
100
112
|
|
101
113
|
def on_method_add_block(args, rest)
|
@@ -117,11 +129,20 @@ module RubyLanguageServer
|
|
117
129
|
pop_scope
|
118
130
|
end
|
119
131
|
|
120
|
-
|
121
|
-
|
132
|
+
def on_block_var(args, rest)
|
133
|
+
(_, ((_, name, (line, column)))) = args
|
134
|
+
add_variable(name, line, column)
|
135
|
+
# blocks don't declare their first line in the parser
|
136
|
+
current_scope.top_line ||= line
|
137
|
+
process(args)
|
138
|
+
process(rest)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Used only to describe subclasses? -- nope
|
142
|
+
def on_var_ref(_args, _rest)
|
122
143
|
# [:@const, "Bar", [13, 20]]
|
123
|
-
(_, name) = args
|
124
|
-
@current_scope.set_superclass_name(name)
|
144
|
+
# (_, name) = args
|
145
|
+
# @current_scope.set_superclass_name(name)
|
125
146
|
end
|
126
147
|
|
127
148
|
def on_assign(args, rest)
|
@@ -261,9 +282,10 @@ module RubyLanguageServer
|
|
261
282
|
|
262
283
|
def add_scope(args, rest, type)
|
263
284
|
(_, name, (line, column)) = args
|
264
|
-
push_scope(type, name, line, column)
|
285
|
+
scope = push_scope(type, name, line, column)
|
265
286
|
process(rest)
|
266
287
|
pop_scope
|
288
|
+
scope
|
267
289
|
end
|
268
290
|
|
269
291
|
def type_is_class_or_module(type)
|
@@ -292,14 +314,8 @@ module RubyLanguageServer
|
|
292
314
|
# This is a very poor man's "end" handler because there is no end handler.
|
293
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.
|
294
316
|
def close_sibling_scopes(line)
|
295
|
-
parent_scope = @current_scope
|
296
|
-
|
297
|
-
last_sibling = parent_scope.children.last
|
298
|
-
until last_sibling.nil?
|
299
|
-
last_sibling.bottom_line = line - 1
|
300
|
-
last_sibling = last_sibling.children.last
|
301
|
-
end
|
302
|
-
end
|
317
|
+
parent_scope = @current_scope
|
318
|
+
parent_scope&.descendants&.each { |scope| scope.bottom_line = [scope.bottom_line, line - 1].compact.min }
|
303
319
|
end
|
304
320
|
|
305
321
|
def pop_scope
|
@@ -327,7 +343,7 @@ module RubyLanguageServer
|
|
327
343
|
rescue TypeError => exception
|
328
344
|
RubyLanguageServer.logger.error("Exception in sexp: #{exception} for text: #{text}")
|
329
345
|
end
|
330
|
-
processor = SEXPProcessor.new(sexp, text.length)
|
346
|
+
processor = SEXPProcessor.new(sexp, text.split("\n").length)
|
331
347
|
@root_scope = processor.root_scope
|
332
348
|
end
|
333
349
|
end
|
@@ -42,6 +42,10 @@ module RubyLanguageServer
|
|
42
42
|
}
|
43
43
|
end
|
44
44
|
|
45
|
+
def on_initialized(_hash)
|
46
|
+
RubyLanguageServer.logger.error("RubyLanguageServer::VERSION #{RubyLanguageServer::VERSION}")
|
47
|
+
end
|
48
|
+
|
45
49
|
def on_workspace_didChangeWatchedFiles(params)
|
46
50
|
RubyLanguageServer.logger.debug('on_workspace_didChangeWatchedFiles')
|
47
51
|
RubyLanguageServer.logger.debug(params)
|
@@ -35,8 +35,8 @@ Gem::Specification.new do |spec|
|
|
35
35
|
|
36
36
|
# Normally the system will have these - but not if it's a stripped down docker image
|
37
37
|
spec.add_dependency 'bundler'
|
38
|
-
spec.add_dependency 'json'
|
39
38
|
spec.add_dependency 'etc'
|
39
|
+
spec.add_dependency 'json'
|
40
40
|
|
41
41
|
# No - do not put these in dev - they are needed for the app
|
42
42
|
spec.add_dependency '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.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kurt Werle
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: etc
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: json
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|