use ansi_term::{ ANSIStrings, Color::{Fixed, RGB}, Style, }; use zellij_tile::prelude::*; use crate::{LinePart, MORE_MSG}; fn full_length_shortcut( is_first_shortcut: bool, letter: &str, description: &str, palette: Palette, ) -> LinePart { let white_color = match palette.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let separator = if is_first_shortcut { " " } else { " / " }; let separator = Style::new().fg(white_color).paint(separator); let shortcut_len = letter.chars().count() + 3; // 2 for <>'s around shortcut, 1 for the space let shortcut_left_separator = Style::new().fg(white_color).paint("<"); let shortcut = Style::new().fg(green_color).bold().paint(letter); let shortcut_right_separator = Style::new().fg(white_color).paint("> "); let description_len = description.chars().count(); let description = Style::new().fg(white_color).bold().paint(description); let len = shortcut_len + description_len + separator.chars().count(); LinePart { part: format!( "{}", ANSIStrings(&[ separator, shortcut_left_separator, shortcut, shortcut_right_separator, description ]) ), len, } } fn first_word_shortcut( is_first_shortcut: bool, letter: &str, description: &str, palette: Palette, ) -> LinePart { let white_color = match palette.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let separator = if is_first_shortcut { " " } else { " / " }; let separator = Style::new().fg(white_color).paint(separator); let shortcut_len = letter.chars().count() + 3; // 2 for <>'s around shortcut, 1 for the space let shortcut_left_separator = Style::new().fg(white_color).paint("<"); let shortcut = Style::new().fg(green_color).bold().paint(letter); let shortcut_right_separator = Style::new().fg(white_color).paint("> "); let description_first_word = description.split(' ').next().unwrap_or(""); let description_first_word_length = description_first_word.chars().count(); let description_first_word = Style::new() .fg(white_color) .bold() .paint(description_first_word); let len = shortcut_len + description_first_word_length + separator.chars().count(); LinePart { part: format!( "{}", ANSIStrings(&[ separator, shortcut_left_separator, shortcut, shortcut_right_separator, description_first_word, ]) ), len, } } fn quicknav_full(palette: Palette) -> LinePart { let text_first_part = " Tip: "; let alt = "Alt"; let text_second_part = " + "; let new_pane_shortcut = "n"; let text_third_part = " => open new pane. "; let second_alt = "Alt"; let text_fourth_part = " + "; let brackets_navigation = "[]"; let text_fifth_part = " or "; let hjkl_navigation = "hjkl"; let text_sixths_part = " => navigate between panes."; let len = text_first_part.chars().count() + alt.chars().count() + text_second_part.chars().count() + new_pane_shortcut.chars().count() + text_third_part.chars().count() + second_alt.chars().count() + text_fourth_part.chars().count() + brackets_navigation.chars().count() + text_fifth_part.chars().count() + hjkl_navigation.chars().count() + text_sixths_part.chars().count(); let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let orange_color = match palette.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; LinePart { part: format!( "{}{}{}{}{}{}{}{}{}{}{}", text_first_part, Style::new().fg(orange_color).bold().paint(alt), text_second_part, Style::new().fg(green_color).bold().paint(new_pane_shortcut), text_third_part, Style::new().fg(orange_color).bold().paint(second_alt), text_fourth_part, Style::new() .fg(green_color) .bold() .paint(brackets_navigation), text_fifth_part, Style::new().fg(green_color).bold().paint(hjkl_navigation), text_sixths_part, ), len, } } fn quicknav_medium(palette: Palette) -> LinePart { let text_first_part = " Tip: "; let alt = "Alt"; let text_second_part = " + "; let new_pane_shortcut = "n"; let text_third_part = " => new pane. "; let second_alt = "Alt"; let text_fourth_part = " + "; let brackets_navigation = "[]"; let text_fifth_part = " or "; let hjkl_navigation = "hjkl"; let text_sixths_part = " => navigate."; let len = text_first_part.chars().count() + alt.chars().count() + text_second_part.chars().count() + new_pane_shortcut.chars().count() + text_third_part.chars().count() + second_alt.chars().count() + text_fourth_part.chars().count() + brackets_navigation.chars().count() + text_fifth_part.chars().count() + hjkl_navigation.chars().count() + text_sixths_part.chars().count(); let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let orange_color = match palette.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; LinePart { part: format!( "{}{}{}{}{}{}{}{}{}{}{}", text_first_part, Style::new().fg(orange_color).bold().paint(alt), text_second_part, Style::new().fg(green_color).bold().paint(new_pane_shortcut), text_third_part, Style::new().fg(orange_color).bold().paint(second_alt), text_fourth_part, Style::new() .fg(green_color) .bold() .paint(brackets_navigation), text_fifth_part, Style::new().fg(green_color).bold().paint(hjkl_navigation), text_sixths_part, ), len, } } fn quicknav_short(palette: Palette) -> LinePart { let text_first_part = " QuickNav: "; let alt = "Alt"; let text_second_part = " + "; let new_pane_shortcut = "n"; let text_third_part = "/"; let brackets_navigation = "[]"; let text_fifth_part = "/"; let hjkl_navigation = "hjkl"; let len = text_first_part.chars().count() + alt.chars().count() + text_second_part.chars().count() + new_pane_shortcut.chars().count() + text_third_part.chars().count() + brackets_navigation.chars().count() + text_fifth_part.chars().count() + hjkl_navigation.chars().count(); let green_color = match palette.green { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let orange_color = match palette.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; LinePart { part: format!( "{}{}{}{}{}{}{}{}", text_first_part, Style::new().fg(orange_color).bold().paint(alt), text_second_part, Style::new().fg(green_color).bold().paint(new_pane_shortcut), text_third_part, Style::new() .fg(green_color) .bold() .paint(brackets_navigation), text_fifth_part, Style::new().fg(green_color).bold().paint(hjkl_navigation), ), len, } } fn locked_interface_indication(palette: Palette) -> LinePart { let locked_text = " -- INTERFACE LOCKED -- "; let locked_text_len = locked_text.chars().count(); let white_color = match palette.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let locked_styled_text = Style::new().fg(white_color).bold().paint(locked_text); LinePart { part: format!("{}", locked_styled_text), len: locked_text_len, } } fn select_pane_shortcut(is_first_shortcut: bool, palette: Palette) -> LinePart { let shortcut = "ENTER"; let description = "Select pane"; let separator = if is_first_shortcut { " " } else { " / " }; let white_color = match palette.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let orange_color = match palette.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; let separator = Style::new().fg(white_color).paint(separator); let shortcut_len = shortcut.chars().count() + 3; // 2 for <>'s around shortcut, 1 for the space let shortcut_left_separator = Style::new().fg(white_color).paint("<"); let shortcut = Style::new().fg(orange_color).bold().paint(shortcut); let shortcut_right_separator = Style::new().fg(white_color).paint("> "); let description_len = description.chars().count(); let description = Style::new().fg(white_color).bold().paint(description); let len = shortcut_len + description_len + separator.chars().count(); LinePart { part: format!( "{}", ANSIStrings(&[ separator, shortcut_left_separator, shortcut, shortcut_right_separator, description ]) ), len, } } fn full_shortcut_list(help: &ModeInfo) -> LinePart { match help.mode { InputMode::Normal => quicknav_full(help.palette), InputMode::Locked => locked_interface_indication(help.palette), _ => { let mut line_part = LinePart::default(); for (i, (letter, description)) in help.keybinds.iter().enumerate() { let shortcut = full_length_shortcut(i == 0, letter, description, help.palette); line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut,); } let select_pane_shortcut = select_pane_shortcut(help.keybinds.is_empty(), help.palette); line_part.len += select_pane_shortcut.len; line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,); line_part } } } fn shortened_shortcut_list(help: &ModeInfo) -> LinePart { match help.mode { InputMode::Normal => quicknav_medium(help.palette), InputMode::Locked => locked_interface_indication(help.palette), _ => { let mut line_part = LinePart::default(); for (i, (letter, description)) in help.keybinds.iter().enumerate() { let shortcut = first_word_shortcut(i == 0, letter, description, help.palette); line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut,); } let select_pane_shortcut = select_pane_shortcut(help.keybinds.is_empty(), help.palette); line_part.len += select_pane_shortcut.len; line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,); line_part } } } fn best_effort_shortcut_list(help: &ModeInfo, max_len: usize) -> LinePart { match help.mode { InputMode::Normal => { let line_part = quicknav_short(help.palette); if line_part.len <= max_len { line_part } else { LinePart::default() } } InputMode::Locked => { let line_part = locked_interface_indication(help.palette); if line_part.len <= max_len { line_part } else { LinePart::default() } } _ => { let mut line_part = LinePart::default(); for (i, (letter, description)) in help.keybinds.iter().enumerate() { let shortcut = first_word_shortcut(i == 0, letter, description, help.palette); if line_part.len + shortcut.len + MORE_MSG.chars().count() > max_len { // TODO: better line_part.part = format!("{}{}", line_part.part, MORE_MSG); line_part.len += MORE_MSG.chars().count(); break; } line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut); } let select_pane_shortcut = select_pane_shortcut(help.keybinds.is_empty(), help.palette); if line_part.len + select_pane_shortcut.len <= max_len { line_part.len += select_pane_shortcut.len; line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,); } line_part } } } pub fn keybinds(help: &ModeInfo, max_width: usize) -> LinePart { let full_shortcut_list = full_shortcut_list(help); if full_shortcut_list.len <= max_width { return full_shortcut_list; } let shortened_shortcut_list = shortened_shortcut_list(help); if shortened_shortcut_list.len <= max_width { return shortened_shortcut_list; } best_effort_shortcut_list(help, max_width) }