renderer: convert bg extend to new render state

pull/9662/head
Mitchell Hashimoto 2025-11-19 06:53:51 -10:00
parent 07115ce9a9
commit cc268694ed
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
3 changed files with 98 additions and 84 deletions

View File

@ -15,6 +15,7 @@ const cellpkg = @import("cell.zig");
const noMinContrast = cellpkg.noMinContrast;
const constraintWidth = cellpkg.constraintWidth;
const isCovering = cellpkg.isCovering;
const rowNeverExtendBg = @import("row.zig").neverExtendBg;
const imagepkg = @import("image.zig");
const Image = imagepkg.Image;
const ImageMap = imagepkg.ImageMap;
@ -2312,6 +2313,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
// Get our row data from our state
const row_data = state.row_data.slice();
const row_raws = row_data.items(.raw);
const row_cells = row_data.items(.cells);
const row_dirty = row_data.items(.dirty);
const row_selection = row_data.items(.selection);
@ -2326,10 +2328,11 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
);
for (
0..,
row_raws[0..row_len],
row_cells[0..row_len],
row_dirty[0..row_len],
row_selection[0..row_len],
) |y_usize, *cells, *dirty, selection| {
) |y_usize, row, *cells, *dirty, selection| {
const y: terminal.size.CellCountInt = @intCast(y_usize);
if (!rebuild) {
@ -2343,32 +2346,43 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
// Unmark the dirty state in our render state.
dirty.* = false;
// TODO: renderstate
// If our viewport is wider than our cell contents buffer,
// we still only process cells up to the width of the buffer.
const cells_slice = cells.slice();
const cells_len = @min(cells_slice.len, self.cells.size.columns);
const cells_raw = cells_slice.items(.raw);
const cells_style = cells_slice.items(.style);
// On primary screen, we still apply vertical padding
// extension under certain conditions we feel are safe.
//
// This helps make some scenarios look better while
// avoiding scenarios we know do NOT look good.
// switch (self.config.padding_color) {
// // These already have the correct values set above.
// .background, .@"extend-always" => {},
//
// // Apply heuristics for padding extension.
// .extend => if (y == 0) {
// self.uniforms.padding_extend.up = !row.neverExtendBg(
// color_palette,
// background,
// );
// } else if (y == self.cells.size.rows - 1) {
// self.uniforms.padding_extend.down = !row.neverExtendBg(
// color_palette,
// background,
// );
// },
// }
switch (self.config.padding_color) {
// These already have the correct values set above.
.background, .@"extend-always" => {},
// Apply heuristics for padding extension.
.extend => if (y == 0) {
self.uniforms.padding_extend.up = !rowNeverExtendBg(
row,
cells_raw,
cells_style,
&state.colors.palette,
state.colors.background,
);
} else if (y == self.cells.size.rows - 1) {
self.uniforms.padding_extend.down = !rowNeverExtendBg(
row,
cells_raw,
cells_style,
&state.colors.palette,
state.colors.background,
);
},
}
// Iterator of runs for shaping.
const cells_slice = cells.slice();
var run_iter_opts: font.shape.RunOptions = .{
.grid = self.font_grid,
.cells = cells_slice,
@ -2393,11 +2407,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
var shaper_cells: ?[]const font.shape.Cell = null;
var shaper_cells_i: usize = 0;
// If our viewport is wider than our cell contents buffer,
// we still only process cells up to the width of the buffer.
const cells_len = @min(cells_slice.len, self.cells.size.columns);
const cells_raw = cells_slice.items(.raw);
const cells_style = cells_slice.items(.style);
for (
0..,
cells_raw[0..cells_len],

64
src/renderer/row.zig Normal file
View File

@ -0,0 +1,64 @@
const std = @import("std");
const terminal = @import("../terminal/main.zig");
// TODO: Test neverExtendBg function
/// Returns true if the row of this pin should never have its background
/// color extended for filling padding space in the renderer. This is
/// a set of heuristics that help making our padding look better.
pub fn neverExtendBg(
row: terminal.page.Row,
cells: []const terminal.page.Cell,
styles: []const terminal.Style,
palette: *const terminal.color.Palette,
default_background: terminal.color.RGB,
) bool {
// Any semantic prompts should not have their background extended
// because prompts often contain special formatting (such as
// powerline) that looks bad when extended.
switch (row.semantic_prompt) {
.prompt, .prompt_continuation, .input => return true,
.unknown, .command => {},
}
for (0.., cells) |x, *cell| {
// If any cell has a default background color then we don't
// extend because the default background color probably looks
// good enough as an extension.
switch (cell.content_tag) {
// If it is a background color cell, we check the color.
.bg_color_palette, .bg_color_rgb => {
const s: terminal.Style = if (cell.hasStyling()) styles[x] else .{};
const bg = s.bg(cell, palette) orelse return true;
if (bg.eql(default_background)) return true;
},
// If its a codepoint cell we can check the style.
.codepoint, .codepoint_grapheme => {
// For codepoint containing, we also never extend bg
// if any cell has a powerline glyph because these are
// perfect-fit.
switch (cell.codepoint()) {
// Powerline
0xE0B0...0xE0C8,
0xE0CA,
0xE0CC...0xE0D2,
0xE0D4,
=> return true,
else => {},
}
// Never extend a cell that has a default background.
// A default background is applied if there is no background
// on the style or the explicitly set background
// matches our default background.
const s: terminal.Style = if (cell.hasStyling()) styles[x] else .{};
const bg = s.bg(cell, palette) orelse return true;
if (bg.eql(default_background)) return true;
},
}
}
return false;
}

View File

@ -3977,65 +3977,6 @@ pub const Pin = struct {
self.rowAndCell().row.dirty = true;
}
/// Returns true if the row of this pin should never have its background
/// color extended for filling padding space in the renderer. This is
/// a set of heuristics that help making our padding look better.
pub fn neverExtendBg(
self: Pin,
palette: *const color.Palette,
default_background: color.RGB,
) bool {
// Any semantic prompts should not have their background extended
// because prompts often contain special formatting (such as
// powerline) that looks bad when extended.
const rac = self.rowAndCell();
switch (rac.row.semantic_prompt) {
.prompt, .prompt_continuation, .input => return true,
.unknown, .command => {},
}
for (self.cells(.all)) |*cell| {
// If any cell has a default background color then we don't
// extend because the default background color probably looks
// good enough as an extension.
switch (cell.content_tag) {
// If it is a background color cell, we check the color.
.bg_color_palette, .bg_color_rgb => {
const s = self.style(cell);
const bg = s.bg(cell, palette) orelse return true;
if (bg.eql(default_background)) return true;
},
// If its a codepoint cell we can check the style.
.codepoint, .codepoint_grapheme => {
// For codepoint containing, we also never extend bg
// if any cell has a powerline glyph because these are
// perfect-fit.
switch (cell.codepoint()) {
// Powerline
0xE0B0...0xE0C8,
0xE0CA,
0xE0CC...0xE0D2,
0xE0D4,
=> return true,
else => {},
}
// Never extend a cell that has a default background.
// A default background is applied if there is no background
// on the style or the explicitly set background
// matches our default background.
const s = self.style(cell);
const bg = s.bg(cell, palette) orelse return true;
if (bg.eql(default_background)) return true;
},
}
}
return false;
}
/// Iterators. These are the same as PageList iterator funcs but operate
/// on pins rather than points. This is MUCH more efficient than calling
/// pointFromPin and building up the iterator from points.