nu_cmd_plugin/commands/plugin/
rm.rs1use 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 .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}