Allow open to read its filename from input (#841)

* Allow `open` to read its filename from input

* Add examples
This commit is contained in:
JT 2022-01-24 16:04:28 -05:00 committed by GitHub
parent ec94ca46bb
commit 988a873466
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 5 deletions

View file

@ -1,8 +1,9 @@
use nu_engine::CallExt;
use nu_engine::{get_full_help, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{
ByteStream, Category, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value,
ByteStream, Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Spanned,
SyntaxShape, Value,
};
use std::io::{BufRead, BufReader, Read};
@ -24,7 +25,7 @@ impl Command for Open {
fn signature(&self) -> nu_protocol::Signature {
Signature::build("open")
.required("filename", SyntaxShape::Filepath, "the filename to use")
.optional("filename", SyntaxShape::Filepath, "the filename to use")
.switch("raw", "open file as raw binary", Some('r'))
.category(Category::FileSystem)
}
@ -34,14 +35,47 @@ impl Command for Open {
engine_state: &EngineState,
stack: &mut Stack,
call: &Call,
_input: PipelineData,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let raw = call.has_flag("raw");
let call_span = call.head;
let ctrlc = engine_state.ctrlc.clone();
let path = call.req::<Spanned<String>>(engine_state, stack, 0)?;
let path = call.opt::<Spanned<String>>(engine_state, stack, 0)?;
let path = if let Some(path) = path {
path
} else {
// Collect a filename from the input
match input {
PipelineData::Value(Value::Nothing { .. }, ..) => {
return Ok(Value::String {
val: get_full_help(
&Open.signature(),
&Open.examples(),
engine_state,
stack,
),
span: call.head,
}
.into_pipeline_data())
}
PipelineData::Value(val, ..) => val.as_spanned_string()?,
_ => {
return Ok(Value::String {
val: get_full_help(
&Open.signature(),
&Open.examples(),
engine_state,
stack,
),
span: call.head,
}
.into_pipeline_data())
}
}
};
let arg_span = path.span;
let path = Path::new(&path.item);
@ -117,6 +151,26 @@ impl Command for Open {
}
}
}
fn examples(&self) -> Vec<nu_protocol::Example> {
vec![
Example {
description: "Open a file, with structure (based on file extension)",
example: "open myfile.json",
result: None,
},
Example {
description: "Open a file, as raw bytes",
example: "open myfile.json --raw",
result: None,
},
Example {
description: "Open a file, using the input to get filename",
example: "echo 'myfile.txt' | open",
result: None,
},
]
}
}
fn permission_denied(dir: impl AsRef<Path>) -> bool {

View file

@ -190,6 +190,33 @@ impl Value {
}
}
pub fn as_spanned_string(&self) -> Result<Spanned<String>, ShellError> {
match self {
Value::String { val, span } => Ok(Spanned {
item: val.to_string(),
span: *span,
}),
Value::Binary { val, span } => Ok(match std::str::from_utf8(val) {
Ok(s) => Spanned {
item: s.to_string(),
span: *span,
},
Err(_) => {
return Err(ShellError::CantConvert(
"binary".into(),
"string".into(),
self.span()?,
))
}
}),
x => Err(ShellError::CantConvert(
"string".into(),
x.get_type().to_string(),
self.span()?,
)),
}
}
pub fn as_path(&self) -> Result<PathBuf, ShellError> {
match self {
Value::String { val, .. } => Ok(PathBuf::from(val)),