commit 63ff28dd5daf153bbbcd7ff001ced64f340225f4 Author: emilis Date: Tue Jan 17 02:06:16 2023 +0000 kk killed by kkx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0c919d6 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,73 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "kkdisp" +version = "0.1.0" +dependencies = [ + "anyhow", + "termion", +] + +[[package]] +name = "kkx" +version = "0.1.0" +dependencies = [ + "anyhow", + "kkdisp", +] + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_termios" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" +dependencies = [ + "redox_syscall", +] + +[[package]] +name = "termion" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "659c1f379f3408c7e5e84c7d0da6d93404e3800b6b9d063ba24436419302ec90" +dependencies = [ + "libc", + "numtoa", + "redox_syscall", + "redox_termios", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4a184a9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +members = [ + "kkx", + "kkdisp" +] diff --git a/kkdisp/Cargo.toml b/kkdisp/Cargo.toml new file mode 100644 index 0000000..00db0eb --- /dev/null +++ b/kkdisp/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "kkdisp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.68" +termion = "2.0.1" diff --git a/kkdisp/src/component.rs b/kkdisp/src/component.rs new file mode 100644 index 0000000..1b60c26 --- /dev/null +++ b/kkdisp/src/component.rs @@ -0,0 +1,12 @@ +#[derive(PartialEq, Eq, Debug)] +pub enum Component { + X(usize), + String(String), + Clear(Clear), +} + +#[derive(PartialEq, Eq, Debug)] +pub enum Clear { + Line, + Screen, +} diff --git a/kkdisp/src/lib.rs b/kkdisp/src/lib.rs new file mode 100644 index 0000000..3377f58 --- /dev/null +++ b/kkdisp/src/lib.rs @@ -0,0 +1,34 @@ +use std::io::{Stdout, Write}; +use termion::raw::{IntoRawMode, RawTerminal}; + +extern crate termion; +mod component; +mod token; + +pub struct Display { + // needs to hold the termion display + screen: RawTerminal, +} + +impl Display { + pub fn new() -> Result { + Ok(Self { + screen: std::io::stdout().into_raw_mode()?, + }) + } +} + +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/kkdisp/src/token.rs b/kkdisp/src/token.rs new file mode 100644 index 0000000..b88eccd --- /dev/null +++ b/kkdisp/src/token.rs @@ -0,0 +1,174 @@ +use crate::component::Component; + +// (line (centered (limited (padded "hello world")))) +#[derive(Debug, Clone)] +pub enum Token { + Centered(Box), + Limited(Box, usize), + CharPad(Box, char, usize), + String(String), +} + +impl From for Token { + fn from(value: String) -> Self { + Token::String(value) + } +} + +impl Token { + pub fn centered(self) -> Self { + Self::Centered(Box::new(self)) + } + + pub fn limited(self, lim: usize) -> Self { + Self::Limited(Box::new(self), lim) + } + + pub fn padded(self, pad_to: usize) -> Self { + Self::CharPad(Box::new(self), ' ', pad_to) + } + + pub fn str_len(&self) -> usize { + self.walk_to_end().len() + } + + pub fn pad_char(self, c: char, pad_to: usize) -> Self { + Self::CharPad(Box::new(self), c, pad_to) + } + + fn walk_to_end(&self) -> &String { + match self { + Token::String(s) => s, + Token::Centered(t) => t.walk_to_end(), + Token::Limited(t, _) => t.walk_to_end(), + Token::CharPad(t, _, _) => t.walk_to_end(), + } + } + + fn with_width(self, width: usize) -> Vec { + match self { + Token::String(s) => vec![Component::String(s)], + Token::Centered(cnt) => cnt + .with_width(width) + .into_iter() + .map(|comp| { + if let Component::String(s) = comp { + let str_len = s.len(); + let x = if str_len > width { + 0 + } else { + (width - str_len) / 2 + }; + vec![Component::X(x), Component::String(s)] + } else { + vec![comp] + } + }) + .flatten() + .collect(), + Token::Limited(s, lim) => s + .with_width(width) + .into_iter() + .map(|cmp| { + if let Component::String(mut s) = cmp { + s.truncate(lim); + Component::String(s) + } else { + cmp + } + }) + .collect(), + Token::CharPad(s, c, pad_to) => s + .with_width(width) + .into_iter() + .map(|comp| { + if let Component::String(s) = comp { + if s.len() >= pad_to { + return Component::String(s); + } + Component::String(format!( + "{}{}", + s, + c.to_string().repeat(pad_to - s.len()) + )) + } else { + comp + } + }) + .collect(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_token_gen() { + const WIDTH: usize = 20; + vec![ + ( + "string -> string", + Token::String("hello".into()), + vec![Component::String("hello".into())], + ), + ( + "string -> limited", + Token::String( + "This string is too long for this!".into(), + ) + .limited(4), + vec![Component::String("This".into())], + ), + ( + "string -> limit -> pad_to", + Token::String( + "This string is too long, but some".into(), + ) + .limited(10) + .padded(15), + vec![Component::String("This strin ".into())], + ), + ( + "center limited string", + Token::String("Ahhh this won't go far".into()) + .limited(10) + .centered(), + vec![ + Component::X((WIDTH - 10) / 2), + Component::String("Ahhh this ".into()), + ], + ), + ( + "padded string with underscores is centered", + Token::String("It was...".into()) + .pad_char('_', 15) + .centered(), + vec![ + Component::X(WIDTH - 3), + Component::String("It was...______".into()), + ], + ), + ] + .into_iter() + .for_each(|test| { + let (name, token, expected) = test; + eprintln!("token: {:#?}", &token); + let actual = token.with_width(WIDTH); + let actual_fmt = format!("{:#?}", &actual); + assert!( + expected + .iter() + .zip(actual.iter()) + .filter(|&(l, r)| l != r) + .count() + == 0, + "{} expected: {:#?} actual: {}", + name, + expected, + actual_fmt, + ) + }) + } +} diff --git a/kkx/Cargo.toml b/kkx/Cargo.toml new file mode 100644 index 0000000..b932acb --- /dev/null +++ b/kkx/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "kkx" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.68" +kkdisp = { version = "0.1.0", path = "../kkdisp" } diff --git a/kkx/src/main.rs b/kkx/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/kkx/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..0c3b24b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 70 \ No newline at end of file