Move us away from mixing OOP and spreadsheet to just spreadsheet

This commit is contained in:
Jonathan Turner 2019-09-05 04:29:49 +12:00
parent 4591397fa3
commit 0a9897c5ca
14 changed files with 69 additions and 66 deletions

View File

@ -90,7 +90,7 @@ The second container is a bit smaller, if size is important to you.
# Philosophy
Nu draws inspiration from projects like PowerShell, functional programming languages, and modern cli tools. Rather than thinking of files and services as raw streams of text, Nu looks at each input as something with structure. For example, when you list the contents of a directory, what you get back is a list of objects, where each object represents an item in that directory. These values can be piped through a series of steps, in a series of commands called a 'pipeline'.
Nu draws inspiration from projects like PowerShell, functional programming languages, and modern cli tools. Rather than thinking of files and services as raw streams of text, Nu looks at each input as something with structure. For example, when you list the contents of a directory, what you get back is a table of rows, where each row represents an item in that directory. These values can be piped through a series of steps, in a series of commands called a 'pipeline'.
## Pipelines
@ -104,17 +104,18 @@ Commands are separated by the pipe symbol (`|`) to denote a pipeline flowing lef
```
/home/jonathan/Source/nushell(master)> ls | where type == "Directory" | autoview
--------+-----------+----------+--------+--------------+----------------
name | type | readonly | size | accessed | modified
--------+-----------+----------+--------+--------------+----------------
target | Directory | | 4.1 KB | 19 hours ago | 19 hours ago
images | Directory | | 4.1 KB | 2 weeks ago | a week ago
tests | Directory | | 4.1 KB | 2 weeks ago | 18 minutes ago
docs | Directory | | 4.1 KB | a week ago | a week ago
.git | Directory | | 4.1 KB | 2 weeks ago | 25 minutes ago
src | Directory | | 4.1 KB | 2 weeks ago | 25 minutes ago
.cargo | Directory | | 4.1 KB | 2 weeks ago | 2 weeks ago
--------+-----------+----------+--------+--------------+----------------
━━━━┯━━━━━━━━━━━┯━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━┯━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━
# │ name │ type │ readonly │ size │ accessed │ modified
────┼───────────┼───────────┼──────────┼────────┼──────────────┼────────────────
0 │ .azure │ Directory │ │ 4.1 KB │ 2 months ago │ a day ago
1 │ target │ Directory │ │ 4.1 KB │ 3 days ago │ 3 days ago
2 │ images │ Directory │ │ 4.1 KB │ 2 months ago │ 2 weeks ago
3 │ tests │ Directory │ │ 4.1 KB │ 2 months ago │ 37 minutes ago
4 │ tmp │ Directory │ │ 4.1 KB │ 2 weeks ago │ 2 weeks ago
5 │ src │ Directory │ │ 4.1 KB │ 2 months ago │ 37 minutes ago
6 │ assets │ Directory │ │ 4.1 KB │ a month ago │ a month ago
7 │ docs │ Directory │ │ 4.1 KB │ 2 months ago │ 2 months ago
━━━━┷━━━━━━━━━━━┷━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━┷━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━
```
Because most of the time you'll want to see the output of a pipeline, `autoview` is assumed. We could have also written the above:
@ -126,15 +127,16 @@ Because most of the time you'll want to see the output of a pipeline, `autoview`
Being able to use the same commands and compose them differently is an important philosophy in Nu. For example, we could use the built-in `ps` command as well to get a list of the running processes, using the same `where` as above.
```text
C:\Code\nushell(master)> ps | where cpu > 0
------------------ +-----+-------+-------+----------
name | cmd | cpu | pid | status
------------------ +-----+-------+-------+----------
msedge.exe | - | 0.77 | 26472 | Runnable
nu.exe | - | 7.83 | 15473 | Runnable
SearchIndexer.exe | - | 82.17 | 23476 | Runnable
BlueJeans.exe | - | 4.54 | 10000 | Runnable
-------------------+-----+-------+-------+----------
/home/jonathan/Source/nushell(master)> ps | where cpu > 0
━━━┯━━━━━━━┯━━━━━━━━━━━━━━━━━┯━━━━━━━━━━┯━━━━━━━━━━
# │ pid │ name │ status │ cpu
───┼───────┼─────────────────┼──────────┼──────────
0 │ 992 │ chrome │ Sleeping │ 6.988768
1 │ 4240 │ chrome │ Sleeping │ 5.645982
2 │ 13973 │ qemu-system-x86 │ Sleeping │ 4.996551
3 │ 15746 │ nu │ Sleeping │ 84.59905
━━━┷━━━━━━━┷━━━━━━━━━━━━━━━━━┷━━━━━━━━━━┷━━━━━━━━━━
```
## Opening files
@ -143,22 +145,22 @@ Nu can load file and URL contents as raw text or as structured data (if it recog
```
/home/jonathan/Source/nushell(master)> open Cargo.toml
-----------------+------------------+-----------------
dependencies | dev-dependencies | package
-----------------+------------------+-----------------
[object Object] | [object Object] | [object Object]
-----------------+------------------+-----------------
━━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━
bin │ dependencies │ dev-dependencies
──────────────────┼────────────────┼──────────────────
[table: 12 rows] │ [table: 1 row] │ [table: 1 row]
━━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━
```
We can pipeline this into a command that gets the contents of one of the columns:
```
/home/jonathan/Source/nushell(master)> open Cargo.toml | get package
-------------+----------------------------+---------+---------+------+---------
authors | description | edition | license | name | version
-------------+----------------------------+---------+---------+------+---------
[list List] | A shell for the GitHub era | 2018 | MIT | nu | 0.2.0
-------------+----------------------------+---------+---------+------+---------
━━━━━━━━━━━━━━━━━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━┯━━━━━━━━━┯━━━━━━━━━┯━━━━━━┯━━━━━━━━━
authors │ description │ edition │ license │ name │ version
─────────────────┼────────────────────────────┼─────────┼─────────┼──────┼─────────
[table: 3 rows] │ A shell for the GitHub era │ 2018 │ ISC │ nu │ 0.2.0
━━━━━━━━━━━━━━━━━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━━━━━━━━━┷━━━━━━━━━┷━━━━━━┷━━━━━━━━━
```
Finally, we can use commands outside of Nu once we have the data we want:
@ -180,7 +182,7 @@ Finally, to get a list of all the current shells, you can use the `shells` comma
## Plugins
Nu supports plugins that offer additional functionality to the shell and follow the same object model that built-in commands use. This allows you to extend nu for your needs.
Nu supports plugins that offer additional functionality to the shell and follow the same structured data model that built-in commands use. This allows you to extend nu for your needs.
There are a few examples in the `plugins` directory.
@ -196,7 +198,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
* Nu's workflow and tools should have the usability in day-to-day experience of using a shell in 2019 (and beyond).
* Nu views data as both structured and unstructured. It is an object shell like PowerShell.
* Nu views data as both structured and unstructured. It is a structured shell like PowerShell.
* Finally, Nu views data functionally. Rather than using mutation, pipelines act as a means to load, change, and save data without mutable state.
@ -233,18 +235,18 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
| get column-or-column-path | Open column and get data from the corresponding cells |
| sort-by ...columns | Sort by the given columns |
| where condition | Filter table to match the condition |
| inc (field) | Increment a value or version. Optional use the field of a table |
| add field value | Add a new field to the table |
| embed field | Embeds a new field to the table |
| inc (column-or-column-path) | Increment a value or version. Optionally use the column of a table |
| add column-or-column-path value | Add a new column to the table |
| embed column | Creates a new table of one column with the given name, and places the current table inside of it |
| sum | Sum a column of values |
| edit field value | Edit an existing field to have a new value |
| edit column-or-column-path value | Edit an existing column to have a new value |
| reverse | Reverses the table. |
| skip amount | Skip a number of rows |
| skip-while condition | Skips rows while the condition matches. |
| first amount | Show only the first number of rows |
| last amount | Show only the last number of rows |
| nth row-number | Return only the selected row |
| str (field) | Apply string function. Optional use the field of a table |
| str (column) | Apply string function. Optionally use the column of a table |
| tags | Read the tags (metadata) for values |
| to-json | Convert table into .json text |
| to-toml | Convert table into .toml text |
@ -269,7 +271,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
| from-yaml | Parse text as a .yaml/.yml and create a table |
| lines | Split single string into rows, one per line |
| size | Gather word count statistics on the text |
| split-column sep ...fields | Split row contents across multiple columns via the separator |
| split-column sep ...column-names | Split row contents across multiple columns via the separator, optionally give the columns names |
| split-row sep | Split row contents over multiple rows via the separator |
| trim | Trim leading and following whitespace from text data |
| {external-command} $it | Run external command with given arguments, replacing $it with each row text |

View File

@ -238,7 +238,7 @@ impl ExternalCommand {
if let Some(span) = span {
return Err(ShellError::labeled_error(
"External $it needs string data",
"given object instead of string data",
"given row instead of string data",
span,
));
} else {
@ -293,7 +293,7 @@ impl ExternalCommand {
}
return Err(ShellError::labeled_error(
"External $it needs string data",
"given object instead of string data",
"given row instead of string data",
span,
));
}

View File

@ -256,7 +256,7 @@ fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
Value::Binary(x).simple_spanned(name_span),
),
_ => yield Err(ShellError::labeled_error_with_secondary(
"Expected an object with BSON-compatible structure.span() from pipeline",
"Expected a table with BSON-compatible structure.span() from pipeline",
"requires BSON-compatible input",
name_span,
"originates from here".to_string(),
@ -265,7 +265,7 @@ fn to_bson(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
}
}
_ => yield Err(ShellError::labeled_error(
"Expected an object with BSON-compatible structure from pipeline",
"Expected a table with BSON-compatible structure from pipeline",
"requires BSON-compatible input",
name_span))
}

View File

@ -153,7 +153,7 @@ fn to_csv(
}
_ => {
yield Err(ShellError::labeled_error_with_secondary(
"Expected an object with CSV-compatible structure.span() from pipeline",
"Expected a table with CSV-compatible structure.span() from pipeline",
"requires CSV-compatible input",
name_span,
"originates from here".to_string(),

View File

@ -100,7 +100,7 @@ fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
),
_ => yield Err(ShellError::labeled_error_with_secondary(
"Expected an object with JSON-compatible structure.span() from pipeline",
"Expected a table with JSON-compatible structure.span() from pipeline",
"requires JSON-compatible input",
name_span,
"originates from here".to_string(),
@ -109,7 +109,7 @@ fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
}
}
_ => yield Err(ShellError::labeled_error(
"Expected an object with JSON-compatible structure from pipeline",
"Expected a table with JSON-compatible structure from pipeline",
"requires JSON-compatible input",
name_span))
}

View File

@ -187,7 +187,7 @@ fn sqlite_input_stream_to_bytes(
other => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Expected object, found {:?}", other),
format!("Expected row, found {:?}", other),
))
}
}
@ -207,7 +207,7 @@ fn to_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
Ok(out) => yield ReturnSuccess::value(out),
_ => {
yield Err(ShellError::labeled_error(
"Expected an object with SQLite-compatible structure.span() from pipeline",
"Expected a table with SQLite-compatible structure.span() from pipeline",
"requires SQLite-compatible input",
name_span,
))

View File

@ -95,7 +95,7 @@ fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
),
_ => yield Err(ShellError::labeled_error_with_secondary(
"Expected an object with TOML-compatible structure.span() from pipeline",
"Expected a table with TOML-compatible structure.span() from pipeline",
"requires TOML-compatible input",
name_span,
"originates from here".to_string(),
@ -104,7 +104,7 @@ fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
}
}
_ => yield Err(ShellError::labeled_error(
"Expected an object with TOML-compatible structure from pipeline",
"Expected a table with TOML-compatible structure from pipeline",
"requires TOML-compatible input",
name_span))
}

View File

@ -51,8 +51,8 @@ fn to_string_helper(v: &Value) -> Result<String, ShellError> {
Value::Primitive(Primitive::Date(d)) => Ok(d.to_string()),
Value::Primitive(Primitive::Bytes(b)) => Ok(format!("{}", b)),
Value::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?),
Value::List(_) => return Ok(String::from("[list list]")),
Value::Object(_) => return Ok(String::from("[object]")),
Value::List(_) => return Ok(String::from("[table]")),
Value::Object(_) => return Ok(String::from("[row]")),
Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()),
_ => Err(ShellError::string("Unexpected value")),
}
@ -152,7 +152,7 @@ fn to_tsv(
}
_ => {
yield Err(ShellError::labeled_error_with_secondary(
"Expected an object with TSV-compatible structure.span() from pipeline",
"Expected a table with TSV-compatible structure.span() from pipeline",
"requires TSV-compatible input",
name_span,
"originates from here".to_string(),

View File

@ -96,7 +96,7 @@ fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
),
_ => yield Err(ShellError::labeled_error_with_secondary(
"Expected an object with YAML-compatible structure.span() from pipeline",
"Expected a table with YAML-compatible structure.span() from pipeline",
"requires YAML-compatible input",
name_span,
"originates from here".to_string(),
@ -105,7 +105,7 @@ fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream
}
}
_ => yield Err(ShellError::labeled_error(
"Expected an object with YAML-compatible structure from pipeline",
"Expected a table with YAML-compatible structure from pipeline",
"requires YAML-compatible input",
name_span))
}

View File

@ -504,11 +504,11 @@ impl Value {
.map(|e| e.source(&b.source).to_string()),
"; ",
),
Value::Object(_) => format!("[{}]", self.type_name()),
Value::Object(_) => format!("[table: 1 row]"),
Value::List(l) => format!(
"[{} {}]",
"[table: {} {}]",
l.len(),
if l.len() == 1 { "item" } else { "items" }
if l.len() == 1 { "row" } else { "rows" }
),
Value::Binary(_) => format!("<binary>"),
}

View File

@ -29,7 +29,7 @@ impl Add {
}
},
None => Err(ShellError::string(
"add needs a field when adding a value to an object",
"add needs a column name when adding a value to a table",
)),
},
x => Err(ShellError::string(format!(
@ -46,7 +46,8 @@ impl Plugin for Add {
.desc("Add a new field to the table.")
.required("Field", SyntaxType::String)
.required("Value", SyntaxType::String)
.rest(SyntaxType::String).filter())
.rest(SyntaxType::String)
.filter())
}
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {

View File

@ -23,12 +23,12 @@ impl Edit {
Some(v) => return Ok(v),
None => {
return Err(ShellError::string(
"edit could not find place to insert field",
"edit could not find place to insert column",
))
}
},
None => Err(ShellError::string(
"edit needs a field when adding a value to an object",
"edit needs a column when changing a value in a table",
)),
},
x => Err(ShellError::string(format!(
@ -42,7 +42,7 @@ impl Edit {
impl Plugin for Edit {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("edit")
.desc("Edit an existing field to have a new value.")
.desc("Edit an existing column to have a new value.")
.required("Field", SyntaxType::String)
.required("Value", SyntaxType::String)
.filter())

View File

@ -102,7 +102,7 @@ impl Inc {
}
}
None => Err(ShellError::string(
"inc needs a field when incrementing a value in an object",
"inc needs a field when incrementing a column in a table",
)),
},
x => Err(ShellError::string(format!(
@ -116,7 +116,7 @@ impl Inc {
impl Plugin for Inc {
fn config(&mut self) -> Result<Signature, ShellError> {
Ok(Signature::build("inc")
.desc("Increment a value or version. Optional use the field of a table.")
.desc("Increment a value or version. Optionally use the column of a table.")
.switch("major")
.switch("minor")
.switch("patch")

View File

@ -153,7 +153,7 @@ impl Str {
}
None => Err(ShellError::string(format!(
"{}: {}",
"str needs a field when applying it to a value in an object",
"str needs a column when applied to a value in a row",
Str::usage()
))),
},