Add ctrl_c to RunnablePerItemContext. (#1239)

Also, this commit makes `ls` a per-item command.

A command that processes things item by item may still take some time to stream
out the results from a single item. For example, `ls` on a directory with a lot
of files could be interrupted in the middle of showing all of these files.
This commit is contained in:
Jason Gedge
2020-01-18 21:25:07 -05:00
committed by Jonathan Turner
parent 3abfefc025
commit 47d987d37f
14 changed files with 79 additions and 42 deletions

View File

@@ -251,7 +251,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
context.add_commands(vec![
// System/file operations
whole_stream_command(Pwd),
whole_stream_command(Ls),
per_item_command(Ls),
whole_stream_command(Cd),
whole_stream_command(Env),
per_item_command(Remove),

View File

@@ -42,6 +42,7 @@ pub trait CallInfoExt {
fn process<'de, T: Deserialize<'de>>(
&self,
shell_manager: &ShellManager,
ctrl_c: Arc<AtomicBool>,
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
) -> Result<RunnablePerItemArgs<T>, ShellError>;
}
@@ -50,6 +51,7 @@ impl CallInfoExt for CallInfo {
fn process<'de, T: Deserialize<'de>>(
&self,
shell_manager: &ShellManager,
ctrl_c: Arc<AtomicBool>,
callback: fn(T, &RunnablePerItemContext) -> Result<OutputStream, ShellError>,
) -> Result<RunnablePerItemArgs<T>, ShellError> {
let mut deserializer = ConfigDeserializer::from_call_info(self.clone());
@@ -59,6 +61,7 @@ impl CallInfoExt for CallInfo {
context: RunnablePerItemContext {
shell_manager: shell_manager.clone(),
name: self.name_tag.clone(),
ctrl_c,
},
callback,
})
@@ -219,6 +222,7 @@ impl CommandArgs {
pub struct RunnablePerItemContext {
pub shell_manager: ShellManager,
pub name: Tag,
pub ctrl_c: Arc<AtomicBool>,
}
pub struct RunnableContext {

View File

@@ -38,7 +38,9 @@ impl PerItemCommand for Cpy {
raw_args: &RawCommandArgs,
_input: Value,
) -> Result<OutputStream, ShellError> {
call_info.process(&raw_args.shell_manager, cp)?.run()
call_info
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), cp)?
.run()
}
}

View File

@@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::commands::command::RunnablePerItemContext;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_protocol::{CallInfo, Signature, SyntaxShape, Value};
use nu_source::Tagged;
use std::path::PathBuf;
@@ -9,11 +9,11 @@ pub struct Ls;
#[derive(Deserialize)]
pub struct LsArgs {
path: Option<Tagged<PathBuf>>,
full: bool,
pub path: Option<Tagged<PathBuf>>,
pub full: bool,
}
impl WholeStreamCommand for Ls {
impl PerItemCommand for Ls {
fn name(&self) -> &str {
"ls"
}
@@ -34,14 +34,17 @@ impl WholeStreamCommand for Ls {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
call_info: &CallInfo,
_registry: &CommandRegistry,
raw_args: &RawCommandArgs,
_input: Value,
) -> Result<OutputStream, ShellError> {
args.process(registry, ls)?.run()
// ls(args, registry)
call_info
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), ls)?
.run()
}
}
fn ls(LsArgs { path, full }: LsArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
context.shell_manager.ls(path, &context, full)
fn ls(args: LsArgs, context: &RunnablePerItemContext) -> Result<OutputStream, ShellError> {
context.shell_manager.ls(args, context)
}

View File

@@ -33,7 +33,9 @@ impl PerItemCommand for Mkdir {
raw_args: &RawCommandArgs,
_input: Value,
) -> Result<OutputStream, ShellError> {
call_info.process(&raw_args.shell_manager, mkdir)?.run()
call_info
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), mkdir)?
.run()
}
}

View File

@@ -44,7 +44,9 @@ impl PerItemCommand for Move {
raw_args: &RawCommandArgs,
_input: Value,
) -> Result<OutputStream, ShellError> {
call_info.process(&raw_args.shell_manager, mv)?.run()
call_info
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), mv)?
.run()
}
}

View File

@@ -41,7 +41,9 @@ impl PerItemCommand for Remove {
raw_args: &RawCommandArgs,
_input: Value,
) -> Result<OutputStream, ShellError> {
call_info.process(&raw_args.shell_manager, rm)?.run()
call_info
.process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), rm)?
.run()
}
}

View File

@@ -72,6 +72,7 @@ pub(crate) use nu_protocol::{errln, outln};
pub(crate) use crate::commands::command::{
CallInfoExt, CommandArgs, PerItemCommand, RawCommandArgs, RunnableContext,
RunnablePerItemContext,
};
pub(crate) use crate::context::CommandRegistry;
pub(crate) use crate::context::Context;

View File

@@ -1,5 +1,6 @@
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
use crate::commands::mkdir::MkdirArgs;
use crate::commands::mv::MoveArgs;
use crate::commands::rm::RemoveArgs;
@@ -10,7 +11,6 @@ use crate::shell::shell::Shell;
use crate::utils::FileStructure;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue};
use nu_source::Tagged;
use rustyline::completion::FilenameCompleter;
use rustyline::hint::{Hinter, HistoryHinter};
use std::path::{Path, PathBuf};
@@ -84,14 +84,13 @@ impl Shell for FilesystemShell {
fn ls(
&self,
pattern: Option<Tagged<PathBuf>>,
context: &RunnableContext,
full: bool,
LsArgs { path, full }: LsArgs,
context: &RunnablePerItemContext,
) -> Result<OutputStream, ShellError> {
let cwd = self.path();
let mut full_path = PathBuf::from(self.path());
if let Some(value) = &pattern {
if let Some(value) = &path {
full_path.push((*value).as_ref())
}
@@ -106,7 +105,7 @@ impl Shell for FilesystemShell {
let entries = std::fs::read_dir(&entry);
let entries = match entries {
Err(e) => {
if let Some(s) = pattern {
if let Some(s) = path {
return Err(ShellError::labeled_error(
e.to_string(),
e.to_string(),
@@ -160,7 +159,7 @@ impl Shell for FilesystemShell {
let entries = match glob::glob(&full_path.to_string_lossy()) {
Ok(files) => files,
Err(_) => {
if let Some(source) = pattern {
if let Some(source) = path {
return Err(ShellError::labeled_error(
"Invalid pattern",
"Invalid pattern",

View File

@@ -1,5 +1,6 @@
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
use crate::commands::mkdir::MkdirArgs;
use crate::commands::mv::MoveArgs;
use crate::commands::rm::RemoveArgs;
@@ -10,7 +11,6 @@ use nu_errors::ShellError;
use nu_protocol::{
Primitive, ReturnSuccess, ShellTypeName, TaggedDictBuilder, UntaggedValue, Value,
};
use nu_source::Tagged;
use std::ffi::OsStr;
use std::path::PathBuf;
@@ -135,9 +135,8 @@ impl Shell for HelpShell {
fn ls(
&self,
_pattern: Option<Tagged<PathBuf>>,
_context: &RunnableContext,
_full: bool,
_args: LsArgs,
_context: &RunnablePerItemContext,
) -> Result<OutputStream, ShellError> {
Ok(self.commands().map(ReturnSuccess::value).to_output_stream())
}

View File

@@ -1,12 +1,12 @@
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
use crate::commands::mkdir::MkdirArgs;
use crate::commands::mv::MoveArgs;
use crate::commands::rm::RemoveArgs;
use crate::prelude::*;
use crate::stream::OutputStream;
use nu_errors::ShellError;
use nu_source::Tagged;
use std::path::PathBuf;
pub trait Shell: std::fmt::Debug {
@@ -15,9 +15,8 @@ pub trait Shell: std::fmt::Debug {
fn ls(
&self,
pattern: Option<Tagged<PathBuf>>,
context: &RunnableContext,
full: bool,
args: LsArgs,
context: &RunnablePerItemContext,
) -> Result<OutputStream, ShellError>;
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
fn cp(&self, args: CopyArgs, name: Tag, path: &str) -> Result<OutputStream, ShellError>;

View File

@@ -1,5 +1,6 @@
use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext};
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
use crate::commands::mkdir::MkdirArgs;
use crate::commands::mv::MoveArgs;
use crate::commands::rm::RemoveArgs;
@@ -8,7 +9,6 @@ use crate::shell::filesystem_shell::FilesystemShell;
use crate::shell::shell::Shell;
use crate::stream::OutputStream;
use nu_errors::ShellError;
use nu_source::Tagged;
use std::error::Error;
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
@@ -202,12 +202,11 @@ impl ShellManager {
pub fn ls(
&self,
path: Option<Tagged<PathBuf>>,
context: &RunnableContext,
full: bool,
args: LsArgs,
context: &RunnablePerItemContext,
) -> Result<OutputStream, ShellError> {
if let Ok(shells) = self.shells.lock() {
shells[self.current_shell()].ls(path, context, full)
shells[self.current_shell()].ls(args, context)
} else {
Err(ShellError::untagged_runtime_error(
"Internal error: could not lock shells ring buffer (ls)",

View File

@@ -1,5 +1,6 @@
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
use crate::commands::cp::CopyArgs;
use crate::commands::ls::LsArgs;
use crate::commands::mkdir::MkdirArgs;
use crate::commands::mv::MoveArgs;
use crate::commands::rm::RemoveArgs;
@@ -8,7 +9,6 @@ use crate::shell::shell::Shell;
use crate::utils::ValueStructure;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, ShellTypeName, UntaggedValue, Value};
use nu_source::Tagged;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
@@ -90,14 +90,13 @@ impl Shell for ValueShell {
fn ls(
&self,
target: Option<Tagged<PathBuf>>,
context: &RunnableContext,
_full: bool,
LsArgs { path, .. }: LsArgs,
context: &RunnablePerItemContext,
) -> Result<OutputStream, ShellError> {
let mut full_path = PathBuf::from(self.path());
let name_tag = context.name.clone();
if let Some(value) = &target {
if let Some(value) = &path {
full_path.push(value.as_ref());
}
@@ -105,7 +104,7 @@ impl Shell for ValueShell {
value_system.walk_decorate(&self.value)?;
if !value_system.exists(&full_path) {
if let Some(target) = &target {
if let Some(target) = &path {
return Err(ShellError::labeled_error(
"Can not list entries inside",
"No such path exists",