mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 20:57:49 +02:00
Match Hook
fields to match new config defaults
This commit is contained in:
@ -16,7 +16,7 @@ use crate::{
|
|||||||
use crossterm::cursor::SetCursorStyle;
|
use crossterm::cursor::SetCursorStyle;
|
||||||
use log::{error, trace, warn};
|
use log::{error, trace, warn};
|
||||||
use miette::{ErrReport, IntoDiagnostic, Result};
|
use miette::{ErrReport, IntoDiagnostic, Result};
|
||||||
use nu_cmd_base::{hook::eval_hook, util::get_editor};
|
use nu_cmd_base::util::get_editor;
|
||||||
use nu_color_config::StyleComputer;
|
use nu_color_config::StyleComputer;
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
use nu_engine::{convert_env_values, current_dir_str, env_to_strings};
|
use nu_engine::{convert_env_values, current_dir_str, env_to_strings};
|
||||||
@ -313,20 +313,26 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
|
|||||||
perf!("reset signals", start_time, use_color);
|
perf!("reset signals", start_time, use_color);
|
||||||
|
|
||||||
start_time = std::time::Instant::now();
|
start_time = std::time::Instant::now();
|
||||||
// Right before we start our prompt and take input from the user,
|
// Right before we start our prompt and take input from the user, fire the "pre_prompt" hook
|
||||||
// fire the "pre_prompt" hook
|
if let Err(err) = hook::eval_hooks(
|
||||||
if let Some(hook) = engine_state.get_config().hooks.pre_prompt.clone() {
|
engine_state,
|
||||||
if let Err(err) = eval_hook(engine_state, &mut stack, None, vec![], &hook, "pre_prompt") {
|
&mut stack,
|
||||||
report_shell_error(engine_state, &err);
|
vec![],
|
||||||
}
|
&engine_state.get_config().hooks.pre_prompt.clone(),
|
||||||
|
"pre_prompt",
|
||||||
|
) {
|
||||||
|
report_shell_error(engine_state, &err);
|
||||||
}
|
}
|
||||||
perf!("pre-prompt hook", start_time, use_color);
|
perf!("pre-prompt hook", start_time, use_color);
|
||||||
|
|
||||||
start_time = std::time::Instant::now();
|
start_time = std::time::Instant::now();
|
||||||
// Next, check all the environment variables they ask for
|
// Next, check all the environment variables they ask for
|
||||||
// fire the "env_change" hook
|
// fire the "env_change" hook
|
||||||
let env_change = engine_state.get_config().hooks.env_change.clone();
|
if let Err(error) = hook::eval_env_change_hook(
|
||||||
if let Err(error) = hook::eval_env_change_hook(env_change, engine_state, &mut stack) {
|
&engine_state.get_config().hooks.env_change.clone(),
|
||||||
|
engine_state,
|
||||||
|
&mut stack,
|
||||||
|
) {
|
||||||
report_shell_error(engine_state, &error)
|
report_shell_error(engine_state, &error)
|
||||||
}
|
}
|
||||||
perf!("env-change hook", start_time, use_color);
|
perf!("env-change hook", start_time, use_color);
|
||||||
@ -511,18 +517,17 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
|
|||||||
|
|
||||||
// Right before we start running the code the user gave us, fire the `pre_execution`
|
// Right before we start running the code the user gave us, fire the `pre_execution`
|
||||||
// hook
|
// hook
|
||||||
if let Some(hook) = config.hooks.pre_execution.clone() {
|
{
|
||||||
// Set the REPL buffer to the current command for the "pre_execution" hook
|
// Set the REPL buffer to the current command for the "pre_execution" hook
|
||||||
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
|
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
|
||||||
repl.buffer = repl_cmd_line_text.to_string();
|
repl.buffer = repl_cmd_line_text.to_string();
|
||||||
drop(repl);
|
drop(repl);
|
||||||
|
|
||||||
if let Err(err) = eval_hook(
|
if let Err(err) = hook::eval_hooks(
|
||||||
engine_state,
|
engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
None,
|
|
||||||
vec![],
|
vec![],
|
||||||
&hook,
|
&engine_state.get_config().hooks.pre_execution.clone(),
|
||||||
"pre_execution",
|
"pre_execution",
|
||||||
) {
|
) {
|
||||||
report_shell_error(engine_state, &err);
|
report_shell_error(engine_state, &err);
|
||||||
|
@ -7,49 +7,56 @@ use nu_protocol::{
|
|||||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||||
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
PipelineData, PositionalArg, ShellError, Span, Type, Value, VarId,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
pub fn eval_env_change_hook(
|
pub fn eval_env_change_hook(
|
||||||
env_change_hook: Option<Value>,
|
env_change_hook: &HashMap<String, Value>,
|
||||||
engine_state: &mut EngineState,
|
engine_state: &mut EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
if let Some(hook) = env_change_hook {
|
for (env, hook) in env_change_hook {
|
||||||
match hook {
|
let before = engine_state.previous_env_vars.get(env);
|
||||||
Value::Record { val, .. } => {
|
let after = stack.get_env_var(engine_state, env);
|
||||||
for (env_name, hook_value) in &*val {
|
if before != after {
|
||||||
let before = engine_state.previous_env_vars.get(env_name);
|
let before = before.cloned().unwrap_or_default();
|
||||||
let after = stack.get_env_var(engine_state, env_name);
|
let after = after.cloned().unwrap_or_default();
|
||||||
if before != after {
|
|
||||||
let before = before.cloned().unwrap_or_default();
|
|
||||||
let after = after.cloned().unwrap_or_default();
|
|
||||||
|
|
||||||
eval_hook(
|
eval_hook(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
None,
|
None,
|
||||||
vec![("$before".into(), before), ("$after".into(), after.clone())],
|
vec![("$before".into(), before), ("$after".into(), after.clone())],
|
||||||
hook_value,
|
hook,
|
||||||
"env_change",
|
"env_change",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Arc::make_mut(&mut engine_state.previous_env_vars)
|
Arc::make_mut(&mut engine_state.previous_env_vars).insert(env.clone(), after);
|
||||||
.insert(env_name.clone(), after);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x => {
|
|
||||||
return Err(ShellError::TypeMismatch {
|
|
||||||
err_message: "record for the 'env_change' hook".to_string(),
|
|
||||||
span: x.span(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eval_hooks(
|
||||||
|
engine_state: &mut EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
arguments: Vec<(String, Value)>,
|
||||||
|
hooks: &[Value],
|
||||||
|
hook_name: &str,
|
||||||
|
) -> Result<(), ShellError> {
|
||||||
|
for hook in hooks {
|
||||||
|
eval_hook(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
None,
|
||||||
|
arguments.clone(),
|
||||||
|
hook,
|
||||||
|
&format!("{hook_name} list, recursive"),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eval_hook(
|
pub fn eval_hook(
|
||||||
engine_state: &mut EngineState,
|
engine_state: &mut EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
@ -127,16 +134,7 @@ pub fn eval_hook(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::List { vals, .. } => {
|
Value::List { vals, .. } => {
|
||||||
for val in vals {
|
eval_hooks(engine_state, stack, arguments, vals, hook_name)?;
|
||||||
eval_hook(
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
None,
|
|
||||||
arguments.clone(),
|
|
||||||
val,
|
|
||||||
&format!("{hook_name} list, recursive"),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Value::Record { val, .. } => {
|
Value::Record { val, .. } => {
|
||||||
// Hooks can optionally be a record in this form:
|
// Hooks can optionally be a record in this form:
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use crate as nu_protocol;
|
use crate as nu_protocol;
|
||||||
use crate::Record;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Definition of a parsed hook from the config object
|
/// Definition of a parsed hook from the config object
|
||||||
#[derive(Clone, Debug, IntoValue, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, IntoValue, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Hooks {
|
pub struct Hooks {
|
||||||
pub pre_prompt: Option<Value>,
|
pub pre_prompt: Vec<Value>,
|
||||||
pub pre_execution: Option<Value>,
|
pub pre_execution: Vec<Value>,
|
||||||
pub env_change: Option<Value>,
|
pub env_change: HashMap<String, Value>,
|
||||||
pub display_output: Option<Value>,
|
pub display_output: Option<Value>,
|
||||||
pub command_not_found: Option<Value>,
|
pub command_not_found: Option<Value>,
|
||||||
}
|
}
|
||||||
@ -15,14 +15,14 @@ pub struct Hooks {
|
|||||||
impl Hooks {
|
impl Hooks {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
pre_prompt: Some(Value::list(vec![], Span::unknown())),
|
pre_prompt: Vec::new(),
|
||||||
pre_execution: Some(Value::list(vec![], Span::unknown())),
|
pre_execution: Vec::new(),
|
||||||
env_change: Some(Value::record(Record::default(), Span::unknown())),
|
env_change: HashMap::new(),
|
||||||
display_output: Some(Value::string(
|
display_output: Some(Value::string(
|
||||||
"if (term size).columns >= 100 { table -e } else { table }",
|
"if (term size).columns >= 100 { table -e } else { table }",
|
||||||
Span::unknown(),
|
Span::unknown(),
|
||||||
)),
|
)),
|
||||||
command_not_found: Some(Value::list(vec![], Span::unknown())),
|
command_not_found: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,14 +40,6 @@ impl UpdateFromValue for Hooks {
|
|||||||
path: &mut ConfigPath<'a>,
|
path: &mut ConfigPath<'a>,
|
||||||
errors: &mut ConfigErrors,
|
errors: &mut ConfigErrors,
|
||||||
) {
|
) {
|
||||||
fn update_option(field: &mut Option<Value>, value: &Value) {
|
|
||||||
if value.is_nothing() {
|
|
||||||
*field = None;
|
|
||||||
} else {
|
|
||||||
*field = Some(value.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Value::Record { val: record, .. } = value else {
|
let Value::Record { val: record, .. } = value else {
|
||||||
errors.type_mismatch(path, Type::record(), value);
|
errors.type_mismatch(path, Type::record(), value);
|
||||||
return;
|
return;
|
||||||
@ -56,11 +48,35 @@ impl UpdateFromValue for Hooks {
|
|||||||
for (col, val) in record.iter() {
|
for (col, val) in record.iter() {
|
||||||
let path = &mut path.push(col);
|
let path = &mut path.push(col);
|
||||||
match col.as_str() {
|
match col.as_str() {
|
||||||
"pre_prompt" => update_option(&mut self.pre_prompt, val),
|
"pre_prompt" => {
|
||||||
"pre_execution" => update_option(&mut self.pre_execution, val),
|
if let Ok(hooks) = val.as_list() {
|
||||||
"env_change" => update_option(&mut self.env_change, val),
|
self.pre_prompt = hooks.into()
|
||||||
"display_output" => update_option(&mut self.display_output, val),
|
} else {
|
||||||
"command_not_found" => update_option(&mut self.command_not_found, val),
|
errors.type_mismatch(path, Type::list(Type::Any), val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"pre_execution" => {
|
||||||
|
if let Ok(hooks) = val.as_list() {
|
||||||
|
self.pre_execution = hooks.into()
|
||||||
|
} else {
|
||||||
|
errors.type_mismatch(path, Type::list(Type::Any), val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"env_change" => self.env_change.update(val, path, errors),
|
||||||
|
"display_output" => {
|
||||||
|
self.display_output = if val.is_nothing() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(val.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"command_not_found" => {
|
||||||
|
self.command_not_found = if val.is_nothing() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(val.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => errors.unknown_option(path, val),
|
_ => errors.unknown_option(path, val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_cmd_base::hook::{eval_env_change_hook, eval_hook};
|
use nu_cmd_base::hook::{eval_env_change_hook, eval_hooks};
|
||||||
use nu_engine::eval_block;
|
use nu_engine::eval_block;
|
||||||
use nu_parser::parse;
|
use nu_parser::parse;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -250,24 +250,14 @@ pub fn nu_repl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for pre_prompt hook
|
// Check for pre_prompt hook
|
||||||
let config = engine_state.get_config();
|
let hook = engine_state.get_config().hooks.pre_prompt.clone();
|
||||||
if let Some(hook) = config.hooks.pre_prompt.clone() {
|
if let Err(err) = eval_hooks(&mut engine_state, &mut stack, vec![], &hook, "pre_prompt") {
|
||||||
if let Err(err) = eval_hook(
|
outcome_err(&engine_state, &err);
|
||||||
&mut engine_state,
|
|
||||||
&mut stack,
|
|
||||||
None,
|
|
||||||
vec![],
|
|
||||||
&hook,
|
|
||||||
"pre_prompt",
|
|
||||||
) {
|
|
||||||
outcome_err(&engine_state, &err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for env change hook
|
// Check for env change hook
|
||||||
let config = engine_state.get_config();
|
|
||||||
if let Err(err) = eval_env_change_hook(
|
if let Err(err) = eval_env_change_hook(
|
||||||
config.hooks.env_change.clone(),
|
&engine_state.get_config().hooks.env_change.clone(),
|
||||||
&mut engine_state,
|
&mut engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
) {
|
) {
|
||||||
@ -275,7 +265,6 @@ pub fn nu_repl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for pre_execution hook
|
// Check for pre_execution hook
|
||||||
let config = engine_state.get_config();
|
|
||||||
|
|
||||||
engine_state
|
engine_state
|
||||||
.repl_state
|
.repl_state
|
||||||
@ -283,17 +272,15 @@ pub fn nu_repl() {
|
|||||||
.expect("repl state mutex")
|
.expect("repl state mutex")
|
||||||
.buffer = line.to_string();
|
.buffer = line.to_string();
|
||||||
|
|
||||||
if let Some(hook) = config.hooks.pre_execution.clone() {
|
let hook = engine_state.get_config().hooks.pre_execution.clone();
|
||||||
if let Err(err) = eval_hook(
|
if let Err(err) = eval_hooks(
|
||||||
&mut engine_state,
|
&mut engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
None,
|
vec![],
|
||||||
vec![],
|
&hook,
|
||||||
&hook,
|
"pre_execution",
|
||||||
"pre_execution",
|
) {
|
||||||
) {
|
outcome_err(&engine_state, &err);
|
||||||
outcome_err(&engine_state, &err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eval the REPL line
|
// Eval the REPL line
|
||||||
|
Reference in New Issue
Block a user