diff --git a/src/cli.rs b/src/cli.rs index bcaf82506b..f9223f66e8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -162,11 +162,11 @@ pub async fn cli() -> Result<(), Box> { command("from-yaml", Box::new(from_yaml::from_yaml)), command("get", Box::new(get::get)), command("enter", Box::new(enter::enter)), - command("exit", Box::new(exit::exit)), command("n", Box::new(next::next)), command("p", Box::new(prev::prev)), command("lines", Box::new(lines::lines)), command("pick", Box::new(pick::pick)), + command("shells", Box::new(shells::shells)), command("split-column", Box::new(split_column::split_column)), command("split-row", Box::new(split_row::split_row)), command("lines", Box::new(lines::lines)), @@ -185,15 +185,16 @@ pub async fn cli() -> Result<(), Box> { Arc::new(Date), Arc::new(Where), Arc::new(Config), + Arc::new(Exit), Arc::new(SkipWhile), ]); context.add_sinks(vec![ sink("autoview", Box::new(autoview::autoview)), sink("clip", Box::new(clip::clip)), - sink("save", Box::new(save::save)), sink("table", Box::new(table::table)), sink("vtable", Box::new(vtable::vtable)), + Arc::new(Save), ]); } let _ = load_plugins(&mut context); diff --git a/src/commands.rs b/src/commands.rs index d0f76cce72..6f551421fe 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -31,6 +31,7 @@ crate mod ps; crate mod reject; crate mod rm; crate mod save; +crate mod shells; crate mod size; crate mod skip_while; crate mod sort_by; @@ -51,7 +52,9 @@ crate use command::command; crate use config::Config; crate use cp::Copycp; crate use date::Date; +crate use exit::Exit; crate use open::Open; crate use rm::Remove; +crate use save::Save; crate use skip_while::SkipWhile; crate use where_::Where; diff --git a/src/commands/classified.rs b/src/commands/classified.rs index 51c7701304..69807d53ad 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -151,7 +151,7 @@ impl InternalCommand { context.add_span_source(uuid, span_source); } CommandAction::Exit => std::process::exit(0), - CommandAction::Enter(location) => { + CommandAction::EnterShell(location) => { let path = std::path::Path::new(&location); if path.is_dir() { @@ -195,6 +195,12 @@ impl InternalCommand { CommandAction::NextShell => { context.shell_manager.next(); } + CommandAction::LeaveShell => { + context.shell_manager.pop(); + if context.shell_manager.is_empty() { + std::process::exit(0); + } + } }, ReturnSuccess::Value(v) => { diff --git a/src/commands/command.rs b/src/commands/command.rs index eaa14ddfe7..d83feebfc5 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -62,9 +62,10 @@ pub enum CommandAction { ChangePath(String), AddSpanSource(Uuid, SpanSource), Exit, - Enter(String), + EnterShell(String), PreviousShell, NextShell, + LeaveShell, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/commands/enter.rs b/src/commands/enter.rs index 6ad9a923da..987a7115c8 100644 --- a/src/commands/enter.rs +++ b/src/commands/enter.rs @@ -3,9 +3,10 @@ use crate::errors::ShellError; use crate::prelude::*; pub fn enter(args: CommandArgs) -> Result { + //TODO: We could also enter a value in the stream if args.len() == 0 { return Err(ShellError::labeled_error( - "First requires an amount", + "Enter requires a path", "needs parameter", args.call_info.name_span, )); @@ -13,5 +14,8 @@ pub fn enter(args: CommandArgs) -> Result { let location = args.expect_nth(0)?.as_string()?; - Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Enter(location)))].into()) + Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell( + location, + )))] + .into()) } diff --git a/src/commands/exit.rs b/src/commands/exit.rs index 64cddfcfb9..6e33e3d7da 100644 --- a/src/commands/exit.rs +++ b/src/commands/exit.rs @@ -1,7 +1,39 @@ use crate::commands::command::CommandAction; use crate::errors::ShellError; +use crate::parser::registry::{CommandConfig, NamedType}; use crate::prelude::*; +use indexmap::IndexMap; -pub fn exit(_args: CommandArgs) -> Result { - Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into()) +pub struct Exit; + +impl Command for Exit { + fn run(&self, args: CommandArgs) -> Result { + exit(args) + } + + fn name(&self) -> &str { + "exit" + } + + fn config(&self) -> CommandConfig { + let mut named: IndexMap = IndexMap::new(); + named.insert("now".to_string(), NamedType::Switch); + + CommandConfig { + name: self.name().to_string(), + positional: vec![], + rest_positional: false, + named, + is_sink: false, + is_filter: false, + } + } +} + +pub fn exit(args: CommandArgs) -> Result { + if args.call_info.args.has("now") { + Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into()) + } else { + Ok(vec![Ok(ReturnSuccess::Action(CommandAction::LeaveShell))].into()) + } } diff --git a/src/commands/save.rs b/src/commands/save.rs index b34ba0ef3e..0b73e5898d 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -5,9 +5,38 @@ use crate::commands::to_toml::value_to_toml_value; use crate::commands::to_yaml::value_to_yaml_value; use crate::errors::ShellError; use crate::object::{Primitive, Value}; +use crate::parser::registry::{CommandConfig, NamedType}; +use crate::prelude::*; use crate::SpanSource; +use indexmap::IndexMap; use std::path::{Path, PathBuf}; +pub struct Save; + +impl Sink for Save { + fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> { + save(args) + } + + fn name(&self) -> &str { + "save" + } + + fn config(&self) -> CommandConfig { + let mut named: IndexMap = IndexMap::new(); + named.insert("raw".to_string(), NamedType::Switch); + + CommandConfig { + name: self.name().to_string(), + positional: vec![], + rest_positional: false, + named, + is_sink: false, + is_filter: false, + } + } +} + pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> { let cwd = args.ctx.shell_manager.path(); let mut full_path = PathBuf::from(cwd); diff --git a/src/commands/shells.rs b/src/commands/shells.rs new file mode 100644 index 0000000000..6fdc8a7425 --- /dev/null +++ b/src/commands/shells.rs @@ -0,0 +1,18 @@ +use crate::errors::ShellError; +use crate::object::TaggedDictBuilder; +use crate::prelude::*; + +pub fn shells(args: CommandArgs) -> Result { + let mut shells_out = VecDeque::new(); + let span = args.call_info.name_span; + + for shell in args.shell_manager.shells.lock().unwrap().iter() { + let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(span)); + dict.insert("name", shell.name()); + dict.insert("path", shell.path()); + + shells_out.push_back(dict.into_tagged_value()); + } + + Ok(shells_out.to_output_stream()) +} diff --git a/src/context.rs b/src/context.rs index 2bafff846b..73c3b2891d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -96,10 +96,6 @@ impl Context { command.run(command_args) } - pub fn clone_commands(&self) -> indexmap::IndexMap> { - self.commands.clone() - } - crate fn has_command(&self, name: &str) -> bool { self.commands.contains_key(name) } diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index c5db50f290..fab9275dd7 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -50,6 +50,10 @@ impl FilesystemShell { } impl Shell for FilesystemShell { + fn name(&self) -> String { + "filesystem".to_string() + } + fn ls(&self, call_info: CallInfo, _input: InputStream) -> Result { let cwd = self.path.clone(); let mut full_path = PathBuf::from(&self.path); diff --git a/src/shell/shell.rs b/src/shell/shell.rs index 83edbcf8a0..e489e87218 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -8,6 +8,7 @@ where Self: Completer, Self: Hinter, { + fn name(&self) -> String; fn ls(&self, call_info: CallInfo, input: InputStream) -> Result; fn cd(&self, call_info: CallInfo, input: InputStream) -> Result; fn path(&self) -> String; diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs index 7c8bee912e..ab68a79bc6 100644 --- a/src/shell/shell_manager.rs +++ b/src/shell/shell_manager.rs @@ -25,6 +25,14 @@ impl ShellManager { self.set_path(self.path()); } + pub fn pop(&mut self) { + self.shells.lock().unwrap().pop(); + } + + pub fn is_empty(&self) -> bool { + self.shells.lock().unwrap().is_empty() + } + pub fn path(&self) -> String { self.shells.lock().unwrap().last().unwrap().path() } diff --git a/src/shell/value_shell.rs b/src/shell/value_shell.rs index 33761f891f..bc21761c9a 100644 --- a/src/shell/value_shell.rs +++ b/src/shell/value_shell.rs @@ -56,6 +56,10 @@ impl ValueShell { } impl Shell for ValueShell { + fn name(&self) -> String { + "value".to_string() + } + fn ls(&self, _call_info: CallInfo, _input: InputStream) -> Result { Ok(self .members() @@ -110,7 +114,6 @@ impl Completer for ValueShell { _ctx: &rustyline::Context<'_>, ) -> Result<(usize, Vec), ReadlineError> { let mut completions = vec![]; - //let commands = vec!["testme", "whatever"]; let mut possible_completion = vec![]; let members = self.members();