mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
Change PluginCommand API to be more like Command (#12279)
# Description
This is something that was discussed in the core team meeting last
Wednesday. @ayax79 is building `nu-plugin-polars` with all of the
dataframe commands into a plugin, and there are a lot of them, so it
would help to make the API more similar. At the same time, I think the
`Command` API is just better anyway. I don't think the difference is
justified, and the types for core commands have the benefit of requiring
less `.into()` because they often don't own their data
- Broke `signature()` up into `name()`, `usage()`, `extra_usage()`,
`search_terms()`, `examples()`
- `signature()` returns `nu_protocol::Signature`
- `examples()` returns `Vec<nu_protocol::Example>`
- `PluginSignature` and `PluginExample` no longer need to be used by
plugin developers
# User-Facing Changes
Breaking API for plugins yet again 😄
This commit is contained in:
parent
03b5e9d853
commit
01d30a416b
@ -1,6 +1,6 @@
|
|||||||
use std::sync::Arc;
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use nu_plugin::{Plugin, PluginDeclaration};
|
use nu_plugin::{create_plugin_signature, Plugin, PluginDeclaration};
|
||||||
use nu_protocol::{engine::StateWorkingSet, RegisteredPlugin, ShellError};
|
use nu_protocol::{engine::StateWorkingSet, RegisteredPlugin, ShellError};
|
||||||
|
|
||||||
use crate::{fake_persistent_plugin::FakePersistentPlugin, spawn_fake_plugin::spawn_fake_plugin};
|
use crate::{fake_persistent_plugin::FakePersistentPlugin, spawn_fake_plugin::spawn_fake_plugin};
|
||||||
@ -15,7 +15,7 @@ pub fn fake_register(
|
|||||||
let reg_plugin_clone = reg_plugin.clone();
|
let reg_plugin_clone = reg_plugin.clone();
|
||||||
|
|
||||||
for command in plugin.commands() {
|
for command in plugin.commands() {
|
||||||
let signature = command.signature();
|
let signature = create_plugin_signature(command.deref());
|
||||||
let decl = PluginDeclaration::new(reg_plugin.clone(), signature);
|
let decl = PluginDeclaration::new(reg_plugin.clone(), signature);
|
||||||
working_set.add_decl(Box::new(decl));
|
working_set.add_decl(Box::new(decl));
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
//!
|
//!
|
||||||
//! use nu_plugin::*;
|
//! use nu_plugin::*;
|
||||||
//! use nu_plugin_test_support::PluginTest;
|
//! use nu_plugin_test_support::PluginTest;
|
||||||
//! use nu_protocol::{PluginSignature, PipelineData, Type, Span, Value, LabeledError};
|
//! use nu_protocol::{
|
||||||
//! use nu_protocol::IntoInterruptiblePipelineData;
|
//! Example, IntoInterruptiblePipelineData, LabeledError, PipelineData, ShellError, Signature,
|
||||||
|
//! Span, Type, Value,
|
||||||
|
//! };
|
||||||
//!
|
//!
|
||||||
//! struct LowercasePlugin;
|
//! struct LowercasePlugin;
|
||||||
//! struct Lowercase;
|
//! struct Lowercase;
|
||||||
@ -16,26 +18,50 @@
|
|||||||
//! impl PluginCommand for Lowercase {
|
//! impl PluginCommand for Lowercase {
|
||||||
//! type Plugin = LowercasePlugin;
|
//! type Plugin = LowercasePlugin;
|
||||||
//!
|
//!
|
||||||
//! fn signature(&self) -> PluginSignature {
|
//! fn name(&self) -> &str {
|
||||||
//! PluginSignature::build("lowercase")
|
//! "lowercase"
|
||||||
//! .usage("Convert each string in a stream to lowercase")
|
//! }
|
||||||
//! .input_output_type(Type::List(Type::String.into()), Type::List(Type::String.into()))
|
//!
|
||||||
|
//! fn usage(&self) -> &str {
|
||||||
|
//! "Convert each string in a stream to lowercase"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn signature(&self) -> Signature {
|
||||||
|
//! Signature::build(self.name()).input_output_type(
|
||||||
|
//! Type::List(Type::String.into()),
|
||||||
|
//! Type::List(Type::String.into()),
|
||||||
|
//! )
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn examples(&self) -> Vec<Example> {
|
||||||
|
//! vec![Example {
|
||||||
|
//! example: r#"[Hello wORLD] | lowercase"#,
|
||||||
|
//! description: "Lowercase a list of strings",
|
||||||
|
//! result: Some(Value::test_list(vec![
|
||||||
|
//! Value::test_string("hello"),
|
||||||
|
//! Value::test_string("world"),
|
||||||
|
//! ])),
|
||||||
|
//! }]
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn run(
|
//! fn run(
|
||||||
//! &self,
|
//! &self,
|
||||||
//! plugin: &LowercasePlugin,
|
//! _plugin: &LowercasePlugin,
|
||||||
//! engine: &EngineInterface,
|
//! _engine: &EngineInterface,
|
||||||
//! call: &EvaluatedCall,
|
//! call: &EvaluatedCall,
|
||||||
//! input: PipelineData,
|
//! input: PipelineData,
|
||||||
//! ) -> Result<PipelineData, LabeledError> {
|
//! ) -> Result<PipelineData, LabeledError> {
|
||||||
//! let span = call.head;
|
//! let span = call.head;
|
||||||
//! Ok(input.map(move |value| {
|
//! Ok(input.map(
|
||||||
//! value.as_str()
|
//! move |value| {
|
||||||
//! .map(|string| Value::string(string.to_lowercase(), span))
|
//! value
|
||||||
//! // Errors in a stream should be returned as values.
|
//! .as_str()
|
||||||
//! .unwrap_or_else(|err| Value::error(err, span))
|
//! .map(|string| Value::string(string.to_lowercase(), span))
|
||||||
//! }, None)?)
|
//! // Errors in a stream should be returned as values.
|
||||||
|
//! .unwrap_or_else(|err| Value::error(err, span))
|
||||||
|
//! },
|
||||||
|
//! None,
|
||||||
|
//! )?)
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
@ -45,7 +71,14 @@
|
|||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn test_lowercase() -> Result<(), LabeledError> {
|
//! // #[test]
|
||||||
|
//! fn test_examples() -> Result<(), ShellError> {
|
||||||
|
//! PluginTest::new("lowercase", LowercasePlugin.into())?
|
||||||
|
//! .test_command_examples(&Lowercase)
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // #[test]
|
||||||
|
//! fn test_lowercase() -> Result<(), ShellError> {
|
||||||
//! let input = vec![Value::test_string("FooBar")].into_pipeline_data(None);
|
//! let input = vec![Value::test_string("FooBar")].into_pipeline_data(None);
|
||||||
//! let output = PluginTest::new("lowercase", LowercasePlugin.into())?
|
//! let output = PluginTest::new("lowercase", LowercasePlugin.into())?
|
||||||
//! .eval_with("lowercase", input)?
|
//! .eval_with("lowercase", input)?
|
||||||
@ -60,6 +93,7 @@
|
|||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! #
|
//! #
|
||||||
|
//! # test_examples().unwrap();
|
||||||
//! # test_lowercase().unwrap();
|
//! # test_lowercase().unwrap();
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use nu_plugin::{Plugin, PluginCommand, PluginCustomValue, PluginSource};
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
debugger::WithoutDebug,
|
debugger::WithoutDebug,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
report_error_new, LabeledError, PipelineData, PluginExample, ShellError, Span, Value,
|
report_error_new, Example, LabeledError, PipelineData, ShellError, Span, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{diff::diff_by_line, fake_register::fake_register};
|
use crate::{diff::diff_by_line, fake_register::fake_register};
|
||||||
@ -186,20 +186,20 @@ impl PluginTest {
|
|||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use nu_plugin_test_support::PluginTest;
|
/// # use nu_plugin_test_support::PluginTest;
|
||||||
/// # use nu_protocol::{ShellError, PluginExample, Value};
|
/// # use nu_protocol::{ShellError, Example, Value};
|
||||||
/// # use nu_plugin::*;
|
/// # use nu_plugin::*;
|
||||||
/// # fn test(MyPlugin: impl Plugin + Send + 'static) -> Result<(), ShellError> {
|
/// # fn test(MyPlugin: impl Plugin + Send + 'static) -> Result<(), ShellError> {
|
||||||
/// PluginTest::new("my_plugin", MyPlugin.into())?
|
/// PluginTest::new("my_plugin", MyPlugin.into())?
|
||||||
/// .test_examples(&[
|
/// .test_examples(&[
|
||||||
/// PluginExample {
|
/// Example {
|
||||||
/// example: "my-command".into(),
|
/// example: "my-command",
|
||||||
/// description: "Run my-command".into(),
|
/// description: "Run my-command",
|
||||||
/// result: Some(Value::test_string("my-command output")),
|
/// result: Some(Value::test_string("my-command output")),
|
||||||
/// },
|
/// },
|
||||||
/// ])
|
/// ])
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn test_examples(&mut self, examples: &[PluginExample]) -> Result<(), ShellError> {
|
pub fn test_examples(&mut self, examples: &[Example]) -> Result<(), ShellError> {
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
|
|
||||||
for example in examples {
|
for example in examples {
|
||||||
@ -210,7 +210,7 @@ impl PluginTest {
|
|||||||
eprintln!("{} {}", bold.paint("Description:"), example.description);
|
eprintln!("{} {}", bold.paint("Description:"), example.description);
|
||||||
};
|
};
|
||||||
if let Some(expectation) = &example.result {
|
if let Some(expectation) = &example.result {
|
||||||
match self.eval(&example.example) {
|
match self.eval(example.example) {
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
let mut value = data.into_value(Span::test_data());
|
let mut value = data.into_value(Span::test_data());
|
||||||
|
|
||||||
@ -270,6 +270,6 @@ impl PluginTest {
|
|||||||
&mut self,
|
&mut self,
|
||||||
command: &impl PluginCommand,
|
command: &impl PluginCommand,
|
||||||
) -> Result<(), ShellError> {
|
) -> Result<(), ShellError> {
|
||||||
self.test_examples(&command.signature().examples)
|
self.test_examples(&command.examples())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,7 @@ use std::cmp::Ordering;
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, SimplePluginCommand};
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
CustomValue, LabeledError, PipelineData, PluginExample, PluginSignature, ShellError, Span,
|
CustomValue, Example, LabeledError, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
Type, Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -58,14 +57,24 @@ impl Plugin for CustomU32Plugin {
|
|||||||
impl SimplePluginCommand for IntoU32 {
|
impl SimplePluginCommand for IntoU32 {
|
||||||
type Plugin = CustomU32Plugin;
|
type Plugin = CustomU32Plugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("into u32")
|
"into u32"
|
||||||
.input_output_type(Type::Int, Type::Custom("CustomU32".into()))
|
}
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "340 | into u32".into(),
|
fn usage(&self) -> &str {
|
||||||
description: "Make a u32".into(),
|
"Convert a number to a 32-bit unsigned integer"
|
||||||
result: Some(CustomU32(340).into_value(Span::test_data())),
|
}
|
||||||
}])
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name()).input_output_type(Type::Int, Type::Custom("CustomU32".into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "340 | into u32",
|
||||||
|
description: "Make a u32",
|
||||||
|
result: Some(CustomU32(340).into_value(Span::test_data())),
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -87,9 +96,16 @@ impl SimplePluginCommand for IntoU32 {
|
|||||||
impl SimplePluginCommand for IntoIntFromU32 {
|
impl SimplePluginCommand for IntoIntFromU32 {
|
||||||
type Plugin = CustomU32Plugin;
|
type Plugin = CustomU32Plugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("into int from u32")
|
"into int from u32"
|
||||||
.input_output_type(Type::Custom("CustomU32".into()), Type::Int)
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Turn a u32 back into a number"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name()).input_output_type(Type::Custom("CustomU32".into()), Type::Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use nu_plugin::*;
|
use nu_plugin::*;
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
use nu_protocol::{LabeledError, PluginExample, PluginSignature, ShellError, Type, Value};
|
use nu_protocol::{Example, LabeledError, ShellError, Signature, Type, Value};
|
||||||
|
|
||||||
struct HelloPlugin;
|
struct HelloPlugin;
|
||||||
struct Hello;
|
struct Hello;
|
||||||
@ -16,14 +16,24 @@ impl Plugin for HelloPlugin {
|
|||||||
impl SimplePluginCommand for Hello {
|
impl SimplePluginCommand for Hello {
|
||||||
type Plugin = HelloPlugin;
|
type Plugin = HelloPlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("hello")
|
"hello"
|
||||||
.input_output_type(Type::Nothing, Type::String)
|
}
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "hello".into(),
|
fn usage(&self) -> &str {
|
||||||
description: "Print a friendly greeting".into(),
|
"Print a friendly greeting"
|
||||||
result: Some(Value::test_string("Hello, World!")),
|
}
|
||||||
}])
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(PluginCommand::name(self)).input_output_type(Type::Nothing, Type::String)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "hello",
|
||||||
|
description: "Print a friendly greeting",
|
||||||
|
result: Some(Value::test_string("Hello, World!")),
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -44,9 +54,9 @@ fn test_specified_examples() -> Result<(), ShellError> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_an_error_causing_example() -> Result<(), ShellError> {
|
fn test_an_error_causing_example() -> Result<(), ShellError> {
|
||||||
let result = PluginTest::new("hello", HelloPlugin.into())?.test_examples(&[PluginExample {
|
let result = PluginTest::new("hello", HelloPlugin.into())?.test_examples(&[Example {
|
||||||
example: "hello --unknown-flag".into(),
|
example: "hello --unknown-flag",
|
||||||
description: "Run hello with an unknown flag".into(),
|
description: "Run hello with an unknown flag",
|
||||||
result: Some(Value::test_string("Hello, World!")),
|
result: Some(Value::test_string("Hello, World!")),
|
||||||
}]);
|
}]);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
@ -55,9 +65,9 @@ fn test_an_error_causing_example() -> Result<(), ShellError> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_an_example_with_the_wrong_result() -> Result<(), ShellError> {
|
fn test_an_example_with_the_wrong_result() -> Result<(), ShellError> {
|
||||||
let result = PluginTest::new("hello", HelloPlugin.into())?.test_examples(&[PluginExample {
|
let result = PluginTest::new("hello", HelloPlugin.into())?.test_examples(&[Example {
|
||||||
example: "hello".into(),
|
example: "hello",
|
||||||
description: "Run hello but the example result is wrong".into(),
|
description: "Run hello but the example result is wrong",
|
||||||
result: Some(Value::test_string("Goodbye, World!")),
|
result: Some(Value::test_string("Goodbye, World!")),
|
||||||
}]);
|
}]);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use nu_plugin::*;
|
use nu_plugin::*;
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
IntoInterruptiblePipelineData, LabeledError, PipelineData, PluginExample, PluginSignature,
|
Example, IntoInterruptiblePipelineData, LabeledError, PipelineData, ShellError, Signature,
|
||||||
ShellError, Span, Type, Value,
|
Span, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LowercasePlugin;
|
struct LowercasePlugin;
|
||||||
@ -11,21 +11,30 @@ struct Lowercase;
|
|||||||
impl PluginCommand for Lowercase {
|
impl PluginCommand for Lowercase {
|
||||||
type Plugin = LowercasePlugin;
|
type Plugin = LowercasePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("lowercase")
|
"lowercase"
|
||||||
.usage("Convert each string in a stream to lowercase")
|
}
|
||||||
.input_output_type(
|
|
||||||
Type::List(Type::String.into()),
|
fn usage(&self) -> &str {
|
||||||
Type::List(Type::String.into()),
|
"Convert each string in a stream to lowercase"
|
||||||
)
|
}
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: r#"[Hello wORLD] | lowercase"#.into(),
|
fn signature(&self) -> Signature {
|
||||||
description: "Lowercase a list of strings".into(),
|
Signature::build(self.name()).input_output_type(
|
||||||
result: Some(Value::test_list(vec![
|
Type::List(Type::String.into()),
|
||||||
Value::test_string("hello"),
|
Type::List(Type::String.into()),
|
||||||
Value::test_string("world"),
|
)
|
||||||
])),
|
}
|
||||||
}])
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: r#"[Hello wORLD] | lowercase"#,
|
||||||
|
description: "Lowercase a list of strings",
|
||||||
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_string("hello"),
|
||||||
|
Value::test_string("world"),
|
||||||
|
])),
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! use nu_plugin::{EvaluatedCall, MsgPackSerializer, serve_plugin};
|
//! use nu_plugin::{EvaluatedCall, MsgPackSerializer, serve_plugin};
|
||||||
//! use nu_plugin::{Plugin, PluginCommand, SimplePluginCommand, EngineInterface};
|
//! use nu_plugin::{EngineInterface, Plugin, PluginCommand, SimplePluginCommand};
|
||||||
//! use nu_protocol::{PluginSignature, LabeledError, Value};
|
//! use nu_protocol::{LabeledError, Signature, Value};
|
||||||
//!
|
//!
|
||||||
//! struct MyPlugin;
|
//! struct MyPlugin;
|
||||||
//! struct MyCommand;
|
//! struct MyCommand;
|
||||||
@ -32,7 +32,15 @@
|
|||||||
//! impl SimplePluginCommand for MyCommand {
|
//! impl SimplePluginCommand for MyCommand {
|
||||||
//! type Plugin = MyPlugin;
|
//! type Plugin = MyPlugin;
|
||||||
//!
|
//!
|
||||||
//! fn signature(&self) -> PluginSignature {
|
//! fn name(&self) -> &str {
|
||||||
|
//! "my-command"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn usage(&self) -> &str {
|
||||||
|
//! todo!();
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn signature(&self) -> Signature {
|
||||||
//! todo!();
|
//! todo!();
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
@ -71,9 +79,10 @@ pub use serializers::{json::JsonSerializer, msgpack::MsgPackSerializer};
|
|||||||
// Used by other nu crates.
|
// Used by other nu crates.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use plugin::{
|
pub use plugin::{
|
||||||
get_signature, serve_plugin_io, EngineInterfaceManager, GetPlugin, Interface, InterfaceManager,
|
create_plugin_signature, get_signature, serve_plugin_io, EngineInterfaceManager, GetPlugin,
|
||||||
PersistentPlugin, PluginDeclaration, PluginExecutionCommandContext, PluginExecutionContext,
|
Interface, InterfaceManager, PersistentPlugin, PluginDeclaration,
|
||||||
PluginInterface, PluginInterfaceManager, PluginSource, ServePluginError,
|
PluginExecutionCommandContext, PluginExecutionContext, PluginInterface, PluginInterfaceManager,
|
||||||
|
PluginSource, ServePluginError,
|
||||||
};
|
};
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use protocol::{PluginCustomValue, PluginInput, PluginOutput};
|
pub use protocol::{PluginCustomValue, PluginInput, PluginOutput};
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use nu_protocol::{LabeledError, PipelineData, PluginSignature, Value};
|
use nu_protocol::{
|
||||||
|
Example, LabeledError, PipelineData, PluginExample, PluginSignature, Signature, Value,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{EngineInterface, EvaluatedCall, Plugin};
|
use crate::{EngineInterface, EvaluatedCall, Plugin};
|
||||||
|
|
||||||
@ -19,16 +21,23 @@ use crate::{EngineInterface, EvaluatedCall, Plugin};
|
|||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use nu_plugin::*;
|
/// # use nu_plugin::*;
|
||||||
/// # use nu_protocol::{PluginSignature, PipelineData, Type, Value, LabeledError};
|
/// # use nu_protocol::{Signature, PipelineData, Type, Value, LabeledError};
|
||||||
/// struct LowercasePlugin;
|
/// struct LowercasePlugin;
|
||||||
/// struct Lowercase;
|
/// struct Lowercase;
|
||||||
///
|
///
|
||||||
/// impl PluginCommand for Lowercase {
|
/// impl PluginCommand for Lowercase {
|
||||||
/// type Plugin = LowercasePlugin;
|
/// type Plugin = LowercasePlugin;
|
||||||
///
|
///
|
||||||
/// fn signature(&self) -> PluginSignature {
|
/// fn name(&self) -> &str {
|
||||||
/// PluginSignature::build("lowercase")
|
/// "lowercase"
|
||||||
/// .usage("Convert each string in a stream to lowercase")
|
/// }
|
||||||
|
///
|
||||||
|
/// fn usage(&self) -> &str {
|
||||||
|
/// "Convert each string in a stream to lowercase"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn signature(&self) -> Signature {
|
||||||
|
/// Signature::build(PluginCommand::name(self))
|
||||||
/// .input_output_type(Type::List(Type::String.into()), Type::List(Type::String.into()))
|
/// .input_output_type(Type::List(Type::String.into()), Type::List(Type::String.into()))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -60,18 +69,62 @@ use crate::{EngineInterface, EvaluatedCall, Plugin};
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub trait PluginCommand: Sync {
|
pub trait PluginCommand: Sync {
|
||||||
/// The type of plugin this command runs on
|
/// The type of plugin this command runs on.
|
||||||
///
|
///
|
||||||
/// Since [`.run()`] takes a reference to the plugin, it is necessary to define the type of
|
/// Since [`.run()`] takes a reference to the plugin, it is necessary to define the type of
|
||||||
/// plugin that the command expects here.
|
/// plugin that the command expects here.
|
||||||
type Plugin: Plugin;
|
type Plugin: Plugin;
|
||||||
|
|
||||||
/// The signature of the plugin command
|
/// The name of the command from within Nu.
|
||||||
///
|
///
|
||||||
/// These are aggregated from the [`Plugin`] and sent to the engine on `register`.
|
/// In case this contains spaces, it will be treated as a subcommand.
|
||||||
fn signature(&self) -> PluginSignature;
|
fn name(&self) -> &str;
|
||||||
|
|
||||||
/// Perform the actual behavior of the plugin command
|
/// The signature of the command.
|
||||||
|
///
|
||||||
|
/// This defines the arguments and input/output types of the command.
|
||||||
|
fn signature(&self) -> Signature;
|
||||||
|
|
||||||
|
/// A brief description of usage for the command.
|
||||||
|
///
|
||||||
|
/// This should be short enough to fit in completion menus.
|
||||||
|
fn usage(&self) -> &str;
|
||||||
|
|
||||||
|
/// Additional documentation for usage of the command.
|
||||||
|
///
|
||||||
|
/// This is optional - any arguments documented by [`.signature()`] will be shown in the help
|
||||||
|
/// page automatically. However, this can be useful for explaining things that would be too
|
||||||
|
/// brief to include in [`.usage()`] and may span multiple lines.
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Search terms to help users find the command.
|
||||||
|
///
|
||||||
|
/// A search query matching any of these search keywords, e.g. on `help --find`, will also
|
||||||
|
/// show this command as a result. This may be used to suggest this command as a replacement
|
||||||
|
/// for common system commands, or based alternate names for the functionality this command
|
||||||
|
/// provides.
|
||||||
|
///
|
||||||
|
/// For example, a `fold` command might mention `reduce` in its search terms.
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Examples, in Nu, of how the command might be used.
|
||||||
|
///
|
||||||
|
/// The examples are not restricted to only including this command, and may demonstrate
|
||||||
|
/// pipelines using the command. A `result` may optionally be provided to show users what the
|
||||||
|
/// command would return.
|
||||||
|
///
|
||||||
|
/// `PluginTest::test_command_examples()` from the
|
||||||
|
/// [`nu-plugin-test-support`](https://docs.rs/nu-plugin-test-support) crate can be used in
|
||||||
|
/// plugin tests to automatically test that examples produce the `result`s as specified.
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform the actual behavior of the plugin command.
|
||||||
///
|
///
|
||||||
/// The behavior of the plugin is defined by the implementation of this method. When Nushell
|
/// The behavior of the plugin is defined by the implementation of this method. When Nushell
|
||||||
/// invoked the plugin [`serve_plugin`](crate::serve_plugin) will call this method and print the
|
/// invoked the plugin [`serve_plugin`](crate::serve_plugin) will call this method and print the
|
||||||
@ -109,15 +162,23 @@ pub trait PluginCommand: Sync {
|
|||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use nu_plugin::*;
|
/// # use nu_plugin::*;
|
||||||
/// # use nu_protocol::{PluginSignature, Type, Value, LabeledError};
|
/// # use nu_protocol::{LabeledError, Signature, Type, Value};
|
||||||
/// struct HelloPlugin;
|
/// struct HelloPlugin;
|
||||||
/// struct Hello;
|
/// struct Hello;
|
||||||
///
|
///
|
||||||
/// impl SimplePluginCommand for Hello {
|
/// impl SimplePluginCommand for Hello {
|
||||||
/// type Plugin = HelloPlugin;
|
/// type Plugin = HelloPlugin;
|
||||||
///
|
///
|
||||||
/// fn signature(&self) -> PluginSignature {
|
/// fn name(&self) -> &str {
|
||||||
/// PluginSignature::build("hello")
|
/// "hello"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn usage(&self) -> &str {
|
||||||
|
/// "Every programmer's favorite greeting"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn signature(&self) -> Signature {
|
||||||
|
/// Signature::build(PluginCommand::name(self))
|
||||||
/// .input_output_type(Type::Nothing, Type::String)
|
/// .input_output_type(Type::Nothing, Type::String)
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -143,18 +204,62 @@ pub trait PluginCommand: Sync {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub trait SimplePluginCommand: Sync {
|
pub trait SimplePluginCommand: Sync {
|
||||||
/// The type of plugin this command runs on
|
/// The type of plugin this command runs on.
|
||||||
///
|
///
|
||||||
/// Since [`.run()`] takes a reference to the plugin, it is necessary to define the type of
|
/// Since [`.run()`] takes a reference to the plugin, it is necessary to define the type of
|
||||||
/// plugin that the command expects here.
|
/// plugin that the command expects here.
|
||||||
type Plugin: Plugin;
|
type Plugin: Plugin;
|
||||||
|
|
||||||
/// The signature of the plugin command
|
/// The name of the command from within Nu.
|
||||||
///
|
///
|
||||||
/// These are aggregated from the [`Plugin`] and sent to the engine on `register`.
|
/// In case this contains spaces, it will be treated as a subcommand.
|
||||||
fn signature(&self) -> PluginSignature;
|
fn name(&self) -> &str;
|
||||||
|
|
||||||
/// Perform the actual behavior of the plugin command
|
/// The signature of the command.
|
||||||
|
///
|
||||||
|
/// This defines the arguments and input/output types of the command.
|
||||||
|
fn signature(&self) -> Signature;
|
||||||
|
|
||||||
|
/// A brief description of usage for the command.
|
||||||
|
///
|
||||||
|
/// This should be short enough to fit in completion menus.
|
||||||
|
fn usage(&self) -> &str;
|
||||||
|
|
||||||
|
/// Additional documentation for usage of the command.
|
||||||
|
///
|
||||||
|
/// This is optional - any arguments documented by [`.signature()`] will be shown in the help
|
||||||
|
/// page automatically. However, this can be useful for explaining things that would be too
|
||||||
|
/// brief to include in [`.usage()`] and may span multiple lines.
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Search terms to help users find the command.
|
||||||
|
///
|
||||||
|
/// A search query matching any of these search keywords, e.g. on `help --find`, will also
|
||||||
|
/// show this command as a result. This may be used to suggest this command as a replacement
|
||||||
|
/// for common system commands, or based alternate names for the functionality this command
|
||||||
|
/// provides.
|
||||||
|
///
|
||||||
|
/// For example, a `fold` command might mention `reduce` in its search terms.
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Examples, in Nu, of how the command might be used.
|
||||||
|
///
|
||||||
|
/// The examples are not restricted to only including this command, and may demonstrate
|
||||||
|
/// pipelines using the command. A `result` may optionally be provided to show users what the
|
||||||
|
/// command would return.
|
||||||
|
///
|
||||||
|
/// `PluginTest::test_command_examples()` from the
|
||||||
|
/// [`nu-plugin-test-support`](https://docs.rs/nu-plugin-test-support) crate can be used in
|
||||||
|
/// plugin tests to automatically test that examples produce the `result`s as specified.
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform the actual behavior of the plugin command.
|
||||||
///
|
///
|
||||||
/// The behavior of the plugin is defined by the implementation of this method. When Nushell
|
/// The behavior of the plugin is defined by the implementation of this method. When Nushell
|
||||||
/// invoked the plugin [`serve_plugin`](crate::serve_plugin) will call this method and print the
|
/// invoked the plugin [`serve_plugin`](crate::serve_plugin) will call this method and print the
|
||||||
@ -185,8 +290,16 @@ where
|
|||||||
{
|
{
|
||||||
type Plugin = <Self as SimplePluginCommand>::Plugin;
|
type Plugin = <Self as SimplePluginCommand>::Plugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn examples(&self) -> Vec<Example> {
|
||||||
<Self as SimplePluginCommand>::signature(self)
|
<Self as SimplePluginCommand>::examples(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
<Self as SimplePluginCommand>::extra_usage(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
<Self as SimplePluginCommand>::name(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -204,4 +317,45 @@ where
|
|||||||
<Self as SimplePluginCommand>::run(self, plugin, engine, call, &input_value)
|
<Self as SimplePluginCommand>::run(self, plugin, engine, call, &input_value)
|
||||||
.map(|value| PipelineData::Value(value, None))
|
.map(|value| PipelineData::Value(value, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
<Self as SimplePluginCommand>::search_terms(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
<Self as SimplePluginCommand>::signature(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
<Self as SimplePluginCommand>::usage(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a [`PluginSignature`] from the signature-related methods on [`PluginCommand`].
|
||||||
|
///
|
||||||
|
/// This is sent to the engine on `register`.
|
||||||
|
///
|
||||||
|
/// This is not a public API.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn create_plugin_signature(command: &(impl PluginCommand + ?Sized)) -> PluginSignature {
|
||||||
|
PluginSignature::new(
|
||||||
|
// Add results of trait methods to signature
|
||||||
|
command
|
||||||
|
.signature()
|
||||||
|
.usage(command.usage())
|
||||||
|
.extra_usage(command.extra_usage())
|
||||||
|
.search_terms(
|
||||||
|
command
|
||||||
|
.search_terms()
|
||||||
|
.into_iter()
|
||||||
|
.map(String::from)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
// Convert `Example`s to `PluginExample`s
|
||||||
|
command
|
||||||
|
.examples()
|
||||||
|
.into_iter()
|
||||||
|
.map(PluginExample::from)
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::Closure, Config, CustomValue, IntoInterruptiblePipelineData, LabeledError,
|
engine::Closure, Config, CustomValue, IntoInterruptiblePipelineData, LabeledError,
|
||||||
PipelineData, PluginExample, PluginSignature, ShellError, Span, Spanned, Value,
|
PipelineData, PluginExample, PluginSignature, ShellError, Signature, Span, Spanned, Value,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -786,15 +786,16 @@ fn interface_write_signature() -> Result<(), ShellError> {
|
|||||||
fn interface_write_signature_custom_value() -> Result<(), ShellError> {
|
fn interface_write_signature_custom_value() -> Result<(), ShellError> {
|
||||||
let test = TestCase::new();
|
let test = TestCase::new();
|
||||||
let interface = test.engine().interface_for_context(38);
|
let interface = test.engine().interface_for_context(38);
|
||||||
let signatures = vec![PluginSignature::build("test command").plugin_examples(vec![
|
let signatures = vec![PluginSignature::new(
|
||||||
PluginExample {
|
Signature::build("test command"),
|
||||||
|
vec![PluginExample {
|
||||||
example: "test command".into(),
|
example: "test command".into(),
|
||||||
description: "a test".into(),
|
description: "a test".into(),
|
||||||
result: Some(Value::test_custom_value(Box::new(
|
result: Some(Value::test_custom_value(Box::new(
|
||||||
expected_test_custom_value(),
|
expected_test_custom_value(),
|
||||||
))),
|
))),
|
||||||
},
|
}],
|
||||||
])];
|
)];
|
||||||
interface.write_signature(signatures.clone())?;
|
interface.write_signature(signatures.clone())?;
|
||||||
|
|
||||||
let written = test.next_written().expect("nothing written");
|
let written = test.next_written().expect("nothing written");
|
||||||
|
@ -3,15 +3,7 @@ use crate::{
|
|||||||
protocol::{CallInfo, CustomValueOp, PluginCustomValue, PluginInput, PluginOutput},
|
protocol::{CallInfo, CustomValueOp, PluginCustomValue, PluginInput, PluginOutput},
|
||||||
EncodingType,
|
EncodingType,
|
||||||
};
|
};
|
||||||
use nu_engine::documentation::get_flags_section;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Operator, CustomValue, IntoSpanned, LabeledError, PipelineData, PluginSignature,
|
|
||||||
ShellError, Spanned, Value,
|
|
||||||
};
|
|
||||||
#[cfg(unix)]
|
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
#[cfg(windows)]
|
|
||||||
use std::os::windows::process::CommandExt;
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -19,14 +11,28 @@ use std::{
|
|||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
io::{BufReader, Read, Write as WriteTrait},
|
io::{BufReader, Read, Write as WriteTrait},
|
||||||
|
ops::Deref,
|
||||||
path::Path,
|
path::Path,
|
||||||
process::{Child, ChildStdout, Command as CommandSys, Stdio},
|
process::{Child, ChildStdout, Command as CommandSys, Stdio},
|
||||||
sync::mpsc::TrySendError,
|
sync::{
|
||||||
sync::{mpsc, Arc, Mutex},
|
mpsc::{self, TrySendError},
|
||||||
|
Arc, Mutex,
|
||||||
|
},
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use nu_engine::documentation::get_flags_section;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Operator, CustomValue, IntoSpanned, LabeledError, PipelineData, PluginSignature,
|
||||||
|
ShellError, Spanned, Value,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::process::CommandExt;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
use self::gc::PluginGc;
|
use self::gc::PluginGc;
|
||||||
pub use self::interface::{PluginRead, PluginWrite};
|
pub use self::interface::{PluginRead, PluginWrite};
|
||||||
|
|
||||||
@ -38,7 +44,7 @@ mod interface;
|
|||||||
mod persistent;
|
mod persistent;
|
||||||
mod source;
|
mod source;
|
||||||
|
|
||||||
pub use command::{PluginCommand, SimplePluginCommand};
|
pub use command::{create_plugin_signature, PluginCommand, SimplePluginCommand};
|
||||||
pub use declaration::PluginDeclaration;
|
pub use declaration::PluginDeclaration;
|
||||||
pub use interface::{
|
pub use interface::{
|
||||||
EngineInterface, EngineInterfaceManager, Interface, InterfaceManager, PluginInterface,
|
EngineInterface, EngineInterfaceManager, Interface, InterfaceManager, PluginInterface,
|
||||||
@ -229,7 +235,7 @@ where
|
|||||||
/// Basic usage:
|
/// Basic usage:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use nu_plugin::*;
|
/// # use nu_plugin::*;
|
||||||
/// # use nu_protocol::{PluginSignature, LabeledError, Type, Value};
|
/// # use nu_protocol::{LabeledError, Signature, Type, Value};
|
||||||
/// struct HelloPlugin;
|
/// struct HelloPlugin;
|
||||||
/// struct Hello;
|
/// struct Hello;
|
||||||
///
|
///
|
||||||
@ -242,8 +248,16 @@ where
|
|||||||
/// impl SimplePluginCommand for Hello {
|
/// impl SimplePluginCommand for Hello {
|
||||||
/// type Plugin = HelloPlugin;
|
/// type Plugin = HelloPlugin;
|
||||||
///
|
///
|
||||||
/// fn signature(&self) -> PluginSignature {
|
/// fn name(&self) -> &str {
|
||||||
/// PluginSignature::build("hello")
|
/// "hello"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn usage(&self) -> &str {
|
||||||
|
/// "Every programmer's favorite greeting"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn signature(&self) -> Signature {
|
||||||
|
/// Signature::build(PluginCommand::name(self))
|
||||||
/// .input_output_type(Type::Nothing, Type::String)
|
/// .input_output_type(Type::Nothing, Type::String)
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
@ -556,11 +570,11 @@ where
|
|||||||
let mut commands: HashMap<String, _> = HashMap::new();
|
let mut commands: HashMap<String, _> = HashMap::new();
|
||||||
|
|
||||||
for command in plugin.commands() {
|
for command in plugin.commands() {
|
||||||
if let Some(previous) = commands.insert(command.signature().sig.name.clone(), command) {
|
if let Some(previous) = commands.insert(command.name().into(), command) {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Plugin `{plugin_name}` warning: command `{}` shadowed by another command with the \
|
"Plugin `{plugin_name}` warning: command `{}` shadowed by another command with the \
|
||||||
same name. Check your command signatures",
|
same name. Check your commands' `name()` methods",
|
||||||
previous.signature().sig.name
|
previous.name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -636,7 +650,7 @@ where
|
|||||||
ReceivedPluginCall::Signature { engine } => {
|
ReceivedPluginCall::Signature { engine } => {
|
||||||
let sigs = commands
|
let sigs = commands
|
||||||
.values()
|
.values()
|
||||||
.map(|command| command.signature())
|
.map(|command| create_plugin_signature(command.deref()))
|
||||||
.collect();
|
.collect();
|
||||||
engine.write_signature(sigs).try_to_report(&engine)?;
|
engine.write_signature(sigs).try_to_report(&engine)?;
|
||||||
}
|
}
|
||||||
@ -752,23 +766,22 @@ fn print_help(plugin: &impl Plugin, encoder: impl PluginEncoder) {
|
|||||||
|
|
||||||
plugin.commands().into_iter().for_each(|command| {
|
plugin.commands().into_iter().for_each(|command| {
|
||||||
let signature = command.signature();
|
let signature = command.signature();
|
||||||
let res = write!(help, "\nCommand: {}", signature.sig.name)
|
let res = write!(help, "\nCommand: {}", command.name())
|
||||||
.and_then(|_| writeln!(help, "\nUsage:\n > {}", signature.sig.usage))
|
.and_then(|_| writeln!(help, "\nUsage:\n > {}", command.usage()))
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
if !signature.sig.extra_usage.is_empty() {
|
if !command.extra_usage().is_empty() {
|
||||||
writeln!(help, "\nExtra usage:\n > {}", signature.sig.extra_usage)
|
writeln!(help, "\nExtra usage:\n > {}", command.extra_usage())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
let flags = get_flags_section(None, &signature.sig, |v| format!("{:#?}", v));
|
let flags = get_flags_section(None, &signature, |v| format!("{:#?}", v));
|
||||||
write!(help, "{flags}")
|
write!(help, "{flags}")
|
||||||
})
|
})
|
||||||
.and_then(|_| writeln!(help, "\nParameters:"))
|
.and_then(|_| writeln!(help, "\nParameters:"))
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
signature
|
signature
|
||||||
.sig
|
|
||||||
.required_positional
|
.required_positional
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|positional| {
|
.try_for_each(|positional| {
|
||||||
@ -781,7 +794,6 @@ fn print_help(plugin: &impl Plugin, encoder: impl PluginEncoder) {
|
|||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
signature
|
signature
|
||||||
.sig
|
|
||||||
.optional_positional
|
.optional_positional
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|positional| {
|
.try_for_each(|positional| {
|
||||||
@ -793,7 +805,7 @@ fn print_help(plugin: &impl Plugin, encoder: impl PluginEncoder) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
if let Some(rest_positional) = &signature.sig.rest_positional {
|
if let Some(rest_positional) = &signature.rest_positional {
|
||||||
writeln!(
|
writeln!(
|
||||||
help,
|
help,
|
||||||
" ...{} <{}>: {}",
|
" ...{} <{}>: {}",
|
||||||
|
@ -5,7 +5,9 @@ macro_rules! generate_tests {
|
|||||||
PluginCallResponse, PluginCustomValue, PluginInput, PluginOption, PluginOutput,
|
PluginCallResponse, PluginCustomValue, PluginInput, PluginOption, PluginOutput,
|
||||||
StreamData, StreamMessage,
|
StreamData, StreamMessage,
|
||||||
};
|
};
|
||||||
use nu_protocol::{LabeledError, PluginSignature, Span, Spanned, SyntaxShape, Value};
|
use nu_protocol::{
|
||||||
|
LabeledError, PluginSignature, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decode_eof() {
|
fn decode_eof() {
|
||||||
@ -211,17 +213,20 @@ macro_rules! generate_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn response_round_trip_signature() {
|
fn response_round_trip_signature() {
|
||||||
let signature = PluginSignature::build("nu-plugin")
|
let signature = PluginSignature::new(
|
||||||
.required("first", SyntaxShape::String, "first required")
|
Signature::build("nu-plugin")
|
||||||
.required("second", SyntaxShape::Int, "second required")
|
.required("first", SyntaxShape::String, "first required")
|
||||||
.required_named("first-named", SyntaxShape::String, "first named", Some('f'))
|
.required("second", SyntaxShape::Int, "second required")
|
||||||
.required_named(
|
.required_named("first-named", SyntaxShape::String, "first named", Some('f'))
|
||||||
"second-named",
|
.required_named(
|
||||||
SyntaxShape::String,
|
"second-named",
|
||||||
"second named",
|
SyntaxShape::String,
|
||||||
Some('s'),
|
"second named",
|
||||||
)
|
Some('s'),
|
||||||
.rest("remaining", SyntaxShape::Int, "remaining");
|
)
|
||||||
|
.rest("remaining", SyntaxShape::Int, "remaining"),
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
|
||||||
let response = PluginCallResponse::Signature(vec![signature.clone()]);
|
let response = PluginCallResponse::Signature(vec![signature.clone()]);
|
||||||
let output = PluginOutput::CallResponse(3, response);
|
let output = PluginOutput::CallResponse(3, response);
|
||||||
|
@ -530,11 +530,7 @@ impl EngineState {
|
|||||||
let examples = decl
|
let examples = decl
|
||||||
.examples()
|
.examples()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|eg| PluginExample {
|
.map(PluginExample::from)
|
||||||
example: eg.example.into(),
|
|
||||||
description: eg.description.into(),
|
|
||||||
result: eg.result,
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
let sig_with_examples = PluginSignature::new(sig, examples);
|
let sig_with_examples = PluginSignature::new(sig, examples);
|
||||||
serde_json::to_string_pretty(&sig_with_examples)
|
serde_json::to_string_pretty(&sig_with_examples)
|
||||||
|
@ -19,3 +19,13 @@ pub struct PluginExample {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
pub result: Option<Value>,
|
pub result: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Example<'_>> for PluginExample {
|
||||||
|
fn from(value: Example) -> Self {
|
||||||
|
PluginExample {
|
||||||
|
example: value.example.into(),
|
||||||
|
description: value.description.into(),
|
||||||
|
result: value.result,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
use crate::{
|
use crate::{PluginExample, Signature};
|
||||||
engine::Command, BlockId, Category, Flag, PluginExample, PositionalArg, Signature, SyntaxShape,
|
|
||||||
Type,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// A simple wrapper for Signature that includes examples.
|
/// A simple wrapper for Signature that includes examples.
|
||||||
@ -16,210 +13,9 @@ impl PluginSignature {
|
|||||||
Self { sig, examples }
|
Self { sig, examples }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a default help option to a signature
|
|
||||||
pub fn add_help(mut self) -> PluginSignature {
|
|
||||||
self.sig = self.sig.add_help();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build an internal signature with default help option
|
/// Build an internal signature with default help option
|
||||||
pub fn build(name: impl Into<String>) -> PluginSignature {
|
pub fn build(name: impl Into<String>) -> PluginSignature {
|
||||||
let sig = Signature::new(name.into()).add_help();
|
let sig = Signature::new(name.into()).add_help();
|
||||||
Self::new(sig, vec![])
|
Self::new(sig, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a description to the signature
|
|
||||||
pub fn usage(mut self, msg: impl Into<String>) -> PluginSignature {
|
|
||||||
self.sig = self.sig.usage(msg);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an extra description to the signature
|
|
||||||
pub fn extra_usage(mut self, msg: impl Into<String>) -> PluginSignature {
|
|
||||||
self.sig = self.sig.extra_usage(msg);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add search terms to the signature
|
|
||||||
pub fn search_terms(mut self, terms: Vec<String>) -> PluginSignature {
|
|
||||||
self.sig = self.sig.search_terms(terms);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update signature's fields from a Command trait implementation
|
|
||||||
pub fn update_from_command(mut self, command: &dyn Command) -> PluginSignature {
|
|
||||||
self.sig = self.sig.update_from_command(command);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allow unknown signature parameters
|
|
||||||
pub fn allows_unknown_args(mut self) -> PluginSignature {
|
|
||||||
self.sig = self.sig.allows_unknown_args();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a required positional argument to the signature
|
|
||||||
pub fn required(
|
|
||||||
mut self,
|
|
||||||
name: impl Into<String>,
|
|
||||||
shape: impl Into<SyntaxShape>,
|
|
||||||
desc: impl Into<String>,
|
|
||||||
) -> PluginSignature {
|
|
||||||
self.sig = self.sig.required(name, shape, desc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an optional positional argument to the signature
|
|
||||||
pub fn optional(
|
|
||||||
mut self,
|
|
||||||
name: impl Into<String>,
|
|
||||||
shape: impl Into<SyntaxShape>,
|
|
||||||
desc: impl Into<String>,
|
|
||||||
) -> PluginSignature {
|
|
||||||
self.sig = self.sig.optional(name, shape, desc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rest(
|
|
||||||
mut self,
|
|
||||||
name: &str,
|
|
||||||
shape: impl Into<SyntaxShape>,
|
|
||||||
desc: impl Into<String>,
|
|
||||||
) -> PluginSignature {
|
|
||||||
self.sig = self.sig.rest(name, shape, desc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this command capable of operating on its input via cell paths?
|
|
||||||
pub fn operates_on_cell_paths(&self) -> bool {
|
|
||||||
self.sig.operates_on_cell_paths()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an optional named flag argument to the signature
|
|
||||||
pub fn named(
|
|
||||||
mut self,
|
|
||||||
name: impl Into<String>,
|
|
||||||
shape: impl Into<SyntaxShape>,
|
|
||||||
desc: impl Into<String>,
|
|
||||||
short: Option<char>,
|
|
||||||
) -> PluginSignature {
|
|
||||||
self.sig = self.sig.named(name, shape, desc, short);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a required named flag argument to the signature
|
|
||||||
pub fn required_named(
|
|
||||||
mut self,
|
|
||||||
name: impl Into<String>,
|
|
||||||
shape: impl Into<SyntaxShape>,
|
|
||||||
desc: impl Into<String>,
|
|
||||||
short: Option<char>,
|
|
||||||
) -> PluginSignature {
|
|
||||||
self.sig = self.sig.required_named(name, shape, desc, short);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a switch to the signature
|
|
||||||
pub fn switch(
|
|
||||||
mut self,
|
|
||||||
name: impl Into<String>,
|
|
||||||
desc: impl Into<String>,
|
|
||||||
short: Option<char>,
|
|
||||||
) -> PluginSignature {
|
|
||||||
self.sig = self.sig.switch(name, desc, short);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Changes the input type of the command signature
|
|
||||||
pub fn input_output_type(mut self, input_type: Type, output_type: Type) -> PluginSignature {
|
|
||||||
self.sig.input_output_types.push((input_type, output_type));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the input-output type signature variants of the command
|
|
||||||
pub fn input_output_types(mut self, input_output_types: Vec<(Type, Type)>) -> PluginSignature {
|
|
||||||
self.sig = self.sig.input_output_types(input_output_types);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Changes the signature category
|
|
||||||
pub fn category(mut self, category: Category) -> PluginSignature {
|
|
||||||
self.sig = self.sig.category(category);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets that signature will create a scope as it parses
|
|
||||||
pub fn creates_scope(mut self) -> PluginSignature {
|
|
||||||
self.sig = self.sig.creates_scope();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it allowed for the type signature to feature a variant that has no corresponding example?
|
|
||||||
pub fn allow_variants_without_examples(mut self, allow: bool) -> PluginSignature {
|
|
||||||
self.sig = self.sig.allow_variants_without_examples(allow);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call_signature(&self) -> String {
|
|
||||||
self.sig.call_signature()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get list of the short-hand flags
|
|
||||||
pub fn get_shorts(&self) -> Vec<char> {
|
|
||||||
self.sig.get_shorts()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get list of the long-hand flags
|
|
||||||
pub fn get_names(&self) -> Vec<&str> {
|
|
||||||
self.sig.get_names()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_positional(&self, position: usize) -> Option<PositionalArg> {
|
|
||||||
self.sig.get_positional(position)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_positionals(&self) -> usize {
|
|
||||||
self.sig.num_positionals()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_positionals_after(&self, idx: usize) -> usize {
|
|
||||||
self.sig.num_positionals_after(idx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the matching long flag
|
|
||||||
pub fn get_long_flag(&self, name: &str) -> Option<Flag> {
|
|
||||||
self.sig.get_long_flag(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the matching long flag
|
|
||||||
pub fn get_short_flag(&self, short: char) -> Option<Flag> {
|
|
||||||
self.sig.get_short_flag(short)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the filter flag for the signature
|
|
||||||
pub fn filter(mut self) -> PluginSignature {
|
|
||||||
self.sig = self.sig.filter();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a placeholder implementation of Command as a way to predeclare a definition's
|
|
||||||
/// signature so other definitions can see it. This placeholder is later replaced with the
|
|
||||||
/// full definition in a second pass of the parser.
|
|
||||||
pub fn predeclare(self) -> Box<dyn Command> {
|
|
||||||
self.sig.predeclare()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Combines a signature and a block into a runnable block
|
|
||||||
pub fn into_block_command(self, block_id: BlockId) -> Box<dyn Command> {
|
|
||||||
self.sig.into_block_command(block_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn formatted_flags(self) -> String {
|
|
||||||
self.sig.formatted_flags()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn plugin_examples(mut self, examples: Vec<PluginExample>) -> PluginSignature {
|
|
||||||
self.examples = examples;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use crate::CustomValuePlugin;
|
use crate::CustomValuePlugin;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, Category, CustomValue, LabeledError, PluginSignature, ShellError, Span, SyntaxShape,
|
record, Category, CustomValue, LabeledError, ShellError, Signature, Span, SyntaxShape, Value,
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -59,9 +58,16 @@ pub struct DropCheck;
|
|||||||
impl SimplePluginCommand for DropCheck {
|
impl SimplePluginCommand for DropCheck {
|
||||||
type Plugin = CustomValuePlugin;
|
type Plugin = CustomValuePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("custom-value drop-check")
|
"custom-value drop-check"
|
||||||
.usage("Generates a custom value that prints a message when dropped")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Generates a custom value that prints a message when dropped"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.required("msg", SyntaxShape::String, "the message to print on drop")
|
.required("msg", SyntaxShape::String, "the message to print on drop")
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,30 @@
|
|||||||
use crate::{cool_custom_value::CoolCustomValue, CustomValuePlugin};
|
use crate::{cool_custom_value::CoolCustomValue, CustomValuePlugin};
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginExample, PluginSignature, Span, Value};
|
use nu_protocol::{Category, Example, LabeledError, Signature, Span, Value};
|
||||||
|
|
||||||
pub struct Generate;
|
pub struct Generate;
|
||||||
|
|
||||||
impl SimplePluginCommand for Generate {
|
impl SimplePluginCommand for Generate {
|
||||||
type Plugin = CustomValuePlugin;
|
type Plugin = CustomValuePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("custom-value generate")
|
"custom-value generate"
|
||||||
.usage("PluginSignature for a plugin that generates a custom value")
|
}
|
||||||
.category(Category::Experimental)
|
|
||||||
.plugin_examples(vec![PluginExample {
|
fn usage(&self) -> &str {
|
||||||
example: "custom-value generate".into(),
|
"PluginSignature for a plugin that generates a custom value"
|
||||||
description: "Generate a new CoolCustomValue".into(),
|
}
|
||||||
result: Some(CoolCustomValue::new("abc").into_value(Span::test_data())),
|
|
||||||
}])
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name()).category(Category::Experimental)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "custom-value generate",
|
||||||
|
description: "Generate a new CoolCustomValue",
|
||||||
|
result: Some(CoolCustomValue::new("abc").into_value(Span::test_data())),
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -1,35 +1,43 @@
|
|||||||
use crate::{second_custom_value::SecondCustomValue, CustomValuePlugin};
|
use crate::{second_custom_value::SecondCustomValue, CustomValuePlugin};
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{Category, Example, LabeledError, Signature, Span, SyntaxShape, Value};
|
||||||
Category, LabeledError, PluginExample, PluginSignature, Span, SyntaxShape, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Generate2;
|
pub struct Generate2;
|
||||||
|
|
||||||
impl SimplePluginCommand for Generate2 {
|
impl SimplePluginCommand for Generate2 {
|
||||||
type Plugin = CustomValuePlugin;
|
type Plugin = CustomValuePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("custom-value generate2")
|
"custom-value generate2"
|
||||||
.usage("PluginSignature for a plugin that generates a different custom value")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"PluginSignature for a plugin that generates a different custom value"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.optional(
|
.optional(
|
||||||
"closure",
|
"closure",
|
||||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||||
"An optional closure to pass the custom value to",
|
"An optional closure to pass the custom value to",
|
||||||
)
|
)
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
.plugin_examples(vec![
|
}
|
||||||
PluginExample {
|
|
||||||
example: "custom-value generate2".into(),
|
fn examples(&self) -> Vec<Example> {
|
||||||
description: "Generate a new SecondCustomValue".into(),
|
vec![
|
||||||
result: Some(SecondCustomValue::new("xyz").into_value(Span::test_data())),
|
Example {
|
||||||
},
|
example: "custom-value generate2",
|
||||||
PluginExample {
|
description: "Generate a new SecondCustomValue",
|
||||||
example: "custom-value generate2 { print }".into(),
|
result: Some(SecondCustomValue::new("xyz").into_value(Span::test_data())),
|
||||||
description: "Generate a new SecondCustomValue and pass it to a closure".into(),
|
},
|
||||||
result: None,
|
Example {
|
||||||
},
|
example: "custom-value generate2 { print }",
|
||||||
])
|
description: "Generate a new SecondCustomValue and pass it to a closure",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -2,31 +2,38 @@ use crate::{
|
|||||||
cool_custom_value::CoolCustomValue, second_custom_value::SecondCustomValue, CustomValuePlugin,
|
cool_custom_value::CoolCustomValue, second_custom_value::SecondCustomValue, CustomValuePlugin,
|
||||||
};
|
};
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{Category, Example, LabeledError, ShellError, Signature, Span, Value};
|
||||||
Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Update;
|
pub struct Update;
|
||||||
|
|
||||||
impl SimplePluginCommand for Update {
|
impl SimplePluginCommand for Update {
|
||||||
type Plugin = CustomValuePlugin;
|
type Plugin = CustomValuePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("custom-value update")
|
"custom-value update"
|
||||||
.usage("PluginSignature for a plugin that updates a custom value")
|
}
|
||||||
.category(Category::Experimental)
|
|
||||||
.plugin_examples(vec![
|
fn usage(&self) -> &str {
|
||||||
PluginExample {
|
"PluginSignature for a plugin that updates a custom value"
|
||||||
example: "custom-value generate | custom-value update".into(),
|
}
|
||||||
description: "Update a CoolCustomValue".into(),
|
|
||||||
result: Some(CoolCustomValue::new("abcxyz").into_value(Span::test_data())),
|
fn signature(&self) -> Signature {
|
||||||
},
|
Signature::build(self.name()).category(Category::Experimental)
|
||||||
PluginExample {
|
}
|
||||||
example: "custom-value generate2 | custom-value update".into(),
|
|
||||||
description: "Update a SecondCustomValue".into(),
|
fn examples(&self) -> Vec<Example> {
|
||||||
result: Some(SecondCustomValue::new("xyzabc").into_value(Span::test_data())),
|
vec![
|
||||||
},
|
Example {
|
||||||
])
|
example: "custom-value generate | custom-value update",
|
||||||
|
description: "Update a CoolCustomValue",
|
||||||
|
result: Some(CoolCustomValue::new("abcxyz").into_value(Span::test_data())),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
example: "custom-value generate2 | custom-value update",
|
||||||
|
description: "Update a SecondCustomValue",
|
||||||
|
result: Some(SecondCustomValue::new("xyzabc").into_value(Span::test_data())),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
use crate::{update::Update, CustomValuePlugin};
|
use crate::{update::Update, CustomValuePlugin};
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, SyntaxShape, Value};
|
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Value};
|
||||||
|
|
||||||
pub struct UpdateArg;
|
pub struct UpdateArg;
|
||||||
|
|
||||||
impl SimplePluginCommand for UpdateArg {
|
impl SimplePluginCommand for UpdateArg {
|
||||||
type Plugin = CustomValuePlugin;
|
type Plugin = CustomValuePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("custom-value update-arg")
|
"custom-value update-arg"
|
||||||
.usage("PluginSignature for a plugin that updates a custom value as an argument")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Updates a custom value as an argument"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.required(
|
.required(
|
||||||
"custom_value",
|
"custom_value",
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
|
@ -1,35 +1,48 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, LabeledError, PipelineData, PluginExample, PluginSignature, RawStream, Type, Value,
|
Category, Example, LabeledError, PipelineData, RawStream, Signature, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
/// `<list<string>> | example collect-external`
|
/// `<list<string>> | example collect-external`
|
||||||
pub struct CollectExternal;
|
pub struct CollectExternal;
|
||||||
|
|
||||||
impl PluginCommand for CollectExternal {
|
impl PluginCommand for CollectExternal {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example collect-external")
|
"example collect-external"
|
||||||
.usage("Example transformer to raw external stream")
|
}
|
||||||
.search_terms(vec!["example".into()])
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Example transformer to raw external stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::List(Type::String.into()), Type::String),
|
(Type::List(Type::String.into()), Type::String),
|
||||||
(Type::List(Type::Binary.into()), Type::Binary),
|
(Type::List(Type::Binary.into()), Type::Binary),
|
||||||
])
|
])
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "[a b] | example collect-external".into(),
|
|
||||||
description: "collect strings into one stream".into(),
|
|
||||||
result: Some(Value::test_string("ab")),
|
|
||||||
}])
|
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "[a b] | example collect-external",
|
||||||
|
description: "collect strings into one stream",
|
||||||
|
result: Some(Value::test_string("ab")),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
_engine: &EngineInterface,
|
_engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
@ -55,5 +68,5 @@ impl PluginCommand for CollectExternal {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
PluginTest::new("example", Example.into())?.test_command_examples(&CollectExternal)
|
PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&CollectExternal)
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,38 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, Type, Value};
|
use nu_protocol::{Category, LabeledError, Signature, Type, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct Config;
|
pub struct Config;
|
||||||
|
|
||||||
impl SimplePluginCommand for Config {
|
impl SimplePluginCommand for Config {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example config")
|
"example config"
|
||||||
.usage("Show plugin configuration")
|
}
|
||||||
.extra_usage("The configuration is set under $env.config.plugins.example")
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Show plugin configuration"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"The configuration is set under $env.config.plugins.example"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
.search_terms(vec!["example".into(), "configuration".into()])
|
|
||||||
.input_output_type(Type::Nothing, Type::Table(vec![]))
|
.input_output_type(Type::Nothing, Type::Table(vec![]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example", "configuration"]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
engine: &EngineInterface,
|
engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
_input: &Value,
|
_input: &Value,
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, Value};
|
use nu_protocol::{Category, LabeledError, Signature, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct DisableGc;
|
pub struct DisableGc;
|
||||||
|
|
||||||
impl SimplePluginCommand for DisableGc {
|
impl SimplePluginCommand for DisableGc {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example disable-gc")
|
"example disable-gc"
|
||||||
.usage("Disable the plugin garbage collector for `example`")
|
}
|
||||||
.extra_usage(
|
|
||||||
"\
|
fn usage(&self) -> &str {
|
||||||
|
"Disable the plugin garbage collector for `example`"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"\
|
||||||
Plugins are garbage collected by default after a period of inactivity. This
|
Plugins are garbage collected by default after a period of inactivity. This
|
||||||
behavior is configurable with `$env.config.plugin_gc.default`, or to change it
|
behavior is configurable with `$env.config.plugin_gc.default`, or to change it
|
||||||
specifically for the example plugin, use
|
specifically for the example plugin, use
|
||||||
@ -20,21 +25,22 @@ specifically for the example plugin, use
|
|||||||
|
|
||||||
This command demonstrates how plugins can control this behavior and disable GC
|
This command demonstrates how plugins can control this behavior and disable GC
|
||||||
temporarily if they need to. It is still possible to stop the plugin explicitly
|
temporarily if they need to. It is still possible to stop the plugin explicitly
|
||||||
using `plugin stop example`.",
|
using `plugin stop example`."
|
||||||
)
|
}
|
||||||
.search_terms(vec![
|
|
||||||
"example".into(),
|
fn signature(&self) -> Signature {
|
||||||
"gc".into(),
|
Signature::build(self.name())
|
||||||
"plugin_gc".into(),
|
|
||||||
"garbage".into(),
|
|
||||||
])
|
|
||||||
.switch("reset", "Turn the garbage collector back on", None)
|
.switch("reset", "Turn the garbage collector back on", None)
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example", "gc", "plugin_gc", "garbage"]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
engine: &EngineInterface,
|
engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
_input: &Value,
|
_input: &Value,
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, SyntaxShape, Type, Value};
|
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Type, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct Env;
|
pub struct Env;
|
||||||
|
|
||||||
impl SimplePluginCommand for Env {
|
impl SimplePluginCommand for Env {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example env")
|
"example env"
|
||||||
.usage("Get environment variable(s)")
|
}
|
||||||
.extra_usage("Returns all environment variables if no name provided")
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Get environment variable(s)"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"Returns all environment variables if no name provided"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
.optional(
|
.optional(
|
||||||
"name",
|
"name",
|
||||||
@ -25,13 +35,16 @@ impl SimplePluginCommand for Env {
|
|||||||
"Set an environment variable to the value",
|
"Set an environment variable to the value",
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.search_terms(vec!["example".into(), "env".into()])
|
|
||||||
.input_output_type(Type::Nothing, Type::Any)
|
.input_output_type(Type::Nothing, Type::Any)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example", "env"]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
engine: &EngineInterface,
|
engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
_input: &Value,
|
_input: &Value,
|
||||||
|
@ -1,37 +1,48 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{Category, Example, LabeledError, PipelineData, Signature, SyntaxShape, Type};
|
||||||
Category, LabeledError, PipelineData, PluginExample, PluginSignature, SyntaxShape, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
/// `<list> | example for-each { |value| ... }`
|
/// `<list> | example for-each { |value| ... }`
|
||||||
pub struct ForEach;
|
pub struct ForEach;
|
||||||
|
|
||||||
impl PluginCommand for ForEach {
|
impl PluginCommand for ForEach {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example for-each")
|
"example for-each"
|
||||||
.usage("Example execution of a closure with a stream")
|
}
|
||||||
.extra_usage("Prints each value the closure returns to stderr")
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Example execution of a closure with a stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"Prints each value the closure returns to stderr"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_type(Type::ListStream, Type::Nothing)
|
.input_output_type(Type::ListStream, Type::Nothing)
|
||||||
.required(
|
.required(
|
||||||
"closure",
|
"closure",
|
||||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||||
"The closure to run for each input value",
|
"The closure to run for each input value",
|
||||||
)
|
)
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "ls | get name | example for-each { |f| ^file $f }".into(),
|
|
||||||
description: "example with an external command".into(),
|
|
||||||
result: None,
|
|
||||||
}])
|
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "ls | get name | example for-each { |f| ^file $f }",
|
||||||
|
description: "example with an external command",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
engine: &EngineInterface,
|
engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
@ -49,5 +60,5 @@ impl PluginCommand for ForEach {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
PluginTest::new("example", Example.into())?.test_command_examples(&ForEach)
|
PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&ForEach)
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,31 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, IntoInterruptiblePipelineData, LabeledError, PipelineData, PluginExample,
|
Category, Example, IntoInterruptiblePipelineData, LabeledError, PipelineData, Signature,
|
||||||
PluginSignature, SyntaxShape, Type, Value,
|
SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
/// `example generate <initial> { |previous| {out: ..., next: ...} }`
|
/// `example generate <initial> { |previous| {out: ..., next: ...} }`
|
||||||
pub struct Generate;
|
pub struct Generate;
|
||||||
|
|
||||||
impl PluginCommand for Generate {
|
impl PluginCommand for Generate {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example generate")
|
"example generate"
|
||||||
.usage("Example execution of a closure to produce a stream")
|
}
|
||||||
.extra_usage("See the builtin `generate` command")
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Example execution of a closure to produce a stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"See the builtin `generate` command"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_type(Type::Nothing, Type::ListStream)
|
.input_output_type(Type::Nothing, Type::ListStream)
|
||||||
.required(
|
.required(
|
||||||
"initial",
|
"initial",
|
||||||
@ -27,23 +37,25 @@ impl PluginCommand for Generate {
|
|||||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||||
"The closure to run to generate values",
|
"The closure to run to generate values",
|
||||||
)
|
)
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "example generate 0 { |i| if $i <= 10 { {out: $i, next: ($i + 2)} } }"
|
|
||||||
.into(),
|
|
||||||
description: "Generate a sequence of numbers".into(),
|
|
||||||
result: Some(Value::test_list(
|
|
||||||
[0, 2, 4, 6, 8, 10]
|
|
||||||
.into_iter()
|
|
||||||
.map(Value::test_int)
|
|
||||||
.collect(),
|
|
||||||
)),
|
|
||||||
}])
|
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "example generate 0 { |i| if $i <= 10 { {out: $i, next: ($i + 2)} } }",
|
||||||
|
description: "Generate a sequence of numbers",
|
||||||
|
result: Some(Value::test_list(
|
||||||
|
[0, 2, 4, 6, 8, 10]
|
||||||
|
.into_iter()
|
||||||
|
.map(Value::test_int)
|
||||||
|
.collect(),
|
||||||
|
)),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
engine: &EngineInterface,
|
engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
@ -81,7 +93,7 @@ impl PluginCommand for Generate {
|
|||||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||||
use nu_cmd_lang::If;
|
use nu_cmd_lang::If;
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
PluginTest::new("example", Example.into())?
|
PluginTest::new("example", ExamplePlugin.into())?
|
||||||
.add_decl(Box::new(If))?
|
.add_decl(Box::new(If))?
|
||||||
.test_command_examples(&Generate)
|
.test_command_examples(&Generate)
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,38 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, Value};
|
use nu_protocol::{Category, LabeledError, Signature, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct Main;
|
pub struct Main;
|
||||||
|
|
||||||
impl SimplePluginCommand for Main {
|
impl SimplePluginCommand for Main {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example")
|
"example"
|
||||||
.usage("Example commands for Nushell plugins")
|
}
|
||||||
.extra_usage(
|
|
||||||
r#"
|
fn usage(&self) -> &str {
|
||||||
|
"Example commands for Nushell plugins"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
r#"
|
||||||
The `example` plugin demonstrates usage of the Nushell plugin API.
|
The `example` plugin demonstrates usage of the Nushell plugin API.
|
||||||
|
|
||||||
Several commands provided to test and demonstrate different capabilities of
|
Several commands provided to test and demonstrate different capabilities of
|
||||||
plugins exposed through the API. None of these commands are intended to be
|
plugins exposed through the API. None of these commands are intended to be
|
||||||
particularly useful.
|
particularly useful.
|
||||||
"#
|
"#
|
||||||
.trim(),
|
.trim()
|
||||||
)
|
}
|
||||||
.search_terms(vec!["example".into()])
|
|
||||||
.category(Category::Experimental)
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name()).category(Category::Experimental)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -1,37 +1,53 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginExample, PluginSignature, SyntaxShape, Value};
|
use nu_protocol::{Category, Example, LabeledError, Signature, SyntaxShape, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct One;
|
pub struct One;
|
||||||
|
|
||||||
impl SimplePluginCommand for One {
|
impl SimplePluginCommand for One {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
|
"example one"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Plugin test example 1. Returns Value::Nothing"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
"Extra usage for example one"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
// The signature defines the usage of the command inside Nu, and also automatically
|
// The signature defines the usage of the command inside Nu, and also automatically
|
||||||
// generates its help page.
|
// generates its help page.
|
||||||
PluginSignature::build("example one")
|
Signature::build(self.name())
|
||||||
.usage("PluginSignature test 1 for plugin. Returns Value::Nothing")
|
|
||||||
.extra_usage("Extra usage for example one")
|
|
||||||
.search_terms(vec!["example".into()])
|
|
||||||
.required("a", SyntaxShape::Int, "required integer value")
|
.required("a", SyntaxShape::Int, "required integer value")
|
||||||
.required("b", SyntaxShape::String, "required string value")
|
.required("b", SyntaxShape::String, "required string value")
|
||||||
.switch("flag", "a flag for the signature", Some('f'))
|
.switch("flag", "a flag for the signature", Some('f'))
|
||||||
.optional("opt", SyntaxShape::Int, "Optional number")
|
.optional("opt", SyntaxShape::Int, "Optional number")
|
||||||
.named("named", SyntaxShape::String, "named string", Some('n'))
|
.named("named", SyntaxShape::String, "named string", Some('n'))
|
||||||
.rest("rest", SyntaxShape::String, "rest value string")
|
.rest("rest", SyntaxShape::String, "rest value string")
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "example one 3 bb".into(),
|
|
||||||
description: "running example with an int value and string value".into(),
|
|
||||||
result: None,
|
|
||||||
}])
|
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "example one 3 bb",
|
||||||
|
description: "running example with an int value and string value",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
plugin: &Example,
|
plugin: &ExamplePlugin,
|
||||||
_engine: &EngineInterface,
|
_engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
input: &Value,
|
input: &Value,
|
||||||
@ -45,5 +61,5 @@ impl SimplePluginCommand for One {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
PluginTest::new("example", Example.into())?.test_command_examples(&One)
|
PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&One)
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,51 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, LabeledError, ListStream, PipelineData, PluginExample, PluginSignature, SyntaxShape,
|
Category, Example, LabeledError, ListStream, PipelineData, Signature, SyntaxShape, Type, Value,
|
||||||
Type, Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
/// `example seq <first> <last>`
|
/// `example seq <first> <last>`
|
||||||
pub struct Seq;
|
pub struct Seq;
|
||||||
|
|
||||||
impl PluginCommand for Seq {
|
impl PluginCommand for Seq {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example seq")
|
"example seq"
|
||||||
.usage("Example stream generator for a list of values")
|
}
|
||||||
.search_terms(vec!["example".into()])
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Example stream generator for a list of values"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.required("first", SyntaxShape::Int, "first number to generate")
|
.required("first", SyntaxShape::Int, "first number to generate")
|
||||||
.required("last", SyntaxShape::Int, "last number to generate")
|
.required("last", SyntaxShape::Int, "last number to generate")
|
||||||
.input_output_type(Type::Nothing, Type::List(Type::Int.into()))
|
.input_output_type(Type::Nothing, Type::List(Type::Int.into()))
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "example seq 1 3".into(),
|
|
||||||
description: "generate a sequence from 1 to 3".into(),
|
|
||||||
result: Some(Value::test_list(vec![
|
|
||||||
Value::test_int(1),
|
|
||||||
Value::test_int(2),
|
|
||||||
Value::test_int(3),
|
|
||||||
])),
|
|
||||||
}])
|
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "example seq 1 3",
|
||||||
|
description: "generate a sequence from 1 to 3",
|
||||||
|
result: Some(Value::test_list(vec![
|
||||||
|
Value::test_int(1),
|
||||||
|
Value::test_int(2),
|
||||||
|
Value::test_int(3),
|
||||||
|
])),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
_engine: &EngineInterface,
|
_engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
@ -50,5 +62,5 @@ impl PluginCommand for Seq {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
PluginTest::new("example", Example.into())?.test_command_examples(&Seq)
|
PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&Seq)
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,46 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{Category, Example, LabeledError, PipelineData, Signature, Span, Type, Value};
|
||||||
Category, LabeledError, PipelineData, PluginExample, PluginSignature, Span, Type, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
/// `<list> | example sum`
|
/// `<list> | example sum`
|
||||||
pub struct Sum;
|
pub struct Sum;
|
||||||
|
|
||||||
impl PluginCommand for Sum {
|
impl PluginCommand for Sum {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("example sum")
|
"example sum"
|
||||||
.usage("Example stream consumer for a list of values")
|
}
|
||||||
.search_terms(vec!["example".into()])
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Example stream consumer for a list of values"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::List(Type::Int.into()), Type::Int),
|
(Type::List(Type::Int.into()), Type::Int),
|
||||||
(Type::List(Type::Float.into()), Type::Float),
|
(Type::List(Type::Float.into()), Type::Float),
|
||||||
])
|
])
|
||||||
.plugin_examples(vec![PluginExample {
|
|
||||||
example: "example seq 1 5 | example sum".into(),
|
|
||||||
description: "sum values from 1 to 5".into(),
|
|
||||||
result: Some(Value::test_int(15)),
|
|
||||||
}])
|
|
||||||
.category(Category::Experimental)
|
.category(Category::Experimental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
vec!["example"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
example: "example seq 1 5 | example sum",
|
||||||
|
description: "sum values from 1 to 5",
|
||||||
|
result: Some(Value::test_int(15)),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Example,
|
_plugin: &ExamplePlugin,
|
||||||
_engine: &EngineInterface,
|
_engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
@ -92,5 +103,5 @@ impl IntOrFloat {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||||
use nu_plugin_test_support::PluginTest;
|
use nu_plugin_test_support::PluginTest;
|
||||||
PluginTest::new("example", Example.into())?.test_command_examples(&Sum)
|
PluginTest::new("example", ExamplePlugin.into())?.test_command_examples(&Sum)
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,25 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, SyntaxShape, Value};
|
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct Three;
|
pub struct Three;
|
||||||
|
|
||||||
impl SimplePluginCommand for Three {
|
impl SimplePluginCommand for Three {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
|
"example three"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Plugin test example 3. Returns labeled error"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
// The signature defines the usage of the command inside Nu, and also automatically
|
// The signature defines the usage of the command inside Nu, and also automatically
|
||||||
// generates its help page.
|
// generates its help page.
|
||||||
PluginSignature::build("example three")
|
Signature::build(self.name())
|
||||||
.usage("PluginSignature test 3 for plugin. Returns labeled error")
|
|
||||||
.required("a", SyntaxShape::Int, "required integer value")
|
.required("a", SyntaxShape::Int, "required integer value")
|
||||||
.required("b", SyntaxShape::String, "required string value")
|
.required("b", SyntaxShape::String, "required string value")
|
||||||
.switch("flag", "a flag for the signature", Some('f'))
|
.switch("flag", "a flag for the signature", Some('f'))
|
||||||
@ -24,7 +31,7 @@ impl SimplePluginCommand for Three {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
plugin: &Example,
|
plugin: &ExamplePlugin,
|
||||||
_engine: &EngineInterface,
|
_engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
input: &Value,
|
input: &Value,
|
||||||
|
@ -1,18 +1,25 @@
|
|||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{record, Category, LabeledError, PluginSignature, SyntaxShape, Value};
|
use nu_protocol::{record, Category, LabeledError, Signature, SyntaxShape, Value};
|
||||||
|
|
||||||
use crate::Example;
|
use crate::ExamplePlugin;
|
||||||
|
|
||||||
pub struct Two;
|
pub struct Two;
|
||||||
|
|
||||||
impl SimplePluginCommand for Two {
|
impl SimplePluginCommand for Two {
|
||||||
type Plugin = Example;
|
type Plugin = ExamplePlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
|
"example two"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Plugin test example 2. Returns list of records"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
// The signature defines the usage of the command inside Nu, and also automatically
|
// The signature defines the usage of the command inside Nu, and also automatically
|
||||||
// generates its help page.
|
// generates its help page.
|
||||||
PluginSignature::build("example two")
|
Signature::build(self.name())
|
||||||
.usage("PluginSignature test 2 for plugin. Returns list of records")
|
|
||||||
.required("a", SyntaxShape::Int, "required integer value")
|
.required("a", SyntaxShape::Int, "required integer value")
|
||||||
.required("b", SyntaxShape::String, "required string value")
|
.required("b", SyntaxShape::String, "required string value")
|
||||||
.switch("flag", "a flag for the signature", Some('f'))
|
.switch("flag", "a flag for the signature", Some('f'))
|
||||||
@ -24,7 +31,7 @@ impl SimplePluginCommand for Two {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
plugin: &Example,
|
plugin: &ExamplePlugin,
|
||||||
_engine: &EngineInterface,
|
_engine: &EngineInterface,
|
||||||
call: &EvaluatedCall,
|
call: &EvaluatedCall,
|
||||||
input: &Value,
|
input: &Value,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use nu_plugin::EvaluatedCall;
|
use nu_plugin::EvaluatedCall;
|
||||||
use nu_protocol::{LabeledError, Value};
|
use nu_protocol::{LabeledError, Value};
|
||||||
|
|
||||||
pub struct Example;
|
pub struct ExamplePlugin;
|
||||||
|
|
||||||
impl Example {
|
impl ExamplePlugin {
|
||||||
pub fn print_values(
|
pub fn print_values(
|
||||||
&self,
|
&self,
|
||||||
index: u32,
|
index: u32,
|
||||||
|
@ -4,9 +4,9 @@ mod commands;
|
|||||||
mod example;
|
mod example;
|
||||||
|
|
||||||
pub use commands::*;
|
pub use commands::*;
|
||||||
pub use example::Example;
|
pub use example::ExamplePlugin;
|
||||||
|
|
||||||
impl Plugin for Example {
|
impl Plugin for ExamplePlugin {
|
||||||
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
|
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
|
||||||
// This is a list of all of the commands you would like Nu to register when your plugin is
|
// This is a list of all of the commands you would like Nu to register when your plugin is
|
||||||
// loaded.
|
// loaded.
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use nu_plugin::{serve_plugin, MsgPackSerializer};
|
use nu_plugin::{serve_plugin, MsgPackSerializer};
|
||||||
use nu_plugin_example::Example;
|
use nu_plugin_example::ExamplePlugin;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// When defining your plugin, you can select the Serializer that could be
|
// When defining your plugin, you can select the Serializer that could be
|
||||||
// used to encode and decode the messages. The available options are
|
// used to encode and decode the messages. The available options are
|
||||||
// MsgPackSerializer and JsonSerializer. Both are defined in the serializer
|
// MsgPackSerializer and JsonSerializer. Both are defined in the serializer
|
||||||
// folder in nu-plugin.
|
// folder in nu-plugin.
|
||||||
serve_plugin(&Example {}, MsgPackSerializer {})
|
serve_plugin(&ExamplePlugin {}, MsgPackSerializer {})
|
||||||
|
|
||||||
// Note
|
// Note
|
||||||
// When creating plugins in other languages one needs to consider how a plugin
|
// When creating plugins in other languages one needs to consider how a plugin
|
||||||
|
@ -4,20 +4,26 @@ use eml_parser::EmlParser;
|
|||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, SyntaxShape,
|
record, Category, Example, LabeledError, ShellError, Signature, Span, SyntaxShape, Type, Value,
|
||||||
Type, Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_BODY_PREVIEW: usize = 50;
|
const DEFAULT_BODY_PREVIEW: usize = 50;
|
||||||
pub const CMD_NAME: &str = "from eml";
|
|
||||||
|
|
||||||
pub struct FromEml;
|
pub struct FromEml;
|
||||||
|
|
||||||
impl SimplePluginCommand for FromEml {
|
impl SimplePluginCommand for FromEml {
|
||||||
type Plugin = FromCmds;
|
type Plugin = FromCmds;
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build(CMD_NAME)
|
"from eml"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Parse text as .eml and create record."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
||||||
.named(
|
.named(
|
||||||
"preview-body",
|
"preview-body",
|
||||||
@ -25,11 +31,13 @@ impl SimplePluginCommand for FromEml {
|
|||||||
"How many bytes of the body to preview",
|
"How many bytes of the body to preview",
|
||||||
Some('b'),
|
Some('b'),
|
||||||
)
|
)
|
||||||
.usage("Parse text as .eml and create record.")
|
|
||||||
.plugin_examples(examples())
|
|
||||||
.category(Category::Formats)
|
.category(Category::Formats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
examples()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &FromCmds,
|
_plugin: &FromCmds,
|
||||||
@ -45,16 +53,15 @@ impl SimplePluginCommand for FromEml {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn examples() -> Vec<PluginExample> {
|
pub fn examples() -> Vec<Example<'static>> {
|
||||||
vec![
|
vec![
|
||||||
PluginExample {
|
Example {
|
||||||
description: "Convert eml structured data into record".into(),
|
description: "Convert eml structured data into record",
|
||||||
example: "'From: test@email.com
|
example: "'From: test@email.com
|
||||||
Subject: Welcome
|
Subject: Welcome
|
||||||
To: someone@somewhere.com
|
To: someone@somewhere.com
|
||||||
|
|
||||||
Test' | from eml"
|
Test' | from eml",
|
||||||
.into(),
|
|
||||||
result: Some(Value::test_record(record! {
|
result: Some(Value::test_record(record! {
|
||||||
"Subject" => Value::test_string("Welcome"),
|
"Subject" => Value::test_string("Welcome"),
|
||||||
"From" => Value::test_record(record! {
|
"From" => Value::test_record(record! {
|
||||||
@ -68,14 +75,13 @@ Test' | from eml"
|
|||||||
"Body" => Value::test_string("Test"),
|
"Body" => Value::test_string("Test"),
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
PluginExample {
|
Example {
|
||||||
description: "Convert eml structured data into record".into(),
|
description: "Convert eml structured data into record",
|
||||||
example: "'From: test@email.com
|
example: "'From: test@email.com
|
||||||
Subject: Welcome
|
Subject: Welcome
|
||||||
To: someone@somewhere.com
|
To: someone@somewhere.com
|
||||||
|
|
||||||
Test' | from eml -b 1"
|
Test' | from eml -b 1",
|
||||||
.into(),
|
|
||||||
result: Some(Value::test_record(record! {
|
result: Some(Value::test_record(record! {
|
||||||
"Subject" => Value::test_string("Welcome"),
|
"Subject" => Value::test_string("Welcome"),
|
||||||
"From" => Value::test_record(record! {
|
"From" => Value::test_record(record! {
|
||||||
|
@ -1,27 +1,36 @@
|
|||||||
use crate::FromCmds;
|
use crate::FromCmds;
|
||||||
|
|
||||||
use ical::{parser::ical::component::*, property::Property};
|
use ical::{parser::ical::component::*, property::Property};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, Type, Value,
|
record, Category, Example, LabeledError, ShellError, Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
pub const CMD_NAME: &str = "from ics";
|
|
||||||
|
|
||||||
pub struct FromIcs;
|
pub struct FromIcs;
|
||||||
|
|
||||||
impl SimplePluginCommand for FromIcs {
|
impl SimplePluginCommand for FromIcs {
|
||||||
type Plugin = FromCmds;
|
type Plugin = FromCmds;
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build(CMD_NAME)
|
"from ics"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Parse text as .ics and create table."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_types(vec![(Type::String, Type::Table(vec![]))])
|
.input_output_types(vec![(Type::String, Type::Table(vec![]))])
|
||||||
.usage("Parse text as .ics and create table.")
|
|
||||||
.plugin_examples(examples())
|
|
||||||
.category(Category::Formats)
|
.category(Category::Formats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
examples()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &FromCmds,
|
_plugin: &FromCmds,
|
||||||
@ -71,13 +80,11 @@ impl SimplePluginCommand for FromIcs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn examples() -> Vec<PluginExample> {
|
pub fn examples() -> Vec<Example<'static>> {
|
||||||
vec![PluginExample {
|
vec![Example {
|
||||||
example: "
|
example: "'BEGIN:VCALENDAR
|
||||||
'BEGIN:VCALENDAR
|
END:VCALENDAR' | from ics",
|
||||||
END:VCALENDAR' | from ics"
|
description: "Converts ics formatted string to table",
|
||||||
.into(),
|
|
||||||
description: "Converts ics formatted string to table".into(),
|
|
||||||
result: Some(Value::test_list(vec![Value::test_record(record! {
|
result: Some(Value::test_list(vec![Value::test_record(record! {
|
||||||
"properties" => Value::test_list(vec![]),
|
"properties" => Value::test_list(vec![]),
|
||||||
"events" => Value::test_list(vec![]),
|
"events" => Value::test_list(vec![]),
|
||||||
|
@ -1,24 +1,33 @@
|
|||||||
use crate::FromCmds;
|
use crate::FromCmds;
|
||||||
|
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, Category, LabeledError, PluginExample, PluginSignature, Record, ShellError, Type, Value,
|
record, Category, Example, LabeledError, Record, ShellError, Signature, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CMD_NAME: &str = "from ini";
|
|
||||||
|
|
||||||
pub struct FromIni;
|
pub struct FromIni;
|
||||||
|
|
||||||
impl SimplePluginCommand for FromIni {
|
impl SimplePluginCommand for FromIni {
|
||||||
type Plugin = FromCmds;
|
type Plugin = FromCmds;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build(CMD_NAME)
|
"from ini"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Parse text as .ini and create table."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
||||||
.usage("Parse text as .ini and create table.")
|
|
||||||
.plugin_examples(examples())
|
|
||||||
.category(Category::Formats)
|
.category(Category::Formats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
examples()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &FromCmds,
|
_plugin: &FromCmds,
|
||||||
@ -73,13 +82,12 @@ impl SimplePluginCommand for FromIni {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn examples() -> Vec<PluginExample> {
|
pub fn examples() -> Vec<Example<'static>> {
|
||||||
vec![PluginExample {
|
vec![Example {
|
||||||
example: "'[foo]
|
example: "'[foo]
|
||||||
a=1
|
a=1
|
||||||
b=2' | from ini"
|
b=2' | from ini",
|
||||||
.into(),
|
description: "Converts ini formatted string to record",
|
||||||
description: "Converts ini formatted string to record".into(),
|
|
||||||
result: Some(Value::test_record(record! {
|
result: Some(Value::test_record(record! {
|
||||||
"foo" => Value::test_record(record! {
|
"foo" => Value::test_record(record! {
|
||||||
"a" => Value::test_string("1"),
|
"a" => Value::test_string("1"),
|
||||||
|
@ -1,26 +1,35 @@
|
|||||||
use crate::FromCmds;
|
use crate::FromCmds;
|
||||||
|
|
||||||
use ical::{parser::vcard::component::*, property::Property};
|
use ical::{parser::vcard::component::*, property::Property};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, Category, LabeledError, PluginExample, PluginSignature, ShellError, Span, Type, Value,
|
record, Category, Example, LabeledError, ShellError, Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CMD_NAME: &str = "from vcf";
|
|
||||||
|
|
||||||
pub struct FromVcf;
|
pub struct FromVcf;
|
||||||
|
|
||||||
impl SimplePluginCommand for FromVcf {
|
impl SimplePluginCommand for FromVcf {
|
||||||
type Plugin = FromCmds;
|
type Plugin = FromCmds;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build(CMD_NAME)
|
"from vcf"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Parse text as .vcf and create table."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.input_output_types(vec![(Type::String, Type::Table(vec![]))])
|
.input_output_types(vec![(Type::String, Type::Table(vec![]))])
|
||||||
.usage("Parse text as .vcf and create table.")
|
|
||||||
.plugin_examples(examples())
|
|
||||||
.category(Category::Formats)
|
.category(Category::Formats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
examples()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &FromCmds,
|
_plugin: &FromCmds,
|
||||||
@ -68,15 +77,14 @@ impl SimplePluginCommand for FromVcf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn examples() -> Vec<PluginExample> {
|
pub fn examples() -> Vec<Example<'static>> {
|
||||||
vec![PluginExample {
|
vec![Example {
|
||||||
example: "'BEGIN:VCARD
|
example: "'BEGIN:VCARD
|
||||||
N:Foo
|
N:Foo
|
||||||
FN:Bar
|
FN:Bar
|
||||||
EMAIL:foo@bar.com
|
EMAIL:foo@bar.com
|
||||||
END:VCARD' | from vcf"
|
END:VCARD' | from vcf",
|
||||||
.into(),
|
description: "Converts ics formatted string to table",
|
||||||
description: "Converts ics formatted string to table".into(),
|
|
||||||
result: Some(Value::test_list(vec![Value::test_record(record! {
|
result: Some(Value::test_list(vec![Value::test_record(record! {
|
||||||
"properties" => Value::test_list(
|
"properties" => Value::test_list(
|
||||||
vec![
|
vec![
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::GStat;
|
use crate::GStat;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, Spanned, SyntaxShape, Value};
|
use nu_protocol::{Category, LabeledError, Signature, Spanned, SyntaxShape, Value};
|
||||||
|
|
||||||
pub struct GStatPlugin;
|
pub struct GStatPlugin;
|
||||||
|
|
||||||
@ -13,9 +13,16 @@ impl Plugin for GStatPlugin {
|
|||||||
impl SimplePluginCommand for GStat {
|
impl SimplePluginCommand for GStat {
|
||||||
type Plugin = GStatPlugin;
|
type Plugin = GStatPlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("gstat")
|
"gstat"
|
||||||
.usage("Get the git status of a repo")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Get the git status of a repo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(PluginCommand::name(self))
|
||||||
.optional("path", SyntaxShape::Filepath, "path to repo")
|
.optional("path", SyntaxShape::Filepath, "path to repo")
|
||||||
.category(Category::Custom("prompt".to_string()))
|
.category(Category::Custom("prompt".to_string()))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{inc::SemVerAction, Inc};
|
use crate::{inc::SemVerAction, Inc};
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand};
|
||||||
use nu_protocol::{ast::CellPath, LabeledError, PluginSignature, SyntaxShape, Value};
|
use nu_protocol::{ast::CellPath, LabeledError, Signature, SyntaxShape, Value};
|
||||||
|
|
||||||
pub struct IncPlugin;
|
pub struct IncPlugin;
|
||||||
|
|
||||||
@ -13,9 +13,16 @@ impl Plugin for IncPlugin {
|
|||||||
impl SimplePluginCommand for Inc {
|
impl SimplePluginCommand for Inc {
|
||||||
type Plugin = IncPlugin;
|
type Plugin = IncPlugin;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("inc")
|
"inc"
|
||||||
.usage("Increment a value or version. Optionally use the column of a table.")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Increment a value or version. Optionally use the column of a table."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(PluginCommand::name(self))
|
||||||
.optional("cell_path", SyntaxShape::CellPath, "cell path to update")
|
.optional("cell_path", SyntaxShape::CellPath, "cell path to update")
|
||||||
.switch(
|
.switch(
|
||||||
"major",
|
"major",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{query_json::QueryJson, query_web::QueryWeb, query_xml::QueryXml};
|
use crate::{query_json::QueryJson, query_web::QueryWeb, query_xml::QueryXml};
|
||||||
use nu_plugin::{EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand};
|
use nu_plugin::{EvaluatedCall, Plugin, PluginCommand, SimplePluginCommand};
|
||||||
use nu_protocol::{Category, LabeledError, PluginSignature, Value};
|
use nu_protocol::{Category, LabeledError, Signature, Value};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Query;
|
pub struct Query;
|
||||||
@ -32,10 +32,16 @@ pub struct QueryCommand;
|
|||||||
impl SimplePluginCommand for QueryCommand {
|
impl SimplePluginCommand for QueryCommand {
|
||||||
type Plugin = Query;
|
type Plugin = Query;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("query")
|
"query"
|
||||||
.usage("Show all the query commands")
|
}
|
||||||
.category(Category::Filters)
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Show all the query commands"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(PluginCommand::name(self)).category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
use crate::Query;
|
use crate::Query;
|
||||||
use gjson::Value as gjValue;
|
use gjson::Value as gjValue;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{Category, LabeledError, Record, Signature, Span, Spanned, SyntaxShape, Value};
|
||||||
Category, LabeledError, PluginSignature, Record, Span, Spanned, SyntaxShape, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct QueryJson;
|
pub struct QueryJson;
|
||||||
|
|
||||||
impl SimplePluginCommand for QueryJson {
|
impl SimplePluginCommand for QueryJson {
|
||||||
type Plugin = Query;
|
type Plugin = Query;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("query json")
|
"query json"
|
||||||
.usage(
|
}
|
||||||
"execute json query on json file (open --raw <file> | query json 'query string')",
|
|
||||||
)
|
fn usage(&self) -> &str {
|
||||||
|
"execute json query on json file (open --raw <file> | query json 'query string')"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.required("query", SyntaxShape::String, "json query")
|
.required("query", SyntaxShape::String, "json query")
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use crate::{web_tables::WebTable, Query};
|
use crate::{web_tables::WebTable, Query};
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, LabeledError, PluginExample, PluginSignature, Record, Span, Spanned, SyntaxShape,
|
Category, Example, LabeledError, Record, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
use scraper::{Html, Selector as ScraperSelector};
|
use scraper::{Html, Selector as ScraperSelector};
|
||||||
|
|
||||||
@ -11,12 +10,18 @@ pub struct QueryWeb;
|
|||||||
impl SimplePluginCommand for QueryWeb {
|
impl SimplePluginCommand for QueryWeb {
|
||||||
type Plugin = Query;
|
type Plugin = Query;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("query web")
|
"query web"
|
||||||
.usage("execute selector query on html/web")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"execute selector query on html/web"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.named("query", SyntaxShape::String, "selector query", Some('q'))
|
.named("query", SyntaxShape::String, "selector query", Some('q'))
|
||||||
.switch("as-html", "return the query output as html", Some('m'))
|
.switch("as-html", "return the query output as html", Some('m'))
|
||||||
.plugin_examples(web_examples())
|
|
||||||
.named(
|
.named(
|
||||||
"attribute",
|
"attribute",
|
||||||
SyntaxShape::String,
|
SyntaxShape::String,
|
||||||
@ -37,6 +42,10 @@ impl SimplePluginCommand for QueryWeb {
|
|||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
web_examples()
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
_plugin: &Query,
|
_plugin: &Query,
|
||||||
@ -48,27 +57,27 @@ impl SimplePluginCommand for QueryWeb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn web_examples() -> Vec<PluginExample> {
|
pub fn web_examples() -> Vec<Example<'static>> {
|
||||||
vec![
|
vec![
|
||||||
PluginExample {
|
Example {
|
||||||
example: "http get https://phoronix.com | query web --query 'header' | flatten".into(),
|
example: "http get https://phoronix.com | query web --query 'header' | flatten",
|
||||||
description: "Retrieve all `<header>` elements from phoronix.com website".into(),
|
description: "Retrieve all `<header>` elements from phoronix.com website",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
PluginExample {
|
Example {
|
||||||
example: "http get https://en.wikipedia.org/wiki/List_of_cities_in_India_by_population |
|
example: "http get https://en.wikipedia.org/wiki/List_of_cities_in_India_by_population |
|
||||||
query web --as-table [City 'Population(2011)[3]' 'Population(2001)[3][a]' 'State or unionterritory' 'Ref']".into(),
|
query web --as-table [City 'Population(2011)[3]' 'Population(2001)[3][a]' 'State or unionterritory' 'Ref']",
|
||||||
description: "Retrieve a html table from Wikipedia and parse it into a nushell table using table headers as guides".into(),
|
description: "Retrieve a html table from Wikipedia and parse it into a nushell table using table headers as guides",
|
||||||
result: None
|
result: None
|
||||||
},
|
},
|
||||||
PluginExample {
|
Example {
|
||||||
example: "http get https://www.nushell.sh | query web --query 'h2, h2 + p' | each {str join} | group 2 | each {rotate --ccw tagline description} | flatten".into(),
|
example: "http get https://www.nushell.sh | query web --query 'h2, h2 + p' | each {str join} | group 2 | each {rotate --ccw tagline description} | flatten",
|
||||||
description: "Pass multiple css selectors to extract several elements within single query, group the query results together and rotate them to create a table".into(),
|
description: "Pass multiple css selectors to extract several elements within single query, group the query results together and rotate them to create a table",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
PluginExample {
|
Example {
|
||||||
example: "http get https://example.org | query web --query a --attribute href".into(),
|
example: "http get https://example.org | query web --query a --attribute href",
|
||||||
description: "Retrieve a specific html attribute instead of the default text".into(),
|
description: "Retrieve a specific html attribute instead of the default text",
|
||||||
result: None,
|
result: None,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::Query;
|
use crate::Query;
|
||||||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, Category, LabeledError, PluginSignature, Record, Span, Spanned, SyntaxShape, Value,
|
record, Category, LabeledError, Record, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
use sxd_document::parser;
|
use sxd_document::parser;
|
||||||
use sxd_xpath::{Context, Factory};
|
use sxd_xpath::{Context, Factory};
|
||||||
@ -11,9 +11,16 @@ pub struct QueryXml;
|
|||||||
impl SimplePluginCommand for QueryXml {
|
impl SimplePluginCommand for QueryXml {
|
||||||
type Plugin = Query;
|
type Plugin = Query;
|
||||||
|
|
||||||
fn signature(&self) -> PluginSignature {
|
fn name(&self) -> &str {
|
||||||
PluginSignature::build("query xml")
|
"query xml"
|
||||||
.usage("execute xpath query on xml")
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"execute xpath query on xml"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build(self.name())
|
||||||
.required("query", SyntaxShape::String, "xpath query")
|
.required("query", SyntaxShape::String, "xpath query")
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ fn help() {
|
|||||||
"example one --help"
|
"example one --help"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(actual.out.contains("PluginSignature test 1"));
|
assert!(actual.out.contains("test example 1"));
|
||||||
assert!(actual.out.contains("Extra usage for example one"));
|
assert!(actual.out.contains("Extra usage for example one"));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user