1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-23 06:54:45 +03:00

add config for customizing the tabs and new tab button

```lua
local wezterm = require 'wezterm';

-- The filled in variant of the < symbol
local SOLID_LEFT_ARROW = utf8.char(0xe0b2)

-- The filled in variant of the > symbol
local SOLID_RIGHT_ARROW = utf8.char(0xe0b0)

return {
  tab_bar_style = {
    active_tab_left = wezterm.format({
      {Background={Color="#0b0022"}},
      {Foreground={Color="#2b2042"}},
      {Text=SOLID_LEFT_ARROW},
    }),
    active_tab_right = wezterm.format({
      {Background={Color="#0b0022"}},
      {Foreground={Color="#2b2042"}},
      {Text=SOLID_RIGHT_ARROW},
    }),
    inactive_tab_left = wezterm.format({
      {Background={Color="#0b0022"}},
      {Foreground={Color="#1b1032"}},
      {Text=SOLID_LEFT_ARROW},
    }),
    inactive_tab_right = wezterm.format({
      {Background={Color="#0b0022"}},
      {Foreground={Color="#1b1032"}},
      {Text=SOLID_RIGHT_ARROW},
    }),
  }
}
```
This commit is contained in:
Wez Furlong 2021-03-11 21:21:31 -08:00
parent 62d1d11eaf
commit eb4323ee59
4 changed files with 178 additions and 36 deletions

View File

@ -1,3 +1,4 @@
use crate::lua::{format_as_escapes, FormatItem};
use crate::*;
use luahelper::impl_lua_conversion;
use termwiz::cell::CellAttributes;
@ -181,6 +182,56 @@ impl Default for TabBarColors {
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TabBarStyle {
#[serde(default = "default_tab_left")]
pub active_tab_left: String,
#[serde(default = "default_tab_right")]
pub active_tab_right: String,
#[serde(default = "default_tab_left")]
pub inactive_tab_left: String,
#[serde(default = "default_tab_right")]
pub inactive_tab_right: String,
#[serde(default = "default_tab_left")]
pub inactive_tab_hover_left: String,
#[serde(default = "default_tab_right")]
pub inactive_tab_hover_right: String,
#[serde(default = "default_tab_left")]
pub new_tab_left: String,
#[serde(default = "default_tab_right")]
pub new_tab_right: String,
#[serde(default = "default_tab_left")]
pub new_tab_hover_left: String,
#[serde(default = "default_tab_right")]
pub new_tab_hover_right: String,
}
impl Default for TabBarStyle {
fn default() -> Self {
Self {
active_tab_left: default_tab_left(),
active_tab_right: default_tab_right(),
inactive_tab_left: default_tab_left(),
inactive_tab_right: default_tab_right(),
inactive_tab_hover_left: default_tab_left(),
inactive_tab_hover_right: default_tab_right(),
new_tab_left: default_tab_left(),
new_tab_right: default_tab_right(),
new_tab_hover_left: default_tab_left(),
new_tab_hover_right: default_tab_right(),
}
}
}
fn default_tab_left() -> String {
format_as_escapes(vec![FormatItem::Text(" ".to_string())]).unwrap()
}
fn default_tab_right() -> String {
format_as_escapes(vec![FormatItem::Text(" ".to_string())]).unwrap()
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ColorSchemeFile {
/// The color palette

View File

@ -670,6 +670,9 @@ pub struct Config {
/// The color palette
pub colors: Option<Palette>,
#[serde(default)]
pub tab_bar_style: TabBarStyle,
#[serde(skip)]
pub resolved_palette: Palette,

View File

@ -173,9 +173,10 @@ struct ChangeWrap(Change);
impl_lua_conversion!(ChangeWrap);
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
enum FormatColor {
pub enum FormatColor {
AnsiColor(AnsiColor),
Color(String),
Default,
}
impl FormatColor {
@ -195,12 +196,13 @@ impl Into<ColorSpec> for FormatColor {
.unwrap_or(RgbColor::new(0xff, 0xff, 0xff));
rgb.into()
}
FormatColor::Default => ColorSpec::Default,
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
enum FormatItem {
pub enum FormatItem {
Foreground(FormatColor),
Background(FormatColor),
Attribute(AttributeChange),
@ -244,15 +246,17 @@ fn strftime<'lua>(_: &'lua Lua, format: String) -> mlua::Result<String> {
Ok(local.format(&format).to_string())
}
fn format<'lua>(_: &'lua Lua, items: Vec<FormatItem>) -> mlua::Result<String> {
pub fn format_as_escapes(items: Vec<FormatItem>) -> anyhow::Result<String> {
let mut changes: Vec<Change> = items.into_iter().map(Into::into).collect();
changes.push(Change::AllAttributes(CellAttributes::default()).into());
let mut renderer = new_wezterm_terminfo_renderer();
let mut target = FormatTarget { target: vec![] };
renderer
.render_to(&changes, &mut target)
.map_err(|e| mlua::Error::external(e))?;
String::from_utf8(target.target).map_err(|e| mlua::Error::external(e))
renderer.render_to(&changes, &mut target)?;
Ok(String::from_utf8(target.target)?)
}
fn format<'lua>(_: &'lua Lua, items: Vec<FormatItem>) -> mlua::Result<String> {
format_as_escapes(items).map_err(|e| mlua::Error::external(e))
}
#[derive(Serialize, Deserialize, Debug)]

View File

@ -54,13 +54,59 @@ impl TabBarState {
config: &ConfigHandle,
right_status: &str,
) -> Self {
let colors = colors.cloned().unwrap_or_else(TabBarColors::default);
let active_cell_attrs = colors.active_tab.as_cell_attributes();
let inactive_hover_attrs = colors.inactive_tab_hover.as_cell_attributes();
let inactive_cell_attrs = colors.inactive_tab.as_cell_attributes();
let active_tab_left = parse_status_text(
&config.tab_bar_style.active_tab_left,
active_cell_attrs.clone(),
);
let active_tab_right = parse_status_text(
&config.tab_bar_style.active_tab_right,
active_cell_attrs.clone(),
);
let inactive_tab_left = parse_status_text(
&config.tab_bar_style.inactive_tab_left,
inactive_cell_attrs.clone(),
);
let inactive_tab_right = parse_status_text(
&config.tab_bar_style.inactive_tab_right,
inactive_cell_attrs.clone(),
);
let inactive_tab_hover_left = parse_status_text(
&config.tab_bar_style.inactive_tab_hover_left,
inactive_hover_attrs.clone(),
);
let inactive_tab_hover_right = parse_status_text(
&config.tab_bar_style.inactive_tab_hover_right,
inactive_hover_attrs.clone(),
);
let new_tab_left = parse_status_text(
&config.tab_bar_style.new_tab_left,
inactive_cell_attrs.clone(),
);
let new_tab_right = parse_status_text(
&config.tab_bar_style.new_tab_right,
inactive_cell_attrs.clone(),
);
let new_tab_hover_left = parse_status_text(
&config.tab_bar_style.new_tab_hover_left,
inactive_hover_attrs.clone(),
);
let new_tab_hover_right = parse_status_text(
&config.tab_bar_style.new_tab_hover_right,
inactive_hover_attrs.clone(),
);
// We ultimately want to produce a line looking like this:
// ` | tab1-title x | tab2-title x | + . - X `
// Where the `+` sign will spawn a new tab (or show a context
// menu with tab creation options) and the other three chars
// are symbols representing minimize, maximize and close.
let per_tab_overhead = 2;
let system_overhead = 3;
let tab_titles: Vec<String> = window
.iter()
@ -95,8 +141,11 @@ impl TabBarState {
let titles_len: usize = tab_titles.iter().map(|s| unicode_column_width(s)).sum();
let number_of_tabs = tab_titles.len();
let available_cells =
title_width.saturating_sub((number_of_tabs * per_tab_overhead) + system_overhead);
let available_cells = title_width.saturating_sub(
(number_of_tabs.saturating_sub(1)
* (inactive_tab_left.len() + inactive_tab_right.len()))
+ (new_tab_left.len() + new_tab_right.len() + 1),
);
let tab_width_max = if available_cells >= titles_len {
// We can render each title with its full width
usize::max_value()
@ -106,8 +155,6 @@ impl TabBarState {
}
.min(config.tab_max_width);
let colors = colors.cloned().unwrap_or_else(TabBarColors::default);
let mut line = Line::with_width(title_width);
let active_tab_no = window.get_active_idx();
@ -117,23 +164,39 @@ impl TabBarState {
for (tab_idx, tab_title) in tab_titles.iter().enumerate() {
let tab_title_len = unicode_column_width(tab_title).min(tab_width_max);
let hover = mouse_x
.map(|mouse_x| mouse_x >= x && mouse_x < x + tab_title_len + per_tab_overhead)
.unwrap_or(false);
let active = tab_idx == active_tab_no;
let hover = !active
&& mouse_x
.map(|mouse_x| {
mouse_x >= x
&& mouse_x
< x + tab_title_len
+ (inactive_tab_left.len() + inactive_tab_right.len())
})
.unwrap_or(false);
let cell_attrs = if active {
colors.active_tab.as_cell_attributes()
let (cell_attrs, left, right) = if active {
(&active_cell_attrs, &active_tab_left, &active_tab_right)
} else if hover {
colors.inactive_tab_hover.as_cell_attributes()
(
&inactive_hover_attrs,
&inactive_tab_hover_left,
&inactive_tab_hover_right,
)
} else {
colors.inactive_tab.as_cell_attributes()
(
&inactive_cell_attrs,
&inactive_tab_left,
&inactive_tab_right,
)
};
let tab_start_idx = x;
line.set_cell(x, Cell::new(' ', cell_attrs.clone()));
x += 1;
for c in left {
line.set_cell(x, c.clone());
x += 1;
}
for (idx, sub) in tab_title.graphemes(true).enumerate() {
if idx >= tab_width_max {
@ -144,8 +207,10 @@ impl TabBarState {
x += 1;
}
line.set_cell(x, Cell::new(' ', cell_attrs));
x += 1;
for c in right {
line.set_cell(x, c.clone());
x += 1;
}
items.push(TabEntry {
item: TabBarItem::Tab(tab_idx),
@ -160,22 +225,33 @@ impl TabBarState {
.map(|mouse_x| mouse_x >= x && mouse_x < x + 3)
.unwrap_or(false);
let cell_attrs = if hover {
colors.inactive_tab_hover.as_cell_attributes()
let (cell_attrs, left, right) = if hover {
(
&inactive_hover_attrs,
&new_tab_hover_left,
&new_tab_hover_right,
)
} else {
colors.inactive_tab.as_cell_attributes()
(&inactive_cell_attrs, &new_tab_left, &new_tab_right)
};
let button_start = x;
for c in left {
line.set_cell(x, c.clone());
x += 1;
}
line.set_cell(x, Cell::new('+', cell_attrs.clone()));
for c in right {
line.set_cell(x, c.clone());
x += 1;
}
items.push(TabEntry {
item: TabBarItem::NewTabButton,
x,
width: 3,
x: button_start,
width: x - button_start,
});
line.set_cell(x, Cell::new(' ', cell_attrs.clone()));
line.set_cell(x + 1, Cell::new('+', cell_attrs.clone()));
line.set_cell(x + 2, Cell::new(' ', cell_attrs));
x += 3;
}
let black_cell = Cell::new(
@ -270,10 +346,18 @@ fn parse_status_text(text: &str, default_cell: CellAttributes) -> Vec<Cell> {
pen.set_strikethrough(strike);
}
Sgr::Foreground(col) => {
pen.set_foreground(col);
if let ColorSpec::Default = col {
pen.set_foreground(default_cell.foreground);
} else {
pen.set_foreground(col);
}
}
Sgr::Background(col) => {
pen.set_background(col);
if let ColorSpec::Default = col {
pen.set_background(default_cell.background);
} else {
pen.set_background(col);
}
}
Sgr::UnderlineColor(col) => {
pen.set_underline_color(col);