forked from extern/nushell
Merge branch 'master' into implement-whole-stream-command-for-all-commands
This commit is contained in:
commit
421aacee76
@ -140,19 +140,21 @@ impl InternalCommand {
|
|||||||
}
|
}
|
||||||
CommandAction::Exit => std::process::exit(0),
|
CommandAction::Exit => std::process::exit(0),
|
||||||
CommandAction::EnterValueShell(value) => {
|
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) => {
|
CommandAction::EnterShell(location) => {
|
||||||
let path = std::path::Path::new(&location);
|
let path = std::path::Path::new(&location);
|
||||||
|
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
// If it's a directory, add a new filesystem shell
|
// If it's a directory, add a new filesystem shell
|
||||||
context
|
context.shell_manager.insert_at_current(Box::new(
|
||||||
.shell_manager
|
FilesystemShell::with_location(
|
||||||
.push(Box::new(FilesystemShell::with_location(
|
|
||||||
location,
|
location,
|
||||||
context.registry().clone(),
|
context.registry().clone(),
|
||||||
)?));
|
)?,
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
// If it's a file, attempt to open the file as a value and enter it
|
// If it's a file, attempt to open the file as a value and enter it
|
||||||
let cwd = context.shell_manager.path();
|
let cwd = context.shell_manager.path();
|
||||||
@ -180,11 +182,13 @@ impl InternalCommand {
|
|||||||
Span::unknown(),
|
Span::unknown(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
context.shell_manager.push(Box::new(ValueShell::new(value)));
|
context
|
||||||
|
.shell_manager
|
||||||
|
.insert_at_current(Box::new(ValueShell::new(value)));
|
||||||
}
|
}
|
||||||
value => context
|
value => context.shell_manager.insert_at_current(Box::new(
|
||||||
.shell_manager
|
ValueShell::new(value.tagged(contents_tag)),
|
||||||
.push(Box::new(ValueShell::new(value.tagged(contents_tag)))),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +199,7 @@ impl InternalCommand {
|
|||||||
context.shell_manager.next();
|
context.shell_manager.next();
|
||||||
}
|
}
|
||||||
CommandAction::LeaveShell => {
|
CommandAction::LeaveShell => {
|
||||||
context.shell_manager.pop();
|
context.shell_manager.remove_at_current();
|
||||||
if context.shell_manager.is_empty() {
|
if context.shell_manager.is_empty() {
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,10 @@ fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream
|
|||||||
let mut shells_out = VecDeque::new();
|
let mut shells_out = VecDeque::new();
|
||||||
let span = args.call_info.name_span;
|
let span = args.call_info.name_span;
|
||||||
|
|
||||||
let shells_len = args.shell_manager.shells.lock().unwrap().len();
|
|
||||||
|
|
||||||
for (index, shell) in args.shell_manager.shells.lock().unwrap().iter().enumerate() {
|
for (index, shell) in args.shell_manager.shells.lock().unwrap().iter().enumerate() {
|
||||||
let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(span));
|
let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(span));
|
||||||
|
|
||||||
if index == (shells_len - 1) {
|
if index == args.shell_manager.current_shell {
|
||||||
dict.insert(" ", "X".to_string());
|
dict.insert(" ", "X".to_string());
|
||||||
} else {
|
} else {
|
||||||
dict.insert(" ", " ".to_string());
|
dict.insert(" ", " ".to_string());
|
||||||
|
@ -354,7 +354,16 @@ impl Value {
|
|||||||
|
|
||||||
if let Value::Object(ref mut o) = new_obj {
|
if let Value::Object(ref mut o) = new_obj {
|
||||||
let mut current = o;
|
let mut current = o;
|
||||||
for idx in 0..split_path.len() - 1 {
|
|
||||||
|
if split_path.len() == 1 {
|
||||||
|
// Special case for inserting at the top level
|
||||||
|
current
|
||||||
|
.entries
|
||||||
|
.insert(path.to_string(), Tagged::from_item(new_value, tag));
|
||||||
|
return Some(Tagged::from_item(new_obj, tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx in 0..split_path.len() {
|
||||||
match current.entries.get_mut(split_path[idx]) {
|
match current.entries.get_mut(split_path[idx]) {
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
if idx == (split_path.len() - 2) {
|
if idx == (split_path.len() - 2) {
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use crate::commands::command::EvaluatedCommandArgs;
|
|
||||||
use crate::parser::registry::EvaluatedArgs;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use serde::{de, forward_to_deserialize_any};
|
use serde::{de, forward_to_deserialize_any};
|
||||||
|
@ -23,9 +23,10 @@ impl Add {
|
|||||||
Some(f) => match obj.insert_data_at_path(value_tag, &f, v) {
|
Some(f) => match obj.insert_data_at_path(value_tag, &f, v) {
|
||||||
Some(v) => return Ok(v),
|
Some(v) => return Ok(v),
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::string(
|
return Err(ShellError::string(format!(
|
||||||
"add could not find place to insert field",
|
"add could not find place to insert field {:?} {}",
|
||||||
))
|
obj, f
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => Err(ShellError::string(
|
None => Err(ShellError::string(
|
||||||
|
@ -41,7 +41,7 @@ crate use crate::context::CommandRegistry;
|
|||||||
crate use crate::context::{Context, SpanSource};
|
crate use crate::context::{Context, SpanSource};
|
||||||
crate use crate::env::host::handle_unexpected;
|
crate use crate::env::host::handle_unexpected;
|
||||||
crate use crate::env::Host;
|
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::base as value;
|
||||||
crate use crate::object::meta::{Tag, Tagged, TaggedItem};
|
crate use crate::object::meta::{Tag, Tagged, TaggedItem};
|
||||||
crate use crate::object::types::ExtractType;
|
crate use crate::object::types::ExtractType;
|
||||||
|
@ -9,25 +9,44 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ShellManager {
|
pub struct ShellManager {
|
||||||
|
crate current_shell: usize,
|
||||||
crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShellManager {
|
impl ShellManager {
|
||||||
pub fn basic(commands: CommandRegistry) -> Result<ShellManager, Box<dyn Error>> {
|
pub fn basic(commands: CommandRegistry) -> Result<ShellManager, Box<dyn Error>> {
|
||||||
Ok(ShellManager {
|
Ok(ShellManager {
|
||||||
|
current_shell: 0,
|
||||||
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic(
|
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic(
|
||||||
commands,
|
commands,
|
||||||
)?)])),
|
)?)])),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, shell: Box<dyn Shell + Send>) {
|
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) {
|
||||||
self.shells.lock().unwrap().push(shell);
|
self.shells.lock().unwrap().push(shell);
|
||||||
|
self.current_shell = self.shells.lock().unwrap().len() - 1;
|
||||||
self.set_path(self.path());
|
self.set_path(self.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop(&mut self) {
|
pub fn remove_at_current(&mut self) {
|
||||||
self.shells.lock().unwrap().pop();
|
{
|
||||||
|
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 {
|
pub fn is_empty(&self) -> bool {
|
||||||
@ -35,16 +54,11 @@ impl ShellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> String {
|
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) {
|
pub fn set_path(&mut self, path: String) {
|
||||||
self.shells
|
self.shells.lock().unwrap()[self.current_shell].set_path(path)
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.last_mut()
|
|
||||||
.unwrap()
|
|
||||||
.set_path(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn complete(
|
pub fn complete(
|
||||||
@ -53,37 +67,33 @@ impl ShellManager {
|
|||||||
pos: usize,
|
pos: usize,
|
||||||
ctx: &rustyline::Context<'_>,
|
ctx: &rustyline::Context<'_>,
|
||||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||||
self.shells
|
self.shells.lock().unwrap()[self.current_shell].complete(line, pos, ctx)
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.last()
|
|
||||||
.unwrap()
|
|
||||||
.complete(line, pos, ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
pub fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||||
self.shells
|
self.shells.lock().unwrap()[self.current_shell].hint(line, pos, ctx)
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.last()
|
|
||||||
.unwrap()
|
|
||||||
.hint(line, pos, ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
{
|
{
|
||||||
let mut x = self.shells.lock().unwrap();
|
let shell_len = self.shells.lock().unwrap().len();
|
||||||
let shell = x.remove(0);
|
if self.current_shell == (shell_len - 1) {
|
||||||
x.push(shell);
|
self.current_shell = 0;
|
||||||
|
} else {
|
||||||
|
self.current_shell += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.set_path(self.path());
|
self.set_path(self.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prev(&mut self) {
|
pub fn prev(&mut self) {
|
||||||
{
|
{
|
||||||
let mut x = self.shells.lock().unwrap();
|
let shell_len = self.shells.lock().unwrap().len();
|
||||||
let shell = x.pop().unwrap();
|
if self.current_shell == 0 {
|
||||||
x.insert(0, shell);
|
self.current_shell = shell_len - 1;
|
||||||
|
} else {
|
||||||
|
self.current_shell -= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.set_path(self.path());
|
self.set_path(self.path());
|
||||||
}
|
}
|
||||||
@ -91,11 +101,11 @@ impl ShellManager {
|
|||||||
pub fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock().unwrap();
|
let env = self.shells.lock().unwrap();
|
||||||
|
|
||||||
env.last().unwrap().ls(args)
|
env[self.current_shell].ls(args)
|
||||||
}
|
}
|
||||||
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let env = self.shells.lock().unwrap();
|
let env = self.shells.lock().unwrap();
|
||||||
|
|
||||||
env.last().unwrap().cd(args)
|
env[self.current_shell].cd(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ fn knows_the_filesystems_entered() {
|
|||||||
cd ..
|
cd ..
|
||||||
rm red_pill --recursive
|
rm red_pill --recursive
|
||||||
exit
|
exit
|
||||||
|
n
|
||||||
rm blue_pill --recursive
|
rm blue_pill --recursive
|
||||||
exit
|
exit
|
||||||
"#
|
"#
|
||||||
|
Loading…
Reference in New Issue
Block a user