diff --git a/Cargo.lock b/Cargo.lock index 0d10269a..415941ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "autocfg" @@ -34,20 +34,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.3.19" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" dependencies = [ "anstyle", "clap_lex", @@ -55,9 +54,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -67,9 +66,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "crossterm" @@ -114,6 +113,43 @@ dependencies = [ "version_check", ] +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "heck" version = "0.4.1" @@ -230,12 +266,6 @@ dependencies = [ "libc", ] -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - [[package]] name = "parking_lot" version = "0.12.1" @@ -259,6 +289,18 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "powerfmt" version = "0.2.0" @@ -267,18 +309,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -311,18 +353,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -369,6 +411,15 @@ dependencies = [ "libc", ] +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.11.2" @@ -377,9 +428,9 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "syn" -version = "2.0.32" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -405,7 +456,6 @@ version = "0.1.0" dependencies = [ "clap", "humansize", - "yggdrasil-rt", ] [[package]] @@ -461,9 +511,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" @@ -571,13 +621,22 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "yasync" +version = "0.1.0" +dependencies = [ + "futures-util", +] + [[package]] name = "yggdrasil-abi" version = "0.1.0" +source = "git+https://git.alnyan.me/yggdrasil/yggdrasil-abi.git#c957a433c73bd704ca0c64c16477638ababe2432" [[package]] name = "yggdrasil-rt" version = "0.1.0" +source = "git+https://git.alnyan.me/yggdrasil/yggdrasil-rt.git#f00ecdb926c2f912d658589f9f631100e41ad6c5" dependencies = [ "yggdrasil-abi", ] diff --git a/Cargo.toml b/Cargo.toml index 0940d052..bd2c55dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,3 @@ members = [ "sysutils", "red" ] - -[patch.'https://git.alnyan.me/yggdrasil/yggdrasil-abi.git'] -yggdrasil-abi = { path = "../abi" } - -[patch.'https://git.alnyan.me/yggdrasil/yggdrasil-rt.git'] -yggdrasil-rt = { path = "rt" } diff --git a/etc/inittab b/etc/inittab index e20b92de..970e4c55 100644 --- a/etc/inittab +++ b/etc/inittab @@ -1,3 +1,3 @@ init:1:wait:/sbin/rc default -user:1:once:/sbin/login /dev/tty0 +user:1:once:/sbin/login /dev/ttyS0 diff --git a/red/src/config.rs b/red/src/config.rs index 464f88fa..0283a970 100644 --- a/red/src/config.rs +++ b/red/src/config.rs @@ -1,7 +1,7 @@ use crate::{ buffer::Mode, command::Action, - keymap::{bind, KeyMap, PrefixNode}, + keymap::{bindn, bind1, KeyMap, KeySeq, PrefixNode}, }; pub struct Config { @@ -18,30 +18,30 @@ impl Default for Config { use Action::*; let nmap = KeyMap::from_iter([ - bind('i', [InsertBefore]), - bind('a', [InsertAfter]), - bind('h', [MoveCharPrev]), - bind('l', [MoveCharNext]), - bind('j', [MoveLineForward(1)]), - bind("J", [MoveLineForward(25)]), - bind('k', [MoveLineBack(1)]), - bind("K", [MoveLineBack(25)]), - bind("gg", [MoveFirstLine]), - bind("G", [MoveLastLine]), - bind('I', [MoveLineStart, InsertBefore]), - bind('A', [MoveLineEnd, InsertAfter]), - bind('o', [NewlineAfter, MoveLineForward(1), InsertBefore]), - bind('O', [NewlineBefore, MoveLineBack(1), InsertBefore]), - bind("dd", [KillLine]), + bind1('i', [InsertBefore]), + bind1('a', [InsertAfter]), + bind1('h', [MoveCharPrev]), + bind1('l', [MoveCharNext]), + bind1('j', [MoveLineForward(1)]), + bind1('J', [MoveLineForward(25)]), + bind1('k', [MoveLineBack(1)]), + bind1('K', [MoveLineBack(25)]), + bindn(['g', 'g'], [MoveFirstLine]), + bind1('G', [MoveLastLine]), + bind1('I', [MoveLineStart, InsertBefore]), + bind1('A', [MoveLineEnd, InsertAfter]), + bind1('o', [NewlineAfter, MoveLineForward(1), InsertBefore]), + bind1('O', [NewlineBefore, MoveLineBack(1), InsertBefore]), + bindn(['d', 'd'], [KillLine]), ]); let imap = KeyMap::from_iter([ - bind('\x7F', [EraseBackward]), - bind( + bind1('\x7F', [EraseBackward]), + bind1( '\n', [BreakLine, MoveLineForward(1), MoveLineStart, InsertBefore], ), - bind( + bind1( '\x0D', [BreakLine, MoveLineForward(1), MoveLineStart, InsertBefore], ), @@ -57,10 +57,10 @@ impl Default for Config { } impl Config { - pub fn key(&self, mode: Mode, key: &str) -> Option<&PrefixNode>> { + pub fn key_seq(&self, mode: Mode, seq: &KeySeq) -> Option<&PrefixNode>> { match mode { - Mode::Normal => self.nmap.get(key), - Mode::Insert => self.imap.get(key), + Mode::Normal => self.nmap.get(seq), + Mode::Insert => self.imap.get(seq), } } } diff --git a/red/src/keymap/key.rs b/red/src/keymap/key.rs new file mode 100644 index 00000000..32dfb425 --- /dev/null +++ b/red/src/keymap/key.rs @@ -0,0 +1,76 @@ +use std::fmt::{self, Write}; + +use super::map::Prefix; + +#[derive(Clone, Copy, PartialEq, Debug, Hash, Eq)] +pub enum Key { + Char(char), + Escape, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct KeySeq(Vec); + +impl KeySeq { + pub fn one>(k: I) -> Self { + Self(vec![k.into()]) + } + + pub fn empty() -> Self { + Self(vec![]) + } + + pub fn push>(&mut self, k: I) { + self.0.push(k.into()); + } + + pub fn clear(&mut self) { + self.0.clear(); + } +} + +impl Prefix for KeySeq { + fn prefix(&self) -> Option { + self.0.split_last().map(|(_, vs)| vs.iter().copied().collect()).map(Self) + } +} + +impl, I: IntoIterator> From for KeySeq { + fn from(value: I) -> Self { + Self(value.into_iter().map(Into::into).collect()) + } +} + +impl From for KeySeq { + fn from(value: Key) -> Self { + Self::one(value) + } +} + +impl fmt::Display for KeySeq { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (i, key) in self.0.iter().enumerate() { + if i != 0 { + f.write_char('+')?; + } + fmt::Display::fmt(key, f)?; + } + Ok(()) + } +} + +impl From for Key { + fn from(value: char) -> Self { + Self::Char(value) + } +} + +impl fmt::Display for Key { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Char('\t') => f.write_str(""), + Self::Char(key) => fmt::Display::fmt(key, f), + Self::Escape => f.write_str(""), + } + } +} diff --git a/red/src/keymap/mod.rs b/red/src/keymap/mod.rs index b40462b0..480036f0 100644 --- a/red/src/keymap/mod.rs +++ b/red/src/keymap/mod.rs @@ -1,18 +1,18 @@ -use std::{ - borrow::Borrow, - hash::Hash, -}; +use std::{borrow::Borrow, hash::Hash}; use crate::command::Action; -use self::map::{PrefixMap, Prefix}; +use self::map::PrefixMap; pub use self::map::PrefixNode; +mod key; mod map; -#[derive(Debug, Default)] +pub use key::{Key, KeySeq}; + +#[derive(Debug)] pub struct KeyMap { - map: PrefixMap>, + map: PrefixMap>, } impl KeyMap { @@ -22,64 +22,37 @@ impl KeyMap { } } - pub fn get(&self, key: &N) -> Option<&PrefixNode>> + pub fn get(&self, key: &N) -> Option<&PrefixNode>> where - String: Borrow, + KeySeq: Borrow, N: Eq + Hash + ?Sized, { self.map.get(key) } } -impl FromIterator<(String, Vec)> for KeyMap { - fn from_iter)>>(iter: T) -> Self { +impl FromIterator<(KeySeq, Vec)> for KeyMap { + fn from_iter)>>(iter: T) -> Self { Self { map: PrefixMap::from_iter(iter), } } } -impl Prefix for String { - fn prefix(&self) -> Option { - if self.is_empty() { - None - } else { - let mut res = self.clone(); - res.remove(res.len() - 1); - Some(res) - } - } -} - -pub fn bind, V: IntoIterator>( +pub fn bindn, V: IntoIterator>( key: I, actions: V, -) -> (String, Vec) { +) -> (KeySeq, Vec) { (key.into(), actions.into_iter().collect()) } +pub fn bind1, V: IntoIterator>(key: I, actions: V) -> (KeySeq, Vec) { + (KeySeq::one(key), actions.into_iter().collect()) +} + #[cfg(test)] mod tests { - use std::collections::HashSet; - - use crate::{command::Action, keymap::PrefixNode}; - - use super::{bind, KeyMap}; - #[test] fn from_iter() { - let map = KeyMap::from_iter([ - bind("aa", [Action::InsertBefore, Action::MoveLineEnd]), - ]); - - assert_eq!( - map.get("a"), - Some(&PrefixNode::Prefix(HashSet::from_iter(["aa".to_owned()]))) - ); - - assert_eq!( - map.get("aa"), - Some(&PrefixNode::Leaf([Action::InsertBefore, Action::MoveLineEnd].to_vec())) - ); } } diff --git a/red/src/main.rs b/red/src/main.rs index 8399a0b6..be2a345b 100644 --- a/red/src/main.rs +++ b/red/src/main.rs @@ -1,4 +1,4 @@ -#![feature(let_chains, rustc_private)] +#![feature(let_chains, rustc_private, async_fn_in_trait)] #![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_raw_fd, yggdrasil_os))] use std::{env, fmt::Write, path::Path}; @@ -6,7 +6,7 @@ use std::{env, fmt::Write, path::Path}; use buffer::{Buffer, Mode, SetMode}; use config::Config; use error::Error; -use keymap::PrefixNode; +use keymap::{PrefixNode, KeySeq, Key}; use term::{Clear, Color, Term}; pub mod buffer; @@ -29,7 +29,7 @@ pub struct State { command: String, message: Option, status: Option, - key: String, + key_seq: KeySeq, top_mode: TopMode, config: Config, running: bool, @@ -59,7 +59,7 @@ impl State { message: None, status: None, command: String::new(), - key: String::new(), + key_seq: KeySeq::empty(), running: true, buffer, term, @@ -157,7 +157,7 @@ impl State { self.term .set_cursor_position(self.buffer.height(), self.buffer.width() - 10)?; self.term.set_foreground(Color::White)?; - write!(self.term, "{}", self.key).map_err(Error::TerminalFmtError)?; + write!(self.term, "{}", self.key_seq).map_err(Error::TerminalFmtError)?; self.term.reset_style()?; @@ -213,38 +213,37 @@ impl State { command::execute(self, cmd) } - fn handle_command_key(&mut self, key: char) -> Result<(), Error> { + fn handle_command_key(&mut self, key: Key) -> Result<(), Error> { match key { - '\n' | '\x0D' => { + Key::Char('\n') | Key::Char('\x0D') => { self.top_mode = TopMode::Normal; self.handle_command()?; } - '\x7F' => { + Key::Char('\x7F') => { if self.command.is_empty() { self.top_mode = TopMode::Normal; } else { self.command.pop(); } } - '\x1B' => { + Key::Escape => { self.top_mode = TopMode::Normal; } - c if c.is_ascii_graphic() => self.command.push(c), - ' ' => self.command.push(' '), + Key::Char(c) if c.is_ascii_graphic() || c == ' ' => self.command.push(c), _ => (), } Ok(()) } - fn handle_mode_key(&mut self, mode: Mode, key: char) -> Result<(), Error> { + fn handle_mode_key(&mut self, mode: Mode, key: Key) -> Result<(), Error> { let buffer = &mut self.buffer; - self.key.push(key); + self.key_seq.push(key); - match self.config.key(mode, &self.key) { + match self.config.key_seq(mode, &self.key_seq) { Some(PrefixNode::Leaf(actions)) => { - self.key.clear(); + self.key_seq.clear(); for &action in actions { command::perform(buffer, &self.config, action)?; @@ -252,7 +251,7 @@ impl State { } Some(PrefixNode::Prefix(_)) => {} None => { - self.key.clear(); + self.key_seq.clear(); } } @@ -263,15 +262,15 @@ impl State { Ok(()) } - fn handle_normal_key(&mut self, key: char) -> Result<(), Error> { + fn handle_normal_key(&mut self, key: Key) -> Result<(), Error> { match key { - '\x1B' => { - self.key.clear(); + Key::Escape => { + self.key_seq.clear(); self.buffer.set_mode(&self.config, SetMode::Normal); Ok(()) } - ':' => { - self.key.clear(); + Key::Char(':') => { + self.key_seq.clear(); self.command.clear(); self.status = None; self.top_mode = TopMode::Command; @@ -281,13 +280,13 @@ impl State { } } - fn handle_insert_key(&mut self, key: char) -> Result<(), Error> { + fn handle_insert_key(&mut self, key: Key) -> Result<(), Error> { match key { - '\x1B' => { + Key::Escape => { self.buffer.set_mode(&self.config, SetMode::Normal); Ok(()) } - key if !key.is_ascii() || key == ' ' || key == '\t' || key.is_ascii_graphic() => { + Key::Char(key) if !key.is_ascii() || key == ' ' || key == '\t' || key.is_ascii_graphic() => { self.buffer.insert(&self.config, key); Ok(()) } @@ -312,7 +311,7 @@ impl State { if self.message.is_some() { self.message = None; - if key != ':' { + if key != Key::Char(':') { return Ok(()); } } diff --git a/red/src/term/input.rs b/red/src/term/input.rs index 720f3de1..96a24995 100644 --- a/red/src/term/input.rs +++ b/red/src/term/input.rs @@ -1,9 +1,10 @@ -use std::io::{Read, Stdin}; +use std::{io::{Read, Stdin}, future::{Future, self}}; use crate::error::InputError; pub trait ReadChar { fn read_char(&mut self) -> Result; + async fn read_byte_delay(&mut self); } impl ReadChar for Stdin { @@ -23,6 +24,10 @@ impl ReadChar for Stdin { let s = core::str::from_utf8(&buf[..len + 1]).map_err(InputError::DecodeError)?; Ok(s.chars().next().unwrap()) } + + async fn read_byte_delay(&mut self) { + todo!(); + } } const fn utf8_len_prefix(l: u8) -> Option { diff --git a/red/src/term/mod.rs b/red/src/term/mod.rs index 300b97b1..b08ac1c1 100644 --- a/red/src/term/mod.rs +++ b/red/src/term/mod.rs @@ -1,6 +1,6 @@ use std::{io::{Stdout, Write, Stdin, stdin, stdout, self}, fmt}; -use crate::{error::Error, term::input::ReadChar}; +use crate::{error::Error, term::input::ReadChar, keymap::Key}; use self::sys::RawMode; @@ -161,8 +161,14 @@ impl Term { }.map_err(Error::TerminalError) } - pub fn read_key(&mut self) -> Result { - self.stdin.read_char().map_err(Error::InputError) + pub fn read_key(&mut self) -> Result { + let ch = self.stdin.read_char().map_err(Error::InputError)?; + + if ch == '\x1B' { + return Ok(Key::Escape); + } + + Ok(Key::Char(ch)) } pub fn flush(&mut self) -> Result<(), Error> { diff --git a/sysutils/Cargo.toml b/sysutils/Cargo.toml index a4b24584..0566c4ca 100644 --- a/sysutils/Cargo.toml +++ b/sysutils/Cargo.toml @@ -9,7 +9,6 @@ edition = "2021" clap = { version = "4.3.19", features = ["std", "derive"], default-features = false } # TODO own impl humansize = { version = "2.1.3", features = ["impl_style"] } -yggdrasil-rt = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-rt.git" } [lib] path = "src/lib.rs" diff --git a/sysutils/src/colors.rs b/sysutils/src/colors.rs index 954a5560..01398936 100644 --- a/sysutils/src/colors.rs +++ b/sysutils/src/colors.rs @@ -1,11 +1,12 @@ fn main() { - for bg in 40..=49 { - if bg == 48 { continue; } - for fg in 30..=39 { - if fg == 48 { continue; } - print!("\x1B[{}m\x1B[{}m@\x1B[0m", bg, fg); - } - println!(); - } + loop {} + // for bg in 40..=49 { + // if bg == 48 { continue; } + // for fg in 30..=39 { + // if fg == 48 { continue; } + // print!("\x1B[{}m\x1B[{}m@\x1B[0m", bg, fg); + // } + // println!(); + // } } diff --git a/sysutils/src/lib.rs b/sysutils/src/lib.rs index c7585dbc..28ffdaf8 100644 --- a/sysutils/src/lib.rs +++ b/sysutils/src/lib.rs @@ -1,4 +1,50 @@ -use std::{io::{self, Read}, fs::File}; +use std::{ + fs::File, + io::{self, Read}, +}; + +#[cfg(unix)] +pub mod unix { + use std::fmt; + + #[derive(Clone, Copy, PartialEq, Eq, Debug)] + pub struct FileMode(u32); + + impl From for FileMode { + fn from(value: u32) -> Self { + Self(value) + } + } + + impl fmt::Display for FileMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + macro_rules! print_bit { + ($res:expr, $val:expr, $self:expr, $bit:expr) => { + if $self.0 & $bit == $bit { + $res = $val; + } + }; + } + + let mut buf = ['-'; 9]; + + print_bit!(buf[0], 'r', self, 0o400); + print_bit!(buf[1], 'w', self, 0o200); + print_bit!(buf[2], 'x', self, 0o100); + print_bit!(buf[3], 'r', self, 0o040); + print_bit!(buf[4], 'w', self, 0o020); + print_bit!(buf[5], 'x', self, 0o010); + print_bit!(buf[6], 'r', self, 0o004); + print_bit!(buf[7], 'w', self, 0o002); + print_bit!(buf[8], 'x', self, 0o001); + + for ch in buf.iter() { + fmt::Display::fmt(ch, f)?; + } + Ok(()) + } + } +} // TODO replace this pub trait ToExitCode { @@ -9,14 +55,14 @@ impl ToExitCode for io::Result { fn to_exit_code(&self) -> i32 { match self { Ok(_) => 0, - _ => 1 + _ => 1, } } } pub enum Input { Stdin(io::Stdin), - File(io::BufReader) + File(io::BufReader), } impl Input { @@ -47,7 +93,7 @@ impl Read for Input { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self { Self::Stdin(value) => value.read(buf), - Self::File(value) => value.read(buf) + Self::File(value) => value.read(buf), } } } diff --git a/sysutils/src/login.rs b/sysutils/src/login.rs index 600e0ecb..ee78d0da 100644 --- a/sysutils/src/login.rs +++ b/sysutils/src/login.rs @@ -2,18 +2,15 @@ use std::{ env, - io::{stdin, stdout, BufRead, Write}, + io::{self, stdin, stdout, BufRead, Write}, os::{ fd::AsRawFd, - yggdrasil::signal::{set_signal_handler, Signal, SignalHandler}, + yggdrasil::{ + io::{start_terminal_session, DeviceRequest, FdDeviceRequest}, + signal::{set_signal_handler, Signal, SignalHandler}, + }, }, - process::{ExitCode, Command}, -}; - -use yggdrasil_rt::{ - debug_trace, - io::{DeviceRequest, FileMode, OpenOptions, RawFd}, - sys, + process::{self, Command, ExitCode}, }; fn handler(_signal: Signal) {} @@ -22,18 +19,18 @@ fn login_readline( reader: &mut R, buf: &mut String, _secret: bool, -) -> Result { +) -> Result { reader.read_line(buf) } -fn login_as(username: &str, _password: &str) -> Result<(), std::io::Error> { +fn login_as(username: &str, _password: &str) -> Result<(), io::Error> { let mut shell = Command::new("/bin/sh").arg("-l").spawn()?; println!("Hello {:?}", username); shell.wait()?; Ok(()) } -fn login_attempt(erase: bool) -> Result<(), std::io::Error> { +fn login_attempt(erase: bool) -> Result<(), io::Error> { let mut stdin = stdin().lock(); let mut stdout = stdout(); @@ -53,20 +50,6 @@ fn login_attempt(erase: bool) -> Result<(), std::io::Error> { login_as(username.trim(), "") } -fn setup_session(terminal: &str) -> Result<(), yggdrasil_rt::Error> { - // This will close the file descriptors associated with the old terminal - unsafe { sys::start_session()? }; - - unsafe { - // File descriptors 0, 1, 2 are now free, need to reopen them with a new terminal - sys::open(None, terminal, OpenOptions::READ, FileMode::empty())?; - sys::open(None, terminal, OpenOptions::WRITE, FileMode::empty())?; - sys::open(None, terminal, OpenOptions::WRITE, FileMode::empty())?; - } - - Ok(()) -} - fn main() -> ExitCode { let args: Vec<_> = env::args().skip(1).collect(); if args.len() != 1 { @@ -76,21 +59,22 @@ fn main() -> ExitCode { let terminal = args[0].as_str(); // TODO check that `terminal` is a terminal - debug_trace!("Starting a session at {}", terminal); - if let Err(err) = setup_session(terminal) { - debug_trace!("Failed: {:?}", err); - eprintln!("Could not setup session at {}: {:?}", terminal, err); + if let Err(err) = unsafe { start_terminal_session(terminal) } { + debug_trace!("Error: {:?}", err); + eprintln!("Could not setup a session at {}: {:?}", terminal, err); return ExitCode::FAILURE; } let mut attempt_number = 0; loop { debug_trace!("Login attempt {}", attempt_number); + // "Attach" the terminal unsafe { - let mut req = DeviceRequest::SetTerminalGroup(sys::get_pid()); - sys::device_request(RawFd::STDIN, &mut req).unwrap(); + stdin() + .device_request(&mut DeviceRequest::SetTerminalGroup(process::id())) + .expect("Could not attach the terminal"); } if let Err(err) = login_attempt(attempt_number % 3 == 0) { diff --git a/sysutils/src/ls.rs b/sysutils/src/ls.rs index 46119d70..ff827022 100644 --- a/sysutils/src/ls.rs +++ b/sysutils/src/ls.rs @@ -1,14 +1,20 @@ +#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os))] + use std::{ fmt, - fs::{read_dir, FileType}, + fs::{read_dir, FileType, Metadata}, io, mem::MaybeUninit, path::Path, }; +#[cfg(target_os = "yggdrasil")] +use std::os::yggdrasil::fs::MetadataExt; +#[cfg(unix)] +use std::os::unix::fs::MetadataExt; + use clap::Parser; use humansize::{FormatSize, BINARY}; -use yggdrasil_rt::io::FileAttr; #[derive(Parser)] pub struct Args { @@ -74,7 +80,7 @@ impl fmt::Display for DisplaySizeWith<'_, T> { struct Entry { name: String, ty: Option, - attrs: Option, + attrs: Option, } impl DisplayBit for Option { @@ -93,13 +99,29 @@ impl DisplayBit for Option { } } -impl DisplayBit for Option { +#[cfg(target_os = "yggdrasil")] +impl DisplayBit for Option { fn display_bit(&self, opts: &Args, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Some(attrs) = self else { return write!(f, "--------- {:<8}", "???"); }; - write!(f, "{} {:>8}", attrs.mode, attrs.size.display_size_with(opts)) + let mode = attrs.mode_ext(); + write!(f, "{} {:>8}", mode, attrs.len().display_size_with(opts)) + } +} + +#[cfg(unix)] +impl DisplayBit for Option { + fn display_bit(&self, opts: &Args, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use sysutils::unix::FileMode; + + let Some(attrs) = self else { + return write!(f, "--------- {:<8}", "???"); + }; + + let mode = FileMode::from(attrs.mode()); + write!(f, "{} {:>8}", mode, attrs.len().display_size_with(opts)) } } @@ -119,15 +141,6 @@ impl DisplayBit for Entry { } } -fn fetch_entry>(path: P) -> Option { - let mut attrs = MaybeUninit::uninit(); - let attrs = unsafe { - yggdrasil_rt::sys::get_metadata(None, path.as_ref().to_str()?, &mut attrs, false).ok()?; - attrs.assume_init() - }; - Some(attrs) -} - impl Entry { fn invalid() -> Self { Self { @@ -148,7 +161,7 @@ fn list_directory(path: &Path) -> io::Result> { let os_filename = entry.file_name(); let ty = entry.file_type().ok(); - let attrs = fetch_entry(entry.path()); + let attrs = entry.path().metadata().ok(); entries.push(Entry { name: os_filename.to_string_lossy().to_string(), diff --git a/sysutils/src/mount.rs b/sysutils/src/mount.rs index aab80c30..e5312a5d 100644 --- a/sysutils/src/mount.rs +++ b/sysutils/src/mount.rs @@ -1,7 +1,7 @@ -use std::process::ExitCode; +#![feature(rustc_private, yggdrasil_os)] +use std::{process::ExitCode, os::yggdrasil::io::{MountOptions, mount_raw}}; use clap::Parser; -use yggdrasil_rt::{io::MountOptions, sys::mount}; #[derive(Parser, Debug)] struct Args { @@ -14,19 +14,23 @@ struct Args { fn main() -> ExitCode { let args = Args::parse(); - let source = if args.target.is_some() { Some(args.source.as_str()) } else { None }; + let source = if args.target.is_some() { + Some(args.source.as_str()) + } else { + None + }; let target = args.target.as_deref().unwrap_or(args.source.as_str()); let filesystem = args.ty.as_deref(); - // Permissions are not yet implemented, lol - let result = unsafe { - let options = MountOptions { - source, - filesystem, - target - }; + // Permissions are not yet implemented, lol + let result = unsafe { + let options = MountOptions { + source, + filesystem, + target, + }; - mount(&options) + mount_raw(&options) }; match result {