ruby-lsp 0.0.4 → 0.1.0

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: ab0e94532c080cf6e443c95d9ca7ccb16f548ec45768dc58e95fd691c907a965
4
- data.tar.gz: 856df7b413ef111e100ee42da541856843d966184f9dbe1dfe2ee5a50da1e802
3
+ metadata.gz: 2b072ffa3ea73a83aba6d6c32b931c4de30b0de06fd70655d620c3ed95bd8aa4
4
+ data.tar.gz: 24568688b20ffed38defcbc0b00708eb22a7dad20a9b5f397348242a64359bfd
5
5
  SHA512:
6
- metadata.gz: fde4cd9c5e556ff926b22d316d1bfcc5d31c089850d4558ac7d954fe33df4c8d2b8f8c14e55d1dcc2898087d0d29e8b12fc2f768e2b14935fa727f9620ff5c9e
7
- data.tar.gz: 24fb12213f36edcee13fe65d53a94977737b251566d2503dc857dc276192d6f570f93147f57fc5e3b23c8d90b2c1f96f4cc7e308d5b969a02705d39444676f95
6
+ metadata.gz: ea1830f0be08cb291e67d80bbe21dbe17f3e4b4d285b1d9112e004ca2feff32eaca85af755bc2635e3341ab4e64491710c3ba13c5bed617e34495534e1d7a5f8
7
+ data.tar.gz: f84b1b27c5c17455d1e8423f1e52f98a754ed123e1722bd536ee7bfdc754952e5d6619c0f4402664a33dc278bdc2422a3e7a37c8de5f172e4456e7a6c08b7a67
data/.rubocop.yml CHANGED
@@ -25,6 +25,15 @@ Sorbet/FalseSigil:
25
25
  Sorbet/TrueSigil:
26
26
  Enabled: true
27
27
  Include:
28
- - "**/*.rb"
28
+ - "test/**/*.rb"
29
29
  Exclude:
30
30
  - "**/*.rake"
31
+ - "lib/**/*.rb"
32
+
33
+ Sorbet/StrictSigil:
34
+ Enabled: true
35
+ Include:
36
+ - "lib/**/*.rb"
37
+ Exclude:
38
+ - "**/*.rake"
39
+ - "test/**/*.rb"
data/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.0]
10
+
11
+ - Implement token modifiers in SemanticTokenEncoder ([#112](https://github.com/Shopify/ruby-lsp/pull/112))
12
+ - Add semantic token for name in a method definition ([#133](https://github.com/Shopify/ruby-lsp/pull/133))
13
+ - Add semantic highighting for def endless and singleton method names ([#134](https://github.com/Shopify/ruby-lsp/pull/134))
14
+ - Add semantic token for keyword self ([#137](https://github.com/Shopify/ruby-lsp/pull/137))
15
+ - Add semantic token for constants ([#138](https://github.com/Shopify/ruby-lsp/pull/138))
16
+ - Improve error handling + fix formatting hanging issue ([#149](https://github.com/Shopify/ruby-lsp/pull/149))
17
+ - Set the minimum syntax_tree version to 2.4 ([#151](https://github.com/Shopify/ruby-lsp/pull/151))
18
+
9
19
  ## [0.0.4]
10
20
 
11
21
  - Add basic document highlight (https://github.com/Shopify/ruby-lsp/pull/91)
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ gem "minitest", "~> 5.15"
9
9
  gem "minitest-reporters", "~> 1.5"
10
10
  gem "rake", "~> 13.0"
11
11
  gem "rubocop-shopify", "~> 2.7", require: false
12
- gem "rubocop-minitest", "~> 0.20.0", require: false
12
+ gem "rubocop-minitest", "~> 0.20.1", require: false
13
13
  gem "rubocop-rake", "~> 0.6.0", require: false
14
14
  gem "rubocop-sorbet", "~> 0.6", require: false
15
15
  gem "sorbet-static-and-runtime"
data/Gemfile.lock CHANGED
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp (0.0.4)
4
+ ruby-lsp (0.1.0)
5
5
  language_server-protocol
6
6
  rubocop (>= 1.0)
7
7
  sorbet-runtime
8
- syntax_tree (>= 2.3)
8
+ syntax_tree (>= 2.4)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
@@ -47,7 +47,7 @@ GEM
47
47
  reline (0.3.1)
48
48
  io-console (~> 0.5)
49
49
  rexml (3.2.5)
50
- rubocop (1.30.0)
50
+ rubocop (1.30.1)
51
51
  parallel (~> 1.10)
52
52
  parser (>= 3.1.0.0)
53
53
  rainbow (>= 2.2.2, < 4.0)
@@ -58,7 +58,7 @@ GEM
58
58
  unicode-display_width (>= 1.4.0, < 3.0)
59
59
  rubocop-ast (1.18.0)
60
60
  parser (>= 3.1.1.0)
61
- rubocop-minitest (0.20.0)
61
+ rubocop-minitest (0.20.1)
62
62
  rubocop (>= 0.90, < 2.0)
63
63
  rubocop-rake (0.6.0)
64
64
  rubocop (~> 1.0)
@@ -67,14 +67,14 @@ GEM
67
67
  rubocop-sorbet (0.6.8)
68
68
  rubocop (>= 0.90.0)
69
69
  ruby-progressbar (1.11.0)
70
- sorbet (0.5.10073)
71
- sorbet-static (= 0.5.10073)
72
- sorbet-runtime (0.5.10073)
73
- sorbet-static (0.5.10073-universal-darwin-21)
74
- sorbet-static (0.5.10073-x86_64-linux)
75
- sorbet-static-and-runtime (0.5.10073)
76
- sorbet (= 0.5.10073)
77
- sorbet-runtime (= 0.5.10073)
70
+ sorbet (0.5.10092)
71
+ sorbet-static (= 0.5.10092)
72
+ sorbet-runtime (0.5.10092)
73
+ sorbet-static (0.5.10092-universal-darwin-21)
74
+ sorbet-static (0.5.10092-x86_64-linux)
75
+ sorbet-static-and-runtime (0.5.10092)
76
+ sorbet (= 0.5.10092)
77
+ sorbet-runtime (= 0.5.10092)
78
78
  spoom (1.1.11)
79
79
  sorbet (>= 0.5.9204)
80
80
  sorbet-runtime (>= 0.5.9204)
@@ -111,7 +111,7 @@ DEPENDENCIES
111
111
  minitest (~> 5.15)
112
112
  minitest-reporters (~> 1.5)
113
113
  rake (~> 13.0)
114
- rubocop-minitest (~> 0.20.0)
114
+ rubocop-minitest (~> 0.20.1)
115
115
  rubocop-rake (~> 0.6.0)
116
116
  rubocop-shopify (~> 2.7)
117
117
  rubocop-sorbet (~> 0.6)
data/README.md CHANGED
@@ -50,7 +50,7 @@ To add a new expectations test runner for a new request handler:
50
50
  require "expectations/expectations_test_runner"
51
51
 
52
52
  class $HANDLERExpectationsTest < ExpectationsTestRunner
53
- expectations_tests RubyLsp::Requests::$HANDLER, "$EXPECTATIONS_DIR"
53
+ expectations_tests RubyLsp::Requests::$HANDLER, "$EXPECTATIONS_DIR"
54
54
  end
55
55
  ```
56
56
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.1.0
data/exe/ruby-lsp CHANGED
@@ -18,6 +18,6 @@ rescue
18
18
  nil
19
19
  end
20
20
 
21
- require_relative "../lib/internal"
21
+ require_relative "../lib/ruby_lsp/internal"
22
22
 
23
23
  RubyLsp::Cli.start
data/lib/ruby-lsp.rb CHANGED
@@ -1,6 +1,6 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
- VERSION = File.read(File.expand_path("../VERSION", __dir__)).strip
5
+ VERSION = T.let(File.read(File.expand_path("../VERSION", __dir__)).strip, String)
6
6
  end
@@ -32,7 +32,13 @@ module RubyLsp
32
32
  @source == other.source
33
33
  end
34
34
 
35
- sig { params(request_name: Symbol, block: T.proc.params(document: Document).returns(T.untyped)).returns(T.untyped) }
35
+ sig do
36
+ type_parameters(:T)
37
+ .params(
38
+ request_name: Symbol,
39
+ block: T.proc.params(document: Document).returns(T.type_parameter(:T))
40
+ ).returns(T.type_parameter(:T))
41
+ end
36
42
  def cache_fetch(request_name, &block)
37
43
  cached = @cache[request_name]
38
44
  return cached if cached
@@ -28,9 +28,7 @@ module RubyLsp
28
28
  sig { void }
29
29
  def start
30
30
  $stderr.puts "Starting Ruby LSP..."
31
- @reader.read do |request|
32
- with_telemetry(request) { handle(request) }
33
- end
31
+ @reader.read { |request| handle(request) }
34
32
  end
35
33
 
36
34
  sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
@@ -52,11 +50,23 @@ module RubyLsp
52
50
 
53
51
  sig { params(request: T::Hash[Symbol, T.untyped]).void }
54
52
  def handle(request)
53
+ result = T.let(nil, T.untyped)
54
+ error = T.let(nil, T.nilable(StandardError))
55
55
  handler = @handlers[request[:method]]
56
- return unless handler
57
56
 
58
- result = handler.call(request)
59
- @writer.write(id: request[:id], result: result) unless result == VOID
57
+ request_time = Benchmark.realtime do
58
+ if handler
59
+ begin
60
+ result = handler.call(request)
61
+ rescue StandardError => e
62
+ error = e
63
+ end
64
+
65
+ @writer.write(id: request[:id], result: result) unless result == VOID
66
+ end
67
+ end
68
+
69
+ @writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
60
70
  end
61
71
 
62
72
  sig { void }
@@ -114,14 +124,14 @@ module RubyLsp
114
124
  sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
115
125
  def respond_with_document_symbol(uri)
116
126
  store.cache_fetch(uri, :document_symbol) do |document|
117
- RubyLsp::Requests::DocumentSymbol.run(document)
127
+ RubyLsp::Requests::DocumentSymbol.new(document).run
118
128
  end
119
129
  end
120
130
 
121
131
  sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::FoldingRange]) }
122
132
  def respond_with_folding_ranges(uri)
123
133
  store.cache_fetch(uri, :folding_ranges) do |document|
124
- Requests::FoldingRanges.run(document)
134
+ Requests::FoldingRanges.new(document).run
125
135
  end
126
136
  end
127
137
 
@@ -129,11 +139,11 @@ module RubyLsp
129
139
  params(
130
140
  uri: String,
131
141
  positions: T::Array[Document::PositionShape]
132
- ).returns(T::Array[RubyLsp::Requests::Support::SelectionRange])
142
+ ).returns(T::Array[T.nilable(RubyLsp::Requests::Support::SelectionRange)])
133
143
  end
134
144
  def respond_with_selection_ranges(uri, positions)
135
145
  ranges = store.cache_fetch(uri, :selection_ranges) do |document|
136
- Requests::SelectionRanges.run(document)
146
+ Requests::SelectionRanges.new(document).run
137
147
  end
138
148
 
139
149
  # Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
@@ -150,19 +160,22 @@ module RubyLsp
150
160
  sig { params(uri: String).returns(LanguageServer::Protocol::Interface::SemanticTokens) }
151
161
  def respond_with_semantic_highlighting(uri)
152
162
  store.cache_fetch(uri, :semantic_highlighting) do |document|
153
- Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run
163
+ T.cast(
164
+ Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run,
165
+ LanguageServer::Protocol::Interface::SemanticTokens
166
+ )
154
167
  end
155
168
  end
156
169
 
157
- sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::TextEdit]) }
170
+ sig { params(uri: String).returns(T.nilable(T::Array[LanguageServer::Protocol::Interface::TextEdit])) }
158
171
  def respond_with_formatting(uri)
159
- Requests::Formatting.run(uri, store.get(uri))
172
+ Requests::Formatting.new(uri, store.get(uri)).run
160
173
  end
161
174
 
162
175
  sig { params(uri: String).void }
163
176
  def send_diagnostics(uri)
164
177
  response = store.cache_fetch(uri, :diagnostics) do |document|
165
- Requests::Diagnostics.run(uri, document)
178
+ Requests::Diagnostics.new(uri, document).run
166
179
  end
167
180
 
168
181
  @writer.write(
@@ -175,11 +188,11 @@ module RubyLsp
175
188
  end
176
189
 
177
190
  sig do
178
- params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::Diagnostic])
191
+ params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::CodeAction])
179
192
  end
180
193
  def respond_with_code_actions(uri, range)
181
194
  store.cache_fetch(uri, :code_actions) do |document|
182
- Requests::CodeActions.run(uri, document, range)
195
+ Requests::CodeActions.new(uri, document, range).run
183
196
  end
184
197
  end
185
198
 
@@ -190,22 +203,7 @@ module RubyLsp
190
203
  ).returns(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
191
204
  end
192
205
  def respond_with_document_highlight(uri, position)
193
- Requests::DocumentHighlight.run(store.get(uri), position)
194
- end
195
-
196
- sig { params(request: T::Hash[Symbol, T.untyped], block: T.proc.void).returns(T.untyped) }
197
- def with_telemetry(request, &block)
198
- result = T.let(nil, T.untyped)
199
- error = T.let(nil, T.nilable(StandardError))
200
-
201
- request_time = Benchmark.realtime do
202
- result = block.call
203
- rescue StandardError => e
204
- error = e
205
- end
206
-
207
- @writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
208
- result
206
+ Requests::DocumentHighlight.new(store.get(uri), position).run
209
207
  end
210
208
 
211
209
  sig do
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
@@ -1,24 +1,26 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
6
  # :nodoc:
7
7
  class BaseRequest < SyntaxTree::Visitor
8
- def self.run(document)
9
- new(document).run
10
- end
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ abstract!
11
12
 
13
+ sig { params(document: Document).void }
12
14
  def initialize(document)
13
15
  @document = document
14
16
 
15
17
  super()
16
18
  end
17
19
 
18
- def run
19
- raise NotImplementedError, "#{self.class}#run must be implemented"
20
- end
20
+ sig { abstract.returns(Object) }
21
+ def run; end
21
22
 
23
+ sig { params(node: SyntaxTree::Node).returns(LanguageServer::Protocol::Interface::Range) }
22
24
  def range_from_syntax_tree_node(node)
23
25
  loc = node.location
24
26
 
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
@@ -14,23 +14,32 @@ module RubyLsp
14
14
  # puts "Hello" # --> code action: quick fix indentation
15
15
  # end
16
16
  # ```
17
- class CodeActions
18
- def self.run(uri, document, range)
19
- new(uri, document, range).run
20
- end
17
+ class CodeActions < BaseRequest
18
+ extend T::Sig
21
19
 
20
+ sig do
21
+ params(
22
+ uri: String,
23
+ document: Document,
24
+ range: T::Range[Integer]
25
+ ).void
26
+ end
22
27
  def initialize(uri, document, range)
23
- @document = document
28
+ super(document)
29
+
24
30
  @uri = uri
25
31
  @range = range
26
32
  end
27
33
 
34
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::CodeAction], Object)) }
28
35
  def run
29
- diagnostics = Diagnostics.run(@uri, @document)
30
- corrections = diagnostics.select { |diagnostic| diagnostic.correctable? && diagnostic.in_range?(@range) }
36
+ diagnostics = Diagnostics.new(@uri, @document).run
37
+ corrections = diagnostics.select do |diagnostic|
38
+ diagnostic.correctable? && T.cast(diagnostic, Support::RuboCopDiagnostic).in_range?(@range)
39
+ end
31
40
  return [] if corrections.empty?
32
41
 
33
- corrections.map!(&:to_lsp_code_action)
42
+ T.cast(corrections, T::Array[Support::RuboCopDiagnostic]).map!(&:to_lsp_code_action)
34
43
  end
35
44
  end
36
45
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
@@ -15,6 +15,16 @@ module RubyLsp
15
15
  # end
16
16
  # ```
17
17
  class Diagnostics < RuboCopRequest
18
+ extend T::Sig
19
+
20
+ sig do
21
+ override.returns(
22
+ T.any(
23
+ T.all(T::Array[Support::RuboCopDiagnostic], Object),
24
+ T.all(T::Array[Support::SyntaxErrorDiagnostic], Object),
25
+ )
26
+ )
27
+ end
18
28
  def run
19
29
  return syntax_error_diagnostics if @document.syntax_errors?
20
30
 
@@ -23,12 +33,14 @@ module RubyLsp
23
33
  @diagnostics
24
34
  end
25
35
 
36
+ sig { params(_file: String, offenses: T::Array[RuboCop::Cop::Offense]).void }
26
37
  def file_finished(_file, offenses)
27
38
  @diagnostics = offenses.map { |offense| Support::RuboCopDiagnostic.new(offense, @uri) }
28
39
  end
29
40
 
30
41
  private
31
42
 
43
+ sig { returns(T::Array[Support::SyntaxErrorDiagnostic]) }
32
44
  def syntax_error_diagnostics
33
45
  @document.syntax_error_edits.map { |e| Support::SyntaxErrorDiagnostic.new(e) }
34
46
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
@@ -21,18 +21,28 @@ module RubyLsp
21
21
  # end
22
22
  # ```
23
23
  class DocumentHighlight < BaseRequest
24
- def self.run(document, position)
25
- new(document, position).run
24
+ extend T::Sig
25
+
26
+ VarNodes = T.type_alias do
27
+ T.any(
28
+ SyntaxTree::GVar,
29
+ SyntaxTree::Ident,
30
+ SyntaxTree::IVar,
31
+ SyntaxTree::Const,
32
+ SyntaxTree::CVar
33
+ )
26
34
  end
27
35
 
36
+ sig { params(document: Document, position: Document::PositionShape).void }
28
37
  def initialize(document, position)
29
- @highlights = []
38
+ @highlights = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
30
39
  position = Document::Scanner.new(document.source).find_position(position)
31
- @target = find(document.tree, position)
40
+ @target = T.let(find(document.tree, position), T.nilable(VarNodes))
32
41
 
33
42
  super(document)
34
43
  end
35
44
 
45
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight], Object)) }
36
46
  def run
37
47
  # no @target means the target is not highlightable
38
48
  return [] unless @target
@@ -41,6 +51,7 @@ module RubyLsp
41
51
  @highlights
42
52
  end
43
53
 
54
+ sig { params(node: SyntaxTree::VarField).void }
44
55
  def visit_var_field(node)
45
56
  if matches_target?(node.value)
46
57
  add_highlight(
@@ -52,6 +63,7 @@ module RubyLsp
52
63
  super
53
64
  end
54
65
 
66
+ sig { params(node: SyntaxTree::VarRef).void }
55
67
  def visit_var_ref(node)
56
68
  if matches_target?(node.value)
57
69
  add_highlight(
@@ -65,6 +77,7 @@ module RubyLsp
65
77
 
66
78
  private
67
79
 
80
+ sig { params(node: SyntaxTree::Node, position: Integer).returns(T.nilable(VarNodes)) }
68
81
  def find(node, position)
69
82
  matched =
70
83
  node.child_nodes.compact.bsearch do |child|
@@ -83,10 +96,12 @@ module RubyLsp
83
96
  end
84
97
  end
85
98
 
99
+ sig { params(node: SyntaxTree::Node).returns(T::Boolean) }
86
100
  def matches_target?(node)
87
- node.is_a?(@target.class) && node.value == @target.value
101
+ node.is_a?(@target.class) && T.cast(node, VarNodes).value == T.must(@target).value
88
102
  end
89
103
 
104
+ sig { params(node: SyntaxTree::Node, kind: Integer).void }
90
105
  def add_highlight(node, kind)
91
106
  range = range_from_syntax_tree_node(node)
92
107
  @highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: kind)
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
@@ -25,7 +25,9 @@ module RubyLsp
25
25
  # end
26
26
  # ```
27
27
  class DocumentSymbol < BaseRequest
28
- SYMBOL_KIND = {
28
+ extend T::Sig
29
+
30
+ SYMBOL_KIND = T.let({
29
31
  file: 1,
30
32
  module: 2,
31
33
  namespace: 3,
@@ -52,33 +54,43 @@ module RubyLsp
52
54
  event: 24,
53
55
  operator: 25,
54
56
  typeparameter: 26,
55
- }.freeze
57
+ }.freeze, T::Hash[Symbol, Integer])
56
58
 
57
- ATTR_ACCESSORS = ["attr_reader", "attr_writer", "attr_accessor"].freeze
59
+ ATTR_ACCESSORS = T.let(["attr_reader", "attr_writer", "attr_accessor"].freeze, T::Array[String])
58
60
 
59
61
  class SymbolHierarchyRoot
62
+ extend T::Sig
63
+
64
+ sig { returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
60
65
  attr_reader :children
61
66
 
67
+ sig { void }
62
68
  def initialize
63
- @children = []
69
+ @children = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentSymbol])
64
70
  end
65
71
  end
66
72
 
73
+ sig { params(document: Document).void }
67
74
  def initialize(document)
68
75
  super
69
76
 
70
- @root = SymbolHierarchyRoot.new
71
- @stack = [@root]
77
+ @root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
78
+ @stack = T.let(
79
+ [@root],
80
+ T::Array[T.any(SymbolHierarchyRoot, LanguageServer::Protocol::Interface::DocumentSymbol)]
81
+ )
72
82
  end
73
83
 
84
+ sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol], Object)) }
74
85
  def run
75
86
  visit(@document.tree)
76
87
  @root.children
77
88
  end
78
89
 
90
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
79
91
  def visit_class(node)
80
92
  symbol = create_document_symbol(
81
- name: node.constant.constant.value,
93
+ name: fully_qualified_name(node),
82
94
  kind: :class,
83
95
  range_node: node,
84
96
  selection_range_node: node.constant
@@ -89,6 +101,7 @@ module RubyLsp
89
101
  @stack.pop
90
102
  end
91
103
 
104
+ sig { params(node: SyntaxTree::Command).void }
92
105
  def visit_command(node)
93
106
  return unless ATTR_ACCESSORS.include?(node.message.value)
94
107
 
@@ -104,6 +117,7 @@ module RubyLsp
104
117
  end
105
118
  end
106
119
 
120
+ sig { params(node: SyntaxTree::ConstPathField).void }
107
121
  def visit_const_path_field(node)
108
122
  create_document_symbol(
109
123
  name: node.constant.value,
@@ -113,6 +127,7 @@ module RubyLsp
113
127
  )
114
128
  end
115
129
 
130
+ sig { params(node: SyntaxTree::Def).void }
116
131
  def visit_def(node)
117
132
  name = node.name.value
118
133
 
@@ -128,6 +143,7 @@ module RubyLsp
128
143
  @stack.pop
129
144
  end
130
145
 
146
+ sig { params(node: SyntaxTree::DefEndless).void }
131
147
  def visit_def_endless(node)
132
148
  name = node.name.value
133
149
 
@@ -143,6 +159,7 @@ module RubyLsp
143
159
  @stack.pop
144
160
  end
145
161
 
162
+ sig { params(node: SyntaxTree::Defs).void }
146
163
  def visit_defs(node)
147
164
  symbol = create_document_symbol(
148
165
  name: "self.#{node.name.value}",
@@ -156,9 +173,10 @@ module RubyLsp
156
173
  @stack.pop
157
174
  end
158
175
 
176
+ sig { params(node: SyntaxTree::ModuleDeclaration).void }
159
177
  def visit_module(node)
160
178
  symbol = create_document_symbol(
161
- name: node.constant.constant.value,
179
+ name: fully_qualified_name(node),
162
180
  kind: :module,
163
181
  range_node: node,
164
182
  selection_range_node: node.constant
@@ -169,6 +187,7 @@ module RubyLsp
169
187
  @stack.pop
170
188
  end
171
189
 
190
+ sig { params(node: SyntaxTree::TopConstField).void }
172
191
  def visit_top_const_field(node)
173
192
  create_document_symbol(
174
193
  name: node.constant.value,
@@ -178,6 +197,7 @@ module RubyLsp
178
197
  )
179
198
  end
180
199
 
200
+ sig { params(node: SyntaxTree::VarField).void }
181
201
  def visit_var_field(node)
182
202
  kind = case node.value
183
203
  when SyntaxTree::Const
@@ -198,6 +218,14 @@ module RubyLsp
198
218
 
199
219
  private
200
220
 
221
+ sig do
222
+ params(
223
+ name: String,
224
+ kind: Symbol,
225
+ range_node: SyntaxTree::Node,
226
+ selection_range_node: SyntaxTree::Node
227
+ ).returns(LanguageServer::Protocol::Interface::DocumentSymbol)
228
+ end
201
229
  def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
202
230
  symbol = LanguageServer::Protocol::Interface::DocumentSymbol.new(
203
231
  name: name,
@@ -207,10 +235,29 @@ module RubyLsp
207
235
  children: [],
208
236
  )
209
237
 
210
- @stack.last.children << symbol
238
+ T.must(@stack.last).children << symbol
211
239
 
212
240
  symbol
213
241
  end
242
+
243
+ sig { params(node: T.any(SyntaxTree::ClassDeclaration, SyntaxTree::ModuleDeclaration)).returns(String) }
244
+ def fully_qualified_name(node)
245
+ constant = T.let(node.constant, SyntaxTree::Node)
246
+ name = +node.constant.constant.value
247
+
248
+ while constant.is_a?(SyntaxTree::ConstPathRef)
249
+ constant = constant.parent
250
+
251
+ case constant
252
+ when SyntaxTree::ConstPathRef
253
+ name.prepend("#{constant.constant.value}::")
254
+ when SyntaxTree::VarRef
255
+ name.prepend("#{constant.value.value}::")
256
+ end
257
+ end
258
+
259
+ name
260
+ end
214
261
  end
215
262
  end
216
263
  end