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, tabs_after_active: &mut Vec, tabs_to_render: &mut Vec, 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, tabs_to_render: &mut Vec, title_bar: &mut Vec, 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, title_bar: &mut Vec, 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, active_tab_index: usize, cols: usize, ) -> Vec { let mut tabs_to_render: Vec = 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 = 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 }