summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2020-04-04 11:18:27 +0200
committerTom Smeding <tom.smeding@gmail.com>2020-04-04 11:18:27 +0200
commit3775e0e0ce079d12e40aef18f2b5b5598831c380 (patch)
tree103e6998b78c89a1f017679f4d7052faa527003a
parent5b475e392217210d0ca4bf09ba0f131300cdccfd (diff)
Spaces, not tabs, in Rust
-rw-r--r--src/main.rs522
1 files changed, 261 insertions, 261 deletions
diff --git a/src/main.rs b/src/main.rs
index 3d06aec..3b8547f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,187 +15,187 @@ const PROMPT_STR: &str = "> ";
const BEEP_STR: &str = "\x07";
fn min<T: Ord>(a: T, b: T) -> T {
- if b < a {b} else {a}
+ if b < a {b} else {a}
}
fn draw_entries(entries: &[Entry], up: isize) {
- assert!(up < 1<<16);
- if up < 0 {
- print!("{}", termion::cursor::Down((-up) as u16));
- } else if up > 0 {
- print!("{}", termion::cursor::Up(up as u16));
- }
- print!("\r");
- let mut first = true;
- for entry in entries {
- if first {first = false;}
- else {print!("\n\r");}
- print!("{}{}{}", " ".repeat(PROMPT_STR.len()), entry, termion::clear::UntilNewline);
- }
+ assert!(up < 1<<16);
+ if up < 0 {
+ print!("{}", termion::cursor::Down((-up) as u16));
+ } else if up > 0 {
+ print!("{}", termion::cursor::Up(up as u16));
+ }
+ print!("\r");
+ let mut first = true;
+ for entry in entries {
+ if first {first = false;}
+ else {print!("\n\r");}
+ print!("{}{}{}", " ".repeat(PROMPT_STR.len()), entry, termion::clear::UntilNewline);
+ }
}
fn valid_input_char(c: char) -> bool {
- c.is_digit(10) || c == '.' || c == 'e'
+ c.is_digit(10) || c == '.' || c == 'e'
}
type Callback = Box<(dyn Fn(&mut Vec<Entry>) -> usize + 'static)>;
fn mk_callback<F>(f: F) -> Callback
- where F: Fn(&mut Vec<Entry>) -> usize + 'static {
- Box::new(f) as Callback
+ where F: Fn(&mut Vec<Entry>) -> usize + 'static {
+ Box::new(f) as Callback
}
fn stk_binop<F>(f: F) -> Callback
- where F: Fn(Entry, Entry) -> Entry + 'static {
- mk_callback(move |stk| {
- let v2 = stk.pop().unwrap();
- let v1 = stk.pop().unwrap();
- stk.push(f(v1,v2));
- 1
- })
+ where F: Fn(Entry, Entry) -> Entry + 'static {
+ mk_callback(move |stk| {
+ let v2 = stk.pop().unwrap();
+ let v1 = stk.pop().unwrap();
+ stk.push(f(v1,v2));
+ 1
+ })
}
struct State<'a> {
- stk: Vec<Entry>,
- entries_drawn: usize,
- term_height: usize,
- input_buffer: String,
- input_cursor: usize,
- command_map: &'a HashMap<String, (usize, Callback)>,
+ stk: Vec<Entry>,
+ entries_drawn: usize,
+ term_height: usize,
+ input_buffer: String,
+ input_cursor: usize,
+ command_map: &'a HashMap<String, (usize, Callback)>,
}
fn handle_key(key: Key, st: &mut State<'_>) -> Option<bool> {
- match key {
- // Quitting
- Key::Ctrl('c') | Key::Ctrl('d') => {
- if st.input_buffer.len() > 0 {
- print!("\n\r");
- } else {
- print!("\r{}", termion::clear::CurrentLine);
- }
- return Some(false);
- }
+ match key {
+ // Quitting
+ Key::Ctrl('c') | Key::Ctrl('d') => {
+ if st.input_buffer.len() > 0 {
+ print!("\n\r");
+ } else {
+ print!("\r{}", termion::clear::CurrentLine);
+ }
+ return Some(false);
+ }
- // Moving around
- Key::Ctrl('a') => {
- print!("\r{}", termion::cursor::Right(PROMPT_STR.len() as u16));
- st.input_cursor = 0;
- }
- Key::Ctrl('e') => {
- print!("\r{}",
- termion::cursor::Right((PROMPT_STR.len() + st.input_buffer.len()) as u16));
- st.input_cursor = st.input_buffer.len();
- }
- Key::Left => {
- if st.input_cursor > 0 {
- print!("{}", termion::cursor::Left(1));
- st.input_cursor -= 1;
- } else {
- return None;
- }
- }
- Key::Right => {
- if st.input_cursor < st.input_buffer.len() {
- print!("{}", termion::cursor::Right(1));
- st.input_cursor += 1;
- } else {
- return None;
- }
- }
+ // Moving around
+ Key::Ctrl('a') => {
+ print!("\r{}", termion::cursor::Right(PROMPT_STR.len() as u16));
+ st.input_cursor = 0;
+ }
+ Key::Ctrl('e') => {
+ print!("\r{}",
+ termion::cursor::Right((PROMPT_STR.len() + st.input_buffer.len()) as u16));
+ st.input_cursor = st.input_buffer.len();
+ }
+ Key::Left => {
+ if st.input_cursor > 0 {
+ print!("{}", termion::cursor::Left(1));
+ st.input_cursor -= 1;
+ } else {
+ return None;
+ }
+ }
+ Key::Right => {
+ if st.input_cursor < st.input_buffer.len() {
+ print!("{}", termion::cursor::Right(1));
+ st.input_cursor += 1;
+ } else {
+ return None;
+ }
+ }
- // Editing
- Key::Ctrl('u') => {
+ // Editing
+ Key::Ctrl('u') => {
st.input_buffer.drain(..st.input_cursor);
- print!("\r{}{}{}\r{}",
+ print!("\r{}{}{}\r{}",
PROMPT_STR, st.input_buffer, termion::clear::UntilNewline,
termion::cursor::Right(PROMPT_STR.len() as u16));
- st.input_cursor = 0;
- }
- Key::Backspace => {
- if st.input_cursor == 0 {
- return None;
- }
- st.input_cursor -= 1;
- st.input_buffer.remove(st.input_cursor);
- let rest = &st.input_buffer[st.input_cursor..];
- print!("{}{}{}", termion::cursor::Left(1), rest,
- termion::clear::UntilNewline);
- if rest.len() > 0 {
- print!("{}", termion::cursor::Left(rest.len() as u16));
- }
- }
- Key::Delete => {
- if st.input_buffer.len() == 0 {
- if st.stk.len() == 0 {
- return None;
- }
- if st.entries_drawn < st.stk.len() {
- draw_entries(&st.stk[(st.stk.len() - st.entries_drawn - 1)..(st.stk.len() - 1)],
- st.entries_drawn as isize);
- st.input_buffer = match st.stk.last() {
- None => String::new(),
- Some(val) => val.to_string(),
- };
- print!("\n\r{}{}", PROMPT_STR, st.input_buffer);
- st.input_cursor = st.input_buffer.len();
- } else {
- st.entries_drawn -= 1;
- st.input_buffer = match st.stk.last() {
- None => String::new(),
- Some(val) => val.to_string(),
- };
- st.input_cursor = st.input_buffer.len();
- print!("{}{}\r{}{}", termion::clear::CurrentLine,
- termion::cursor::Up(1),
- PROMPT_STR,
- termion::cursor::Right(st.input_cursor as u16))
- }
- st.stk.pop();
- } else if st.input_cursor == st.input_buffer.len() {
- return None;
- } else {
- st.input_buffer.remove(st.input_cursor);
- let rest = &st.input_buffer[st.input_cursor..];
- print!("{}{}", rest, termion::clear::UntilNewline);
- if rest.len() > 0 {
- print!("{}", termion::cursor::Left(rest.len() as u16));
- }
- }
- }
+ st.input_cursor = 0;
+ }
+ Key::Backspace => {
+ if st.input_cursor == 0 {
+ return None;
+ }
+ st.input_cursor -= 1;
+ st.input_buffer.remove(st.input_cursor);
+ let rest = &st.input_buffer[st.input_cursor..];
+ print!("{}{}{}", termion::cursor::Left(1), rest,
+ termion::clear::UntilNewline);
+ if rest.len() > 0 {
+ print!("{}", termion::cursor::Left(rest.len() as u16));
+ }
+ }
+ Key::Delete => {
+ if st.input_buffer.len() == 0 {
+ if st.stk.len() == 0 {
+ return None;
+ }
+ if st.entries_drawn < st.stk.len() {
+ draw_entries(&st.stk[(st.stk.len() - st.entries_drawn - 1)..(st.stk.len() - 1)],
+ st.entries_drawn as isize);
+ st.input_buffer = match st.stk.last() {
+ None => String::new(),
+ Some(val) => val.to_string(),
+ };
+ print!("\n\r{}{}", PROMPT_STR, st.input_buffer);
+ st.input_cursor = st.input_buffer.len();
+ } else {
+ st.entries_drawn -= 1;
+ st.input_buffer = match st.stk.last() {
+ None => String::new(),
+ Some(val) => val.to_string(),
+ };
+ st.input_cursor = st.input_buffer.len();
+ print!("{}{}\r{}{}", termion::clear::CurrentLine,
+ termion::cursor::Up(1),
+ PROMPT_STR,
+ termion::cursor::Right(st.input_cursor as u16))
+ }
+ st.stk.pop();
+ } else if st.input_cursor == st.input_buffer.len() {
+ return None;
+ } else {
+ st.input_buffer.remove(st.input_cursor);
+ let rest = &st.input_buffer[st.input_cursor..];
+ print!("{}{}", rest, termion::clear::UntilNewline);
+ if rest.len() > 0 {
+ print!("{}", termion::cursor::Left(rest.len() as u16));
+ }
+ }
+ }
- // Inputting
- Key::Char(c) if valid_input_char(c) => {
- st.input_buffer.insert(st.input_cursor, c);
- let rest = &st.input_buffer[st.input_cursor..];
- print!("{}", rest);
- if rest.len() > 1 {
- print!("{}", termion::cursor::Left((rest.len() - 1) as u16));
- }
- st.input_cursor += 1;
- }
+ // Inputting
+ Key::Char(c) if valid_input_char(c) => {
+ st.input_buffer.insert(st.input_cursor, c);
+ let rest = &st.input_buffer[st.input_cursor..];
+ print!("{}", rest);
+ if rest.len() > 1 {
+ print!("{}", termion::cursor::Left((rest.len() - 1) as u16));
+ }
+ st.input_cursor += 1;
+ }
- // Submitting
- Key::Char('\n') | Key::Char('\r') => {
- match st.input_buffer.parse::<Entry>() {
- Ok(val) => {
- st.stk.push(val);
- print!("{}\r{}{}\n\r{}",
- termion::clear::CurrentLine, " ".repeat(PROMPT_STR.len()),
- val, PROMPT_STR);
- st.input_buffer.clear();
- st.input_cursor = 0;
- if st.entries_drawn < st.term_height - 1 {
- st.entries_drawn += 1;
- }
- }
- Err(_) => return None,
- }
- }
+ // Submitting
+ Key::Char('\n') | Key::Char('\r') => {
+ match st.input_buffer.parse::<Entry>() {
+ Ok(val) => {
+ st.stk.push(val);
+ print!("{}\r{}{}\n\r{}",
+ termion::clear::CurrentLine, " ".repeat(PROMPT_STR.len()),
+ val, PROMPT_STR);
+ st.input_buffer.clear();
+ st.input_cursor = 0;
+ if st.entries_drawn < st.term_height - 1 {
+ st.entries_drawn += 1;
+ }
+ }
+ Err(_) => return None,
+ }
+ }
- // Command
- Key::Char(c) | Key::Alt(c) => {
- let name = String::from(c.to_string());
- if let Some(&(nargs, ref f)) = st.command_map.get(&name) {
+ // Command
+ Key::Char(c) | Key::Alt(c) => {
+ let name = String::from(c.to_string());
+ if let Some(&(nargs, ref f)) = st.command_map.get(&name) {
let delay_lf;
if st.input_buffer.len() != 0 {
match st.input_buffer.parse::<Entry>() {
@@ -218,124 +218,124 @@ fn handle_key(key: Key, st: &mut State<'_>) -> Option<bool> {
delay_lf = 0;
}
- if st.stk.len() < nargs {
- return None;
- }
- let prevlen = st.stk.len();
- let npushed = f(&mut st.stk);
- let sizeincr = st.stk.len() as isize - prevlen as isize;
- assert!(sizeincr < 0 || npushed >= sizeincr as usize);
- let mut print_newline = true;
- if sizeincr >= 0 {
- // Stack grew
- let usizeincr = sizeincr as usize;
- draw_entries(&st.stk[(st.stk.len() - npushed)..],
- npushed as isize - sizeincr - delay_lf);
- st.entries_drawn = min(st.entries_drawn + usizeincr,
- st.term_height - 1);
- } else if prevlen >= st.term_height && st.stk.len() < st.term_height {
- // Didn't fit before, but fits now
- draw_entries(&st.stk[..], st.stk.len() as isize);
- st.entries_drawn = st.stk.len();
- } else if prevlen < st.term_height {
- // Fit before, and still fits
- assert!(st.stk.len() < st.term_height);
- draw_entries(&st.stk[(st.stk.len() - npushed)..],
- (-sizeincr) + npushed as isize - delay_lf);
- st.entries_drawn = st.stk.len();
- if npushed == 0 {print_newline = false;}
- } else {
- // Didn't fit before, and still doesn't fit
- assert!(prevlen >= st.term_height && st.stk.len() >= st.term_height);
- if sizeincr + delay_lf == 0 {
- let up = min(npushed, st.term_height - 1);
- draw_entries(&st.stk[(st.stk.len() - up)..], up as isize);
- } else {
- draw_entries(&st.stk[(st.stk.len() - st.term_height + 1)..],
- st.term_height as isize - 1);
- }
- st.entries_drawn = st.term_height - 1;
- }
- if print_newline {print!("\n\r");}
- print!("{}{}", termion::clear::AfterCursor, PROMPT_STR);
- } else {
- return None;
- }
- }
+ if st.stk.len() < nargs {
+ return None;
+ }
+ let prevlen = st.stk.len();
+ let npushed = f(&mut st.stk);
+ let sizeincr = st.stk.len() as isize - prevlen as isize;
+ assert!(sizeincr < 0 || npushed >= sizeincr as usize);
+ let mut print_newline = true;
+ if sizeincr >= 0 {
+ // Stack grew
+ let usizeincr = sizeincr as usize;
+ draw_entries(&st.stk[(st.stk.len() - npushed)..],
+ npushed as isize - sizeincr - delay_lf);
+ st.entries_drawn = min(st.entries_drawn + usizeincr,
+ st.term_height - 1);
+ } else if prevlen >= st.term_height && st.stk.len() < st.term_height {
+ // Didn't fit before, but fits now
+ draw_entries(&st.stk[..], st.stk.len() as isize);
+ st.entries_drawn = st.stk.len();
+ } else if prevlen < st.term_height {
+ // Fit before, and still fits
+ assert!(st.stk.len() < st.term_height);
+ draw_entries(&st.stk[(st.stk.len() - npushed)..],
+ (-sizeincr) + npushed as isize - delay_lf);
+ st.entries_drawn = st.stk.len();
+ if npushed == 0 {print_newline = false;}
+ } else {
+ // Didn't fit before, and still doesn't fit
+ assert!(prevlen >= st.term_height && st.stk.len() >= st.term_height);
+ if sizeincr + delay_lf == 0 {
+ let up = min(npushed, st.term_height - 1);
+ draw_entries(&st.stk[(st.stk.len() - up)..], up as isize);
+ } else {
+ draw_entries(&st.stk[(st.stk.len() - st.term_height + 1)..],
+ st.term_height as isize - 1);
+ }
+ st.entries_drawn = st.term_height - 1;
+ }
+ if print_newline {print!("\n\r");}
+ print!("{}{}", termion::clear::AfterCursor, PROMPT_STR);
+ } else {
+ return None;
+ }
+ }
- // Otherwise
- _ => return None,
- }
+ // Otherwise
+ _ => return None,
+ }
- Some(true)
+ Some(true)
}
fn main() {
- let command_map = {
- let mut h = HashMap::new();
+ let command_map = {
+ let mut h = HashMap::new();
- h.insert(String::from("+"), (2, stk_binop(|a,b| a+b)));
- h.insert(String::from("-"), (2, stk_binop(|a,b| a-b)));
- h.insert(String::from("*"), (2, stk_binop(|a,b| a*b)));
- h.insert(String::from("/"), (2, stk_binop(|a,b| a/b)));
- h.insert(String::from("m"), (1, mk_callback(|stk| {
- let v = stk.pop().unwrap();
- stk.push(-v);
- 1
- })));
- h.insert(String::from("s"), (2, mk_callback(|stk| {
- let v = stk.pop().unwrap();
- let len = stk.len();
- stk.insert(len - 1, v);
- 2
- })));
- h.insert(String::from("d"), (1, mk_callback(|stk| {
- let v = stk[stk.len() - 1];
- stk.push(v);
- 2
- })));
- h.insert(String::from("D"), (1, mk_callback(|stk| {
- stk.pop();
- 0
- })));
+ h.insert(String::from("+"), (2, stk_binop(|a,b| a+b)));
+ h.insert(String::from("-"), (2, stk_binop(|a,b| a-b)));
+ h.insert(String::from("*"), (2, stk_binop(|a,b| a*b)));
+ h.insert(String::from("/"), (2, stk_binop(|a,b| a/b)));
+ h.insert(String::from("m"), (1, mk_callback(|stk| {
+ let v = stk.pop().unwrap();
+ stk.push(-v);
+ 1
+ })));
+ h.insert(String::from("s"), (2, mk_callback(|stk| {
+ let v = stk.pop().unwrap();
+ let len = stk.len();
+ stk.insert(len - 1, v);
+ 2
+ })));
+ h.insert(String::from("d"), (1, mk_callback(|stk| {
+ let v = stk[stk.len() - 1];
+ stk.push(v);
+ 2
+ })));
+ h.insert(String::from("D"), (1, mk_callback(|stk| {
+ stk.pop();
+ 0
+ })));
- h
- };
+ h
+ };
- let mut st = State {
- stk: Vec::<Entry>::new(),
- entries_drawn: 0,
- term_height: 0,
- input_buffer: String::new(),
- input_cursor: 0,
- command_map: &command_map,
- };
+ let mut st = State {
+ stk: Vec::<Entry>::new(),
+ entries_drawn: 0,
+ term_height: 0,
+ input_buffer: String::new(),
+ input_cursor: 0,
+ command_map: &command_map,
+ };
- let stdin = io::stdin();
- let mut stdout = io::stdout().into_raw_mode().unwrap();
+ let stdin = io::stdin();
+ let mut stdout = io::stdout().into_raw_mode().unwrap();
- print!("{}", PROMPT_STR);
- stdout.flush().unwrap();
+ print!("{}", PROMPT_STR);
+ stdout.flush().unwrap();
- for key in stdin.keys() {
- let new_term_height = termion::terminal_size().unwrap().1 as usize;
- if new_term_height < st.term_height {
- st.entries_drawn = min(new_term_height - 1, st.stk.len());
- } else if new_term_height > st.term_height {
- let extra_num = min(new_term_height - st.term_height, st.stk.len() - st.entries_drawn);
- if extra_num > 0 {
- let idx = st.stk.len() - st.entries_drawn - extra_num;
- draw_entries(&st.stk[idx..], (st.stk.len() - st.entries_drawn) as isize);
- st.entries_drawn += extra_num;
- }
- }
- st.term_height = new_term_height;
+ for key in stdin.keys() {
+ let new_term_height = termion::terminal_size().unwrap().1 as usize;
+ if new_term_height < st.term_height {
+ st.entries_drawn = min(new_term_height - 1, st.stk.len());
+ } else if new_term_height > st.term_height {
+ let extra_num = min(new_term_height - st.term_height, st.stk.len() - st.entries_drawn);
+ if extra_num > 0 {
+ let idx = st.stk.len() - st.entries_drawn - extra_num;
+ draw_entries(&st.stk[idx..], (st.stk.len() - st.entries_drawn) as isize);
+ st.entries_drawn += extra_num;
+ }
+ }
+ st.term_height = new_term_height;
- match handle_key(key.unwrap(), &mut st) {
- None => print!("{}", BEEP_STR),
- Some(true) => {},
- Some(false) => break,
- }
- stdout.flush().unwrap();
- }
+ match handle_key(key.unwrap(), &mut st) {
+ None => print!("{}", BEEP_STR),
+ Some(true) => {},
+ Some(false) => break,
+ }
+ stdout.flush().unwrap();
+ }
}