From f11e2e3a64a85bd36090fe3121163f0fa585aa19 Mon Sep 17 00:00:00 2001 From: pointer-to-bios Date: Wed, 25 Sep 2024 01:40:35 +0800 Subject: [PATCH] base application --- Cargo.lock | 249 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 + config/default.toml | 7 ++ src/application.rs | 171 +++++++++++++++++++++++++++++- src/colortheme.rs | 30 ++++++ src/lib.rs | 31 +++++- src/main.rs | 11 +- src/window.rs | 6 ++ 8 files changed, 501 insertions(+), 7 deletions(-) create mode 100644 config/default.toml create mode 100644 src/colortheme.rs create mode 100644 src/window.rs diff --git a/Cargo.lock b/Cargo.lock index ac6d8e4..896b34b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,54 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + [[package]] name = "cfg-if" version = "1.0.0" @@ -45,6 +81,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.9" @@ -55,12 +97,34 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "libc" version = "0.2.158" @@ -89,6 +153,21 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.2" @@ -107,6 +186,18 @@ name = "muxde" version = "0.1.0" dependencies = [ "crossterm", + "serde", + "tokio", + "toml", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", ] [[package]] @@ -132,6 +223,30 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + [[package]] name = "redox_syscall" version = "0.5.4" @@ -141,6 +256,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustix" version = "0.38.37" @@ -160,6 +281,35 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + [[package]] name = "signal-hook" version = "0.3.17" @@ -196,6 +346,96 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -296,3 +536,12 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 286e22f..298313a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,6 @@ edition = "2021" [dependencies] crossterm = "0.28.1" +serde = { version = "1.0.210", features = ["derive", "serde_derive"] } +tokio = { version = "1.40.0", features = ["full"] } +toml = "0.8.19" diff --git a/config/default.toml b/config/default.toml new file mode 100644 index 0000000..1f29b0b --- /dev/null +++ b/config/default.toml @@ -0,0 +1,7 @@ +[colortheme] +background = [26, 26, 28] +command_bar = [20, 28, 20] + +[command] +new_window = "n" +quit = "q" diff --git a/src/application.rs b/src/application.rs index b538973..60150d0 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,3 +1,170 @@ +use std::{ + collections::HashMap, + io::{self, stdout, Stdout, Write}, + thread, + time::Duration, +}; + +use crossterm::{ + cursor, event, queue, + style::{self, Color}, + terminal::{self, disable_raw_mode, enable_raw_mode, ClearType}, +}; + +use crate::{colortheme::ColorTheme, iterate_config, window::Window, Config}; + pub struct Application { - windows: Window, -} \ No newline at end of file + config: Config, + colortheme: ColorTheme, + stdout: Stdout, + size: (u16, u16), + windows: HashMap, + command_mode: bool, + command: String, + cmdbar_show: String, +} + +impl Application { + pub fn new(config: Config) -> Result { + queue!( + stdout(), + event::EnableMouseCapture, + terminal::EnterAlternateScreen, + terminal::Clear(ClearType::All), + style::SetBackgroundColor(Color::Black) + )?; + enable_raw_mode()?; + stdout().flush()?; + Ok(Application { + colortheme: ColorTheme::from(config.get("colortheme").unwrap().as_table().unwrap()), + config, + stdout: stdout(), + size: terminal::size()?, + windows: HashMap::new(), + command_mode: true, + command: String::new(), + cmdbar_show: String::new(), + }) + } + + pub fn exec(&mut self) -> io::Result<()> { + self.render()?; + self.stdout.flush()?; + loop { + if event::poll(Duration::from_secs(5))? { + match event::read()? { + event::Event::FocusGained => queue!(self.stdout, cursor::Show)?, + event::Event::FocusLost => queue!(self.stdout, cursor::Hide)?, + event::Event::Key(key_event) => match key_event.code { + event::KeyCode::Backspace => { + if self.command_mode { + self.command.pop(); + self.cmdbar_show.clone_from(&self.command); + } + } + event::KeyCode::Enter => (), + event::KeyCode::Left => (), + event::KeyCode::Right => (), + event::KeyCode::Up => (), + event::KeyCode::Down => (), + event::KeyCode::Home => (), + event::KeyCode::End => (), + event::KeyCode::PageUp => (), + event::KeyCode::PageDown => (), + event::KeyCode::Tab => (), + event::KeyCode::BackTab => (), + event::KeyCode::Delete => (), + event::KeyCode::Insert => (), + event::KeyCode::F(_) => (), + event::KeyCode::Char(c) => { + if self.command_mode { + self.command.push(c); + self.cmdbar_show.clone_from(&self.command); + } + } + event::KeyCode::Null => (), + event::KeyCode::Esc => (), + event::KeyCode::CapsLock => (), + event::KeyCode::ScrollLock => (), + event::KeyCode::NumLock => (), + event::KeyCode::PrintScreen => (), + event::KeyCode::Pause => (), + event::KeyCode::Menu => (), + event::KeyCode::KeypadBegin => (), + event::KeyCode::Media(media_key_code) => (), + event::KeyCode::Modifier(modifier_key_code) => (), + }, + event::Event::Mouse(mouse_event) => (), + event::Event::Paste(_) => (), + event::Event::Resize(w, h) => self.size = (w, h), + } + self.render()?; + let f = |_, value| { + if let &toml::Value::String(ref s) = value { + s == &self.command + } else { + false + } + }; + if let toml::Value::Table(map) = &self.config.get("command").unwrap() { + if let Some((name, _)) = iterate_config(map, &f) { + match name.as_str() { + "quit" => break, + "print" => queue!( + self.stdout, + style::SetBackgroundColor(self.colortheme.background), + cursor::SavePosition, + cursor::MoveTo(0, 0), + style::Print("Hello"), + cursor::RestorePosition, + )?, + _ => (), + } + self.command.clear(); + } + } + self.stdout.flush()?; + } else { + } + } + self.render()?; + self.stdout.flush()?; + thread::sleep(Duration::from_millis(200)); + Ok(()) + } + + fn render(&mut self) -> io::Result<()> { + let mut show = String::new(); + for c in self.cmdbar_show.chars() { + show.push(c); + if cursor::position().unwrap().0 >= self.size.0 - 1 { + break; + } + } + queue!( + self.stdout, + style::SetBackgroundColor(self.colortheme.command_bar), + cursor::MoveTo(0, self.size.1 - 1), + style::Print(show), + )?; + let x = cursor::position().unwrap().0; + queue!( + self.stdout, + style::Print(" ".repeat((self.size.0 - x) as usize)), + cursor::MoveTo(x, self.size.1 - 1), + )?; + Ok(()) + } +} + +impl Drop for Application { + fn drop(&mut self) { + disable_raw_mode().unwrap(); + queue!( + self.stdout, + terminal::LeaveAlternateScreen, + event::DisableMouseCapture, + ) + .unwrap(); + } +} diff --git a/src/colortheme.rs b/src/colortheme.rs new file mode 100644 index 0000000..8110510 --- /dev/null +++ b/src/colortheme.rs @@ -0,0 +1,30 @@ +use crossterm::style::Color; +use toml::{Table, Value}; + + +pub struct ColorTheme { + pub background: Color, + pub command_bar: Color, +} + +impl From<&Table> for ColorTheme { + fn from(value: &Table) -> Self { + let f = |name| { + if let Value::Array(arr) = value.get(name).unwrap() { + Color::Rgb { + r: arr[0].as_integer().unwrap() as u8, + g: arr[1].as_integer().unwrap() as u8, + b: arr[2].as_integer().unwrap() as u8, + } + } else { + panic!(); + } + }; + let background = f("background"); + let command_bar = f("command_bar"); + Self { + background, + command_bar, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e566fe7..44ecab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,32 @@ pub mod application; +pub mod colortheme; +pub mod window; + +use std::io; use application::Application; +use toml::map::Map; -pub fn run() { - let app = Application::new(); -} \ No newline at end of file +pub type Config = Map; + +pub fn iterate_config<'a, 'b: 'a, F>(config: &'b Config, f: &F) -> Option<(String, toml::Value)> +where + F: Fn(&'a str, &'b toml::Value) -> bool, +{ + for (name, value) in config { + if let toml::Value::Table(map) = value { + if let Some(p) = iterate_config(map, f) { + return Some(p); + } + } else if f(name, value) { + return Some((name.clone(), value.clone())); + } + } + None +} + +pub fn run(config: Config) -> io::Result<()> { + let mut app = Application::new(config)?; + app.exec()?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 283a1fb..d175466 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,10 @@ -fn main() { - crate::run(); +use std::fs; + +use muxde::{run, Config}; + +fn main() -> std::io::Result<()> { + let config = fs::read_to_string("config/default.toml")?; + let config: Config = toml::from_str(&config).unwrap(); + run(config)?; + Ok(()) } diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 0000000..41ad61f --- /dev/null +++ b/src/window.rs @@ -0,0 +1,6 @@ +pub struct Window { + pos: (u16, u16), + size: (u16, u16), +} + +