ruby-lsp 0.0.4 → 0.1.0

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 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