diff --git a/src/cli.rs b/src/cli.rs index 341d634727..20199d4756 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -262,6 +262,7 @@ pub fn create_default_context( per_item_command(Help), per_item_command(History), whole_stream_command(Save), + per_item_command(Touch), per_item_command(Cpy), whole_stream_command(Date), per_item_command(Calc), diff --git a/src/commands.rs b/src/commands.rs index 4d712aeeba..f96178ef77 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -123,6 +123,7 @@ pub(crate) mod kill; pub(crate) use kill::Kill; pub(crate) mod clear; pub(crate) use clear::Clear; +pub(crate) mod touch; pub(crate) use enter::Enter; pub(crate) use env::Env; #[allow(unused_imports)] @@ -195,6 +196,7 @@ pub(crate) use to_toml::ToTOML; pub(crate) use to_tsv::ToTSV; pub(crate) use to_url::ToURL; pub(crate) use to_yaml::ToYAML; +pub(crate) use touch::Touch; pub(crate) use trim::Trim; pub(crate) use uniq::Uniq; pub(crate) use version::Version; diff --git a/src/commands/touch.rs b/src/commands/touch.rs new file mode 100644 index 0000000000..6585360fdd --- /dev/null +++ b/src/commands/touch.rs @@ -0,0 +1,55 @@ +use crate::prelude::*; +use nu_errors::ShellError; +use nu_protocol::{CallInfo, Signature, SyntaxShape, Value}; +use nu_source::Tagged; +use std::error::Error; +use std::fs::OpenOptions; +use std::path::PathBuf; + +pub struct Touch; + +#[derive(Deserialize)] +pub struct TouchArgs { + pub target: Tagged, +} + +impl PerItemCommand for Touch { + fn name(&self) -> &str { + "touch" + } + fn signature(&self) -> Signature { + Signature::build("touch").required( + "filename", + SyntaxShape::Path, + "the path of the file you want to create", + ) + } + fn usage(&self) -> &str { + "creates a file" + } + fn run( + &self, + call_info: &CallInfo, + _registry: &CommandRegistry, + raw_args: &RawCommandArgs, + _input: Value, + ) -> Result { + call_info + .process(&raw_args.shell_manager, raw_args.ctrl_c.clone(), touch)? + .run() + } +} +fn touch(args: TouchArgs, _context: &RunnablePerItemContext) -> Result { + match OpenOptions::new() + .write(true) + .create(true) + .open(&args.target) + { + Ok(_) => Ok(OutputStream::empty()), + Err(err) => Err(ShellError::labeled_error( + "File Error", + err.description(), + &args.target.tag, + )), + } +} diff --git a/tests/commands/mod.rs b/tests/commands/mod.rs index 8039c59310..7ed1888131 100644 --- a/tests/commands/mod.rs +++ b/tests/commands/mod.rs @@ -28,6 +28,7 @@ mod save; mod sort_by; mod split_by; mod split_column; +mod touch; mod uniq; mod where_; mod wrap; diff --git a/tests/commands/touch.rs b/tests/commands/touch.rs new file mode 100644 index 0000000000..86a40dff81 --- /dev/null +++ b/tests/commands/touch.rs @@ -0,0 +1,19 @@ +use nu_test_support::fs::Stub::EmptyFile; +use nu_test_support::nu; +use nu_test_support::playground::Playground; + +#[test] +fn adds_a_file() { + Playground::setup("add_test_1", |dirs, sandbox| { + sandbox.with_files(vec![EmptyFile("i_will_be_created.txt")]); + + nu!( + cwd: dirs.root(), + "touch touch_test/i_will_be_created.txt" + ); + + let path = dirs.test().join("i_will_be_created.txt"); + + assert!(path.exists()); + }) +}