Fix pager rendering slowness.
This commit is contained in:
+64
-3
@@ -38,6 +38,11 @@ watch: c_uint = 0,
|
|||||||
/// True once the child process has exited and the PTY hung up.
|
/// True once the child process has exited and the PTY hung up.
|
||||||
exited: bool = false,
|
exited: bool = false,
|
||||||
|
|
||||||
|
/// Cell size in pixels, as last set by a resize. Kept because the XTWINOPS
|
||||||
|
/// size queries report it and the answer has to come from somewhere; the
|
||||||
|
/// widget owns the real geometry and hands it down here.
|
||||||
|
cell_px: struct { w: u32 = 8, h: u32 = 16 } = .{},
|
||||||
|
|
||||||
/// Latest state reported by the child. Kept so a repeated report of the
|
/// Latest state reported by the child. Kept so a repeated report of the
|
||||||
/// state we are already in doesn't wake the UI for nothing.
|
/// state we are already in doesn't wake the UI for nothing.
|
||||||
status: Status = .idle,
|
status: Status = .idle,
|
||||||
@@ -139,13 +144,23 @@ pub fn create(
|
|||||||
errdefer self.stream.deinit();
|
errdefer self.stream.deinit();
|
||||||
|
|
||||||
// Wire up the side effects we care about. `readonly` handles terminal
|
// Wire up the side effects we care about. `readonly` handles terminal
|
||||||
// state but silently drops anything that needs to talk back to the
|
// state but silently drops anything that needs to talk back to the child.
|
||||||
// child; we need the writes so that queries (cursor position, device
|
//
|
||||||
// attributes, in-band resize) get answers.
|
// Every query below has to be answered, not merely permitted to write.
|
||||||
|
// `write_pty` is only the pipe; a query whose own effect is null is
|
||||||
|
// dropped before it ever reaches that pipe. And an unanswered query is
|
||||||
|
// not a missing feature, it is a stall: the standard way to test for a
|
||||||
|
// capability is to send the query followed by a device attributes
|
||||||
|
// request, and take the DA1 reply arriving alone as "unsupported".
|
||||||
|
// A terminal that answers neither leaves the program waiting out its
|
||||||
|
// own timeout, once per run, for every capability it probes.
|
||||||
var effects = vt.TerminalStream.Handler.Effects.readonly;
|
var effects = vt.TerminalStream.Handler.Effects.readonly;
|
||||||
effects.write_pty = &effectWritePty;
|
effects.write_pty = &effectWritePty;
|
||||||
effects.title_changed = &effectTitleChanged;
|
effects.title_changed = &effectTitleChanged;
|
||||||
effects.progress_report = &effectProgressReport;
|
effects.progress_report = &effectProgressReport;
|
||||||
|
effects.device_attributes = &effectDeviceAttributes;
|
||||||
|
effects.color_scheme = &effectColorScheme;
|
||||||
|
effects.size = &effectSize;
|
||||||
self.stream.handler.effects = effects;
|
self.stream.handler.effects = effects;
|
||||||
|
|
||||||
const shell = try defaultShell(alloc);
|
const shell = try defaultShell(alloc);
|
||||||
@@ -268,6 +283,48 @@ fn effectWritePty(handler: *vt.TerminalStream.Handler, data: [:0]const u8) void
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Effect callback: OSC 0/2 changed the window title.
|
/// Effect callback: OSC 0/2 changed the window title.
|
||||||
|
/// The reply type an effect has to return, recovered from the effect's own
|
||||||
|
/// signature. libghostty-vt exports the device attributes *request* enum by
|
||||||
|
/// name but not the reply struct, and naming it this way can't drift from
|
||||||
|
/// what the callback is actually required to return.
|
||||||
|
fn EffectReply(comptime name: []const u8) type {
|
||||||
|
const Opt = @FieldType(vt.TerminalStream.Handler.Effects, name);
|
||||||
|
const Fn = @typeInfo(@typeInfo(Opt).optional.child).pointer.child;
|
||||||
|
return @typeInfo(Fn).@"fn".return_type.?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Effect callback: the child asked what kind of terminal this is (CSI c and
|
||||||
|
/// friends). The defaults describe a VT220 that does ANSI colour, which is
|
||||||
|
/// what this actually is — the answer matters less than there being one.
|
||||||
|
fn effectDeviceAttributes(
|
||||||
|
_: *vt.TerminalStream.Handler,
|
||||||
|
) EffectReply("device_attributes") {
|
||||||
|
return .{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Effect callback: the child asked whether it is drawing on a light or dark
|
||||||
|
/// background (CSI ? 996 n), so it can pick readable colours. Answered from
|
||||||
|
/// the scheme the grid is actually painted in.
|
||||||
|
fn effectColorScheme(
|
||||||
|
_: *vt.TerminalStream.Handler,
|
||||||
|
) ?vt.device_status.ColorScheme {
|
||||||
|
return switch (theme.currentScheme()) {
|
||||||
|
.light => .light,
|
||||||
|
.dark => .dark,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Effect callback: the child asked for the terminal geometry (CSI 14/16/18 t).
|
||||||
|
fn effectSize(handler: *vt.TerminalStream.Handler) ?vt.size_report.Size {
|
||||||
|
const self = fromHandler(handler);
|
||||||
|
return .{
|
||||||
|
.rows = self.term.rows,
|
||||||
|
.columns = self.term.cols,
|
||||||
|
.cell_width = self.cell_px.w,
|
||||||
|
.cell_height = self.cell_px.h,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn effectTitleChanged(handler: *vt.TerminalStream.Handler) void {
|
fn effectTitleChanged(handler: *vt.TerminalStream.Handler) void {
|
||||||
const self = fromHandler(handler);
|
const self = fromHandler(handler);
|
||||||
self.on_title(self.ctx, self.term.title.items);
|
self.on_title(self.ctx, self.term.title.items);
|
||||||
@@ -320,6 +377,10 @@ pub fn write(self: *Session, bytes: []const u8) void {
|
|||||||
|
|
||||||
/// Resize the terminal grid and tell the child about it.
|
/// Resize the terminal grid and tell the child about it.
|
||||||
pub fn resize(self: *Session, cols: u16, rows: u16, cell_w: u32, cell_h: u32) !void {
|
pub fn resize(self: *Session, cols: u16, rows: u16, cell_w: u32, cell_h: u32) !void {
|
||||||
|
// Recorded before the early return: the grid can keep its dimensions
|
||||||
|
// across a font change that moves every pixel measurement.
|
||||||
|
self.cell_px = .{ .w = cell_w, .h = cell_h };
|
||||||
|
|
||||||
if (cols == self.term.cols and rows == self.term.rows) return;
|
if (cols == self.term.cols and rows == self.term.rows) return;
|
||||||
|
|
||||||
try self.stream.handler.resize(.{
|
try self.stream.handler.resize(.{
|
||||||
|
|||||||
Reference in New Issue
Block a user