Reworked prompt

pull/2/head
Mark 2023-03-23 22:10:53 -07:00
parent a23cea274f
commit 0eec282cc2
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
4 changed files with 131 additions and 135 deletions

74
Cargo.lock generated
View File

@ -2,12 +2,18 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "calc" name = "calc"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"signal-hook", "signal-hook",
"termcolor", "termion",
] ]
[[package]] [[package]]
@ -16,6 +22,30 @@ version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
[[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]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.15" version = "0.3.15"
@ -36,41 +66,13 @@ dependencies = [
] ]
[[package]] [[package]]
name = "termcolor" name = "termion"
version = "1.2.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" checksum = "659c1f379f3408c7e5e84c7d0da6d93404e3800b6b9d063ba24436419302ec90"
dependencies = [ dependencies = [
"winapi-util", "libc",
"numtoa",
"redox_syscall",
"redox_termios",
] ]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -15,7 +15,5 @@ panic = "abort"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
#dialoguer = "0.10.3"
#colored = "2.0.0"
termcolor = "1.2.0"
signal-hook = "0.3.15" signal-hook = "0.3.15"
termion = "2.0.1"

View File

@ -1,110 +1,103 @@
use std::io; use std::io::{Write, stdout, stdin};
use std::io::Write; use termion::event::Key;
//use std::io::Read; use termion::input::TermRead;
use std::sync::Arc; use termion::raw::IntoRawMode;
use std::sync::atomic::{AtomicBool, Ordering}; use termion::raw::RawTerminal;
use termion::{color, style};
use termcolor::{
Color,
ColorChoice,
ColorSpec,
StandardStream,
WriteColor
};
mod parser; mod parser;
use crate::parser::Token; //use crate::parser::Token;
//use crate::parser::ParserError; //use crate::parser::ParserError;
use crate::parser::LineLocation; use crate::parser::LineLocation;
const PROMPT_PREFIX: &str = "==> ";
/// Show a prompt and save trimmed input to `input`. fn draw_line(stdout: &mut RawTerminal<std::io::Stdout>, s: &String) -> Result<(), std::io::Error> {
/// write!(
/// # Arguments: stdout,
/// "\r{}{}==>{}{} {s} {}",
/// * `stdout`: Where we should write the prompt style::Bold,
/// * `input`: Where we should save user input color::Fg(color::Blue),
/// color::Fg(color::Reset),
/// # Example usage: style::Reset,
/// ```
/// let mut input = String::new();
/// prompt(&mut stdout, &mut input)?;
/// ```
fn prompt(
stdout: &mut StandardStream,
input: &mut String
) -> Result<(), std::io::Error> {
// Print colored prompt prefix // Our string can change by at most one character each iteration.
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Blue)))?; // Clearing is done by inserting an extra space, then moving the cursor left.
write!(*stdout, "{PROMPT_PREFIX}")?; termion::cursor::Left(1)
stdout.reset()?; // reset colors )?;
stdout.flush()?; // flush, we didn't print a full line yet. stdout.flush()?;
// Ask for input return Ok(());
io::stdin().read_line(input)?;
// If this input doesn't end with a newline,
// the user terminated this prompt with ctrl-d.
// Add a newline to keep spacing consistent,
// and clear the input.
if match input.chars().last() {
Some(val) => val != '\n',
None => true
} {
write!(*stdout, "\n")?;
input.clear();
} else {
(*input) = input.trim().to_string();
} }
Ok(())
}
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
let mut stdout = stdout().into_raw_mode().unwrap();
let mut stdout = StandardStream::stdout(ColorChoice::Always); //let size = termion::terminal_size().unwrap();
//write!(stdout, "{:?}", size).unwrap();
let term = Arc::new(AtomicBool::new(false)); let mut s: String = String::with_capacity(64);
signal_hook::flag::register(signal_hook::consts::SIGINT, Arc::clone(&term))?;
while !term.load(Ordering::Relaxed) {
let mut input = String::with_capacity(64);
prompt(&mut stdout, &mut input).expect("Could not show prompt");
let input = input;
// Ignore empty input 'outer: loop {
if input == "" {
stdout.flush()?;
continue;
}
// Parse input. s.clear();
// Fail if we encounter invalid characters. draw_line(&mut stdout, &s)?;
let g: Token = match parser::parse(&input) {
Ok(g) => g, let stdin = stdin();
for c in stdin.keys() {
if let Key::Char(q) = c.as_ref().unwrap() {
match q {
'\n' => {
let s = s.trim().to_string();
if s == "" { write!(stdout, "\r\n")?; break; }
RawTerminal::suspend_raw_mode(&stdout)?;
write!(stdout, "\n")?;
let g = parser::parse(&s);
RawTerminal::activate_raw_mode(&stdout)?;
match g {
Ok(g) => {
RawTerminal::suspend_raw_mode(&stdout)?;
writeln!(stdout, "Tokenized: {g:#?}")?;
RawTerminal::activate_raw_mode(&stdout)?;
},
Err((l, e)) => { Err((l, e)) => {
let LineLocation{pos, len} = l; let LineLocation{pos, len} = l;
write!(
let s = " "; stdout,
let m = "^"; "{}{}{} {e:?}{}\r\n",
println!("{}{} {:?}", s.repeat(pos + 4), m.repeat(len), e); color::Fg(color::Red),
stdout.flush()?; " ".repeat(pos + 4),
continue; "^".repeat(len),
color::Fg(color::Reset),
)?;
} }
}; };
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; break;
write!(stdout, "\n => ")?; },
stdout.reset()?; '/' => { s.push('÷'); },
write!(stdout, "Got {input}\n\n\n")?; '*' => { s.push('×'); },
_ => { s.push(*q); }
};
} else {
match c.unwrap() {
Key::Backspace => { s.pop(); },
Key::Delete => { s.pop(); },
Key::Left => {},
Key::Right => {},
Key::Up => {},
Key::Down => {},
writeln!(stdout, "Tokenized: {g:#?}")?; Key::Ctrl('d') |
Key::Ctrl('c') => { break 'outer; },
_ => {}
};
};
draw_line(&mut stdout, &s)?;
}
} }
writeln!(stdout, "Exiting.")?; write!(stdout, "\r\n")?;
Ok(()) return Ok(());
} }

View File

@ -211,15 +211,18 @@ pub fn tokenize(input: &String) -> Result<Token, (LineLocation, ParserError)> {
// Operator // Operator
// Always one character // Always one character
'+' | '*' | '/' | '^' | '%' => {
'*'|'×'|
'/'|'÷'|
'+'|'%'|'^' => {
push_token(g_now, i, t)?; push_token(g_now, i, t)?;
t = Some(Token::PreOperator( t = Some(Token::PreOperator(
LineLocation{pos: i, len: 1}, LineLocation{pos: i, len: 1},
match c { match c {
'^' => Operators::Power, '^' => Operators::Power,
'%' => Operators::Modulo, '%' => Operators::Modulo,
'*' => Operators::Multiply, '*'|'×' => Operators::Multiply,
'/' => Operators::Divide, '/'|'÷' => Operators::Divide,
'+' => Operators::Add, '+' => Operators::Add,
_ => panic!() _ => panic!()
} }