From 3775e0e0ce079d12e40aef18f2b5b5598831c380 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Sat, 4 Apr 2020 11:18:27 +0200 Subject: Spaces, not tabs, in Rust --- src/main.rs | 522 ++++++++++++++++++++++++++++++------------------------------ 1 file 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(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) -> usize + 'static)>; fn mk_callback(f: F) -> Callback - where F: Fn(&mut Vec) -> usize + 'static { - Box::new(f) as Callback + where F: Fn(&mut Vec) -> usize + 'static { + Box::new(f) as Callback } fn stk_binop(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, - entries_drawn: usize, - term_height: usize, - input_buffer: String, - input_cursor: usize, - command_map: &'a HashMap, + stk: Vec, + entries_drawn: usize, + term_height: usize, + input_buffer: String, + input_cursor: usize, + command_map: &'a HashMap, } fn handle_key(key: Key, st: &mut State<'_>) -> Option { - 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::() { - 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::() { + 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::() { @@ -218,124 +218,124 @@ fn handle_key(key: Key, st: &mut State<'_>) -> Option { 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::::new(), - entries_drawn: 0, - term_height: 0, - input_buffer: String::new(), - input_cursor: 0, - command_map: &command_map, - }; + let mut st = State { + stk: Vec::::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(); + } } -- cgit v1.2.3