ruby_language_server 0.2.0 → 0.2.1
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/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
|
- - ">="
|