diff --git a/.gitignore b/.gitignore index ea8c4bf..0a42548 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +debug.log diff --git a/src/display/body.rs b/src/display/body.rs index 5aef8f2..90c7f50 100644 --- a/src/display/body.rs +++ b/src/display/body.rs @@ -9,7 +9,7 @@ type Result = std::result::Result; #[derive(Debug, Clone)] pub enum Body { Echo, - Signin(SigninPage), + // Signin(SigninPage), } impl Body { @@ -17,9 +17,10 @@ impl Body { let event = format!("{}", event); write!( screen, - "{fr}{}", - env.frame.writeln(&format!("Event: {}", event), 1, 1), - fr = env.primary_frame(), + "{clear}{frame}{content}", + clear = clear::All, + frame = env.frame.frame_str(env.theme.primary()), + content = env.frame.writeln(&format!("Event: {}", event), 0, 0), )?; screen.flush()?; Ok(()) @@ -34,7 +35,7 @@ impl Page for Body { event: Event, ) -> Result<()> { match self { - Body::Signin(b) => b.receive_event(env, screen, event)?, + // Body::Signin(b) => b.receive_event(env, screen, event)?, Body::Echo => Body::echo(env, screen, event)?, }; Ok(()) @@ -45,7 +46,7 @@ impl Page for Body { screen, "{hide}{clear}{fr}{cursor}", hide = cursor::Hide, - fr = env.frame.frame_str(&env.theme, env.theme.primary()), + fr = env.frame.frame_str(env.theme.primary()), cursor = env.frame.goto(0, 0), clear = clear::All )?; @@ -54,51 +55,51 @@ impl Page for Body { } } -#[derive(Debug, Clone, Default)] -struct SigninPage { - hostname: String, - username: String, - cursor: SigninCursorLocation, -} +// #[derive(Debug, Clone, Default)] +// struct SigninPage { +// hostname: String, +// username: String, +// cursor: SigninCursorLocation, +// } -#[derive(Debug, Clone)] -enum SigninCursorLocation { - Hostname, - Username, - Next, -} +// #[derive(Debug, Clone)] +// enum SigninCursorLocation { +// Hostname, +// Username, +// Next, +// } -impl Default for SigninCursorLocation { - fn default() -> Self { - Self::Hostname - } -} +// impl Default for SigninCursorLocation { +// fn default() -> Self { +// Self::Hostname +// } +// } -impl SigninPage { - fn frame_string() -> String { - format!("") - } -} +// impl SigninPage { +// fn frame_string() -> String { +// format!("") +// } +// } -impl Page for SigninPage { - fn receive_event( - &mut self, - env: Environment, - screen: &mut RawTerminal, - event: Event, - ) -> Result<()> { - Ok(()) - } +// impl Page for SigninPage { +// fn receive_event( +// &mut self, +// env: Environment, +// screen: &mut RawTerminal, +// event: Event, +// ) -> Result<()> { +// Ok(()) +// } - fn init(&self, env: Environment, screen: &mut RawTerminal) -> Result<()> { - write!( - screen, - "{frame}{hide_cursor}", - frame = env.frame.frame_str(&env.theme, env.theme.primary()), - hide_cursor = cursor::Hide, - )?; - screen.flush()?; +// fn init(&self, env: Environment, screen: &mut RawTerminal) -> Result<()> { +// write!( +// screen, +// "{frame}{hide_cursor}", +// frame = env.frame.frame_str(&env.theme, env.theme.primary()), +// hide_cursor = cursor::Hide, +// )?; +// screen.flush()?; - Ok(()) - } -} +// Ok(()) +// } +// } diff --git a/src/display/debug.rs b/src/display/debug.rs new file mode 100644 index 0000000..40c0520 --- /dev/null +++ b/src/display/debug.rs @@ -0,0 +1,15 @@ +pub fn debug_append(s: String) { + std::process::Command::new("fish") + .arg("-c") + .arg(format!("echo \"{}\" >> debug.log", s)) + .output() + .unwrap(); +} +macro_rules! debug { + ($fmt_string:expr, $($arg:tt)*) => { + $crate::display::debug::debug_append( + format!($fmt_string, $($arg)*) + ); + }; +} +pub(crate) use debug; diff --git a/src/display/frame.rs b/src/display/frame.rs index 8891689..a62fae3 100644 --- a/src/display/frame.rs +++ b/src/display/frame.rs @@ -3,10 +3,12 @@ use termion::{clear, cursor}; const ESTIMATED_FRAME_BIT_SIZE: usize = 11; use std::io::Write; +use crate::display::debug::debug; + use super::theme::Theme; -const FRAME_CHAR_HORIZONTAL: char = 'h'; -const FRAME_CHAR_VERTICAL: char = 'v'; +const FRAME_CHAR_HORIZONTAL: char = ' '; +const FRAME_CHAR_VERTICAL: char = ' '; pub enum FrameSize { ByAbsolute(u16, u16), @@ -18,72 +20,100 @@ pub struct Frame { // Both are (w, h) start: (u16, u16), end: (u16, u16), + width: u16, + theme: Theme, } impl Frame { - #[inline] + #[inline(always)] pub fn goto(&self, x: u16, y: u16) -> String { let cg = cursor::Goto( - (self.start.0 + x).min(self.end.0 - 1), - (self.start.1 + y).min(self.end.1 - 1), + (self.width + self.start.0 + x).min(self.end.0 - self.width), + (self.width + self.start.1 + y).min(self.end.1 - self.width), ); cg.into() } + #[inline(always)] + fn goto_internal(&self, x: u16, y: u16) -> String { + cursor::Goto( + (self.start.0 + x).min(self.end.0), + (self.start.1 + y).min(self.end.1), + ) + .into() + } + pub fn writeln(&self, s: &str, x: u16, y: u16) -> String { let words = s.split('\n').collect::>(); let mut out_words = Vec::with_capacity(words.len()); for i in 0..words.len() { out_words.push(format!( - "{str}{ret}", + "{ret}{str}", str = words[i], - ret = self.goto(1, y + i as u16 + 1) + ret = self.goto(x, y + i as u16), )); } out_words.concat() } - #[inline] + #[inline(always)] pub fn size(&self) -> (u16, u16) { (self.end.0 - self.start.0, self.end.1 - self.start.1) } - pub fn from_terminal_size() -> Result { + #[inline(always)] + pub fn from_terminal_size(theme: Theme, width: u16) -> Result { let term = termion::terminal_size()?; // Swap term dimensions to use x/y let term = (term.1, term.0); - Ok(Self::from_bottom_right(term, term)) + Ok(Self::from_bottom_right(term, term, width, theme)) } - fn from_bottom_right((pos_h, pos_w): (u16, u16), (term_h, term_w): (u16, u16)) -> Self { + #[inline(always)] + fn from_bottom_right( + (pos_h, pos_w): (u16, u16), + (term_h, term_w): (u16, u16), + width: u16, + theme: Theme, + ) -> Self { Self { start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)), end: (pos_w, pos_h), + width, + theme, } } - pub fn frame_str(&self, theme: &Theme, body_theme: String) -> String { - self.goto(0, 0); + pub fn frame_str(&self, body_theme: String) -> String { + if self.width == 0 { + return body_theme + &clear::All.to_string(); + } + self.goto_internal(0, 0); let (w_len, h_len) = self.size(); let width_str = FRAME_CHAR_HORIZONTAL.to_string().repeat(w_len as usize + 1); let mut frame = Vec::with_capacity(h_len as usize + 4); - let frame_theme = theme.frame(); + let frame_theme = self.theme.frame(); let body_clear = body_theme.clone() + &clear::CurrentLine.to_string(); frame.push(frame_theme.clone()); let make_line = |y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y)); - frame.push(make_line(self.start.1)); - for y in self.start.1 + 1..self.end.1 { + for y in 0..self.width { + frame.push(make_line(self.start.1 + y)); + } + for y in self.width + self.start.1..self.end.1 - self.width { frame.push(format!( "{left}{body_clear}{frame_theme}{char}{right}{char}", body_clear = &body_clear, frame_theme = &frame_theme, left = cursor::Goto(self.start.0, y), - right = cursor::Goto(self.start.0 + self.end.0, y), - char = FRAME_CHAR_VERTICAL, + right = cursor::Goto(self.start.0 + self.end.0 - self.width, y), + char = FRAME_CHAR_VERTICAL.to_string().repeat(self.width as usize), )); } + for y in self.end.1 - self.width - 1..self.end.1 { + frame.push(make_line(self.start.1 + y)); + } frame.push(make_line(self.end.1)); frame.push(self.goto(1, 1)); frame.push(body_theme); @@ -92,7 +122,8 @@ impl Frame { } impl FrameSize { - fn abs_size(&self) -> Frame { + #[inline(always)] + fn abs_size(&self, theme: Theme, width: u16) -> Frame { let (term_height, term_width) = termion::terminal_size().expect("could not get terminal size"); let pos = match self { @@ -108,6 +139,6 @@ impl FrameSize { ) } }; - Frame::from_bottom_right(pos, (term_height, term_width)) + Frame::from_bottom_right(pos, (term_height, term_width), width, theme) } } diff --git a/src/display/mod.rs b/src/display/mod.rs index fb6503d..6e41fde 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -13,6 +13,7 @@ use self::frame::Frame; use self::theme::{Color, Theme}; pub mod body; +pub mod debug; pub mod frame; pub mod theme; type Result = std::result::Result; @@ -66,7 +67,7 @@ impl Into for Environment { fn into(self) -> String { format!( "{frame}{theme}", - frame = self.frame.frame_str(&self.theme, self.theme.primary()), + frame = self.frame.frame_str(self.theme.primary()), theme = self.theme.primary(), ) } @@ -74,15 +75,18 @@ impl Into for Environment { impl Environment { fn initial_must(theme: Theme) -> Self { + let w: u16 = std::env::var("FRAME_WIDTH") + .map(|f| f.parse().unwrap_or(1)) + .unwrap_or(1); Self { theme, - frame: Frame::from_terminal_size().expect("could not get terminal size"), + frame: Frame::from_terminal_size(theme, w).expect("could not get terminal size"), } } #[inline(always)] pub fn primary_frame(&self) -> String { - self.frame.frame_str(&self.theme, self.theme.primary()) + self.frame.frame_str(self.theme.primary()) } } @@ -133,6 +137,7 @@ impl Screen { clear = clear::All, show_cursor = cursor::Show, )?; + scr.flush(); Ok(()) }