forked from extern/nushell
Add binary type and tree sink
This commit is contained in:
parent
dc8545ce10
commit
65a0d27c8a
@ -84,6 +84,10 @@ path = "src/plugins/inc.rs"
|
||||
name = "nu_plugin_newskip"
|
||||
path = "src/plugins/newskip.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_treeview"
|
||||
path = "src/plugins/treeview.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu"
|
||||
path = "src/main.rs"
|
||||
|
@ -34,7 +34,7 @@ pub enum MaybeOwned<'a, T> {
|
||||
}
|
||||
|
||||
impl<T> MaybeOwned<'a, T> {
|
||||
crate fn borrow(&self) -> &T {
|
||||
pub fn borrow(&self) -> &T {
|
||||
match self {
|
||||
MaybeOwned::Owned(v) => v,
|
||||
MaybeOwned::Borrowed(v) => v,
|
||||
@ -59,6 +59,7 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
||||
let request = JsonRpc::new("config", Vec::<Value>::new());
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
stdin.write(format!("{}\n", request_raw).as_bytes())?;
|
||||
let path = dunce::canonicalize(path).unwrap();
|
||||
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
@ -129,14 +130,12 @@ fn load_plugins(context: &mut Context) -> Result<(), ShellError> {
|
||||
None => println!("PATH is not defined in the environment."),
|
||||
}
|
||||
|
||||
/*
|
||||
// Also use our debug output for now
|
||||
let mut path = std::path::PathBuf::from(".");
|
||||
path.push("target");
|
||||
path.push("debug");
|
||||
|
||||
let _ = load_plugins_in_dir(&path, context);
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -5,11 +5,10 @@ use crate::prelude::*;
|
||||
|
||||
pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
if args.input.len() > 0 {
|
||||
if equal_shapes(&args.input) {
|
||||
let mut host = args.ctx.host.lock().unwrap();
|
||||
let view = TableView::from_list(&args.input).unwrap();
|
||||
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
if let Value::Binary(_) = args.input[0] {
|
||||
println!("Binary");
|
||||
} else if equal_shapes(&args.input) {
|
||||
args.ctx.get_sink("table").run(args)?;
|
||||
} else {
|
||||
let mut host = args.ctx.host.lock().unwrap();
|
||||
for i in args.input.iter() {
|
||||
|
@ -67,11 +67,16 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
};
|
||||
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Enter(parse_as_value(
|
||||
file_extension,
|
||||
contents,
|
||||
span,
|
||||
)?)));
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(x)) => {
|
||||
stream.push_back(ReturnValue::Action(CommandAction::Enter(parse_as_value(
|
||||
file_extension,
|
||||
x,
|
||||
span,
|
||||
)?)));
|
||||
}
|
||||
x => stream.push_back(ReturnValue::Action(CommandAction::Enter(x))),
|
||||
}
|
||||
|
||||
Ok(stream.boxed())
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ pub fn fetch(
|
||||
cwd: &PathBuf,
|
||||
location: &str,
|
||||
span: Span,
|
||||
) -> Result<(Option<String>, String), ShellError> {
|
||||
) -> Result<(Option<String>, Value), ShellError> {
|
||||
let mut cwd = cwd.clone();
|
||||
if location.starts_with("http:") || location.starts_with("https:") {
|
||||
let response = reqwest::get(location);
|
||||
@ -71,7 +71,7 @@ pub fn fetch(
|
||||
None => path_extension,
|
||||
};
|
||||
|
||||
Ok((extension, s))
|
||||
Ok((extension, Value::string(s)))
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
@ -91,12 +91,15 @@ pub fn fetch(
|
||||
}
|
||||
} else {
|
||||
cwd.push(Path::new(location));
|
||||
match std::fs::read_to_string(&cwd) {
|
||||
Ok(s) => Ok((
|
||||
cwd.extension()
|
||||
.map(|name| name.to_string_lossy().to_string()),
|
||||
s,
|
||||
)),
|
||||
match std::fs::read(&cwd) {
|
||||
Ok(bytes) => match std::str::from_utf8(&bytes) {
|
||||
Ok(s) => Ok((
|
||||
cwd.extension()
|
||||
.map(|name| name.to_string_lossy().to_string()),
|
||||
Value::string(s),
|
||||
)),
|
||||
Err(_) => Ok((None, Value::Binary(bytes))),
|
||||
},
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"File cound not be opened",
|
||||
@ -227,11 +230,12 @@ fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
};
|
||||
|
||||
stream.push_back(ReturnValue::Value(parse_as_value(
|
||||
file_extension,
|
||||
contents,
|
||||
span,
|
||||
)?));
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(x)) => {
|
||||
stream.push_back(ReturnValue::Value(parse_as_value(file_extension, x, span)?));
|
||||
}
|
||||
x => stream.push_back(ReturnValue::Value(x)),
|
||||
}
|
||||
|
||||
Ok(stream.boxed())
|
||||
}
|
||||
|
@ -24,6 +24,13 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
||||
}
|
||||
Value::Error(e) => serde_json::Value::String(e.to_string()),
|
||||
Value::Block(_) => serde_json::Value::Null,
|
||||
Value::Binary(b) => serde_json::Value::Array(
|
||||
b.iter()
|
||||
.map(|x| {
|
||||
serde_json::Value::Number(serde_json::Number::from_f64(*x as f64).unwrap())
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
Value::Object(o) => {
|
||||
let mut m = serde_json::Map::new();
|
||||
for (k, v) in o.entries.iter() {
|
||||
|
@ -18,6 +18,9 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
||||
Value::List(l) => toml::Value::Array(l.iter().map(|x| value_to_toml_value(x)).collect()),
|
||||
Value::Error(e) => toml::Value::String(e.to_string()),
|
||||
Value::Block(_) => toml::Value::String("<Block>".to_string()),
|
||||
Value::Binary(b) => {
|
||||
toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect())
|
||||
}
|
||||
Value::Object(o) => {
|
||||
let mut m = toml::map::Map::new();
|
||||
for (k, v) in o.entries.iter() {
|
||||
|
2
src/env/host.rs
vendored
2
src/env/host.rs
vendored
@ -40,7 +40,7 @@ impl Host for Box<dyn Host> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
crate struct BasicHost;
|
||||
pub struct BasicHost;
|
||||
|
||||
impl Host for BasicHost {
|
||||
fn out_terminal(&self) -> Box<term::StdoutTerminal> {
|
||||
|
@ -41,6 +41,11 @@ impl RenderView for GenericView<'value> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Value::Binary(_) => {
|
||||
host.stdout("<Binary>");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Value::Filesystem => {
|
||||
host.stdout("<filesystem>");
|
||||
Ok(())
|
||||
|
@ -7,14 +7,8 @@ use ptree::print_config::PrintConfig;
|
||||
use ptree::style::{Color, Style};
|
||||
use ptree::TreeBuilder;
|
||||
|
||||
// An entries list is printed like this:
|
||||
//
|
||||
// name : ...
|
||||
// name2 : ...
|
||||
// another_name : ...
|
||||
#[derive(new)]
|
||||
pub struct TreeView {
|
||||
//entries: Vec<(crate::object::DescriptorName, Value)>,
|
||||
tree: StringItem,
|
||||
}
|
||||
|
||||
@ -39,6 +33,7 @@ impl TreeView {
|
||||
Value::Block(_) => {}
|
||||
Value::Error(_) => {}
|
||||
Value::Filesystem => {}
|
||||
Value::Binary(_) => {}
|
||||
}
|
||||
}
|
||||
crate fn from_value(value: &Value) -> TreeView {
|
||||
@ -73,7 +68,6 @@ impl RenderView for TreeView {
|
||||
bold: true,
|
||||
..Style::default()
|
||||
};
|
||||
//config.characters = UTF_CHARS_BOLD.into();
|
||||
config.indent = 4;
|
||||
config
|
||||
};
|
||||
|
@ -21,6 +21,7 @@ mod shell;
|
||||
mod stream;
|
||||
|
||||
pub use crate::commands::command::ReturnValue;
|
||||
pub use crate::env::host::BasicHost;
|
||||
pub use crate::parser::parse::span::SpannedItem;
|
||||
pub use crate::parser::Spanned;
|
||||
pub use crate::plugin::{serve_plugin, Plugin};
|
||||
|
@ -75,7 +75,7 @@ impl Primitive {
|
||||
}
|
||||
}
|
||||
|
||||
crate fn format(&self, field_name: Option<&String>) -> String {
|
||||
pub fn format(&self, field_name: Option<&String>) -> String {
|
||||
match self {
|
||||
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||
@ -180,6 +180,8 @@ pub enum Value {
|
||||
Primitive(Primitive),
|
||||
Object(crate::object::Dictionary),
|
||||
List(Vec<Value>),
|
||||
Binary(Vec<u8>),
|
||||
|
||||
#[allow(unused)]
|
||||
Block(Block),
|
||||
Filesystem,
|
||||
@ -217,6 +219,7 @@ impl fmt::Debug for ValueDebug<'a> {
|
||||
Value::Block(_) => write!(f, "[[block]]"),
|
||||
Value::Error(err) => write!(f, "[[error :: {} ]]", err),
|
||||
Value::Filesystem => write!(f, "[[filesystem]]"),
|
||||
Value::Binary(_) => write!(f, "[[binary]]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,6 +240,7 @@ impl Value {
|
||||
Value::Block(_) => format!("block"),
|
||||
Value::Error(_) => format!("error"),
|
||||
Value::Filesystem => format!("filesystem"),
|
||||
Value::Binary(_) => format!("binary"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +248,7 @@ impl Value {
|
||||
ValueDebug { value: self }
|
||||
}
|
||||
|
||||
crate fn data_descriptors(&self) -> Vec<String> {
|
||||
pub fn data_descriptors(&self) -> Vec<String> {
|
||||
match self {
|
||||
Value::Primitive(_) => vec![],
|
||||
Value::Object(o) => o
|
||||
@ -257,6 +261,7 @@ impl Value {
|
||||
Value::List(_) => vec![],
|
||||
Value::Error(_) => vec![],
|
||||
Value::Filesystem => vec![],
|
||||
Value::Binary(_) => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,7 +291,7 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
crate fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
|
||||
pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
|
||||
match self {
|
||||
p @ Value::Primitive(_) => MaybeOwned::Borrowed(p),
|
||||
p @ Value::Filesystem => MaybeOwned::Borrowed(p),
|
||||
@ -294,6 +299,7 @@ impl Value {
|
||||
Value::Block(_) => MaybeOwned::Owned(Value::nothing()),
|
||||
Value::List(_) => MaybeOwned::Owned(Value::nothing()),
|
||||
Value::Error(e) => MaybeOwned::Owned(Value::string(&format!("{:#?}", e))),
|
||||
Value::Binary(_) => MaybeOwned::Owned(Value::nothing()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,6 +314,7 @@ impl Value {
|
||||
}
|
||||
Value::Error(e) => Value::Error(Box::new(e.copy_error())),
|
||||
Value::Filesystem => Value::Filesystem,
|
||||
Value::Binary(b) => Value::Binary(b.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,6 +331,7 @@ impl Value {
|
||||
Value::List(_) => format!("[list List]"),
|
||||
Value::Error(e) => format!("{}", e),
|
||||
Value::Filesystem => format!("<filesystem>"),
|
||||
Value::Binary(_) => format!("<binary>"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl Dictionary {
|
||||
out
|
||||
}
|
||||
|
||||
crate fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
|
||||
pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
|
||||
match self.entries.get(desc) {
|
||||
Some(v) => MaybeOwned::Borrowed(v),
|
||||
None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)),
|
||||
|
114
src/plugins/treeview.rs
Normal file
114
src/plugins/treeview.rs
Normal file
@ -0,0 +1,114 @@
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use nu::{serve_plugin, Args, CommandConfig, Plugin, ShellError, Value};
|
||||
use ptree::item::StringItem;
|
||||
use ptree::output::print_tree_with;
|
||||
use ptree::print_config::PrintConfig;
|
||||
use ptree::style::{Color, Style};
|
||||
use ptree::TreeBuilder;
|
||||
|
||||
#[derive(new)]
|
||||
pub struct TreeView {
|
||||
tree: StringItem,
|
||||
}
|
||||
|
||||
impl TreeView {
|
||||
fn from_value_helper(value: &Value, mut builder: &mut TreeBuilder) {
|
||||
match value {
|
||||
Value::Primitive(p) => {
|
||||
let _ = builder.add_empty_child(p.format(None));
|
||||
}
|
||||
Value::Object(o) => {
|
||||
for (k, v) in o.entries.iter() {
|
||||
builder = builder.begin_child(k.clone());
|
||||
Self::from_value_helper(v, builder);
|
||||
builder = builder.end_child();
|
||||
}
|
||||
}
|
||||
Value::List(l) => {
|
||||
for elem in l.iter() {
|
||||
Self::from_value_helper(elem, builder);
|
||||
}
|
||||
}
|
||||
Value::Block(_) => {}
|
||||
Value::Error(_) => {}
|
||||
Value::Filesystem => {}
|
||||
Value::Binary(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn from_value(value: &Value) -> TreeView {
|
||||
let descs = value.data_descriptors();
|
||||
|
||||
let mut tree = TreeBuilder::new("".to_string());
|
||||
let mut builder = &mut tree;
|
||||
|
||||
for desc in descs {
|
||||
let value = value.get_data(&desc);
|
||||
builder = builder.begin_child(desc.clone());
|
||||
Self::from_value_helper(value.borrow(), &mut builder);
|
||||
builder = builder.end_child();
|
||||
//entries.push((desc.name.clone(), value.borrow().copy()))
|
||||
}
|
||||
|
||||
TreeView::new(builder.build())
|
||||
}
|
||||
|
||||
fn render_view(&self) -> Result<(), ShellError> {
|
||||
// Set up the print configuration
|
||||
let config = {
|
||||
let mut config = PrintConfig::from_env();
|
||||
config.branch = Style {
|
||||
foreground: Some(Color::Green),
|
||||
dimmed: true,
|
||||
..Style::default()
|
||||
};
|
||||
config.leaf = Style {
|
||||
bold: true,
|
||||
..Style::default()
|
||||
};
|
||||
//config.characters = UTF_CHARS_BOLD.into();
|
||||
config.indent = 4;
|
||||
config
|
||||
};
|
||||
|
||||
// Print out the tree using custom formatting
|
||||
print_tree_with(&self.tree, &config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct TreeViewer;
|
||||
|
||||
impl Plugin for TreeViewer {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
name: "treeview".to_string(),
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
can_load: vec![],
|
||||
can_save: vec![],
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
}
|
||||
|
||||
fn sink(&mut self, _args: Args, input: Vec<Value>) {
|
||||
if input.len() > 0 {
|
||||
for i in input.iter() {
|
||||
let view = TreeView::from_value(&i);
|
||||
let _ = view.render_view();
|
||||
//handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
}
|
||||
|
||||
//Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
serve_plugin(&mut TreeViewer);
|
||||
}
|
Loading…
Reference in New Issue
Block a user