mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 05:06:24 +03:00
terminal: make error sets more explicit, capture explicit errors
This commit is contained in:
@ -1758,6 +1758,8 @@ pub const AdjustCapacity = struct {
|
|||||||
string_bytes: ?usize = null,
|
string_bytes: ?usize = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const AdjustCapacityError = Allocator.Error || Page.CloneFromError;
|
||||||
|
|
||||||
/// Adjust the capcaity of the given page in the list. This should
|
/// Adjust the capcaity of the given page in the list. This should
|
||||||
/// be used in cases where OutOfMemory is returned by some operation
|
/// be used in cases where OutOfMemory is returned by some operation
|
||||||
/// i.e to increase style counts, grapheme counts, etc.
|
/// i.e to increase style counts, grapheme counts, etc.
|
||||||
@ -1778,25 +1780,31 @@ pub fn adjustCapacity(
|
|||||||
self: *PageList,
|
self: *PageList,
|
||||||
page: *List.Node,
|
page: *List.Node,
|
||||||
adjustment: AdjustCapacity,
|
adjustment: AdjustCapacity,
|
||||||
) !*List.Node {
|
) AdjustCapacityError!*List.Node {
|
||||||
// We always start with the base capacity of the existing page. This
|
// We always start with the base capacity of the existing page. This
|
||||||
// ensures we never shrink from what we need.
|
// ensures we never shrink from what we need.
|
||||||
var cap = page.data.capacity;
|
var cap = page.data.capacity;
|
||||||
|
|
||||||
|
// All ceilPowerOfTwo is unreachable because we're always same or less
|
||||||
|
// bit width so maxInt is always possible.
|
||||||
if (adjustment.styles) |v| {
|
if (adjustment.styles) |v| {
|
||||||
const aligned = try std.math.ceilPowerOfTwo(usize, v);
|
comptime assert(@bitSizeOf(@TypeOf(v)) <= @bitSizeOf(usize));
|
||||||
|
const aligned = std.math.ceilPowerOfTwo(usize, v) catch unreachable;
|
||||||
cap.styles = @max(cap.styles, aligned);
|
cap.styles = @max(cap.styles, aligned);
|
||||||
}
|
}
|
||||||
if (adjustment.grapheme_bytes) |v| {
|
if (adjustment.grapheme_bytes) |v| {
|
||||||
const aligned = try std.math.ceilPowerOfTwo(usize, v);
|
comptime assert(@bitSizeOf(@TypeOf(v)) <= @bitSizeOf(usize));
|
||||||
|
const aligned = std.math.ceilPowerOfTwo(usize, v) catch unreachable;
|
||||||
cap.grapheme_bytes = @max(cap.grapheme_bytes, aligned);
|
cap.grapheme_bytes = @max(cap.grapheme_bytes, aligned);
|
||||||
}
|
}
|
||||||
if (adjustment.hyperlink_bytes) |v| {
|
if (adjustment.hyperlink_bytes) |v| {
|
||||||
const aligned = try std.math.ceilPowerOfTwo(usize, v);
|
comptime assert(@bitSizeOf(@TypeOf(v)) <= @bitSizeOf(usize));
|
||||||
|
const aligned = std.math.ceilPowerOfTwo(usize, v) catch unreachable;
|
||||||
cap.hyperlink_bytes = @max(cap.hyperlink_bytes, aligned);
|
cap.hyperlink_bytes = @max(cap.hyperlink_bytes, aligned);
|
||||||
}
|
}
|
||||||
if (adjustment.string_bytes) |v| {
|
if (adjustment.string_bytes) |v| {
|
||||||
const aligned = try std.math.ceilPowerOfTwo(usize, v);
|
comptime assert(@bitSizeOf(@TypeOf(v)) <= @bitSizeOf(usize));
|
||||||
|
const aligned = std.math.ceilPowerOfTwo(usize, v) catch unreachable;
|
||||||
cap.string_bytes = @max(cap.string_bytes, aligned);
|
cap.string_bytes = @max(cap.string_bytes, aligned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1830,7 +1838,7 @@ pub fn adjustCapacity(
|
|||||||
fn createPage(
|
fn createPage(
|
||||||
self: *PageList,
|
self: *PageList,
|
||||||
cap: Capacity,
|
cap: Capacity,
|
||||||
) !*List.Node {
|
) Allocator.Error!*List.Node {
|
||||||
// log.debug("create page cap={}", .{cap});
|
// log.debug("create page cap={}", .{cap});
|
||||||
return try createPageExt(&self.pool, cap, &self.page_size);
|
return try createPageExt(&self.pool, cap, &self.page_size);
|
||||||
}
|
}
|
||||||
@ -1839,7 +1847,7 @@ fn createPageExt(
|
|||||||
pool: *MemoryPool,
|
pool: *MemoryPool,
|
||||||
cap: Capacity,
|
cap: Capacity,
|
||||||
total_size: ?*usize,
|
total_size: ?*usize,
|
||||||
) !*List.Node {
|
) Allocator.Error!*List.Node {
|
||||||
var page = try pool.nodes.create();
|
var page = try pool.nodes.create();
|
||||||
errdefer pool.nodes.destroy(page);
|
errdefer pool.nodes.destroy(page);
|
||||||
|
|
||||||
@ -2292,7 +2300,7 @@ pub fn pin(self: *const PageList, pt: point.Point) ?Pin {
|
|||||||
/// automatically updated as the pagelist is modified. If the point the
|
/// automatically updated as the pagelist is modified. If the point the
|
||||||
/// pin points to is removed completely, the tracked pin will be updated
|
/// pin points to is removed completely, the tracked pin will be updated
|
||||||
/// to the top-left of the screen.
|
/// to the top-left of the screen.
|
||||||
pub fn trackPin(self: *PageList, p: Pin) !*Pin {
|
pub fn trackPin(self: *PageList, p: Pin) Allocator.Error!*Pin {
|
||||||
if (comptime std.debug.runtime_safety) assert(self.pinIsValid(p));
|
if (comptime std.debug.runtime_safety) assert(self.pinIsValid(p));
|
||||||
|
|
||||||
// Create our tracked pin
|
// Create our tracked pin
|
||||||
|
@ -437,7 +437,7 @@ pub fn adjustCapacity(
|
|||||||
self: *Screen,
|
self: *Screen,
|
||||||
page: *PageList.List.Node,
|
page: *PageList.List.Node,
|
||||||
adjustment: PageList.AdjustCapacity,
|
adjustment: PageList.AdjustCapacity,
|
||||||
) !*PageList.List.Node {
|
) PageList.AdjustCapacityError!*PageList.List.Node {
|
||||||
// If the page being modified isn't our cursor page then
|
// If the page being modified isn't our cursor page then
|
||||||
// this is a quick operation because we have no additional
|
// this is a quick operation because we have no additional
|
||||||
// accounting.
|
// accounting.
|
||||||
|
@ -1444,6 +1444,7 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
|||||||
const start_y = self.screen.cursor.y;
|
const start_y = self.screen.cursor.y;
|
||||||
defer {
|
defer {
|
||||||
self.screen.cursorAbsolute(self.scrolling_region.left, start_y);
|
self.screen.cursorAbsolute(self.scrolling_region.left, start_y);
|
||||||
|
|
||||||
// Always unset pending wrap
|
// Always unset pending wrap
|
||||||
self.screen.cursor.pending_wrap = false;
|
self.screen.cursor.pending_wrap = false;
|
||||||
}
|
}
|
||||||
@ -1464,8 +1465,15 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
|||||||
var cur_p = self.screen.pages.trackPin(
|
var cur_p = self.screen.pages.trackPin(
|
||||||
self.screen.cursor.page_pin.down(rem - 1).?,
|
self.screen.cursor.page_pin.down(rem - 1).?,
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
std.log.err("TODO: insertLines handle trackPin error err={}", .{err});
|
comptime assert(@TypeOf(err) == error{OutOfMemory});
|
||||||
@panic("TODO: insertLines handle trackPin error");
|
|
||||||
|
// This error scenario means that our GPA is OOM. This is not a
|
||||||
|
// situation we can gracefully handle. We can't just ignore insertLines
|
||||||
|
// because it'll result in a corrupted screen. Ideally in the future
|
||||||
|
// we flag the state as broken and show an error message to the user.
|
||||||
|
// For now, we panic.
|
||||||
|
log.err("insertLines trackPin error err={}", .{err});
|
||||||
|
@panic("insertLines trackPin OOM");
|
||||||
};
|
};
|
||||||
defer self.screen.pages.untrackPin(cur_p);
|
defer self.screen.pages.untrackPin(cur_p);
|
||||||
|
|
||||||
@ -1525,7 +1533,7 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
|||||||
|
|
||||||
// Increase style memory
|
// Increase style memory
|
||||||
error.StyleSetOutOfMemory,
|
error.StyleSetOutOfMemory,
|
||||||
=> .{.styles = cap.styles * 2 },
|
=> .{ .styles = cap.styles * 2 },
|
||||||
|
|
||||||
// Increase string memory
|
// Increase string memory
|
||||||
error.StringAllocOutOfMemory,
|
error.StringAllocOutOfMemory,
|
||||||
@ -1541,10 +1549,27 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
|||||||
error.GraphemeAllocOutOfMemory,
|
error.GraphemeAllocOutOfMemory,
|
||||||
=> .{ .grapheme_bytes = cap.grapheme_bytes * 2 },
|
=> .{ .grapheme_bytes = cap.grapheme_bytes * 2 },
|
||||||
},
|
},
|
||||||
) catch |e| {
|
) catch |e| switch (e) {
|
||||||
std.log.err("TODO: insertLines handle adjustCapacity error err={}", .{e});
|
// This shouldn't be possible because above we're only
|
||||||
@panic("TODO: insertLines handle adjustCapacity error");
|
// adjusting capacity _upwards_. So it should have all
|
||||||
|
// the existing capacity it had to fit the adjusted
|
||||||
|
// data. Panic since we don't expect this.
|
||||||
|
error.StyleSetOutOfMemory,
|
||||||
|
error.StyleSetNeedsRehash,
|
||||||
|
error.StringAllocOutOfMemory,
|
||||||
|
error.HyperlinkSetOutOfMemory,
|
||||||
|
error.HyperlinkSetNeedsRehash,
|
||||||
|
error.HyperlinkMapOutOfMemory,
|
||||||
|
error.GraphemeMapOutOfMemory,
|
||||||
|
error.GraphemeAllocOutOfMemory,
|
||||||
|
=> @panic("adjustCapacity resulted in capacity errors"),
|
||||||
|
|
||||||
|
// The system allocator is OOM. We can't currently do
|
||||||
|
// anything graceful here. We panic.
|
||||||
|
error.OutOfMemory,
|
||||||
|
=> @panic("adjustCapacity system allocator OOM"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Continue the loop to try handling this row again.
|
// Continue the loop to try handling this row again.
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@ -1643,8 +1668,10 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
|||||||
var cur_p = self.screen.pages.trackPin(
|
var cur_p = self.screen.pages.trackPin(
|
||||||
self.screen.cursor.page_pin.*,
|
self.screen.cursor.page_pin.*,
|
||||||
) catch |err| {
|
) catch |err| {
|
||||||
std.log.err("TODO: deleteLines handle trackPin error err={}", .{err});
|
// See insertLines
|
||||||
@panic("TODO: deleteLines handle trackPin error");
|
comptime assert(@TypeOf(err) == error{OutOfMemory});
|
||||||
|
log.err("deleteLines trackPin error err={}", .{err});
|
||||||
|
@panic("deleteLines trackPin OOM");
|
||||||
};
|
};
|
||||||
defer self.screen.pages.untrackPin(cur_p);
|
defer self.screen.pages.untrackPin(cur_p);
|
||||||
|
|
||||||
@ -1704,7 +1731,7 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
|||||||
|
|
||||||
// Increase style memory
|
// Increase style memory
|
||||||
error.StyleSetOutOfMemory,
|
error.StyleSetOutOfMemory,
|
||||||
=> .{.styles = cap.styles * 2 },
|
=> .{ .styles = cap.styles * 2 },
|
||||||
|
|
||||||
// Increase string memory
|
// Increase string memory
|
||||||
error.StringAllocOutOfMemory,
|
error.StringAllocOutOfMemory,
|
||||||
@ -1720,10 +1747,22 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
|||||||
error.GraphemeAllocOutOfMemory,
|
error.GraphemeAllocOutOfMemory,
|
||||||
=> .{ .grapheme_bytes = cap.grapheme_bytes * 2 },
|
=> .{ .grapheme_bytes = cap.grapheme_bytes * 2 },
|
||||||
},
|
},
|
||||||
) catch |e| {
|
) catch |e| switch (e) {
|
||||||
std.log.err("TODO: deleteLines handle adjustCapacity error err={}", .{e});
|
// See insertLines which has the same error capture.
|
||||||
@panic("TODO: deleteLines handle adjustCapacity error");
|
error.StyleSetOutOfMemory,
|
||||||
|
error.StyleSetNeedsRehash,
|
||||||
|
error.StringAllocOutOfMemory,
|
||||||
|
error.HyperlinkSetOutOfMemory,
|
||||||
|
error.HyperlinkSetNeedsRehash,
|
||||||
|
error.HyperlinkMapOutOfMemory,
|
||||||
|
error.GraphemeMapOutOfMemory,
|
||||||
|
error.GraphemeAllocOutOfMemory,
|
||||||
|
=> @panic("adjustCapacity resulted in capacity errors"),
|
||||||
|
|
||||||
|
error.OutOfMemory,
|
||||||
|
=> @panic("adjustCapacity system allocator OOM"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Continue the loop to try handling this row again.
|
// Continue the loop to try handling this row again.
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
@ -708,7 +708,7 @@ pub const Page = struct {
|
|||||||
const cells = dst_row.cells.ptr(self.memory)[x_start..x_end];
|
const cells = dst_row.cells.ptr(self.memory)[x_start..x_end];
|
||||||
|
|
||||||
// If our destination has styles or graphemes then we need to
|
// If our destination has styles or graphemes then we need to
|
||||||
// clear some state.
|
// clear some state. This will free up the managed memory as well.
|
||||||
if (dst_row.managedMemory()) self.clearCells(dst_row, x_start, x_end);
|
if (dst_row.managedMemory()) self.clearCells(dst_row, x_start, x_end);
|
||||||
|
|
||||||
// Copy all the row metadata but keep our cells offset
|
// Copy all the row metadata but keep our cells offset
|
||||||
@ -771,6 +771,8 @@ pub const Page = struct {
|
|||||||
// Copy the grapheme codepoints
|
// Copy the grapheme codepoints
|
||||||
const cps = other.lookupGrapheme(src_cell).?;
|
const cps = other.lookupGrapheme(src_cell).?;
|
||||||
|
|
||||||
|
// Safe to use setGraphemes because we cleared all
|
||||||
|
// managed memory for our destination cell range.
|
||||||
try self.setGraphemes(dst_row, dst_cell, cps);
|
try self.setGraphemes(dst_row, dst_cell, cps);
|
||||||
}
|
}
|
||||||
if (src_cell.hyperlink) hyperlink: {
|
if (src_cell.hyperlink) hyperlink: {
|
||||||
@ -801,10 +803,11 @@ pub const Page = struct {
|
|||||||
if (self.hyperlink_set.lookupContext(
|
if (self.hyperlink_set.lookupContext(
|
||||||
self.memory,
|
self.memory,
|
||||||
other_link.*,
|
other_link.*,
|
||||||
.{ .page = @constCast(other) },
|
|
||||||
// `lookupContext` uses the context for hashing, and
|
// `lookupContext` uses the context for hashing, and
|
||||||
// that doesn't write to the page, so this constCast
|
// that doesn't write to the page, so this constCast
|
||||||
// is completely safe.
|
// is completely safe.
|
||||||
|
.{ .page = @constCast(other) },
|
||||||
)) |i| {
|
)) |i| {
|
||||||
self.hyperlink_set.use(self.memory, i);
|
self.hyperlink_set.use(self.memory, i);
|
||||||
break :dst_id i;
|
break :dst_id i;
|
||||||
|
Reference in New Issue
Block a user