mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-22 11:46:11 +03:00
make cell attrs bools instead of u1s
This commit is contained in:
18
src/Grid.zig
18
src/Grid.zig
@ -428,7 +428,7 @@ fn addCursor(self: *Grid, term: Terminal) void {
|
||||
GPUCellMode,
|
||||
@enumToInt(self.cursor_style),
|
||||
);
|
||||
if (cell.attrs.wide == 1) mode = mode.mask(.wide_mask);
|
||||
if (cell.attrs.wide) mode = mode.mask(.wide_mask);
|
||||
|
||||
self.cells.appendAssumeCapacity(.{
|
||||
.mode = mode,
|
||||
@ -492,7 +492,7 @@ pub fn updateCell(
|
||||
}
|
||||
}
|
||||
|
||||
const res: BgFg = if (cell.attrs.inverse == 0) .{
|
||||
const res: BgFg = if (!cell.attrs.inverse) .{
|
||||
// In normal mode, background and fg match the cell. We
|
||||
// un-optionalize the fg by defaulting to our fg color.
|
||||
.bg = cell.bg,
|
||||
@ -508,14 +508,14 @@ pub fn updateCell(
|
||||
};
|
||||
|
||||
// If we are a trailing spacer, we never render anything.
|
||||
if (cell.attrs.wide_spacer_tail == 1) return true;
|
||||
if (cell.attrs.wide_spacer_tail) return true;
|
||||
|
||||
// Calculate the amount of space we need in the cells list.
|
||||
const needed = needed: {
|
||||
var i: usize = 0;
|
||||
if (colors.bg != null) i += 1;
|
||||
if (!cell.empty()) i += 1;
|
||||
if (cell.attrs.underline == 1) i += 1;
|
||||
if (cell.attrs.underline) i += 1;
|
||||
break :needed i;
|
||||
};
|
||||
if (self.cells.items.len + needed > self.cells.capacity) return false;
|
||||
@ -523,7 +523,7 @@ pub fn updateCell(
|
||||
// If the cell has a background, we always draw it.
|
||||
if (colors.bg) |rgb| {
|
||||
var mode: GPUCellMode = .bg;
|
||||
if (cell.attrs.wide == 1) mode = mode.mask(.wide_mask);
|
||||
if (cell.attrs.wide) mode = mode.mask(.wide_mask);
|
||||
|
||||
self.cells.appendAssumeCapacity(.{
|
||||
.mode = mode,
|
||||
@ -549,7 +549,7 @@ pub fn updateCell(
|
||||
// If the cell is empty then we draw nothing in the box.
|
||||
if (!cell.empty()) {
|
||||
// Determine our glyph styling
|
||||
const style: font.Style = if (cell.attrs.bold == 1)
|
||||
const style: font.Style = if (cell.attrs.bold)
|
||||
.bold
|
||||
else
|
||||
.regular;
|
||||
@ -562,7 +562,7 @@ pub fn updateCell(
|
||||
const glyph = goa.glyph;
|
||||
|
||||
// If the cell is wide, we need to note that in the mode
|
||||
if (cell.attrs.wide == 1) mode = mode.mask(.wide_mask);
|
||||
if (cell.attrs.wide) mode = mode.mask(.wide_mask);
|
||||
|
||||
self.cells.appendAssumeCapacity(.{
|
||||
.mode = mode,
|
||||
@ -585,9 +585,9 @@ pub fn updateCell(
|
||||
});
|
||||
}
|
||||
|
||||
if (cell.attrs.underline == 1) {
|
||||
if (cell.attrs.underline) {
|
||||
var mode: GPUCellMode = .underline;
|
||||
if (cell.attrs.wide == 1) mode = mode.mask(.wide_mask);
|
||||
if (cell.attrs.wide) mode = mode.mask(.wide_mask);
|
||||
|
||||
self.cells.appendAssumeCapacity(.{
|
||||
.mode = mode,
|
||||
|
@ -64,25 +64,24 @@ pub const Cell = struct {
|
||||
|
||||
/// On/off attributes that can be set
|
||||
attrs: packed struct {
|
||||
bold: u1 = 0,
|
||||
underline: u1 = 0,
|
||||
inverse: u1 = 0,
|
||||
bold: bool = false,
|
||||
faint: bool = false,
|
||||
underline: bool = false,
|
||||
inverse: bool = false,
|
||||
|
||||
/// If 1, this line is soft-wrapped. Only the last cell in a row
|
||||
/// should have this set. The first cell of the next row is actually
|
||||
/// part of this row in raw input.
|
||||
wrap: u1 = 0,
|
||||
wrap: bool = false,
|
||||
|
||||
/// True if this is a wide character. This char takes up
|
||||
/// two cells. The following cell ALWAYS is a space.
|
||||
wide: u1 = 0,
|
||||
wide: bool = false,
|
||||
|
||||
/// Notes that this only exists to be blank for a preceeding
|
||||
/// wide character (tail) or following (head).
|
||||
wide_spacer_tail: u1 = 0,
|
||||
wide_spacer_head: u1 = 0,
|
||||
|
||||
_padding: u1 = 0,
|
||||
wide_spacer_tail: bool = false,
|
||||
wide_spacer_head: bool = false,
|
||||
} = .{},
|
||||
|
||||
/// True if the cell should be skipped for drawing
|
||||
@ -573,7 +572,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
}
|
||||
|
||||
// If no reflow, just keep going
|
||||
if (row[row.len - 1].attrs.wrap == 0) {
|
||||
if (!row[row.len - 1].attrs.wrap) {
|
||||
y += 1;
|
||||
continue;
|
||||
}
|
||||
@ -583,7 +582,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
// only reloop when we're back to clean non-wrapped lines.
|
||||
|
||||
// Mark the last element as not wrapped
|
||||
new_row[row.len - 1].attrs.wrap = 0;
|
||||
new_row[row.len - 1].attrs.wrap = false;
|
||||
|
||||
// We maintain an x coord so that we can set cursors properly
|
||||
var x: usize = row.len;
|
||||
@ -611,7 +610,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
}
|
||||
|
||||
// If this row isn't also wrapped, we're done!
|
||||
if (wrapped_rem[wrapped_rem.len - 1].attrs.wrap == 0) {
|
||||
if (!wrapped_rem[wrapped_rem.len - 1].attrs.wrap) {
|
||||
y += 1;
|
||||
|
||||
// If we were able to copy the entire row then
|
||||
@ -628,7 +627,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
}
|
||||
|
||||
// Wrapped again!
|
||||
new_row[wrapped_rem.len - 1].attrs.wrap = 0;
|
||||
new_row[wrapped_rem.len - 1].attrs.wrap = false;
|
||||
new_row = new_row[wrapped_rem.len..];
|
||||
x += wrapped_rem.len;
|
||||
break;
|
||||
@ -637,7 +636,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
// The row doesn't fit, meaning we have to soft-wrap the
|
||||
// new row but probably at a diff boundary.
|
||||
std.mem.copy(Cell, new_row, wrapped_rem[0..new_row.len]);
|
||||
new_row[new_row.len - 1].attrs.wrap = 1;
|
||||
new_row[new_row.len - 1].attrs.wrap = true;
|
||||
|
||||
// We still need to copy the remainder
|
||||
wrapped_rem = wrapped_rem[new_row.len..];
|
||||
@ -799,7 +798,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
// Soft wrap if we have to
|
||||
if (x == self.cols) {
|
||||
var last_cell = self.getCell(y, x - 1);
|
||||
last_cell.attrs.wrap = 1;
|
||||
last_cell.attrs.wrap = true;
|
||||
x = 0;
|
||||
y += 1;
|
||||
}
|
||||
@ -823,7 +822,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
// log.warn("y={} x={} rows={}", .{ y, x, self.rows });
|
||||
var new_cell = self.getCell(y, x);
|
||||
new_cell.* = cell;
|
||||
new_cell.attrs.wrap = 0;
|
||||
new_cell.attrs.wrap = false;
|
||||
|
||||
// Next
|
||||
x += 1;
|
||||
@ -843,7 +842,7 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
||||
|
||||
// If we aren't wrapping, then move to the next row
|
||||
if (trimmed_row.len == 0 or
|
||||
trimmed_row[trimmed_row.len - 1].attrs.wrap == 0)
|
||||
!trimmed_row[trimmed_row.len - 1].attrs.wrap)
|
||||
{
|
||||
y += 1;
|
||||
x = 0;
|
||||
@ -946,15 +945,15 @@ pub fn selectionString(self: Screen, alloc: Allocator, sel: Selection) ![:0]cons
|
||||
// at a newline and we add it.
|
||||
if (idx > 0 and
|
||||
@mod(idx + slices.top_offset, self.cols) == 0 and
|
||||
slices.top[idx - 1].attrs.wrap == 0)
|
||||
!slices.top[idx - 1].attrs.wrap)
|
||||
{
|
||||
buf[i] = '\n';
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Skip spacers
|
||||
if (cell.attrs.wide_spacer_head == 1 or
|
||||
cell.attrs.wide_spacer_tail == 1) continue;
|
||||
if (cell.attrs.wide_spacer_head or
|
||||
cell.attrs.wide_spacer_tail) continue;
|
||||
|
||||
const char = if (cell.char > 0) cell.char else ' ';
|
||||
i += try std.unicode.utf8Encode(@intCast(u21, char), buf[i..]);
|
||||
@ -969,9 +968,9 @@ pub fn selectionString(self: Screen, alloc: Allocator, sel: Selection) ![:0]cons
|
||||
// a bit unique because if we're at idx 0, we actually need to
|
||||
// check the end of the top.
|
||||
const wrapped = if (idx > 0)
|
||||
slices.bot[idx - 1].attrs.wrap == 1
|
||||
slices.bot[idx - 1].attrs.wrap
|
||||
else
|
||||
slices.top[slices.top.len - 1].attrs.wrap == 1;
|
||||
slices.top[slices.top.len - 1].attrs.wrap;
|
||||
|
||||
if (!wrapped) {
|
||||
buf[i] = '\n';
|
||||
@ -980,8 +979,8 @@ pub fn selectionString(self: Screen, alloc: Allocator, sel: Selection) ![:0]cons
|
||||
}
|
||||
|
||||
// Skip spacers
|
||||
if (cell.attrs.wide_spacer_head == 1 or
|
||||
cell.attrs.wide_spacer_tail == 1) continue;
|
||||
if (cell.attrs.wide_spacer_head or
|
||||
cell.attrs.wide_spacer_tail) continue;
|
||||
|
||||
const char = if (cell.char > 0) cell.char else ' ';
|
||||
i += try std.unicode.utf8Encode(@intCast(u21, char), buf[i..]);
|
||||
@ -1019,7 +1018,7 @@ fn selectionSlices(self: Screen, sel_raw: Selection) struct {
|
||||
// first part of the next line.
|
||||
if (sel.end.x == self.cols - 1) {
|
||||
const row = self.getRow(.{ .screen = sel.end.y });
|
||||
if (row[sel.end.x].attrs.wide_spacer_head == 1) {
|
||||
if (row[sel.end.x].attrs.wide_spacer_head) {
|
||||
sel.end.y += 1;
|
||||
sel.end.x = 0;
|
||||
}
|
||||
@ -1029,7 +1028,7 @@ fn selectionSlices(self: Screen, sel_raw: Selection) struct {
|
||||
// wide char.
|
||||
if (sel.start.x > 0) {
|
||||
const row = self.getRow(.{ .screen = sel.start.y });
|
||||
if (row[sel.start.x].attrs.wide_spacer_tail == 1) {
|
||||
if (row[sel.start.x].attrs.wide_spacer_tail) {
|
||||
sel.end.x -= 1;
|
||||
}
|
||||
}
|
||||
@ -1119,7 +1118,7 @@ fn testWriteString(self: *Screen, text: []const u8) void {
|
||||
|
||||
// If we're writing past the end, we need to soft wrap.
|
||||
if (x == self.cols) {
|
||||
row[x - 1].attrs.wrap = 1;
|
||||
row[x - 1].attrs.wrap = true;
|
||||
y += 1;
|
||||
x = 0;
|
||||
if (y >= self.rows) {
|
||||
@ -1138,10 +1137,10 @@ fn testWriteString(self: *Screen, text: []const u8) void {
|
||||
2 => {
|
||||
if (x == self.cols - 1) {
|
||||
row[x].char = ' ';
|
||||
row[x].attrs.wide_spacer_head = 1;
|
||||
row[x].attrs.wide_spacer_head = true;
|
||||
|
||||
// wrap
|
||||
row[x].attrs.wrap = 1;
|
||||
row[x].attrs.wrap = true;
|
||||
y += 1;
|
||||
x = 0;
|
||||
if (y >= self.rows) {
|
||||
@ -1152,11 +1151,11 @@ fn testWriteString(self: *Screen, text: []const u8) void {
|
||||
}
|
||||
|
||||
row[x].char = @intCast(u32, c);
|
||||
row[x].attrs.wide = 1;
|
||||
row[x].attrs.wide = true;
|
||||
|
||||
x += 1;
|
||||
row[x].char = ' ';
|
||||
row[x].attrs.wide_spacer_tail = 1;
|
||||
row[x].attrs.wide_spacer_tail = true;
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
|
@ -59,12 +59,21 @@ scrolling_region: ScrollingRegion,
|
||||
/// Modes - This isn't exhaustive, since some modes (i.e. cursor origin)
|
||||
/// are applied to the cursor and others aren't boolean yes/no.
|
||||
modes: packed struct {
|
||||
const Self = @This();
|
||||
|
||||
reverse_colors: u1 = 0, // 5,
|
||||
origin: u1 = 0, // 6
|
||||
autowrap: u1 = 1, // 7
|
||||
|
||||
deccolm: u1 = 0, // 3,
|
||||
deccolm_supported: u1 = 0, // 40
|
||||
|
||||
test {
|
||||
// We have this here so that we explicitly fail when we change the
|
||||
// size of modes. The size of modes is NOT particularly important,
|
||||
// we just want to be mentally aware when it happens.
|
||||
try std.testing.expectEqual(1, @sizeOf(Self));
|
||||
}
|
||||
} = .{},
|
||||
|
||||
/// Scrolling region is the area of the screen designated where scrolling
|
||||
@ -289,19 +298,19 @@ pub fn setAttribute(self: *Terminal, attr: sgr.Attribute) !void {
|
||||
},
|
||||
|
||||
.bold => {
|
||||
self.screen.cursor.pen.attrs.bold = 1;
|
||||
self.screen.cursor.pen.attrs.bold = true;
|
||||
},
|
||||
|
||||
.underline => {
|
||||
self.screen.cursor.pen.attrs.underline = 1;
|
||||
self.screen.cursor.pen.attrs.underline = true;
|
||||
},
|
||||
|
||||
.inverse => {
|
||||
self.screen.cursor.pen.attrs.inverse = 1;
|
||||
self.screen.cursor.pen.attrs.inverse = true;
|
||||
},
|
||||
|
||||
.reset_inverse => {
|
||||
self.screen.cursor.pen.attrs.inverse = 0;
|
||||
self.screen.cursor.pen.attrs.inverse = false;
|
||||
},
|
||||
|
||||
.direct_color_fg => |rgb| {
|
||||
@ -374,17 +383,17 @@ pub fn print(self: *Terminal, c: u21) !void {
|
||||
// char as normal.
|
||||
if (self.screen.cursor.x == self.cols - 1) {
|
||||
const spacer_head = self.printCell(' ');
|
||||
spacer_head.attrs.wide_spacer_head = 1;
|
||||
spacer_head.attrs.wide_spacer_head = true;
|
||||
_ = self.printWrap();
|
||||
}
|
||||
|
||||
const wide_cell = self.printCell(c);
|
||||
wide_cell.attrs.wide = 1;
|
||||
wide_cell.attrs.wide = true;
|
||||
|
||||
// Write our spacer
|
||||
self.screen.cursor.x += 1;
|
||||
const spacer = self.printCell(' ');
|
||||
spacer.attrs.wide_spacer_tail = 1;
|
||||
spacer.attrs.wide_spacer_tail = true;
|
||||
},
|
||||
|
||||
else => unreachable,
|
||||
@ -411,22 +420,22 @@ fn printCell(self: *Terminal, c: u21) *Screen.Cell {
|
||||
// If this cell is wide char then we need to clear it.
|
||||
// We ignore wide spacer HEADS because we can just write
|
||||
// single-width characters into that.
|
||||
if (cell.attrs.wide == 1) {
|
||||
if (cell.attrs.wide) {
|
||||
const x = self.screen.cursor.x + 1;
|
||||
assert(x < self.cols);
|
||||
|
||||
const spacer_cell = self.screen.getCell(self.screen.cursor.y, x);
|
||||
spacer_cell.attrs.wide_spacer_tail = 0;
|
||||
spacer_cell.attrs.wide_spacer_tail = false;
|
||||
|
||||
if (self.screen.cursor.x <= 1) {
|
||||
self.clearWideSpacerHead();
|
||||
}
|
||||
} else if (cell.attrs.wide_spacer_tail == 1) {
|
||||
} else if (cell.attrs.wide_spacer_tail) {
|
||||
assert(self.screen.cursor.x > 0);
|
||||
const x = self.screen.cursor.x - 1;
|
||||
|
||||
const wide_cell = self.screen.getCell(self.screen.cursor.y, x);
|
||||
wide_cell.attrs.wide = 0;
|
||||
wide_cell.attrs.wide = false;
|
||||
|
||||
if (self.screen.cursor.x <= 1) {
|
||||
self.clearWideSpacerHead();
|
||||
@ -446,7 +455,7 @@ fn printWrap(self: *Terminal) *Screen.Cell {
|
||||
self.screen.cursor.y,
|
||||
self.screen.cursor.x,
|
||||
);
|
||||
cell.attrs.wrap = 1;
|
||||
cell.attrs.wrap = true;
|
||||
|
||||
// Move to the next line
|
||||
self.index();
|
||||
@ -462,7 +471,7 @@ fn clearWideSpacerHead(self: *Terminal) void {
|
||||
self.screen.cursor.y - 1,
|
||||
self.cols - 1,
|
||||
);
|
||||
cell.attrs.wide_spacer_head = 0;
|
||||
cell.attrs.wide_spacer_head = false;
|
||||
}
|
||||
|
||||
/// Resets all margins and fills the whole screen with the character 'E'
|
||||
|
Reference in New Issue
Block a user