diff --git a/crates/nu-protocol/src/type_name.rs b/crates/nu-protocol/src/type_name.rs index b9d6344c0e..0020e68157 100644 --- a/crates/nu-protocol/src/type_name.rs +++ b/crates/nu-protocol/src/type_name.rs @@ -1,37 +1,44 @@ use nu_source::{DebugDocBuilder, HasSpan, Spanned, SpannedItem, Tagged}; +/// A trait that allows structures to define a known .type_name() which pretty-prints the type pub trait ShellTypeName { fn type_name(&self) -> &'static str; } impl ShellTypeName for Spanned { + /// Return the type_name of the spanned item fn type_name(&self) -> &'static str { self.item.type_name() } } impl ShellTypeName for &T { + /// Return the type_name for the borrowed reference fn type_name(&self) -> &'static str { (*self).type_name() } } +/// A trait that allows structures to define a known way to return a spanned type name pub trait SpannedTypeName { fn spanned_type_name(&self) -> Spanned<&'static str>; } impl SpannedTypeName for T { + /// Return the type name as a spanned string fn spanned_type_name(&self) -> Spanned<&'static str> { self.type_name().spanned(self.span()) } } impl SpannedTypeName for Tagged { + /// Return the spanned type name for a Tagged value fn spanned_type_name(&self) -> Spanned<&'static str> { self.item.type_name().spanned(self.tag.span) } } +/// A trait to enable pretty-printing of type information pub trait PrettyType { fn pretty_type(&self) -> DebugDocBuilder; } diff --git a/crates/nu-protocol/src/type_shape.rs b/crates/nu-protocol/src/type_shape.rs index c43f1f06eb..c3881ca36f 100644 --- a/crates/nu-protocol/src/type_shape.rs +++ b/crates/nu-protocol/src/type_shape.rs @@ -15,42 +15,62 @@ use std::collections::BTreeMap; use std::fmt::Debug; use std::hash::Hash; +/// Representation of the type of ranges #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize, new)] pub struct RangeType { from: (Type, RangeInclusion), to: (Type, RangeInclusion), } +/// Representation of for the type of a value in Nu #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum Type { + /// A value which has no value Nothing, + /// An integer-based value Int, + /// A range between two values Range(Box), + /// A decimal (floating point) value Decimal, + /// A filesize in bytes Bytesize, + /// A string of text String, + /// A line of text (a string with trailing line ending) Line, + /// A path through a table ColumnPath, + /// A glob pattern (like foo*) Pattern, + /// A boolean value Boolean, + /// A date value (in UTC) Date, + /// A data duration value Duration, + /// A filepath value Path, + /// A binary (non-text) buffer value Binary, + /// A row of data Row(Row), + /// A full table of data Table(Vec), - // TODO: Block arguments + /// A block of script (TODO) Block, - // TODO: Error type + /// An error value (TODO) Error, - // Stream markers (used as bookend markers rather than actual values) + /// Beginning of stream marker (used as bookend markers rather than actual values) BeginningOfStream, + /// End of stream marker (used as bookend markers rather than actual values) EndOfStream, } +/// A shape representation of the type of a row #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, new)] pub struct Row { #[new(default)] @@ -102,6 +122,7 @@ impl<'de> Deserialize<'de> for Row { } impl Type { + /// Convert a Primitive into its corresponding Type pub fn from_primitive(primitive: &Primitive) -> Type { match primitive { Primitive::Nothing => Type::Nothing, @@ -132,6 +153,7 @@ impl Type { } } + /// Convert a dictionary into its corresponding row Type pub fn from_dictionary(dictionary: &Dictionary) -> Type { let mut map = BTreeMap::new(); @@ -143,6 +165,7 @@ impl Type { Type::Row(Row { map }) } + /// Convert a table into its corresponding Type pub fn from_table<'a>(table: impl IntoIterator) -> Type { let mut vec = vec![]; @@ -153,6 +176,7 @@ impl Type { Type::Table(vec) } + /// Convert a value into its corresponding Type pub fn from_value<'a>(value: impl Into<&'a UntaggedValue>) -> Type { match value.into() { UntaggedValue::Primitive(p) => Type::from_primitive(p), @@ -165,6 +189,7 @@ impl Type { } impl PrettyDebug for Type { + /// Prepare Type for pretty-printing fn pretty(&self) -> DebugDocBuilder { match self { Type::Nothing => ty("nothing"), @@ -266,6 +291,7 @@ impl PrettyDebug for Type { } } +/// A view into dictionaries for debug purposes #[derive(Debug, new)] struct DebugEntry<'a> { key: &'a Column, @@ -273,6 +299,7 @@ struct DebugEntry<'a> { } impl<'a> PrettyDebug for DebugEntry<'a> { + /// Prepare debug entries for pretty-printing fn pretty(&self) -> DebugDocBuilder { (b::key(match self.key { Column::String(string) => string.clone(), @@ -281,6 +308,7 @@ impl<'a> PrettyDebug for DebugEntry<'a> { } } +/// Helper to create a pretty-print for the type fn ty(name: impl std::fmt::Display) -> DebugDocBuilder { b::kind(format!("{}", name)) } diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index ff586b481b..27c4b5ad6d 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -23,19 +23,25 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; use std::time::SystemTime; +/// The core structured values that flow through a pipeline #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] pub enum UntaggedValue { + /// A primitive (or fundamental) type of values Primitive(Primitive), + /// A table row Row(Dictionary), + /// A full inner (or embedded) table Table(Vec), - // Errors are a type of value too + /// An error value that represents an error that occurred as the values in the pipeline were built Error(ShellError), + /// A block of Nu code, eg `{ ls | get name }` Block(Evaluate), } impl UntaggedValue { + /// Tags an UntaggedValue so that it can become a Value pub fn retag(self, tag: impl Into) -> Value { Value { value: self, @@ -43,6 +49,7 @@ impl UntaggedValue { } } + /// Get the corresponding descriptors (column names) associated with this value pub fn data_descriptors(&self) -> Vec { match self { UntaggedValue::Primitive(_) => vec![], @@ -53,6 +60,7 @@ impl UntaggedValue { } } + /// Convert this UntaggedValue to a Value with the given Tag pub fn into_value(self, tag: impl Into) -> Value { Value { value: self, @@ -60,6 +68,7 @@ impl UntaggedValue { } } + /// Convert this UntaggedValue into a Value with an empty Tag pub fn into_untagged_value(self) -> Value { Value { value: self, @@ -67,6 +76,7 @@ impl UntaggedValue { } } + /// Returns true if this value represents boolean true pub fn is_true(&self) -> bool { match self { UntaggedValue::Primitive(Primitive::Boolean(true)) => true, @@ -74,10 +84,12 @@ impl UntaggedValue { } } + /// Returns true if the value represents something other than Nothing pub fn is_some(&self) -> bool { !self.is_none() } + /// Returns true if the value represents Nothing pub fn is_none(&self) -> bool { match self { UntaggedValue::Primitive(Primitive::Nothing) => true, @@ -85,6 +97,7 @@ impl UntaggedValue { } } + /// Returns true if the value represents an error pub fn is_error(&self) -> bool { match self { UntaggedValue::Error(_err) => true, @@ -92,6 +105,7 @@ impl UntaggedValue { } } + /// Expect this value to be an error and return it pub fn expect_error(&self) -> ShellError { match self { UntaggedValue::Error(err) => err.clone(), @@ -99,6 +113,7 @@ impl UntaggedValue { } } + /// Expect this value to be a string and return it pub fn expect_string(&self) -> &str { match self { UntaggedValue::Primitive(Primitive::String(string)) => &string[..], @@ -106,53 +121,65 @@ impl UntaggedValue { } } + /// Helper for creating row values #[allow(unused)] pub fn row(entries: IndexMap) -> UntaggedValue { UntaggedValue::Row(entries.into()) } + /// Helper for creating table values pub fn table(list: &[Value]) -> UntaggedValue { UntaggedValue::Table(list.to_vec()) } + /// Helper for creating string values pub fn string(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::String(s.into())) } + /// Helper for creating line values pub fn line(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Line(s.into())) } + /// Helper for creating column-path values pub fn column_path(s: Vec>) -> UntaggedValue { UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new( s.into_iter().map(|p| p.into()).collect(), ))) } + /// Helper for creating integer values pub fn int(i: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Int(i.into())) } + /// Helper for creating glob pattern values pub fn pattern(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::String(s.into())) } + /// Helper for creating filepath values pub fn path(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Path(s.into())) } + /// Helper for creating bytesize values pub fn bytes(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Bytes(s.into())) } + /// Helper for creating decimal values pub fn decimal(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Decimal(s.into())) } + /// Helper for creating binary (non-text) buffer values pub fn binary(binary: Vec) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Binary(binary)) } + /// Helper for creating range values pub fn range( left: (Spanned, RangeInclusion), right: (Spanned, RangeInclusion), @@ -160,29 +187,35 @@ impl UntaggedValue { UntaggedValue::Primitive(Primitive::Range(Box::new(Range::new(left, right)))) } + /// Helper for creating boolean values pub fn boolean(s: impl Into) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Boolean(s.into())) } + /// Helper for creating date duration values pub fn duration(secs: u64) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Duration(secs)) } + /// Helper for creating datatime values pub fn system_date(s: SystemTime) -> UntaggedValue { UntaggedValue::Primitive(Primitive::Date(s.into())) } + /// Helper for creating the Nothing value pub fn nothing() -> UntaggedValue { UntaggedValue::Primitive(Primitive::Nothing) } } +/// The fundamental structured value that flows through the pipeline, with associated metadata #[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq, Hash, Serialize, Deserialize)] pub struct Value { pub value: UntaggedValue, pub tag: Tag, } +/// Overload deferencing to give back the UntaggedValue inside of a Value impl std::ops::Deref for Value { type Target = UntaggedValue; @@ -192,18 +225,22 @@ impl std::ops::Deref for Value { } impl Value { + /// Get the corresponding anchor (originating location) for the Value pub fn anchor(&self) -> Option { self.tag.anchor() } + /// Get the name (url, filepath, etc) behind an anchor for the Value pub fn anchor_name(&self) -> Option { self.tag.anchor_name() } + /// Get the metadata for the Value pub fn tag(&self) -> Tag { self.tag.clone() } + /// View the Value as a string, if possible pub fn as_string(&self) -> Result { match &self.value { UntaggedValue::Primitive(Primitive::String(string)) => Ok(string.clone()), @@ -212,6 +249,7 @@ impl Value { } } + /// View into the borrowed string contents of a Value, if possible pub fn as_forgiving_string(&self) -> Result<&str, ShellError> { match &self.value { UntaggedValue::Primitive(Primitive::String(string)) => Ok(&string[..]), @@ -219,6 +257,7 @@ impl Value { } } + /// View the Value as a path, if possible pub fn as_path(&self) -> Result { match &self.value { UntaggedValue::Primitive(Primitive::Path(path)) => Ok(path.clone()), @@ -227,6 +266,7 @@ impl Value { } } + /// View the Value as a Primitive value, if possible pub fn as_primitive(&self) -> Result { match &self.value { UntaggedValue::Primitive(primitive) => Ok(primitive.clone()), @@ -237,6 +277,7 @@ impl Value { } } + /// View the Value as unsigned 64-bit, if possible pub fn as_u64(&self) -> Result { match &self.value { UntaggedValue::Primitive(primitive) => primitive.as_u64(self.tag.span), @@ -244,6 +285,7 @@ impl Value { } } + /// View the Value as boolean, if possible pub fn as_bool(&self) -> Result { match &self.value { UntaggedValue::Primitive(Primitive::Boolean(p)) => Ok(*p), @@ -253,17 +295,20 @@ impl Value { } impl Into for &str { + /// Convert a string slice into an UntaggedValue fn into(self) -> UntaggedValue { UntaggedValue::Primitive(Primitive::String(self.to_string())) } } impl Into for Value { + /// Convert a Value into an UntaggedValue fn into(self) -> UntaggedValue { self.value } } +/// Convert a borrowed Value into a borrowed UntaggedValue impl<'a> Into<&'a UntaggedValue> for &'a Value { fn into(self) -> &'a UntaggedValue { &self.value @@ -271,18 +316,21 @@ impl<'a> Into<&'a UntaggedValue> for &'a Value { } impl HasSpan for Value { + /// Return the corresponding Span for the Value fn span(&self) -> Span { self.tag.span } } impl ShellTypeName for Value { + /// Get the type name for the Value fn type_name(&self) -> &'static str { ShellTypeName::type_name(&self.value) } } impl ShellTypeName for UntaggedValue { + /// Get the type name for the UntaggedValue fn type_name(&self) -> &'static str { match &self { UntaggedValue::Primitive(p) => p.type_name(), @@ -295,12 +343,14 @@ impl ShellTypeName for UntaggedValue { } impl From for UntaggedValue { + /// Convert a Primitive to an UntaggedValue fn from(input: Primitive) -> UntaggedValue { UntaggedValue::Primitive(input) } } impl From for UntaggedValue { + /// Convert a String to an UntaggedValue fn from(input: String) -> UntaggedValue { UntaggedValue::Primitive(Primitive::String(input)) } diff --git a/crates/nu-source/src/meta.rs b/crates/nu-source/src/meta.rs index 454b665769..bfd262acbe 100644 --- a/crates/nu-source/src/meta.rs +++ b/crates/nu-source/src/meta.rs @@ -20,9 +20,11 @@ pub enum AnchorLocation { } pub trait HasTag { + /// Get the associated metadata fn tag(&self) -> Tag; } +/// A wrapper type that attaches a Span to a value #[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Spanned { pub span: Span, @@ -30,6 +32,7 @@ pub struct Spanned { } impl Spanned { + /// Allows mapping over a Spanned value pub fn map(self, input: impl FnOnce(T) -> U) -> Spanned { let span = self.span; @@ -39,6 +42,7 @@ impl Spanned { } impl Spanned { + /// Iterates over the contained String pub fn items<'a, U>( items: impl Iterator>, ) -> impl Iterator { @@ -47,6 +51,7 @@ impl Spanned { } impl Spanned { + /// Borrows the contained String pub fn borrow_spanned(&self) -> Spanned<&str> { let span = self.span; self.item[..].spanned(span) @@ -54,6 +59,7 @@ impl Spanned { } pub trait SpannedItem: Sized { + /// Converts a value into a Spanned value fn spanned(self, span: impl Into) -> Spanned { Spanned { item: self, @@ -61,6 +67,7 @@ pub trait SpannedItem: Sized { } } + /// Converts a value into a Spanned value, using an unknown Span fn spanned_unknown(self) -> Spanned { Spanned { item: self, @@ -73,11 +80,13 @@ impl SpannedItem for T {} impl std::ops::Deref for Spanned { type Target = T; + /// Shorthand to deref to the contained value fn deref(&self) -> &T { &self.item } } +/// A wrapper type that attaches a Tag to a value #[derive(new, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Tagged { pub tag: Tag, @@ -85,29 +94,34 @@ pub struct Tagged { } impl Tagged { + /// Allows borrowing the contained string slice as a spanned value pub fn borrow_spanned(&self) -> Spanned<&str> { let span = self.tag.span; self.item[..].spanned(span) } + /// Allows borrowing the contained string slice as a tagged value pub fn borrow_tagged(&self) -> Tagged<&str> { self.item[..].tagged(self.tag.clone()) } } impl Tagged> { + /// Iterates over the contained value(s) pub fn items(&self) -> impl Iterator { self.item.iter() } } impl HasTag for Tagged { + /// Helper for getting the Tag from the Tagged value fn tag(&self) -> Tag { self.tag.clone() } } impl AsRef for Tagged { + /// Gets the reference to the contained Path fn as_ref(&self) -> &Path { self.item.as_ref() } diff --git a/src/cli.rs b/src/cli.rs index 3191c7055c..28f85498ef 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -226,6 +226,21 @@ impl History { } } +fn create_default_starship_config() -> Option { + let mut map = toml::value::Table::new(); + map.insert("add_newline".into(), toml::Value::Boolean(false)); + + let mut git_branch = toml::value::Table::new(); + git_branch.insert("symbol".into(), toml::Value::String("📙 ".into())); + map.insert("git_branch".into(), toml::Value::Table(git_branch)); + + let mut git_status = toml::value::Table::new(); + git_status.insert("disabled".into(), toml::Value::Boolean(true)); + map.insert("git_status".into(), toml::Value::Table(git_status)); + + Some(toml::Value::Table(map)) +} + /// The entry point for the CLI. Will register all known internal commands, load experimental commands, load plugins, then prepare the prompt and line reader for input. pub async fn cli() -> Result<(), Box> { let mut context = Context::basic()?; @@ -404,10 +419,19 @@ pub async fn cli() -> Result<(), Box> { #[cfg(feature = "starship-prompt")] { std::env::set_var("STARSHIP_SHELL", ""); - starship::print::get_prompt(starship::context::Context::new_with_dir( - clap::ArgMatches::default(), - cwd, - )) + let mut starship_context = + starship::context::Context::new_with_dir(clap::ArgMatches::default(), cwd); + + match starship_context.config.config { + None => { + starship_context.config.config = create_default_starship_config(); + } + Some(toml::Value::Table(t)) if t.is_empty() => { + starship_context.config.config = create_default_starship_config(); + } + _ => {} + }; + starship::print::get_prompt(starship_context) } #[cfg(not(feature = "starship-prompt"))] { diff --git a/src/data/files.rs b/src/data/files.rs index 689efa30a5..89ae02c35d 100644 --- a/src/data/files.rs +++ b/src/data/files.rs @@ -48,7 +48,11 @@ pub(crate) fn dir_entry_dict( } } - dict.insert_untagged("size", UntaggedValue::bytes(metadata.len() as u64)); + if metadata.is_file() { + dict.insert_untagged("size", UntaggedValue::bytes(metadata.len() as u64)); + } else { + dict.insert_untagged("size", UntaggedValue::bytes(0u64)); + } if full { if let Ok(c) = metadata.created() {