New tab styling (#216)

* draft

* feat(tabbar): new ui

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2021-03-03 18:52:17 +01:00 committed by GitHub
parent 955d38906d
commit 845478fe11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 247 additions and 13 deletions

View 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
}

View file

@ -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) {

View 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)
}