some type of intermediate
This commit is contained in:
parent
803230738e
commit
b8cb2d07e4
5 changed files with 558 additions and 23 deletions
79
Cargo.lock
generated
79
Cargo.lock
generated
|
@ -388,6 +388,12 @@ dependencies = [
|
|||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
|
@ -1107,6 +1113,15 @@ dependencies = [
|
|||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
|
@ -1138,6 +1153,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
|
@ -1599,6 +1624,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
@ -1924,7 +1958,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
|||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core 0.9.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1941,6 +1985,19 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.13",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
|
@ -2236,8 +2293,10 @@ name = "rust_term"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bpaf",
|
||||
"heapless",
|
||||
"iced",
|
||||
"nix",
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2508,6 +2567,12 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -2873,7 +2938,7 @@ checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
|
|||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
"parking_lot",
|
||||
"parking_lot 0.11.2",
|
||||
"pin-utils",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
|
@ -3021,7 +3086,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"log",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.4",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"smallvec",
|
||||
|
@ -3049,7 +3114,7 @@ dependencies = [
|
|||
"log",
|
||||
"naga",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.4",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"rustc-hash 1.1.0",
|
||||
|
@ -3091,7 +3156,7 @@ dependencies = [
|
|||
"ndk-sys 0.5.0+25.2.9519653",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.4",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
|
@ -3602,9 +3667,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
|||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.26"
|
||||
version = "0.8.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
|
||||
checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7"
|
||||
|
||||
[[package]]
|
||||
name = "yazi"
|
||||
|
|
|
@ -7,6 +7,8 @@ edition = "2024"
|
|||
nix = { version = "0.30.1", features = ["term", "process", "fs"], default-features = false }
|
||||
iced = { version = "0.13.1", features = ["advanced", "smol", "wgpu"], default-features = false }
|
||||
bpaf = { version = "0.9.20", features = ["derive"], default-features = false }
|
||||
heapless = "0.8.0"
|
||||
nom = "8.0.0"
|
||||
|
||||
[lints.clippy]
|
||||
cargo = "deny"
|
||||
|
|
230
src/enums.rs
Normal file
230
src/enums.rs
Normal file
|
@ -0,0 +1,230 @@
|
|||
//! docs are more or less from [this document](https://real-world-systems.com/docs/ANSIcode.html)
|
||||
//! this source file `enums.rs` is licensed under the Mozilla Public License 2.0 (MPL2.0)
|
||||
//! as parts of it are from [this](https://gitlab.com/davidbittner/ansi-parser) excellent crate
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::parsers::parse_escape;
|
||||
use heapless::Vec;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Token<'a> {
|
||||
Text(&'a str),
|
||||
C0(C0),
|
||||
EscapeSequence(EscapeSequence),
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for Token<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Token::*;
|
||||
match self {
|
||||
Text(txt) => write!(f, "{}", txt),
|
||||
C0(c0) => write!(f, "{:?}", c0),
|
||||
EscapeSequence(escape_sequence) => write!(f, "{:?}", escape_sequence),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum C0 {
|
||||
NUL,
|
||||
SOH,
|
||||
STX,
|
||||
ETX,
|
||||
EOT,
|
||||
ENQ,
|
||||
ACK,
|
||||
BEL,
|
||||
BS,
|
||||
HT,
|
||||
LF,
|
||||
VT,
|
||||
FF,
|
||||
CR,
|
||||
SO,
|
||||
SI,
|
||||
DLE,
|
||||
DC1,
|
||||
DC2,
|
||||
DC3,
|
||||
DC4,
|
||||
NAK,
|
||||
SYN,
|
||||
ETB,
|
||||
CAN,
|
||||
EM,
|
||||
SUB,
|
||||
ESC,
|
||||
FS,
|
||||
GS,
|
||||
RS,
|
||||
US,
|
||||
SP,
|
||||
DEL,
|
||||
}
|
||||
|
||||
// TODO figure out defaults
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum EscapeSequence {
|
||||
ICH(u32), // [#@ def 1 Insert CHaracter
|
||||
CUU(u32), // [#A def 1 CUrsor Up
|
||||
CUD(u32), // [#B def 1 CUrsor Down
|
||||
CUF(u32), // [#C def 1 CUrsor Forward
|
||||
CUB(u32), // [#D def 1 CUrsor Backward
|
||||
CNL(u32), // [#E def 1 Cursor to Next Line
|
||||
CPL(u32), // [#F def 1 Cursor to Previous Line
|
||||
CHA(u32), // [#G def 1 Cursor Horizontal position Absolute
|
||||
CUP(u32, u32), // [#;#H def 1;1 CUrsor Position
|
||||
CHT(u32), // [#I def 1 Cursor Horizontal Tabulation
|
||||
ED(u32), // [#J def 0 Erase in Display
|
||||
EL(u32), // [#K def 0 Erase in Line
|
||||
IL(u32), // [#L def 0 Insert Line, current line moves down
|
||||
DL(u32), // [#M def 0 Delete Line, lines below current move up
|
||||
EF(u32), // [#N def 0 Erase in Field
|
||||
EA(u32), // [#O def 0 Erase in qualified Area
|
||||
DCH(u32), // [#P def 1 Delete CHaracter
|
||||
SEM(u32), // [#Q def 0 Set Editing extent Mode
|
||||
CPR, // [R Cursor Position Report
|
||||
SU(u32), // [#S def 1 Scroll Up
|
||||
SD(u32), // [#T def 1 Scroll Down
|
||||
NP(u32), // [#U def 1 Next Page
|
||||
PP(u32), // [#V def 1 Previous Page
|
||||
CTC(u32), // [#W def 0 Cursor Tabulation Control
|
||||
ECH(u32), // [#X def 1 Erase CHaracter
|
||||
CVT(u32), // [#Y def 1 Cursor Vertical Tab
|
||||
CBT(u32), // [#Z def 1 Cursor Back Tab
|
||||
HPA(u32), // [#` def 0 Horizontal Position Absolute
|
||||
HPR(u32), // [#a def 0 Horizontal Position Relative
|
||||
REP(u32), // [#b def 1 REPeat previous displayable character
|
||||
DA, // [c Device Attributes
|
||||
VPA(u32), // [#d def 0 Vertical Position Absolute
|
||||
VPR(u32), // [#e def 0 Vertical Position Relative
|
||||
HVP(u32, u32), // [#;#f def 0;0 Horizontal and Vertical Position
|
||||
TBC(u32), // [#g def 0 TaBulation Clear
|
||||
SM(u32), // [#h def 0 Set Mode
|
||||
MC(u32), // [#i def 0 Media Copy
|
||||
PageFormatSelect(u32), // [#j def 0
|
||||
RM, // [l Reset Mode
|
||||
SGR(Vec<u8, 5>), // [#;#;#;#;#l def 0 Set Graphics Rendition
|
||||
DSR(u32), // [#n def 0 Device Status Report
|
||||
DAQ(u32), // [#o def 0 Define Area Qualification starting at current position
|
||||
DECLL, // [q UNIMPLEMENTED many params
|
||||
DECSTBM(u32, u32), // [#;#r def 1;1 top and bottom margins
|
||||
DECSTRM(u32, u32), // [#;#s def 1;1 left and right margins
|
||||
DECSLPP(u32), // [#t def 66 physical lines per page
|
||||
DECSHTS, // [u UNIMPLEMENTED many params
|
||||
DECSVTS, // [v UNIMPLEMENTED many params
|
||||
DECSHORP(u32), // [#w def 0 set horizontal pitch on LAxxx printers
|
||||
DECREQTPARM, // [x UNIMPLEMENTED many params
|
||||
DECTST(u32, u32), // [#;#y def 2;1 invoke confidence test
|
||||
DECVERP(u32), // [#z def 0 set vertical -pitch on LA100
|
||||
DECTTC(u32), // [#| def 0 transmit termination character
|
||||
DECPRO, // [} UNIMPLEMENTED many params
|
||||
DECKEYS(u32), // [#~ def 0 sent by special function keys
|
||||
DELETE, // [DELETE always ignored
|
||||
SL(u32), // [# @ def 1 Scroll Left
|
||||
SR(u32), // [# A def 1 Scroll Right
|
||||
GSM(u32, u32), // [#;# B def 100;100 Graphic Size Modification
|
||||
GSS(u32), // [# C def 720 Graphic Size Selection
|
||||
FNT(u32, u32), // [#;# D def 0;1 FoNT selection
|
||||
TSS(u32), // [# E def 720 Thin Space Specification
|
||||
JFY(u32), // [# F def 0 JustiFY
|
||||
SPI(u32, u32), // [#;# G def 720;720 SPacing Increment
|
||||
QUAD(u32), // [# H def 0 do QUADding on current line of text
|
||||
}
|
||||
|
||||
pub trait AnsiParser {
|
||||
fn ansi_parse(&self) -> AnsiParseIterator<'_>;
|
||||
}
|
||||
|
||||
impl AnsiParser for str {
|
||||
fn ansi_parse(&self) -> AnsiParseIterator<'_> {
|
||||
AnsiParseIterator { dat: &self }
|
||||
}
|
||||
}
|
||||
|
||||
impl AnsiParser for String {
|
||||
fn ansi_parse(&self) -> AnsiParseIterator<'_> {
|
||||
AnsiParseIterator { dat: self }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AnsiParseIterator<'a> {
|
||||
dat: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AnsiParseIterator<'a> {
|
||||
type Item = Token<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.dat.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (head, tail) = head(self.dat);
|
||||
let dat = self.dat;
|
||||
self.dat = tail;
|
||||
|
||||
// bound checked
|
||||
use C0::*;
|
||||
Some(match head {
|
||||
"\u{00}" => Token::C0(NUL),
|
||||
"\u{01}" => Token::C0(SOH),
|
||||
"\u{02}" => Token::C0(STX),
|
||||
"\u{03}" => Token::C0(ETX),
|
||||
"\u{04}" => Token::C0(EOT),
|
||||
"\u{05}" => Token::C0(ENQ),
|
||||
"\u{06}" => Token::C0(ACK),
|
||||
"\u{07}" => Token::C0(BEL),
|
||||
"\u{08}" => Token::C0(BS),
|
||||
"\u{09}" => Token::C0(HT),
|
||||
"\u{0a}" => Token::C0(LF),
|
||||
"\u{0b}" => Token::C0(VT),
|
||||
"\u{0c}" => Token::C0(FF),
|
||||
"\u{0d}" => Token::C0(CR),
|
||||
"\u{0e}" => Token::C0(SO),
|
||||
"\u{0f}" => Token::C0(SI),
|
||||
"\u{10}" => Token::C0(DLE),
|
||||
"\u{11}" => Token::C0(DC1),
|
||||
"\u{12}" => Token::C0(DC2),
|
||||
"\u{13}" => Token::C0(DC3),
|
||||
"\u{14}" => Token::C0(DC4),
|
||||
"\u{15}" => Token::C0(NAK),
|
||||
"\u{16}" => Token::C0(SYN),
|
||||
"\u{17}" => Token::C0(ETB),
|
||||
"\u{18}" => Token::C0(CAN),
|
||||
"\u{19}" => Token::C0(EM),
|
||||
"\u{1a}" => Token::C0(SUB),
|
||||
"\u{1b}" => {
|
||||
if let Ok(ret) = parse_escape(dat) {
|
||||
println!("^[ successfully parsed");
|
||||
self.dat = ret.0.clone();
|
||||
Token::EscapeSequence(ret.1)
|
||||
} else {
|
||||
println!("^[ unimplemented");
|
||||
Token::C0(ESC)
|
||||
}
|
||||
}
|
||||
"\u{1c}" => Token::C0(FS),
|
||||
"\u{1d}" => Token::C0(GS),
|
||||
"\u{1e}" => Token::C0(RS),
|
||||
"\u{1f}" => Token::C0(US),
|
||||
"\u{20}" => Token::C0(SP),
|
||||
"\u{7F}" => Token::C0(DEL),
|
||||
txt => Token::Text(txt),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn head(string: &str) -> (&str, &str) {
|
||||
for i in 1..5 {
|
||||
let r = string.get(0..i);
|
||||
match r {
|
||||
Some(val) => return (val, &string[i..]),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
panic!();
|
||||
}
|
103
src/lib.rs
103
src/lib.rs
|
@ -16,6 +16,9 @@
|
|||
reason = ""
|
||||
)]
|
||||
|
||||
use crate::enums::*;
|
||||
use crate::parsers::*;
|
||||
|
||||
use bpaf::Bpaf;
|
||||
|
||||
use iced::widget::{column, rich_text, row, scrollable, span, text};
|
||||
|
@ -32,9 +35,18 @@ use std::os::unix::io::{AsFd as _, OwnedFd};
|
|||
use std::process::Command;
|
||||
use std::{error, fmt, thread, time as core_time};
|
||||
|
||||
pub mod enums;
|
||||
pub mod parsers;
|
||||
|
||||
/// whether to enable verbose logging; see `Flags::verbose`
|
||||
static mut VERBOSE: bool = false;
|
||||
|
||||
/// whether to enable debug logging; see `Flags::debug`
|
||||
static mut DEBUG: bool = false;
|
||||
|
||||
/// whether to enable vomit logging; see `Flags::vomit`
|
||||
static mut VOMIT: bool = false;
|
||||
|
||||
/// shell path; see `Flags::shell`
|
||||
static mut SHELL: Option<String> = None;
|
||||
|
||||
|
@ -106,13 +118,25 @@ pub struct Flags {
|
|||
#[bpaf(short('S'), long)]
|
||||
shell: Option<String>,
|
||||
|
||||
/// whether to debug log
|
||||
/// no logging, NOOP; log level 0
|
||||
#[bpaf(short, long)]
|
||||
quiet: bool,
|
||||
|
||||
/// whether to error log; log level 1
|
||||
#[bpaf(short('v'), long)]
|
||||
verbose: bool,
|
||||
|
||||
/// whether to display version: TODO
|
||||
/// whether to debug log; log level 2
|
||||
#[bpaf(long)]
|
||||
debug: bool,
|
||||
|
||||
/// whether to vomit log; log level 3
|
||||
#[bpaf(long)]
|
||||
vomit: bool,
|
||||
|
||||
/// whether to display version, NOOP; TODO
|
||||
#[expect(dead_code, reason = "TODO")]
|
||||
#[bpaf(short, long)]
|
||||
#[bpaf(short('V'), long)]
|
||||
version: bool,
|
||||
}
|
||||
|
||||
|
@ -126,7 +150,7 @@ pub struct Flags {
|
|||
/// .subscription(Model::subscription)
|
||||
/// .run()
|
||||
/// ```
|
||||
pub struct Model {
|
||||
pub struct Model<'a> {
|
||||
/// location of cursor in user input line
|
||||
cursor_index: usize,
|
||||
/// fd of pty
|
||||
|
@ -139,9 +163,12 @@ pub struct Model {
|
|||
screen_buffer_index: usize,
|
||||
/// path to shell
|
||||
shell: String,
|
||||
|
||||
screen: Vec<&'a str>,
|
||||
cursor: (usize, usize),
|
||||
}
|
||||
|
||||
impl Model {
|
||||
impl Model<'_> {
|
||||
/// applies needed side effects when taking an input char
|
||||
#[expect(
|
||||
clippy::arithmetic_side_effects,
|
||||
|
@ -238,7 +265,7 @@ impl Model {
|
|||
print_err(&error);
|
||||
}
|
||||
}
|
||||
Err(error) => print_err(&error),
|
||||
Err(error) => print_vomit(&error.to_string()),
|
||||
}
|
||||
return iced::Task::none();
|
||||
}
|
||||
|
@ -252,15 +279,21 @@ impl Model {
|
|||
reason = "all is bound checked"
|
||||
)]
|
||||
fn update_screen_buffer(&mut self, vec: &[u8]) -> Result<(), Error> {
|
||||
let offset = self.screen_buffer_index;
|
||||
for (i, chr) in vec.iter().enumerate() {
|
||||
let index = i + offset;
|
||||
if index < self.screen_buffer.len() {
|
||||
self.screen_buffer[index] = *chr;
|
||||
} else {
|
||||
return Err(Error::IndexOutOfBounds);
|
||||
for chr in String::from_utf8_lossy(vec).ansi_parse() {
|
||||
match chr {
|
||||
Token::Text(txt) => {
|
||||
print_debug(&(String::from("[CHR]") + txt));
|
||||
if self.screen_buffer_index < self.screen_buffer.len() {
|
||||
self.screen_buffer[self.screen_buffer_index] =
|
||||
*txt.as_bytes().get(0).unwrap_or(&b'_');
|
||||
self.screen_buffer_index += 1;
|
||||
}
|
||||
}
|
||||
Token::C0(c0) => print_debug(&(String::from("[C0]") + &format!("{:?}", c0))),
|
||||
Token::EscapeSequence(seq) => {
|
||||
print_debug(&(String::from("[SEQ]") + &format!("{:?}", seq)))
|
||||
}
|
||||
}
|
||||
self.screen_buffer_index += 1;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -324,7 +357,7 @@ impl Model {
|
|||
}
|
||||
}
|
||||
|
||||
impl Default for Model {
|
||||
impl Default for Model<'_> {
|
||||
#[inline]
|
||||
#[expect(clippy::undocumented_unsafe_blocks, reason = "clippy be trippin")]
|
||||
fn default() -> Self {
|
||||
|
@ -339,6 +372,8 @@ impl Default for Model {
|
|||
|| return String::from("/home/mtgmonkey/.nix-profile/bin/dash"),
|
||||
|shell| return shell,
|
||||
),
|
||||
screen: vec![],
|
||||
cursor: (1, 1),
|
||||
};
|
||||
me.fd = spawn_pty_with_shell(&me.shell).ok();
|
||||
let mut nored = true;
|
||||
|
@ -361,9 +396,15 @@ impl Default for Model {
|
|||
#[inline]
|
||||
#[expect(clippy::undocumented_unsafe_blocks, reason = "clippy be trippin")]
|
||||
pub unsafe fn init(flags: Flags) {
|
||||
unsafe {
|
||||
DEBUG = flags.debug;
|
||||
}
|
||||
unsafe {
|
||||
VERBOSE = flags.verbose;
|
||||
}
|
||||
unsafe {
|
||||
VOMIT = flags.vomit;
|
||||
}
|
||||
unsafe {
|
||||
SHELL = flags.shell;
|
||||
}
|
||||
|
@ -448,8 +489,38 @@ fn set_nonblock(fd: &OwnedFd) -> Result<(), Error> {
|
|||
clippy be buggin"
|
||||
)]
|
||||
fn print_err(error: &Error) {
|
||||
/// SAFETY the only time VERBOSE is written to should be `init()`
|
||||
/// SAFETY the only time `VERBOSE` is written to should be `init()`
|
||||
if unsafe { VERBOSE } {
|
||||
println!("[ERROR] {error}");
|
||||
}
|
||||
}
|
||||
|
||||
/// if `VOMIT` is `true`, logs vomit
|
||||
#[inline]
|
||||
#[expect(
|
||||
clippy::print_stdout,
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
reason = "toggleable with VERBOSE option\n
|
||||
clippy be buggin"
|
||||
)]
|
||||
fn print_vomit(vomit: &str) {
|
||||
/// SAFETY the only time `VOMIT` is written to should be `init()`
|
||||
if unsafe { VOMIT } {
|
||||
println!("[VOMIT] {:?}", vomit);
|
||||
}
|
||||
}
|
||||
|
||||
/// if `DEBUG` is `true`, logs errors
|
||||
#[inline]
|
||||
#[expect(
|
||||
clippy::print_stdout,
|
||||
clippy::undocumented_unsafe_blocks,
|
||||
reason = "toggleable with VERBOSE option\n
|
||||
clippy be buggin"
|
||||
)]
|
||||
fn print_debug(debug: &str) {
|
||||
/// SAFETY the only time `DEBUG` is written to should be `init()`
|
||||
if unsafe { DEBUG } {
|
||||
println!("[DEBUG] {:?}", debug);
|
||||
}
|
||||
}
|
||||
|
|
167
src/parsers.rs
Normal file
167
src/parsers.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
//! docs are more or less from [this document](https://real-world-systems.com/docs/ANSIcode.html)
|
||||
//! this source file `parsers.rs` is licensed under the Mozilla Public License 2.0 (MPL2.0)
|
||||
//! as parts of it are from [this](https://gitlab.com/davidbittner/ansi-parser) excellent crate
|
||||
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::character::complete::{digit0, digit1};
|
||||
use nom::combinator::{map, map_res, opt, value};
|
||||
use nom::sequence::{delimited, preceded};
|
||||
use nom::{IResult, Parser};
|
||||
|
||||
use crate::enums::{C0, EscapeSequence};
|
||||
|
||||
macro_rules! tag_parser {
|
||||
($sig:ident, $tag:expr, $ret:expr) => {
|
||||
fn $sig(input: &str) -> IResult<&str, EscapeSequence> {
|
||||
value($ret, tag($tag)).parse(input)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! one_ctlseq {
|
||||
($sig:ident, $tag:expr, $def:expr, $ret:expr) => {
|
||||
fn $sig(input: &str) -> IResult<&str, EscapeSequence> {
|
||||
map(
|
||||
delimited(tag("["), |a| parse_maybe_int(a, $def), tag($tag)),
|
||||
|am| $ret(am),
|
||||
)
|
||||
.parse(input)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! two_ctlseq {
|
||||
($sig:ident, $tag:expr, $def0:expr, $def1:expr, $ret:expr) => {
|
||||
fn $sig(input: &str) -> IResult<&str, EscapeSequence> {
|
||||
map(
|
||||
(
|
||||
tag("["),
|
||||
|a| parse_maybe_int(a, $def0),
|
||||
opt(tag(";")),
|
||||
|b| parse_maybe_int(b, $def1),
|
||||
tag($tag),
|
||||
),
|
||||
|(_, a, _, b, _)| $ret(a, b),
|
||||
)
|
||||
.parse(input)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn parse_u32(input: &str) -> IResult<&str, u32> {
|
||||
map_res(digit1, |s: &str| s.parse::<u32>()).parse(input)
|
||||
}
|
||||
|
||||
fn parse_maybe_int(input: &str, default: u32) -> IResult<&str, u32> {
|
||||
map(digit0, |s: &str| s.parse::<u32>().unwrap_or(default)).parse(input)
|
||||
}
|
||||
|
||||
fn combined(input: &str) -> IResult<&str, EscapeSequence> {
|
||||
alt((
|
||||
alt((
|
||||
ICH, CUU, CUD, CUF, CUB, CNL, CPL, CHA, CUP, CHT, ED, EL, IL, DL, EF, EA, DCH, SEM,
|
||||
CPR, SU, SD,
|
||||
)),
|
||||
alt((
|
||||
NP,
|
||||
PP,
|
||||
CTC,
|
||||
ECH,
|
||||
CVT,
|
||||
CBT,
|
||||
HPA,
|
||||
HPR,
|
||||
REP,
|
||||
DA,
|
||||
VPA,
|
||||
VPR,
|
||||
HVP,
|
||||
TBC,
|
||||
SM,
|
||||
MC,
|
||||
PageFormatSelect,
|
||||
RM,
|
||||
/*SGR,*/ DSR,
|
||||
DAQ,
|
||||
)),
|
||||
alt((
|
||||
DECLL, DECSTBM, DECSTRM, DECSLPP, /*DECSHTS,*/ /*DECSVTS,*/ DECSHORP,
|
||||
/*DECREQTPARM,*/ DECTST, DECVERP, DECTTC, /*DECPRO,*/ DECKEYS,
|
||||
/*DELETE,*/ SL, SR, GSM, GSS, FNT, TSS, JFY,
|
||||
)),
|
||||
SPI,
|
||||
QUAD,
|
||||
))
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
pub fn parse_escape(input: &str) -> IResult<&str, EscapeSequence> {
|
||||
preceded(tag("\u{1b}"), combined).parse(input)
|
||||
}
|
||||
|
||||
one_ctlseq!(ICH, "@", 1, EscapeSequence::ICH);
|
||||
one_ctlseq!(CUU, "A", 1, EscapeSequence::CUU);
|
||||
one_ctlseq!(CUD, "B", 1, EscapeSequence::CUD);
|
||||
one_ctlseq!(CUF, "C", 1, EscapeSequence::CUF);
|
||||
one_ctlseq!(CUB, "D", 1, EscapeSequence::CUB);
|
||||
one_ctlseq!(CNL, "E", 1, EscapeSequence::CNL);
|
||||
one_ctlseq!(CPL, "F", 1, EscapeSequence::CPL);
|
||||
one_ctlseq!(CHA, "G", 1, EscapeSequence::CHA);
|
||||
two_ctlseq!(CUP, "H", 1, 1, EscapeSequence::CUP);
|
||||
one_ctlseq!(CHT, "I", 1, EscapeSequence::CHT);
|
||||
one_ctlseq!(ED, "J", 0, EscapeSequence::ED);
|
||||
one_ctlseq!(EL, "K", 0, EscapeSequence::EL);
|
||||
one_ctlseq!(IL, "L", 0, EscapeSequence::IL);
|
||||
one_ctlseq!(DL, "M", 0, EscapeSequence::DL);
|
||||
one_ctlseq!(EF, "N", 0, EscapeSequence::EF);
|
||||
one_ctlseq!(EA, "O", 0, EscapeSequence::EA);
|
||||
one_ctlseq!(DCH, "P", 1, EscapeSequence::DCH);
|
||||
one_ctlseq!(SEM, "Q", 0, EscapeSequence::SEM);
|
||||
tag_parser!(CPR, "[R", EscapeSequence::CPR);
|
||||
one_ctlseq!(SU, "S", 1, EscapeSequence::SU);
|
||||
one_ctlseq!(SD, "T", 1, EscapeSequence::SD);
|
||||
one_ctlseq!(NP, "U", 1, EscapeSequence::NP);
|
||||
one_ctlseq!(PP, "V", 1, EscapeSequence::PP);
|
||||
one_ctlseq!(CTC, "W", 0, EscapeSequence::CTC);
|
||||
one_ctlseq!(ECH, "X", 1, EscapeSequence::ECH);
|
||||
one_ctlseq!(CVT, "Y", 1, EscapeSequence::CVT);
|
||||
one_ctlseq!(CBT, "Z", 1, EscapeSequence::CBT);
|
||||
one_ctlseq!(HPA, "`", 0, EscapeSequence::HPA);
|
||||
one_ctlseq!(HPR, "a", 0, EscapeSequence::HPR);
|
||||
one_ctlseq!(REP, "b", 1, EscapeSequence::REP);
|
||||
tag_parser!(DA, "[c", EscapeSequence::DA);
|
||||
one_ctlseq!(VPA, "d", 0, EscapeSequence::VPA);
|
||||
one_ctlseq!(VPR, "e", 0, EscapeSequence::VPR);
|
||||
two_ctlseq!(HVP, "f", 1, 1, EscapeSequence::HVP);
|
||||
one_ctlseq!(TBC, "g", 0, EscapeSequence::TBC);
|
||||
one_ctlseq!(SM, "h", 0, EscapeSequence::SM);
|
||||
one_ctlseq!(MC, "i", 0, EscapeSequence::MC);
|
||||
one_ctlseq!(PageFormatSelect, "j", 0, EscapeSequence::PageFormatSelect);
|
||||
tag_parser!(RM, "[l", EscapeSequence::RM);
|
||||
// TODO SGR takes 5 parameters
|
||||
one_ctlseq!(DSR, "n", 0, EscapeSequence::DSR);
|
||||
one_ctlseq!(DAQ, "o", 0, EscapeSequence::DAQ);
|
||||
tag_parser!(DECLL, "[q", EscapeSequence::DECLL);
|
||||
two_ctlseq!(DECSTBM, "r", 1, 1, EscapeSequence::DECSTBM);
|
||||
two_ctlseq!(DECSTRM, "s", 1, 1, EscapeSequence::DECSTRM);
|
||||
one_ctlseq!(DECSLPP, "t", 66, EscapeSequence::DECSLPP);
|
||||
// TODO DECSHTS takes many parameters
|
||||
// TODO DECSVTS takes many parameters
|
||||
one_ctlseq!(DECSHORP, "w", 0, EscapeSequence::DECSHORP);
|
||||
// TODO DECREQTPARM takes many parameters
|
||||
two_ctlseq!(DECTST, "y", 2, 1, EscapeSequence::DECTST);
|
||||
one_ctlseq!(DECVERP, "z", 0, EscapeSequence::DECVERP);
|
||||
one_ctlseq!(DECTTC, "!", 0, EscapeSequence::DECTTC);
|
||||
// TODO DECPRO takes many parameters
|
||||
one_ctlseq!(DECKEYS, "~", 0, EscapeSequence::DECKEYS);
|
||||
// TODO DELETE needs reading into, what hex code do I need
|
||||
one_ctlseq!(SL, " @", 1, EscapeSequence::SL);
|
||||
one_ctlseq!(SR, " A", 1, EscapeSequence::SR);
|
||||
two_ctlseq!(GSM, " B", 100, 100, EscapeSequence::GSM);
|
||||
one_ctlseq!(GSS, " C", 720, EscapeSequence::GSS);
|
||||
two_ctlseq!(FNT, " D", 0, 1, EscapeSequence::FNT);
|
||||
one_ctlseq!(TSS, " E", 720, EscapeSequence::TSS);
|
||||
one_ctlseq!(JFY, " F", 0, EscapeSequence::JFY);
|
||||
two_ctlseq!(SPI, " G", 720, 720, EscapeSequence::SPI);
|
||||
one_ctlseq!(QUAD, " H", 0, EscapeSequence::QUAD);
|
Loading…
Add table
Add a link
Reference in a new issue