diff --git a/Cargo.lock b/Cargo.lock index 9253ec5..541db11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,17 +357,6 @@ dependencies = [ "instant", ] -[[package]] -name = "fed" -version = "0.1.0" -dependencies = [ - "anyhow", - "misskey", - "signal-hook", - "termion", - "tokio 1.24.1", -] - [[package]] name = "flume" version = "0.9.2" @@ -669,6 +658,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kk" +version = "0.1.0" +dependencies = [ + "anyhow", + "misskey", + "termion", + "tokio 1.24.1", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1417,16 +1416,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.0" diff --git a/src/display/body.rs b/src/display/body.rs index 15fd780..e71d7cc 100644 --- a/src/display/body.rs +++ b/src/display/body.rs @@ -2,11 +2,7 @@ use std::io::{Stdout, Write}; use termion::{clear, cursor, raw::RawTerminal}; -use super::{ - frame::{self, FrameDef}, - theme::Theme, - Event, Page, -}; +use super::{Environment, Event, Page}; type Result = std::result::Result; @@ -17,15 +13,15 @@ pub enum Body { } impl Body { - fn echo(theme: Theme, screen: &mut RawTerminal, event: Event) -> Result<()> { + fn echo(env: Environment, screen: &mut RawTerminal, event: Event) -> Result<()> { let event = format!("{}", event); write!( screen, - "{theme}{clear}{start}Event: {}", - event, - theme = theme.display_string(), + "{theme}{clear}{start}{}", + env.frame.write(&format!("Event: {}", event), 1, 1), + theme = env.theme.display_string(), clear = clear::All, - start = cursor::Goto(1, 1) + start = env.frame.goto(1, 1) )?; screen.flush()?; Ok(()) @@ -35,24 +31,24 @@ impl Body { impl Page for Body { fn receive_event( &mut self, - theme: Theme, + env: Environment, screen: &mut RawTerminal, event: Event, ) -> Result<()> { match self { - Body::Signin(b) => b.receive_event(theme, screen, event)?, - Body::Echo => Body::echo(theme, screen, event)?, + Body::Signin(b) => b.receive_event(env, screen, event)?, + Body::Echo => Body::echo(env, screen, event)?, }; Ok(()) } - fn init(&self, theme: Theme, screen: &mut RawTerminal) -> Result<()> { + fn init(&self, env: Environment, screen: &mut RawTerminal) -> Result<()> { write!( screen, - "{theme}{cursor}{clear}{fr}", - fr = frame::draw_frame(theme, FrameDef::ByPercent(90, 90)), - theme = theme.display_string(), - cursor = cursor::Goto(1, 1), + "{theme}{clear}{cursor}{fr}", + theme = env.theme.display_string(), + fr = env.frame.frame_str(), + cursor = env.frame.goto(0, 0), clear = clear::All )?; screen.flush()?; @@ -89,20 +85,19 @@ impl SigninPage { impl Page for SigninPage { fn receive_event( &mut self, - theme: Theme, + env: Environment, screen: &mut RawTerminal, event: Event, ) -> Result<()> { Ok(()) } - fn init(&self, theme: Theme, screen: &mut RawTerminal) -> Result<()> { - let fr = frame::draw_frame(theme, FrameDef::ByPercent(40, 40)); + fn init(&self, env: Environment, screen: &mut RawTerminal) -> Result<()> { write!( screen, "{theme}{clear}{hide_cursor}{frame}", - frame = fr, - theme = theme.display_string(), + frame = env.frame.frame_str(), + theme = env.theme.display_string(), clear = clear::All, hide_cursor = cursor::Hide, )?; diff --git a/src/display/frame.rs b/src/display/frame.rs index e260ae4..71a3fc4 100644 --- a/src/display/frame.rs +++ b/src/display/frame.rs @@ -1,34 +1,85 @@ -use std::{io, process}; +use termion::cursor; -use termion::{color, cursor, screen::IntoAlternateScreen}; - -use super::theme::Theme; const ESTIMATED_FRAME_BIT_SIZE: usize = 11; -pub enum FrameDef { +const FRAME_CHAR: char = ' '; + +pub enum FrameSize { ByAbsolute(u16, u16), ByPercent(u16, u16), } -struct Frame { - start: (u16, u16), - end: (u16, u16), +#[derive(Debug, Clone, Copy)] +pub struct Frame { + start: (u16, u16), // (w, h) + end: (u16, u16), // (w, h) } impl Frame { - fn from_bottom_right(pos: (u16, u16), term: (u16, u16)) -> Self { + #[inline] + 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), + ); + // eprintln!( + // "goto x: {x} y: {y} -> x: {nx} y: {ny}", + // x = x, + // y = y, + // nx = cg.0, + // ny = cg.1 + // ); + // eprintln!("self start: {:#?} self end: {:#?}", self.start, self.end); + cg.into() + } + + pub fn write(&self, s: &str, x: u16, y: u16) -> String { + let words = s.split('\n'); + let (width, height) = self.size(); + let mut lines_down = 0; + let mut curr_len = width; + let mut write_parts = Vec::with_capacity(s.len() / 5); + write_parts.push(self.goto(x, y)); + for w in words { + // if curr_len + (w.len() as u16) > width { + // if y + 1 >= height { + // panic!("out of vertical space") + // } + // lines_down += 1; + // curr_len = 1; + // } + write_parts.push(self.goto(1, lines_down + y)); + lines_down += 1; + write_parts.push(w.to_string()); + } + write_parts.concat() + } + + // (x, y) + #[inline] + pub fn size(&self) -> (u16, u16) { + (self.end.0 - self.start.0, self.end.1 - self.start.1) + } + + pub fn from_terminal_size() -> Result { + let term = termion::terminal_size()?; + + Ok(Self::from_bottom_right(term, term)) + } + + fn from_bottom_right((pos_h, pos_w): (u16, u16), (term_h, term_w): (u16, u16)) -> Self { Self { - start: (term.0 - pos.0, term.1 - pos.1), - end: pos, + start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)), + end: (pos_w, pos_h), } } - fn frame_str(&self, frame_char: char) -> String { + pub fn frame_str(&self) -> String { let (w_len, h_len) = ( (self.end.0 - self.start.0) as usize, (self.end.1 - self.start.1 - 1) as usize, ); - let width_str = frame_char.to_string().repeat(w_len + 1); + let width_str = FRAME_CHAR.to_string().repeat(w_len + 1); let mut frame = String::with_capacity((h_len * 2) + (w_len * 2) * ESTIMATED_FRAME_BIT_SIZE); let make_line = |y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y)); @@ -36,67 +87,33 @@ impl Frame { for y in self.start.1 + 1..self.end.1 { frame.push_str(&format!( "{left}{char}{right}{char}", - left = cursor::Goto(self.start.0, y), - right = cursor::Goto(self.end.0, y), - char = frame_char, + left = self.goto(self.start.0, y), + right = self.goto(self.end.0, y), + char = FRAME_CHAR, )); } frame.push_str(&make_line(self.end.1)); + frame.push_str(&self.goto(1, 1)); frame } } -#[cfg(test)] -mod test { - use super::Frame; - - #[test] - fn test_idk() { - let x = Frame::from_bottom_right((16, 16), (32, 32)).frame_str('='); - println!("starting"); - println!("{}", x); - println!("ending"); - assert!(false) - } -} - -impl FrameDef { +impl FrameSize { fn abs_size(&self) -> Frame { let (term_height, term_width) = termion::terminal_size().expect("could not get terminal size"); let pos = match self { - FrameDef::ByAbsolute(h, w) => { - let (mut h, mut w) = (*h, *w); - if h > term_height { - h = term_height; - } - if w > term_width { - w = term_width; - } - (h, w) - } - FrameDef::ByPercent(h, w) => { + FrameSize::ByAbsolute(h, w) => ((*h).min(term_height), (*w).min(term_width)), + FrameSize::ByPercent(h, w) => { // term_height = 100% // x = h% // x = term_height * h / 100 - let (h, w) = ( - if *h > 100 { 100 } else { *h }, - if *w > 100 { 100 } else { *w }, - ); - // (h * 100 / term_height, w * 100 / term_width) - (term_height * h / 100, term_width * w / 100) + ( + term_height * (*h).min(100) / 100, + term_width * (*w).min(100) / 100, + ) } }; Frame::from_bottom_right(pos, (term_height, term_width)) } } - -pub fn draw_frame(theme: Theme, frame_size: FrameDef) -> String { - let frame_specs = frame_size.abs_size(); - format!( - "{fg}{bg}{frame}", - fg = theme.colors.frame_fg.fg_string(), - bg = theme.colors.frame_bg.bg_string(), - frame = frame_specs.frame_str('='), - ) -} diff --git a/src/display/mod.rs b/src/display/mod.rs index 0f3ace5..ef9b2b6 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -9,6 +9,7 @@ use tokio::sync::Mutex; use tokio::time::Instant; use self::body::Body; +use self::frame::Frame; use self::theme::Theme; pub mod body; @@ -46,15 +47,40 @@ impl From for Event { } pub trait Page { - fn init(&self, theme: Theme, screen: &mut RawTerminal) -> Result<()>; + fn init(&self, env: Environment, screen: &mut RawTerminal) -> Result<()>; fn receive_event( &mut self, - theme: Theme, + env: Environment, screen: &mut RawTerminal, event: Event, ) -> Result<()>; } +#[derive(Debug, Clone, Copy)] +pub struct Environment { + pub theme: Theme, + pub frame: Frame, +} + +impl Into for Environment { + fn into(self) -> String { + format!( + "{frame}{theme}", + frame = self.frame.frame_str(), + theme = self.theme.display_string(), + ) + } +} + +impl Environment { + fn initial_must(theme: Theme) -> Self { + Self { + theme, + frame: Frame::from_terminal_size().expect("could not get terminal size"), + } + } +} + impl Screen { pub fn new(theme: Theme) -> Result { let screen = Mutex::new(io::stdout().into_raw_mode()?); @@ -72,21 +98,24 @@ impl Screen { } pub async fn start(mut self) -> Result<()> { + let env = Environment::initial_must(self.theme); { let mut scr = self.screen.lock().await; - self.body.init(self.theme, &mut scr)?; + self.body.init(env, &mut scr)?; } while let Some(ev) = self.events_ch.recv().await { let mut scr = self.screen.lock().await; if let Event::Interrupt = ev { - if let Some(last) = self.last_interrupt && last.elapsed().as_millis() < 500 { - self.events_ch.close(); - break; + if let Some(last) = self.last_interrupt { + if last.elapsed().as_millis() < 500 { + self.events_ch.close(); + break; + } } self.last_interrupt = Some(Instant::now()); } - self.body.receive_event(self.theme, &mut scr, ev)?; + self.body.receive_event(env, &mut scr, ev)?; } // Cleanup diff --git a/src/display/theme.rs b/src/display/theme.rs index 5abab8f..a594263 100644 --- a/src/display/theme.rs +++ b/src/display/theme.rs @@ -66,6 +66,7 @@ impl Default for Theme { } impl Theme { + #[inline] pub fn display_string(&self) -> String { format!( "{primary_bg}{text}", diff --git a/src/main.rs b/src/main.rs index 170fd31..86cf4ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -#![feature(let_chains)] use std::process; use display::theme::Theme;