Skip to content

Commit

Permalink
Support DocumentSymbol (#16)
Browse files Browse the repository at this point in the history
* Bump ruby-lsp

* Support document symbol

* Add document symbol demo
  • Loading branch information
st0012 authored Feb 10, 2024
1 parent 94a3d5c commit c626d87
Show file tree
Hide file tree
Showing 9 changed files with 9,684 additions and 6,189 deletions.
94 changes: 47 additions & 47 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,62 @@ PATH
remote: .
specs:
ruby-lsp-rspec (0.1.9)
ruby-lsp (~> 0.13.0)
ruby-lsp (~> 0.14.0)

GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
diff-lcs (1.5.0)
debug (1.9.1)
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.5.1)
erubi (1.12.0)
io-console (0.6.0)
irb (1.9.1)
io-console (0.7.2)
irb (1.11.2)
rdoc
reline (>= 0.3.8)
json (2.7.0)
reline (>= 0.4.2)
json (2.7.1)
language_server-protocol (3.17.0.3)
netrc (0.11.0)
parallel (1.23.0)
parser (3.2.2.4)
parallel (1.24.0)
parser (3.3.0.5)
ast (~> 2.4.1)
racc
prettier_print (1.2.1)
prism (0.18.0)
psych (5.1.1.1)
prism (0.21.0)
psych (5.1.2)
stringio
racc (1.7.3)
rainbow (3.1.1)
rake (13.1.0)
rbi (0.1.5)
prism (>= 0.18.0, < 0.19)
rbi (0.1.8)
prism (>= 0.18.0, < 0.22)
sorbet-runtime (>= 0.5.9204)
rdoc (6.6.0)
rdoc (6.6.2)
psych (>= 4.0.0)
regexp_parser (2.8.2)
reline (0.4.1)
regexp_parser (2.9.0)
reline (0.4.2)
io-console (~> 0.5)
rexml (3.2.6)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.3)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.6)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.1)
rubocop (1.58.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.0)
rubocop (1.60.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.4)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
Expand All @@ -70,21 +70,21 @@ GEM
rubocop (~> 1.0)
rubocop-shopify (2.14.0)
rubocop (~> 1.51)
rubocop-sorbet (0.7.5)
rubocop-sorbet (0.7.6)
rubocop (>= 0.90.0)
ruby-lsp (0.13.0)
ruby-lsp (0.14.0)
language_server-protocol (~> 3.17.0)
prism (>= 0.18.0, < 0.19)
sorbet-runtime (>= 0.5.5685)
prism (>= 0.19.0, < 0.22)
sorbet-runtime (>= 0.5.10782)
ruby-progressbar (1.13.0)
sorbet (0.5.11144)
sorbet-static (= 0.5.11144)
sorbet-runtime (0.5.11144)
sorbet-static (0.5.11144-universal-darwin)
sorbet-static (0.5.11144-x86_64-linux)
sorbet-static-and-runtime (0.5.11144)
sorbet (= 0.5.11144)
sorbet-runtime (= 0.5.11144)
sorbet (0.5.11237)
sorbet-static (= 0.5.11237)
sorbet-runtime (0.5.11237)
sorbet-static (0.5.11237-universal-darwin)
sorbet-static (0.5.11237-x86_64-linux)
sorbet-static-and-runtime (0.5.11237)
sorbet (= 0.5.11237)
sorbet-runtime (= 0.5.11237)
spoom (1.2.4)
erubi (>= 1.10.0)
sorbet-static-and-runtime (>= 0.5.10187)
Expand All @@ -93,12 +93,12 @@ GEM
stringio (3.1.0)
syntax_tree (6.2.0)
prettier_print (>= 1.2.0)
tapioca (0.11.12)
tapioca (0.12.0)
bundler (>= 2.2.25)
netrc (>= 0.11.0)
parallel (>= 1.21.0)
rbi (>= 0.1.4, < 0.2)
sorbet-static-and-runtime (>= 0.5.10187)
sorbet-static-and-runtime (>= 0.5.10820)
spoom (~> 1.2.0, >= 1.2.0)
thor (>= 1.2.0)
yard-sorbet
Expand All @@ -110,7 +110,7 @@ GEM
yard (>= 0.9)

PLATFORMS
arm64-darwin-22
universal-darwin
x86_64-linux

DEPENDENCIES
Expand All @@ -127,4 +127,4 @@ DEPENDENCIES
tapioca (~> 0.11)

BUNDLED WITH
2.4.18
2.5.4
18 changes: 15 additions & 3 deletions lib/ruby_lsp/ruby_lsp_rspec/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "ruby_lsp/internal"

require_relative "code_lens"
require_relative "document_symbol"

module RubyLsp
module RSpec
Expand All @@ -20,14 +21,25 @@ def deactivate; end
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
sig do
override.params(
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
uri: URI::Generic,
emitter: Prism::Dispatcher,
).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
).void
end
def create_code_lens_listener(uri, emitter)
def create_code_lens_listener(response_builder, uri, emitter)
return unless uri.to_standardized_path&.end_with?("_test.rb") || uri.to_standardized_path&.end_with?("_spec.rb")

CodeLens.new(uri, emitter)
CodeLens.new(response_builder, uri, emitter)
end

sig do
override.params(
response_builder: ResponseBuilders::DocumentSymbol,
dispatcher: Prism::Dispatcher,
).void
end
def create_document_symbol_listener(response_builder, dispatcher)
DocumentSymbol.new(response_builder, dispatcher)
end

sig { override.returns(String) }
Expand Down
28 changes: 13 additions & 15 deletions lib/ruby_lsp/ruby_lsp_rspec/code_lens.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@

module RubyLsp
module RSpec
class CodeLens < ::RubyLsp::Listener
class CodeLens
extend T::Sig
extend T::Generic

include ::RubyLsp::Requests::Support::Common

ResponseType = type_member { { fixed: T::Array[::RubyLsp::Interface::CodeLens] } }

sig { override.returns(ResponseType) }
attr_reader :_response

sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher).void }
def initialize(uri, dispatcher)
@_response = T.let([], ResponseType)
sig do
params(
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
uri: URI::Generic,
dispatcher: Prism::Dispatcher,
).void
end
def initialize(response_builder, uri, dispatcher)
@response_builder = response_builder
# Listener is only initialized if uri.to_standardized_path is valid
@path = T.let(T.must(uri.to_standardized_path), String)
@group_id = T.let(1, Integer)
Expand All @@ -39,8 +39,6 @@ def initialize(uri, dispatcher)
end,
String,
)

super(dispatcher)
end

sig { params(node: Prism::CallNode).void }
Expand Down Expand Up @@ -119,23 +117,23 @@ def add_test_code_lens(node, name:, kind:)
},
]

@_response << create_code_lens(
@response_builder << create_code_lens(
node,
title: "Run",
command_name: "rubyLsp.runTest",
arguments: arguments,
data: { type: "test", **grouping_data },
)

@_response << create_code_lens(
@response_builder << create_code_lens(
node,
title: "Run In Terminal",
command_name: "rubyLsp.runTestInTerminal",
arguments: arguments,
data: { type: "test_in_terminal", **grouping_data },
)

@_response << create_code_lens(
@response_builder << create_code_lens(
node,
title: "Debug",
command_name: "rubyLsp.debugTest",
Expand Down
88 changes: 88 additions & 0 deletions lib/ruby_lsp/ruby_lsp_rspec/document_symbol.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# typed: strict
# frozen_string_literal: true

module RubyLsp
module RSpec
class DocumentSymbol
extend T::Sig

include ::RubyLsp::Requests::Support::Common

sig do
params(
response_builder: ResponseBuilders::DocumentSymbol,
dispatcher: Prism::Dispatcher,
).void
end
def initialize(response_builder, dispatcher)
@response_builder = response_builder

dispatcher.register(self, :on_call_node_enter, :on_call_node_leave)
end

sig { params(node: Prism::CallNode).void }
def on_call_node_enter(node)
case node.message
when "example", "it", "specify"
name = generate_name(node)

return unless name

@response_builder.last.children << RubyLsp::Interface::DocumentSymbol.new(
name: name,
kind: LanguageServer::Protocol::Constant::SymbolKind::METHOD,
selection_range: range_from_node(node),
range: range_from_node(node),
)
when "context", "describe"
return if node.receiver && node.receiver&.slice != "RSpec"

name = generate_name(node)

return unless name

symbol = RubyLsp::Interface::DocumentSymbol.new(
name: name,
kind: LanguageServer::Protocol::Constant::SymbolKind::MODULE,
selection_range: range_from_node(node),
range: range_from_node(node),
children: [],
)

@response_builder.last.children << symbol
@response_builder.push(symbol)
end
end

sig { params(node: Prism::CallNode).void }
def on_call_node_leave(node)
case node.message
when "context", "describe"
return if node.receiver && node.receiver&.slice != "RSpec"

@response_builder.pop
end
end

sig { params(node: Prism::CallNode).returns(T.nilable(String)) }
def generate_name(node)
arguments = node.arguments&.arguments

return unless arguments

argument = arguments.first

case argument
when Prism::StringNode
argument.content.dump
when Prism::CallNode
"<#{argument.name}>"
when nil
nil
else
argument.slice
end
end
end
end
end
Binary file added misc/document-symbol-example.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ruby-lsp-rspec.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "ruby-lsp", "~> 0.13.0"
spec.add_dependency "ruby-lsp", "~> 0.14.0"
end
Loading

0 comments on commit c626d87

Please sign in to comment.