frame width, clearing, debug log

This commit is contained in:
emilis 2023-01-14 17:59:45 +00:00
parent a64048104c
commit 9f7be00735
5 changed files with 124 additions and 71 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target /target
debug.log

View File

@ -9,7 +9,7 @@ type Result<T> = std::result::Result<T, anyhow::Error>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Body { pub enum Body {
Echo, Echo,
Signin(SigninPage), // Signin(SigninPage),
} }
impl Body { impl Body {
@ -17,9 +17,10 @@ impl Body {
let event = format!("{}", event); let event = format!("{}", event);
write!( write!(
screen, screen,
"{fr}{}", "{clear}{frame}{content}",
env.frame.writeln(&format!("Event: {}", event), 1, 1), clear = clear::All,
fr = env.primary_frame(), frame = env.frame.frame_str(env.theme.primary()),
content = env.frame.writeln(&format!("Event: {}", event), 0, 0),
)?; )?;
screen.flush()?; screen.flush()?;
Ok(()) Ok(())
@ -34,7 +35,7 @@ impl Page for Body {
event: Event, event: Event,
) -> Result<()> { ) -> Result<()> {
match self { 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)?, Body::Echo => Body::echo(env, screen, event)?,
}; };
Ok(()) Ok(())
@ -45,7 +46,7 @@ impl Page for Body {
screen, screen,
"{hide}{clear}{fr}{cursor}", "{hide}{clear}{fr}{cursor}",
hide = cursor::Hide, 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), cursor = env.frame.goto(0, 0),
clear = clear::All clear = clear::All
)?; )?;
@ -54,51 +55,51 @@ impl Page for Body {
} }
} }
#[derive(Debug, Clone, Default)] // #[derive(Debug, Clone, Default)]
struct SigninPage { // struct SigninPage {
hostname: String, // hostname: String,
username: String, // username: String,
cursor: SigninCursorLocation, // cursor: SigninCursorLocation,
} // }
#[derive(Debug, Clone)] // #[derive(Debug, Clone)]
enum SigninCursorLocation { // enum SigninCursorLocation {
Hostname, // Hostname,
Username, // Username,
Next, // Next,
} // }
impl Default for SigninCursorLocation { // impl Default for SigninCursorLocation {
fn default() -> Self { // fn default() -> Self {
Self::Hostname // Self::Hostname
} // }
} // }
impl SigninPage { // impl SigninPage {
fn frame_string() -> String { // fn frame_string() -> String {
format!("") // format!("")
} // }
} // }
impl Page for SigninPage { // impl Page for SigninPage {
fn receive_event( // fn receive_event(
&mut self, // &mut self,
env: Environment, // env: Environment,
screen: &mut RawTerminal<Stdout>, // screen: &mut RawTerminal<Stdout>,
event: Event, // event: Event,
) -> Result<()> { // ) -> Result<()> {
Ok(()) // Ok(())
} // }
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> { // fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
write!( // write!(
screen, // screen,
"{frame}{hide_cursor}", // "{frame}{hide_cursor}",
frame = env.frame.frame_str(&env.theme, env.theme.primary()), // frame = env.frame.frame_str(&env.theme, env.theme.primary()),
hide_cursor = cursor::Hide, // hide_cursor = cursor::Hide,
)?; // )?;
screen.flush()?; // screen.flush()?;
Ok(()) // Ok(())
} // }
} // }

15
src/display/debug.rs Normal file
View File

@ -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;

View File

@ -3,10 +3,12 @@ use termion::{clear, cursor};
const ESTIMATED_FRAME_BIT_SIZE: usize = 11; const ESTIMATED_FRAME_BIT_SIZE: usize = 11;
use std::io::Write; use std::io::Write;
use crate::display::debug::debug;
use super::theme::Theme; use super::theme::Theme;
const FRAME_CHAR_HORIZONTAL: char = 'h'; const FRAME_CHAR_HORIZONTAL: char = ' ';
const FRAME_CHAR_VERTICAL: char = 'v'; const FRAME_CHAR_VERTICAL: char = ' ';
pub enum FrameSize { pub enum FrameSize {
ByAbsolute(u16, u16), ByAbsolute(u16, u16),
@ -18,72 +20,100 @@ pub struct Frame {
// Both are (w, h) // Both are (w, h)
start: (u16, u16), start: (u16, u16),
end: (u16, u16), end: (u16, u16),
width: u16,
theme: Theme,
} }
impl Frame { impl Frame {
#[inline] #[inline(always)]
pub fn goto(&self, x: u16, y: u16) -> String { pub fn goto(&self, x: u16, y: u16) -> String {
let cg = cursor::Goto( let cg = cursor::Goto(
(self.start.0 + x).min(self.end.0 - 1), (self.width + self.start.0 + x).min(self.end.0 - self.width),
(self.start.1 + y).min(self.end.1 - 1), (self.width + self.start.1 + y).min(self.end.1 - self.width),
); );
cg.into() 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 { pub fn writeln(&self, s: &str, x: u16, y: u16) -> String {
let words = s.split('\n').collect::<Vec<&str>>(); let words = s.split('\n').collect::<Vec<&str>>();
let mut out_words = Vec::with_capacity(words.len()); let mut out_words = Vec::with_capacity(words.len());
for i in 0..words.len() { for i in 0..words.len() {
out_words.push(format!( out_words.push(format!(
"{str}{ret}", "{ret}{str}",
str = words[i], str = words[i],
ret = self.goto(1, y + i as u16 + 1) ret = self.goto(x, y + i as u16),
)); ));
} }
out_words.concat() out_words.concat()
} }
#[inline] #[inline(always)]
pub fn size(&self) -> (u16, u16) { pub fn size(&self) -> (u16, u16) {
(self.end.0 - self.start.0, self.end.1 - self.start.1) (self.end.0 - self.start.0, self.end.1 - self.start.1)
} }
pub fn from_terminal_size() -> Result<Self, anyhow::Error> { #[inline(always)]
pub fn from_terminal_size(theme: Theme, width: u16) -> Result<Self, anyhow::Error> {
let term = termion::terminal_size()?; let term = termion::terminal_size()?;
// Swap term dimensions to use x/y // Swap term dimensions to use x/y
let term = (term.1, term.0); 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 { Self {
start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)), start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)),
end: (pos_w, pos_h), end: (pos_w, pos_h),
width,
theme,
} }
} }
pub fn frame_str(&self, theme: &Theme, body_theme: String) -> String { pub fn frame_str(&self, body_theme: String) -> String {
self.goto(0, 0); if self.width == 0 {
return body_theme + &clear::All.to_string();
}
self.goto_internal(0, 0);
let (w_len, h_len) = self.size(); let (w_len, h_len) = self.size();
let width_str = FRAME_CHAR_HORIZONTAL.to_string().repeat(w_len as usize + 1); 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 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(); let body_clear = body_theme.clone() + &clear::CurrentLine.to_string();
frame.push(frame_theme.clone()); frame.push(frame_theme.clone());
let make_line = let make_line =
|y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y)); |y: u16| format!("{left}{}", width_str, left = cursor::Goto(self.start.0, y));
frame.push(make_line(self.start.1)); for y in 0..self.width {
for y in self.start.1 + 1..self.end.1 { frame.push(make_line(self.start.1 + y));
}
for y in self.width + self.start.1..self.end.1 - self.width {
frame.push(format!( frame.push(format!(
"{left}{body_clear}{frame_theme}{char}{right}{char}", "{left}{body_clear}{frame_theme}{char}{right}{char}",
body_clear = &body_clear, body_clear = &body_clear,
frame_theme = &frame_theme, frame_theme = &frame_theme,
left = cursor::Goto(self.start.0, y), left = cursor::Goto(self.start.0, y),
right = cursor::Goto(self.start.0 + self.end.0, y), right = cursor::Goto(self.start.0 + self.end.0 - self.width, y),
char = FRAME_CHAR_VERTICAL, 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(make_line(self.end.1));
frame.push(self.goto(1, 1)); frame.push(self.goto(1, 1));
frame.push(body_theme); frame.push(body_theme);
@ -92,7 +122,8 @@ impl Frame {
} }
impl FrameSize { impl FrameSize {
fn abs_size(&self) -> Frame { #[inline(always)]
fn abs_size(&self, theme: Theme, width: u16) -> Frame {
let (term_height, term_width) = let (term_height, term_width) =
termion::terminal_size().expect("could not get terminal size"); termion::terminal_size().expect("could not get terminal size");
let pos = match self { 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)
} }
} }

View File

@ -13,6 +13,7 @@ use self::frame::Frame;
use self::theme::{Color, Theme}; use self::theme::{Color, Theme};
pub mod body; pub mod body;
pub mod debug;
pub mod frame; pub mod frame;
pub mod theme; pub mod theme;
type Result<T> = std::result::Result<T, anyhow::Error>; type Result<T> = std::result::Result<T, anyhow::Error>;
@ -66,7 +67,7 @@ impl Into<String> for Environment {
fn into(self) -> String { fn into(self) -> String {
format!( format!(
"{frame}{theme}", "{frame}{theme}",
frame = self.frame.frame_str(&self.theme, self.theme.primary()), frame = self.frame.frame_str(self.theme.primary()),
theme = self.theme.primary(), theme = self.theme.primary(),
) )
} }
@ -74,15 +75,18 @@ impl Into<String> for Environment {
impl Environment { impl Environment {
fn initial_must(theme: Theme) -> Self { 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 { Self {
theme, 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)] #[inline(always)]
pub fn primary_frame(&self) -> String { 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, clear = clear::All,
show_cursor = cursor::Show, show_cursor = cursor::Show,
)?; )?;
scr.flush();
Ok(()) Ok(())
} }