* feature(resize): Non directional resize * Implement special cases * fix resizing for panes that have `+` cross section * fix resizing for panes that have `T` cross section * fix panics * Add Nondirection resize keys to plugin * fix formatting * fix: clippy warnings * fix the last edge case * implemented some of the suggested changes * Remove helper function and elevate comment to top of function * Use `=` to keep it consistent with Normal mode mapping as its easier to use * Remove extra reference borrowing * fix an edge case * add test for nondirectional resize increase/decrease * fix(controls): add + to resize * refactor(resize): simplify methods * fix(resize): properly resize opposite corner pane Co-authored-by: Aram Drevekenin <aram@poor.dev>
507 lines
19 KiB
Rust
507 lines
19 KiB
Rust
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 third_alt = "Alt";
|
|
let text_seventh_parth = " + ";
|
|
let increase_decrease_parth = "<+->";
|
|
let text_eighth_parth = " => increase/decrease pane size.";
|
|
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()
|
|
+ third_alt.chars().count()
|
|
+ text_seventh_parth.chars().count()
|
|
+ increase_decrease_parth.chars().count()
|
|
+ text_eighth_parth.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,
|
|
Style::new().fg(orange_color).bold().paint(third_alt),
|
|
text_seventh_parth,
|
|
Style::new()
|
|
.fg(green_color)
|
|
.bold()
|
|
.paint(increase_decrease_parth),
|
|
text_eighth_parth,
|
|
),
|
|
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 third_alt = "Alt";
|
|
let text_seventh_parth = " + ";
|
|
let increase_decrease_parth = "<+->";
|
|
let text_eighth_parth = " => resize pane. ";
|
|
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()
|
|
+ third_alt.chars().count()
|
|
+ text_seventh_parth.chars().count()
|
|
+ increase_decrease_parth.chars().count()
|
|
+ text_eighth_parth.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,
|
|
Style::new().fg(orange_color).bold().paint(third_alt),
|
|
text_seventh_parth,
|
|
Style::new()
|
|
.fg(green_color)
|
|
.bold()
|
|
.paint(increase_decrease_parth),
|
|
text_eighth_parth,
|
|
),
|
|
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 text_sixth_part = "/";
|
|
let increase_decrease_part = "+-";
|
|
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()
|
|
+ text_sixth_part.chars().count()
|
|
+ increase_decrease_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(green_color)
|
|
.bold()
|
|
.paint(brackets_navigation),
|
|
text_fifth_part,
|
|
Style::new().fg(green_color).bold().paint(hjkl_navigation),
|
|
text_sixth_part,
|
|
Style::new()
|
|
.fg(green_color)
|
|
.bold()
|
|
.paint(increase_decrease_part),
|
|
),
|
|
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)
|
|
}
|
|
|
|
pub fn text_copied_hint(palette: &Palette) -> LinePart {
|
|
let hint = " Text copied to clipboard";
|
|
let green_color = match palette.green {
|
|
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
|
|
PaletteColor::EightBit(color) => Fixed(color),
|
|
};
|
|
LinePart {
|
|
part: format!("{}", Style::new().fg(green_color).bold().paint(hint)),
|
|
len: hint.len(),
|
|
}
|
|
}
|
|
|
|
pub fn fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> 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 orange_color = match palette.orange {
|
|
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
|
|
PaletteColor::EightBit(color) => Fixed(color),
|
|
};
|
|
let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
|
|
let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): ");
|
|
let fullscreen = "FULLSCREEN";
|
|
let puls = "+ ";
|
|
let panes = panes_to_hide.to_string();
|
|
let hide = " hidden panes";
|
|
let len = fullscreen.chars().count()
|
|
+ puls.chars().count()
|
|
+ panes.chars().count()
|
|
+ hide.chars().count()
|
|
+ 5; // 3 for ():'s around shortcut, 2 for the space
|
|
LinePart {
|
|
part: format!(
|
|
"{}{}{}{}{}{}",
|
|
shortcut_left_separator,
|
|
Style::new().fg(orange_color).bold().paint(fullscreen),
|
|
shortcut_right_separator,
|
|
Style::new().fg(white_color).bold().paint(puls),
|
|
Style::new().fg(green_color).bold().paint(panes),
|
|
Style::new().fg(white_color).bold().paint(hide)
|
|
),
|
|
len,
|
|
}
|
|
}
|
|
|
|
pub fn locked_fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> 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 orange_color = match palette.orange {
|
|
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
|
|
PaletteColor::EightBit(color) => Fixed(color),
|
|
};
|
|
let locked_text = " -- INTERFACE LOCKED -- ";
|
|
let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
|
|
let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): ");
|
|
let fullscreen = "FULLSCREEN";
|
|
let puls = "+ ";
|
|
let panes = panes_to_hide.to_string();
|
|
let hide = " hidden panes";
|
|
let len = locked_text.chars().count()
|
|
+ fullscreen.chars().count()
|
|
+ puls.chars().count()
|
|
+ panes.chars().count()
|
|
+ hide.chars().count()
|
|
+ 5; // 3 for ():'s around shortcut, 2 for the space
|
|
LinePart {
|
|
part: format!(
|
|
"{}{}{}{}{}{}{}",
|
|
Style::new().fg(white_color).bold().paint(locked_text),
|
|
shortcut_left_separator,
|
|
Style::new().fg(orange_color).bold().paint(fullscreen),
|
|
shortcut_right_separator,
|
|
Style::new().fg(white_color).bold().paint(puls),
|
|
Style::new().fg(green_color).bold().paint(panes),
|
|
Style::new().fg(white_color).bold().paint(hide)
|
|
),
|
|
len,
|
|
}
|
|
}
|