mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-24 12:46:10 +03:00
process ASCII events manually to avoid function call overhead
This commit is contained in:
@ -1271,9 +1271,43 @@ fn ttyRead(t: *libuv.Tty, n: isize, buf: []const u8) void {
|
||||
// Schedule a render
|
||||
win.render_timer.schedule() catch unreachable;
|
||||
|
||||
// Process the terminal data
|
||||
win.terminal_stream.nextSlice(buf[0..@intCast(usize, n)]) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err});
|
||||
// Process the terminal data. This is an extremely hot part of the
|
||||
// terminal emulator, so we do some abstraction leakage to avoid
|
||||
// function calls and unnecessary logic.
|
||||
//
|
||||
// The ground state is the only state that we can see and print/execute
|
||||
// ASCII, so we only execute this hot path if we're already in the ground
|
||||
// state.
|
||||
//
|
||||
// Empirically, this alone improved throughput of large text output by ~20%.
|
||||
var i: usize = 0;
|
||||
const end = @intCast(usize, n);
|
||||
if (win.terminal_stream.parser.state == .ground) {
|
||||
for (buf[i..end]) |c| {
|
||||
switch (terminal.parse_table.table[c][@enumToInt(terminal.Parser.State.ground)].action) {
|
||||
// Print, call directly.
|
||||
.print => win.print(@intCast(u21, c)) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err}),
|
||||
|
||||
// C0 execute, let our stream handle this one but otherwise
|
||||
// continue since we're guaranteed to be back in ground.
|
||||
.execute => win.terminal_stream.next(c) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err}),
|
||||
|
||||
// Otherwise, break out and go the slow path until we're
|
||||
// back in ground.
|
||||
else => break,
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < end) {
|
||||
//log.warn("SLOW={}", .{end - i});
|
||||
win.terminal_stream.nextSlice(buf[i..end]) catch |err|
|
||||
log.err("error processing terminal data: {}", .{err});
|
||||
}
|
||||
}
|
||||
|
||||
fn ttyWrite(req: *libuv.WriteReq, status: i32) void {
|
||||
|
@ -6,6 +6,7 @@ const Parser = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const trace = @import("tracy").trace;
|
||||
const testing = std.testing;
|
||||
const table = @import("parse_table.zig").table;
|
||||
const osc = @import("osc.zig");
|
||||
@ -212,6 +213,9 @@ pub fn init() Parser {
|
||||
/// Up to 3 actions may need to be exected -- in order -- representing
|
||||
/// the state exit, transition, and entry actions.
|
||||
pub fn next(self: *Parser, c: u8) [3]?Action {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
// If we're processing UTF-8, we handle this manually.
|
||||
if (self.state == .utf8) {
|
||||
return .{ self.next_utf8(c), null, null };
|
||||
|
@ -22,6 +22,7 @@ const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const utf8proc = @import("utf8proc");
|
||||
const trace = @import("tracy").trace;
|
||||
const color = @import("color.zig");
|
||||
const point = @import("point.zig");
|
||||
const CircBuf = @import("circ_buf.zig").CircBuf;
|
||||
@ -432,6 +433,9 @@ pub fn rowIterator(self: *Screen, tag: RowIndexTag) RowIterator {
|
||||
/// Returns the row at the given index. This row is writable, although
|
||||
/// only the active area should probably be written to.
|
||||
pub fn getRow(self: *Screen, index: RowIndex) Row {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
// Get our offset into storage
|
||||
const offset = index.toScreen(self).screen * (self.cols + 1);
|
||||
|
||||
|
@ -464,7 +464,7 @@ pub fn print(self: *Terminal, c: u21) !void {
|
||||
|
||||
switch (width) {
|
||||
// Single cell is very easy: just write in the cell
|
||||
1 => _ = self.printCell(c),
|
||||
1 => _ = @call(.{ .modifier = .always_inline }, self.printCell, .{c}),
|
||||
|
||||
// Wide character requires a spacer. We print this by
|
||||
// using two cells: the first is flagged "wide" and has the
|
||||
@ -505,6 +505,9 @@ pub fn print(self: *Terminal, c: u21) !void {
|
||||
}
|
||||
|
||||
fn printCell(self: *Terminal, unmapped_c: u21) *Screen.Cell {
|
||||
// const tracy = trace(@src());
|
||||
// defer tracy.end();
|
||||
|
||||
const c = c: {
|
||||
// TODO: non-utf8 handling, gr
|
||||
|
||||
@ -558,6 +561,9 @@ fn printCell(self: *Terminal, unmapped_c: u21) *Screen.Cell {
|
||||
}
|
||||
|
||||
fn printWrap(self: *Terminal) !void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const row = self.screen.getRow(.{ .active = self.screen.cursor.y });
|
||||
row.setWrapped(true);
|
||||
|
||||
|
@ -7,6 +7,7 @@ const csi = @import("csi.zig");
|
||||
const sgr = @import("sgr.zig");
|
||||
pub const point = @import("point.zig");
|
||||
pub const color = @import("color.zig");
|
||||
pub const parse_table = @import("parse_table.zig");
|
||||
|
||||
pub const Charset = charsets.Charset;
|
||||
pub const CharsetSlot = charsets.Slots;
|
||||
|
Reference in New Issue
Block a user