More docs and random fixes (#1237)

This commit is contained in:
Jonathan Turner 2020-01-19 08:42:36 +13:00 committed by GitHub
parent a5c5b4e711
commit 3abfefc025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 136 additions and 9 deletions

View File

@ -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<T: ShellTypeName> ShellTypeName for Spanned<T> {
/// Return the type_name of the spanned item
fn type_name(&self) -> &'static str {
self.item.type_name()
}
}
impl<T: ShellTypeName> 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<T: ShellTypeName + HasSpan> 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<T: ShellTypeName> SpannedTypeName for Tagged<T> {
/// 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;
}

View File

@ -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<RangeType>),
/// 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<Type>),
// 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<Item = &'a Value>) -> 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))
}

View File

@ -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<Value>),
// 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<Tag>) -> 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<String> {
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<Tag>) -> 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<String, Value>) -> 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<String>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::String(s.into()))
}
/// Helper for creating line values
pub fn line(s: impl Into<String>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Line(s.into()))
}
/// Helper for creating column-path values
pub fn column_path(s: Vec<impl Into<PathMember>>) -> 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<BigInt>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Int(i.into()))
}
/// Helper for creating glob pattern values
pub fn pattern(s: impl Into<String>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::String(s.into()))
}
/// Helper for creating filepath values
pub fn path(s: impl Into<PathBuf>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Path(s.into()))
}
/// Helper for creating bytesize values
pub fn bytes(s: impl Into<u64>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Bytes(s.into()))
}
/// Helper for creating decimal values
pub fn decimal(s: impl Into<BigDecimal>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Decimal(s.into()))
}
/// Helper for creating binary (non-text) buffer values
pub fn binary(binary: Vec<u8>) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::Binary(binary))
}
/// Helper for creating range values
pub fn range(
left: (Spanned<Primitive>, RangeInclusion),
right: (Spanned<Primitive>, 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<bool>) -> 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<AnchorLocation> {
self.tag.anchor()
}
/// Get the name (url, filepath, etc) behind an anchor for the Value
pub fn anchor_name(&self) -> Option<String> {
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<String, ShellError> {
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<PathBuf, ShellError> {
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<Primitive, ShellError> {
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<u64, ShellError> {
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<bool, ShellError> {
match &self.value {
UntaggedValue::Primitive(Primitive::Boolean(p)) => Ok(*p),
@ -253,17 +295,20 @@ impl Value {
}
impl Into<UntaggedValue> for &str {
/// Convert a string slice into an UntaggedValue
fn into(self) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::String(self.to_string()))
}
}
impl Into<UntaggedValue> 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<Primitive> for UntaggedValue {
/// Convert a Primitive to an UntaggedValue
fn from(input: Primitive) -> UntaggedValue {
UntaggedValue::Primitive(input)
}
}
impl From<String> for UntaggedValue {
/// Convert a String to an UntaggedValue
fn from(input: String) -> UntaggedValue {
UntaggedValue::Primitive(Primitive::String(input))
}

View File

@ -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<T> {
pub span: Span,
@ -30,6 +32,7 @@ pub struct Spanned<T> {
}
impl<T> Spanned<T> {
/// Allows mapping over a Spanned value
pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Spanned<U> {
let span = self.span;
@ -39,6 +42,7 @@ impl<T> Spanned<T> {
}
impl Spanned<String> {
/// Iterates over the contained String
pub fn items<'a, U>(
items: impl Iterator<Item = &'a Spanned<String>>,
) -> impl Iterator<Item = &'a str> {
@ -47,6 +51,7 @@ impl Spanned<String> {
}
impl Spanned<String> {
/// 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<String> {
}
pub trait SpannedItem: Sized {
/// Converts a value into a Spanned value
fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
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<Self> {
Spanned {
item: self,
@ -73,11 +80,13 @@ impl<T> SpannedItem for T {}
impl<T> std::ops::Deref for Spanned<T> {
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<T> {
pub tag: Tag,
@ -85,29 +94,34 @@ pub struct Tagged<T> {
}
impl Tagged<String> {
/// 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<T> Tagged<Vec<T>> {
/// Iterates over the contained value(s)
pub fn items(&self) -> impl Iterator<Item = &T> {
self.item.iter()
}
}
impl<T> HasTag for Tagged<T> {
/// Helper for getting the Tag from the Tagged value
fn tag(&self) -> Tag {
self.tag.clone()
}
}
impl AsRef<Path> for Tagged<PathBuf> {
/// Gets the reference to the contained Path
fn as_ref(&self) -> &Path {
self.item.as_ref()
}

View File

@ -226,6 +226,21 @@ impl History {
}
}
fn create_default_starship_config() -> Option<toml::Value> {
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<dyn Error>> {
let mut context = Context::basic()?;
@ -404,10 +419,19 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
#[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"))]
{

View File

@ -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() {