Merge env into $nu and simplify table/get (#1463)

This commit is contained in:
Jonathan Turner 2020-03-08 18:33:30 +13:00 committed by GitHub
parent ebf139f5e5
commit 50fb97f6b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 63 additions and 296 deletions

View File

@ -240,7 +240,6 @@ pub fn create_default_context(
per_item_command(Ls), per_item_command(Ls),
per_item_command(Du), per_item_command(Du),
whole_stream_command(Cd), whole_stream_command(Cd),
whole_stream_command(Env),
per_item_command(Remove), per_item_command(Remove),
per_item_command(Open), per_item_command(Open),
whole_stream_command(Config), whole_stream_command(Config),

View File

@ -23,7 +23,6 @@ pub(crate) mod du;
pub(crate) mod echo; pub(crate) mod echo;
pub(crate) mod edit; pub(crate) mod edit;
pub(crate) mod enter; pub(crate) mod enter;
pub(crate) mod env;
#[allow(unused)] #[allow(unused)]
pub(crate) mod evaluate_by; pub(crate) mod evaluate_by;
pub(crate) mod exit; pub(crate) mod exit;
@ -126,7 +125,6 @@ pub(crate) mod clear;
pub(crate) use clear::Clear; pub(crate) use clear::Clear;
pub(crate) mod touch; pub(crate) mod touch;
pub(crate) use enter::Enter; pub(crate) use enter::Enter;
pub(crate) use env::Env;
#[allow(unused_imports)] #[allow(unused_imports)]
pub(crate) use evaluate_by::EvaluateBy; pub(crate) use evaluate_by::EvaluateBy;
pub(crate) use exit::Exit; pub(crate) use exit::Exit;

View File

@ -1,91 +0,0 @@
use crate::cli::History;
use crate::data::config;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Signature, TaggedDictBuilder, UntaggedValue, Value};
use crate::commands::WholeStreamCommand;
use indexmap::IndexMap;
pub struct Env;
impl WholeStreamCommand for Env {
fn name(&self) -> &str {
"env"
}
fn signature(&self) -> Signature {
Signature::build("env")
}
fn usage(&self) -> &str {
"Get the current environment."
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
env(args, registry)
}
}
pub fn get_environment(tag: Tag) -> Result<Value, Box<dyn std::error::Error>> {
let mut indexmap = IndexMap::new();
let path = std::env::current_dir()?;
indexmap.insert(
"cwd".to_string(),
UntaggedValue::path(path).into_value(&tag),
);
if let Some(home) = dirs::home_dir() {
indexmap.insert(
"home".to_string(),
UntaggedValue::path(home).into_value(&tag),
);
}
let config = config::default_path()?;
indexmap.insert(
"config".to_string(),
UntaggedValue::path(config).into_value(&tag),
);
let history = History::path();
indexmap.insert(
"history".to_string(),
UntaggedValue::path(history).into_value(&tag),
);
let temp = std::env::temp_dir();
indexmap.insert(
"temp".to_string(),
UntaggedValue::path(temp).into_value(&tag),
);
let mut dict = TaggedDictBuilder::new(&tag);
for v in std::env::vars() {
dict.insert_untagged(v.0, UntaggedValue::string(v.1));
}
if !dict.is_empty() {
indexmap.insert("vars".to_string(), dict.into_value());
}
Ok(UntaggedValue::Row(Dictionary::from(indexmap)).into_value(&tag))
}
pub fn env(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let mut env_out = VecDeque::new();
let tag = args.call_info.name_tag.clone();
let value = get_environment(tag)?;
env_out.push_back(value);
let env_out = futures::stream::iter(env_out);
Ok(env_out.to_output_stream())
}

View File

@ -1,7 +1,5 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::data::base::shape::Shapes;
use crate::prelude::*; use crate::prelude::*;
use futures_util::pin_mut;
use indexmap::set::IndexSet; use indexmap::set::IndexSet;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
@ -180,23 +178,15 @@ pub fn get_column_path(path: &ColumnPath, obj: &Value) -> Result<Value, ShellErr
pub fn get( pub fn get(
GetArgs { rest: mut fields }: GetArgs, GetArgs { rest: mut fields }: GetArgs,
RunnableContext { input, .. }: RunnableContext, RunnableContext { mut input, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
if fields.is_empty() { if fields.is_empty() {
let stream = async_stream! { let stream = async_stream! {
let values = input.values; let mut vec = input.drain_vec().await;
pin_mut!(values);
let mut shapes = Shapes::new(); let descs = nu_protocol::merge_descriptors(&vec);
let mut index = 0; for desc in descs {
yield ReturnSuccess::value(desc);
while let Some(row) = values.next().await {
shapes.add(&row, index);
index += 1;
}
for row in shapes.to_values() {
yield ReturnSuccess::value(row);
} }
}; };

View File

@ -1,7 +1,9 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value}; use nu_protocol::{
merge_descriptors, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue,
};
use nu_source::{SpannedItem, Tagged}; use nu_source::{SpannedItem, Tagged};
use nu_value_ext::get_data_by_key; use nu_value_ext::get_data_by_key;
@ -52,18 +54,6 @@ impl WholeStreamCommand for Pivot {
} }
} }
fn merge_descriptors(values: &[Value]) -> Vec<String> {
let mut ret = vec![];
for value in values {
for desc in value.data_descriptors() {
if !ret.contains(&desc) {
ret.push(desc);
}
}
}
ret
}
pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result<OutputStream, ShellError> { pub fn pivot(args: PivotArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
let stream = async_stream! { let stream = async_stream! {
let input = context.input.into_vec().await; let input = context.input.into_vec().await;

View File

@ -1,17 +1,11 @@
use crate::prelude::*; use crate::prelude::*;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use indexmap::IndexMap;
use nu_errors::ShellError;
use nu_protocol::RangeInclusion; use nu_protocol::RangeInclusion;
use nu_protocol::{ use nu_protocol::{format_primitive, ColumnPath, Dictionary, Primitive, UntaggedValue, Value};
format_primitive, ColumnPath, Dictionary, Evaluate, Primitive, ShellTypeName,
TaggedDictBuilder, UntaggedValue, Value,
};
use nu_source::{b, PrettyDebug}; use nu_source::{b, PrettyDebug};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
@ -193,13 +187,17 @@ impl PrettyDebug for FormatInlineShape {
"[", "[",
b::kind("row") b::kind("row")
+ b::space() + b::space()
+ b::intersperse( + if row.keys().len() <= 6 {
row.keys().map(|key| match key { b::intersperse(
Column::String(string) => b::description(string), row.keys().map(|key| match key {
Column::Value => b::blank(), Column::String(string) => b::description(string),
}), Column::Value => b::blank(),
b::space(), }),
), b::space(),
)
} else {
b::description(format!("{} columns", row.keys().len()))
},
"]", "]",
) )
.group(), .group(),
@ -269,113 +267,3 @@ impl Into<Column> for &str {
Column::String(self.to_string()) Column::String(self.to_string())
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Shape {
Primitive(&'static str),
Row(Vec<Column>),
Table { from: usize, to: usize },
Error(ShellError),
Block(Evaluate),
}
impl Shape {
pub fn for_value(value: &Value) -> Shape {
match &value.value {
UntaggedValue::Primitive(p) => Shape::Primitive(p.type_name()),
UntaggedValue::Row(row) => Shape::for_dict(row),
UntaggedValue::Table(table) => Shape::Table {
from: 0,
to: table.len(),
},
UntaggedValue::Error(error) => Shape::Error(error.clone()),
UntaggedValue::Block(block) => Shape::Block(block.clone()),
}
}
fn for_dict(dict: &Dictionary) -> Shape {
Shape::Row(dict.keys().map(|key| Column::String(key.clone())).collect())
}
pub fn describe(&self, w: &mut impl Write) -> Result<(), std::io::Error> {
match self {
Shape::Primitive(desc) => write!(w, "[{}]", desc),
Shape::Row(d) => write!(
w,
"[row: {}]",
d.iter()
.map(|c| match c {
Column::String(s) => s.clone(),
Column::Value => "<value>".to_owned(),
})
.join(", ")
),
Shape::Table { to, .. } => {
if *to == 1 {
write!(w, "[table: {} row]", to)
} else {
write!(w, "[table: {} rows]", to)
}
}
Shape::Error(_) => write!(w, "[error]"),
Shape::Block(_) => write!(w, "[block]"),
}
}
fn to_value(&self) -> Value {
let mut out = vec![];
self.describe(&mut out)
.expect("Writing into a Vec can't fail");
let string = String::from_utf8_lossy(&out);
UntaggedValue::string(string).into_untagged_value()
}
}
pub struct Shapes {
shapes: IndexMap<Shape, Vec<usize>>,
}
impl Shapes {
pub fn new() -> Shapes {
Shapes {
shapes: IndexMap::default(),
}
}
pub fn add(&mut self, value: &Value, row: usize) {
let shape = Shape::for_value(value);
self.shapes
.entry(shape)
.and_modify(|indexes| indexes.push(row))
.or_insert_with(|| vec![row]);
}
pub fn to_values(&self) -> Vec<Value> {
if self.shapes.len() == 1 {
if let Some(shape) = self.shapes.keys().nth(0) {
let mut tagged_dict = TaggedDictBuilder::new(Tag::unknown());
tagged_dict.insert_untagged("type", shape.to_value());
tagged_dict.insert_untagged("rows", UntaggedValue::string("all"));
vec![tagged_dict.into_value()]
} else {
unreachable!("Internal error: impossible state in to_values")
}
} else {
self.shapes
.iter()
.map(|(shape, rows)| {
let rows = rows.iter().map(|i| i.to_string()).join(", ");
let mut tagged_dict = TaggedDictBuilder::new(Tag::unknown());
tagged_dict.insert_untagged("type", shape.to_value());
tagged_dict
.insert_untagged("rows", UntaggedValue::string(format!("[ {} ]", rows)));
tagged_dict.into_value()
})
.collect()
}
}
}

View File

@ -1,3 +1,4 @@
use crate::cli::History;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value}; use nu_protocol::{TaggedDictBuilder, UntaggedValue, Value};
use nu_source::Tag; use nu_source::Tag;
@ -27,5 +28,24 @@ pub fn nu(tag: impl Into<Tag>) -> Result<Value, ShellError> {
} }
nu_dict.insert_value("path", UntaggedValue::table(&table).into_value(&tag)); nu_dict.insert_value("path", UntaggedValue::table(&table).into_value(&tag));
let path = std::env::current_dir()?;
nu_dict.insert_value("cwd", UntaggedValue::path(path).into_value(&tag));
if let Some(home) = dirs::home_dir() {
nu_dict.insert_value("home-dir", UntaggedValue::path(home).into_value(&tag));
}
let temp = std::env::temp_dir();
nu_dict.insert_value("temp-dir", UntaggedValue::path(temp).into_value(&tag));
let config = crate::data::config::default_path()?;
nu_dict.insert_value("config-path", UntaggedValue::path(config).into_value(&tag));
let history = History::path();
nu_dict.insert_value(
"history-path",
UntaggedValue::path(history).into_value(&tag),
);
Ok(nu_dict.into_value()) Ok(nu_dict.into_value())
} }

View File

@ -26,27 +26,6 @@ enum TableMode {
} }
impl TableView { impl TableView {
fn merge_descriptors(values: &[Value]) -> Vec<String> {
let mut ret: Vec<String> = vec![];
let value_column = "<value>".to_string();
for value in values {
let descs = value.data_descriptors();
if descs.is_empty() {
if !ret.contains(&value_column) {
ret.push("<value>".to_string());
}
} else {
for desc in value.data_descriptors() {
if !ret.contains(&desc) {
ret.push(desc);
}
}
}
}
ret
}
pub fn from_list(values: &[Value], starting_idx: usize) -> Option<TableView> { pub fn from_list(values: &[Value], starting_idx: usize) -> Option<TableView> {
if values.is_empty() { if values.is_empty() {
return None; return None;
@ -55,7 +34,7 @@ impl TableView {
// Different platforms want different amounts of buffer, not sure why // Different platforms want different amounts of buffer, not sure why
let termwidth = std::cmp::max(textwrap::termwidth(), 20); let termwidth = std::cmp::max(textwrap::termwidth(), 20);
let mut headers = TableView::merge_descriptors(values); let mut headers = nu_protocol::merge_descriptors(values);
let mut entries = values_to_entries(values, &mut headers, starting_idx); let mut entries = values_to_entries(values, &mut headers, starting_idx);
let max_per_column = max_per_column(&headers, &entries, values.len()); let max_per_column = max_per_column(&headers, &entries, values.len());

View File

@ -23,4 +23,4 @@ pub use crate::value::evaluate::{Evaluate, EvaluateTrait, Scope};
pub use crate::value::primitive::Primitive; pub use crate::value::primitive::Primitive;
pub use crate::value::primitive::{format_date, format_duration, format_primitive}; pub use crate::value::primitive::{format_date, format_duration, format_primitive};
pub use crate::value::range::{Range, RangeInclusion}; pub use crate::value::range::{Range, RangeInclusion};
pub use crate::value::{UntaggedValue, Value}; pub use crate::value::{merge_descriptors, UntaggedValue, Value};

View File

@ -378,3 +378,24 @@ impl From<ShellError> for UntaggedValue {
UntaggedValue::Error(e) UntaggedValue::Error(e)
} }
} }
pub fn merge_descriptors(values: &[Value]) -> Vec<String> {
let mut ret: Vec<String> = vec![];
let value_column = "<value>".to_string();
for value in values {
let descs = value.data_descriptors();
if descs.is_empty() {
if !ret.contains(&value_column) {
ret.push("<value>".to_string());
}
} else {
for desc in value.data_descriptors() {
if !ret.contains(&desc) {
ret.push(desc);
}
}
}
}
ret
}

View File

@ -1,27 +0,0 @@
# env
The `env` command prints to terminal the environment of nushell
This includes
- cwd : the path to the current working the directory (`cwd`),
- home : the path to the home directory
- config : the path to the config file for nushell
- history : the path to the nushell command history
- temp : the path to the temp file
- vars : descriptor variable for the table
`env` does not take any arguments, and ignores any arguments given.
## Examples -
```shell
/home/username/mynushell/docs/commands(master)> env
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━┯━━━━━━━━━━━━━━━━
cwd │ home │ config │ history │ temp │ vars
────────────────────────────────────────┼────────────────┼───────────────────────────────────────┼────────────────────────────────────────────┼──────┼────────────────
/home/username/mynushell/docs/commands │ /home/username │ /home/username/.config/nu/config.toml │ /home/username/.local/share/nu/history.txt │ /tmp │ [table: 1 row]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━┷━━━━━━━━━━━━━━━━
```