nu_cmd_plugin/commands/plugin/
rm.rs

1use nu_engine::command_prelude::*;
2
3use crate::util::{canonicalize_possible_filename_arg, modify_plugin_file};
4
5#[derive(Clone)]
6pub struct PluginRm;
7
8impl Command for PluginRm {
9    fn name(&self) -> &str {
10        "plugin rm"
11    }
12
13    fn signature(&self) -> Signature {
14        Signature::build(self.name())
15            .input_output_type(Type::Nothing, Type::Nothing)
16            // This matches the option to `nu`
17            .named(
18                "plugin-config",
19                SyntaxShape::Filepath,
20                "Use a plugin registry file other than the one set in `$nu.plugin-path`",
21                None,
22            )
23            .switch(
24                "force",
25                "Don't cause an error if the plugin name wasn't found in the file",
26                Some('f'),
27            )
28            .required(
29                "name",
30                SyntaxShape::String,
31                "The name, or filename, of the plugin to remove.",
32            )
33            .category(Category::Plugin)
34    }
35
36    fn description(&self) -> &str {
37        "Remove a plugin from the plugin registry file."
38    }
39
40    fn extra_description(&self) -> &str {
41        r#"
42This does not remove the plugin commands from the current scope or from `plugin
43list` in the current shell. It instead removes the plugin from the plugin
44registry file (by default, `$nu.plugin-path`). The changes will be apparent the
45next time `nu` is launched with that plugin registry file.
46
47This can be useful for removing an invalid plugin signature, if it can't be
48fixed with `plugin add`.
49"#
50        .trim()
51    }
52
53    fn search_terms(&self) -> Vec<&str> {
54        vec!["remove", "delete", "signature"]
55    }
56
57    fn examples(&self) -> Vec<Example<'_>> {
58        vec![
59            Example {
60                example: "plugin rm inc",
61                description: "Remove the installed signatures for the `inc` plugin.",
62                result: None,
63            },
64            Example {
65                example: "plugin rm ~/.cargo/bin/nu_plugin_inc",
66                description: "Remove the installed signatures for the plugin with the filename `~/.cargo/bin/nu_plugin_inc`.",
67                result: None,
68            },
69            Example {
70                example: "plugin rm --plugin-config polars.msgpackz polars",
71                description: "Remove the installed signatures for the `polars` plugin from the \"polars.msgpackz\" plugin registry file.",
72                result: None,
73            },
74        ]
75    }
76
77    fn run(
78        &self,
79        engine_state: &EngineState,
80        stack: &mut Stack,
81        call: &Call,
82        _input: PipelineData,
83    ) -> Result<PipelineData, ShellError> {
84        let name: Spanned<String> = call.req(engine_state, stack, 0)?;
85        let custom_path = call.get_flag(engine_state, stack, "plugin-config")?;
86        let force = call.has_flag(engine_state, stack, "force")?;
87
88        let filename = canonicalize_possible_filename_arg(engine_state, stack, &name.item);
89
90        modify_plugin_file(engine_state, stack, call.head, &custom_path, |contents| {
91            if let Some(index) = contents
92                .plugins
93                .iter()
94                .position(|p| p.name == name.item || p.filename == filename)
95            {
96                contents.plugins.remove(index);
97                Ok(())
98            } else if force {
99                Ok(())
100            } else {
101                Err(ShellError::GenericError {
102                    error: format!("Failed to remove the `{}` plugin", name.item),
103                    msg: "couldn't find a plugin with this name in the registry file".into(),
104                    span: Some(name.span),
105                    help: None,
106                    inner: vec![],
107                })
108            }
109        })?;
110
111        Ok(Value::nothing(call.head).into_pipeline_data())
112    }
113}