Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LSP related improvements for Sublime LSP #513

Merged
merged 5 commits into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/steep/server/interaction_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def process_hover(job)
end

LSP::Interface::Hover.new(
contents: { kind: "markdown", value: format_hover(content) },
contents: { kind: "markdown", value: format_hover(content)&.gsub(/<!--(?~-->)-->/, "") },
range: range
)
end
Expand Down Expand Up @@ -271,7 +271,7 @@ def format_completion_item_for_rbs(sig_service, type_name, context, job, prefix)
),
end: LanguageServer::Protocol::Interface::Position.new(
line: job.line - 1,
character: job.column - prefix.size
character: job.column
)
)

Expand Down
2 changes: 1 addition & 1 deletion lib/steep/server/master.rb
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ def on_type_check_update(guid:, path:)
{ kind: "end" }
else
progress_string = ("▮"*(percentage/5)) + ("▯"*(20 - percentage/5))
{ kind: "report", percentage: percentage, message: "#{progress_string} (#{percentage}%)" }
{ kind: "report", percentage: percentage, message: "#{progress_string}" }
end

job_queue << SendMessageJob.to_client(
Expand Down
2 changes: 1 addition & 1 deletion lib/steep/server/type_check_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ def goto(job)
line = job.params[:position][:line] + 1
column = job.params[:position][:character]

goto_service = Services::GotoService.new(type_check: service)
goto_service = Services::GotoService.new(type_check: service, assignment: assignment)
locations =
case
when job.definition?
Expand Down
10 changes: 7 additions & 3 deletions lib/steep/server/worker_process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@ def initialize(reader:, writer:, stderr:, wait_thread:, name:, index: nil)
end

def self.spawn_worker(type, name:, steepfile:, options: [], delay_shutdown: false, index: nil)
log_level = %w(debug info warn error fatal unknown)[Steep.logger.level]
args = ["--name=#{name}", "--steepfile=#{steepfile}"]
args << (%w(debug info warn error fatal unknown)[Steep.logger.level].yield_self {|log_level| "--log-level=#{log_level}" })
if Steep.log_output.is_a?(String)
args << "--log-output=#{Steep.log_output}"
end
command = case type
when :interaction
["steep", "worker", "--interaction", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}", *options]
["steep", "worker", "--interaction", *args, *options]
when :typecheck
["steep", "worker", "--typecheck", "--name=#{name}", "--log-level=#{log_level}", "--steepfile=#{steepfile}", *options]
["steep", "worker", "--typecheck", *args, *options]
else
raise "Unknown type: #{type}"
end
Expand Down
17 changes: 14 additions & 3 deletions lib/steep/services/goto_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ def from_rbs?
end
TypeNameQuery = Struct.new(:name, keyword_init: true)

attr_reader :type_check
attr_reader :type_check, :assignment

def initialize(type_check:)
def initialize(type_check:, assignment:)
@type_check = type_check
@assignment = assignment
end

def project
Expand Down Expand Up @@ -78,7 +79,17 @@ def definition(path:, line:, column:)
end
end

locations.uniq
# Drop un-assigned paths here.
# The path assignment makes sense only for `.rbs` files, because un-assigned `.rb` files are already skipped since they are not type checked.
#
locations.uniq.select do |loc|
case loc
when RBS::Location
assignment =~ loc.name
else
true
end
end
end

def test_ast_location(loc, line:, column:)
Expand Down
63 changes: 51 additions & 12 deletions test/goto_service_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def dir
@dir ||= Pathname(Dir.mktmpdir)
end

def assignment
Services::PathAssignment.all
end

def project
@project ||= Project.new(steepfile_path: dir + "Steepfile").tap do |project|
Project::DSL.parse(project, <<EOF)
Expand Down Expand Up @@ -54,7 +58,7 @@ class Customer
RUBY
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.definition(path: dir + "sig/customer.rbs", line: 2, column: 4).tap do |locations|
end
Expand All @@ -80,7 +84,7 @@ class Customer
RUBY
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.query_at(path: dir + "lib/customer.rb", line: 1, column: 10).tap do |qs|
assert_equal 1, qs.size
Expand Down Expand Up @@ -130,7 +134,7 @@ class Customer
RUBY
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.query_at(path: dir + "sig/customer.rbs", line: 1, column: 10).tap do |qs|
assert_equal 1, qs.size
Expand Down Expand Up @@ -173,7 +177,7 @@ def self.bar
RUBY
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.query_at(path: dir + "sig/customer.rbs", line: 2, column: 7).tap do |qs|
assert_equal 1, qs.size
Expand Down Expand Up @@ -237,7 +241,7 @@ def foo: ([String, string] key) -> String
RBS
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.query_at(path: dir + "sig/customer.rbs", line: 2, column: 16).tap do |qs|
assert_equal 1, qs.size
Expand Down Expand Up @@ -276,7 +280,7 @@ def self?.baz: () -> void
RUBY
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.query_at(path: dir + "lib/main.rb", line: 1, column: 16).tap do |qs|
assert_equal 1, qs.size
Expand Down Expand Up @@ -326,7 +330,7 @@ module ::Customer2
type_check.source_files.each_key do |path|
type_check.typecheck_source(path: path) {}
end
service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.constant_definition_in_ruby(TypeName("::Customer"), locations: []).tap do |locs|
assert_equal 1, locs.size
Expand Down Expand Up @@ -420,7 +424,7 @@ def self.find
type_check.source_files.each_key do |path|
type_check.typecheck_source(path: path) {}
end
service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.method_locations(MethodName("::Customer#foo"), locations: [], in_ruby: true, in_rbs: true).tap do |locs|
assert_equal 2, locs.size
Expand Down Expand Up @@ -493,7 +497,7 @@ class Customer
RBS
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.type_name_locations(TypeName("::Customer")).tap do |locs|
assert_equal 2, locs.size
Expand Down Expand Up @@ -554,7 +558,7 @@ def self.new: (Integer) -> Baz
RBS
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.definition(path: dir + "lib/test.rb", line: 1, column: 6).tap do |locs|
assert_any!(locs) do |loc|
Expand Down Expand Up @@ -612,7 +616,7 @@ def self.new(i)
RBS
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.implementation(path: dir + "lib/test.rb", line: 12, column: 6).tap do |locs|
assert_any!(locs, size: 1) do |loc|
Expand All @@ -639,12 +643,47 @@ def test_method_block
RBS
end

service = Services::GotoService.new(type_check: type_check)
service = Services::GotoService.new(type_check: type_check, assignment: assignment)

service.definition(path: dir + "lib/test.rb", line: 1, column: 4).tap do |locs|
assert_any!(locs, size: 1) do |loc|
assert_equal Pathname("array.rbs"), Pathname(loc.buffer.name).basename
end
end
end

def test_goto_definition_wrt_assignment
type_check = type_check_service do |changes|
changes[Pathname("sig/a.rbs")] = [ContentChange.string(<<RBS)]
class Customer
end
RBS
changes[Pathname("sig/b.rbs")] = [ContentChange.string(<<RBS)]
class Customer
end
RBS
changes[Pathname("lib/customer.rb")] = [ContentChange.string(<<RUBY)]
class Customer
end
RUBY
end

a = Services::PathAssignment.new(index: 0, max_index: 1)
a.cache[Pathname("sig/a.rbs")] = 0
a.cache[Pathname("sig/b.rbs")] = 1
Services::GotoService.new(type_check: type_check, assignment: a).tap do |service|
service.definition(path: dir + "lib/customer.rb", line: 1, column: 10).tap do |locs|
assert_equal [Pathname("sig/a.rbs")], locs.map(&:name)
end
end

b = Services::PathAssignment.new(index: 0, max_index: 1)
b.cache[Pathname("sig/a.rbs")] = 1
b.cache[Pathname("sig/b.rbs")] = 0
Services::GotoService.new(type_check: type_check, assignment: b).tap do |service|
service.definition(path: dir + "lib/customer.rb", line: 1, column: 10).tap do |locs|
assert_equal [Pathname("sig/b.rbs")], locs.map(&:name)
end
end
end
end
39 changes: 39 additions & 0 deletions test/interaction_worker_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,45 @@ class ::Foo[T] < ::Parent[T]
end
end

def test_handle_class_hover_strip_html_comment
in_tmpdir do
project = Project.new(steepfile_path: current_dir + "Steepfile")
Project::DSL.parse(project, <<EOF)
target :lib do
check "lib"
signature "sig"
end
EOF

worker = InteractionWorker.new(project: project, reader: worker_reader, writer: worker_writer)

worker.service.update(
changes: {
Pathname("sig/hello.rbs") => [ContentChange.string(<<RBS)]
# <!-- HTML comment here -->
# This is comment content
class Foo[T] end

type hello = Foo[String]
RBS
}
) {}

response = worker.process_hover(InteractionWorker::HoverJob.new(path: Pathname("sig/hello.rbs"), line: 5, column: 15))

response = response.attributes
expected_value = "
This is comment content


```rbs
class ::Foo[T]
```
"
assert_equal({ kind: "markdown", value: expected_value }, response[:contents])
end
end

def test_handle_hover_invalid
in_tmpdir do
project = Project.new(steepfile_path: current_dir + "Steepfile")
Expand Down