From 3e3f2dcf59723fe893be9425aaf3bb4dcbd82e0d Mon Sep 17 00:00:00 2001 From: Daniel Berlin Date: Fri, 6 Oct 2023 17:04:58 -0400 Subject: [PATCH] Add support for stretching tab bar to fill width of tab bar Resolves #1914 --- Cargo.toml | 12 +++---- config/src/config.rs | 4 +++ docs/config/appearance.md | 2 ++ docs/config/lua/config/tab_bar_title_fill.md | 15 +++++++++ wezterm-gui/src/tabbar.rs | 23 +++++++++----- .../src/termwindow/render/fancy_tab_bar.rs | 31 +++++++++++++++++-- 6 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 docs/config/lua/config/tab_bar_title_fill.md diff --git a/Cargo.toml b/Cargo.toml index 6422e0503bf8..719a3d1067cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,15 @@ members = [ "wezterm-gui", "wezterm-mux-server", "wezterm-open-url", - "wezterm-ssh" + "wezterm-ssh", ] resolver = "2" -exclude = [ - "termwiz/codegen" -] +exclude = ["termwiz/codegen"] [profile.release] opt-level = 3 +lto = "thin" +codegen-units = 1 # debug = 2 [profile.dev] @@ -28,8 +28,8 @@ opt-level = 3 #split-debuginfo = "unpacked" [patch.crates-io] -xcb = {git="https://github.com/rust-x-bindings/rust-xcb", rev="dbdaa01c178c6fbe68bd51b7ad44c08172181083"} # waiting on a release with https://github.com/rust-x-bindings/rust-xcb/pull/230 +xcb = { git = "https://github.com/rust-x-bindings/rust-xcb", rev = "dbdaa01c178c6fbe68bd51b7ad44c08172181083" } # waiting on a release with https://github.com/rust-x-bindings/rust-xcb/pull/230 # We use our own vendored cairo, which has minimal deps and should just # build via cargo. -cairo-sys-rs = {path="deps/cairo", version="0.18.0"} +cairo-sys-rs = { path = "deps/cairo", version = "0.18.0" } diff --git a/config/src/config.rs b/config/src/config.rs index 19d5b9c81d90..8cc675faf42f 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -461,6 +461,10 @@ pub struct Config { #[dynamic(default)] pub tab_and_split_indices_are_zero_based: bool, + /// Specifies to fill the width of the window with the tab bar + #[dynamic(default)] + pub tab_bar_fill: bool, + /// Specifies the maximum width that a tab can have in the /// tab bar. Defaults to 16 glyphs in width. #[dynamic(default = "default_tab_max_width")] diff --git a/docs/config/appearance.md b/docs/config/appearance.md index 99cb144dce56..116d5a2141dd 100644 --- a/docs/config/appearance.md +++ b/docs/config/appearance.md @@ -277,6 +277,8 @@ details. bar at the bottom of the window instead of the top * [tab_max_width](lua/config/tab_max_width.md) sets the maximum width, measured in cells, of a given tab when using retro tab mode. +* [tab_bar_fill](lua/config/tab_bar_fill.md) sets the fancy tab bar to fill + the width of the title bar. #### Native (Fancy) Tab Bar appearance diff --git a/docs/config/lua/config/tab_bar_title_fill.md b/docs/config/lua/config/tab_bar_title_fill.md new file mode 100644 index 000000000000..195e2593d6dd --- /dev/null +++ b/docs/config/lua/config/tab_bar_title_fill.md @@ -0,0 +1,15 @@ +--- +tags: + - tab_bar +--- +# `tab_bar_fill` + +Specifies that the fancy tab bar should allow tab titles +to take up the entire width of the tab bar. +In this mode, maximum tab width is ignored. + +Defaults to false. + +```lua +config.tab_bar_fill = true +``` diff --git a/wezterm-gui/src/tabbar.rs b/wezterm-gui/src/tabbar.rs index 06ac12c33200..363e75ed5fb9 100644 --- a/wezterm-gui/src/tabbar.rs +++ b/wezterm-gui/src/tabbar.rs @@ -324,6 +324,14 @@ impl TabBarState { let mut active_tab_no = 0; + let config_tab_max_width = if config.tab_bar_fill { + // We have no layout, so this is a rough estimate + // The tab bar consits of the tab titles, the new tab button, and some padding + title_width.saturating_sub(new_tab.len() + 3) / (tab_info.len()) + } else { + config.tab_max_width + }; + let tab_titles: Vec = if config.show_tabs_in_tab_bar { tab_info .iter() @@ -337,7 +345,7 @@ impl TabBarState { pane_info, config, false, - config.tab_max_width, + config_tab_max_width, ) }) .collect() @@ -346,18 +354,16 @@ impl TabBarState { }; let titles_len: usize = tab_titles.iter().map(|s| s.len).sum(); let number_of_tabs = tab_titles.len(); - let available_cells = title_width.saturating_sub(number_of_tabs.saturating_sub(1) + new_tab.len()); let tab_width_max = if config.use_fancy_tab_bar || available_cells >= titles_len { // We can render each title with its full width - usize::max_value() + usize::MAX } else { // We need to clamp the length to balance them out available_cells / number_of_tabs } - .min(config.tab_max_width); - + .min(config_tab_max_width); let mut line = Line::with_width(0, SEQ_ZERO); let mut x = 0; @@ -399,9 +405,10 @@ impl TabBarState { } for (tab_idx, tab_title) in tab_titles.iter().enumerate() { - let tab_title_len = tab_title.len.min(tab_width_max); + // The title is allowed to grow to the max size of the computed tab width + let tab_title_max_len = tab_title.len.max(tab_width_max).min(tab_width_max); let active = tab_idx == active_tab_no; - let hover = !active && is_tab_hover(mouse_x, x, tab_title_len); + let hover = !active && is_tab_hover(mouse_x, x, tab_title_max_len); // Recompute the title so that it factors in both the hover state // and the adjusted maximum tab width based on available space. @@ -411,7 +418,7 @@ impl TabBarState { pane_info, config, hover, - tab_title_len, + tab_title_max_len, ); let cell_attrs = if active { diff --git a/wezterm-gui/src/termwindow/render/fancy_tab_bar.rs b/wezterm-gui/src/termwindow/render/fancy_tab_bar.rs index 56a50705d9ed..11306d8cb09b 100644 --- a/wezterm-gui/src/termwindow/render/fancy_tab_bar.rs +++ b/wezterm-gui/src/termwindow/render/fancy_tab_bar.rs @@ -299,9 +299,33 @@ impl crate::TermWindow { _ => 0., }) .sum(); - let max_tab_width = ((self.dimensions.pixel_width as f32 / num_tabs) - - (1.5 * metrics.cell_size.width as f32)) - .max(0.); + + // Unlike num tabs this only includes items on the tab bar, since the new tab button is fixed width. + let num_tabs_or_status: f32 = items + .iter() + .map(|item| match item.item { + TabBarItem::RightStatus { .. } + | TabBarItem::LeftStatus { .. } + | TabBarItem::Tab { .. } => 1., + _ => 0., + }) + .sum(); + // When filling, we allow the entire title bar to be taken up, leaving + // a little space for the new tab button (which is 2x cell width) + // and padding. + let max_tab_width = if self.config.tab_bar_fill { + (self.dimensions.pixel_width as f32 - (5.0 * metrics.cell_size.width as f32)).max(0.) + / num_tabs_or_status + } else { + ((self.dimensions.pixel_width as f32 / num_tabs) + - (1.5 * metrics.cell_size.width as f32)) + .max(0.) + }; + let min_tab_width = if self.config.tab_bar_fill { + (max_tab_width - 5.0).max(0.) + } else { + 0. + }; // Reserve space for the native titlebar buttons if self @@ -335,6 +359,7 @@ impl crate::TermWindow { } TabBarItem::Tab { tab_idx, active } => { let mut elem = item_to_elem(item); + elem.min_width = Some(Dimension::Pixels(min_tab_width)); elem.max_width = Some(Dimension::Pixels(max_tab_width)); elem.content = match elem.content { ElementContent::Text(_) => unreachable!(),