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,
@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,

View File

@ -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,

View File

@ -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'