Skip to content

Commit

Permalink
Merge pull request #1218 from soutaro/typecheck-request
Browse files Browse the repository at this point in the history
Make type checking a LSP request, not a LSP notification
  • Loading branch information
soutaro committed Sep 13, 2024
2 parents 73ac84b + 7d97b6f commit 86c3487
Show file tree
Hide file tree
Showing 21 changed files with 349 additions and 135 deletions.
2 changes: 2 additions & 0 deletions lib/steep.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
require "yaml"
require "securerandom"
require "base64"
require "time"

require "concurrent/utility/processor_counter"
require "terminal-table"
Expand Down Expand Up @@ -114,6 +115,7 @@
require "steep/services/file_loader"
require "steep/services/goto_service"

require "steep/server/custom_methods"
require "steep/server/work_done_progress"
require "steep/server/delay_queue"
require "steep/server/lsp_formatter"
Expand Down
23 changes: 10 additions & 13 deletions lib/steep/drivers/check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,37 +66,34 @@ def run

request_guid = SecureRandom.uuid
Steep.logger.info { "Starting type checking: #{request_guid}" }
client_writer.write({ method: "$/typecheck", params: { guid: request_guid } })
client_writer.write(Server::CustomMethods::TypeCheck.request(request_guid, { guid: request_guid}))

diagnostic_notifications = [] #: Array[LanguageServer::Protocol::Interface::PublishDiagnosticsParams]
error_messages = [] #: Array[String]
client_reader.read do |response|

response = wait_for_response_id(reader: client_reader, id: request_guid) do |message|
case
when response[:method] == "textDocument/publishDiagnostics"
ds = response[:params][:diagnostics]
when message[:method] == "textDocument/publishDiagnostics"
ds = message[:params][:diagnostics]
ds.select! {|d| keep_diagnostic?(d, severity_level: severity_level) }
if ds.empty?
stdout.print "."
else
stdout.print "F"
end
diagnostic_notifications << response[:params]
diagnostic_notifications << message[:params]
stdout.flush
when response[:method] == "window/showMessage"
when message[:method] == "window/showMessage"
# Assuming ERROR message means unrecoverable error.
message = response[:params]
message = message[:params]
if message[:type] == LSP::Constant::MessageType::ERROR
error_messages << message[:message]
end
when response[:method] == "$/progress"
if response[:params][:token] == request_guid
if response[:params][:value][:kind] == "end"
break
end
end
end
end

Steep.logger.info { "Finished type checking: #{response.inspect}" }

Steep.logger.info { "Shutting down..." }

shutdown_exit(reader: client_reader, writer: client_writer)
Expand Down
8 changes: 2 additions & 6 deletions lib/steep/drivers/checkfile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,8 @@ def run
if message[:type] == LSP::Constant::MessageType::ERROR
error_messages << message[:message]
end
when response[:method] == "$/progress"
if response[:params][:token] == request_guid
if response[:params][:value][:kind] == "end"
break
end
end
when response[:id] == request_guid
break
end
end

Expand Down
20 changes: 8 additions & 12 deletions lib/steep/drivers/stats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def print(stats_result)
csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
stats_result.each do |row|
if row[:type] == "success"
# @type var row: Steep::Services::StatsCalculator::SuccessStats::json
csv << [
row[:target],
row[:path],
Expand All @@ -30,6 +31,7 @@ def print(stats_result)
end
]
else
# @type var row: Steep::Services::StatsCalculator::ErrorStats::json
csv << [
row[:target],
row[:path],
Expand Down Expand Up @@ -57,7 +59,8 @@ def print(stats_result)
rows = [] #: Array[Array[untyped]]
stats_result.sort_by {|row| row[:path] }.each do |row|
if row[:type] == "success"
rows << [
# @type var row: Steep::Services::StatsCalculator::SuccessStats::json
rows << [
row[:target],
row[:path] + " ",
row[:type],
Expand All @@ -71,6 +74,7 @@ def print(stats_result)
end
]
else
# @type var row: Steep::Services::StatsCalculator::ErrorStats::json
rows << [
row[:target],
row[:path],
Expand Down Expand Up @@ -161,24 +165,16 @@ def run
master.start_type_check(last_request: nil, progress: progress, include_unchanged: true, report_progress_threshold: 0)
end
wait_for_message(reader: client_reader) do |message|
message[:method] == "$/progress" &&
message[:params][:token] == typecheck_guid &&
message[:params][:value][:kind] == "end"
message[:id] == typecheck_guid
end

Steep.logger.info { "Finished type checking for stats" }

stats_id = request_id()
client_writer.write(
{
id: stats_id,
method: "workspace/executeCommand",
params: { command: "steep/stats", arguments: _ = [] }
}
)
client_writer.write(Server::CustomMethods::Stats.request(stats_id))

stats_response = wait_for_response_id(reader: client_reader, id: stats_id)
stats_result = stats_response[:result]
stats_result = stats_response[:result] #: Server::CustomMethods::Stats::result

shutdown_exit(reader: client_reader, writer: client_writer)
main_thread.join()
Expand Down
33 changes: 23 additions & 10 deletions lib/steep/drivers/utils/driver_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,28 @@ def request_id
SecureRandom.alphanumeric(10)
end

def wait_for_response_id(reader:, id:, unknown_responses: :ignore)
wait_for_message(reader: reader, unknown_messages: unknown_responses) do |response|
response[:id] == id
def wait_for_response_id(reader:, id:, unknown_responses: nil, &block)
reader.read do |message|
Steep.logger.debug { "Received message waiting for #{id}: #{message.inspect}" }

response_id = message[:id]

if response_id == id
return message
end

if block
yield message
else
case unknown_responses
when :ignore, nil
# nop
when :log
Steep.logger.error { "Unexpected message: #{message.inspect}" }
when :raise
raise "Unexpected message: #{message.inspect}"
end
end
end
end

Expand Down Expand Up @@ -84,13 +103,7 @@ def keep_diagnostic?(diagnostic, severity_level:)
end
end

(DEFAULT_CLI_LSP_INITIALIZE_PARAMS = {
capabilities: {
window: {
workDoneProgress: true
}
}
}).freeze
(DEFAULT_CLI_LSP_INITIALIZE_PARAMS = {}).freeze
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/steep/drivers/watch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,15 @@ def run()
end
end

client_writer.write(method: "$/typecheck", params: { guid: nil })
client_writer.write(Server::CustomMethods::TypeCheck.request(SecureRandom.uuid, { guid: nil }))

stdout.puts Rainbow("done!").bold
end.tap(&:start)

begin
stdout.puts Rainbow("👀 Watching directories, Ctrl-C to stop.").bold

client_writer.write(method: "$/typecheck", params: { guid: nil })
client_writer.write(Server::CustomMethods::TypeCheck.request(SecureRandom.uuid, { guid: nil }))

client_reader.read do |response|
case response[:method]
Expand Down
61 changes: 61 additions & 0 deletions lib/steep/server/custom_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
module Steep
module Server
module CustomMethods
module FileLoad
METHOD = "$/steep/file/load"

def self.notification(params)
{ method: METHOD, params: params }
end
end

module FileReset
METHOD = "$/steep/file/reset"

def self.notification(params)
{ method: METHOD, params: params }
end
end

module TypeCheck
METHOD = "$/steep/typecheck"

def self.request(id, params)
{ method: METHOD, id: id, params: params }
end

def self.response(id, result)
{ id: id, result: result }
end
end

module TypeCheck__Start
METHOD = "$/steep/typecheck/start"

def self.notification(params)
{ method: METHOD, params: params }
end
end

module TypeCheck__Progress
METHOD = "$/steep/typecheck/progress"

def self.notification(params)
{ method: METHOD, params: params }
end
end

module Stats
METHOD = "$/steep/stats"

def self.request(id)
{ method: METHOD, id: id, params: nil }
end

def self.response(id, result)
{ id: id, result: result }
end
end
end
end
end
9 changes: 8 additions & 1 deletion lib/steep/server/delay_queue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ def initialize(delay:)
end

if proc.equal?(last_task)
proc[]
unless @cancelled
proc[]
end
end
end
end
end

def cancel
@cancelled = true
queue.clear()
end

def execute(&block)
@last_task = block
scheduled_at = Time.now + delay
Expand Down
12 changes: 7 additions & 5 deletions lib/steep/server/interaction_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,16 @@ def handle_request(request)
collect_changes(request)
queue_job ApplyChangeJob.new

when "$/file/load"
input = request[:params][:content]
when CustomMethods::FileLoad::METHOD
params = request[:params] #: CustomMethods::FileLoad::params
input = params[:content]
load_files(input)
queue_job ApplyChangeJob.new

when "$/file/reset"
uri = request[:params][:uri]
text = request[:params][:content]
when CustomMethods::FileReset::METHOD
params = request[:params] #: CustomMethods::FileReset::params
uri = params[:uri]
text = params[:content]
reset_change(uri: uri, text: text)
queue_job ApplyChangeJob.new

Expand Down
Loading

0 comments on commit 86c3487

Please sign in to comment.