diff --git a/crates/nu-protocol/src/call_info.rs b/crates/nu-protocol/src/call_info.rs index d5be3ff245..b231248d8e 100644 --- a/crates/nu-protocol/src/call_info.rs +++ b/crates/nu-protocol/src/call_info.rs @@ -5,12 +5,16 @@ use nu_errors::ShellError; use nu_source::Tag; use serde::{Deserialize, Serialize}; +/// Associated information for the call of a command, including the args passed to the command and a tag that spans the name of the command being called #[derive(Deserialize, Serialize, Debug, Clone)] pub struct CallInfo { pub args: EvaluatedArgs, pub name_tag: Tag, } +/// The set of positional and named arguments, after their values have been evaluated. +/// Positional arguments are those who are given as values, without any associated flag. For example, in `foo arg1 arg2`, both `arg1` and `arg2` are positional arguments +/// Named arguments are those associated with a flag. For example, `foo --given bar` the named argument would be name `given` and the value `bar`. #[derive(Debug, Default, new, Serialize, Deserialize, Clone)] pub struct EvaluatedArgs { pub positional: Option>, @@ -18,6 +22,7 @@ pub struct EvaluatedArgs { } impl EvaluatedArgs { + /// Retrieve a subset of positional arguments starting at a given position pub fn slice_from(&self, from: usize) -> Vec { let positional = &self.positional; @@ -27,6 +32,7 @@ impl EvaluatedArgs { } } + /// Get the nth positional argument, if possible pub fn nth(&self, pos: usize) -> Option<&Value> { match &self.positional { None => None, @@ -34,6 +40,7 @@ impl EvaluatedArgs { } } + /// Get the nth positional argument, error if not possible pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> { match &self.positional { None => Err(ShellError::unimplemented("Better error: expect_nth")), @@ -44,6 +51,7 @@ impl EvaluatedArgs { } } + /// Get the number of positional arguments available pub fn len(&self) -> usize { match &self.positional { None => 0, @@ -51,10 +59,12 @@ impl EvaluatedArgs { } } + /// Return if there are no positional arguments pub fn is_empty(&self) -> bool { self.len() == 0 } + /// Return true if the set of named arguments contains the name provided pub fn has(&self, name: &str) -> bool { match &self.named { None => false, @@ -62,6 +72,7 @@ impl EvaluatedArgs { } } + /// Gets the corresponding Value for the named argument given, if possible pub fn get(&self, name: &str) -> Option<&Value> { match &self.named { None => None, @@ -69,6 +80,7 @@ impl EvaluatedArgs { } } + /// Iterates over the positional arguments pub fn positional_iter(&self) -> PositionalIter<'_> { match &self.positional { None => PositionalIter::Empty, @@ -80,6 +92,7 @@ impl EvaluatedArgs { } } +/// An iterator to help iterate over positional arguments pub enum PositionalIter<'a> { Empty, Array(std::slice::Iter<'a, Value>), @@ -88,6 +101,7 @@ pub enum PositionalIter<'a> { impl<'a> Iterator for PositionalIter<'a> { type Item = &'a Value; + /// The required `next` function to implement the Iterator trait fn next(&mut self) -> Option { match self { PositionalIter::Empty => None, diff --git a/crates/nu-protocol/src/maybe_owned.rs b/crates/nu-protocol/src/maybe_owned.rs index 5c48dc0225..10c57cb387 100644 --- a/crates/nu-protocol/src/maybe_owned.rs +++ b/crates/nu-protocol/src/maybe_owned.rs @@ -1,5 +1,6 @@ #![allow(clippy::should_implement_trait)] +/// Helper type to allow passing something that may potentially be owned, but could also be borrowed #[derive(Debug)] pub enum MaybeOwned<'a, T> { Owned(T), @@ -7,6 +8,7 @@ pub enum MaybeOwned<'a, T> { } impl MaybeOwned<'_, T> { + /// Allows the borrowing of an owned value or passes out the borrowed value pub fn borrow(&self) -> &T { match self { MaybeOwned::Owned(v) => v, diff --git a/crates/nu-protocol/src/return_value.rs b/crates/nu-protocol/src/return_value.rs index b35a4c269f..c439579791 100644 --- a/crates/nu-protocol/src/return_value.rs +++ b/crates/nu-protocol/src/return_value.rs @@ -3,21 +3,33 @@ use nu_errors::ShellError; use nu_source::{b, DebugDocBuilder, PrettyDebug}; use serde::{Deserialize, Serialize}; +/// The inner set of actions for the command processor. Each denotes a way to change state in the processor without changing it directly from the command itself. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum CommandAction { + /// Change to a new directory or path (in non-filesystem situations) ChangePath(String), + /// Exit out of Nu Exit, + /// Display an error Error(ShellError), + /// Enter a new shell at the given path EnterShell(String), + /// Convert the value given from one type to another AutoConvert(Value, String), + /// Enter a value shell, one that allows exploring inside of a Value EnterValueShell(Value), + /// Enter the help shell, which allows exploring the help system EnterHelpShell(Value), + /// Go to the previous shell in the shell ring buffer PreviousShell, + /// Go to the next shell in the shell ring buffer NextShell, + /// Leave the current shell. If it's the last shell, exit out of Nu LeaveShell, } impl PrettyDebug for CommandAction { + /// Get a command action ready to be pretty-printed fn pretty(&self) -> DebugDocBuilder { match self { CommandAction::ChangePath(path) => b::typed("change path", b::description(path)), @@ -36,14 +48,19 @@ impl PrettyDebug for CommandAction { } } +/// The fundamental success type in the pipeline. Commands return these values as their main responsibility #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ReturnSuccess { + /// A value to be used or shown to the user Value(Value), + /// A debug-enabled value to be used or shown to the user DebugValue(Value), + /// An action to be performed as values pass out of the command. These are performed rather than passed to the next command in the pipeline Action(CommandAction), } impl PrettyDebug for ReturnSuccess { + /// Get a return success ready to be pretty-printed fn pretty(&self) -> DebugDocBuilder { match self { ReturnSuccess::Value(value) => b::typed("value", value.pretty()), @@ -53,15 +70,18 @@ impl PrettyDebug for ReturnSuccess { } } +/// The core Result type for pipelines pub type ReturnValue = Result; impl Into for Value { + /// Lift a Value into a ReturnValue fn into(self) -> ReturnValue { Ok(ReturnSuccess::Value(self)) } } impl ReturnSuccess { + /// Get to the contained Value, if possible pub fn raw_value(&self) -> Option { match self { ReturnSuccess::Value(raw) => Some(raw.clone()), @@ -70,18 +90,22 @@ impl ReturnSuccess { } } + /// Helper function for an action to change the the path pub fn change_cwd(path: String) -> ReturnValue { Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) } + /// Helper function to create simple values for returning pub fn value(input: impl Into) -> ReturnValue { Ok(ReturnSuccess::Value(input.into())) } + /// Helper function to create simple debug-enabled values for returning pub fn debug_value(input: impl Into) -> ReturnValue { Ok(ReturnSuccess::DebugValue(input.into())) } + /// Helper function for creating actions pub fn action(input: CommandAction) -> ReturnValue { Ok(ReturnSuccess::Action(input)) } diff --git a/crates/nu-protocol/src/value/dict.rs b/crates/nu-protocol/src/value/dict.rs index 03217fca51..c1f4d5350f 100644 --- a/crates/nu-protocol/src/value/dict.rs +++ b/crates/nu-protocol/src/value/dict.rs @@ -187,6 +187,7 @@ impl TaggedDictBuilder { builder.into_value() } + /// Create a new builder with a pre-defined capacity pub fn with_capacity(tag: impl Into, n: usize) -> TaggedDictBuilder { TaggedDictBuilder { tag: tag.into(), @@ -194,30 +195,36 @@ impl TaggedDictBuilder { } } + /// Insert an untagged key/value pair into the dictionary, to later be tagged when built pub fn insert_untagged(&mut self, key: impl Into, value: impl Into) { self.dict .insert(key.into(), value.into().into_value(&self.tag)); } + /// Insert a key/value pair into the dictionary pub fn insert_value(&mut self, key: impl Into, value: impl Into) { self.dict.insert(key.into(), value.into()); } + /// Convert the dictionary into a tagged Value using the original tag pub fn into_value(self) -> Value { let tag = self.tag.clone(); self.into_untagged_value().into_value(tag) } + /// Convert the dictionary into an UntaggedValue pub fn into_untagged_value(self) -> UntaggedValue { UntaggedValue::Row(Dictionary { entries: self.dict }) } + /// Returns true if the dictionary is empty, false otherwise pub fn is_empty(&self) -> bool { self.dict.is_empty() } } impl From for Value { + /// Convert a builder into a tagged Value fn from(input: TaggedDictBuilder) -> Value { input.into_value() } diff --git a/crates/nu-protocol/src/value/evaluate.rs b/crates/nu-protocol/src/value/evaluate.rs index 9dea813809..2a95db1403 100644 --- a/crates/nu-protocol/src/value/evaluate.rs +++ b/crates/nu-protocol/src/value/evaluate.rs @@ -6,6 +6,9 @@ use serde::{Deserialize, Serialize}; use std::cmp::{Ord, Ordering, PartialOrd}; use std::fmt::Debug; +/// An evaluation scope. Scopes map variable names to Values and aid in evaluating blocks and expressions. +/// Additionally, holds the value for the special $it variable, a variable used to refer to the value passing +/// through the pipeline at that moment #[derive(Debug)] pub struct Scope { pub it: Value, @@ -13,6 +16,7 @@ pub struct Scope { } impl Scope { + /// Create a new scope pub fn new(it: Value) -> Scope { Scope { it, @@ -22,6 +26,7 @@ impl Scope { } impl Scope { + /// Create an empty scope pub fn empty() -> Scope { Scope { it: UntaggedValue::Primitive(Primitive::Nothing).into_untagged_value(), @@ -29,6 +34,7 @@ impl Scope { } } + /// Create an empty scope, setting $it to a known Value pub fn it_value(value: Value) -> Scope { Scope { it: value, diff --git a/crates/nu-protocol/src/value/primitive.rs b/crates/nu-protocol/src/value/primitive.rs index dd2d32eae4..d3a3c41643 100644 --- a/crates/nu-protocol/src/value/primitive.rs +++ b/crates/nu-protocol/src/value/primitive.rs @@ -11,32 +11,52 @@ use num_traits::cast::{FromPrimitive, ToPrimitive}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; +/// The most fundamental of structured values in Nu are the Primitive values. These values represent types like integers, strings, booleans, dates, etc that are then used +/// as the buildig blocks to build up more complex structures. +/// +/// Primitives also include marker values BeginningOfStream and EndOfStream which denote a change of condition in the stream #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize)] pub enum Primitive { + /// An empty value Nothing, + /// A "big int", an integer with arbitrarily large size (aka not limited to 64-bit) #[serde(with = "serde_bigint")] Int(BigInt), + /// A "big decimal", an decimal number with arbitrarily large size (aka not limited to 64-bit) #[serde(with = "serde_bigdecimal")] Decimal(BigDecimal), + /// A count in the number of bytes, used as a filesize Bytes(u64), + /// A string value String(String), + /// A string value with an implied carriage return (or cr/lf) ending Line(String), + /// A path to travel to reach a value in a table ColumnPath(ColumnPath), + /// A glob pattern, eg foo* Pattern(String), + /// A boolean value Boolean(bool), + /// A date value, in UTC Date(DateTime), - Duration(u64), // Duration in seconds + /// A count in the number of seconds + Duration(u64), + /// A range of values Range(Box), + /// A file path Path(PathBuf), + /// A vector of raw binary data #[serde(with = "serde_bytes")] Binary(Vec), - // Stream markers (used as bookend markers rather than actual values) + /// Beginning of stream marker, a pseudo-value not intended for tables BeginningOfStream, + /// End of stream marker, a pseudo-value not intended for tables EndOfStream, } impl Primitive { + /// Converts a primitive value to a u64, if possible. Uses a span to build an error if the conversion isn't possible. pub fn as_u64(&self, span: Span) -> Result { match self { Primitive::Int(int) => match int.to_u64() { @@ -56,12 +76,14 @@ impl Primitive { } impl From for Primitive { + /// Helper to convert from decimals to a Primitive value fn from(decimal: BigDecimal) -> Primitive { Primitive::Decimal(decimal) } } impl From for Primitive { + /// Helper to convert from 64-bit float to a Primitive value fn from(float: f64) -> Primitive { if let Some(f) = BigDecimal::from_f64(float) { Primitive::Decimal(f) @@ -72,6 +94,7 @@ impl From for Primitive { } impl ShellTypeName for Primitive { + /// Get the name of the type of a Primitive value fn type_name(&self) -> &'static str { match self { Primitive::Nothing => "nothing", @@ -94,6 +117,7 @@ impl ShellTypeName for Primitive { } } +/// Format a Primitive value into a string pub fn format_primitive(primitive: &Primitive, field_name: Option<&String>) -> String { match primitive { Primitive::Nothing => String::new(), @@ -157,6 +181,7 @@ pub fn format_primitive(primitive: &Primitive, field_name: Option<&String>) -> S } } +/// Format a duration in seconds into a string pub fn format_duration(sec: u64) -> String { let (minutes, seconds) = (sec / 60, sec % 60); let (hours, minutes) = (minutes / 60, minutes % 60); @@ -171,6 +196,7 @@ pub fn format_duration(sec: u64) -> String { } } +/// Format a UTC date value into a humanized string (eg "1 week ago" instead of a formal date string) pub fn format_date(d: &DateTime) -> String { let utc: DateTime = Utc::now(); diff --git a/crates/nu-protocol/src/value/range.rs b/crates/nu-protocol/src/value/range.rs index 8f153970c2..ab60b1f362 100644 --- a/crates/nu-protocol/src/value/range.rs +++ b/crates/nu-protocol/src/value/range.rs @@ -3,6 +3,8 @@ use derive_new::new; use nu_source::{b, DebugDocBuilder, Spanned}; use serde::{Deserialize, Serialize}; +/// The two types of ways to include a range end. Inclusive means to include the value (eg 1..3 inclusive would include the 3 value). +/// Exclusive excludes the value (eg 1..3 exclusive does not include 3 value) #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] pub enum RangeInclusion { Inclusive, @@ -10,6 +12,7 @@ pub enum RangeInclusion { } impl RangeInclusion { + /// Get a RangeInclusion left bracket ready for pretty printing pub fn debug_left_bracket(self) -> DebugDocBuilder { b::delimiter(match self { RangeInclusion::Exclusive => "(", @@ -17,6 +20,7 @@ impl RangeInclusion { }) } + /// Get a RangeInclusion right bracket ready for pretty printing pub fn debug_right_bracket(self) -> DebugDocBuilder { b::delimiter(match self { RangeInclusion::Exclusive => ")", @@ -25,6 +29,7 @@ impl RangeInclusion { } } +/// The range definition, holding the starting and end point of the range #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize, new)] pub struct Range { pub from: (Spanned, RangeInclusion), diff --git a/crates/nu-protocol/src/value/serde_bigdecimal.rs b/crates/nu-protocol/src/value/serde_bigdecimal.rs index d7dd1ab626..0bc407f232 100644 --- a/crates/nu-protocol/src/value/serde_bigdecimal.rs +++ b/crates/nu-protocol/src/value/serde_bigdecimal.rs @@ -2,6 +2,7 @@ use bigdecimal::BigDecimal; use num_traits::cast::FromPrimitive; use num_traits::cast::ToPrimitive; +/// Enable big decimal serialization by providing a `serialize` function pub fn serialize(big_decimal: &BigDecimal, serializer: S) -> Result where S: serde::Serializer, @@ -14,6 +15,7 @@ where ) } +/// Enable big decimal deserialization by providing a `deserialize` function pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, diff --git a/crates/nu-protocol/src/value/serde_bigint.rs b/crates/nu-protocol/src/value/serde_bigint.rs index be66ffb769..c9c05bd57b 100644 --- a/crates/nu-protocol/src/value/serde_bigint.rs +++ b/crates/nu-protocol/src/value/serde_bigint.rs @@ -2,6 +2,7 @@ use num_bigint::BigInt; use num_traits::cast::FromPrimitive; use num_traits::cast::ToPrimitive; +/// Enable big int serialization by providing a `serialize` function pub fn serialize(big_int: &BigInt, serializer: S) -> Result where S: serde::Serializer, @@ -14,6 +15,7 @@ where ) } +/// Enable big int deserialization by providing a `deserialize` function pub fn deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>,