summaryrefslogtreecommitdiff
path: root/src/gui/gui.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/gui.zig')
-rw-r--r--src/gui/gui.zig27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 91380e46..11e9f53b 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -899,6 +899,9 @@ const Msg = union(enum) {
eof: struct { pane: u8, gen: u32, fd: c_int },
/// a language query finished on its own thread (see lspThread)
lsp: struct { id: u32, rows: []u8 },
+ /// a language SERVER changed state; narrated by the client's reader
+ /// threads through the status sink, lsp-allocator-owned
+ lsp_status: []u8,
/// a selection-filter worker finished; every stdout is gpa-owned
pipe: selection_pipe.Response,
/// something happened in a watched directory (see watchThread)
@@ -917,6 +920,7 @@ const Msg = union(enum) {
switch (m) {
.output => |o| gpa.free(o.bytes),
.lsp => |l| lsp_allocator.free(l.rows),
+ .lsp_status => |t| lsp_allocator.free(t),
.pipe => |response_value| {
var response = response_value;
response.deinit(gpa);
@@ -1120,6 +1124,15 @@ const Queue = struct {
}
};
+/// The registered `lsp.setStatusSink` target, called from the protocol
+/// client's reader threads: dupe with the concurrent lsp allocator, push to
+/// the mutex queue. A push after close is disposed by the queue itself.
+fn lspStatusSink(ctx: ?*anyopaque, text: []const u8) void {
+ const q: *Queue = @ptrCast(@alignCast(ctx orelse return));
+ const copy = q.lsp_allocator.dupe(u8, text) catch return;
+ q.push(.{ .lsp_status = copy });
+}
+
fn readPtyThread(gpa: std.mem.Allocator, fd: c_int, pane: u8, gen: u32, q: *Queue) void {
var buf: [0x10000]u8 = undefined;
while (true) {
@@ -2158,6 +2171,10 @@ fn localSession(
if (test_mode) setStdinRaw() catch {};
shell.threads_ok = true;
+ // Server state narration: reader threads → queue → drainQueue → the
+ // message row. Unset before the queue closes (see the defer above it).
+ pardes.lsp.setStatusSink(&queue, lspStatusSink);
+ defer pardes.lsp.setStatusSink(null, null);
// The core owns the loop. This owns the two things a pump cannot do from
// inside itself, because both replace the whole session and are only safe
@@ -2580,6 +2597,8 @@ fn runGrid(init: std.process.Init, opts_in: pardes.Options) !void {
while (core.nextEffect()) |e| core.perform(e);
for (&ptys, 0..) |*slot, id| if (slot.*) |pt| spawnReader(gpa, pt, @intCast(id), gens[id], &queue);
shell.threads_ok = true;
+ pardes.lsp.setStatusSink(&queue, lspStatusSink);
+ defer pardes.lsp.setStatusSink(null, null);
setStdinRaw() catch {}; // stdin may be a pipe, not a pty — best effort
@@ -3696,6 +3715,14 @@ const Shell = struct {
s.lsp_allocator.free(l.rows);
s.saw_event = true;
},
+ // Server state on the transient message row of the ACTIVE pane —
+ // session news, same row and same stamp a completed save uses.
+ .lsp_status => |text| {
+ var mbuf: [256]u8 = undefined;
+ s.core.setMessage(s.core.active, message.stamp(&mbuf, "lsp", text));
+ s.lsp_allocator.free(text);
+ s.saw_event = true;
+ },
.pipe => |response_value| {
var response = response_value;
s.core.update(.{ .pipe_resp = .{