diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 45262bfee..309af2441 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -140,19 +140,21 @@ impl InternalCommand { } CommandAction::Exit => std::process::exit(0), CommandAction::EnterValueShell(value) => { - context.shell_manager.push(Box::new(ValueShell::new(value))); + context + .shell_manager + .insert_at_current(Box::new(ValueShell::new(value))); } CommandAction::EnterShell(location) => { let path = std::path::Path::new(&location); if path.is_dir() { // If it's a directory, add a new filesystem shell - context - .shell_manager - .push(Box::new(FilesystemShell::with_location( + context.shell_manager.insert_at_current(Box::new( + FilesystemShell::with_location( location, context.registry().clone(), - )?)); + )?, + )); } else { // If it's a file, attempt to open the file as a value and enter it let cwd = context.shell_manager.path(); @@ -180,11 +182,13 @@ impl InternalCommand { Span::unknown(), )?; - context.shell_manager.push(Box::new(ValueShell::new(value))); + context + .shell_manager + .insert_at_current(Box::new(ValueShell::new(value))); } - value => context - .shell_manager - .push(Box::new(ValueShell::new(value.tagged(contents_tag)))), + value => context.shell_manager.insert_at_current(Box::new( + ValueShell::new(value.tagged(contents_tag)), + )), } } } @@ -195,7 +199,7 @@ impl InternalCommand { context.shell_manager.next(); } CommandAction::LeaveShell => { - context.shell_manager.pop(); + context.shell_manager.remove_at_current(); if context.shell_manager.is_empty() { std::process::exit(0); } diff --git a/src/commands/shells.rs b/src/commands/shells.rs index 9aa65bdfc..f31a16fd5 100644 --- a/src/commands/shells.rs +++ b/src/commands/shells.rs @@ -27,12 +27,10 @@ fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result { if idx == (split_path.len() - 2) { diff --git a/src/parser/deserializer.rs b/src/parser/deserializer.rs index fe0289aa0..b2cc00ac6 100644 --- a/src/parser/deserializer.rs +++ b/src/parser/deserializer.rs @@ -1,5 +1,3 @@ -use crate::commands::command::EvaluatedCommandArgs; -use crate::parser::registry::EvaluatedArgs; use crate::prelude::*; use log::trace; use serde::{de, forward_to_deserialize_any}; diff --git a/src/plugins/add.rs b/src/plugins/add.rs index 11b90de63..2634c1497 100644 --- a/src/plugins/add.rs +++ b/src/plugins/add.rs @@ -23,9 +23,10 @@ impl Add { Some(f) => match obj.insert_data_at_path(value_tag, &f, v) { Some(v) => return Ok(v), None => { - return Err(ShellError::string( - "add could not find place to insert field", - )) + return Err(ShellError::string(format!( + "add could not find place to insert field {:?} {}", + obj, f + ))) } }, None => Err(ShellError::string( diff --git a/src/prelude.rs b/src/prelude.rs index eec943a99..9e1f7322f 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -41,7 +41,7 @@ crate use crate::context::CommandRegistry; crate use crate::context::{Context, SpanSource}; crate use crate::env::host::handle_unexpected; crate use crate::env::Host; -crate use crate::errors::{ShellError, ShellErrorUtils}; +crate use crate::errors::ShellError; crate use crate::object::base as value; crate use crate::object::meta::{Tag, Tagged, TaggedItem}; crate use crate::object::types::ExtractType; diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs index bce931c51..d8f63ceb0 100644 --- a/src/shell/shell_manager.rs +++ b/src/shell/shell_manager.rs @@ -9,25 +9,44 @@ use std::sync::{Arc, Mutex}; #[derive(Clone, Debug)] pub struct ShellManager { + crate current_shell: usize, crate shells: Arc>>>, } impl ShellManager { pub fn basic(commands: CommandRegistry) -> Result> { Ok(ShellManager { + current_shell: 0, shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic( commands, )?)])), }) } - pub fn push(&mut self, shell: Box) { + pub fn insert_at_current(&mut self, shell: Box) { self.shells.lock().unwrap().push(shell); + self.current_shell = self.shells.lock().unwrap().len() - 1; self.set_path(self.path()); } - pub fn pop(&mut self) { - self.shells.lock().unwrap().pop(); + pub fn remove_at_current(&mut self) { + { + let mut shells = self.shells.lock().unwrap(); + if shells.len() > 0 { + if self.current_shell == shells.len() - 1 { + shells.pop(); + let new_len = shells.len(); + if new_len > 0 { + self.current_shell = new_len - 1; + } else { + return; + } + } else { + shells.remove(self.current_shell); + } + } + } + self.set_path(self.path()); } pub fn is_empty(&self) -> bool { @@ -35,16 +54,11 @@ impl ShellManager { } pub fn path(&self) -> String { - self.shells.lock().unwrap().last().unwrap().path() + self.shells.lock().unwrap()[self.current_shell].path() } pub fn set_path(&mut self, path: String) { - self.shells - .lock() - .unwrap() - .last_mut() - .unwrap() - .set_path(path) + self.shells.lock().unwrap()[self.current_shell].set_path(path) } pub fn complete( @@ -53,37 +67,33 @@ impl ShellManager { pos: usize, ctx: &rustyline::Context<'_>, ) -> Result<(usize, Vec), rustyline::error::ReadlineError> { - self.shells - .lock() - .unwrap() - .last() - .unwrap() - .complete(line, pos, ctx) + self.shells.lock().unwrap()[self.current_shell].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) + self.shells.lock().unwrap()[self.current_shell].hint(line, pos, ctx) } pub fn next(&mut self) { { - let mut x = self.shells.lock().unwrap(); - let shell = x.remove(0); - x.push(shell); + let shell_len = self.shells.lock().unwrap().len(); + if self.current_shell == (shell_len - 1) { + self.current_shell = 0; + } else { + self.current_shell += 1; + } } self.set_path(self.path()); } pub fn prev(&mut self) { { - let mut x = self.shells.lock().unwrap(); - let shell = x.pop().unwrap(); - x.insert(0, shell); + let shell_len = self.shells.lock().unwrap().len(); + if self.current_shell == 0 { + self.current_shell = shell_len - 1; + } else { + self.current_shell -= 1; + } } self.set_path(self.path()); } @@ -91,11 +101,11 @@ impl ShellManager { pub fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result { let env = self.shells.lock().unwrap(); - env.last().unwrap().ls(args) + env[self.current_shell].ls(args) } pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result { let env = self.shells.lock().unwrap(); - env.last().unwrap().cd(args) + env[self.current_shell].cd(args) } } diff --git a/tests/command_enter_test.rs b/tests/command_enter_test.rs index 051d19467..077c1f66c 100644 --- a/tests/command_enter_test.rs +++ b/tests/command_enter_test.rs @@ -48,6 +48,7 @@ fn knows_the_filesystems_entered() { cd .. rm red_pill --recursive exit + n rm blue_pill --recursive exit "#