mirror of
https://github.com/nushell/nushell.git
synced 2025-08-19 04:45:57 +02:00
Update plugin protocol for begin, and create new sys plugin
This commit is contained in:
@@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct CallInfo {
|
||||
pub args: Args,
|
||||
pub source_map: SourceMap,
|
||||
|
@@ -78,46 +78,64 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
.spawn()
|
||||
.expect("Failed to spawn child process");
|
||||
|
||||
{
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("begin_filter", args.call_info);
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
stdin.write(format!("{}\n", request_raw).as_bytes())?;
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
return Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
e, input
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let mut bos: VecDeque<Spanned<Value>> = VecDeque::new();
|
||||
bos.push_back(Value::Primitive(Primitive::BeginningOfStream).spanned_unknown());
|
||||
|
||||
let mut eos: VecDeque<Spanned<Value>> = VecDeque::new();
|
||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).spanned_unknown());
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
.values
|
||||
let call_info = args.call_info;
|
||||
|
||||
let stream = bos
|
||||
.chain(args.input.values)
|
||||
.chain(eos)
|
||||
.map(move |v| match v {
|
||||
Spanned {
|
||||
item: Value::Primitive(Primitive::BeginningOfStream),
|
||||
..
|
||||
} => {
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("begin_filter", call_info.clone());
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(params) => params,
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Err(e));
|
||||
result
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing begin_filter response: {:?} {}",
|
||||
e, input
|
||||
))));
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while reading begin_filter response: {:?}",
|
||||
e
|
||||
))));
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
Spanned {
|
||||
item: Value::Primitive(Primitive::EndOfStream),
|
||||
..
|
||||
@@ -154,7 +172,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
"Error while processing end_filter response: {:?} {}",
|
||||
e, input
|
||||
))));
|
||||
result
|
||||
@@ -164,7 +182,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?}",
|
||||
"Error while reading end_filter: {:?}",
|
||||
e
|
||||
))));
|
||||
result
|
||||
@@ -197,7 +215,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
"Error while processing filter response: {:?} {}",
|
||||
e, input
|
||||
))));
|
||||
result
|
||||
@@ -207,7 +225,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?}",
|
||||
"Error while reading filter response: {:?}",
|
||||
e
|
||||
))));
|
||||
result
|
||||
|
@@ -9,6 +9,7 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
||||
}
|
||||
Value::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
||||
Value::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
||||
Value::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
||||
Value::Primitive(Primitive::Float(f)) => {
|
||||
serde_json::Value::Number(serde_json::Number::from_f64(f.into_inner()).unwrap())
|
||||
}
|
||||
|
@@ -9,6 +9,9 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
||||
Value::Primitive(Primitive::EndOfStream) => {
|
||||
toml::Value::String("<End of Stream>".to_string())
|
||||
}
|
||||
Value::Primitive(Primitive::BeginningOfStream) => {
|
||||
toml::Value::String("<Beginning of Stream>".to_string())
|
||||
}
|
||||
Value::Primitive(Primitive::Float(f)) => toml::Value::Float(f.into_inner()),
|
||||
Value::Primitive(Primitive::Int(i)) => toml::Value::Integer(*i),
|
||||
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
|
||||
|
@@ -9,6 +9,7 @@ pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value {
|
||||
}
|
||||
Value::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()),
|
||||
Value::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null,
|
||||
Value::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null,
|
||||
Value::Primitive(Primitive::Float(f)) => {
|
||||
serde_yaml::Value::Number(serde_yaml::Number::from(f.into_inner()))
|
||||
}
|
||||
|
@@ -27,11 +27,13 @@ mod stream;
|
||||
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
|
||||
pub use crate::context::{SourceMap, SpanSource};
|
||||
pub use crate::env::host::BasicHost;
|
||||
pub use crate::parser::parse::span::Span;
|
||||
pub use crate::parser::parse::span::SpannedItem;
|
||||
pub use crate::parser::Spanned;
|
||||
pub use crate::plugin::{serve_plugin, Plugin};
|
||||
pub use cli::cli;
|
||||
pub use errors::ShellError;
|
||||
pub use object::base::{Primitive, Value};
|
||||
pub use object::dict::{Dictionary, SpannedDictBuilder};
|
||||
pub use parser::parse::text::Text;
|
||||
pub use parser::registry::{Args, CommandConfig, NamedType, PositionalType};
|
||||
|
@@ -43,6 +43,8 @@ pub enum Primitive {
|
||||
Date(DateTime<Utc>),
|
||||
Path(PathBuf),
|
||||
|
||||
// Stream markers (used as bookend markers rather than actual values)
|
||||
BeginningOfStream,
|
||||
EndOfStream,
|
||||
}
|
||||
|
||||
@@ -52,6 +54,7 @@ impl Primitive {
|
||||
|
||||
match self {
|
||||
Nothing => "nothing",
|
||||
BeginningOfStream => "beginning-of-stream",
|
||||
EndOfStream => "end-of-stream",
|
||||
Path(_) => "path",
|
||||
Int(_) => "int",
|
||||
@@ -69,6 +72,7 @@ impl Primitive {
|
||||
|
||||
match self {
|
||||
Nothing => write!(f, "Nothing"),
|
||||
BeginningOfStream => write!(f, "BeginningOfStream"),
|
||||
EndOfStream => write!(f, "EndOfStream"),
|
||||
Int(int) => write!(f, "{}", int),
|
||||
Path(path) => write!(f, "{}", path.display()),
|
||||
@@ -83,6 +87,7 @@ impl Primitive {
|
||||
pub fn format(&self, field_name: Option<&String>) -> String {
|
||||
match self {
|
||||
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::BeginningOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::Path(p) => format!("{}", p.display()),
|
||||
Primitive::Bytes(b) => {
|
||||
|
@@ -79,7 +79,7 @@ pub struct CommandConfig {
|
||||
pub is_sink: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, new, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, new, Serialize, Deserialize, Clone)]
|
||||
pub struct Args {
|
||||
pub positional: Option<Vec<Spanned<Value>>>,
|
||||
pub named: Option<IndexMap<String, Spanned<Value>>>,
|
||||
|
@@ -5,14 +5,12 @@ use std::io;
|
||||
pub trait Plugin {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError>;
|
||||
#[allow(unused)]
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
||||
Err(ShellError::string(
|
||||
"`begin_filter` not implemented in plugin",
|
||||
))
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
#[allow(unused)]
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Err(ShellError::string("`filter` not implemented in plugin"))
|
||||
Ok(vec![])
|
||||
}
|
||||
#[allow(unused)]
|
||||
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
@@ -21,9 +19,7 @@ pub trait Plugin {
|
||||
#[allow(unused)]
|
||||
fn sink(&mut self, call_info: CallInfo, input: Vec<Spanned<Value>>) {}
|
||||
|
||||
fn quit(&mut self) {
|
||||
return;
|
||||
}
|
||||
fn quit(&mut self) {}
|
||||
}
|
||||
|
||||
pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
||||
@@ -37,11 +33,7 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
||||
send_response(plugin.config());
|
||||
}
|
||||
Ok(NuCommand::begin_filter { params }) => {
|
||||
send_response(
|
||||
plugin
|
||||
.begin_filter(params)
|
||||
.map(|_| Vec::<ReturnValue>::new()),
|
||||
);
|
||||
send_response(plugin.begin_filter(params));
|
||||
}
|
||||
Ok(NuCommand::filter { params }) => {
|
||||
send_response(plugin.filter(params));
|
||||
@@ -78,11 +70,7 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
||||
send_response(plugin.config());
|
||||
}
|
||||
Ok(NuCommand::begin_filter { params }) => {
|
||||
send_response(
|
||||
plugin
|
||||
.begin_filter(params)
|
||||
.map(|_| Vec::<ReturnValue>::new()),
|
||||
);
|
||||
send_response(plugin.begin_filter(params));
|
||||
}
|
||||
Ok(NuCommand::filter { params }) => {
|
||||
send_response(plugin.filter(params));
|
||||
|
@@ -53,7 +53,7 @@ impl Plugin for Add {
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if let Some(args) = call_info.args.positional {
|
||||
match &args[0] {
|
||||
Spanned {
|
||||
@@ -76,7 +76,7 @@ impl Plugin for Add {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
|
@@ -53,7 +53,7 @@ impl Plugin for Edit {
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if let Some(args) = call_info.args.positional {
|
||||
match &args[0] {
|
||||
Spanned {
|
||||
@@ -76,7 +76,7 @@ impl Plugin for Edit {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
|
@@ -99,7 +99,7 @@ impl Plugin for Inc {
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if call_info.args.has("major") {
|
||||
self.major = true;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ impl Plugin for Inc {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
|
@@ -24,7 +24,7 @@ impl Plugin for Skip {
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
if let Some(args) = call_info.args.positional {
|
||||
for arg in args {
|
||||
match arg {
|
||||
@@ -45,7 +45,7 @@ impl Plugin for Skip {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
|
@@ -77,8 +77,8 @@ impl Plugin for Sum {
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
fn begin_filter(&mut self, _: CallInfo) -> Result<(), ShellError> {
|
||||
Ok(())
|
||||
fn begin_filter(&mut self, _: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
|
111
src/plugins/sys.rs
Normal file
111
src/plugins/sys.rs
Normal file
@@ -0,0 +1,111 @@
|
||||
#![feature(async_await)]
|
||||
|
||||
use futures::executor::block_on;
|
||||
use futures::stream::StreamExt;
|
||||
use heim::{disk, memory};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, ReturnSuccess, ReturnValue, ShellError, Span,
|
||||
Spanned, SpannedDictBuilder, Value,
|
||||
};
|
||||
use std::ffi::OsStr;
|
||||
|
||||
struct Sys;
|
||||
impl Sys {
|
||||
fn new() -> Sys {
|
||||
Sys
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add more error checking
|
||||
|
||||
async fn mem(span: Span) -> Spanned<Value> {
|
||||
let memory = memory::memory().await.unwrap();
|
||||
//let swap = memory::swap().await.unwrap();
|
||||
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
|
||||
dict.insert("total", Value::bytes(memory.total().get()));
|
||||
dict.insert("free", Value::bytes(memory.free().get()));
|
||||
|
||||
dict.into_spanned_value()
|
||||
}
|
||||
|
||||
async fn swap(span: Span) -> Spanned<Value> {
|
||||
let swap = memory::swap().await.unwrap();
|
||||
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
|
||||
dict.insert("total", Value::bytes(swap.total().get()));
|
||||
dict.insert("free", Value::bytes(swap.free().get()));
|
||||
|
||||
dict.into_spanned_value()
|
||||
}
|
||||
|
||||
async fn disks(span: Span) -> Value {
|
||||
let mut output = vec![];
|
||||
let mut partitions = disk::partitions_physical();
|
||||
while let Some(part) = partitions.next().await {
|
||||
let part = part.unwrap();
|
||||
let usage = disk::usage(part.mount_point().to_path_buf()).await.unwrap();
|
||||
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
|
||||
dict.insert(
|
||||
"device",
|
||||
Value::string(
|
||||
part.device()
|
||||
.unwrap_or_else(|| OsStr::new("N/A"))
|
||||
.to_string_lossy(),
|
||||
),
|
||||
);
|
||||
|
||||
dict.insert("type", Value::string(part.file_system().as_str()));
|
||||
dict.insert("mount", Value::string(part.mount_point().to_string_lossy()));
|
||||
dict.insert("total", Value::bytes(usage.total().get()));
|
||||
dict.insert("used", Value::bytes(usage.used().get()));
|
||||
dict.insert("free", Value::bytes(usage.free().get()));
|
||||
|
||||
output.push(dict.into_spanned_value());
|
||||
}
|
||||
|
||||
Value::List(output)
|
||||
}
|
||||
|
||||
async fn sysinfo(span: Span) -> Vec<Spanned<Value>> {
|
||||
let mut sysinfo = SpannedDictBuilder::new(span);
|
||||
|
||||
// Disks
|
||||
sysinfo.insert("disks", disks(span).await);
|
||||
sysinfo.insert_spanned("mem", mem(span).await);
|
||||
sysinfo.insert_spanned("swap", swap(span).await);
|
||||
|
||||
vec![sysinfo.into_spanned_value()]
|
||||
}
|
||||
|
||||
impl Plugin for Sys {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
name: "sys".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Ok(block_on(sysinfo(callinfo.name_span.unwrap()))
|
||||
.into_iter()
|
||||
.map(|x| ReturnSuccess::value(x))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn filter(&mut self, _: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut Sys::new());
|
||||
}
|
@@ -83,12 +83,6 @@ fn paint_textview(
|
||||
}
|
||||
}
|
||||
|
||||
// if it's a short buffer, be sure to fill it out
|
||||
// while pos < (width * height) {
|
||||
// frame_buffer.push((' ', 0, 0, 0));
|
||||
// pos += 1;
|
||||
// }
|
||||
|
||||
let num_frame_buffer_rows = frame_buffer.len() / width;
|
||||
let buffer_needs_scrolling = num_frame_buffer_rows > height;
|
||||
|
||||
|
@@ -98,8 +98,6 @@ impl Plugin for TreeViewer {
|
||||
let _ = view.render_view();
|
||||
}
|
||||
}
|
||||
|
||||
//Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user