nushell.github.io icon indicating copy to clipboard operation
nushell.github.io copied to clipboard

contributor-book/plugins

Open jesper-olsen opened this issue 11 months ago • 1 comments

This page is not up to date - I read it recently for the first time and tried to follow the examples: https://www.nushell.sh/contributor-book/plugins.html#creating-a-plugin-in-rust

The examples reference v. 0.90.2 and nushell is now at (0.101.1) - I think there have been a lot of changes to the plugin interface, in particular the streaming interface.

For SimplePluginCommand, it is enough to rename fn usage() to fn description() - then it compiles and seems to work ok. For PluginCommand() it is more complicated.

In section "under the hood" there is this example:

Putting that together, it looks like this:

$ ./target/release/nu_plugin_len --stdio
json{"Hello":{"protocol":"nu-plugin","version":"0.90.2","features":[]}}
{"Hello":{"protocol":"nu-plugin","version":"0.90.2","features":[]}}
{"Call":[0,"Signature"]}
{"CallResponse":[0, {"Signature":[{"sig":{"name":"len","usage":"calculates the length of its input","extra_usage":"","search_terms":[],"required_positional":[],"optional_positional":[],"rest_positional":null,"vectorizes_over_list":false,"named":[{"long":"help","short":"h","arg":null,"required":false,"desc":"Display the help message for this command","var_id":null,"default_value":null}],"input_type":"String","output_type":"Int","input_output_types":[],"allow_variants_without_examples":false,"is_filter":false,"creates_scope":false,"allows_unknown_args":false,"category":"Default"},"examples":[]}]}]}

I does work - with the SimplePluginCommand implementation - but I think it should be re-written using piped input. Input and output in this version are interleaved and it is not possible - at least in my terminal - to interactively input the example; Plugin waits for enter and input terminates after enter.

There is also this example in the section:

$ echo '{"Hello":{"protocol":"nu-plugin","version":"0.90.2","features":[]}}{"Call":[0,{"Run":{"name":"len","call":{"head":{"start":100953,"end":100957},"positional":[],"named":[]},"input":{"Value":{"String":{"val":"hello","span":{"start":100953,"end":100957}}}}}}]}' | target/release/nu_plugin_len --stdio
json{"Hello":{"protocol":"nu-plugin","version":"0.90.2","features":[]}}
{"PipelineData":{"Value":{"Int":{"val":5,"span":{"start":100953,"end":100957}}}}}

It doesn't work as listed any more and in any case, it would be good to have an explanation of where 100953 comes from. I guess 100953 and 100957 are indexes into the input buffer - beginning and end of "hello". But why are the indexes so large? Are they stable over different shell sessions?

jesper-olsen avatar Jan 05 '25 14:01 jesper-olsen

We'd accept a PR for these changes.

It doesn't work as listed any more and in any case, it would be good to have an explanation of where 100953 comes from. I guess 100953 and 100957 are indexes into the input buffer - beginning and end of "hello". But why are the indexes so large?

These are span offsets and the indexes grow as files and repl is read into memory. You can see an example of these with view files

Are they stable over different shell sessions?

I wouldn't rely on it being stable over different sessions. If you change config files or files you source, the offsets will be different. Or if you run a command initially after you start the repl and then 20 commands later, the offsets will be different.

fdncred avatar Jan 05 '25 15:01 fdncred

I went through the example; the simple plugin (first section) worked just fine, with newer version numbers (#1895).

The pipeline plugin has three compilation errors for me:

   Compiling nu_plugin_len v0.1.0 (C:\dev\nushell\nu_plugin_len)
error[E0308]: mismatched types
  --> src\main.rs:63:21
   |
62 |                 match &value {
   |                       ------ this expression has type `&Result<nu_protocol::Value, nu_protocol::ShellError>`
63 |                     Value::String { val, .. } => Ok(
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<Value, ShellError>`, found `Value`
   |
   = note: expected enum `Result<nu_protocol::Value, nu_protocol::ShellError>`
              found enum `nu_protocol::Value`

error[E0599]: no method named `span` found for enum `Result` in the current scope
   --> src\main.rs:64:60
    |
64  |                         Value::int(val.len() as i64, value.span()).into_pipeline_data()
    |                                                            ^^^^
    |
note: the method `span` exists on the type `nu_protocol::Value`
   --> C:\cache\cargo\registry\src\index.crates.io-1949cf8c6b5b557f\nu-protocol-0.103.0\src\value\mod.rs:716:5
    |
716 |     pub fn span(&self) -> Span {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: there is a method `err_span` with a similar name, but with different arguments
   --> C:\cache\cargo\registry\src\index.crates.io-1949cf8c6b5b557f\nu-protocol-0.103.0\src\span.rs:256:5
    |
256 |     fn err_span(self, span: Span) -> Self::Result;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use the `?` operator to extract the `nu_protocol::Value` value, propagating a `Result::Err` value to the caller
    |
64  |                         Value::int(val.len() as i64, value?.span()).into_pipeline_data()
    |                                                           +

error[E0599]: no method named `get_type` found for enum `Result` in the current scope
   --> src\main.rs:72:39
    |
72  | ...                   value.get_type(),
    |                             ^^^^^^^^ method not found in `Result<Value, ShellError>`
    |
note: the method `get_type` exists on the type `nu_protocol::Value`
   --> C:\cache\cargo\registry\src\index.crates.io-1949cf8c6b5b557f\nu-protocol-0.103.0\src\value\mod.rs:768:5
    |
768 |     pub fn get_type(&self) -> Type {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use the `?` operator to extract the `nu_protocol::Value` value, propagating a `Result::Err` value to the caller
    |
72  |                                 value?.get_type(),
    |                                      +

Some errors have detailed explanations: E0308, E0599.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `nu_plugin_len` (bin "nu_plugin_len") due to 3 previous errors
error: failed to compile `nu_plugin_len v0.1.0 (C:\dev\nushell\nu_plugin_len)`, intermediate artifacts can be found at `C:\dev\nushell\nu_plugin_len\target`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

Kissaki avatar Apr 27 '25 23:04 Kissaki