Merge branch 'ghostty-org:main' into macos-window-deocrations-rework

This commit is contained in:
Ethan Johnson
2024-10-21 17:43:37 -04:00
committed by GitHub
10 changed files with 159 additions and 21 deletions

View File

@ -43,17 +43,17 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate {
item.view = self.titleTextField
item.visibilityPriority = .user
// NSToolbarItem.minSize and NSToolbarItem.maxSize are deprecated, and make big ugly
// warnings in Xcode when you use them, but I cannot for the life of me figure out
// how to get this to work with constraints. The behavior isn't the same, instead of
// shrinking the item and clipping the subview, it hides the item as soon as the
// intrinsic size of the subview gets too big for the toolbar width, regardless of
// whether I have constraints set on its width, height, or both :/
//
// If someone can fix this so we don't have to use deprecated properties: Please do.
item.minSize = NSSize(width: 32, height: 1)
item.maxSize = NSSize(width: 1024, height: self.titleTextField.intrinsicContentSize.height)
// This ensures the title text field doesn't disappear when shrinking the view
self.titleTextField.translatesAutoresizingMaskIntoConstraints = false
self.titleTextField.setContentHuggingPriority(.defaultLow, for: .horizontal)
self.titleTextField.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
// Add constraints to the toolbar item's view
NSLayoutConstraint.activate([
// Set the height constraint to match the toolbar's height
self.titleTextField.heightAnchor.constraint(equalToConstant: 22), // Adjust as needed
])
item.isEnabled = true
case .resetZoom:
item = NSToolbarItem(itemIdentifier: .resetZoom)
@ -73,23 +73,27 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate {
// getting smaller than the max size so starts clipping. Lucky for us, two of the
// built-in spacers plus the un-zoom button item seems to exactly match the space
// on the left that's reserved for the window buttons.
return [.titleText, .flexibleSpace, .space, .space, .resetZoom]
return [.flexibleSpace, .titleText, .flexibleSpace]
}
}
/// A label that expands to fit whatever text you put in it and horizontally centers itself in the current window.
fileprivate class CenteredDynamicLabel: NSTextField {
override func viewDidMoveToSuperview() {
// Truncate the title when it gets too long, cutting it off with an ellipsis.
// Configure the text field
isEditable = false
isBordered = false
drawsBackground = false
alignment = .center
lineBreakMode = .byTruncatingTail
cell?.truncatesLastVisibleLine = true
cell?.lineBreakMode = .byCharWrapping
// Make the text field as small as possible while fitting its text.
setContentHuggingPriority(.required, for: .horizontal)
cell?.alignment = .center
// We've changed some alignment settings, make sure the layout is updated immediately.
needsLayout = true
// Use Auto Layout
translatesAutoresizingMaskIntoConstraints = false
// Set content hugging and compression resistance priorities
setContentHuggingPriority(.defaultLow, for: .horizontal)
setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
}
}

View File

@ -27,6 +27,8 @@ pub const Sprite = enum(u32) {
strikethrough,
overline,
cursor_rect,
cursor_hollow_rect,
cursor_bar,

View File

@ -150,6 +150,16 @@ pub fn renderGlyph(
self.thickness,
),
.overline => try underline.renderGlyph(
alloc,
atlas,
@enumFromInt(cp),
width,
self.height,
0,
self.thickness,
),
.powerline => powerline: {
const f: Powerline = .{
.width = width,
@ -166,6 +176,7 @@ pub fn renderGlyph(
const Kind = enum {
box,
underline,
overline,
strikethrough,
powerline,
@ -179,6 +190,9 @@ const Kind = enum {
.underline_curly,
=> .underline,
.overline,
=> .overline,
.strikethrough,
=> .strikethrough,

View File

@ -34,6 +34,7 @@ pub fn renderGlyph(
.underline_dotted => try drawDotted(alloc, width, line_thickness),
.underline_dashed => try drawDashed(alloc, width, line_thickness),
.underline_curly => try drawCurly(alloc, width, line_thickness),
.overline => try drawSingle(alloc, width, line_thickness),
.strikethrough => try drawSingle(alloc, width, line_thickness),
else => unreachable,
};

View File

@ -2492,6 +2492,18 @@ fn rebuildCells(
);
};
if (style.flags.overline) self.addOverline(
@intCast(x),
@intCast(y),
fg,
alpha
) catch |err| {
log.warn(
"error adding overline to cell, will be invalid x={} y={}, err={}",
.{ x, y, err },
);
};
// If we're at or past the end of our shaper run then
// we need to get the next run from the run iterator.
if (shaper_cells != null and shaper_cells_i >= shaper_cells.?.len) {
@ -2709,6 +2721,38 @@ fn addUnderline(
});
}
/// Add a overline decoration to the specified cell
fn addOverline(
self: *Metal,
x: terminal.size.CellCountInt,
y: terminal.size.CellCountInt,
color: terminal.color.RGB,
alpha: u8,
) !void {
const render = try self.font_grid.renderGlyph(
self.alloc,
font.sprite_index,
@intFromEnum(font.Sprite.overline),
.{
.cell_width = 1,
.grid_metrics = self.grid_metrics,
},
);
try self.cells.add(self.alloc, .overline, .{
.mode = .fg,
.grid_pos = .{ @intCast(x), @intCast(y) },
.constraint_width = 1,
.color = .{ color.r, color.g, color.b, alpha },
.glyph_pos = .{ render.glyph.atlas_x, render.glyph.atlas_y },
.glyph_size = .{ render.glyph.width, render.glyph.height },
.bearings = .{
@intCast(render.glyph.offset_x),
@intCast(render.glyph.offset_y),
},
});
}
/// Add a strikethrough decoration to the specified cell
fn addStrikethrough(
self: *Metal,

View File

@ -1586,6 +1586,19 @@ pub fn rebuildCells(
);
};
if (style.flags.overline) self.addOverline(
@intCast(x),
@intCast(y),
fg,
alpha,
bg_color,
) catch |err| {
log.warn(
"error adding overline to cell, will be invalid x={} y={}, err={}",
.{ x, y, err },
);
};
// If we're at or past the end of our shaper run then
// we need to get the next run from the run iterator.
if (shaper_cells != null and shaper_cells_i >= shaper_cells.?.len) {
@ -1955,6 +1968,47 @@ fn addUnderline(
});
}
/// Add an overline decoration to the specified cell
fn addOverline(
self: *OpenGL,
x: terminal.size.CellCountInt,
y: terminal.size.CellCountInt,
color: terminal.color.RGB,
alpha: u8,
bg: [4]u8,
) !void {
const render = try self.font_grid.renderGlyph(
self.alloc,
font.sprite_index,
@intFromEnum(font.Sprite.overline),
.{
.cell_width = 1,
.grid_metrics = self.grid_metrics,
},
);
try self.cells.append(self.alloc, .{
.mode = .fg,
.grid_col = @intCast(x),
.grid_row = @intCast(y),
.grid_width = 1,
.glyph_x = render.glyph.atlas_x,
.glyph_y = render.glyph.atlas_y,
.glyph_width = render.glyph.width,
.glyph_height = render.glyph.height,
.glyph_offset_x = render.glyph.offset_x,
.glyph_offset_y = render.glyph.offset_y,
.r = color.r,
.g = color.g,
.b = color.b,
.a = alpha,
.bg_r = bg[0],
.bg_g = bg[1],
.bg_b = bg[2],
.bg_a = bg[3],
});
}
/// Add a strikethrough decoration to the specified cell
fn addStrikethrough(
self: *OpenGL,

View File

@ -12,6 +12,7 @@ pub const Key = enum {
text,
underline,
strikethrough,
overline,
/// Returns the GPU vertex type for this key.
pub fn CellType(self: Key) type {
@ -21,6 +22,7 @@ pub const Key = enum {
.text,
.underline,
.strikethrough,
.overline,
=> mtl_shaders.CellText,
};
}
@ -196,6 +198,7 @@ pub const Contents = struct {
.text,
.underline,
.strikethrough,
.overline,
// We have a special list containing the cursor cell at the start
// of our fg row pool, so we need to add 1 to the y to get the
// correct index.

View File

@ -1618,6 +1618,14 @@ pub fn setAttribute(self: *Screen, attr: sgr.Attribute) !void {
self.cursor.style.underline_color = .none;
},
.overline => {
self.cursor.style.flags.overline = true;
},
.reset_overline => {
self.cursor.style.flags.overline = false;
},
.blink => {
self.cursor.style.flags.blink = true;
},

View File

@ -37,6 +37,10 @@ pub const Attribute = union(enum) {
@"256_underline_color": u8,
reset_underline_color: void,
// Overline the text
overline: void,
reset_overline: void,
/// Blink the text
blink: void,
reset_blink: void,
@ -237,6 +241,9 @@ pub const Parser = struct {
49 => return Attribute{ .reset_bg = {} },
53 => return Attribute{ .overline = {} },
55 => return Attribute{ .reset_overline = {} },
58 => if (slice.len >= 5 and slice[1] == 2) {
self.idx += 4;

View File

@ -35,6 +35,7 @@ pub const Style = struct {
inverse: bool = false,
invisible: bool = false,
strikethrough: bool = false,
overline: bool = false,
underline: sgr.Attribute.Underline = .none,
} = .{},