ruby_language_server 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.txt +67 -0
- data/FAQ_ROADMAP.md +30 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +111 -0
- data/Guardfile +36 -0
- data/LICENSE +21 -0
- data/Makefile +35 -0
- data/README.md +55 -0
- data/Rakefile +17 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/ruby_language_server +9 -0
- data/lib/ruby_language_server/code_file.rb +129 -0
- data/lib/ruby_language_server/completion.rb +87 -0
- data/lib/ruby_language_server/gem_installer.rb +24 -0
- data/lib/ruby_language_server/good_cop.rb +125 -0
- data/lib/ruby_language_server/io.rb +130 -0
- data/lib/ruby_language_server/line_context.rb +39 -0
- data/lib/ruby_language_server/location.rb +29 -0
- data/lib/ruby_language_server/logger.rb +14 -0
- data/lib/ruby_language_server/project_manager.rb +231 -0
- data/lib/ruby_language_server/scope_data/base.rb +23 -0
- data/lib/ruby_language_server/scope_data/scope.rb +104 -0
- data/lib/ruby_language_server/scope_data/variable.rb +25 -0
- data/lib/ruby_language_server/scope_parser.rb +334 -0
- data/lib/ruby_language_server/scope_parser_commands/rails_commands.rb +29 -0
- data/lib/ruby_language_server/scope_parser_commands/rake_commands.rb +31 -0
- data/lib/ruby_language_server/scope_parser_commands/readme.txt +9 -0
- data/lib/ruby_language_server/scope_parser_commands/rspec_commands.rb +26 -0
- data/lib/ruby_language_server/scope_parser_commands/ruby_commands.rb +70 -0
- data/lib/ruby_language_server/server.rb +123 -0
- data/lib/ruby_language_server/version.rb +5 -0
- data/lib/ruby_language_server.rb +14 -0
- data/ruby_language_server.gemspec +56 -0
- metadata +293 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 403609bb04e3734281518bc6a175b6e839e6b731d684dd5716f31e91bb7e1d98
|
4
|
+
data.tar.gz: b7c597616a85977982dc2ddbcb8b8c7d896a1829904fa19dfbb52951da6895b6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cfbd3c60687d08b1f9e19bc632e9d8f4ceb0f5e579e8d6b9edd7e7cf81403dac9b0c7a795fac403b550950b7c1ef615095ad94bbbefe80662390edbdd16f13b7
|
7
|
+
data.tar.gz: 784a22cdadad7ebdf6f25ce35a78e2cff90aa148dbf62c88e650ba42e7ce522df59e9758e9de166f99308e5226b9100505c73a7f9ee7c470575435072926afae
|
data/CHANGELOG.txt
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
#### 0.2.0 Mon Dec 24 18:19:55 PST 2018
|
4
|
+
|
5
|
+
* Support for rake files
|
6
|
+
* Support for rspec files
|
7
|
+
* Removed ripper tags & refactoring
|
8
|
+
* Better handling of parameter variables
|
9
|
+
* Probably better performance (not measured, but reasonably sure)
|
10
|
+
|
11
|
+
#### 0.1.1 Fri Dec 21 16:48:46 PST 2018
|
12
|
+
|
13
|
+
* Fix a few little issues that came to light while updating ide-ruby
|
14
|
+
|
15
|
+
#### 0.1.0 Fri Dec 21 15:19:00 PST 2018
|
16
|
+
|
17
|
+
* Refactor server & project_manager
|
18
|
+
* fix bugs with def self.method and class << self (https://github.com/kwerle/ide-ruby/issues/19)
|
19
|
+
* Add support for additional rubocop gems (https://github.com/kwerle/ide-ruby/issues/17)
|
20
|
+
|
21
|
+
#### 0.0.9 Thu Oct 18 17:48:35 PDT 2018
|
22
|
+
|
23
|
+
* Refactor & some RuboCop
|
24
|
+
* Fix most of https://github.com/kwerle/ide-ruby/issues/18
|
25
|
+
* * Rubocop issues: no inline support,
|
26
|
+
* * invalid snake_case warnings,
|
27
|
+
* * NOT missing "rubocop failed to load" indicator
|
28
|
+
* More work on completion stuff
|
29
|
+
|
30
|
+
#### 0.0.8 Thu Jul 19 00:01:25 PDT 2018
|
31
|
+
|
32
|
+
* Bump ruby version
|
33
|
+
* Fix the initial background thread
|
34
|
+
* Refactor
|
35
|
+
* Ignore setting text to the same
|
36
|
+
|
37
|
+
#### 0.0.7 Thu Jul 12 16:11:26 PDT 2018
|
38
|
+
|
39
|
+
* Whoops - forgot to merge changes in.
|
40
|
+
|
41
|
+
#### 0.0.6 Thu Jul 12 16:11:26 PDT 2018
|
42
|
+
|
43
|
+
* Fix RuboCop again. Sigh.
|
44
|
+
|
45
|
+
#### 0.0.5 Thu Jul 12 15:07:58 PDT 2018
|
46
|
+
|
47
|
+
* Parse all project files on startup
|
48
|
+
* Fix possible issue with RuboCop config
|
49
|
+
|
50
|
+
#### 0.0.4 Tue Mar 20 19:39:06 PDT 2018
|
51
|
+
|
52
|
+
* Provide support for .rubocop.yml. This will work once I update ide-ruby.
|
53
|
+
|
54
|
+
#### 0.0.3
|
55
|
+
|
56
|
+
* Uhh. What did I do? Looks like a bunch.
|
57
|
+
|
58
|
+
#### 0.0.2 Mon Nov 13 20:49:54 PST 2017
|
59
|
+
|
60
|
+
* Fix rails has_one(etc) so it gets the right parent
|
61
|
+
|
62
|
+
#### Sat Nov 11 07:59:25 PST 2017
|
63
|
+
|
64
|
+
* Outline working but buggy (double listing for parents)
|
65
|
+
* Go to definition working but lazy (have to visit a file before definitions 'known')
|
66
|
+
* Completions working in a very basic way - local scope context only
|
67
|
+
* Linter not working (not being called, NYI)
|
data/FAQ_ROADMAP.md
ADDED
@@ -0,0 +1,30 @@
|
|
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
|
+
# Next?
|
16
|
+
|
17
|
+
* 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
|
+
* 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
|
+
* 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
|
+
* It makes me very sad that I could not get this working using sockets. Tried and tried and failed.
|
25
|
+
|
26
|
+
# Then?
|
27
|
+
|
28
|
+
* Pay special attention to the project's Gemfile. Install all the gems (we can). Integrate with gem server?
|
29
|
+
* Full scan of installed gems?
|
30
|
+
* 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/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby_language_server (0.2.0)
|
5
|
+
amatch
|
6
|
+
bundler
|
7
|
+
etc
|
8
|
+
fuzzy_match
|
9
|
+
json
|
10
|
+
rubocop
|
11
|
+
rubocop-rspec
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: https://rubygems.org/
|
15
|
+
specs:
|
16
|
+
amatch (0.4.0)
|
17
|
+
mize
|
18
|
+
tins (~> 1.0)
|
19
|
+
ast (2.4.0)
|
20
|
+
byebug (10.0.2)
|
21
|
+
coderay (1.1.2)
|
22
|
+
etc (1.0.1)
|
23
|
+
ffi (1.9.25)
|
24
|
+
formatador (0.2.5)
|
25
|
+
fuzzy_match (2.1.0)
|
26
|
+
guard (2.15.0)
|
27
|
+
formatador (>= 0.2.4)
|
28
|
+
listen (>= 2.7, < 4.0)
|
29
|
+
lumberjack (>= 1.0.12, < 2.0)
|
30
|
+
nenv (~> 0.1)
|
31
|
+
notiffany (~> 0.0)
|
32
|
+
pry (>= 0.9.12)
|
33
|
+
shellany (~> 0.0)
|
34
|
+
thor (>= 0.18.1)
|
35
|
+
guard-compat (1.2.1)
|
36
|
+
guard-minitest (2.4.6)
|
37
|
+
guard-compat (~> 1.2)
|
38
|
+
minitest (>= 3.0)
|
39
|
+
guard-rubocop (1.3.0)
|
40
|
+
guard (~> 2.0)
|
41
|
+
rubocop (~> 0.20)
|
42
|
+
jaro_winkler (1.5.1)
|
43
|
+
json (2.1.0)
|
44
|
+
listen (3.1.5)
|
45
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
46
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
47
|
+
ruby_dep (~> 1.2)
|
48
|
+
lumberjack (1.0.13)
|
49
|
+
method_source (0.9.2)
|
50
|
+
minitest (5.11.3)
|
51
|
+
minitest-color (0.0.2)
|
52
|
+
minitest (~> 5)
|
53
|
+
mize (0.3.5)
|
54
|
+
protocol
|
55
|
+
nenv (0.3.0)
|
56
|
+
notiffany (0.1.1)
|
57
|
+
nenv (~> 0.1)
|
58
|
+
shellany (~> 0.0)
|
59
|
+
parallel (1.12.1)
|
60
|
+
parser (2.5.3.0)
|
61
|
+
ast (~> 2.4.0)
|
62
|
+
powerpack (0.1.2)
|
63
|
+
protocol (1.0.1)
|
64
|
+
ruby_parser (~> 3.0)
|
65
|
+
pry (0.12.2)
|
66
|
+
coderay (~> 1.1.0)
|
67
|
+
method_source (~> 0.9.0)
|
68
|
+
pry-byebug (3.6.0)
|
69
|
+
byebug (~> 10.0)
|
70
|
+
pry (~> 0.10)
|
71
|
+
rainbow (3.0.0)
|
72
|
+
rake (12.3.2)
|
73
|
+
rb-fsevent (0.10.3)
|
74
|
+
rb-inotify (0.10.0)
|
75
|
+
ffi (~> 1.0)
|
76
|
+
rubocop (0.61.1)
|
77
|
+
jaro_winkler (~> 1.5.1)
|
78
|
+
parallel (~> 1.10)
|
79
|
+
parser (>= 2.5, != 2.5.1.1)
|
80
|
+
powerpack (~> 0.1)
|
81
|
+
rainbow (>= 2.2.2, < 4.0)
|
82
|
+
ruby-progressbar (~> 1.7)
|
83
|
+
unicode-display_width (~> 1.4.0)
|
84
|
+
rubocop-rspec (1.30.1)
|
85
|
+
rubocop (>= 0.60.0)
|
86
|
+
ruby-progressbar (1.10.0)
|
87
|
+
ruby_dep (1.5.0)
|
88
|
+
ruby_parser (3.12.0)
|
89
|
+
sexp_processor (~> 4.9)
|
90
|
+
sexp_processor (4.11.0)
|
91
|
+
shellany (0.0.1)
|
92
|
+
thor (0.20.3)
|
93
|
+
tins (1.20.2)
|
94
|
+
unicode-display_width (1.4.1)
|
95
|
+
|
96
|
+
PLATFORMS
|
97
|
+
ruby
|
98
|
+
|
99
|
+
DEPENDENCIES
|
100
|
+
guard
|
101
|
+
guard-minitest
|
102
|
+
guard-rubocop
|
103
|
+
minitest
|
104
|
+
minitest-color
|
105
|
+
pry
|
106
|
+
pry-byebug
|
107
|
+
rake
|
108
|
+
ruby_language_server!
|
109
|
+
|
110
|
+
BUNDLED WITH
|
111
|
+
1.17.3
|
data/Guardfile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A sample Guardfile
|
4
|
+
# More info at https://github.com/guard/guard#readme
|
5
|
+
|
6
|
+
## Uncomment and set this to only include directories you want to watch
|
7
|
+
# directories %w(app lib config test spec features) \
|
8
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
9
|
+
|
10
|
+
## Note: if you are using the `directories` clause above and you are not
|
11
|
+
## watching the project directory ('.'), then you will want to move
|
12
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
13
|
+
#
|
14
|
+
# $ mkdir config
|
15
|
+
# $ mv Guardfile config/
|
16
|
+
# $ ln -s config/Guardfile .
|
17
|
+
#
|
18
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
19
|
+
|
20
|
+
guard :minitest, all_after_pass: true do
|
21
|
+
# with Minitest::Unit
|
22
|
+
# watch(%r{^test/(.*)\/?test_(.*)\.rb$})
|
23
|
+
# watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
24
|
+
# watch(%r{^test/test_helper\.rb$}) { 'test' }
|
25
|
+
|
26
|
+
# with Minitest::Spec
|
27
|
+
watch(%r{^spec/**/(.*)_spec\.rb$})
|
28
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
29
|
+
watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
|
30
|
+
end
|
31
|
+
|
32
|
+
guard :rubocop, cli: ['-c', '.rubocop_ruby_language_parser.yml'] do
|
33
|
+
watch('.rubocop_ruby_language_parser.yml')
|
34
|
+
watch(/.+\.rb$/)
|
35
|
+
watch(%r{(?:.+/)?\.rubocop(?:_todo)?\.yml$}) { |m| File.dirname(m[0]) }
|
36
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Kurt Werle
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Makefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
PROJECT_NAME=ruby_language_server
|
2
|
+
LOCAL_LINK=-v $(PWD):/tmp/src -w /tmp/src
|
3
|
+
|
4
|
+
build:
|
5
|
+
docker build -t $(PROJECT_NAME) .
|
6
|
+
|
7
|
+
guard: build
|
8
|
+
docker run -it $(LOCAL_LINK) $(PROJECT_NAME) sh -c 'bundle && guard'
|
9
|
+
|
10
|
+
continuous_development: build
|
11
|
+
echo "You are going to want to set the ide-ruby 'Image Name' to local_ruby_language_server"
|
12
|
+
sleep 15
|
13
|
+
while (true) ; \
|
14
|
+
do \
|
15
|
+
docker build -t local_ruby_language_server . ; \
|
16
|
+
sleep 2 ; \
|
17
|
+
done
|
18
|
+
|
19
|
+
console: build
|
20
|
+
docker run -it $(LOCAL_LINK) $(PROJECT_NAME) bin/console
|
21
|
+
|
22
|
+
shell: build
|
23
|
+
docker run -it $(LOCAL_LINK) $(PROJECT_NAME) sh
|
24
|
+
|
25
|
+
# Just to make sure it works.
|
26
|
+
server: build
|
27
|
+
docker run -it $(LOCAL_LINK) $(PROJECT_NAME)
|
28
|
+
|
29
|
+
gem: build
|
30
|
+
rm -f $(PROJECT_NAME)*.gem
|
31
|
+
docker run $(LOCAL_LINK) $(PROJECT_NAME) gem build $(PROJECT_NAME)
|
32
|
+
|
33
|
+
# Requires rubygems be installed on host
|
34
|
+
gem_release: gem
|
35
|
+
gem push $(PROJECT_NAME)*.gem
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Overview
|
2
|
+
|
3
|
+
https://github.com/kwerle/ruby_language_server
|
4
|
+
|
5
|
+
The goal of this project is to provide a [language server](https://microsoft.github.io/language-server-protocol/) implementation for ruby in ruby.
|
6
|
+
|
7
|
+
# Status
|
8
|
+
|
9
|
+
Beta. It does some stuff. Pretty stable. Used day-to-day.
|
10
|
+
|
11
|
+
Help wanted.
|
12
|
+
|
13
|
+
# Features
|
14
|
+
|
15
|
+
* Definitions
|
16
|
+
* Completions
|
17
|
+
* Lint - thanks to [RuboCop](https://github.com/bbatsov/rubocop)
|
18
|
+
* Please see the [FAQ_ROADMAP.md](./FAQ_ROADMAP.md)
|
19
|
+
|
20
|
+
# Editor Integrations
|
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
|
25
|
+
|
26
|
+
# Running
|
27
|
+
|
28
|
+
`ruby_language_server` will start the program and wait for activity using LSP's STDIO interface
|
29
|
+
|
30
|
+
# Development
|
31
|
+
|
32
|
+
Clone. I love git [HubFlow](https://datasift.github.io/gitflow/).
|
33
|
+
|
34
|
+
Check out the [Makefile](Makefile). You are going to want to do
|
35
|
+
`make guard` and `make continuous_development`.
|
36
|
+
|
37
|
+
* In Atom: install the ide-ruby.
|
38
|
+
* Settings > Packages > ide-ruby > Image Name > local_ruby_language_server
|
39
|
+
* CMD-ALT-CTRL-l (that's an L) will reload the window
|
40
|
+
* CMD-ALT-i will show debugging info
|
41
|
+
|
42
|
+
Write tests and guard will run them. Make changes and reload the window. Test them out.
|
43
|
+
|
44
|
+
# Similar
|
45
|
+
|
46
|
+
* [mtsmfm/language_server-ruby](https://github.com/mtsmfm/language_server-ruby)
|
47
|
+
* [castwide/solargraph](https://github.com/castwide/solargraph)
|
48
|
+
|
49
|
+
# Authors
|
50
|
+
|
51
|
+
* [Kurt Werle](kurt@CircleW.org)
|
52
|
+
|
53
|
+
# Contributors
|
54
|
+
|
55
|
+
* *Your name here!*
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'spec'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Run guard'
|
13
|
+
task guard: [] do
|
14
|
+
`guard`
|
15
|
+
end
|
16
|
+
|
17
|
+
task default: :test
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'ruby_language_server'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'scope_data/base'
|
4
|
+
require_relative 'scope_data/scope'
|
5
|
+
require_relative 'scope_data/variable'
|
6
|
+
|
7
|
+
module RubyLanguageServer
|
8
|
+
class CodeFile
|
9
|
+
attr_reader :uri
|
10
|
+
attr_reader :text
|
11
|
+
attr_reader :lint_found
|
12
|
+
|
13
|
+
def initialize(uri, text)
|
14
|
+
RubyLanguageServer.logger.debug("CodeFile initialize #{uri}")
|
15
|
+
@uri = uri
|
16
|
+
@text = text
|
17
|
+
@refresh_root_scope = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def text=(new_text)
|
21
|
+
RubyLanguageServer.logger.debug("text= for #{uri}")
|
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
|
28
|
+
end
|
29
|
+
|
30
|
+
SYMBOL_KIND = {
|
31
|
+
file: 1,
|
32
|
+
'module': 5, # 2,
|
33
|
+
namespace: 3,
|
34
|
+
package: 4,
|
35
|
+
'class': 5,
|
36
|
+
'method': 6,
|
37
|
+
'singleton method': 6,
|
38
|
+
property: 7,
|
39
|
+
field: 8,
|
40
|
+
constructor: 9,
|
41
|
+
enum: 10,
|
42
|
+
interface: 11,
|
43
|
+
function: 12,
|
44
|
+
variable: 13,
|
45
|
+
constant: 14,
|
46
|
+
string: 15,
|
47
|
+
number: 16,
|
48
|
+
boolean: 17,
|
49
|
+
array: 18
|
50
|
+
}.freeze
|
51
|
+
|
52
|
+
# Find the ancestor of this scope with a name and return that. Or nil.
|
53
|
+
def ancestor_scope_name(scope)
|
54
|
+
return_scope = scope
|
55
|
+
while (return_scope = return_scope.parent)
|
56
|
+
return return_scope.name unless return_scope.name.nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def tags
|
61
|
+
RubyLanguageServer.logger.debug("Asking about tags for #{uri}")
|
62
|
+
return @tags = {} if text.nil? || text == ''
|
63
|
+
|
64
|
+
tags = []
|
65
|
+
root_scope.self_and_descendants.each do |scope|
|
66
|
+
next if scope.type == ScopeData::Base::TYPE_BLOCK
|
67
|
+
|
68
|
+
name = scope.name
|
69
|
+
kind = SYMBOL_KIND[scope.type] || 7
|
70
|
+
kind = 9 if name == 'initialize' # Magical special case
|
71
|
+
scope_hash = {
|
72
|
+
name: name,
|
73
|
+
kind: kind,
|
74
|
+
location: Location.hash(uri, scope.top_line)
|
75
|
+
}
|
76
|
+
container_name = ancestor_scope_name(scope)
|
77
|
+
scope_hash[:containerName] = container_name if container_name
|
78
|
+
tags << scope_hash
|
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
|
93
|
+
end
|
94
|
+
# byebug
|
95
|
+
tags.reject! { |tag| tag[:name].nil? }
|
96
|
+
# RubyLanguageServer.logger.debug("Raw tags for #{uri}: #{tags}")
|
97
|
+
# If you don't reverse the list then atom? won't be able to find the
|
98
|
+
# container and containers will get duplicated.
|
99
|
+
@tags = tags.reverse_each do |tag|
|
100
|
+
child_tags = tags.select { |child_tag| child_tag[:containerName] == tag[:name] }
|
101
|
+
max_line = child_tags.map { |child_tag| child_tag[:location][:range][:end][:line].to_i }.max || 0
|
102
|
+
tag[:location][:range][:end][:line] = [tag[:location][:range][:end][:line], max_line].max
|
103
|
+
end
|
104
|
+
# RubyLanguageServer.logger.debug("Done with tags for #{uri}: #{@tags}")
|
105
|
+
# RubyLanguageServer.logger.debug("tags caller #{caller * ','}")
|
106
|
+
@tags
|
107
|
+
end
|
108
|
+
|
109
|
+
def diagnostics
|
110
|
+
# Maybe we should be sharing this GoodCop across instances
|
111
|
+
@good_cop ||= GoodCop.new
|
112
|
+
@good_cop.diagnostics(@text, @uri)
|
113
|
+
end
|
114
|
+
|
115
|
+
def root_scope
|
116
|
+
# RubyLanguageServer.logger.error("Asking about root_scope with #{text}")
|
117
|
+
if @refresh_root_scope
|
118
|
+
new_root_scope = ScopeParser.new(text).root_scope
|
119
|
+
@root_scope ||= new_root_scope # In case we had NONE
|
120
|
+
return @root_scope if new_root_scope.children.empty?
|
121
|
+
|
122
|
+
@root_scope = new_root_scope
|
123
|
+
@refresh_root_scope = false
|
124
|
+
@tags = nil
|
125
|
+
end
|
126
|
+
@root_scope
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyLanguageServer
|
4
|
+
module Completion
|
5
|
+
COMPLETION_ITEM_KIND = {
|
6
|
+
text: 1,
|
7
|
+
method: 2,
|
8
|
+
function: 3,
|
9
|
+
constructor: 4,
|
10
|
+
field: 5,
|
11
|
+
variable: 6,
|
12
|
+
class: 7,
|
13
|
+
interface: 8,
|
14
|
+
module: 9,
|
15
|
+
property: 10,
|
16
|
+
unit: 11,
|
17
|
+
value: 12,
|
18
|
+
enum: 13,
|
19
|
+
keyword: 14,
|
20
|
+
snippet: 15,
|
21
|
+
color: 16,
|
22
|
+
file: 17,
|
23
|
+
reference: 18
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def completion(context, context_scope, scopes)
|
28
|
+
RubyLanguageServer.logger.debug("completion(#{context}, #{context_scope.self_and_ancestors.map(&:name)}, #{scopes.map(&:name)})")
|
29
|
+
completions =
|
30
|
+
if context.length < 2
|
31
|
+
scope_completions(context.last, context_scope.self_and_ancestors)
|
32
|
+
else
|
33
|
+
scope_completions_in_target_context(context, context_scope, scopes)
|
34
|
+
end
|
35
|
+
{
|
36
|
+
isIncomplete: true,
|
37
|
+
items: completions.uniq.map do |word, hash|
|
38
|
+
{
|
39
|
+
label: word,
|
40
|
+
kind: COMPLETION_ITEM_KIND[hash[:type]]
|
41
|
+
}
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def scope_with_name(name, scopes)
|
47
|
+
scopes.detect { |scope| scope.name == name }
|
48
|
+
end
|
49
|
+
|
50
|
+
def scope_completions_in_target_context(context, context_scope, scopes)
|
51
|
+
working_array = context.dup
|
52
|
+
context_word = working_array[-2]
|
53
|
+
if context_word.match?(/^[A-Z]/)
|
54
|
+
scope = scope_with_name(context_word, scopes)
|
55
|
+
else
|
56
|
+
context_word = context_word.split(/_/).map(&:capitalize).join('')
|
57
|
+
scope = scope_with_name(context_word, scopes)
|
58
|
+
RubyLanguageServer.logger.debug("scope_with_name: #{scope}")
|
59
|
+
end
|
60
|
+
scope ||= context_scope
|
61
|
+
RubyLanguageServer.logger.debug("scope: #{scope}")
|
62
|
+
scope_completions(context.last, scope.self_and_ancestors)
|
63
|
+
end
|
64
|
+
|
65
|
+
def scope_completions(word, scopes)
|
66
|
+
words = {}
|
67
|
+
scopes.each_with_object(words) do |scope, words_hash|
|
68
|
+
scope.children.each do |function|
|
69
|
+
words_hash[function.name] ||= {
|
70
|
+
depth: scope.depth,
|
71
|
+
type: function.type
|
72
|
+
}
|
73
|
+
end
|
74
|
+
scope.variables.each do |variable|
|
75
|
+
words_hash[variable.name] ||= {
|
76
|
+
depth: scope.depth,
|
77
|
+
type: variable.type
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
# words = words.sort_by{|word, hash| hash[:depth] }.to_h
|
82
|
+
good_words = FuzzyMatch.new(words.keys, threshold: 0.01).find_all(word).slice(0..10) || []
|
83
|
+
words = good_words.map { |w| [w, words[w]] }.to_h
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
module RubyLanguageServer
|
6
|
+
# Sole purpose is to install gems
|
7
|
+
module GemInstaller
|
8
|
+
class << self
|
9
|
+
def install_gems(gem_names)
|
10
|
+
gem_names&.compact!
|
11
|
+
gem_names&.reject! { |name| name.strip == '' }
|
12
|
+
return if gem_names.nil? || gem_names.empty?
|
13
|
+
|
14
|
+
RubyLanguageServer.logger.info("Trying to install gems #{gem_names}")
|
15
|
+
gemfile do
|
16
|
+
source 'https://rubygems.org'
|
17
|
+
gem_names.each do |gem_name|
|
18
|
+
gem gem_name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|