1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
use crate::jsonrpc::{send_response, NuCommand};
use nu_errors::ShellError;
use nu_protocol::{CallInfo, ReturnValue, Signature, Value};
use std::io;
/// The `Plugin` trait defines the API which plugins may use to "hook" into nushell.
pub trait Plugin {
/// The `config` method is used to configure a plugin's user interface / signature.
///
/// This is where the "name" of the plugin (ex `fetch`), description, any required/optional fields, and flags
/// can be defined. This information will displayed in nushell when running help <plugin name>
fn config(&mut self) -> Result<Signature, ShellError>;
/// `begin_filter` is the first method to be called if the `Signature` of the plugin is configured to be filterable.
/// Any setup required for the plugin such as parsing arguments from `CallInfo` or initializing data structures
/// can be done here. The `CallInfo` parameter will contain data configured in the `config` method of the Plugin trait.
fn begin_filter(&mut self, _call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
Ok(vec![])
}
/// `filter` is called for every `Value` that is processed by the plugin.
/// This method requires the plugin `Signature` to be configured as filterable.
fn filter(&mut self, _input: Value) -> Result<Vec<ReturnValue>, ShellError> {
Ok(vec![])
}
/// `end_filter` is the last method to be called by the plugin after all `Value`s are processed by the plugin.
/// This method requires the plugin `Signature` to be configured as filterable.
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
Ok(vec![])
}
/// `sink` consumes the `Value`s that are passed in, preventing further processing.
/// This method requires the plugin `Signature` to be configured without filtering.
fn sink(&mut self, _call_info: CallInfo, _input: Vec<Value>) {}
fn quit(&mut self) {}
}
pub fn serve_plugin(plugin: &mut dyn Plugin) {
let mut args = std::env::args();
if args.len() > 1 {
let input = args.nth(1);
let input = match input {
Some(arg) => std::fs::read_to_string(arg),
None => {
send_response(ShellError::untagged_runtime_error("No input given."));
return;
}
};
if let Ok(input) = input {
let command = serde_json::from_str::<NuCommand>(&input);
match command {
Ok(NuCommand::config) => {
send_response(plugin.config());
return;
}
Ok(NuCommand::begin_filter { params }) => {
send_response(plugin.begin_filter(params));
}
Ok(NuCommand::filter { params }) => {
send_response(plugin.filter(params));
}
Ok(NuCommand::end_filter) => {
send_response(plugin.end_filter());
return;
}
Ok(NuCommand::sink { params }) => {
plugin.sink(params.0, params.1);
return;
}
Ok(NuCommand::quit) => {
plugin.quit();
return;
}
e => {
send_response(ShellError::untagged_runtime_error(format!(
"Could not handle plugin message: {} {:?}",
input, e
)));
return;
}
}
}
} else {
loop {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => {
let command = serde_json::from_str::<NuCommand>(&input);
match command {
Ok(NuCommand::config) => {
send_response(plugin.config());
break;
}
Ok(NuCommand::begin_filter { params }) => {
send_response(plugin.begin_filter(params));
}
Ok(NuCommand::filter { params }) => {
send_response(plugin.filter(params));
}
Ok(NuCommand::end_filter) => {
send_response(plugin.end_filter());
break;
}
Ok(NuCommand::sink { params }) => {
plugin.sink(params.0, params.1);
break;
}
Ok(NuCommand::quit) => {
plugin.quit();
break;
}
e => {
send_response(ShellError::untagged_runtime_error(format!(
"Could not handle plugin message: {} {:?}",
input, e
)));
break;
}
}
}
e => {
send_response(ShellError::untagged_runtime_error(format!(
"Could not handle plugin message: {:?}",
e,
)));
break;
}
}
}
}
}