zellij/default-plugins/status-bar/src/second_line.rs
Kaito Akita 4632e90b73
feat(ui): The status bar indicates that the panes are full screen and how many hidden panes are (#450)
* fix(ui): offset content after viewport construction

* Added the feature to display fullscreen information on the second line of the status-bar.

* fix(strider): update host mount-point

* fix(plugin): create missing data directories as needed

* feat(layout): specify only tab name in `tabs` section (#722)

Allow specifying only the tab name in the `tabs` section

- For example this is now possible:
```
tabs:
  - name: first
    parts:
      - direction: Vertical
      - direction: Vertical
  - name: second
  - name: third
```
  For that the tab section defaults the direction to
  `direction::Horizontal`

- Adds an error upon specifying a tab name inside the `parts` section
  of the tab-layout

* docs(changelog): Solely name tab in `tabs` section

* feature(release): Copy default config to the examples folder on release (#736)

fixes #733

* docs(changelog): Copy example config on release

* Update default config (#737)

* feat(plugin): add manifest to allow for plugin configuration (#660)

* feat(plugins-manifest): Add a plugins manifest to allow for more configuration of plugins

* refactor(plugins-manifest): Better storage of plugin metadata in wasm_vm

* fix(plugins-manifest): Inherit permissions from run configuration

* refactor(plugins-manifest): Rename things for more clarity

- The Plugins/Plugin structs had "Config" appended to them to clarify
  that they're metadata about plugins, and not the plugins themselves.

- The PluginType::OncePerPane variant was renamed to be just
  PluginType::Pane, and the documentation clarified to explain what it
  is.

- The "service" nomenclature was completely removed in favor of
  "headless".

* refactor(plugins-manifest): Move security warning into start plugin

* refactor(plugins-manifest): Remove hack in favor of standard method

* refactor(plugins-manifest): Change display of plugin location

The only time that a plugin location is displayed in Zellij is the
border of the pane. Having `zellij:strider` display instead of just
`strider` was a little annoying, so we're stripping out the scheme
information from a locations display.

* refactor(plugins-manifest): Add a little more documentation

* fix(plugins-manifest): Formatting

Co-authored-by: Jesse Tuchsen <not@disclosing>

* chore(docs): update changelog

* feat(sessions): mirrored sessions (#740)

* feat(sessions): mirrored sessions

* fix(tests): input units

* style(fmt): make rustfmt happy

* fix(tests): make mirrored sessions e2e test more robust

* refactor(sessions): remove force attach

* style(fmt): rustfmtify

* docs(changelog): update change

* fix(e2e): retry on all errors

Co-authored-by: Brooks J Rady <b.j.rady@gmail.com>
Co-authored-by: a-kenji <aks.kenji@protonmail.com>
Co-authored-by: spacemaison <tuchsen@protonmail.com>
Co-authored-by: Jesse Tuchsen <not@disclosing>
Co-authored-by: Aram Drevekenin <aram@poor.dev>
2021-09-27 12:07:28 +02:00

468 lines
17 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 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)
}
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,
}
}