make cell attrs bools instead of u1s

This commit is contained in:
Mitchell Hashimoto
2022-08-26 11:09:48 -07:00
parent 469515c02b
commit 65df657b4e
3 changed files with 61 additions and 53 deletions

View File

@ -428,7 +428,7 @@ fn addCursor(self: *Grid, term: Terminal) void {
GPUCellMode, GPUCellMode,
@enumToInt(self.cursor_style), @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(.{ self.cells.appendAssumeCapacity(.{
.mode = mode, .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 // In normal mode, background and fg match the cell. We
// un-optionalize the fg by defaulting to our fg color. // un-optionalize the fg by defaulting to our fg color.
.bg = cell.bg, .bg = cell.bg,
@ -508,14 +508,14 @@ pub fn updateCell(
}; };
// If we are a trailing spacer, we never render anything. // 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. // Calculate the amount of space we need in the cells list.
const needed = needed: { const needed = needed: {
var i: usize = 0; var i: usize = 0;
if (colors.bg != null) i += 1; if (colors.bg != null) i += 1;
if (!cell.empty()) i += 1; if (!cell.empty()) i += 1;
if (cell.attrs.underline == 1) i += 1; if (cell.attrs.underline) i += 1;
break :needed i; break :needed i;
}; };
if (self.cells.items.len + needed > self.cells.capacity) return false; 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 the cell has a background, we always draw it.
if (colors.bg) |rgb| { if (colors.bg) |rgb| {
var mode: GPUCellMode = .bg; 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(.{ self.cells.appendAssumeCapacity(.{
.mode = mode, .mode = mode,
@ -549,7 +549,7 @@ pub fn updateCell(
// If the cell is empty then we draw nothing in the box. // If the cell is empty then we draw nothing in the box.
if (!cell.empty()) { if (!cell.empty()) {
// Determine our glyph styling // Determine our glyph styling
const style: font.Style = if (cell.attrs.bold == 1) const style: font.Style = if (cell.attrs.bold)
.bold .bold
else else
.regular; .regular;
@ -562,7 +562,7 @@ pub fn updateCell(
const glyph = goa.glyph; const glyph = goa.glyph;
// If the cell is wide, we need to note that in the mode // 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(.{ self.cells.appendAssumeCapacity(.{
.mode = mode, .mode = mode,
@ -585,9 +585,9 @@ pub fn updateCell(
}); });
} }
if (cell.attrs.underline == 1) { if (cell.attrs.underline) {
var mode: GPUCellMode = .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(.{ self.cells.appendAssumeCapacity(.{
.mode = mode, .mode = mode,

View File

@ -64,25 +64,24 @@ pub const Cell = struct {
/// On/off attributes that can be set /// On/off attributes that can be set
attrs: packed struct { attrs: packed struct {
bold: u1 = 0, bold: bool = false,
underline: u1 = 0, faint: bool = false,
inverse: u1 = 0, underline: bool = false,
inverse: bool = false,
/// If 1, this line is soft-wrapped. Only the last cell in a row /// 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 /// should have this set. The first cell of the next row is actually
/// part of this row in raw input. /// part of this row in raw input.
wrap: u1 = 0, wrap: bool = false,
/// True if this is a wide character. This char takes up /// True if this is a wide character. This char takes up
/// two cells. The following cell ALWAYS is a space. /// 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 /// Notes that this only exists to be blank for a preceeding
/// wide character (tail) or following (head). /// wide character (tail) or following (head).
wide_spacer_tail: u1 = 0, wide_spacer_tail: bool = false,
wide_spacer_head: u1 = 0, wide_spacer_head: bool = false,
_padding: u1 = 0,
} = .{}, } = .{},
/// True if the cell should be skipped for drawing /// 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 no reflow, just keep going
if (row[row.len - 1].attrs.wrap == 0) { if (!row[row.len - 1].attrs.wrap) {
y += 1; y += 1;
continue; 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. // only reloop when we're back to clean non-wrapped lines.
// Mark the last element as not wrapped // 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 // We maintain an x coord so that we can set cursors properly
var x: usize = row.len; 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 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; y += 1;
// If we were able to copy the entire row then // 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! // 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..]; new_row = new_row[wrapped_rem.len..];
x += wrapped_rem.len; x += wrapped_rem.len;
break; 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 // The row doesn't fit, meaning we have to soft-wrap the
// new row but probably at a diff boundary. // new row but probably at a diff boundary.
std.mem.copy(Cell, new_row, wrapped_rem[0..new_row.len]); 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 // We still need to copy the remainder
wrapped_rem = wrapped_rem[new_row.len..]; 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 // Soft wrap if we have to
if (x == self.cols) { if (x == self.cols) {
var last_cell = self.getCell(y, x - 1); var last_cell = self.getCell(y, x - 1);
last_cell.attrs.wrap = 1; last_cell.attrs.wrap = true;
x = 0; x = 0;
y += 1; 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 }); // log.warn("y={} x={} rows={}", .{ y, x, self.rows });
var new_cell = self.getCell(y, x); var new_cell = self.getCell(y, x);
new_cell.* = cell; new_cell.* = cell;
new_cell.attrs.wrap = 0; new_cell.attrs.wrap = false;
// Next // Next
x += 1; 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 we aren't wrapping, then move to the next row
if (trimmed_row.len == 0 or 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; y += 1;
x = 0; x = 0;
@ -946,15 +945,15 @@ pub fn selectionString(self: Screen, alloc: Allocator, sel: Selection) ![:0]cons
// at a newline and we add it. // at a newline and we add it.
if (idx > 0 and if (idx > 0 and
@mod(idx + slices.top_offset, self.cols) == 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'; buf[i] = '\n';
i += 1; i += 1;
} }
// Skip spacers // Skip spacers
if (cell.attrs.wide_spacer_head == 1 or if (cell.attrs.wide_spacer_head or
cell.attrs.wide_spacer_tail == 1) continue; cell.attrs.wide_spacer_tail) continue;
const char = if (cell.char > 0) cell.char else ' '; const char = if (cell.char > 0) cell.char else ' ';
i += try std.unicode.utf8Encode(@intCast(u21, char), buf[i..]); 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 // a bit unique because if we're at idx 0, we actually need to
// check the end of the top. // check the end of the top.
const wrapped = if (idx > 0) const wrapped = if (idx > 0)
slices.bot[idx - 1].attrs.wrap == 1 slices.bot[idx - 1].attrs.wrap
else else
slices.top[slices.top.len - 1].attrs.wrap == 1; slices.top[slices.top.len - 1].attrs.wrap;
if (!wrapped) { if (!wrapped) {
buf[i] = '\n'; buf[i] = '\n';
@ -980,8 +979,8 @@ pub fn selectionString(self: Screen, alloc: Allocator, sel: Selection) ![:0]cons
} }
// Skip spacers // Skip spacers
if (cell.attrs.wide_spacer_head == 1 or if (cell.attrs.wide_spacer_head or
cell.attrs.wide_spacer_tail == 1) continue; cell.attrs.wide_spacer_tail) continue;
const char = if (cell.char > 0) cell.char else ' '; const char = if (cell.char > 0) cell.char else ' ';
i += try std.unicode.utf8Encode(@intCast(u21, char), buf[i..]); 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. // first part of the next line.
if (sel.end.x == self.cols - 1) { if (sel.end.x == self.cols - 1) {
const row = self.getRow(.{ .screen = sel.end.y }); 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.y += 1;
sel.end.x = 0; sel.end.x = 0;
} }
@ -1029,7 +1028,7 @@ fn selectionSlices(self: Screen, sel_raw: Selection) struct {
// wide char. // wide char.
if (sel.start.x > 0) { if (sel.start.x > 0) {
const row = self.getRow(.{ .screen = sel.start.y }); 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; 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 we're writing past the end, we need to soft wrap.
if (x == self.cols) { if (x == self.cols) {
row[x - 1].attrs.wrap = 1; row[x - 1].attrs.wrap = true;
y += 1; y += 1;
x = 0; x = 0;
if (y >= self.rows) { if (y >= self.rows) {
@ -1138,10 +1137,10 @@ fn testWriteString(self: *Screen, text: []const u8) void {
2 => { 2 => {
if (x == self.cols - 1) { if (x == self.cols - 1) {
row[x].char = ' '; row[x].char = ' ';
row[x].attrs.wide_spacer_head = 1; row[x].attrs.wide_spacer_head = true;
// wrap // wrap
row[x].attrs.wrap = 1; row[x].attrs.wrap = true;
y += 1; y += 1;
x = 0; x = 0;
if (y >= self.rows) { if (y >= self.rows) {
@ -1152,11 +1151,11 @@ fn testWriteString(self: *Screen, text: []const u8) void {
} }
row[x].char = @intCast(u32, c); row[x].char = @intCast(u32, c);
row[x].attrs.wide = 1; row[x].attrs.wide = true;
x += 1; x += 1;
row[x].char = ' '; row[x].char = ' ';
row[x].attrs.wide_spacer_tail = 1; row[x].attrs.wide_spacer_tail = true;
}, },
else => unreachable, else => unreachable,

View File

@ -59,12 +59,21 @@ scrolling_region: ScrollingRegion,
/// Modes - This isn't exhaustive, since some modes (i.e. cursor origin) /// Modes - This isn't exhaustive, since some modes (i.e. cursor origin)
/// are applied to the cursor and others aren't boolean yes/no. /// are applied to the cursor and others aren't boolean yes/no.
modes: packed struct { modes: packed struct {
const Self = @This();
reverse_colors: u1 = 0, // 5, reverse_colors: u1 = 0, // 5,
origin: u1 = 0, // 6 origin: u1 = 0, // 6
autowrap: u1 = 1, // 7 autowrap: u1 = 1, // 7
deccolm: u1 = 0, // 3, deccolm: u1 = 0, // 3,
deccolm_supported: u1 = 0, // 40 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 /// 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 => { .bold => {
self.screen.cursor.pen.attrs.bold = 1; self.screen.cursor.pen.attrs.bold = true;
}, },
.underline => { .underline => {
self.screen.cursor.pen.attrs.underline = 1; self.screen.cursor.pen.attrs.underline = true;
}, },
.inverse => { .inverse => {
self.screen.cursor.pen.attrs.inverse = 1; self.screen.cursor.pen.attrs.inverse = true;
}, },
.reset_inverse => { .reset_inverse => {
self.screen.cursor.pen.attrs.inverse = 0; self.screen.cursor.pen.attrs.inverse = false;
}, },
.direct_color_fg => |rgb| { .direct_color_fg => |rgb| {
@ -374,17 +383,17 @@ pub fn print(self: *Terminal, c: u21) !void {
// char as normal. // char as normal.
if (self.screen.cursor.x == self.cols - 1) { if (self.screen.cursor.x == self.cols - 1) {
const spacer_head = self.printCell(' '); const spacer_head = self.printCell(' ');
spacer_head.attrs.wide_spacer_head = 1; spacer_head.attrs.wide_spacer_head = true;
_ = self.printWrap(); _ = self.printWrap();
} }
const wide_cell = self.printCell(c); const wide_cell = self.printCell(c);
wide_cell.attrs.wide = 1; wide_cell.attrs.wide = true;
// Write our spacer // Write our spacer
self.screen.cursor.x += 1; self.screen.cursor.x += 1;
const spacer = self.printCell(' '); const spacer = self.printCell(' ');
spacer.attrs.wide_spacer_tail = 1; spacer.attrs.wide_spacer_tail = true;
}, },
else => unreachable, 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. // If this cell is wide char then we need to clear it.
// We ignore wide spacer HEADS because we can just write // We ignore wide spacer HEADS because we can just write
// single-width characters into that. // single-width characters into that.
if (cell.attrs.wide == 1) { if (cell.attrs.wide) {
const x = self.screen.cursor.x + 1; const x = self.screen.cursor.x + 1;
assert(x < self.cols); assert(x < self.cols);
const spacer_cell = self.screen.getCell(self.screen.cursor.y, x); 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) { if (self.screen.cursor.x <= 1) {
self.clearWideSpacerHead(); self.clearWideSpacerHead();
} }
} else if (cell.attrs.wide_spacer_tail == 1) { } else if (cell.attrs.wide_spacer_tail) {
assert(self.screen.cursor.x > 0); assert(self.screen.cursor.x > 0);
const x = self.screen.cursor.x - 1; const x = self.screen.cursor.x - 1;
const wide_cell = self.screen.getCell(self.screen.cursor.y, x); 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) { if (self.screen.cursor.x <= 1) {
self.clearWideSpacerHead(); self.clearWideSpacerHead();
@ -446,7 +455,7 @@ fn printWrap(self: *Terminal) *Screen.Cell {
self.screen.cursor.y, self.screen.cursor.y,
self.screen.cursor.x, self.screen.cursor.x,
); );
cell.attrs.wrap = 1; cell.attrs.wrap = true;
// Move to the next line // Move to the next line
self.index(); self.index();
@ -462,7 +471,7 @@ fn clearWideSpacerHead(self: *Terminal) void {
self.screen.cursor.y - 1, self.screen.cursor.y - 1,
self.cols - 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' /// Resets all margins and fills the whole screen with the character 'E'