renaming Shell to Session

main
Jordan Orelli 9 months ago
parent 68909d22a8
commit f39a22d408

@ -1,7 +1,7 @@
use crate::log::*;
use std::cmp::min;
pub struct Line {
pub struct Editor {
/// the current contents of the line
chars: Vec<char>,
@ -9,7 +9,7 @@ pub struct Line {
cursor: usize,
}
impl Line {
impl Editor {
pub fn new() -> Self {
Self {
chars: Vec::new(),

@ -1,8 +1,8 @@
use crate::{error::Error, key, log::*};
use anyhow::{Context, Result};
use macros::escapes;
use windows::Win32::Foundation::HANDLE;
use windows::Win32::System::Console;
use macros::escapes;
#[allow(dead_code)]
fn log_input_mode(mode: Console::CONSOLE_MODE) {
@ -214,49 +214,79 @@ impl Reader {
';' => match self.next_escape_char()? {
'5' => match self.next_escape_char()? {
'u' => Ok(Event::Drop(String::from("13;5u"))),
e => Err(Error::input_error(format!("[13;5 unexpected escape char: {}", e)).into()),
}
e => Err(Error::input_error(format!("[13; unexpected escape char: {}", e)).into()),
}
e => Err(Error::input_error(format!("[13 unexpected escape char: {}", e)).into()),
}
e => Err(Error::input_error(format!(
"[13;5 unexpected escape char: {}",
e
))
.into()),
},
e => Err(Error::input_error(format!(
"[13; unexpected escape char: {}",
e
))
.into()),
},
e => Err(
Error::input_error(format!("[13 unexpected escape char: {}", e)).into(),
),
},
'5' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[15~ - F5"))),
e => Err(Error::input_error(format!("[15 unexpected escape char: {}", e)).into()),
}
e => Err(
Error::input_error(format!("[15 unexpected escape char: {}", e)).into(),
),
},
'7' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[17~ - F6"))),
e => Err(Error::input_error(format!("[17 unexpected escape char: {}", e)).into()),
}
e => Err(
Error::input_error(format!("[17 unexpected escape char: {}", e)).into(),
),
},
'8' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[18~ - F7"))),
e => Err(Error::input_error(format!("[18 unexpected escape char: {}", e)).into()),
}
e => Err(
Error::input_error(format!("[18 unexpected escape char: {}", e)).into(),
),
},
'9' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[19~ - F8"))),
e => Err(Error::input_error(format!("[19 unexpected escape char: {}", e)).into()),
e => Err(
Error::input_error(format!("[19 unexpected escape char: {}", e)).into(),
),
},
e => {
Err(Error::input_error(format!("[1 unexpected escape char: {}", e)).into())
}
e => Err(Error::input_error(format!("[1 unexpected escape char: {}", e)).into()),
},
'2' => match self.next_escape_char()? {
'0' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[20~ - F9"))),
e => Err(Error::input_error(format!("[20 unexpected escape char: {}", e)).into()),
}
e => Err(
Error::input_error(format!("[20 unexpected escape char: {}", e)).into(),
),
},
'1' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[21~ - F10"))),
e => Err(Error::input_error(format!("[20 unexpected escape char: {}", e)).into()),
}
e => Err(
Error::input_error(format!("[20 unexpected escape char: {}", e)).into(),
),
},
'3' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[23~ - F11"))),
e => Err(Error::input_error(format!("[23 unexpected escape char: {}", e)).into()),
}
e => Err(
Error::input_error(format!("[23 unexpected escape char: {}", e)).into(),
),
},
'4' => match self.next_escape_char()? {
'~' => Ok(Event::Drop(String::from("[24~ - F12"))),
e => Err(Error::input_error(format!("[24 unexpected escape char: {}", e)).into()),
e => Err(
Error::input_error(format!("[24 unexpected escape char: {}", e)).into(),
),
},
e => {
Err(Error::input_error(format!("[2 unexpected escape char: {}", e)).into())
}
e => Err(Error::input_error(format!("[2 unexpected escape char: {}", e)).into()),
}
},
e => Err(Error::input_error(format!("[ unexpected escape char: {}", e)).into()),
},
'O' => match self.next_escape_char()? {
@ -265,27 +295,11 @@ impl Reader {
'R' => Ok(Event::Drop(String::from("OR - F3"))),
'S' => Ok(Event::Drop(String::from("OS - F4"))),
e => Err(Error::input_error(format!("O unexpected escape char: {}", e)).into()),
}
},
e => Err(Error::input_error(format!("unexpected escape char: {}", e)).into()),
}
}
// fn take_bracket(&mut self) -> Result<()> {
// let rec = self.next_rec()?;
// if rec.EventType as u32 != Console::KEY_EVENT {
// Err(Error::input_error("failed to read escape sequence: not a key event").into())
// } else {
// unsafe {
// let event = rec.Event.KeyEvent;
// if event.wVirtualKeyCode == 0 && event.uChar.UnicodeChar == 91 {
// Ok(())
// } else {
// Err(Error::input_error("failed to read escape sequence: not a [").into())
// }
// }
// }
// }
fn next_escape_char(&mut self) -> Result<char> {
let rec = self.next_rec()?;
if rec.EventType as u32 != Console::KEY_EVENT {
@ -416,5 +430,3 @@ escapes! {
"[24~" F12
"[53;5u" Ctrl_Shift_5
}
/*
*/

@ -1,7 +1,7 @@
use crate::{
edit::Editor,
ext::{Command, Echo, Printenv, Tail, Which},
input,
line::Line,
log::*,
output, syntax,
};
@ -16,26 +16,26 @@ use std::{
use anyhow::Result;
use dirs;
pub struct Shell {
pub struct Session {
pub input: input::Reader,
pub output: output::Writer,
pub line: Line,
pub editor: Editor,
pub state: syntax::State,
}
impl Shell {
impl Session {
pub fn new() -> Result<Self> {
Ok(Self {
input: input::Reader::new()?,
output: output::Writer::stdout()?,
line: Line::new(),
editor: Editor::new(),
state: syntax::State::new(),
})
}
pub fn back(&mut self, n: usize) -> Result<()> {
debug!("⛬ ←");
if self.line.back(n) {
if self.editor.back(n) {
self.output.back(n)?;
}
Ok(())
@ -43,7 +43,7 @@ impl Shell {
pub fn forward(&mut self, n: usize) -> Result<()> {
debug!("⛬ →");
if self.line.forward(n) {
if self.editor.forward(n) {
self.output.forward(n)?;
}
Ok(())
@ -57,7 +57,7 @@ impl Shell {
pub fn seek_right(&mut self) -> Result<()> {
info!("»");
let n = self.line.seek_right();
let n = self.editor.seek_right();
if n > 0 {
// move right by the distance seeked
self.output.forward(n)?;
@ -67,7 +67,7 @@ impl Shell {
pub fn seek_left(&mut self) -> Result<()> {
info!("«");
let n = self.line.seek_left();
let n = self.editor.seek_left();
if n > 0 {
// move left by the distance seeked
self.output.back(n)?;

@ -11,6 +11,9 @@ mod ext;
/// handles input from terminals
mod input;
/// defines the interactive mode
mod interactive;
/// key presses, independent from input sources
mod key;
@ -18,7 +21,7 @@ mod key;
mod lex;
/// a real primitive line editor
mod line;
mod edit;
mod log;
mod output;
@ -27,7 +30,6 @@ mod output;
mod parse;
mod prompt;
mod shell;
/// syntax and semantic analysis
mod syntax;
@ -35,25 +37,22 @@ mod syntax;
/// topoglyph is a real word, i promise
mod topo;
use crate::log::*;
use prompt::Prompt;
use shell::Shell;
use syntax::Eval;
use crate::{interactive::Session, log::*, prompt::Prompt, syntax::Eval};
use std::io::Write;
use anyhow::Result;
fn main() -> Result<()> {
let mut shell = Shell::new()?;
shell.enable_logging("~/clyde.log");
let mut session = Session::new()?;
session.enable_logging("~/clyde.log");
let prompt = Prompt::new();
prompt.print(&mut shell.output)?;
prompt.print(&mut session.output)?;
info!("» shell session start --------");
loop {
match shell.input.next()? {
match session.input.next()? {
input::Event::Key(event) => {
if event.down {
if event.code.val == 0 {
@ -66,18 +65,18 @@ fn main() -> Result<()> {
info!(" {}", event);
if event.code == key::LEFT {
shell.back(1)?;
session.back(1)?;
continue;
}
if event.code == key::RIGHT {
shell.forward(1)?;
session.forward(1)?;
continue;
}
if event.code == key::ENTER {
shell.output.newline()?;
let s = shell.line.pop();
session.output.newline()?;
let s = session.editor.pop();
info!("◇ {}", s);
if let Ok(tokens) = lex::lex(&s) {
for t in tokens {
@ -90,19 +89,19 @@ fn main() -> Result<()> {
let mut state = syntax::State::new();
if let Err(e) = tree.eval(&mut state) {
error!("{e:?}");
shell.render_error(e);
_ = session.render_error(e);
}
}
Err(e) => {
error!("{e:?}");
shell.render_error(e);
_ = session.render_error(e);
}
}
// shell.exec(tree.into())?;
// Some commands don't leave the terminal in a clean state, so we use reset
// to ensure that our input and output modes are what we expect them to be.
shell.reset()?;
prompt.print(&mut shell.output)?;
session.reset()?;
prompt.print(&mut session.output)?;
continue;
}
@ -111,22 +110,22 @@ fn main() -> Result<()> {
}
if event.code == key::BACKSPACE {
if shell.line.backspace() {
if session.editor.backspace() {
// move cursor back two spaces
shell.output.back(2)?;
let tail = format!("{} ", shell.line.tail());
session.output.back(2)?;
let tail = format!("{} ", session.editor.tail());
let n = tail.chars().count();
shell.output.write(tail.as_bytes())?;
session.output.write(tail.as_bytes())?;
// after writing out the tail, rewind by the number of characters in
// the tail
if n > 1 {
// let text = format!("\x1b[{}D", n - 1);
shell.output.back(n - 1)?;
session.output.back(n - 1)?;
// output.write(text.as_bytes())?;
} else {
// honestly I can't remember how I figured this out
shell.output.write(b" \x1b[1D")?;
session.output.write(b" \x1b[1D")?;
}
}
continue;
@ -135,7 +134,7 @@ fn main() -> Result<()> {
// CTRL-D to exit
if event.ctrl && event.code == key::D {
info!("» exit");
shell.output.close()?;
session.output.close()?;
return Ok(());
}
@ -143,7 +142,7 @@ fn main() -> Result<()> {
if event.ctrl && event.code == key::J {
debug!("⎈ j: dot");
// red bullet
shell
session
.output
.write(String::from("\x1b[31m\u{2022}\x1b[0m").as_bytes())?;
continue;
@ -152,69 +151,71 @@ fn main() -> Result<()> {
// CTRL-L to clear the screen
if event.ctrl && event.code == key::L {
info!("» clear");
shell.output.clear()?;
prompt.print(&mut shell.output)?;
shell.output.write(shell.line.show().as_bytes())?;
shell.output.back(shell.line.len() - shell.line.pos())?;
shell.reset()?;
session.output.clear()?;
prompt.print(&mut session.output)?;
session.output.write(session.editor.show().as_bytes())?;
session
.output
.back(session.editor.len() - session.editor.pos())?;
session.reset()?;
continue;
}
// CTRL-U to erase to the beginning of the line
if event.ctrl && event.code == key::U {
info!("» clear left");
let n = shell.line.clear_left();
let n = session.editor.clear_left();
if n > 0 {
// move left by the number of elements removed
shell.output.back(n)?;
session.output.back(n)?;
// draw the elements remaining, followed by a space for each removed
// element
let kept = shell.line.show();
let kept = session.editor.show();
let text = format!("{}{:width$}", kept, "", width = n);
shell.output.write(text.as_bytes())?;
shell.output.back(n + kept.chars().count())?;
session.output.write(text.as_bytes())?;
session.output.back(n + kept.chars().count())?;
}
continue;
}
// CTRL-A to move to the beginning of the line
if event.ctrl && event.code == key::A {
shell.seek_left()?;
session.seek_left()?;
continue;
}
// CTRL-E to move to the end of the line
if event.ctrl && event.code == key::E {
shell.seek_right()?;
session.seek_right()?;
continue;
}
// TODO: something better here, this is crappy. I should be checking characters
// based on their unicode categories, not this garbo
if !event.char.is_control() {
shell.line.insert(event.char);
session.editor.insert(event.char);
let tail = shell.line.tail();
let tail = session.editor.tail();
let n = tail.chars().count();
// write everything from the current line cursor out to the output buffer.
shell.output.write(tail.as_bytes())?;
session.output.write(tail.as_bytes())?;
if n > 1 {
// if we wrote more than one character, because we weren't at the end, we
// need to rewind the terminal cursor to where it was.
shell.output.back(n - 1)?;
session.output.back(n - 1)?;
}
continue;
}
warn!("‽ {}", event);
}
input::Event::Left => shell.back(1)?,
input::Event::Right => shell.forward(1)?,
input::Event::Left => session.back(1)?,
input::Event::Right => session.forward(1)?,
input::Event::Up => debug!("⛬ ↑"),
input::Event::Down => debug!("⛬ ↓"),
input::Event::Home => shell.seek_left()?,
input::Event::End => shell.seek_right()?,
input::Event::Home => session.seek_left()?,
input::Event::End => session.seek_right()?,
input::Event::Focus(true) => {}
input::Event::Focus(false) => {}
input::Event::Menu(_command_id) => {}

Loading…
Cancel
Save