summaryrefslogtreecommitdiffstats
path: root/default-plugins/session-manager/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'default-plugins/session-manager/src/ui')
-rw-r--r--default-plugins/session-manager/src/ui/components.rs384
-rw-r--r--default-plugins/session-manager/src/ui/mod.rs7
-rw-r--r--default-plugins/session-manager/src/ui/welcome_screen.rs168
3 files changed, 441 insertions, 118 deletions
diff --git a/default-plugins/session-manager/src/ui/components.rs b/default-plugins/session-manager/src/ui/components.rs
index 4d9839c0f..d3c4afe80 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");
-
- 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}");
+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 > 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 94a1a8a72..b86db9468 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 000000000..ccf20c50a
--- /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#" 
+ 
+  _y$ y@g_
+  ya@@@@L4@@@@gy_
+  u@@@@@@F "@@@@@@@@y_
+  _a@@, @@@P~` _[38;2