Skip to content

Commit

Permalink
Merge pull request #287 from soutaro/refactor-master
Browse files Browse the repository at this point in the history
UI improvement
  • Loading branch information
soutaro committed Dec 30, 2020
2 parents 951b54a + e6bc784 commit 14e9f12
Show file tree
Hide file tree
Showing 19 changed files with 1,013 additions and 208 deletions.
6 changes: 3 additions & 3 deletions bin/smoke_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
rb_files = []
expectations = []
allowed_paths = []

dir.children.each do |file|
if file.extname == ".rb"
buffer = ::Parser::Source::Buffer.new(file.to_s)
Expand Down Expand Up @@ -98,9 +98,9 @@
expectations.each do |expectation|
deleted = lines.reject! do |string|
if expectation.prefix_test
string =~ /\A#{Regexp.escape(expectation.path.to_s)}:#{expectation.line}:\d+: #{Regexp.quote expectation.message}/
string =~ /\A#{Regexp.escape(expectation.path.to_s)}:#{expectation.line}:\d+: \[.*?\] #{Regexp.quote expectation.message}/
else
string =~ /\A#{Regexp.escape(expectation.path.to_s)}:#{expectation.line}:\d+: #{Regexp.quote expectation.message} \(/
string =~ /\A#{Regexp.escape(expectation.path.to_s)}:#{expectation.line}:\d+: \[.*?\] #{Regexp.quote expectation.message} \(/
end
end

Expand Down
2 changes: 2 additions & 0 deletions lib/steep.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
require "steep/project/file_loader"
require "steep/project/hover_content"
require "steep/project/completion_provider"
require "steep/project/stats_calculator"
require "steep/drivers/utils/driver_helper"
require "steep/drivers/check"
require "steep/drivers/stats"
Expand All @@ -110,6 +111,7 @@
require "steep/drivers/init"
require "steep/drivers/vendor"
require "steep/drivers/worker"
require "steep/drivers/diagnostic_printer"

if ENV["NO_COLOR"]
Rainbow.enabled = false
Expand Down
2 changes: 1 addition & 1 deletion lib/steep/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def process_check
opts.banner = "Usage: steep check [options] [sources]"

opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
opts.on("--dump-all-types") { check.dump_all_types = true }
handle_logging_options opts
end.parse!(argv)

Expand Down Expand Up @@ -184,6 +183,7 @@ def process_worker
opts.on("--signature") { command.worker_type = :signature }
opts.on("--steepfile=PATH") {|path| command.steepfile = Pathname(path) }
opts.on("--name=NAME") {|name| command.worker_name = name }
opts.on("--delay-shutdown") { command.delay_shutdown = true }
end.parse!(argv)
end.run
end
Expand Down
130 changes: 70 additions & 60 deletions lib/steep/drivers/check.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@ class Check
attr_reader :stderr
attr_reader :command_line_patterns

attr_accessor :dump_all_types

include Utils::DriverHelper

def initialize(stdout:, stderr:)
@stdout = stdout
@stderr = stderr
@command_line_patterns = []

self.dump_all_types = false
end

def run
Expand All @@ -24,73 +20,87 @@ def run
loader.load_sources(command_line_patterns)
loader.load_signatures()

type_check(project)

if self.dump_all_types
project.targets.each do |target|
case (status = target.status)
when Project::Target::TypeCheckStatus
target.source_files.each_value do |file|
case (file_status = file.status)
when Project::SourceFile::TypeCheckStatus
output_types(file_status.typing)
end
end
end
end
stdout.puts Rainbow("# Type checking files:").bold
stdout.puts

client_read, server_write = IO.pipe
server_read, client_write = IO.pipe

client_reader = LanguageServer::Protocol::Transport::Io::Reader.new(client_read)
client_writer = LanguageServer::Protocol::Transport::Io::Writer.new(client_write)

server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)

interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, delay_shutdown: true)
signature_worker = Server::WorkerProcess.spawn_worker(:signature, name: "signature", steepfile: project.steepfile_path, delay_shutdown: true)
code_workers = Server::WorkerProcess.spawn_code_workers(steepfile: project.steepfile_path, delay_shutdown: true)

master = Server::Master.new(
project: project,
reader: server_reader,
writer: server_writer,
interaction_worker: interaction_worker,
signature_worker: signature_worker,
code_workers: code_workers
)

main_thread = Thread.start do
master.start()
end
main_thread.abort_on_exception = true

project.targets.each do |target|
Steep.logger.tagged "target=#{target.name}" do
case (status = target.status)
when Project::Target::SignatureSyntaxErrorStatus
printer = SignatureErrorPrinter.new(stdout: stdout, stderr: stderr)
printer.print_syntax_errors(status.errors)
when Project::Target::SignatureValidationErrorStatus
printer = SignatureErrorPrinter.new(stdout: stdout, stderr: stderr)
printer.print_semantic_errors(status.errors)
when Project::Target::TypeCheckStatus
status.type_check_sources.each do |source_file|
case source_file.status
when Project::SourceFile::TypeCheckStatus
source_file.errors.select {|error| target.options.error_to_report?(error) }.each do |error|
error.print_to stdout
end
when Project::SourceFile::TypeCheckErrorStatus
Steep.log_error source_file.status.error
end
end
when Project::Target::SignatureOtherErrorStatus
Steep.log_error status.error
client_writer.write({ method: :initialize, id: 0 })

shutdown_id = -1
client_writer.write({ method: :shutdown, id: shutdown_id })

responses = []
client_reader.read do |response|
case
when response[:method] == "textDocument/publishDiagnostics"
ds = response[:params][:diagnostics]
if ds.empty?
stdout.print "."
else
Steep.logger.error { "Unexpected status: #{status.class}" }
stdout.print "F"
end
responses << response[:params]
stdout.flush
when response[:id] == shutdown_id
break
end
end

if project.targets.all? {|target| target.status.is_a?(Project::Target::TypeCheckStatus) && target.no_error? && target.errors.empty? }
Steep.logger.info "No type error found"
return 0
end
client_writer.write({ method: :exit })
client_writer.io.close()

1
end
main_thread.join()

def output_types(typing)
lines = []
stdout.puts
stdout.puts

typing.each_typing do |node, _|
begin
type = typing.type_of(node: node)
lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, type]
rescue
lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, nil]
end
end
if responses.all? {|res| res[:diagnostics].empty? }
emoji = %w(🫖 🫖 🫖 🫖 🫖 🫖 🫖 🫖 🍵 🧋 🧉).sample
stdout.puts Rainbow("No type error detected. #{emoji}").green.bold
0
else
errors = responses.reject {|res| res[:diagnostics].empty? }
total = errors.sum {|res| res[:diagnostics].size }
stdout.puts Rainbow("Detected #{total} problems from #{errors.size} files").red.bold
stdout.puts

errors.each do |resp|
path = project.relative_path(Pathname(URI.parse(resp[:uri]).path))
buffer = RBS::Buffer.new(name: path, content: path.read)
printer = DiagnosticPrinter.new(buffer: buffer, stdout: stdout)

lines.sort {|x,y| y <=> x }.reverse_each do |line|
source = line[3].loc.expression.source
stdout.puts "#{line[0]}:(#{line[2].join(",")}):(#{line[1].join(",")}):\t#{line[3].type}:\t#{line[4]}\t(#{source.split(/\n/).first})"
resp[:diagnostics].each do |diag|
printer.print(diag)
stdout.puts
end
end
1
end
end
end
Expand Down
86 changes: 86 additions & 0 deletions lib/steep/drivers/diagnostic_printer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module Steep
module Drivers
class DiagnosticPrinter
LSP = LanguageServer::Protocol

attr_reader :stdout
attr_reader :buffer

def initialize(stdout:, buffer:)
@stdout = stdout
@buffer = buffer
end

def path
buffer.name
end

def color_severity(string, severity:)
s = Rainbow(string)

case severity
when LSP::Constant::DiagnosticSeverity::ERROR
s.red
when LSP::Constant::DiagnosticSeverity::WARNING
s.yellow
when LSP::Constant::DiagnosticSeverity::INFORMATION
s.blue
else
s
end
end

def severity_message(severity)
string = case severity
when LSP::Constant::DiagnosticSeverity::ERROR
"error"
when LSP::Constant::DiagnosticSeverity::WARNING
"warning"
when LSP::Constant::DiagnosticSeverity::INFORMATION
"information"
when LSP::Constant::DiagnosticSeverity::HINT
"hint"
end

color_severity(string, severity: severity)
end

def location(diagnostic)
start = diagnostic[:range][:start]
Rainbow("#{path}:#{start[:line]+1}:#{start[:character]}").magenta
end

def print(diagnostic)
header, *rest = diagnostic[:message].split(/\n/)

stdout.puts "#{location(diagnostic)}: [#{severity_message(diagnostic[:severity])}] #{Rainbow(header).underline}"

rest.each do |message|
stdout.puts "│ #{message}"
end
stdout.puts "│"

print_source_line(diagnostic)
end

def print_source_line(diagnostic)
start_pos = diagnostic[:range][:start]
end_pos = diagnostic[:range][:end]

line = buffer.lines[start_pos[:line]]

leading = line[0...start_pos[:character]]
if start_pos[:line] == end_pos[:line]
subject = line[start_pos[:character]...end_pos[:character]]
trailing = line[end_pos[:character]...].chomp
else
subject = line[start_pos[:character]...].chomp
trailing = ""
end

stdout.puts "└ #{leading}#{color_severity(subject, severity: diagnostic[:severity])}#{trailing}"
stdout.puts " #{" " * leading.size}#{"~" * subject.size}"
end
end
end
end
Loading

0 comments on commit 14e9f12

Please sign in to comment.