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

Let watch command support watching files #323

Merged
merged 1 commit into from
Mar 8, 2021
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
3 changes: 2 additions & 1 deletion lib/steep/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ def process_watch
handle_logging_options opts
end.parse!(argv)

command.dirs.push *argv
dirs = argv.map {|dir| Pathname(dir) }
command.dirs.push(*dirs)
end.run
end

Expand Down
70 changes: 40 additions & 30 deletions lib/steep/drivers/watch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def initialize(stdout:, stderr:)
@queue = Thread::Queue.new
end

def watching?(changed_path, files:, dirs:)
files.empty? || files.include?(changed_path) || dirs.intersect?(changed_path.ascend.to_set)
end

def run()
if dirs.empty?
stdout.puts "Specify directories to watch"
Expand All @@ -35,7 +39,7 @@ def run()
server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)

typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs, count: jobs_count)
typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), count: jobs_count)

master = Server::Master.new(
project: project,
Expand All @@ -53,45 +57,51 @@ def run()
client_writer.write(method: "initialize", id: 0)

Steep.logger.info "Watching #{dirs.join(", ")}..."
listener = Listen.to(*dirs.map(&:to_s)) do |modified, added, removed|

watch_paths = dirs.map do |dir|
case
when dir.directory?
dir.realpath
when dir.file?
dir.parent.realpath
else
dir
end
end

dir_paths = Set.new(dirs.select(&:directory?).map(&:realpath))
file_paths = Set.new(dirs.select(&:file?).map(&:realpath))

listener = Listen.to(*watch_paths.map(&:to_s)) do |modified, added, removed|
stdout.puts Rainbow("🔬 Type checking updated files...").bold

version = Time.now.to_i
Steep.logger.tagged "watch" do
Steep.logger.info "Received file system updates: modified=[#{modified.join(",")}], added=[#{added.join(",")}], removed=[#{removed.join(",")}]"

(modified + added).each do |path|
client_writer.write(
method: "textDocument/didChange",
params: {
textDocument: {
uri: "file://#{path}",
version: version
},
contentChanges: [
{
text: Pathname(path).read
}
]
}
)
p = Pathname(path)
if watching?(p, files: file_paths, dirs: dir_paths)
client_writer.write(
method: "textDocument/didChange",
params: {
textDocument: { uri: "file://#{path}", version: version },
contentChanges: [{ text: p.read }]
}
)
end
end

removed.each do |path|
client_writer.write(
method: "textDocument/didChange",
params: {
textDocument: {
uri: "file://#{path}",
version: version
},
contentChanges: [
{
text: ""
}
]
}
)
if watching?(p, files: file_paths, dirs: dir_paths)
client_writer.write(
method: "textDocument/didChange",
params: {
textDocument: { uri: "file://#{path}", version: version },
contentChanges: [{ text: "" }]
}
)
end
end
end
end.tap(&:start)
Expand Down
62 changes: 60 additions & 2 deletions test/cli_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,21 +280,79 @@ class Person
pid = spawn(*steep.push("watch", "app/lib"), out: w, chdir: current_dir.to_s)
w.close

output = []

begin
output = []
read_thread = Thread.new do
while line = r.gets
output << line
end
end

sleep 15
ensure
Process.kill(:INT, pid)
read_thread.join

Process.waitpid(pid)
assert_equal 0, $?.exitstatus
end

assert_includes output.join("\n"), "app/lib/foo.rb"
refute_includes output.join("\n"), "app/models/person.rb"
end
end

def test_watch_file
in_tmpdir do
(current_dir + "Steepfile").write(<<-EOF)
target :app do
check "app"
signature "sig"
end
EOF

(current_dir + "app").mkdir
(current_dir + "app/lib").mkdir
(current_dir + "app/models").mkdir
(current_dir + "sig").mkdir

(current_dir + "app/models/person.rb").write <<RUBY
class Person
end

"hello" + 3
RUBY


r, w = IO.pipe
pid = spawn(*steep.push("watch", "app/models/person.rb"), out: w, chdir: current_dir.to_s)
w.close

Thread.new do
output = []

begin
read_thread = Thread.new do
while line = r.gets
output << line
end
end

sleep 10

(current_dir + "app/models/group.rb").write <<RUBY
1+"2"
RUBY
sleep 5
ensure
Process.kill(:INT, pid)
read_thread.join
Process.waitpid(pid)
assert_equal 0, $?.exitstatus
end

assert_includes output.join("\n"), "app/models/person.rb"
refute_includes output.join("\n"), "app/models/group.rb"
end
end

Expand Down