1use nu_engine::command_prelude::*;
2use nu_protocol::engine::{ENV_VARIABLE_ID, IN_VARIABLE_ID, NU_VARIABLE_ID};
3
4#[derive(Clone)]
5pub struct DeleteVar;
6
7impl Command for DeleteVar {
8 fn name(&self) -> &str {
9 "unlet"
10 }
11
12 fn description(&self) -> &str {
13 "Delete variables from nushell memory, making them unrecoverable."
14 }
15
16 fn signature(&self) -> nu_protocol::Signature {
17 Signature::build("unlet")
18 .input_output_types(vec![(Type::Nothing, Type::Nothing)])
19 .rest(
20 "rest",
21 SyntaxShape::Any,
22 "The variables to delete (pass as $variable_name).",
23 )
24 .category(Category::Experimental)
25 }
26
27 fn run(
28 &self,
29 _engine_state: &EngineState,
30 stack: &mut Stack,
31 call: &Call,
32 _input: PipelineData,
33 ) -> Result<PipelineData, ShellError> {
34 let expressions: Vec<_> = (0..).map_while(|i| call.positional_nth(stack, i)).collect();
36
37 if expressions.is_empty() {
39 return Err(ShellError::GenericError {
40 error: "Wrong number of arguments".into(),
41 msg: "unlet takes at least one argument".into(),
42 span: Some(call.head),
43 help: None,
44 inner: vec![],
45 });
46 }
47
48 let mut var_ids = Vec::with_capacity(expressions.len());
50 for expr in expressions {
51 match &expr.expr {
52 nu_protocol::ast::Expr::Var(var_id) => {
53 if var_id == &NU_VARIABLE_ID
55 || var_id == &ENV_VARIABLE_ID
56 || var_id == &IN_VARIABLE_ID
57 {
58 let var_name = match *var_id {
60 NU_VARIABLE_ID => "nu",
61 ENV_VARIABLE_ID => "env",
62 IN_VARIABLE_ID => "in",
63 _ => "unknown", };
65
66 return Err(ShellError::GenericError {
67 error: "Cannot delete built-in variable".into(),
68 msg: format!(
69 "'${}' is a built-in variable and cannot be deleted",
70 var_name
71 ),
72 span: Some(expr.span),
73 help: None,
74 inner: vec![],
75 });
76 }
77 var_ids.push(*var_id);
78 }
79 _ => {
80 return Err(ShellError::GenericError {
82 error: "Not a variable".into(),
83 msg: "Argument must be a variable reference like $x".into(),
84 span: Some(expr.span),
85 help: Some("Use $variable_name to refer to the variable".into()),
86 inner: vec![],
87 });
88 }
89 }
90 }
91
92 for var_id in var_ids {
94 stack.remove_var(var_id);
95 }
96
97 Ok(PipelineData::empty())
98 }
99
100 fn requires_ast_for_arguments(&self) -> bool {
101 true
102 }
103
104 fn examples(&self) -> Vec<Example<'_>> {
105 vec![
106 Example {
107 example: "let x = 42; unlet $x",
108 description: "Delete a variable from memory",
109 result: None,
110 },
111 Example {
112 example: "let x = 1; let y = 2; unlet $x $y",
113 description: "Delete multiple variables from memory",
114 result: None,
115 },
116 Example {
117 example: "unlet $nu",
118 description: "Attempting to delete a built-in variable fails",
119 result: None,
120 },
121 Example {
122 example: "unlet 42",
123 description: "Attempting to delete a non-variable fails",
124 result: None,
125 },
126 ]
127 }
128}