Skip to content

Commit

Permalink
Send $/progress messages on build file parsing (#2141)
Browse files Browse the repository at this point in the history
  • Loading branch information
sphaerophoria authored Jan 17, 2025
1 parent ce11ba2 commit 80ac2bc
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
99 changes: 99 additions & 0 deletions src/DocumentStore.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const URI = @import("uri.zig");
const analysis = @import("analysis.zig");
const offsets = @import("offsets.zig");
const log = std.log.scoped(.store);
const lsp = @import("lsp");
const Ast = std.zig.Ast;
const BuildAssociatedConfig = @import("BuildAssociatedConfig.zig");
const BuildConfig = @import("build_runner/shared.zig").BuildConfig;
Expand All @@ -25,6 +26,9 @@ handles: std.StringArrayHashMapUnmanaged(*Handle) = .empty,
build_files: std.StringArrayHashMapUnmanaged(*BuildFile) = .empty,
cimports: std.AutoArrayHashMapUnmanaged(Hash, translate_c.Result) = .empty,
diagnostics_collection: *DiagnosticsCollection,
builds_in_progress: std.atomic.Value(i32) = .init(0),
transport: ?lsp.AnyTransport = null,
supports_work_done_progress: bool = false,

pub const Uri = []const u8;

Expand Down Expand Up @@ -833,9 +837,101 @@ pub fn invalidateBuildFile(self: *DocumentStore, build_file_uri: Uri) void {
};
}

const progress_token = "buildProgressToken";

fn sendMessageToClient(allocator: std.mem.Allocator, transport: lsp.AnyTransport, message: anytype) !void {
const serialized = try std.json.stringifyAlloc(
allocator,
message,
.{ .emit_null_optional_fields = false },
);
defer allocator.free(serialized);

try transport.writeJsonMessage(serialized);
}

fn notifyBuildStart(self: *DocumentStore) void {
if (!self.supports_work_done_progress) return;

// Atomicity note: We do not actually care about memory surrounding the
// counter, we only care about the counter itself. We only need to ensure
// we aren't double entering/exiting
const prev = self.builds_in_progress.fetchAdd(1, .monotonic);
if (prev != 0) return;

const transport = self.transport orelse return;

sendMessageToClient(
self.allocator,
transport,
.{
.jsonrpc = "2.0",
.id = "progress",
.method = "window/workDoneProgress/create",
.params = lsp.types.WorkDoneProgressCreateParams{
.token = .{ .string = progress_token },
},
},
) catch |err| {
log.err("Failed to send create work message: {}", .{err});
return;
};

sendMessageToClient(self.allocator, transport, .{
.jsonrpc = "2.0",
.method = "$/progress",
.params = .{
.token = progress_token,
.value = lsp.types.WorkDoneProgressBegin{
.title = "Loading build configuration",
},
},
}) catch |err| {
log.err("Failed to send progress start message: {}", .{err});
return;
};
}

const EndStatus = enum { success, failed };

fn notifyBuildEnd(self: *DocumentStore, status: EndStatus) void {
if (!self.supports_work_done_progress) return;

// Atomicity note: We do not actually care about memory surrounding the
// counter, we only care about the counter itself. We only need to ensure
// we aren't double entering/exiting
const prev = self.builds_in_progress.fetchSub(1, .monotonic);
if (prev != 1) return;

const transport = self.transport orelse return;

const message = switch (status) {
.failed => "Failed",
.success => "Success",
};

sendMessageToClient(self.allocator, transport, .{
.jsonrpc = "2.0",
.method = "$/progress",
.params = .{
.token = progress_token,
.value = lsp.types.WorkDoneProgressEnd{
.message = message,
},
},
}) catch |err| {
log.err("Failed to send progress end message: {}", .{err});
return;
};
}

fn invalidateBuildFileWorker(self: *DocumentStore, build_file_uri: Uri, is_build_file_uri_owned: bool) void {
defer if (is_build_file_uri_owned) self.allocator.free(build_file_uri);

var end_status: EndStatus = .failed;
self.notifyBuildStart();
defer self.notifyBuildEnd(end_status);

const build_config = loadBuildConfiguration(self, build_file_uri) catch |err| {
log.err("Failed to load build configuration for {s} (error: {})", .{ build_file_uri, err });
return;
Expand All @@ -846,6 +942,9 @@ fn invalidateBuildFileWorker(self: *DocumentStore, build_file_uri: Uri, is_build
return;
};
build_file.setBuildConfig(build_config);

// Looks like a useless assignment, but alters deffered onEnd
end_status = .success;
}

/// The `DocumentStore` represents a graph structure where every
Expand Down
7 changes: 7 additions & 0 deletions src/Server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,12 @@ fn initializeHandler(server: *Server, arena: std.mem.Allocator, request: types.I
}
}

if (request.capabilities.window) |window| {
if (window.workDoneProgress) |wdp| {
server.document_store.supports_work_done_progress = wdp;
}
}

if (request.capabilities.workspace) |workspace| {
server.client_capabilities.supports_apply_edits = workspace.applyEdit orelse false;
server.client_capabilities.supports_configuration = workspace.configuration orelse false;
Expand Down Expand Up @@ -1904,6 +1910,7 @@ pub fn destroy(server: *Server) void {
pub fn setTransport(server: *Server, transport: lsp.AnyTransport) void {
server.transport = transport;
server.diagnostics_collection.transport = transport;
server.document_store.transport = transport;
}

pub fn keepRunning(server: Server) bool {
Expand Down

0 comments on commit 80ac2bc

Please sign in to comment.