From 0f27fc2a0d3c190559961f3a5f9546c3942ea61c Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sat, 3 Aug 2024 14:36:06 -0500 Subject: [PATCH 1/2] Implement asymmetric window padding. Add `window-padding-top`, `window-padding-bottom`, `window-padding-left`, and `window-padding-right` options. The `window-padding-x` and `window-padding-y` options will override the individual options. --- src/Surface.zig | 68 ++++++++++++++-------- src/build/fish_completions.zig | 2 +- src/config/Config.zig | 101 +++++++++++++++++++++++++++++++-- 3 files changed, 140 insertions(+), 31 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 183d4b3f8..a62f9b759 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -217,8 +217,10 @@ const DerivedConfig = struct { macos_non_native_fullscreen: configpkg.NonNativeFullscreen, macos_option_as_alt: configpkg.OptionAsAlt, vt_kam_allowed: bool, - window_padding_x: u32, - window_padding_y: u32, + window_padding_top: u32, + window_padding_bottom: u32, + window_padding_left: u32, + window_padding_right: u32, window_padding_balance: bool, title: ?[:0]const u8, links: []Link, @@ -275,8 +277,10 @@ const DerivedConfig = struct { .macos_non_native_fullscreen = config.@"macos-non-native-fullscreen", .macos_option_as_alt = config.@"macos-option-as-alt", .vt_kam_allowed = config.@"vt-kam-allowed", - .window_padding_x = config.@"window-padding-x", - .window_padding_y = config.@"window-padding-y", + .window_padding_top = config.@"window-padding-y" orelse config.@"window-padding-top", + .window_padding_bottom = config.@"window-padding-y" orelse config.@"window-padding-bottom", + .window_padding_left = config.@"window-padding-x" orelse config.@"window-padding-left", + .window_padding_right = config.@"window-padding-x" orelse config.@"window-padding-right", .window_padding_balance = config.@"window-padding-balance", .title = config.title, .links = links, @@ -341,19 +345,27 @@ pub fn init( const cell_size = font_grid.cellSize(); // Convert our padding from points to pixels - const padding_x: u32 = padding_x: { - const padding_x: f32 = @floatFromInt(config.@"window-padding-x"); - break :padding_x @intFromFloat(@floor(padding_x * x_dpi / 72)); + const padding_top: u32 = padding_top: { + const padding_top: f32 = @floatFromInt(config.@"window-padding-y" orelse config.@"window-padding-top"); + break :padding_top @intFromFloat(@floor(padding_top * y_dpi / 72)); }; - const padding_y: u32 = padding_y: { - const padding_y: f32 = @floatFromInt(config.@"window-padding-y"); - break :padding_y @intFromFloat(@floor(padding_y * y_dpi / 72)); + const padding_bottom: u32 = padding_bottom: { + const padding_bottom: f32 = @floatFromInt(config.@"window-padding-y" orelse config.@"window-padding-bottom"); + break :padding_bottom @intFromFloat(@floor(padding_bottom * y_dpi / 72)); + }; + const padding_left: u32 = padding_left: { + const padding_left: f32 = @floatFromInt(config.@"window-padding-x" orelse config.@"window-padding-left"); + break :padding_left @intFromFloat(@floor(padding_left * x_dpi / 72)); + }; + const padding_right: u32 = padding_right: { + const padding_right: f32 = @floatFromInt(config.@"window-padding-y" orelse config.@"window-padding-right"); + break :padding_right @intFromFloat(@floor(padding_right * x_dpi / 72)); }; const padding: renderer.Padding = .{ - .top = padding_y, - .bottom = padding_y, - .right = padding_x, - .left = padding_x, + .top = padding_top, + .bottom = padding_bottom, + .left = padding_left, + .right = padding_right, }; // Create our terminal grid with the initial size @@ -1825,20 +1837,28 @@ pub fn contentScaleCallback(self: *Surface, content_scale: apprt.ContentScale) ! // Update our padding which is dependent on DPI. self.padding = padding: { - const padding_x: u32 = padding_x: { - const padding_x: f32 = @floatFromInt(self.config.window_padding_x); - break :padding_x @intFromFloat(@floor(padding_x * x_dpi / 72)); + const padding_top: u32 = padding_top: { + const padding_top: f32 = @floatFromInt(self.config.window_padding_top); + break :padding_top @intFromFloat(@floor(padding_top * y_dpi / 72)); }; - const padding_y: u32 = padding_y: { - const padding_y: f32 = @floatFromInt(self.config.window_padding_y); - break :padding_y @intFromFloat(@floor(padding_y * y_dpi / 72)); + const padding_bottom: u32 = padding_bottom: { + const padding_bottom: f32 = @floatFromInt(self.config.window_padding_bottom); + break :padding_bottom @intFromFloat(@floor(padding_bottom * y_dpi / 72)); + }; + const padding_left: u32 = padding_left: { + const padding_left: f32 = @floatFromInt(self.config.window_padding_left); + break :padding_left @intFromFloat(@floor(padding_left * x_dpi / 72)); + }; + const padding_right: u32 = padding_right: { + const padding_right: f32 = @floatFromInt(self.config.window_padding_right); + break :padding_right @intFromFloat(@floor(padding_right * x_dpi / 72)); }; break :padding .{ - .top = padding_y, - .bottom = padding_y, - .right = padding_x, - .left = padding_x, + .top = padding_top, + .bottom = padding_bottom, + .left = padding_left, + .right = padding_right, }; }; diff --git a/src/build/fish_completions.zig b/src/build/fish_completions.zig index 3a006a7b2..b6fe9b0dc 100644 --- a/src/build/fish_completions.zig +++ b/src/build/fish_completions.zig @@ -12,7 +12,7 @@ pub const fish_completions = comptimeGenerateFishCompletions(); fn comptimeGenerateFishCompletions() []const u8 { comptime { - @setEvalBranchQuota(15000); + @setEvalBranchQuota(16000); var counter = std.io.countingWriter(std.io.null_writer); try writeFishCompletions(&counter.writer()); diff --git a/src/config/Config.zig b/src/config/Config.zig index b31570a14..f17bb44e6 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -640,10 +640,27 @@ class: ?[:0]const u8 = null, /// "unconsumed:ctrl+a=reload_config" keybind: Keybinds = .{}, -/// Window padding. This applies padding between the terminal cells and the -/// window border. The `x` option applies to the left and right padding and the -/// `y` option is top and bottom. The value is in points, meaning that it will -/// be scaled appropriately for screen DPI. +/// Horizontal window padding. This applies padding between the terminal cells +/// and the left and right window borders. The value is in points, meaning that +/// it will be scaled appropriately for screen DPI. +/// +/// If this value is set too large, the screen will render nothing, because the +/// grid will be completely squished by the padding. It is up to you as the user +/// to pick a reasonable value. If you pick an unreasonable value, a warning +/// will appear in the logs. +/// +/// Changing this configuration at runtime will only affect new terminals, i.e. +/// new windows, tabs, etc. +/// +/// If this value is set, the value of `window-padding-left` and +/// `window-padding-right` will have no effect. +/// +/// By default, this value is unset. +@"window-padding-x": ?u32 = null, + +/// Vertical window padding. This applies padding between the terminal cells and +/// the top and bottom window borders. The value is in points, meaning that it +/// will be scaled appropriately for screen DPI. /// /// If this value is set too large, the screen will render nothing, because the /// grid will be completely squished by the padding. It is up to you as the user @@ -652,8 +669,80 @@ keybind: Keybinds = .{}, /// /// Changing this configuration at runtime will only affect new terminals, /// i.e. new windows, tabs, etc. -@"window-padding-x": u32 = 2, -@"window-padding-y": u32 = 2, +/// +/// If this value is set, the value of `window-padding-top` and +/// `window-padding-bottom` will have no effect. +/// +/// By default, this value is unset. +@"window-padding-y": ?u32 = null, + +/// Top window padding. This applies padding between the terminal cells and the +/// top window border. The value is in points, meaning that it will be scaled +/// appropriately for screen DPI. +/// +/// If this value is set too large, the screen will render nothing, because the +/// grid will be completely squished by the padding. It is up to you as the user +/// to pick a reasonable value. If you pick an unreasonable value, a warning +/// will appear in the logs. +/// +/// Changing this configuration at runtime will only affect new terminals, +/// i.e. new windows, tabs, etc. +/// +/// If `window-padding-y` is set, this value will be ignored. +/// +/// This value is set to 2 by default. +@"window-padding-top": u32 = 2, + +/// Bottom window padding. This applies padding between the terminal cells and +/// the bottom window border. The value is in points, meaning that it will be +/// scaled appropriately for screen DPI. +/// +/// If this value is set too large, the screen will render nothing, because the +/// grid will be completely squished by the padding. It is up to you as the user +/// to pick a reasonable value. If you pick an unreasonable value, a warning +/// will appear in the logs. +/// +/// Changing this configuration at runtime will only affect new terminals, +/// i.e. new windows, tabs, etc. +/// +/// If `window-padding-y` is set, this value will be ignored. +/// +/// This value is set to 2 by default. +@"window-padding-bottom": u32 = 2, + +/// Left window padding. This applies padding between the terminal cells and the +/// left window border. The value is in points, meaning that it will be scaled +/// appropriately for screen DPI. +/// +/// If this value is set too large, the screen will render nothing, because the +/// grid will be completely squished by the padding. It is up to you as the user +/// to pick a reasonable value. If you pick an unreasonable value, a warning +/// will appear in the logs. +/// +/// Changing this configuration at runtime will only affect new terminals, +/// i.e. new windows, tabs, etc. +/// +/// If `window-padding-x` is set, this value will be ignored. +/// +/// This value is set to 2 by default. +@"window-padding-left": u32 = 2, + +/// Right window padding. This applies padding between the terminal cells and +/// the right window border. The value is in points, meaning that it will be +/// scaled appropriately for screen DPI. +/// +/// If this value is set too large, the screen will render nothing, because the +/// grid will be completely squished by the padding. It is up to you as the user +/// to pick a reasonable value. If you pick an unreasonable value, a warning +/// will appear in the logs. +/// +/// Changing this configuration at runtime will only affect new terminals, +/// i.e. new windows, tabs, etc. +/// +/// If `window-padding-x` is set, this value will be ignored. +/// +/// This value is set to 2 by default. +@"window-padding-right": u32 = 2, /// The viewport dimensions are usually not perfectly divisible by the cell /// size. In this case, some extra padding on the end of a column and the bottom From c2778ab3a6271678b4292c07dfcb5c5c2e15fd3c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 5 Aug 2024 15:51:42 -0700 Subject: [PATCH 2/2] config: window-padding-x/y take two values for uneven padding --- src/Surface.zig | 16 ++-- src/config/Config.zig | 183 ++++++++++++++++++++++++------------------ 2 files changed, 113 insertions(+), 86 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index a62f9b759..6d28c33c4 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -277,10 +277,10 @@ const DerivedConfig = struct { .macos_non_native_fullscreen = config.@"macos-non-native-fullscreen", .macos_option_as_alt = config.@"macos-option-as-alt", .vt_kam_allowed = config.@"vt-kam-allowed", - .window_padding_top = config.@"window-padding-y" orelse config.@"window-padding-top", - .window_padding_bottom = config.@"window-padding-y" orelse config.@"window-padding-bottom", - .window_padding_left = config.@"window-padding-x" orelse config.@"window-padding-left", - .window_padding_right = config.@"window-padding-x" orelse config.@"window-padding-right", + .window_padding_top = config.@"window-padding-y".top_left, + .window_padding_bottom = config.@"window-padding-y".bottom_right, + .window_padding_left = config.@"window-padding-x".top_left, + .window_padding_right = config.@"window-padding-x".bottom_right, .window_padding_balance = config.@"window-padding-balance", .title = config.title, .links = links, @@ -346,19 +346,19 @@ pub fn init( // Convert our padding from points to pixels const padding_top: u32 = padding_top: { - const padding_top: f32 = @floatFromInt(config.@"window-padding-y" orelse config.@"window-padding-top"); + const padding_top: f32 = @floatFromInt(derived_config.window_padding_top); break :padding_top @intFromFloat(@floor(padding_top * y_dpi / 72)); }; const padding_bottom: u32 = padding_bottom: { - const padding_bottom: f32 = @floatFromInt(config.@"window-padding-y" orelse config.@"window-padding-bottom"); + const padding_bottom: f32 = @floatFromInt(derived_config.window_padding_bottom); break :padding_bottom @intFromFloat(@floor(padding_bottom * y_dpi / 72)); }; const padding_left: u32 = padding_left: { - const padding_left: f32 = @floatFromInt(config.@"window-padding-x" orelse config.@"window-padding-left"); + const padding_left: f32 = @floatFromInt(derived_config.window_padding_left); break :padding_left @intFromFloat(@floor(padding_left * x_dpi / 72)); }; const padding_right: u32 = padding_right: { - const padding_right: f32 = @floatFromInt(config.@"window-padding-y" orelse config.@"window-padding-right"); + const padding_right: f32 = @floatFromInt(derived_config.window_padding_right); break :padding_right @intFromFloat(@floor(padding_right * x_dpi / 72)); }; const padding: renderer.Padding = .{ diff --git a/src/config/Config.zig b/src/config/Config.zig index f17bb44e6..383c5d6ad 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -652,11 +652,12 @@ keybind: Keybinds = .{}, /// Changing this configuration at runtime will only affect new terminals, i.e. /// new windows, tabs, etc. /// -/// If this value is set, the value of `window-padding-left` and -/// `window-padding-right` will have no effect. -/// -/// By default, this value is unset. -@"window-padding-x": ?u32 = null, +/// To set a different left and right padding, specify two numerical values +/// separated by a comma. For example, `window-padding-x = 2,4` will set the +/// left padding to 2 and the right padding to 4. If you want to set both +/// paddings to the same value, you can use a single value. For example, +/// `window-padding-x = 2` will set both paddings to 2. +@"window-padding-x": WindowPadding = .{ .top_left = 2, .bottom_right = 2 }, /// Vertical window padding. This applies padding between the terminal cells and /// the top and bottom window borders. The value is in points, meaning that it @@ -670,79 +671,12 @@ keybind: Keybinds = .{}, /// Changing this configuration at runtime will only affect new terminals, /// i.e. new windows, tabs, etc. /// -/// If this value is set, the value of `window-padding-top` and -/// `window-padding-bottom` will have no effect. -/// -/// By default, this value is unset. -@"window-padding-y": ?u32 = null, - -/// Top window padding. This applies padding between the terminal cells and the -/// top window border. The value is in points, meaning that it will be scaled -/// appropriately for screen DPI. -/// -/// If this value is set too large, the screen will render nothing, because the -/// grid will be completely squished by the padding. It is up to you as the user -/// to pick a reasonable value. If you pick an unreasonable value, a warning -/// will appear in the logs. -/// -/// Changing this configuration at runtime will only affect new terminals, -/// i.e. new windows, tabs, etc. -/// -/// If `window-padding-y` is set, this value will be ignored. -/// -/// This value is set to 2 by default. -@"window-padding-top": u32 = 2, - -/// Bottom window padding. This applies padding between the terminal cells and -/// the bottom window border. The value is in points, meaning that it will be -/// scaled appropriately for screen DPI. -/// -/// If this value is set too large, the screen will render nothing, because the -/// grid will be completely squished by the padding. It is up to you as the user -/// to pick a reasonable value. If you pick an unreasonable value, a warning -/// will appear in the logs. -/// -/// Changing this configuration at runtime will only affect new terminals, -/// i.e. new windows, tabs, etc. -/// -/// If `window-padding-y` is set, this value will be ignored. -/// -/// This value is set to 2 by default. -@"window-padding-bottom": u32 = 2, - -/// Left window padding. This applies padding between the terminal cells and the -/// left window border. The value is in points, meaning that it will be scaled -/// appropriately for screen DPI. -/// -/// If this value is set too large, the screen will render nothing, because the -/// grid will be completely squished by the padding. It is up to you as the user -/// to pick a reasonable value. If you pick an unreasonable value, a warning -/// will appear in the logs. -/// -/// Changing this configuration at runtime will only affect new terminals, -/// i.e. new windows, tabs, etc. -/// -/// If `window-padding-x` is set, this value will be ignored. -/// -/// This value is set to 2 by default. -@"window-padding-left": u32 = 2, - -/// Right window padding. This applies padding between the terminal cells and -/// the right window border. The value is in points, meaning that it will be -/// scaled appropriately for screen DPI. -/// -/// If this value is set too large, the screen will render nothing, because the -/// grid will be completely squished by the padding. It is up to you as the user -/// to pick a reasonable value. If you pick an unreasonable value, a warning -/// will appear in the logs. -/// -/// Changing this configuration at runtime will only affect new terminals, -/// i.e. new windows, tabs, etc. -/// -/// If `window-padding-x` is set, this value will be ignored. -/// -/// This value is set to 2 by default. -@"window-padding-right": u32 = 2, +/// To set a different top and bottom padding, specify two numerical values +/// separated by a comma. For example, `window-padding-y = 2,4` will set the +/// top padding to 2 and the bottom padding to 4. If you want to set both +/// paddings to the same value, you can use a single value. For example, +/// `window-padding-y = 2` will set both paddings to 2. +@"window-padding-y": WindowPadding = .{ .top_left = 2, .bottom_right = 2 }, /// The viewport dimensions are usually not perfectly divisible by the cell /// size. In this case, some extra padding on the end of a column and the bottom @@ -4067,6 +4001,99 @@ pub const Duration = struct { } }; +pub const WindowPadding = struct { + const Self = @This(); + + top_left: u32 = 0, + bottom_right: u32 = 0, + + pub fn clone(self: Self, _: Allocator) !Self { + return self; + } + + pub fn equal(self: Self, other: Self) bool { + return std.meta.eql(self, other); + } + + pub fn parseCLI(input_: ?[]const u8) !WindowPadding { + const input = input_ orelse return error.ValueRequired; + const whitespace = " \t"; + + if (std.mem.indexOf(u8, input, ",")) |idx| { + const input_left = std.mem.trim(u8, input[0..idx], whitespace); + const input_right = std.mem.trim(u8, input[idx + 1 ..], whitespace); + const left = std.fmt.parseInt(u32, input_left, 10) catch + return error.InvalidValue; + const right = std.fmt.parseInt(u32, input_right, 10) catch + return error.InvalidValue; + return .{ .top_left = left, .bottom_right = right }; + } else { + const value = std.fmt.parseInt( + u32, + std.mem.trim(u8, input, whitespace), + 10, + ) catch return error.InvalidValue; + return .{ .top_left = value, .bottom_right = value }; + } + } + + pub fn formatEntry(self: Self, formatter: anytype) !void { + var buf: [128]u8 = undefined; + if (self.top_left == self.bottom_right) { + try formatter.formatEntry( + []const u8, + std.fmt.bufPrint( + &buf, + "{}", + .{self.top_left}, + ) catch return error.OutOfMemory, + ); + } else { + try formatter.formatEntry( + []const u8, + std.fmt.bufPrint( + &buf, + "{},{}", + .{ self.top_left, self.bottom_right }, + ) catch return error.OutOfMemory, + ); + } + } + + test "parse WindowPadding" { + const testing = std.testing; + + { + const v = try WindowPadding.parseCLI("100"); + try testing.expectEqual(WindowPadding{ + .top_left = 100, + .bottom_right = 100, + }, v); + } + + { + const v = try WindowPadding.parseCLI("100,200"); + try testing.expectEqual(WindowPadding{ + .top_left = 100, + .bottom_right = 200, + }, v); + } + + // Trim whitespace + { + const v = try WindowPadding.parseCLI(" 100 , 200 "); + try testing.expectEqual(WindowPadding{ + .top_left = 100, + .bottom_right = 200, + }, v); + } + + try testing.expectError(error.ValueRequired, WindowPadding.parseCLI(null)); + try testing.expectError(error.InvalidValue, WindowPadding.parseCLI("")); + try testing.expectError(error.InvalidValue, WindowPadding.parseCLI("a")); + } +}; + test "parse duration" { inline for (Duration.units) |unit| { var buf: [16]u8 = undefined;