New tab styling (#216)
* draft * feat(tabbar): new ui * style(fmt): rustfmt
This commit is contained in:
parent
955d38906d
commit
845478fe11
3 changed files with 247 additions and 13 deletions
165
default-tiles/tab-bar/src/line.rs
Normal file
165
default-tiles/tab-bar/src/line.rs
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
use colored::*;
|
||||||
|
|
||||||
|
use crate::{LinePart, ARROW_SEPARATOR};
|
||||||
|
|
||||||
|
fn get_current_title_len(current_title: &[LinePart]) -> usize {
|
||||||
|
current_title
|
||||||
|
.iter()
|
||||||
|
.fold(0, |acc, title_part| acc + title_part.len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn populate_tabs_in_tab_line(
|
||||||
|
tabs_before_active: &mut Vec<LinePart>,
|
||||||
|
tabs_after_active: &mut Vec<LinePart>,
|
||||||
|
tabs_to_render: &mut Vec<LinePart>,
|
||||||
|
cols: usize,
|
||||||
|
) {
|
||||||
|
let mut take_next_tab_from_tabs_after = true;
|
||||||
|
loop {
|
||||||
|
if tabs_before_active.is_empty() && tabs_after_active.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let current_title_len = get_current_title_len(&tabs_to_render);
|
||||||
|
if current_title_len >= cols {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let should_take_next_tab = take_next_tab_from_tabs_after;
|
||||||
|
let can_take_next_tab = !tabs_after_active.is_empty()
|
||||||
|
&& tabs_after_active.get(0).unwrap().len + current_title_len <= cols;
|
||||||
|
let can_take_previous_tab = !tabs_before_active.is_empty()
|
||||||
|
&& tabs_before_active.last().unwrap().len + current_title_len <= cols;
|
||||||
|
if should_take_next_tab && can_take_next_tab {
|
||||||
|
let next_tab = tabs_after_active.remove(0);
|
||||||
|
tabs_to_render.push(next_tab);
|
||||||
|
take_next_tab_from_tabs_after = false;
|
||||||
|
} else if can_take_previous_tab {
|
||||||
|
let previous_tab = tabs_before_active.pop().unwrap();
|
||||||
|
tabs_to_render.insert(0, previous_tab);
|
||||||
|
take_next_tab_from_tabs_after = true;
|
||||||
|
} else if can_take_next_tab {
|
||||||
|
let next_tab = tabs_after_active.remove(0);
|
||||||
|
tabs_to_render.push(next_tab);
|
||||||
|
take_next_tab_from_tabs_after = false;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn left_more_message(tab_count_to_the_left: usize) -> LinePart {
|
||||||
|
if tab_count_to_the_left == 0 {
|
||||||
|
return LinePart {
|
||||||
|
part: String::new(),
|
||||||
|
len: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let more_text = if tab_count_to_the_left < 10000 {
|
||||||
|
format!(" ← +{} ", tab_count_to_the_left)
|
||||||
|
} else {
|
||||||
|
format!(" ← +many ")
|
||||||
|
};
|
||||||
|
let more_styled_text = format!(
|
||||||
|
"{}{}",
|
||||||
|
more_text.black().on_yellow(),
|
||||||
|
ARROW_SEPARATOR.yellow().on_black(),
|
||||||
|
);
|
||||||
|
LinePart {
|
||||||
|
part: more_styled_text,
|
||||||
|
len: more_text.chars().count() + 1, // 1 for the arrow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right_more_message(tab_count_to_the_right: usize) -> LinePart {
|
||||||
|
if tab_count_to_the_right == 0 {
|
||||||
|
return LinePart {
|
||||||
|
part: String::new(),
|
||||||
|
len: 0,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let more_text = if tab_count_to_the_right < 10000 {
|
||||||
|
format!(" +{} → ", tab_count_to_the_right)
|
||||||
|
} else {
|
||||||
|
format!(" +many → ")
|
||||||
|
};
|
||||||
|
let more_styled_text = format!(
|
||||||
|
"{}{}{}",
|
||||||
|
ARROW_SEPARATOR.black().on_yellow(),
|
||||||
|
more_text.black().on_yellow(),
|
||||||
|
ARROW_SEPARATOR.yellow().on_black(),
|
||||||
|
);
|
||||||
|
LinePart {
|
||||||
|
part: more_styled_text,
|
||||||
|
len: more_text.chars().count() + 2, // 2 for the arrows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_previous_tabs_msg(
|
||||||
|
tabs_before_active: &mut Vec<LinePart>,
|
||||||
|
tabs_to_render: &mut Vec<LinePart>,
|
||||||
|
title_bar: &mut Vec<LinePart>,
|
||||||
|
cols: usize,
|
||||||
|
) {
|
||||||
|
while get_current_title_len(&tabs_to_render) +
|
||||||
|
// get_tabs_before_len(tabs_before_active.len()) >= cols {
|
||||||
|
left_more_message(tabs_before_active.len()).len
|
||||||
|
>= cols
|
||||||
|
{
|
||||||
|
tabs_before_active.push(tabs_to_render.remove(0));
|
||||||
|
}
|
||||||
|
let left_more_message = left_more_message(tabs_before_active.len());
|
||||||
|
title_bar.push(left_more_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_next_tabs_msg(
|
||||||
|
tabs_after_active: &mut Vec<LinePart>,
|
||||||
|
title_bar: &mut Vec<LinePart>,
|
||||||
|
cols: usize,
|
||||||
|
) {
|
||||||
|
while get_current_title_len(&title_bar) +
|
||||||
|
// get_tabs_after_len(tabs_after_active.len()) >= cols {
|
||||||
|
right_more_message(tabs_after_active.len()).len
|
||||||
|
>= cols
|
||||||
|
{
|
||||||
|
tabs_after_active.insert(0, title_bar.pop().unwrap());
|
||||||
|
}
|
||||||
|
let right_more_message = right_more_message(tabs_after_active.len());
|
||||||
|
title_bar.push(right_more_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tab_line(
|
||||||
|
mut all_tabs: Vec<LinePart>,
|
||||||
|
active_tab_index: usize,
|
||||||
|
cols: usize,
|
||||||
|
) -> Vec<LinePart> {
|
||||||
|
let mut tabs_to_render: Vec<LinePart> = vec![];
|
||||||
|
let mut tabs_after_active = all_tabs.split_off(active_tab_index);
|
||||||
|
let mut tabs_before_active = all_tabs;
|
||||||
|
let active_tab = if !tabs_after_active.is_empty() {
|
||||||
|
tabs_after_active.remove(0)
|
||||||
|
} else {
|
||||||
|
tabs_before_active.pop().unwrap()
|
||||||
|
};
|
||||||
|
tabs_to_render.push(active_tab);
|
||||||
|
|
||||||
|
populate_tabs_in_tab_line(
|
||||||
|
&mut tabs_before_active,
|
||||||
|
&mut tabs_after_active,
|
||||||
|
&mut tabs_to_render,
|
||||||
|
cols,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut tab_line: Vec<LinePart> = vec![];
|
||||||
|
if !tabs_before_active.is_empty() {
|
||||||
|
add_previous_tabs_msg(
|
||||||
|
&mut tabs_before_active,
|
||||||
|
&mut tabs_to_render,
|
||||||
|
&mut tab_line,
|
||||||
|
cols,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tab_line.append(&mut tabs_to_render);
|
||||||
|
if !tabs_after_active.is_empty() {
|
||||||
|
add_next_tabs_msg(&mut tabs_after_active, &mut tab_line, cols);
|
||||||
|
}
|
||||||
|
tab_line
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,25 @@
|
||||||
use colored::*;
|
mod line;
|
||||||
|
mod tab;
|
||||||
|
|
||||||
use zellij_tile::*;
|
use zellij_tile::*;
|
||||||
|
|
||||||
|
use crate::line::tab_line;
|
||||||
|
use crate::tab::nameless_tab;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LinePart {
|
||||||
|
part: String,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct State {
|
struct State {
|
||||||
active_tab_index: usize,
|
active_tab_index: usize,
|
||||||
num_tabs: usize,
|
num_tabs: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ARROW_SEPARATOR: &str = "";
|
||||||
|
|
||||||
register_tile!(State);
|
register_tile!(State);
|
||||||
|
|
||||||
impl ZellijTile for State {
|
impl ZellijTile for State {
|
||||||
|
|
@ -18,19 +31,23 @@ impl ZellijTile for State {
|
||||||
self.num_tabs = 0;
|
self.num_tabs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, _rows: usize, _cols: usize) {
|
fn draw(&mut self, _rows: usize, cols: usize) {
|
||||||
let mut s = String::new();
|
if self.num_tabs == 0 {
|
||||||
let active_tab = self.active_tab_index + 1;
|
return;
|
||||||
for i in 1..=self.num_tabs {
|
|
||||||
let tab;
|
|
||||||
if i == active_tab {
|
|
||||||
tab = format!("*{} ", i).black().bold().on_magenta();
|
|
||||||
} else {
|
|
||||||
tab = format!("-{} ", i).white();
|
|
||||||
}
|
|
||||||
s = format!("{}{}", s, tab);
|
|
||||||
}
|
}
|
||||||
println!("Tabs: {}\u{1b}[40m\u{1b}[0K", s);
|
let mut all_tabs: Vec<LinePart> = vec![];
|
||||||
|
for i in 0..self.num_tabs {
|
||||||
|
let tab = nameless_tab(i, i == self.active_tab_index);
|
||||||
|
all_tabs.push(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tab_line = tab_line(all_tabs, self.active_tab_index, cols);
|
||||||
|
|
||||||
|
let mut s = String::new();
|
||||||
|
for bar_part in tab_line {
|
||||||
|
s = format!("{}{}", s, bar_part.part);
|
||||||
|
}
|
||||||
|
println!("{}\u{1b}[40m\u{1b}[0K", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_tabs(&mut self, active_tab_index: usize, num_tabs: usize) {
|
fn update_tabs(&mut self, active_tab_index: usize, num_tabs: usize) {
|
||||||
|
|
|
||||||
52
default-tiles/tab-bar/src/tab.rs
Normal file
52
default-tiles/tab-bar/src/tab.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use colored::*;
|
||||||
|
|
||||||
|
use crate::{LinePart, ARROW_SEPARATOR};
|
||||||
|
|
||||||
|
pub fn active_tab(text: String, is_furthest_to_the_left: bool) -> LinePart {
|
||||||
|
let left_separator = if is_furthest_to_the_left {
|
||||||
|
" ".black().on_magenta()
|
||||||
|
} else {
|
||||||
|
ARROW_SEPARATOR.black().on_magenta()
|
||||||
|
};
|
||||||
|
let right_separator = ARROW_SEPARATOR.magenta().on_black();
|
||||||
|
let tab_styled_text = format!("{}{}{}", left_separator, text, right_separator)
|
||||||
|
.black()
|
||||||
|
.bold()
|
||||||
|
.on_magenta();
|
||||||
|
let tab_text_len = text.chars().count() + 2; // 2 for left and right separators
|
||||||
|
LinePart {
|
||||||
|
part: format!("{}", tab_styled_text),
|
||||||
|
len: tab_text_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn non_active_tab(text: String, is_furthest_to_the_left: bool) -> LinePart {
|
||||||
|
let left_separator = if is_furthest_to_the_left {
|
||||||
|
" ".black().on_green()
|
||||||
|
} else {
|
||||||
|
ARROW_SEPARATOR.black().on_green()
|
||||||
|
};
|
||||||
|
let right_separator = ARROW_SEPARATOR.green().on_black();
|
||||||
|
let tab_styled_text = format!("{}{}{}", left_separator, text, right_separator)
|
||||||
|
.black()
|
||||||
|
.bold()
|
||||||
|
.on_green();
|
||||||
|
let tab_text_len = text.chars().count() + 2; // 2 for the left and right separators
|
||||||
|
LinePart {
|
||||||
|
part: format!("{}", tab_styled_text),
|
||||||
|
len: tab_text_len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tab(text: String, is_active_tab: bool, is_furthest_to_the_left: bool) -> LinePart {
|
||||||
|
if is_active_tab {
|
||||||
|
active_tab(text, is_furthest_to_the_left)
|
||||||
|
} else {
|
||||||
|
non_active_tab(text, is_furthest_to_the_left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nameless_tab(index: usize, is_active_tab: bool) -> LinePart {
|
||||||
|
let tab_text = format!(" Tab #{} ", index + 1);
|
||||||
|
tab(tab_text, is_active_tab, index == 0)
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue