From f03650e4b71b83f95c897f7ad5cc2cebb40ab22e Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 26 Dec 2023 10:18:18 +0000 Subject: [PATCH] First half of FileStatusLine. Rendering undone. --- src/text.rs | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 2 deletions(-) diff --git a/src/text.rs b/src/text.rs index 49fa819..651ffd4 100644 --- a/src/text.rs +++ b/src/text.rs @@ -2,7 +2,8 @@ use chrono::{DateTime, Local, Utc}; #[cfg(test)] use chrono::NaiveDateTime; use core::cmp::min; -use std::collections::{HashMap, BTreeSet}; +use std::collections::{HashMap, BTreeMap, BTreeSet}; +use unicode_width::UnicodeWidthStr; use super::html; use super::coloured_string::{ColouredString, ColouredStringSlice}; @@ -1049,6 +1050,157 @@ fn test_media() { }); } +type Key = String; // FIXME: maybe make this a richer type later so we + // can match it against actual keypresses + +struct Keypress { + key: Key, + description: ColouredString, +} + +pub struct FileStatusLine { + keypresses: Vec<(Keypress, usize)>, // each with display priority + proportion: Option, + message: Option, +} + +struct FileStatusLineFinal { + fs: FileStatusLine, + priwidth: Vec<(usize, usize)>, // min priority, total width of those keys +} + +impl FileStatusLine { + const SPACING: usize = 2; + + pub fn new() -> FileStatusLine { + FileStatusLine { + keypresses: Vec::new(), + proportion: None, + message: None, + } + } + + pub fn set_proportion(mut self, numer: usize, denom: usize) -> Self { + self.proportion = Some((100 * numer / denom) as u32); + self + } + + pub fn message(mut self, msg: &str) -> Self { + self.message = Some(msg.to_owned()); + self + } + + pub fn add(mut self, key: Key, description: &str, priority: usize) -> Self { + self.keypresses.push((Keypress { + key: key, + description: ColouredString::plain(description) + }, priority)); + self + } + + fn finalise(self) -> FileStatusLineFinal { + let mut bypri = BTreeMap::new(); + for (kp, pri) in &self.keypresses { + // [key]:desc + let key: &str = &kp.key; + let width = UnicodeWidthStr::width(key) + + kp.description.width() + 3; + + if let Some(priwidth) = bypri.get_mut(pri) { + *priwidth += Self::SPACING + width; + } else { + bypri.insert(pri, width); + } + } + + // If the keypresses are the only thing on this status line, + // then we don't need an extra SPACING to separate them from + // other stuff. + let initial = if self.proportion.is_some() || + self.message.is_some() { Self::SPACING } else { 0 }; + + let mut cumulative = initial; + let mut priwidth = Vec::new(); + for (minpri, thiswidth) in bypri.iter().rev() { + cumulative += thiswidth + + if cumulative == initial { 0 } else { Self::SPACING }; + priwidth.push((**minpri, cumulative)); + } + + FileStatusLineFinal { + fs: self, + priwidth: priwidth + } + } + + pub fn into_box(self) -> Box { + Box::new(self.finalise()) + } +} + +#[test] +fn test_filestatus_build() { + let fs = FileStatusLine::new().set_proportion(34, 55); + assert_eq!(fs.proportion, Some(61)); + + let fs = FileStatusLine::new().message("hello, world"); + assert_eq!(fs.message, Some("hello, world".to_owned())); + + let fsf = FileStatusLine::new() + .add("A".to_string(), "Annoy", 10) + .finalise(); + assert_eq!(fsf.priwidth, vec! { + (10, 9), + }); + + let fsf = FileStatusLine::new() + .add("A".to_string(), "Annoy", 10) + .add("B".to_string(), "Badger", 10) + .finalise(); + assert_eq!(fsf.priwidth, vec! { + (10, 9 + 10 + FileStatusLine::SPACING), + }); + + let fsf = FileStatusLine::new() + .add("A".to_string(), "Annoy", 10) + .add("B".to_string(), "Badger", 5) + .finalise(); + assert_eq!(fsf.priwidth, vec! { + (10, 9), + (5, 9 + 10 + FileStatusLine::SPACING), + }); + + let fsf = FileStatusLine::new() + .add("A".to_owned(), "Annoy", 10) + .finalise(); + assert_eq!(fsf.priwidth, vec! { + (10, 9), + }); + + let fsf = FileStatusLine::new() + .set_proportion(2, 3) + .add("A".to_owned(), "Annoy", 10) + .finalise(); + assert_eq!(fsf.priwidth, vec! { + (10, 9 + FileStatusLine::SPACING), + }); + + let fsf = FileStatusLine::new() + .message("aha") + .add("A".to_owned(), "Annoy", 10) + .finalise(); + assert_eq!(fsf.priwidth, vec! { + (10, 9 + FileStatusLine::SPACING), + }); +} + +impl TextFragment for FileStatusLineFinal { + fn render(&self, _width: usize) -> Vec { + vec! { + ColouredString::plain("FIXME"), + } + } +} + // TODO: -// FileStatusLine, with priorities // MenuKeypressLine -- 2.30.2