From ab8176d4c7e7791db9ee785605af8b89157557e8 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 7 Aug 2019 15:42:46 +1200 Subject: [PATCH] WIP --- src/cli.rs | 16 +--- src/commands/cd.rs | 5 +- src/commands/classified.rs | 24 ++--- src/commands/command.rs | 3 +- src/commands/cp.rs | 20 +--- src/commands/ls.rs | 4 +- src/commands/open.rs | 8 +- src/commands/rm.rs | 10 +- src/commands/save.rs | 10 +- src/context.rs | 6 +- src/env.rs | 2 - src/prelude.rs | 5 +- src/shell.rs | 2 + src/shell/completer.rs | 1 - .../filesystem_shell.rs} | 30 +++--- src/shell/helper.rs | 21 +---- src/shell/shell.rs | 15 +++ src/shell/shell_manager.rs | 92 +++++++++++++++++++ 18 files changed, 153 insertions(+), 121 deletions(-) rename src/{env/environment.rs => shell/filesystem_shell.rs} (92%) create mode 100644 src/shell/shell.rs create mode 100644 src/shell/shell_manager.rs diff --git a/src/cli.rs b/src/cli.rs index 129c54c7e6..aa6376929e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -223,19 +223,11 @@ pub async fn cli() -> Result<(), Box> { continue; } - let cwd = { - context - .env - .lock() - .unwrap() - .last() - .unwrap() - .path() - .display() - .to_string() - }; + let cwd = context.shell_manager.path(); - rl.set_helper(Some(crate::shell::Helper::new(context.env.clone()))); + rl.set_helper(Some(crate::shell::Helper::new( + context.shell_manager.clone(), + ))); let readline = rl.readline(&format!( "{}{}> ", diff --git a/src/commands/cd.rs b/src/commands/cd.rs index f8edce2425..ed14c8baf6 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -1,9 +1,6 @@ use crate::errors::ShellError; use crate::prelude::*; -use crate::shell::shell::Shell; pub fn cd(args: CommandArgs) -> Result { - let env = args.env.lock().unwrap(); - - env.last().unwrap().cd(args.call_info, args.input) + args.shell_manager.cd(args.call_info, args.input) } diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 521da20a2f..b308b2b2f9 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -145,13 +145,7 @@ impl InternalCommand { match item? { ReturnSuccess::Action(action) => match action { CommandAction::ChangePath(path) => { - let result = context - .env - .lock() - .unwrap() - .last_mut() - .unwrap() - .set_path(path); + context.shell_manager.set_path(&path); } CommandAction::AddSpanSource(uuid, span_source) => { context.add_span_source(uuid, span_source); @@ -159,20 +153,14 @@ impl InternalCommand { CommandAction::Exit => std::process::exit(0), CommandAction::Enter(location) => { context - .env - .lock() - .unwrap() - .push(Box::new(Environment::with_location(location)?)); + .shell_manager + .push(Box::new(FilesystemShell::with_location(location)?)); } CommandAction::PreviousShell => { - let mut x = context.env.lock().unwrap(); - let shell = x.pop().unwrap(); - x.insert(0, shell); + context.shell_manager.prev(); } CommandAction::NextShell => { - let mut x = context.env.lock().unwrap(); - let shell = x.remove(0); - x.push(shell); + context.shell_manager.next(); } }, @@ -321,7 +309,7 @@ impl ExternalCommand { process = Exec::shell(new_arg_string); } - process = process.cwd(context.env.lock().unwrap().last().unwrap().path()); + process = process.cwd(context.shell_manager.path()); let mut process = match stream_next { StreamNext::Last => process, diff --git a/src/commands/command.rs b/src/commands/command.rs index a0dec6c045..ffc4c18ebf 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -4,7 +4,6 @@ use crate::errors::ShellError; use crate::object::Value; use crate::parser::registry::{self, Args}; use crate::prelude::*; -use crate::shell::shell::Shell; use getset::Getters; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -21,7 +20,7 @@ pub struct CallInfo { #[get = "crate"] pub struct CommandArgs { pub host: Arc>, - pub env: Arc>>>, + pub shell_manager: ShellManager, pub call_info: CallInfo, pub input: InputStream, } diff --git a/src/commands/cp.rs b/src/commands/cp.rs index ccc5d784c8..f1acfc506a 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -3,7 +3,7 @@ use crate::parser::hir::SyntaxType; use crate::parser::registry::{CommandConfig, NamedType, PositionalType}; use crate::prelude::*; use indexmap::IndexMap; -use std::path::Path; +use std::path::{Path, PathBuf}; pub struct Copycp; @@ -32,22 +32,8 @@ impl Command for Copycp { } pub fn cp(args: CommandArgs) -> Result { - let mut source = args - .env - .lock() - .unwrap() - .last() - .unwrap() - .path() - .to_path_buf(); - let mut destination = args - .env - .lock() - .unwrap() - .last() - .unwrap() - .path() - .to_path_buf(); + let mut source = PathBuf::from(args.shell_manager.path()); + let mut destination = PathBuf::from(args.shell_manager.path()); let mut dst = String::new(); diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 9b5e59eac7..c591c1fb2a 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -2,7 +2,5 @@ use crate::errors::ShellError; use crate::prelude::*; pub fn ls(args: CommandArgs) -> Result { - let env = args.env.lock().unwrap(); - - env.last().unwrap().ls(args.call_info, args.input) + args.shell_manager.ls(args.call_info, args.input) } diff --git a/src/commands/open.rs b/src/commands/open.rs index a33e2319e9..fc754c6ab4 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -12,13 +12,7 @@ command! { let span = args.call_info.name_span; let cwd = args - .env - .lock() - .unwrap() - .last() - .unwrap() - .path() - .to_path_buf(); + .shell_manager.path(); let full_path = PathBuf::from(cwd); diff --git a/src/commands/rm.rs b/src/commands/rm.rs index ecbb833258..aa0d10c43f 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -5,6 +5,7 @@ use crate::prelude::*; use glob::glob; use indexmap::IndexMap; +use std::path::PathBuf; pub struct Remove; @@ -33,14 +34,7 @@ impl Command for Remove { } pub fn rm(args: CommandArgs) -> Result { - let mut full_path = args - .env - .lock() - .unwrap() - .last() - .unwrap() - .path() - .to_path_buf(); + let mut full_path = PathBuf::from(args.shell_manager.path()); match args .nth(0) diff --git a/src/commands/save.rs b/src/commands/save.rs index b0df6aa4ab..b34ba0ef3e 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -9,15 +9,7 @@ use crate::SpanSource; use std::path::{Path, PathBuf}; pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { - let cwd = args - .ctx - .env - .lock() - .unwrap() - .last() - .unwrap() - .path() - .to_path_buf(); + let cwd = args.ctx.shell_manager.path(); let mut full_path = PathBuf::from(cwd); let save_raw = if args.call_info.args.has("raw") { diff --git a/src/context.rs b/src/context.rs index b7c34375ab..2bafff846b 100644 --- a/src/context.rs +++ b/src/context.rs @@ -38,7 +38,7 @@ pub struct Context { sinks: IndexMap>, crate source_map: SourceMap, crate host: Arc>, - crate env: Arc>>>, + crate shell_manager: ShellManager, } impl Context { @@ -48,7 +48,7 @@ impl Context { sinks: indexmap::IndexMap::new(), source_map: SourceMap::new(), host: Arc::new(Mutex::new(crate::env::host::BasicHost)), - env: Arc::new(Mutex::new(vec![Box::new(Environment::basic()?)])), + shell_manager: ShellManager::basic()?, }) } @@ -118,7 +118,7 @@ impl Context { ) -> Result { let command_args = CommandArgs { host: self.host.clone(), - env: self.env.clone(), + shell_manager: self.shell_manager.clone(), call_info: CallInfo { name_span, source_map, diff --git a/src/env.rs b/src/env.rs index cc571b836e..2dd836f1fe 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,5 +1,3 @@ -crate mod environment; crate mod host; -crate use self::environment::Environment; crate use self::host::Host; diff --git a/src/prelude.rs b/src/prelude.rs index e7e705a4ca..d6dbf7bace 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -38,12 +38,13 @@ crate use crate::commands::command::{ }; crate use crate::context::{Context, SpanSource}; crate use crate::env::host::handle_unexpected; -crate use crate::env::{Environment, Host}; +crate use crate::env::Host; crate use crate::errors::ShellError; crate use crate::object::meta::{Tag, Tagged, TaggedItem}; crate use crate::object::types::ExtractType; crate use crate::object::{Primitive, Value}; -crate use crate::shell::shell::Shell; +crate use crate::shell::filesystem_shell::FilesystemShell; +crate use crate::shell::shell_manager::ShellManager; crate use crate::stream::{InputStream, OutputStream}; crate use crate::Span; crate use crate::Text; diff --git a/src/shell.rs b/src/shell.rs index b0bc80de9e..9613d07833 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1,5 +1,7 @@ crate mod completer; +crate mod filesystem_shell; crate mod helper; crate mod shell; +crate mod shell_manager; crate use helper::Helper; diff --git a/src/shell/completer.rs b/src/shell/completer.rs index fbfa9cda97..191838ff1d 100644 --- a/src/shell/completer.rs +++ b/src/shell/completer.rs @@ -1,4 +1,3 @@ -use crate::prelude::*; use derive_new::new; use rustyline::completion::Completer; use rustyline::completion::{self, FilenameCompleter}; diff --git a/src/env/environment.rs b/src/shell/filesystem_shell.rs similarity index 92% rename from src/env/environment.rs rename to src/shell/filesystem_shell.rs index ca6b87096e..a54459cd4a 100644 --- a/src/env/environment.rs +++ b/src/shell/filesystem_shell.rs @@ -7,15 +7,15 @@ use rustyline::completion::{self, Completer, FilenameCompleter}; use rustyline::error::ReadlineError; use rustyline::hint::{Hinter, HistoryHinter}; use std::path::{Path, PathBuf}; -pub struct Environment { +pub struct FilesystemShell { crate path: PathBuf, completer: NuCompleter, hinter: HistoryHinter, } -impl Clone for Environment { +impl Clone for FilesystemShell { fn clone(&self) -> Self { - Environment { + FilesystemShell { path: self.path.clone(), completer: NuCompleter { file_completer: FilenameCompleter::new(), @@ -25,11 +25,11 @@ impl Clone for Environment { } } -impl Environment { - pub fn basic() -> Result { +impl FilesystemShell { + pub fn basic() -> Result { let path = std::env::current_dir()?; - Ok(Environment { + Ok(FilesystemShell { path, completer: NuCompleter { file_completer: FilenameCompleter::new(), @@ -38,10 +38,10 @@ impl Environment { }) } - pub fn with_location(location: String) -> Result { + pub fn with_location(location: String) -> Result { let path = std::path::PathBuf::from(location); - Ok(Environment { + Ok(FilesystemShell { path, completer: NuCompleter { file_completer: FilenameCompleter::new(), @@ -49,13 +49,9 @@ impl Environment { hinter: HistoryHinter {}, }) } - - pub fn path(&self) -> &Path { - self.path.as_path() - } } -impl Shell for Environment { +impl Shell for FilesystemShell { fn ls(&self, call_info: CallInfo, _input: InputStream) -> Result { let cwd = self.path.clone(); let mut full_path = PathBuf::from(&self.path); @@ -179,12 +175,12 @@ impl Shell for Environment { self.path.clone() } - fn set_path(&mut self, path: std::path::PathBuf) { - self.path = path; + fn set_path(&mut self, path: &std::path::PathBuf) { + self.path = path.clone(); } } -impl Completer for Environment { +impl Completer for FilesystemShell { type Candidate = completion::Pair; fn complete( @@ -197,7 +193,7 @@ impl Completer for Environment { } } -impl Hinter for Environment { +impl Hinter for FilesystemShell { fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option { self.hinter.hint(line, pos, ctx) } diff --git a/src/shell/helper.rs b/src/shell/helper.rs index 57220b4f82..7db29c1f25 100644 --- a/src/shell/helper.rs +++ b/src/shell/helper.rs @@ -2,7 +2,7 @@ use crate::parser::nom_input; use crate::parser::parse::token_tree::TokenNode; use crate::parser::parse::tokens::RawToken; use crate::parser::{Pipeline, PipelineElement}; -use crate::shell::shell::Shell; +use crate::shell::shell_manager::ShellManager; use crate::Tagged; use ansi_term::Color; use rustyline::completion::{self, Completer}; @@ -10,14 +10,13 @@ use rustyline::error::ReadlineError; use rustyline::highlight::Highlighter; use rustyline::hint::Hinter; use std::borrow::Cow::{self, Owned}; -use std::sync::{Arc, Mutex}; crate struct Helper { - helper: Arc>>>, + helper: ShellManager, } impl Helper { - crate fn new(helper: Arc>>>) -> Helper { + crate fn new(helper: ShellManager) -> Helper { Helper { helper } } } @@ -31,23 +30,13 @@ impl Completer for Helper { pos: usize, ctx: &rustyline::Context<'_>, ) -> Result<(usize, Vec), ReadlineError> { - self.helper - .lock() - .unwrap() - .last() - .unwrap() - .complete(line, pos, ctx) + self.helper.complete(line, pos, ctx) } } impl Hinter for Helper { fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option { - self.helper - .lock() - .unwrap() - .last() - .unwrap() - .hint(line, pos, ctx) + self.helper.hint(line, pos, ctx) } } diff --git a/src/shell/shell.rs b/src/shell/shell.rs new file mode 100644 index 0000000000..c68f205b93 --- /dev/null +++ b/src/shell/shell.rs @@ -0,0 +1,15 @@ +use crate::commands::command::CallInfo; +use crate::errors::ShellError; +use crate::stream::{InputStream, OutputStream}; +use rustyline::{completion::Completer, hint::Hinter}; + +pub trait Shell +where + Self: Completer, + Self: Hinter, +{ + fn ls(&self, call_info: CallInfo, input: InputStream) -> Result; + fn cd(&self, call_info: CallInfo, input: InputStream) -> Result; + fn path(&self) -> std::path::PathBuf; + fn set_path(&mut self, path: &std::path::PathBuf); +} diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs new file mode 100644 index 0000000000..9532572376 --- /dev/null +++ b/src/shell/shell_manager.rs @@ -0,0 +1,92 @@ +use crate::commands::command::CallInfo; +use crate::errors::ShellError; +use crate::shell::filesystem_shell::FilesystemShell; +use crate::shell::shell::Shell; +use crate::stream::{InputStream, OutputStream}; +use rustyline::completion::{self, Completer}; +use rustyline::error::ReadlineError; +use std::error::Error; +use std::sync::{Arc, Mutex}; + +#[derive(Clone)] +pub struct ShellManager { + crate shells: Arc>>>, +} + +impl ShellManager { + pub fn basic() -> Result> { + Ok(ShellManager { + shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic()?)])), + }) + } + + pub fn push(&mut self, shell: Box) { + self.shells.lock().unwrap().push(shell) + } + + pub fn path(&self) -> String { + self.shells + .lock() + .unwrap() + .last() + .unwrap() + .path() + .display() + .to_string() + } + + pub fn set_path(&mut self, path: &std::path::PathBuf) { + self.shells + .lock() + .unwrap() + .last_mut() + .unwrap() + .set_path(path) + } + + pub fn complete( + &self, + line: &str, + pos: usize, + ctx: &rustyline::Context<'_>, + ) -> Result<(usize, Vec), ReadlineError> { + self.shells + .lock() + .unwrap() + .last() + .unwrap() + .complete(line, pos, ctx) + } + + pub fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option { + self.shells + .lock() + .unwrap() + .last() + .unwrap() + .hint(line, pos, ctx) + } + + pub fn next(&mut self) { + let mut x = self.shells.lock().unwrap(); + let shell = x.pop().unwrap(); + x.insert(0, shell); + } + + pub fn prev(&mut self) { + let mut x = self.shells.lock().unwrap(); + let shell = x.remove(0); + x.push(shell); + } + + pub fn ls(&self, call_info: CallInfo, input: InputStream) -> Result { + let env = self.shells.lock().unwrap(); + + env.last().unwrap().ls(call_info, input) + } + pub fn cd(&self, call_info: CallInfo, input: InputStream) -> Result { + let env = self.shells.lock().unwrap(); + + env.last().unwrap().cd(call_info, input) + } +}