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