zellij/default-tiles/tab-bar/src/line.rs
Aram Drevekenin 8d0ff0fe40
feat(input): new shortcuts and ui (#220)
* feat(statusbar): new shortcuts

* feat(input): new shortcuts and ui

* style(fmt): rustfmt
2021-03-11 16:03:28 +01:00

180 lines
5.8 KiB
Rust

use crate::colors::{BLACK, GRAY, ORANGE, WHITE};
use ansi_term::{ANSIStrings, Style};
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 ")
};
// 238
let more_text_len = more_text.chars().count() + 2; // 2 for the arrows
let left_separator = Style::new().fg(GRAY).on(ORANGE).paint(ARROW_SEPARATOR);
let more_styled_text = Style::new().fg(BLACK).on(ORANGE).bold().paint(more_text);
let right_separator = Style::new().fg(ORANGE).on(GRAY).paint(ARROW_SEPARATOR);
let more_styled_text = format!(
"{}",
ANSIStrings(&[left_separator, more_styled_text, right_separator,])
);
LinePart {
part: more_styled_text,
len: more_text_len,
}
}
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_text_len = more_text.chars().count() + 1; // 2 for the arrow
let left_separator = Style::new().fg(GRAY).on(ORANGE).paint(ARROW_SEPARATOR);
let more_styled_text = Style::new().fg(BLACK).on(ORANGE).bold().paint(more_text);
let right_separator = Style::new().fg(ORANGE).on(GRAY).paint(ARROW_SEPARATOR);
let more_styled_text = format!(
"{}",
ANSIStrings(&[left_separator, more_styled_text, right_separator,])
);
LinePart {
part: more_styled_text,
len: more_text_len,
}
}
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) + 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) + 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);
}
fn tab_line_prefix() -> LinePart {
let prefix_text = format!(" Zellij ");
let prefix_text_len = prefix_text.chars().count();
let prefix_styled_text = Style::new().fg(WHITE).on(GRAY).bold().paint(prefix_text);
LinePart {
part: format!("{}", prefix_styled_text),
len: prefix_text_len,
}
}
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);
let prefix = tab_line_prefix();
populate_tabs_in_tab_line(
&mut tabs_before_active,
&mut tabs_after_active,
&mut tabs_to_render,
cols - prefix.len,
);
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 - prefix.len,
);
}
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 - prefix.len);
}
tab_line.insert(0, prefix);
tab_line
}