feat(tasks): stream task output to buffer in the background
This commit is contained in:
parent
649d369a56
commit
a28f1db4c7
2 changed files with 59 additions and 21 deletions
|
@ -13,10 +13,11 @@ pub const Writer = std.io.Writer(*Self, Error, write);
|
|||
pub const BufferedWriter = std.io.BufferedWriter(max_chunk_size, Writer);
|
||||
pub const Error = error{ InvalidShellArg0, OutOfMemory, Exit, ThespianSpawnFailed, Closed };
|
||||
|
||||
pub const OutputHandler = fn (parent: tp.pid_ref, arg0: []const u8, output: []const u8) void;
|
||||
pub const ExitHandler = fn (parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void;
|
||||
pub const OutputHandler = fn (context: usize, parent: tp.pid_ref, arg0: []const u8, output: []const u8) void;
|
||||
pub const ExitHandler = fn (context: usize, parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void;
|
||||
|
||||
pub const Handlers = struct {
|
||||
context: usize = 0,
|
||||
out: *const OutputHandler,
|
||||
err: ?*const OutputHandler = null,
|
||||
exit: *const ExitHandler = log_exit_handler,
|
||||
|
@ -74,7 +75,8 @@ pub fn bufferedWriter(self: *Self) BufferedWriter {
|
|||
return .{ .unbuffered_writer = self.writer() };
|
||||
}
|
||||
|
||||
pub fn log_handler(parent: tp.pid_ref, arg0: []const u8, output: []const u8) void {
|
||||
pub fn log_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, output: []const u8) void {
|
||||
_ = context;
|
||||
_ = parent;
|
||||
_ = arg0;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
|
@ -82,14 +84,16 @@ pub fn log_handler(parent: tp.pid_ref, arg0: []const u8, output: []const u8) voi
|
|||
while (it.next()) |line| if (line.len > 0) logger.print("{s}", .{line});
|
||||
}
|
||||
|
||||
pub fn log_err_handler(parent: tp.pid_ref, arg0: []const u8, output: []const u8) void {
|
||||
pub fn log_err_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, output: []const u8) void {
|
||||
_ = context;
|
||||
_ = parent;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
var it = std.mem.splitScalar(u8, output, '\n');
|
||||
while (it.next()) |line| logger.print_err(arg0, "{s}", .{line});
|
||||
}
|
||||
|
||||
pub fn log_exit_handler(parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void {
|
||||
pub fn log_exit_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void {
|
||||
_ = context;
|
||||
_ = parent;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
if (exit_code > 0) {
|
||||
|
@ -99,7 +103,8 @@ pub fn log_exit_handler(parent: tp.pid_ref, arg0: []const u8, err_msg: []const u
|
|||
}
|
||||
}
|
||||
|
||||
pub fn log_exit_err_handler(parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void {
|
||||
pub fn log_exit_err_handler(context: usize, parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void {
|
||||
_ = context;
|
||||
_ = parent;
|
||||
const logger = log.logger(@typeName(Self));
|
||||
if (exit_code > 0) {
|
||||
|
@ -178,9 +183,9 @@ const Process = struct {
|
|||
} else if (try m.match(.{"close"})) {
|
||||
try self.close();
|
||||
} else if (try m.match(.{ module_name, "stdout", tp.extract(&bytes) })) {
|
||||
self.handlers.out(self.parent.ref(), self.arg0, bytes);
|
||||
self.handlers.out(self.handlers.context, self.parent.ref(), self.arg0, bytes);
|
||||
} else if (try m.match(.{ module_name, "stderr", tp.extract(&bytes) })) {
|
||||
(self.handlers.err orelse self.handlers.out)(self.parent.ref(), self.arg0, bytes);
|
||||
(self.handlers.err orelse self.handlers.out)(self.handlers.context, self.parent.ref(), self.arg0, bytes);
|
||||
} else if (try m.match(.{ module_name, "term", tp.more })) {
|
||||
self.handle_terminated(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
} else if (try m.match(.{ "exit", "normal" })) {
|
||||
|
@ -195,11 +200,11 @@ const Process = struct {
|
|||
var err_msg: []const u8 = undefined;
|
||||
var exit_code: i64 = undefined;
|
||||
if (try m.match(.{ tp.any, tp.any, "exited", 0 })) {
|
||||
self.handlers.exit(self.parent.ref(), self.arg0, "exited", 0);
|
||||
self.handlers.exit(self.handlers.context, self.parent.ref(), self.arg0, "exited", 0);
|
||||
} else if (try m.match(.{ tp.any, tp.any, "error.FileNotFound", 1 })) {
|
||||
self.logger.print_err(self.arg0, "'{s}' executable not found", .{self.arg0});
|
||||
} else if (try m.match(.{ tp.any, tp.any, tp.extract(&err_msg), tp.extract(&exit_code) })) {
|
||||
self.handlers.exit(self.parent.ref(), self.arg0, err_msg, exit_code);
|
||||
self.handlers.exit(self.handlers.context, self.parent.ref(), self.arg0, err_msg, exit_code);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ const build_options = @import("build_options");
|
|||
const Plane = @import("renderer").Plane;
|
||||
const input = @import("input");
|
||||
const command = @import("command");
|
||||
const BufferManager = @import("Buffer").Manager;
|
||||
const Buffer = @import("Buffer");
|
||||
|
||||
const tui = @import("tui.zig");
|
||||
const Box = @import("Box.zig");
|
||||
|
@ -48,7 +48,7 @@ active_view: ?usize = 0,
|
|||
panels: ?*WidgetList = null,
|
||||
last_match_text: ?[]const u8 = null,
|
||||
location_history: location_history,
|
||||
buffer_manager: BufferManager,
|
||||
buffer_manager: Buffer.Manager,
|
||||
find_in_files_state: enum { init, adding, done } = .done,
|
||||
file_list_type: FileListType = .find_in_files,
|
||||
panel_height: ?usize = null,
|
||||
|
@ -70,7 +70,7 @@ pub fn create(allocator: std.mem.Allocator) !Widget {
|
|||
.location_history = try location_history.create(),
|
||||
.views = undefined,
|
||||
.views_widget = undefined,
|
||||
.buffer_manager = BufferManager.init(allocator),
|
||||
.buffer_manager = Buffer.Manager.init(allocator),
|
||||
};
|
||||
try self.commands.init(self);
|
||||
const w = Widget.to(self);
|
||||
|
@ -287,7 +287,7 @@ const cmds = struct {
|
|||
if (self.file_list_type == .diagnostics and self.is_panel_view_showing(filelist_view))
|
||||
try self.toggle_panel_view(filelist_view, false);
|
||||
self.buffer_manager.deinit();
|
||||
self.buffer_manager = BufferManager.init(self.allocator);
|
||||
self.buffer_manager = Buffer.Manager.init(self.allocator);
|
||||
try project_manager.open(project_dir);
|
||||
const project = tp.env.get().str("project");
|
||||
tui.rdr().set_terminal_working_directory(project);
|
||||
|
@ -685,7 +685,7 @@ const cmds = struct {
|
|||
return error.InvalidShellArgument;
|
||||
const cmd = ctx.args;
|
||||
const handlers = struct {
|
||||
fn out(parent: tp.pid_ref, _: []const u8, output: []const u8) void {
|
||||
fn out(_: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
|
||||
var pos: usize = 0;
|
||||
var nl_count: usize = 0;
|
||||
while (std.mem.indexOfScalarPos(u8, output, pos, '\n')) |next| {
|
||||
|
@ -711,10 +711,10 @@ const cmds = struct {
|
|||
return error.InvalidShellArgument;
|
||||
const cmd = ctx.args;
|
||||
const handlers = struct {
|
||||
fn out(parent: tp.pid_ref, _: []const u8, output: []const u8) void {
|
||||
parent.send(.{ "cmd", "insert_chars", .{output} }) catch {};
|
||||
fn out(buffer_ref: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
|
||||
parent.send(.{ "cmd", "shell_execute_stream_output", .{ buffer_ref, output } }) catch {};
|
||||
}
|
||||
fn exit(parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void {
|
||||
fn exit(buffer_ref: usize, parent: tp.pid_ref, arg0: []const u8, err_msg: []const u8, exit_code: i64) void {
|
||||
var buf: [256]u8 = undefined;
|
||||
var stream = std.io.fixedBufferStream(&buf);
|
||||
const writer = stream.writer();
|
||||
|
@ -723,14 +723,47 @@ const cmds = struct {
|
|||
} else {
|
||||
writer.print("\n'{s}' exited\n", .{arg0}) catch {};
|
||||
}
|
||||
parent.send(.{ "cmd", "move_buffer_end", .{} }) catch {};
|
||||
parent.send(.{ "cmd", "insert_chars", .{stream.getWritten()} }) catch {};
|
||||
parent.send(.{ "cmd", "shell_execute_stream_output", .{ buffer_ref, stream.getWritten() } }) catch {};
|
||||
parent.send(.{ "cmd", "shell_execute_stream_output_complete", .{buffer_ref} }) catch {};
|
||||
}
|
||||
};
|
||||
try shell.execute(self.allocator, cmd, .{ .out = handlers.out, .err = handlers.out, .exit = handlers.exit });
|
||||
const editor = self.get_active_editor() orelse return error.Stop;
|
||||
const buffer = editor.buffer orelse return error.Stop;
|
||||
const buffer_ref = self.buffer_manager.buffer_to_ref(buffer);
|
||||
try shell.execute(self.allocator, cmd, .{ .context = buffer_ref, .out = handlers.out, .err = handlers.out, .exit = handlers.exit });
|
||||
}
|
||||
pub const shell_execute_stream_meta = .{ .arguments = &.{.string} };
|
||||
|
||||
pub fn shell_execute_stream_output(self: *Self, ctx: Ctx) Result {
|
||||
var buffer_ref: usize = 0;
|
||||
var output: []const u8 = undefined;
|
||||
if (!try ctx.args.match(.{ tp.extract(&buffer_ref), tp.extract(&output) }))
|
||||
return error.InvalidShellOutputArgument;
|
||||
const buffer = self.buffer_manager.buffer_from_ref(buffer_ref) orelse return;
|
||||
if (self.get_active_editor()) |editor| if (editor.buffer) |eb| if (eb == buffer) {
|
||||
editor.move_buffer_end(.{}) catch {};
|
||||
editor.insert_chars(command.fmt(.{output})) catch {};
|
||||
return;
|
||||
};
|
||||
var cursor: Buffer.Cursor = .{};
|
||||
const metrics = self.plane.metrics(1);
|
||||
cursor.move_buffer_end(buffer.root, metrics);
|
||||
var root_ = buffer.root;
|
||||
_, _, root_ = try root_.insert_chars(cursor.row, cursor.col, output, self.allocator, metrics);
|
||||
buffer.store_undo(&[_]u8{}) catch {};
|
||||
buffer.update(root_);
|
||||
}
|
||||
pub const shell_execute_stream_output_meta = .{ .arguments = &.{ .integer, .string } };
|
||||
|
||||
pub fn shell_execute_stream_output_complete(self: *Self, ctx: Ctx) Result {
|
||||
var buffer_ref: usize = 0;
|
||||
if (!try ctx.args.match(.{tp.extract(&buffer_ref)}))
|
||||
return error.InvalidShellOutputCompleteArgument;
|
||||
// TODO
|
||||
_ = self;
|
||||
}
|
||||
pub const shell_execute_stream_output_complete_meta = .{ .arguments = &.{ .integer, .string } };
|
||||
|
||||
pub fn adjust_fontsize(_: *Self, ctx: Ctx) Result {
|
||||
var amount: f32 = undefined;
|
||||
if (!try ctx.args.match(.{tp.extract(&amount)}))
|
||||
|
|
Loading…
Add table
Reference in a new issue