diff options
| author | Aram Drevekenin <aram@poor.dev> | 2024-02-06 14:26:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-06 14:26:14 +0100 |
| commit | 6b20a958f4e8db5614fffb27fe5d32f07ddfe855 (patch) | |
| tree | c8383fb7941b5e0c23cb348a655f2ea0fafd8668 /default-plugins/session-manager/src/ui | |
| parent | docs(readme): add sponsor (diff) | |
| download | sl0ppij-6b20a958f4e8db5614fffb27fe5d32f07ddfe855.tar.gz sl0ppij-6b20a958f4e8db5614fffb27fe5d32f07ddfe855.tar.xz sl0ppij-6b20a958f4e8db5614fffb27fe5d32f07ddfe855.zip | |
feat(sessions): welcome screen (#3112)
* prototype - can send layout name for new session from session-manager
* feat(sessions): ui for selecting layout for new session in the session-manager
* fix: send available layouts to plugins
* make tests compile
* fix tests
* improve ui
* fix: respect built-in layouts
* ui for built-in layouts
* some cleanups
* style(fmt): rustfmt
* welcome screen ui
* fix: make sure layout config is not shared between sessions
* allow disconnecting other users from current session and killing other sessions
* fix: respect default layout
* add welcome screen layout
* tests(plugins): new api methods
* fix(session-manager): do not quit welcome screen on esc and break
* fix(plugins): adjust permissions
* style(fmt): rustfmt
* style(fmt): fix warnings
Diffstat (limited to 'default-plugins/session-manager/src/ui')
| -rw-r--r-- | default-plugins/session-manager/src/ui/components.rs | 382 | ||||
| -rw-r--r-- | default-plugins/session-manager/src/ui/mod.rs | 7 | ||||
| -rw-r--r-- | default-plugins/session-manager/src/ui/welcome_screen.rs | 168 |
3 files changed, 440 insertions, 117 deletions
diff --git a/default-plugins/session-manager/src/ui/components.rs b/default-plugins/session-manager/src/ui/components.rs index 4d9839c0..d3c4afe8 100644 --- a/default-plugins/session-manager/src/ui/components.rs +++ b/default-plugins/session-manager/src/ui/components.rs @@ -3,6 +3,7 @@ use unicode_width::UnicodeWidthStr; use zellij_tile::prelude::*; use crate::ui::{PaneUiInfo, SessionUiInfo, TabUiInfo}; +use crate::{ActiveScreen, NewSessionInfo}; #[derive(Debug)] pub struct ListItem { @@ -292,18 +293,45 @@ impl LineToRender { pub fn append(&mut self, to_append: &str) { self.line.push_str(to_append) } - pub fn make_selected(&mut self) { + pub fn make_selected_as_search(&mut self, add_arrows: bool) { self.is_selected = true; + let arrows = if add_arrows { + self.colors.magenta(" <↓↑> ") + } else { + " ".to_owned() + }; + match self.colors.palette.bg { + PaletteColor::EightBit(byte) => { + self.line = format!( + "\u{1b}[48;5;{byte}m\u{1b}[K\u{1b}[48;5;{byte}m{arrows}{}", + self.line + ); + }, + PaletteColor::Rgb((r, g, b)) => { + self.line = format!( + "\u{1b}[48;2;{};{};{}m\u{1b}[K\u{1b}[48;2;{};{};{}m{arrows}{}", + r, g, b, r, g, b, self.line + ); + }, + } + } + pub fn make_selected(&mut self, add_arrows: bool) { + self.is_selected = true; + let arrows = if add_arrows { + self.colors.magenta("<←↓↑→>") + } else { + " ".to_owned() + }; match self.colors.palette.bg { PaletteColor::EightBit(byte) => { self.line = format!( - "\u{1b}[48;5;{byte}m\u{1b}[K\r\u{1b}[48;5;{byte}m{}", + "\u{1b}[48;5;{byte}m\u{1b}[K\u{1b}[48;5;{byte}m{arrows}{}", self.line ); }, PaletteColor::Rgb((r, g, b)) => { self.line = format!( - "\u{1b}[48;2;{};{};{}m\u{1b}[K\r\u{1b}[48;2;{};{};{}m{}", + "\u{1b}[48;2;{};{};{}m\u{1b}[K\u{1b}[48;2;{};{};{}m{arrows}{}", r, g, b, r, g, b, self.line ); }, @@ -323,7 +351,7 @@ impl LineToRender { if self.is_selected { self.line.clone() } else { - format!("\u{1b}[49m{}", line) + format!("\u{1b}[49m {}", line) } } pub fn add_truncated_results(&mut self, result_count: usize) { @@ -475,151 +503,275 @@ pub fn minimize_lines( (start_index, anchor_index, end_index, line_count_to_remove) } -pub fn render_prompt(typing_session_name: bool, search_term: &str, colors: Colors) { - if !typing_session_name { - let prompt = colors.bold(&format!("> {}_", search_term)); - println!("\u{1b}[H{}\n", prompt); - } else { - println!("\n"); - } +pub fn render_prompt(search_term: &str, colors: Colors, x: usize, y: usize) { + let prompt = colors.green(&format!("Search:")); + let search_term = colors.bold(&format!("{}_", search_term)); + println!("\u{1b}[{};{}H{} {}\n", y + 1, x, prompt, search_term); } -pub fn render_resurrection_toggle(cols: usize, resurrection_screen_is_active: bool) { +pub fn render_screen_toggle(active_screen: ActiveScreen, x: usize, y: usize, max_cols: usize) { let key_indication_text = "<TAB>"; - let running_sessions_text = "Running"; - let exited_sessions_text = "Exited"; + let (new_session_text, running_sessions_text, exited_sessions_text) = if max_cols > 66 { + ("New Session", "Attach to Session", "Resurrect Session") + } else { + ("New", "Attach", "Resurrect") + }; let key_indication_len = key_indication_text.chars().count() + 1; - let first_ribbon_length = running_sessions_text.chars().count() + 4; - let second_ribbon_length = exited_sessions_text.chars().count() + 4; - let key_indication_x = - cols.saturating_sub(key_indication_len + first_ribbon_length + second_ribbon_length); + let first_ribbon_length = new_session_text.chars().count() + 4; + let second_ribbon_length = running_sessions_text.chars().count() + 4; + let third_ribbon_length = exited_sessions_text.chars().count() + 4; + let total_len = + key_indication_len + first_ribbon_length + second_ribbon_length + third_ribbon_length; + let key_indication_x = x; let first_ribbon_x = key_indication_x + key_indication_len; let second_ribbon_x = first_ribbon_x + first_ribbon_length; + let third_ribbon_x = second_ribbon_x + second_ribbon_length; + let mut new_session_text = Text::new(new_session_text); + let mut running_sessions_text = Text::new(running_sessions_text); + let mut exited_sessions_text = Text::new(exited_sessions_text); + match active_screen { + ActiveScreen::NewSession => { + new_session_text = new_session_text.selected(); + }, + ActiveScreen::AttachToSession => { + running_sessions_text = running_sessions_text.selected(); + }, + ActiveScreen::ResurrectSession => { + exited_sessions_text = exited_sessions_text.selected(); + }, + } print_text_with_coordinates( Text::new(key_indication_text).color_range(3, ..), key_indication_x, - 0, + y, None, None, ); - if resurrection_screen_is_active { - print_ribbon_with_coordinates( - Text::new(running_sessions_text), - first_ribbon_x, - 0, - None, - None, - ); - print_ribbon_with_coordinates( - Text::new(exited_sessions_text).selected(), - second_ribbon_x, - 0, - None, - None, - ); - } else { - print_ribbon_with_coordinates( - Text::new(running_sessions_text).selected(), - first_ribbon_x, - 0, - None, - None, - ); - print_ribbon_with_coordinates( - Text::new(exited_sessions_text), - second_ribbon_x, - 0, - None, - None, - ); - } + print_ribbon_with_coordinates(new_session_text, first_ribbon_x, y, None, None); + print_ribbon_with_coordinates(running_sessions_text, second_ribbon_x, y, None, None); + print_ribbon_with_coordinates(exited_sessions_text, third_ribbon_x, y, None, None); } -pub fn render_new_session_line(session_name: &Option<String>, is_searching: bool, colors: Colors) { - if is_searching { - return; - } - let new_session_shortcut_text = "<Ctrl w>"; - let new_session_shortcut = colors.magenta(new_session_shortcut_text); - let new_session = colors.bold("New session"); +pub fn render_new_session_block( + new_session_info: &NewSessionInfo, + colors: Colors, + max_rows_of_new_session_block: usize, + max_cols_of_new_session_block: usize, + x: usize, + y: usize, +) { let enter = colors.magenta("<ENTER>"); - match session_name { - Some(session_name) => { + if new_session_info.entering_new_session_name() { + let prompt = "New session name:"; + let long_instruction = "when done, blank for random"; + let new_session_name = new_session_info.name(); + if max_cols_of_new_session_block + > prompt.width() + long_instruction.width() + new_session_name.width() + 15 + { println!( - "\u{1b}[m > {}_ ({}, {} when done)", - colors.orange(session_name), - colors.bold("Type optional name"), - enter + "\u{1b}[m{}{} {}_ ({} {})", + format!("\u{1b}[{};{}H", y + 1, x + 1), + colors.green(prompt), + colors.orange(&new_session_name), + enter, + long_instruction, ); - }, - None => { - println!("\u{1b}[m > {new_session_shortcut} - {new_session}"); - }, + } else { + println!( + "\u{1b}[m{}{} {}_ {}", + format!("\u{1b}[{};{}H", y + 1, x + 1), + colors.green(prompt), + colors.orange(&new_session_name), + enter, + ); + } + } else if new_session_info.entering_layout_search_term() { + let new_session_name = if new_session_info.name().is_empty() { + "<RANDOM>" + } else { + new_session_info.name() + }; + let prompt = "New session name:"; + let long_instruction = "to correct"; + let esc = colors.magenta("<ESC>"); + if max_cols_of_new_session_block + > prompt.width() + long_instruction.width() + new_session_name.width() + 15 + { + println!( + "\u{1b}[m{}{}: {} ({} to correct)", + format!("\u{1b}[{};{}H", y + 1, x + 1), + colors.green("New session name"), + colors.orange(new_session_name), + esc, + ); + } else { + println!( + "\u{1b}[m{}{}: {} {}", + format!("\u{1b}[{};{}H", y + 1, x + 1), + colors.green("New session name"), + colors.orange(new_session_name), + esc, + ); + } + render_layout_selection_list( + new_session_info, + max_rows_of_new_session_block.saturating_sub(1), + max_cols_of_new_session_block, + x, + y + 1, + ); } } -pub fn render_error(error_text: &str, rows: usize, columns: usize) { +pub fn render_layout_selection_list( + new_session_info: &NewSessionInfo, + max_rows_of_new_session_block: usize, + max_cols_of_new_session_block: usize, + x: usize, + y: usize, +) { + let layout_search_term = new_session_info.layout_search_term(); + let search_term_len = layout_search_term.width(); + let layout_indication_line = if max_cols_of_new_session_block > 73 + search_term_len { + Text::new(format!( + "New session layout: {}_ (Search and select from list, <ENTER> when done)", + layout_search_term + )) + .color_range(2, ..20 + search_term_len) + .color_range(3, 20..20 + search_term_len) + .color_range(3, 52 + search_term_len..59 + search_term_len) + } else { + Text::new(format!( + "New session layout: {}_ <ENTER>", + layout_search_term + )) + .color_range(2, ..20 + search_term_len) + .color_range(3, 20..20 + search_term_len) + .color_range(3, 22 + search_term_len..) + }; + print_text_with_coordinates(layout_indication_line, x, y + 1, None, None); + println!(); + let mut table = Table::new(); + for (i, (layout_info, indices, is_selected)) in + new_session_info.layouts_to_render().into_iter().enumerate() + { + let layout_name = layout_info.name(); + let layout_name_len = layout_name.width(); + let is_builtin = layout_info.is_builtin(); + if i > max_rows_of_new_session_block { + break; + } else { + let mut layout_cell = if is_builtin { + Text::new(format!("{} (built-in)", layout_name)) + .color_range(1, 0..layout_name_len) + .color_range(0, layout_name_len + 1..) + .color_indices(3, indices) + } else { + Text::new(format!("{}", layout_name)) + .color_range(1, ..) + .color_indices(3, indices) + }; + if is_selected { + layout_cell = layout_cell.selected(); + } + let arrow_cell = if is_selected { + Text::new(format!("<↓↑>")).selected().color_range(3, ..) + } else { + Text::new(format!(" ")).color_range(3, ..) + }; + table = table.add_styled_row(vec![arrow_cell, layout_cell]); + } + } + print_table_with_coordinates(table, x, y + 3, None, None); +} + +pub fn render_error(error_text: &str, rows: usize, columns: usize, x: usize, y: usize) { print_text_with_coordinates( Text::new(format!("Error: {}", error_text)).color_range(3, ..), - 0, - rows, + x, + y + rows, Some(columns), None, ); } -pub fn render_renaming_session_screen(new_session_name: &str, rows: usize, columns: usize) { +pub fn render_renaming_session_screen( + new_session_name: &str, + rows: usize, + columns: usize, + x: usize, + y: usize, +) { if rows == 0 || columns == 0 { return; } - let prompt_text = "NEW NAME FOR CURRENT SESSION"; - let new_session_name = format!("{}_", new_session_name); - let prompt_y_location = (rows / 2).saturating_sub(1); - let session_name_y_location = (rows / 2) + 1; - let prompt_x_location = columns.saturating_sub(prompt_text.chars().count()) / 2; - let session_name_x_location = columns.saturating_sub(new_session_name.chars().count()) / 2; - print_text_with_coordinates( - Text::new(prompt_text).color_range(0, ..), - prompt_x_location, - prompt_y_location, - None, - None, - ); - print_text_with_coordinates( - Text::new(new_session_name).color_range(3, ..), - session_name_x_location, - session_name_y_location, - None, - None, + let text = Text::new(format!( + "New name for current session: {}_ (<ENTER> when done)", + new_session_name + )) + .color_range(2, ..29) + .color_range( + 3, + 33 + new_session_name.width()..40 + new_session_name.width(), ); + print_text_with_coordinates(text, x, y, None, None); } -pub fn render_controls_line(is_searching: bool, row: usize, max_cols: usize, colors: Colors) { - let (arrows, navigate) = if is_searching { - (colors.magenta("<↓↑>"), colors.bold("Navigate")) - } else { - (colors.magenta("<←↓↑→>"), colors.bold("Navigate and Expand")) - }; - let rename = colors.magenta("<Ctrl r>"); - let rename_text = colors.bold("Rename session"); - let enter = colors.magenta("<ENTER>"); - let select = colors.bold("Switch to selected"); - let esc = colors.magenta("<ESC>"); - let to_hide = colors.bold("Hide"); +pub fn render_controls_line( + active_screen: ActiveScreen, + max_cols: usize, + colors: Colors, + x: usize, + y: usize, +) { + match active_screen { + ActiveScreen::NewSession => { + if max_cols >= 50 { + print!( + "\u{1b}[m\u{1b}[{y};{x}H\u{1b}[1mHelp: Fill in the form to start a new session." + ); + } + }, + ActiveScreen::AttachToSession => { + let arrows = colors.magenta("<←↓↑→>"); + let navigate = colors.bold("Navigate"); + let enter = colors.magenta("<ENTER>"); + let select = colors.bold("Attach"); + let rename = colors.magenta("<Ctrl r>"); + let rename_text = colors.bold("Rename"); + let disconnect = colors.magenta("<Ctrl x>"); + let disconnect_text = colors.bold("Disconnect others"); + let kill = colors.magenta("<Del>"); + let kill_text = colors.bold("Kill"); + let kill_all = colors.magenta("<Ctrl d>"); + let kill_all_text = colors.bold("Kill all"); - if max_cols >= 104 { - print!( - "\u{1b}[m\u{1b}[{row}HHelp: {arrows} - {navigate}, {enter} - {select}, {rename} - {rename_text}, {esc} - {to_hide}" - ); - } else if max_cols >= 73 { - let navigate = colors.bold("Navigate"); - let select = colors.bold("Switch"); - let rename_text = colors.bold("Rename"); - print!( - "\u{1b}[m\u{1b}[{row}HHelp: {arrows} - {navigate}, {enter} - {select}, {rename} - {rename_text}, {esc} - {to_hide}" - ); - } else if max_cols >= 28 { - print!("\u{1b}[m\u{1b}[{row}H{arrows}/{enter}/{rename}/{esc}"); + if max_cols > 90 { + print!( + "\u{1b}[m\u{1b}[{y};{x}HHelp: {rename} - {rename_text}, {disconnect} - {disconnect_text}, {kill} - {kill_text}, {kill_all} - {kill_all_text}" + ); + } else if max_cols >= 28 { + print!("\u{1b}[m\u{1b}[{y};{x}H{rename}/{disconnect}/{kill}/{kill_all}"); + } + }, + ActiveScreen::ResurrectSession => { + let arrows = colors.magenta("<↓↑>"); + let navigate = colors.bold("Navigate"); + let enter = colors.magenta("<ENTER>"); + let select = colors.bold("Resurrect"); + let del = colors.magenta("<DEL>"); + let del_text = colors.bold("Delete"); + let del_all = colors.magenta("<Ctrl d>"); + let del_all_text = colors.bold("Delete all"); + + if max_cols > 83 { + print!( + "\u{1b}[m\u{1b}[{y};{x}HHelp: {arrows} - {navigate}, {enter} - {select}, {del} - {del_text}, {del_all} - {del_all_text}" + ); + } else if max_cols >= 28 { + print!("\u{1b}[m\u{1b}[{y};{x}H{arrows}/{enter}/{del}/{del_all}"); + } + }, } } diff --git a/default-plugins/session-manager/src/ui/mod.rs b/default-plugins/session-manager/src/ui/mod.rs index 94a1a8a7..b86db946 100644 --- a/default-plugins/session-manager/src/ui/mod.rs +++ b/default-plugins/session-manager/src/ui/mod.rs @@ -1,4 +1,5 @@ pub mod components; +pub mod welcome_screen; use zellij_tile::prelude::*; use crate::session_list::{SelectedIndex, SessionList}; @@ -29,7 +30,7 @@ macro_rules! render_assets { if $selected_index.is_some() && !$has_deeper_selected_assets { let mut selected_asset: LineToRender = selected_asset.as_line_to_render(current_index, $max_cols, $colors); - selected_asset.make_selected(); + selected_asset.make_selected(true); selected_asset.add_truncated_results(truncated_result_count_above); if anchor_asset_index + 1 >= end_index { // no more results below, let's add the more indication if we need to @@ -76,8 +77,10 @@ impl SessionList { if lines_to_render.len() + result.lines_to_render() <= max_rows { let mut result_lines = result.render(max_cols); if Some(i) == self.selected_search_index { + let mut render_arrows = true; for line_to_render in result_lines.iter_mut() { - line_to_render.make_selected(); + line_to_render.make_selected_as_search(render_arrows); + render_arrows = false; // only render arrows on the first search result } } lines_to_render.append(&mut result_lines); diff --git a/default-plugins/session-manager/src/ui/welcome_screen.rs b/default-plugins/session-manager/src/ui/welcome_screen.rs new file mode 100644 index 00000000..ccf20c50 --- /dev/null +++ b/default-plugins/session-manager/src/ui/welcome_screen.rs @@ -0,0 +1,168 @@ +static BANNER: &str = " +██╗ ██╗██╗ ███████╗██████╗ ██████╗ ███╗ ███╗ ███████╗███████╗██╗ ██╗ ██╗ ██╗██╗ +██║ ██║██║ ██╔════╝██╔══██╗██╔═══██╗████╗ ████║ ╚══███╔╝██╔════╝██║ ██║ ██║ ██║██║ +███████║██║ █████╗ ██████╔╝██║ ██║██╔████╔██║ ███╔╝ █████╗ ██║ ██║ ██║ ██║██║ +██╔══██║██║ ██╔══╝ ██╔══██╗██║ ██║██║╚██╔╝██║ ███╔╝ ██╔══╝ ██║ ██║ ██║██ ██║╚═╝ +██║ ██║██║ ██║ ██║ ██║╚██████╔╝██║ ╚═╝ ██║ ███████╗███████╗███████╗███████╗██║╚█████╔╝██╗ +╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚══════╝╚═╝ ╚════╝ ╚═╝ +"; + +static SMALL_BANNER: &str = " +██╗ ██╗██╗ ██╗ +██║ ██║██║ ██║ +███████║██║ ██║ +██╔══██║██║ ╚═╝ +██║ ██║██║ ██╗ +╚═╝ ╚═╝╚═╝ ╚═╝ +"; + +static MEDIUM_BANNER: &str = " +██╗ ██╗██╗ ████████╗██╗ ██╗███████╗██████╗ ███████╗ ██╗ +██║ ██║██║ ╚══██╔══╝██║ ██║██╔════╝██╔══██╗██╔════╝ ██║ +███████║██║ ██║ ███████║█████╗ ██████╔╝█████╗ ██║ +██╔══██║██║ ██║ ██╔══██║██╔══╝ ██╔══██╗██╔══╝ ╚═╝ +██║ ██║██║ ██║ ██║ ██║███████╗██║ ██║███████╗ ██╗ +╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝ ╚═╝ +"; + +pub fn render_banner(x: usize, y: usize, rows: usize, cols: usize) { + if rows >= 8 { + if cols > 100 { + println!("\u{1b}[{}H", y + rows.saturating_sub(8) / 2); + for line in BANNER.lines() { + println!("\u{1b}[{}C{}", x.saturating_sub(1), line); + } + } else if cols > 63 { + println!("\u{1b}[{}H", y + rows.saturating_sub(8) / 2); + let x = (cols.saturating_sub(63) as f64 / 2.0) as usize; + for line in MEDIUM_BANNER.lines() { + println!("\u{1b}[{}C{}", x, line); + } + } else { + println!("\u{1b}[{}H", y + rows.saturating_sub(8) / 2); + let x = (cols.saturating_sub(18) as f64 / 2.0) as usize; + for line in SMALL_BANNER.lines() { + println!("\u{1b}[{}C{}", x, line); + } + } + } else if rows > 2 { + println!( + "\u{1b}[{};{}H\u{1b}[1mHi from Zellij!", + (y + rows / 2) + 1, + (x + cols.saturating_sub(15) / 2).saturating_sub(1) + ); + } +} + +pub fn render_welcome_boundaries(rows: usize, cols: usize) { + let width_of_main_menu = std::cmp::min(cols, 101); + let has_room_for_logos = cols.saturating_sub(width_of_main_menu) > 100; + let left_boundary_x = (cols.saturating_sub(width_of_main_menu) as f64 / 2.0).floor() as usize; + let right_boundary_x = left_boundary_x + width_of_main_menu; + let y_starting_point = rows.saturating_sub(15) / 2; + let middle_row = + (y_starting_point + rows.saturating_sub(y_starting_point) / 2).saturating_sub(1); + for i in y_starting_point..rows { + if i == middle_row { + if has_room_for_logos { + print!("\u{1b}[{};{}H┤", i + 1, left_boundary_x + 1); + print!( + "\u{1b}[m\u{1b}[{};{}H├\u{1b}[K", + i + 1, + right_boundary_x + 1 + ); + print!("\u{1b}[{};{}H", i + 1, left_boundary_x.saturating_sub(9)); + for _ in 0..10 { + print!("─"); + } + print!("\u{1b}[{};{}H", i + 1, right_boundary_x + 2); + for _ in 0..10 { + print!("─"); + } + } else { + print!("\u{1b}[{};{}H│", i + 1, left_boundary_x + 1); + print!( + "\u{1b}[m\u{1b}[{};{}H│\u{1b}[K", + i + 1, + right_boundary_x + 1 + ); + } + } else { + if i == y_starting_point { + print!("\u{1b}[{};{}H┌", i + 1, left_boundary_x + 1); + print!( + "\u{1b}[m\u{1b}[{};{}H┐\u{1b}[K", + i + 1, + right_boundary_x + 1 + ); + } else if i == rows.saturating_sub(1) { + print!("\u{1b}[{};{}H└", i + 1, left_boundary_x + 1); + print!( + "\u{1b}[m\u{1b}[{};{}H┘\u{1b}[K", + i + 1, + right_boundary_x + 1 + ); + } else { + print!("\u{1b}[{};{}H│", i + 1, left_boundary_x + 1); + print!( + "\u{1b}[m\u{1b}[{};{}H│\u{1b}[K", + i + 1, + right_boundary_x + 1 + ); // this includes some + // ANSI magic to delete + // everything after this + // boundary in order to + // fix some rendering + // bugs in the legacy + // components of this + // plugin + } + } + } + if rows.saturating_sub(y_starting_point) > 25 && has_room_for_logos { + for (i, line) in LOGO.lines().enumerate() { + print!( + "\u{1b}[{};{}H{}", + middle_row.saturating_sub(12) + i, + 0, + line + ); + } + for (i, line) in LOGO.lines().enumerate() { + print!( + "\u{1b}[{};{}H{}", + middle_row.saturating_sub(12) + i, + cols.saturating_sub(47), + line + ); + } + } +} +static LOGO: &str = r#" [38;2;0;0;0m + [38;2;0;0;0m + [38;2;0;0;0m [38;2;160;186;139m_[38;2;142;164;125my[38;2;148;171;129m$ [38;2;79;88;77my[38;2;151;175;132m@[38;2;131;151;117mg[38;2;163;189;141m_ + [38;2;0;0;0m [38;2;114;130;103my[38;2;156;181;136ma[38;2;159;184;138m@[38;2;163;189;141m@@@[38;2;73;82;73mL[38;2;103;117;95m4[38;2;163;189;141m@@@@[38;2;160;185;138mg[38;2;123;141;110my[38;2;110;125;100m_ + [38;2;0;0;0m [38;2;82;92;79mu[38;2;163;189;141m@@@@@@[38;2;160;185;138mF [38;2;85;96;82m"[38;2;143;165;126m@[38;2;163;189;141m@@@@@@[38;2;148;171;129m@[38;2;145;167;127my[38;2;162;188;140m_ + [38;2;0;0;0m [38;2;190;97;107m_[38;2;165;84;95ma[38;2;174;88;99m@[38;2;190;97;107m@[38;2;117;59;73m, [38;2;159;184;138m@[38;2;163;189;141m@[38;2;160;186;139m@[38;2;147;170;129mP[38;2;163;189;141m~[38;2;66;73;67m` [38;2;126;159;190m_[38;2;118;149;179m_ [38;2;106;121;97m~[38;2;120;138;108mT[38;2;135;156;120m@[38;2;163;189;141m@@@@@@[38;2;162;188;140m@[38;2;132;152;117mg + [38;2;0;0;0m [38;2;130;66;79m_[38;2;144;73;86my[38;2;187;95;105mg[38;2;189;96;106m@[38;2;190;97;107m@@@@[38;2;174;89;99m$ [38;2;118;136;107m"[38;2;128;147;114m~ [38;2;89;110;138m_[38;2;97;120;149my[38;2;124;156;187mg[38;2;125;158;189m@[38;2;126;159;190m@@[38;2;123;156;186m@[38;2;112;140;170mg[38;2;84;103;131my [38;2;120;138;108m`[38;2;162;188;140m~[38;2;128;148;115mP[38;2;146;168;128mR[38;2;135;155;119m@[38;2;139;160;122mF[38;2;158;183;137m~[38;2;233;202;138m_[38;2;196;170;119my[38;2;234;203;139mg[38;2;217;188;130mg[38;2;180;155;111my[38;2;166;143;104m_ + [38;2;0;0;0m [38;2;168;85;97my[38;2;174;89;99m$[38;2;190;97;107m@@@@@@[38;2;184;94;104mP[38;2;139;70;83mF [38;2;125;158;189m_[38;2;112;141;171my[38;2;116;146;176m$[38;2;126;159;190m@@@@@@@@@@[38;2;125;158;189mg[38;2;100;125;153my[38;2;101;127;155m_ [38;2;206;179;125m4[38;2;232;202;138m@[38;2;234;203;139m@@@@@[38;2;212;183;127m@[38;2;206;178;124my[38;2;145;124;93m_ + [38;2;0;0;0m [38;2;189;96;106mg[38;2;190;97;107m@@@@[38;2;178;91;101m@[38;2;168;85;97mF[38;2;187;95;105m~ [38;2;65;79;104m_[38;2;91;113;141my[38;2;120;151;182mg[38;2;124;157;188m@[38;2;126;159;190m@@@@@@@@@@@@@@@@[38;2;119;149;180m@[38;2;101;126;155mg[38;2;126;159;190m_ [38;2;200;173;121m~[38;2;180;156;111mF[38;2;217;188;130m@[38;2;234;203;139m@@@@[38;2;196;169;119m@ + [38;2;0;0;0m [38;2;183;93;104m$[38;2;190;97;107m@@@[38;2;189;97;107mF [38;2;103;128;157my[38;2;126;159;190mg@@@@@@@@@@@@@@@@@@@@@@@@[38;2;122;154;185mg[38;2;75;92;118my [38;2;206;178;124m9[38;2;234;203;139m@[38;2;199;172;121m@[38;2;193;167;118mF[38;2;106;90;73m" + [38;2;0;0;0m [38;2;182;93;103m$[38;2;190;97;107m@@@[38;2;130;66;79m$ [38;2;79;97;124m4[38;2;126;159;190m@@@@@[38;2;112;140;170m@[38;2;126;159;190m~[38;2;104;130;159m@[38;2;126;159;190m@@@@@@@@@@@@@@@@@@@@ [38;2;82;68;61m"[38;2;154;132;98m_[38;2;183;157;112my[38;2;226;196;135mg[38;2;208;180;126m$ + [38;2;0;0;0m [38;2;178;90;101m$[38;2;190;97;107m@@@[38;2;131;66;79m$ [38;2;80;98;125m4[38;2;126;159;190m@@@@[38;2;96;120;148m@ [38;2;108;136;165m~[38;2;105;132;161m@[38;2;126;159;190m@@@@@@@@@@@@@@@@@@ [38;2;168;144;105mg[38;2;234;203;139m@@@[38;2;233;202;138m@ + [38;2;0;0;0m [38;2;173;88;99m$[38;2;190;97;107m@@@[38;2;131;66;80m$ [38;2;80;98;125m4[38;2;126;159;190m@@@@@[38;2;118;148;178m@[38;2;91;113;141my [38;2;109;136;166m~[38;2;107;134;163m@[38;2;126;159;190m@@@@@@@@@@@@@@@@ [38;2;182;157;112m$[38;2;234;203;139m@@[38;2;233;202;138m@[38;2;224;194;134mF + [38;2;0;0;0m [38;2;173;88;99m$[38;2;190;97;107m@@@[38;2;132;67;80m$ [38;2;80;98;125m4[38;2;126;159;190m@@@@@@@[38;2;116;146;176m@[38;2;79;98;124my [38;2;109;137;166m~[38;2;112;141;171m@[38;2;126;159;190m@@@@@@@@@@@@@@ [38;2;140;120;90m`[38;2;189;163;116m~[38;2;234;203;139m_[38;2;161;138;101my[38;2;182;157;112m_ + [38;2;0;0;0m [38;2;173;88;99m$[38;2;190;97;107m@@@[38;2;134;68;81m$ [38;2;80;99;125m4[38;2;126;159;190m@@@@@@@[38;2;114;143;173mP[38;2;113;142;172m` [38;2;56;67;92m_[38;2;98;122;151mg[38;2;125;158;189m@[38;2;126;159;190m@@@@@@@@@@@@@@ [38;2;148;127;95my[38;2;234;203;139m@@@[38;2;213;184;128m@ + [38;2;0;0;0m [38;2;173;88;99m$[38;2;190;97;107m@@@[38;2;139;70;83m$ [38;2;80;99;126m4[38;2;126;159;190m@@@@@[38;2;117;147;177mP[38;2;119;150;180m` [38;2;52;62;86m_[38;2;109;137;166my[38;2;125;158;189m@[38;2;126;159;190m@@@@@@@@@@@@@@@@ [38;2;163;140;102m4[38;2;234;203;139m@@@[38;2;216;187;129m@ + [38;2;0;0;0m [38;2;174;88;99m$[38;2;190;97;107m@@@[38;2;143;73;85m$ [38;2;80;99;126m4[38;2;126;159;190m@@@@[38;2;104;129;158m$[38;2;54;64;89m_ [38;2;108;136;165my[38;2;125;158;189m@[38;2;126;159;190m@@@[38;2;110;139;168m@[38;2;126;159;190m [38;2;114;144;174m$[38;2;126;159;190m@@@@ [38;2;136;116;88m4[38;2;234;203;139m@@@[38;2;218;189;131m@ + [38;2;0;0;0m [38;2;174;88;99m$[38;2;190;97;107m@@@[38;2;145;73;86m$ [38;2;81;99;126m4[38;2;126;159;190m@@@@@@[38;2;113;142;172mg[38;2;124;157;188m@[38;2;126;159;190m@@@@@[38;2;125;158;188m@[38;2;107;135;164m@[38;2;107;134;163m@@@@@@@[38;2;108;136;165m@[38;2;121;153;184m@[38;2;126;159;190m@@@@ [38;2;198;171;120m~[38;2;208;180;125m@[38;2;234;203;139m@[38;2;220;191;132m@ + [38;2;0;0;0m [38;2;174;89;99m$[38;2;190;97;107m@@[38;2;184;93;104mP [38;2;91;113;141m7[38;2;109;137;166mR[38;2;126;159;190m@@@@@@@@@@@@@@@@@@@@@@@[38;2;123;155;186m@[38;2;111;139;169mP[38;2;84;104;131m~ [38;2;117;134;106m_[38;2;129;149;115m@[38;2;140;162;124mg[38;2;83;93;80m_[38;2;174;150;108m7[38;2;222;192;133m@ + [38;2;0;0;0m [38;2;145;73;86m~[38;2;168;85;97m~[38;2;140;162;124m_[38;2;125;144;112my[38;2;158;183;137mg[38;2;157;182;137m@[38;2;146;169;128mg[38;2;111;127;101my[38;2;61;67;64m_ [38;2;115;145;175m~[38;2;91;113;141m5[38;2;121;152;182m@[38;2;126;159;190m@@@@@@@@@@@@@@@@[38;2;108;136;165m@[38;2;105;131;160mF[38;2;98;122;151m~ [38;2;145;167;127m_[38;2;130;150;116my[38;2;162;188;140mg[38;2;163;189;141m@@@@[38;2;137;158;121my + [38;2;0;0;0m [38;2;140;161;123mR[38;2;163;189;141m@@@@@@[38;2;113;129;102m@ [38;2;82;101;128m~[38;2;126;159;190m~[38;2;101;126;154m@[38;2;126;159;190m@@@@@@@@@[38;2;125;158;189m@[38;2;118;148;178mP[38;2;126;159;190m~[38;2;84;103;130m` [38;2;112;127;102my[38;2;153;177;133ma[38;2;154;179;134m@[38;2;163;189;141m@@@@@@[38;2;132;152;117m@[38;2;117;134;106mF + [38;2;0;0;0m [38;2;147;170;129m~[38;2;116;132;105m5[38;2;153;177;133m@[38;2;163;189;141m@@@ [38;2;117;134;106m4[38;2;160;185;138m@[38;2;144;166;126mg[38;2;107;122;98my [38;2;62;74;99m`[38;2;122;154;184m~[38;2;109;137;167m4[38;2;124;157;188m@[38;2;126;159;190m@@[38;2;114;143;173m@[38;2;109;137;166mF[38;2;115;145;175m~ [38;2;122;140;110my[38;2;155;179;135m@[38;2;163;189;141m@@@@@[38;2;160;186;139m@[38;2;146;169;128mP[38;2;163;189;141m~[38;2;61;67;63m` + [38;2;0;0;0m [38;2;162;188;140m`[38;2;163;189;141m~[38;2;143;165;126mP [38;2;99;112;92m4[38;2;163;189;141m@@@@[38;2;162;187;140mg[38;2;127;145;113my[38;2;120;137;108m_ [38;2;105;131;160m`[38;2;104;130;159m` [38;2;133;154;118m_[38;2;130;149;116my[38;2;126;145;113mr [38;2;137;158;121ma[38;2;163;189;141m@@@@[38;2;144;167;127m@[38;2;139;160;122mF[38;2;138;159;122m~ + [38;2;0;0;0m [38;2;116;132;105m5[38;2;154;178;134m@[38;2;163;189;141m@@@@@[38;2;152;176;133m@[38;2;163;189;141mgg[38;2;147;169;128m@[38;2;161;187;140m@[38;2;148;171;129m~[38;2;103;117;95m_[38;2;162;188;140mg[38;2;163;189;141m@@[38;2;122;140;110m@[38;2;163;189;141m~[38;2;140;161;123m` + [38;2;0;0;0m [38;2;95;108;89m~[38;2;163;189;141m~[38;2;128;147;114m@[38;2;163;189;141m@@@@@[38;2;145;168;127m@[38;2;82;92;79m^[38;2;129;149;115my[38;2;155;180;135m@[38;2;145;168;127mF[38;2;160;185;139m~ + [38;2;0;0;0m [38;2;71;78;71m`[38;2;157;181;136m~[38;2;140;162;124m4[38;2;149;173;131m@[38;2;151;175;132mF [38;2;108;124;99m~ + [38;2;0;0;0m + [38;2;0;0;0m "#; |
