Basic prompt/command stuff
This commit is contained in:
104
src/command.rs
Normal file
104
src/command.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use std::io::{self, BufRead, ErrorKind, Read, Seek, Write};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Copy, Default, Clone, PartialEq, Eq)]
|
||||
pub enum Encoding {
|
||||
#[default]
|
||||
UTF8Strict,
|
||||
UTF8Lossy,
|
||||
Bytes,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Default, Clone, PartialEq, Eq)]
|
||||
pub enum LineEnding {
|
||||
Keep,
|
||||
StripLF,
|
||||
|
||||
#[default]
|
||||
StripCRLF,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct ReadOptions {
|
||||
pub encoding: Encoding,
|
||||
pub ending: LineEnding,
|
||||
pub max_read: u64,
|
||||
}
|
||||
|
||||
impl Default for ReadOptions {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
encoding: Default::default(),
|
||||
ending: Default::default(),
|
||||
max_read: 2048,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Command {
|
||||
pub line: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CommandReadError {
|
||||
#[error("An IO Error occurred while attempting to retrieve the next command.")]
|
||||
IOError(#[from] io::Error),
|
||||
|
||||
#[error(
|
||||
"The maximum line length limit was encountered while attempting to read the next command."
|
||||
)]
|
||||
MaxCommandLengthError(String),
|
||||
|
||||
#[error("The command input was closed.")]
|
||||
InputClosed,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn normalize_line_ending(v: &mut String, ending: LineEnding) {
|
||||
if v.ends_with('\n') {
|
||||
match ending {
|
||||
LineEnding::StripLF => {
|
||||
v.pop();
|
||||
}
|
||||
LineEnding::StripCRLF => {
|
||||
v.pop();
|
||||
if v.ends_with('\r') {
|
||||
v.pop();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("No match? {}", v.ends_with('\n'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a single line of `source` into `sink` using the provided ReadOptions.
|
||||
pub fn read_command(opts: ReadOptions) -> Result<Option<String>, CommandReadError> {
|
||||
match opts.encoding {
|
||||
Encoding::UTF8Strict => {}
|
||||
encode => unimplemented!(
|
||||
"Encoding support for {:?} has not been implemented yet!",
|
||||
encode
|
||||
),
|
||||
}
|
||||
|
||||
let mut line = String::with_capacity(8);
|
||||
let stdin = io::stdin().lock();
|
||||
let n = stdin.take(opts.max_read).read_line(&mut line)?;
|
||||
if n == 0 {
|
||||
return Err(CommandReadError::InputClosed);
|
||||
}
|
||||
|
||||
if n == (opts.max_read as usize) && !line.ends_with('\n') {
|
||||
return Err(CommandReadError::MaxCommandLengthError(line));
|
||||
}
|
||||
|
||||
normalize_line_ending(&mut line, opts.ending);
|
||||
if line.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(line))
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
pub mod command;
|
||||
pub mod prompt;
|
||||
|
||||
use strum::Display;
|
||||
|
||||
// Terminal Colors
|
||||
|
||||
33
src/main.rs
33
src/main.rs
@@ -1,3 +1,32 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::io::Write;
|
||||
|
||||
use cacoon_lib::{command::{read_command, CommandReadError, ReadOptions}, prompt::write_prompt};
|
||||
use anyhow::Result;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut stdout = std::io::stdout().lock();
|
||||
|
||||
let prompt = "Cacoon -> ";
|
||||
let response = "Haha, you said: ".as_bytes();
|
||||
|
||||
loop {
|
||||
write_prompt(prompt)?;
|
||||
match read_command(ReadOptions::default()) {
|
||||
Ok(Some(command)) => {
|
||||
// Laugh at the user
|
||||
stdout.write_all(response)?;
|
||||
stdout.write_all(command.as_bytes())?;
|
||||
stdout.write_all(b"\n")?;
|
||||
stdout.flush()?;
|
||||
}
|
||||
Err(CommandReadError::InputClosed) => {
|
||||
stdout.write_all(b"\nGoodbye.\n")?;
|
||||
stdout.flush()?;
|
||||
return Ok(());
|
||||
},
|
||||
other => {
|
||||
other?;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
14
src/prompt.rs
Normal file
14
src/prompt.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use std::io::{self, stdout, Write};
|
||||
|
||||
/// Writes the provided prompt string into the provided output.
|
||||
pub fn write_prompt_into<W: Write>(prompt: &str, output: &mut W) -> io::Result<()> {
|
||||
output.write_all(prompt.as_bytes())?;
|
||||
output.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes the provided prompt to stdout.
|
||||
pub fn write_prompt(prompt: &str, ) -> io::Result<()> {
|
||||
let mut stdout = stdout().lock();
|
||||
write_prompt_into(prompt, &mut stdout)
|
||||
}
|
||||
Reference in New Issue
Block a user