use crate::{Args, CommandConfig, ReturnValue, ShellError, Spanned, Value}; use serde::{Deserialize, Serialize}; use std::io; pub trait Plugin { fn config(&mut self) -> Result; #[allow(unused)] fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { Err(ShellError::string( "`begin_filter` not implemented in plugin", )) } #[allow(unused)] fn filter(&mut self, input: Spanned) -> Result, ShellError> { Err(ShellError::string("`filter` not implemented in plugin")) } #[allow(unused)] fn sink(&mut self, args: Args, input: Vec>) {} fn quit(&mut self) { return; } } pub fn serve_plugin(plugin: &mut dyn Plugin) { let args = std::env::args(); if args.len() > 1 { let input = std::fs::read_to_string(args.skip(1).next().unwrap()); if let Ok(input) = input { let command = serde_json::from_str::(&input); match command { Ok(NuCommand::config) => { send_response(plugin.config()); } Ok(NuCommand::begin_filter { params }) => { let _ = plugin.begin_filter(params); } Ok(NuCommand::filter { params }) => { send_response(plugin.filter(params)); } Ok(NuCommand::sink { params }) => { plugin.sink(params.0, params.1); return; } Ok(NuCommand::quit) => { plugin.quit(); return; } e => { send_response(ShellError::string(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::(&input); match command { Ok(NuCommand::config) => { send_response(plugin.config()); } Ok(NuCommand::begin_filter { params }) => { let _ = plugin.begin_filter(params); } Ok(NuCommand::filter { params }) => { send_response(plugin.filter(params)); } Ok(NuCommand::sink { params }) => { plugin.sink(params.0, params.1); break; } Ok(NuCommand::quit) => { plugin.quit(); break; } e => { send_response(ShellError::string(format!( "Could not handle plugin message: {} {:?}", input, e ))); break; } } } e => { send_response(ShellError::string(format!( "Could not handle plugin message: {:?}", e, ))); break; } } } } } #[derive(Debug, Serialize, Deserialize)] pub struct JsonRpc { jsonrpc: String, pub method: String, pub params: T, } impl JsonRpc { pub fn new>(method: U, params: T) -> Self { JsonRpc { jsonrpc: "2.0".into(), method: method.into(), params, } } } fn send_response(result: T) { let response = JsonRpc::new("response", result); let response_raw = serde_json::to_string(&response).unwrap(); println!("{}", response_raw); } #[derive(Debug, Serialize, Deserialize)] #[serde(tag = "method")] #[allow(non_camel_case_types)] pub enum NuCommand { config, begin_filter { params: Args }, filter { params: Spanned }, sink { params: (Args, Vec>) }, quit, }