From 65f97a673b184b7881c5ae123dcbb952185f2a0c Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 07:59:11 +0200 Subject: [PATCH 1/8] refactor(main): improve command input handling loop --- src/main.rs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index d4ce347..d43b637 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,26 @@ -use std::{io::stdin, process::Command}; +use std::{io::{stdin, stdout, Write}, process::Command}; fn main(){ - let mut input = String::new(); - stdin().read_line(&mut input).unwrap(); + loop { + // use the `>` character as the prompt + // need to explicitly flush this to ensure it prints before read_line + print!("> "); + stdout().flush(); - // read_line leaves a trailing newline, which trim removes - let command = input.trim(); + let mut input = String::new(); + stdin().read_line(&mut input).unwrap(); - Command::new(command) - .spawn() - .unwrap(); + let mut parts = input.trim().split_whitespace(); + let command = parts.next().unwrap(); + let args = parts; + + let mut child = Command::new(command) + .args(args) + .spawn() + .unwrap(); + + // don't accept another command until this one completes + child.wait(); + } } + From 1d50cd25d59050a2f1082e43c0296043e7a92da9 Mon Sep 17 00:00:00 2001 From: Renovate Date: Wed, 28 Aug 2024 06:00:40 +0000 Subject: [PATCH 2/8] chore(deps): add renovate.json --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..c183f9d --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "local>Renovate/renovate-config" + ] +} From 3ed823485252f62a2ce832262dedfb1e81d32efb Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 12:17:44 +0200 Subject: [PATCH 3/8] feat: add support for 'cd' command in REPL loop --- src/main.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index d43b637..46a2036 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,7 @@ -use std::{io::{stdin, stdout, Write}, process::Command}; +use std::{env, io::{stdin, stdout, Write}, path::Path, process::Command}; fn main(){ loop { - // use the `>` character as the prompt - // need to explicitly flush this to ensure it prints before read_line print!("> "); stdout().flush(); @@ -14,13 +12,23 @@ fn main(){ let command = parts.next().unwrap(); let args = parts; - let mut child = Command::new(command) - .args(args) - .spawn() - .unwrap(); + match command { + "cd" => { + // default to '/' as new directory if one was not provided + let new_dir = args.peekable().peek().map_or("/", |x| *x); + let root = Path::new(new_dir); + if let Err(e) = env::set_current_dir(&root) { + eprintln!("{}", e); + } + }, + command => { + let mut child = Command::new(command) + .args(args) + .spawn() + .unwrap(); - // don't accept another command until this one completes - child.wait(); + child.wait(); + } + } } } - From 797f401cf302508026aeb6fb8bdd1a0ed3fd5be8 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 12:31:16 +0200 Subject: [PATCH 4/8] feat: implement command piping in shell program --- src/main.rs | 77 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index 46a2036..6085b11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{env, io::{stdin, stdout, Write}, path::Path, process::Command}; +use std::{env, io::{stdin, stdout, Write}, path::Path, process::{Child, Command, Stdio}}; fn main(){ loop { @@ -8,27 +8,66 @@ fn main(){ let mut input = String::new(); stdin().read_line(&mut input).unwrap(); - let mut parts = input.trim().split_whitespace(); - let command = parts.next().unwrap(); - let args = parts; + // must be peekable so we know when we are on the last command + let mut commands = input.trim().split(" | ").peekable(); + let mut previous_command = None; - match command { - "cd" => { - // default to '/' as new directory if one was not provided - let new_dir = args.peekable().peek().map_or("/", |x| *x); - let root = Path::new(new_dir); - if let Err(e) = env::set_current_dir(&root) { - eprintln!("{}", e); + while let Some(command) = commands.next() { + + let mut parts = command.trim().split_whitespace(); + let command = parts.next().unwrap(); + let args = parts; + + match command { + "cd" => { + let new_dir = args.peekable().peek() + .map_or("/", |x| *x); + let root = Path::new(new_dir); + if let Err(e) = env::set_current_dir(&root) { + eprintln!("{}", e); + } + + previous_command = None; + }, + "exit" => return, + command => { + let stdin = previous_command + .map_or( + Stdio::inherit(), + |output: Child| Stdio::from(output.stdout.unwrap()) + ); + + let stdout = if commands.peek().is_some() { + // there is another command piped behind this one + // prepare to send output to the next command + Stdio::piped() + } else { + // there are no more commands piped behind this one + // send output to shell stdout + Stdio::inherit() + }; + + let output = Command::new(command) + .args(args) + .stdin(stdin) + .stdout(stdout) + .spawn(); + + match output { + Ok(output) => { previous_command = Some(output); }, + Err(e) => { + previous_command = None; + eprintln!("{}", e); + }, + }; } - }, - command => { - let mut child = Command::new(command) - .args(args) - .spawn() - .unwrap(); - - child.wait(); } } + + if let Some(mut final_command) = previous_command { + // block until the final command has finished + final_command.wait(); + } + } } From 5961309babe78c8addc57ca6694f49e845f357fa Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 12:36:07 +0200 Subject: [PATCH 5/8] style(main): remove unused result warnings in main.rs --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6085b11..2d7fefa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::{env, io::{stdin, stdout, Write}, path::Path, process::{Child, Command, fn main(){ loop { print!("> "); - stdout().flush(); + let _ = stdout().flush(); let mut input = String::new(); stdin().read_line(&mut input).unwrap(); @@ -66,7 +66,7 @@ fn main(){ if let Some(mut final_command) = previous_command { // block until the final command has finished - final_command.wait(); + let _ = final_command.wait(); } } From 0a5d3e11e44c92dd9ebd8830b20f417b5702e89e Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 13:01:08 +0200 Subject: [PATCH 6/8] feat: add current directory display in main loop --- src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.rs b/src/main.rs index 2d7fefa..f18ab02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ use std::{env, io::{stdin, stdout, Write}, path::Path, process::{Child, Command, fn main(){ loop { + println!(""); + println!("{}", env::current_dir().unwrap().to_str().unwrap()); print!("> "); let _ = stdout().flush(); From 2dbc4d6a288c319011dcc8dce9c117e13213090a Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 13:10:26 +0200 Subject: [PATCH 7/8] feat: add shell_completion dependency and import --- Cargo.lock | 9 +++++++++ Cargo.toml | 1 + src/main.rs | 2 ++ 3 files changed, 12 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 79262b3..50f7213 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,12 @@ version = 3 [[package]] name = "jshell" version = "0.1.0" +dependencies = [ + "shell_completion", +] + +[[package]] +name = "shell_completion" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73937c192504363290613e241705a02dff92ae7c03f544e2a69bbef24cc1042c" diff --git a/Cargo.toml b/Cargo.toml index 023b8d3..b2a72a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +shell_completion = "0.0.2" diff --git a/src/main.rs b/src/main.rs index f18ab02..8bde03e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ use std::{env, io::{stdin, stdout, Write}, path::Path, process::{Child, Command, Stdio}}; +use shell_completion::{BashCompletionInput, CompletionInput, CompletionSet}; + fn main(){ loop { println!(""); From e177b263484d36779c3c936375ccaf2601848444 Mon Sep 17 00:00:00 2001 From: Jan Klattenhoff Date: Wed, 28 Aug 2024 13:19:38 +0200 Subject: [PATCH 8/8] refactor: remove unused imports in main.rs --- src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8bde03e..f18ab02 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,5 @@ use std::{env, io::{stdin, stdout, Write}, path::Path, process::{Child, Command, Stdio}}; -use shell_completion::{BashCompletionInput, CompletionInput, CompletionSet}; - fn main(){ loop { println!("");