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.
version = 3
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "calc"
version = "0.1.0"
dependencies = [
"signal-hook",
"termcolor",
"termion",
]
[[package]]
@ -16,6 +22,30 @@ version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "signal-hook"
version = "0.3.15"
@ -36,41 +66,13 @@ dependencies = [
]
[[package]]
name = "termcolor"
version = "1.2.0"
name = "termion"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
checksum = "659c1f379f3408c7e5e84c7d0da6d93404e3800b6b9d063ba24436419302ec90"
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
[dependencies]
#dialoguer = "0.10.3"
#colored = "2.0.0"
termcolor = "1.2.0"
signal-hook = "0.3.15"
termion = "2.0.1"

View File

@ -1,110 +1,103 @@
use std::io;
use std::io::Write;
//use std::io::Read;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use termcolor::{
Color,
ColorChoice,
ColorSpec,
StandardStream,
WriteColor
};
use std::io::{Write, stdout, stdin};
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;
use termion::{color, style};
mod parser;
use crate::parser::Token;
//use crate::parser::Token;
//use crate::parser::ParserError;
use crate::parser::LineLocation;
const PROMPT_PREFIX: &str = "==> ";
/// Show a prompt and save trimmed input to `input`.
///
/// # Arguments:
///
/// * `stdout`: Where we should write the prompt
/// * `input`: Where we should save user input
///
/// # Example usage:
/// ```
/// let mut input = String::new();
/// prompt(&mut stdout, &mut input)?;
/// ```
fn prompt(
stdout: &mut StandardStream,
input: &mut String
) -> Result<(), std::io::Error> {
fn draw_line(stdout: &mut RawTerminal<std::io::Stdout>, s: &String) -> Result<(), std::io::Error> {
write!(
stdout,
"\r{}{}==>{}{} {s} {}",
style::Bold,
color::Fg(color::Blue),
color::Fg(color::Reset),
style::Reset,
// Print colored prompt prefix
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Blue)))?;
write!(*stdout, "{PROMPT_PREFIX}")?;
stdout.reset()?; // reset colors
stdout.flush()?; // flush, we didn't print a full line yet.
// Our string can change by at most one character each iteration.
// Clearing is done by inserting an extra space, then moving the cursor left.
termion::cursor::Left(1)
)?;
stdout.flush()?;
// Ask for input
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(())
return Ok(());
}
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));
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;
let mut s: String = String::with_capacity(64);
// Ignore empty input
if input == "" {
stdout.flush()?;
continue;
'outer: loop {
s.clear();
draw_line(&mut stdout, &s)?;
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)) => {
let LineLocation{pos, len} = l;
write!(
stdout,
"{}{}{} {e:?}{}\r\n",
color::Fg(color::Red),
" ".repeat(pos + 4),
"^".repeat(len),
color::Fg(color::Reset),
)?;
}
};
break;
},
'/' => { s.push('÷'); },
'*' => { 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 => {},
Key::Ctrl('d') |
Key::Ctrl('c') => { break 'outer; },
_ => {}
};
};
draw_line(&mut stdout, &s)?;
}
// Parse input.
// Fail if we encounter invalid characters.
let g: Token = match parser::parse(&input) {
Ok(g) => g,
Err((l, e)) => {
let LineLocation{pos, len} = l;
let s = " ";
let m = "^";
println!("{}{} {:?}", s.repeat(pos + 4), m.repeat(len), e);
stdout.flush()?;
continue;
}
};
stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?;
write!(stdout, "\n => ")?;
stdout.reset()?;
write!(stdout, "Got {input}\n\n\n")?;
writeln!(stdout, "Tokenized: {g:#?}")?;
}
writeln!(stdout, "Exiting.")?;
Ok(())
write!(stdout, "\r\n")?;
return Ok(());
}

View File

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