New "display_output" hook. (#6915)

* New "display_output" hook.

* Fix unrelated "clippy" complaint in nu-tables crate.

* Fix code-formattng and style issues in "display_output" hook

* Enhance eval_hook to return PipelineData.

This allows a hook (including display_output) to return a value.

Co-authored-by: JT <547158+jntrnr@users.noreply.github.com>
This commit is contained in:
Per Bothner
2022-11-05 17:46:40 -07:00
committed by GitHub
parent b90d701f89
commit beec658872
5 changed files with 106 additions and 43 deletions

View File

@ -32,6 +32,7 @@ pub struct Hooks {
pub pre_prompt: Option<Value>,
pub pre_execution: Option<Value>,
pub env_change: Option<Value>,
pub display_output: Option<Value>,
}
impl Hooks {
@ -40,6 +41,7 @@ impl Hooks {
pre_prompt: None,
pre_execution: None,
env_change: None,
display_output: None,
}
}
}
@ -571,9 +573,10 @@ fn create_hooks(value: &Value) -> Result<Hooks, ShellError> {
"pre_prompt" => hooks.pre_prompt = Some(vals[idx].clone()),
"pre_execution" => hooks.pre_execution = Some(vals[idx].clone()),
"env_change" => hooks.env_change = Some(vals[idx].clone()),
"display_output" => hooks.display_output = Some(vals[idx].clone()),
x => {
return Err(ShellError::UnsupportedConfigValue(
"'pre_prompt', 'pre_execution', or 'env_change'".to_string(),
"'pre_prompt', 'pre_execution', 'env_change'".to_string(),
x.to_string(),
*span,
));

View File

@ -426,34 +426,13 @@ impl PipelineData {
..
} = self
{
// NOTE: currently we don't need anything from stderr
// so directly consumes `stderr_stream` to make sure that everything is done.
std::thread::spawn(move || stderr_stream.map(|x| x.into_bytes()));
if let Some(stream) = stream {
for s in stream {
let s_live = s?;
let bin_output = s_live.as_binary()?;
if !to_stderr {
stdout_write_all_and_flush(bin_output)?
} else {
stderr_write_all_and_flush(bin_output)?
}
}
return print_if_stream(stream, stderr_stream, to_stderr, exit_code);
/*
if let Ok(exit_code) = print_if_stream(stream, stderr_stream, to_stderr, exit_code) {
return Ok(exit_code);
}
// Make sure everything has finished
if let Some(exit_code) = exit_code {
let mut exit_codes: Vec<_> = exit_code.into_iter().collect();
return match exit_codes.pop() {
#[cfg(unix)]
Some(Value::Error { error }) => Err(error),
Some(Value::Int { val, .. }) => Ok(val),
_ => Ok(0),
};
}
return Ok(0);
*/
}
match engine_state.find_decl("table".as_bytes(), &[]) {
@ -549,6 +528,42 @@ impl IntoIterator for PipelineData {
}
}
pub fn print_if_stream(
stream: Option<RawStream>,
stderr_stream: Option<RawStream>,
to_stderr: bool,
exit_code: Option<ListStream>,
) -> Result<i64, ShellError> {
// NOTE: currently we don't need anything from stderr
// so directly consumes `stderr_stream` to make sure that everything is done.
std::thread::spawn(move || stderr_stream.map(|x| x.into_bytes()));
if let Some(stream) = stream {
for s in stream {
let s_live = s?;
let bin_output = s_live.as_binary()?;
if !to_stderr {
stdout_write_all_and_flush(bin_output)?
} else {
stderr_write_all_and_flush(bin_output)?
}
}
}
// Make sure everything has finished
if let Some(exit_code) = exit_code {
let mut exit_codes: Vec<_> = exit_code.into_iter().collect();
return match exit_codes.pop() {
#[cfg(unix)]
Some(Value::Error { error }) => Err(error),
Some(Value::Int { val, .. }) => Ok(val),
_ => Ok(0),
};
}
Ok(0)
}
impl Iterator for PipelineIterator {
type Item = Value;