nushell-plugin-builder

安装量: 36
排名: #19382

安装

npx skills add https://github.com/ypares/agent-skills --skill nushell-plugin-builder

Nushell Plugin Builder Overview This skill helps create Nushell plugins in Rust. Plugins are standalone executables that extend Nushell with custom commands, data transformations, and integrations. Quick Start 1. Create Plugin Project cargo new nu_plugin_ < name

cd nu_plugin_ < name

cargo add nu-plugin nu-protocol 2. Basic Plugin Structure use nu_plugin :: { EvaluatedCall , MsgPackSerializer , serve_plugin } ; use nu_plugin :: { EngineInterface , Plugin , PluginCommand , SimplePluginCommand } ; use nu_protocol :: { LabeledError , Signature , Type , Value } ; struct MyPlugin ; impl Plugin for MyPlugin { fn version ( & self ) -> String { env! ( "CARGO_PKG_VERSION" ) . into ( ) } fn commands ( & self ) -> Vec < Box < dyn PluginCommand < Plugin = Self

{ vec! [ Box :: new ( MyCommand ) ] } } struct MyCommand ; impl SimplePluginCommand for MyCommand { type Plugin = MyPlugin ; fn name ( & self ) -> & str { "my-command" } fn signature ( & self ) -> Signature { Signature :: build ( "my-command" ) . input_output_type ( Type :: String , Type :: Int ) } fn run ( & self , _plugin : & MyPlugin , _engine : & EngineInterface , call : & EvaluatedCall , input : & Value , ) -> Result < Value , LabeledError

{ match input { Value :: String { val , .. } => { Ok ( Value :: int ( val . len ( ) as i64 , call . head ) ) } _ => Err ( LabeledError :: new ( "Expected string input" ) . with_label ( "requires string" , call . head ) ) } } } fn main ( ) { serve_plugin ( & MyPlugin , MsgPackSerializer ) } 3. Build and Install

Build

cargo build --release

Install to cargo bin

cargo install --path . --locked

Register with nushell

plugin add ~/.cargo/bin/nu_plugin_ < name

Add .exe on Windows

plugin use < name

Test

"hello" | my-command Command Types SimplePluginCommand For commands that operate on single values: Input: &Value Output: Result Use for: transformations, simple filters, single value operations PluginCommand For commands that handle streams: Input: PipelineData Output: Result Use for: streaming transformations, lazy processing, large datasets See references/advanced-features.md for streaming examples. Defining Command Signatures Input-Output Types use nu_protocol :: { Signature , Type } ; Signature :: build ( "my-command" ) . input_output_type ( Type :: String , Type :: Int ) Common types: String , Int , Float , Bool , List(Box) , Record(...) , Any Parameters Signature :: build ( "my-command" ) // Named flags . named ( "output" , SyntaxShape :: Filepath , "output file" , Some ( 'o' ) ) . switch ( "verbose" , "enable verbose output" , Some ( 'v' ) ) // Positional arguments . required ( "input" , SyntaxShape :: String , "input value" ) . optional ( "count" , SyntaxShape :: Int , "repeat count" ) . rest ( "files" , SyntaxShape :: Filepath , "files to process" ) Accessing Arguments fn run ( & self , call : & EvaluatedCall , ... ) -> Result < Value , LabeledError

{ let output : Option < String

= call . get_flag ( "output" ) ? ; let verbose : bool = call . has_flag ( "verbose" ) ? ; let input : String = call . req ( 0 ) ? ; // First positional let count : Option < i64

= call . opt ( 1 ) ? ; // Second positional let files : Vec < String

= call . rest ( 2 ) ? ; // Remaining args } Error Handling Always return LabeledError with span information: Err ( LabeledError :: new ( "Error message" ) . with_label ( "specific issue" , call . head ) ) This shows users exactly where the error occurred in their command. Serialization MsgPackSerializer (Recommended) Binary format, much faster Use for production plugins JsonSerializer Text-based, human-readable Useful for debugging Choose in main() : serve_plugin ( & MyPlugin , MsgPackSerializer ) // Production // serve_plugin(&MyPlugin, JsonSerializer) // Debug Common Patterns String Transformation Value :: String { val , .. } => { Ok ( Value :: string ( val . to_uppercase ( ) , call . head ) ) } List Generation let items = vec! [ Value :: string ( "a" , call . head ) , Value :: string ( "b" , call . head ) , ] ; Ok ( Value :: list ( items , call . head ) ) Record (Table Row) use nu_protocol :: record ; Ok ( Value :: record ( record! { "name" => Value :: string ( "example" , call . head ) , "size" => Value :: int ( 42 , call . head ) , } , call . head , ) ) Table (List of Records) let records = vec! [ Value :: record ( record! { "name" => Value :: string ( "a" , span ) } , span ) , Value :: record ( record! { "name" => Value :: string ( "b" , span ) } , span ) , ] ; Ok ( Value :: list ( records , call . head ) ) See references/examples.md for complete working examples including: Filtering streams HTTP API calls File system operations Multi-command plugins Development Workflow Iterative Development

Build

cargo build

Test (debug build)

plugin add target/debug/nu_plugin_ < name

plugin use < name

"test" | my-command

After changes, reload

plugin rm < name

plugin add target/debug/nu_plugin_ < name

plugin use < name

Automated Testing [ dev-dependencies ] nu-plugin-test-support = "0.109.1"

[cfg(test)]

mod tests { use nu_plugin_test_support :: PluginTest ;

[test]

fn test_command ( ) -> Result < ( ) , nu_protocol :: ShellError

{ PluginTest :: new ( "myplugin" , MyPlugin . into ( ) ) ? . test_examples ( & MyCommand ) } } See references/testing-debugging.md for debugging techniques and troubleshooting. Advanced Features Streaming Data For lazy processing of large datasets, use PipelineData : impl PluginCommand for MyCommand { fn run ( & self , input : PipelineData , ... ) -> Result < PipelineData , LabeledError

{ let filtered = input . into_iter ( ) . filter ( | v | / condition / ) ; Ok ( PipelineData :: ListStream ( ListStream :: new ( filtered , span , None ) , None ) ) } } Engine Interaction // Get environment variables let home = engine . get_env_var ( "HOME" ) ? ; // Set environment variables (before response) engine . add_env_var ( "MY_VAR" , Value :: string ( "value" , span ) ) ? ; // Get plugin config from $env.config.plugins. let config = engine . get_plugin_config ( ) ? ; // Get current directory for path resolution let cwd = engine . get_current_dir ( ) ? ; Custom Values Define custom data types that extend beyond Nushell's built-in types. See references/advanced-features.md for complete guide. Important Constraints Stdio Restrictions Plugins cannot use stdin/stdout (reserved for protocol) Check engine.is_using_stdio() before attempting stdio access Path Handling Always use paths relative to engine.get_current_dir() Never assume current working directory Version Compatibility Match nu-plugin and nu-protocol versions Both should match target Nushell version Reference Documentation references/plugin-protocol.md - Protocol details, serialization, lifecycle references/advanced-features.md - Streaming, EngineInterface, custom values references/examples.md - Complete working examples and patterns references/testing-debugging.md - Development workflow, debugging, troubleshooting External Resources Official Plugin Guide nu-plugin API Docs Plugin Examples Repository Awesome Nu - Community plugins nushellWith - Nix flake for building reproducible Nushell environments with plugins. Includes 100+ pre-packaged plugins from crates.io with binary caching via Garnix. Useful for testing plugins in isolated environments or building standalone Nu scripts. Template Script Use scripts/init_plugin.py to scaffold a new plugin with proper structure: python3 scripts/init_plugin.py < plugin-name

[ --output-dir < path

] This creates a complete working plugin template ready to customize.

返回排行榜