ongoing frame work, still experimenting
This commit is contained in:
parent
0b9f43b9d2
commit
b66b5e5123
|
@ -357,17 +357,6 @@ dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fed"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"misskey",
|
|
||||||
"signal-hook",
|
|
||||||
"termion",
|
|
||||||
"tokio 1.24.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flume"
|
name = "flume"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
|
@ -669,6 +658,16 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kk"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"misskey",
|
||||||
|
"termion",
|
||||||
|
"tokio 1.24.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -1417,16 +1416,6 @@ dependencies = [
|
||||||
"opaque-debug",
|
"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]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
|
@ -2,11 +2,7 @@ use std::io::{Stdout, Write};
|
||||||
|
|
||||||
use termion::{clear, cursor, raw::RawTerminal};
|
use termion::{clear, cursor, raw::RawTerminal};
|
||||||
|
|
||||||
use super::{
|
use super::{Environment, Event, Page};
|
||||||
frame::{self, FrameDef},
|
|
||||||
theme::Theme,
|
|
||||||
Event, Page,
|
|
||||||
};
|
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, anyhow::Error>;
|
type Result<T> = std::result::Result<T, anyhow::Error>;
|
||||||
|
|
||||||
|
@ -17,15 +13,15 @@ pub enum Body {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Body {
|
impl Body {
|
||||||
fn echo(theme: Theme, screen: &mut RawTerminal<Stdout>, event: Event) -> Result<()> {
|
fn echo(env: Environment, screen: &mut RawTerminal<Stdout>, event: Event) -> Result<()> {
|
||||||
let event = format!("{}", event);
|
let event = format!("{}", event);
|
||||||
write!(
|
write!(
|
||||||
screen,
|
screen,
|
||||||
"{theme}{clear}{start}Event: {}",
|
"{theme}{clear}{start}{}",
|
||||||
event,
|
env.frame.write(&format!("Event: {}", event), 1, 1),
|
||||||
theme = theme.display_string(),
|
theme = env.theme.display_string(),
|
||||||
clear = clear::All,
|
clear = clear::All,
|
||||||
start = cursor::Goto(1, 1)
|
start = env.frame.goto(1, 1)
|
||||||
)?;
|
)?;
|
||||||
screen.flush()?;
|
screen.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -35,24 +31,24 @@ impl Body {
|
||||||
impl Page for Body {
|
impl Page for Body {
|
||||||
fn receive_event(
|
fn receive_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
theme: Theme,
|
env: Environment,
|
||||||
screen: &mut RawTerminal<Stdout>,
|
screen: &mut RawTerminal<Stdout>,
|
||||||
event: Event,
|
event: Event,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Body::Signin(b) => b.receive_event(theme, screen, event)?,
|
Body::Signin(b) => b.receive_event(env, screen, event)?,
|
||||||
Body::Echo => Body::echo(theme, screen, event)?,
|
Body::Echo => Body::echo(env, screen, event)?,
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, theme: Theme, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
||||||
write!(
|
write!(
|
||||||
screen,
|
screen,
|
||||||
"{theme}{cursor}{clear}{fr}",
|
"{theme}{clear}{cursor}{fr}",
|
||||||
fr = frame::draw_frame(theme, FrameDef::ByPercent(90, 90)),
|
theme = env.theme.display_string(),
|
||||||
theme = theme.display_string(),
|
fr = env.frame.frame_str(),
|
||||||
cursor = cursor::Goto(1, 1),
|
cursor = env.frame.goto(0, 0),
|
||||||
clear = clear::All
|
clear = clear::All
|
||||||
)?;
|
)?;
|
||||||
screen.flush()?;
|
screen.flush()?;
|
||||||
|
@ -89,20 +85,19 @@ impl SigninPage {
|
||||||
impl Page for SigninPage {
|
impl Page for SigninPage {
|
||||||
fn receive_event(
|
fn receive_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
theme: Theme,
|
env: Environment,
|
||||||
screen: &mut RawTerminal<Stdout>,
|
screen: &mut RawTerminal<Stdout>,
|
||||||
event: Event,
|
event: Event,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(&self, theme: Theme, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()> {
|
||||||
let fr = frame::draw_frame(theme, FrameDef::ByPercent(40, 40));
|
|
||||||
write!(
|
write!(
|
||||||
screen,
|
screen,
|
||||||
"{theme}{clear}{hide_cursor}{frame}",
|
"{theme}{clear}{hide_cursor}{frame}",
|
||||||
frame = fr,
|
frame = env.frame.frame_str(),
|
||||||
theme = theme.display_string(),
|
theme = env.theme.display_string(),
|
||||||
clear = clear::All,
|
clear = clear::All,
|
||||||
hide_cursor = cursor::Hide,
|
hide_cursor = cursor::Hide,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -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;
|
const ESTIMATED_FRAME_BIT_SIZE: usize = 11;
|
||||||
|
|
||||||
pub enum FrameDef {
|
const FRAME_CHAR: char = ' ';
|
||||||
|
|
||||||
|
pub enum FrameSize {
|
||||||
ByAbsolute(u16, u16),
|
ByAbsolute(u16, u16),
|
||||||
ByPercent(u16, u16),
|
ByPercent(u16, u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Frame {
|
#[derive(Debug, Clone, Copy)]
|
||||||
start: (u16, u16),
|
pub struct Frame {
|
||||||
end: (u16, u16),
|
start: (u16, u16), // (w, h)
|
||||||
|
end: (u16, u16), // (w, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
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<Self, anyhow::Error> {
|
||||||
|
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 {
|
Self {
|
||||||
start: (term.0 - pos.0, term.1 - pos.1),
|
start: (1.max(term_w - pos_w), 1.max(term_h - pos_h)),
|
||||||
end: pos,
|
end: (pos_w, pos_h),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frame_str(&self, frame_char: char) -> String {
|
pub fn frame_str(&self) -> String {
|
||||||
let (w_len, h_len) = (
|
let (w_len, h_len) = (
|
||||||
(self.end.0 - self.start.0) as usize,
|
(self.end.0 - self.start.0) as usize,
|
||||||
(self.end.1 - self.start.1 - 1) 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 mut frame = String::with_capacity((h_len * 2) + (w_len * 2) * ESTIMATED_FRAME_BIT_SIZE);
|
||||||
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));
|
||||||
|
@ -36,67 +87,33 @@ impl Frame {
|
||||||
for y in self.start.1 + 1..self.end.1 {
|
for y in self.start.1 + 1..self.end.1 {
|
||||||
frame.push_str(&format!(
|
frame.push_str(&format!(
|
||||||
"{left}{char}{right}{char}",
|
"{left}{char}{right}{char}",
|
||||||
left = cursor::Goto(self.start.0, y),
|
left = self.goto(self.start.0, y),
|
||||||
right = cursor::Goto(self.end.0, y),
|
right = self.goto(self.end.0, y),
|
||||||
char = frame_char,
|
char = FRAME_CHAR,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
frame.push_str(&make_line(self.end.1));
|
frame.push_str(&make_line(self.end.1));
|
||||||
|
frame.push_str(&self.goto(1, 1));
|
||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
impl FrameSize {
|
||||||
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 {
|
|
||||||
fn abs_size(&self) -> Frame {
|
fn abs_size(&self) -> 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 {
|
||||||
FrameDef::ByAbsolute(h, w) => {
|
FrameSize::ByAbsolute(h, w) => ((*h).min(term_height), (*w).min(term_width)),
|
||||||
let (mut h, mut w) = (*h, *w);
|
FrameSize::ByPercent(h, w) => {
|
||||||
if h > term_height {
|
|
||||||
h = term_height;
|
|
||||||
}
|
|
||||||
if w > term_width {
|
|
||||||
w = term_width;
|
|
||||||
}
|
|
||||||
(h, w)
|
|
||||||
}
|
|
||||||
FrameDef::ByPercent(h, w) => {
|
|
||||||
// term_height = 100%
|
// term_height = 100%
|
||||||
// x = h%
|
// x = h%
|
||||||
// x = term_height * h / 100
|
// x = term_height * h / 100
|
||||||
let (h, w) = (
|
(
|
||||||
if *h > 100 { 100 } else { *h },
|
term_height * (*h).min(100) / 100,
|
||||||
if *w > 100 { 100 } else { *w },
|
term_width * (*w).min(100) / 100,
|
||||||
);
|
)
|
||||||
// (h * 100 / term_height, w * 100 / term_width)
|
|
||||||
(term_height * h / 100, term_width * w / 100)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Frame::from_bottom_right(pos, (term_height, term_width))
|
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('='),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ use tokio::sync::Mutex;
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
|
|
||||||
use self::body::Body;
|
use self::body::Body;
|
||||||
|
use self::frame::Frame;
|
||||||
use self::theme::Theme;
|
use self::theme::Theme;
|
||||||
|
|
||||||
pub mod body;
|
pub mod body;
|
||||||
|
@ -46,15 +47,40 @@ impl From<Key> for Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Page {
|
pub trait Page {
|
||||||
fn init(&self, theme: Theme, screen: &mut RawTerminal<Stdout>) -> Result<()>;
|
fn init(&self, env: Environment, screen: &mut RawTerminal<Stdout>) -> Result<()>;
|
||||||
fn receive_event(
|
fn receive_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
theme: Theme,
|
env: Environment,
|
||||||
screen: &mut RawTerminal<Stdout>,
|
screen: &mut RawTerminal<Stdout>,
|
||||||
event: Event,
|
event: Event,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Environment {
|
||||||
|
pub theme: Theme,
|
||||||
|
pub frame: Frame,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<String> 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 {
|
impl Screen {
|
||||||
pub fn new(theme: Theme) -> Result<Self> {
|
pub fn new(theme: Theme) -> Result<Self> {
|
||||||
let screen = Mutex::new(io::stdout().into_raw_mode()?);
|
let screen = Mutex::new(io::stdout().into_raw_mode()?);
|
||||||
|
@ -72,21 +98,24 @@ impl Screen {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(mut self) -> Result<()> {
|
pub async fn start(mut self) -> Result<()> {
|
||||||
|
let env = Environment::initial_must(self.theme);
|
||||||
{
|
{
|
||||||
let mut scr = self.screen.lock().await;
|
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 {
|
while let Some(ev) = self.events_ch.recv().await {
|
||||||
let mut scr = self.screen.lock().await;
|
let mut scr = self.screen.lock().await;
|
||||||
if let Event::Interrupt = ev {
|
if let Event::Interrupt = ev {
|
||||||
if let Some(last) = self.last_interrupt && last.elapsed().as_millis() < 500 {
|
if let Some(last) = self.last_interrupt {
|
||||||
self.events_ch.close();
|
if last.elapsed().as_millis() < 500 {
|
||||||
break;
|
self.events_ch.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.last_interrupt = Some(Instant::now());
|
self.last_interrupt = Some(Instant::now());
|
||||||
}
|
}
|
||||||
self.body.receive_event(self.theme, &mut scr, ev)?;
|
self.body.receive_event(env, &mut scr, ev)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
|
|
|
@ -66,6 +66,7 @@ impl Default for Theme {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Theme {
|
impl Theme {
|
||||||
|
#[inline]
|
||||||
pub fn display_string(&self) -> String {
|
pub fn display_string(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{primary_bg}{text}",
|
"{primary_bg}{text}",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#![feature(let_chains)]
|
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use display::theme::Theme;
|
use display::theme::Theme;
|
||||||
|
|
Loading…
Reference in New Issue