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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 403609bb04e3734281518bc6a175b6e839e6b731d684dd5716f31e91bb7e1d98
4
- data.tar.gz: b7c597616a85977982dc2ddbcb8b8c7d896a1829904fa19dfbb52951da6895b6
3
+ metadata.gz: ccce6fdef542a593c6ccc3add4e33f24bce0f612ed5969ee24dddc8e5a806a41
4
+ data.tar.gz: 630857182e42bca93affb6c591de7c1826812242608c541fd3b42a99458fab0c
5
5
  SHA512:
6
- metadata.gz: cfbd3c60687d08b1f9e19bc632e9d8f4ceb0f5e579e8d6b9edd7e7cf81403dac9b0c7a795fac403b550950b7c1ef615095ad94bbbefe80662390edbdd16f13b7
7
- data.tar.gz: 784a22cdadad7ebdf6f25ce35a78e2cff90aa148dbf62c88e650ba42e7ce522df59e9758e9de166f99308e5226b9100505c73a7f9ee7c470575435072926afae
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
- * 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
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 |function|
69
- words_hash[function.name] ||= {
68
+ scope.children.select(&:'method?').each do |method_scope|
69
+ words_hash[method_scope.name] ||= {
70
70
  depth: scope.depth,
71
- type: function.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
- # words = words.sort_by{|word, hash| hash[:depth] }.to_h
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}[:\.\w]+)$/)[1]
33
- matches = end_match.split('.', -1)
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') { 'info' }.upcase
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
- lines = text_for_uri(uri).split("\n")
180
- line = lines[position.line]
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)
@@ -18,6 +18,12 @@ module RubyLanguageServer
18
18
  TYPE_ROOT => '',
19
19
  TYPE_VARIABLE => '^'
20
20
  }.freeze
21
+
22
+ attr_accessor :type # Type of this scope (module, class, block)
23
+
24
+ def method?
25
+ type == TYPE_METHOD
26
+ end
21
27
  end
22
28
  end
23
29
  end
@@ -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, contanst, and children - which could be functions, classes, blocks, etc. Anything that adds 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
- @full_name = [parent ? parent.full_name : nil, @name].compact.join(JoinHash[type]) unless type == TYPE_ROOT
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
- return [self, parent.self_and_ancestors].flatten unless parent.nil?
91
-
92
- [self]
92
+ [self, parent&.self_and_ancestors].flatten.compact
93
93
  end
94
94
 
95
95
  def set_superclass_name(partial)
@@ -7,7 +7,6 @@ module RubyLanguageServer
7
7
  attr_accessor :column # column
8
8
  attr_accessor :name # name
9
9
  attr_accessor :full_name # Module::Class name
10
- attr_accessor :type # type
11
10
 
12
11
  def initialize(scope, name, line = 1, column = 1, type = TYPE_VARIABLE)
13
12
  @name = name
@@ -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
- # Used only to describe subclasses?
121
- def on_var_ref(args, _)
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.parent
296
- unless parent_scope.nil?
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyLanguageServer
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  end
@@ -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.0
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: 2018-12-29 00:00:00.000000000 Z
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: json
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: etc
42
+ name: json
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="