aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2021-02-09 17:36:07 +0100
committerGitHub <noreply@github.com>2021-02-09 17:36:07 +0100
commit380f056315cffa69dbbf76a9b4457b4a70b4fdfd (patch)
tree20c635dc5795f5739dfb37301edc17b62b9450c3
parentMerge pull request #1 from mosaic-org/max-height (diff)
parentMerge branch 'master' into new-design (diff)
downloadsl0ppij-380f056315cffa69dbbf76a9b4457b4a70b4fdfd.tar.gz
sl0ppij-380f056315cffa69dbbf76a9b4457b4a70b4fdfd.tar.xz
sl0ppij-380f056315cffa69dbbf76a9b4457b4a70b4fdfd.zip
feat(ui): new design
-rw-r--r--src/main.rs314
1 files changed, 278 insertions, 36 deletions
diff --git a/src/main.rs b/src/main.rs
index 0b0542fc..9aa93b13 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,52 +1,294 @@
use colored::*;
use mosaic_tile::*;
+use std::fmt::{Display, Formatter, Error};
+
+// for more of these, copy paste from: https://en.wikipedia.org/wiki/Box-drawing_character
+static ARROW_SEPARATOR: &str = " ";
+static MORE_MSG: &str = " ... ";
#[derive(Default)]
-struct State {
- lines: Vec<String>,
- page: usize,
-}
+struct State {}
register_tile!(State);
-impl MosaicTile for State {
- fn init(&mut self) {
- set_selectable(false);
- set_max_height(1);
+struct LinePart {
+ part: String,
+ len: usize,
+}
+
+impl Display for LinePart {
+ fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+ write!(f, "{}", self.part)
}
+}
- fn draw(&mut self, _rows: usize, cols: usize) {
- let more_msg = ", <?> More";
- self.lines = vec![String::new()];
- for item in get_help() {
- let width = self.lines.last().unwrap().len();
- if width + item.len() + 2 > cols - more_msg.len() {
- self.lines.last_mut().unwrap().push_str(more_msg);
- self.lines.push(item);
- } else {
- let line = self.lines.last_mut().unwrap();
- if !line.is_empty() {
- line.push_str(", ");
- }
- line.push_str(&item);
- }
+
+fn prefix(help: &Help) -> LinePart {
+ let prefix_text = " Mosaic ";
+ let part = match (&help.mode, help.mode_is_persistent) {
+ (InputMode::Command, false) => {
+ let prefix = prefix_text.bold().white().on_black();
+ let separator = ARROW_SEPARATOR.black().on_magenta();
+ format!("{}{}", prefix, separator)
+ }
+ (_, true) => {
+ let prefix = prefix_text.bold().white().on_black();
+ let separator = ARROW_SEPARATOR.black().on_yellow();
+ format!("{}{}", prefix, separator)
+ }
+ (InputMode::Normal, _) => {
+ let prefix = prefix_text.bold().white().on_black();
+ let separator = ARROW_SEPARATOR.black().on_green();
+ format!("{}{}", prefix, separator)
+ }
+ _ => {
+ let prefix = prefix_text.bold().white().on_black();
+ let separator = ARROW_SEPARATOR.black().on_magenta();
+ format!("{}{}", prefix, separator)
+ }
+ };
+ let len = prefix_text.chars().count() + ARROW_SEPARATOR.chars().count();
+ LinePart {
+ part,
+ len
+ }
+}
+
+fn key_path(help: &Help) -> LinePart {
+ let superkey_text = "<Ctrl-g> ";
+ let locked_text = "LOCKED ";
+ let (part, len) = match (&help.mode, help.mode_is_persistent) {
+ (InputMode::Command, false) => {
+ let key_path = superkey_text.bold().on_magenta();
+ let first_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = superkey_text.chars().count() + ARROW_SEPARATOR.chars().count() + ARROW_SEPARATOR.chars().count();
+ (format!("{}{}", key_path, first_separator), len)
+ }
+ (InputMode::Command, true) => {
+ let locked = locked_text.bold().white().on_yellow();
+ let locked_separator = ARROW_SEPARATOR.yellow().on_magenta();
+ let key_path = superkey_text.bold().on_magenta();
+ let superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = superkey_text.chars().count() + ARROW_SEPARATOR.chars().count() + locked_text.chars().count();
+ (format!("{}{}{}{}", locked, locked_separator, key_path, superkey_separator), len)
+ }
+ (InputMode::Resize, false) => {
+ let mode_shortcut_text = "r ";
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}", superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Resize, true) => {
+ let mode_shortcut_text = "r ";
+ let locked = locked_text.white().bold().on_yellow();
+ let locked_separator = ARROW_SEPARATOR.yellow().on_magenta();
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = locked_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}{}{}", locked, locked_separator, superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
}
- self.page %= self.lines.len();
- let line = format!(
- "{}{}",
- self.lines[self.page],
- if self.page > 0 && self.lines.len() == self.page + 1 {
- ", <?> Back"
+ (InputMode::Pane, false) => {
+ let mode_shortcut_text = "p ";
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}", superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Pane, true) => {
+ let mode_shortcut_text = "p ";
+ let locked = locked_text.white().bold().on_yellow();
+ let locked_separator = ARROW_SEPARATOR.yellow().on_magenta();
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = locked_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}{}{}", locked, locked_separator, superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Tab, false) => {
+ let mode_shortcut_text = "t ";
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}", superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Tab, true) => {
+ let mode_shortcut_text = "t ";
+ let locked = locked_text.white().bold().on_yellow();
+ let locked_separator = ARROW_SEPARATOR.yellow().on_magenta();
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = locked_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}{}{}", locked, locked_separator, superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Scroll, false) => {
+ let mode_shortcut_text = "s ";
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}", superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Scroll, true) => {
+ let mode_shortcut_text = "s ";
+ let locked = locked_text.white().bold().on_yellow();
+ let locked_separator = ARROW_SEPARATOR.yellow().on_magenta();
+ let superkey = superkey_text.bold().on_magenta();
+ let first_superkey_separator = ARROW_SEPARATOR.magenta().on_black();
+ let second_superkey_separator = ARROW_SEPARATOR.black().on_magenta();
+ let mode_shortcut = mode_shortcut_text.white().bold().on_magenta();
+ let mode_shortcut_separator = ARROW_SEPARATOR.magenta().on_black();
+ let len = locked_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ superkey_text.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ ARROW_SEPARATOR.chars().count() +
+ mode_shortcut_text.chars().count() +
+ ARROW_SEPARATOR.chars().count();
+ (format!("{}{}{}{}{}{}{}", locked, locked_separator, superkey, first_superkey_separator, second_superkey_separator, mode_shortcut, mode_shortcut_separator), len)
+ }
+ (InputMode::Normal, _) | _ => {
+ let key_path = superkey_text.on_green();
+ let separator = ARROW_SEPARATOR.green().on_black();
+ (format!("{}{}", key_path, separator), superkey_text.chars().count() + ARROW_SEPARATOR.chars().count())
+ }
+ };
+ LinePart {
+ part,
+ len
+ }
+}
+
+fn keybinds(help: &Help, max_width: usize) -> LinePart {
+ let mut keybinds = String::new();
+ let mut len = 0;
+ let full_keybinds_len = help.keybinds.iter().enumerate().fold(0, |acc, (i, (shortcut, description))| {
+ let shortcut_length = shortcut.chars().count() + 3; // 2 for <>'s around shortcut, 1 for the space
+ let description_length = description.chars().count() + 2;
+ let (_separator, separator_len) = if i > 0 { (" / ", 3) } else { ("", 0) };
+ acc + shortcut_length + description_length + separator_len
+ });
+ if full_keybinds_len < max_width {
+ for (i, (shortcut, description)) in help.keybinds.iter().enumerate() {
+ let separator = if i > 0 { " / " } else { "" };
+ let shortcut_len = shortcut.chars().count();
+ let shortcut = match help.mode {
+ InputMode::Normal => shortcut.cyan(),
+ _ => shortcut.white().bold(),
+ };
+ keybinds = format!("{}{}<{}> {}", keybinds, separator, shortcut, description);
+ len += shortcut_len + separator.chars().count();
+ }
+ } else {
+ for (i, (shortcut, description)) in help.keybinds.iter().enumerate() {
+ let description_first_word = description.split(' ').next().unwrap_or("");
+ let current_length = keybinds.chars().count();
+ let shortcut_length = shortcut.chars().count() + 3; // 2 for <>'s around shortcut, 1 for the space
+ let description_first_word_length = description_first_word.chars().count();
+ let (separator, separator_len) = if i > 0 { (" / ", 3) } else { ("", 0) };
+ let shortcut = match help.mode {
+ InputMode::Normal => shortcut.cyan(),
+ _ => shortcut.white().bold(),
+ };
+ if current_length + shortcut_length + description_first_word_length + separator_len + MORE_MSG.chars().count() < max_width {
+ keybinds = format!("{}{}<{}> {}", keybinds, separator, shortcut, description_first_word);
+ len += shortcut_length + description_first_word_length + separator_len;
+ } else if current_length + shortcut_length + separator_len + MORE_MSG.chars().count() < max_width {
+ keybinds = format!("{}{}<{}>", keybinds, separator, shortcut);
+ len += shortcut_length + separator_len;
} else {
- ""
+ keybinds = format!("{}{}", keybinds, MORE_MSG);
+ len += MORE_MSG.chars().count();
+ break;
}
- );
- println!("{}", line.italic());
+ }
+ }
+ LinePart {
+ part: keybinds,
+ len,
}
+}
- fn handle_global_key(&mut self, key: Key) {
- if let Key::Char('?') = key {
- self.page += 1;
- }
+impl MosaicTile for State {
+ fn init(&mut self) {
+ set_selectable(false);
+ set_invisible_borders(true);
+ set_max_height(1);
+ }
+
+ fn draw(&mut self, _rows: usize, cols: usize) {
+ let help = get_help();
+ let line_prefix = prefix(&help);
+ let key_path = key_path(&help);
+ let line_len_before_keybinds = line_prefix.len + key_path.len;
+ let status_bar = if line_len_before_keybinds + MORE_MSG.chars().count() < cols {
+ let keybinds = keybinds(&help, cols - line_len_before_keybinds);
+ let keybinds = keybinds.part.cyan().on_black();
+ format!("{}{}{}", line_prefix, key_path, keybinds)
+ } else if line_len_before_keybinds < cols {
+ format!("{}{}", line_prefix, key_path)
+ } else if line_prefix.len < cols {
+ format!("{}", line_prefix)
+ } else {
+ // sorry, too small :(
+ format!("")
+ };
+ // 40m is black background, 0K is so that it fills the rest of the line,
+ // I could not find a way to do this with colored and did not want to have to
+ // manually fill the line with spaces to achieve the same
+ println!("{}\u{1b}[40m\u{1b}[0K", status_bar);
}
}