mirror of
https://github.com/nushell/nushell
synced 2024-12-28 14:03:09 +00:00
parent
525ed7653f
commit
3d0b1ef1ce
20 changed files with 640 additions and 34 deletions
|
@ -1,11 +1,13 @@
|
||||||
mod completions;
|
mod completions;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
mod nu_highlight;
|
||||||
mod prompt;
|
mod prompt;
|
||||||
mod syntax_highlight;
|
mod syntax_highlight;
|
||||||
mod validation;
|
mod validation;
|
||||||
|
|
||||||
pub use completions::NuCompleter;
|
pub use completions::NuCompleter;
|
||||||
pub use errors::CliError;
|
pub use errors::CliError;
|
||||||
|
pub use nu_highlight::NuHighlight;
|
||||||
pub use prompt::NushellPrompt;
|
pub use prompt::NushellPrompt;
|
||||||
pub use syntax_highlight::NuHighlighter;
|
pub use syntax_highlight::NuHighlighter;
|
||||||
pub use validation::NuValidator;
|
pub use validation::NuValidator;
|
||||||
|
|
63
crates/nu-cli/src/nu_highlight.rs
Normal file
63
crates/nu-cli/src/nu_highlight.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Value};
|
||||||
|
use reedline::Highlighter;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct NuHighlight;
|
||||||
|
|
||||||
|
impl Command for NuHighlight {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"nu-highlight"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("nu-highlight").category(Category::Strings)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Syntax highlight the input string."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
|
||||||
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
let engine_state = engine_state.clone();
|
||||||
|
let config = stack.get_config()?;
|
||||||
|
|
||||||
|
let highlighter = crate::NuHighlighter {
|
||||||
|
engine_state,
|
||||||
|
config,
|
||||||
|
};
|
||||||
|
|
||||||
|
input.map(
|
||||||
|
move |x| match x.as_string() {
|
||||||
|
Ok(line) => {
|
||||||
|
let highlights = highlighter.highlight(&line);
|
||||||
|
|
||||||
|
Value::String {
|
||||||
|
val: highlights.render_simple(),
|
||||||
|
span: head,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => Value::Error { error: err },
|
||||||
|
},
|
||||||
|
ctrlc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Describe the type of a string",
|
||||||
|
example: "'let x = 3' | nu-highlight",
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,12 +24,12 @@ impl Command for Into {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: get_full_help(&Into.signature(), &[], engine_state),
|
val: get_full_help(&Into.signature(), &[], engine_state, stack),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl Command for ExportCommand {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
@ -33,6 +33,7 @@ impl Command for ExportCommand {
|
||||||
&ExportCommand.signature(),
|
&ExportCommand.signature(),
|
||||||
&ExportCommand.examples(),
|
&ExportCommand.examples(),
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
),
|
),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,9 @@ fn help(
|
||||||
let output = full_commands
|
let output = full_commands
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(signature, _, _, _)| signature.name == name)
|
.filter(|(signature, _, _, _)| signature.name == name)
|
||||||
.map(|(signature, examples, _, _)| get_full_help(signature, examples, engine_state))
|
.map(|(signature, examples, _, _)| {
|
||||||
|
get_full_help(signature, examples, engine_state, stack)
|
||||||
|
})
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
if !output.is_empty() {
|
if !output.is_empty() {
|
||||||
|
|
|
@ -17,6 +17,7 @@ mod let_;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
mod module;
|
mod module;
|
||||||
mod source;
|
mod source;
|
||||||
|
mod tutor;
|
||||||
mod use_;
|
mod use_;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ pub use let_::Let;
|
||||||
pub use metadata::Metadata;
|
pub use metadata::Metadata;
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use source::Source;
|
pub use source::Source;
|
||||||
|
pub use tutor::Tutor;
|
||||||
pub use use_::Use;
|
pub use use_::Use;
|
||||||
pub use version::Version;
|
pub use version::Version;
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
|
466
crates/nu-command/src/core_commands/tutor.rs
Normal file
466
crates/nu-command/src/core_commands/tutor.rs
Normal file
|
@ -0,0 +1,466 @@
|
||||||
|
use itertools::Itertools;
|
||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Tutor;
|
||||||
|
|
||||||
|
impl Command for Tutor {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"tutor"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("tutor")
|
||||||
|
.optional(
|
||||||
|
"search",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"item to search for, or 'list' to list available tutorials",
|
||||||
|
)
|
||||||
|
.named(
|
||||||
|
"find",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Search tutorial for a phrase",
|
||||||
|
Some('f'),
|
||||||
|
)
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Run the tutorial. To begin, run: tutor"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
tutor(engine_state, stack, call)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Begin the tutorial",
|
||||||
|
example: "tutor begin",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Search a tutorial by phrase",
|
||||||
|
example: "tutor -f \"$in\"",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tutor(
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let span = call.head;
|
||||||
|
|
||||||
|
let search: Option<String> = call.opt(engine_state, stack, 0).unwrap_or(None);
|
||||||
|
let find: Option<String> = call.get_flag(engine_state, stack, "find")?;
|
||||||
|
|
||||||
|
let search_space = [
|
||||||
|
(vec!["begin"], begin_tutor()),
|
||||||
|
(
|
||||||
|
vec!["table", "tables", "row", "rows", "column", "columns"],
|
||||||
|
table_tutor(),
|
||||||
|
),
|
||||||
|
(vec!["cell", "cells"], cell_tutor()),
|
||||||
|
(
|
||||||
|
vec![
|
||||||
|
"expr",
|
||||||
|
"exprs",
|
||||||
|
"expressions",
|
||||||
|
"subexpression",
|
||||||
|
"subexpressions",
|
||||||
|
"sub-expression",
|
||||||
|
"sub-expressions",
|
||||||
|
],
|
||||||
|
expression_tutor(),
|
||||||
|
),
|
||||||
|
(vec!["echo"], echo_tutor()),
|
||||||
|
(vec!["each", "iteration", "iter"], each_tutor()),
|
||||||
|
(
|
||||||
|
vec!["var", "vars", "variable", "variables"],
|
||||||
|
variable_tutor(),
|
||||||
|
),
|
||||||
|
(vec!["engine-q", "e-q"], engineq_tutor()),
|
||||||
|
(vec!["block", "blocks"], block_tutor()),
|
||||||
|
(vec!["shorthand", "shorthands"], shorthand_tutor()),
|
||||||
|
];
|
||||||
|
|
||||||
|
if let Some(find) = find {
|
||||||
|
let mut results = vec![];
|
||||||
|
for search_group in search_space {
|
||||||
|
if search_group.1.contains(&find) {
|
||||||
|
results.push(search_group.0[0].to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = format!("You can find '{}' in the following topics:\n{}\n\nYou can learn about a topic using `tutor` followed by the name of the topic.\nFor example: `tutor table` to open the table topic.\n\n",
|
||||||
|
find,
|
||||||
|
results.into_iter().map(|x| format!("- {}", x)).join("\n")
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(display(&message, engine_state, stack, span));
|
||||||
|
} else if let Some(search) = search {
|
||||||
|
for search_group in search_space {
|
||||||
|
if search_group.0.contains(&search.as_str()) {
|
||||||
|
return Ok(display(search_group.1, engine_state, stack, span));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(display(default_tutor(), engine_state, stack, span))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Welcome to the Nushell tutorial!
|
||||||
|
|
||||||
|
With the `tutor` command, you'll be able to learn a lot about how Nushell
|
||||||
|
works along with many fun tips and tricks to speed up everyday tasks.
|
||||||
|
|
||||||
|
To get started, you can use `tutor begin`.
|
||||||
|
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Nushell is a structured shell and programming language. One way to begin
|
||||||
|
using it is to try a few of the commands.
|
||||||
|
|
||||||
|
The first command to try is `ls`. The `ls` command will show you a list
|
||||||
|
of the files in the current directory. Notice that these files are shown
|
||||||
|
as a table. Each column of this table not only tells us what is being
|
||||||
|
shown, but also gives us a way to work with the data.
|
||||||
|
|
||||||
|
You can combine the `ls` command with other commands using the pipeline
|
||||||
|
symbol '|'. This allows data to flow from one command to the next.
|
||||||
|
|
||||||
|
For example, if we only wanted the name column, we could do:
|
||||||
|
```
|
||||||
|
ls | select name
|
||||||
|
```
|
||||||
|
Notice that we still get a table, but this time it only has one column:
|
||||||
|
the name column.
|
||||||
|
|
||||||
|
You can continue to learn more about tables by running:
|
||||||
|
```
|
||||||
|
tutor tables
|
||||||
|
```
|
||||||
|
If at any point, you'd like to restart this tutorial, you can run:
|
||||||
|
```
|
||||||
|
tutor begin
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
The most common form of data in Nushell is the table. Tables contain rows and
|
||||||
|
columns of data. In each cell of the table, there is data that you can access
|
||||||
|
using Nushell commands.
|
||||||
|
|
||||||
|
To get the 3rd row in the table, you can use the `nth` command:
|
||||||
|
```
|
||||||
|
ls | nth 2
|
||||||
|
```
|
||||||
|
This will get the 3rd (note that `nth` is zero-based) row in the table created
|
||||||
|
by the `ls` command. You can use `nth` on any table created by other commands
|
||||||
|
as well.
|
||||||
|
|
||||||
|
You can also access the column of data in one of two ways. If you want
|
||||||
|
to keep the column as part of a new table, you can use `select`.
|
||||||
|
```
|
||||||
|
ls | select name
|
||||||
|
```
|
||||||
|
This runs `ls` and returns only the "name" column of the table.
|
||||||
|
|
||||||
|
If, instead, you'd like to get access to the values inside of the column, you
|
||||||
|
can use the `get` command.
|
||||||
|
```
|
||||||
|
ls | get name
|
||||||
|
```
|
||||||
|
This allows us to get to the list of strings that are the filenames rather
|
||||||
|
than having a full table. In some cases, this can make the names easier to
|
||||||
|
work with.
|
||||||
|
|
||||||
|
You can continue to learn more about working with cells of the table by
|
||||||
|
running:
|
||||||
|
```
|
||||||
|
tutor cells
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cell_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Working with cells of data in the table is a key part of working with data in
|
||||||
|
Nushell. Because of this, there is a rich list of commands to work with cells
|
||||||
|
as well as handy shorthands for accessing cells.
|
||||||
|
|
||||||
|
Cells can hold simple values like strings and numbers, or more complex values
|
||||||
|
like lists and tables.
|
||||||
|
|
||||||
|
To reach a cell of data from a table, you can combine a row operation and a
|
||||||
|
column operation.
|
||||||
|
```
|
||||||
|
ls | nth 4 | get name
|
||||||
|
```
|
||||||
|
You can combine these operations into one step using a shortcut.
|
||||||
|
```
|
||||||
|
(ls).4.name
|
||||||
|
```
|
||||||
|
Names/strings represent columns names and numbers represent row numbers.
|
||||||
|
|
||||||
|
The `(ls)` is a form of expression. You can continue to learn more about
|
||||||
|
expressions by running:
|
||||||
|
```
|
||||||
|
tutor expressions
|
||||||
|
```
|
||||||
|
You can also learn about these cell shorthands by running:
|
||||||
|
```
|
||||||
|
tutor shorthands
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Expressions give you the power to mix calls to commands with math. The
|
||||||
|
simplest expression is a single value like a string or number.
|
||||||
|
```
|
||||||
|
3
|
||||||
|
```
|
||||||
|
Expressions can also include math operations like addition or division.
|
||||||
|
```
|
||||||
|
10 / 2
|
||||||
|
```
|
||||||
|
Normally, an expression is one type of operation: math or commands. You can
|
||||||
|
mix these types by using subexpressions. Subexpressions are just like
|
||||||
|
expressions, but they're wrapped in parentheses `()`.
|
||||||
|
```
|
||||||
|
10 * (3 + 4)
|
||||||
|
```
|
||||||
|
Here we use parentheses to create a higher math precedence in the math
|
||||||
|
expression.
|
||||||
|
```
|
||||||
|
echo (2 + 3)
|
||||||
|
```
|
||||||
|
You can continue to learn more about the `echo` command by running:
|
||||||
|
```
|
||||||
|
tutor echo
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn echo_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
The `echo` command in Nushell is a powerful tool for not only seeing values,
|
||||||
|
but also for creating new ones.
|
||||||
|
```
|
||||||
|
echo "Hello"
|
||||||
|
```
|
||||||
|
You can echo output. This output, if it's not redirected using a "|" pipeline
|
||||||
|
will be displayed to the screen.
|
||||||
|
```
|
||||||
|
echo 1..10
|
||||||
|
```
|
||||||
|
You can also use echo to work with individual values of a range. In this
|
||||||
|
example, `echo` will create the values from 1 to 10 as a list.
|
||||||
|
```
|
||||||
|
echo 1 2 3 4 5
|
||||||
|
```
|
||||||
|
You can also create lists of values by passing `echo` multiple arguments.
|
||||||
|
This can be helpful if you want to later processes these values.
|
||||||
|
|
||||||
|
The `echo` command can pair well with the `each` command which can run
|
||||||
|
code on each row, or item, of input.
|
||||||
|
|
||||||
|
You can continue to learn more about the `each` command by running:
|
||||||
|
```
|
||||||
|
tutor each
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn each_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
The `each` command gives us a way of working with each individual row or
|
||||||
|
element of a list one at a time. It reads these in from the pipeline and
|
||||||
|
runs a block on each element. A block is a group of pipelines.
|
||||||
|
```
|
||||||
|
echo 1 2 3 | each { $it + 10}
|
||||||
|
```
|
||||||
|
This example iterates over each element sent by `echo`, giving us three new
|
||||||
|
values that are the original value + 10. Here, the `$it` is a variable that
|
||||||
|
is the name given to the block's parameter by default.
|
||||||
|
|
||||||
|
You can learn more about blocks by running:
|
||||||
|
```
|
||||||
|
tutor blocks
|
||||||
|
```
|
||||||
|
You can also learn more about variables by running:
|
||||||
|
```
|
||||||
|
tutor variables
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn variable_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Variables are an important way to store values to be used later. To create a
|
||||||
|
variable, you can use the `let` keyword. The `let` command will create a
|
||||||
|
variable and then assign it a value in one step.
|
||||||
|
```
|
||||||
|
let $x = 3
|
||||||
|
```
|
||||||
|
Once created, we can refer to this variable by name.
|
||||||
|
```
|
||||||
|
$x
|
||||||
|
```
|
||||||
|
Nushell also comes with built-in variables. The `$nu` variable is a reserved
|
||||||
|
variable that contains a lot of information about the currently running
|
||||||
|
instance of Nushell. The `$it` variable is the name given to block parameters
|
||||||
|
if you don't specify one. And `$in` is the variable that allows you to work
|
||||||
|
with all of the data coming in from the pipeline in one place.
|
||||||
|
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Blocks are a special form of expression that hold code to be run at a later
|
||||||
|
time. Often, you'll see blocks as one of the arguments given to commands
|
||||||
|
like `each` and `if`.
|
||||||
|
```
|
||||||
|
ls | each {|x| $x.name}
|
||||||
|
```
|
||||||
|
The above will create a list of the filenames in the directory.
|
||||||
|
```
|
||||||
|
if $true { echo "it's true" } { echo "it's not true" }
|
||||||
|
```
|
||||||
|
This `if` call will run the first block if the expression is true, or the
|
||||||
|
second block if the expression is false.
|
||||||
|
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shorthand_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
You can access cells in a table using a shorthand notation sometimes called a
|
||||||
|
"column path" or "cell path". These paths allow you to go from a table to
|
||||||
|
rows, columns, or cells inside of the table.
|
||||||
|
|
||||||
|
Shorthand paths are made from rows numbers, column names, or both. You can use
|
||||||
|
them on any variable or subexpression.
|
||||||
|
```
|
||||||
|
$nu.cwd
|
||||||
|
```
|
||||||
|
The above accesses the built-in `$nu` variable, gets its table, and then uses
|
||||||
|
the shorthand path to retrieve only the cell data inside the "cwd" column.
|
||||||
|
```
|
||||||
|
(ls).name.4
|
||||||
|
```
|
||||||
|
This will retrieve the cell data in the "name" column on the 5th row (note:
|
||||||
|
row numbers are zero-based).
|
||||||
|
|
||||||
|
Rows and columns don't need to come in any specific order. You can get the
|
||||||
|
same value using:
|
||||||
|
```
|
||||||
|
(ls).4.name
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn engineq_tutor() -> &'static str {
|
||||||
|
r#"
|
||||||
|
Engine-q is the upcoming engine for Nushell. Build for speed and correctness,
|
||||||
|
it also comes with a set of changes from Nushell versions prior to 0.60. To
|
||||||
|
get ready for engine-q look for some of these changes that might impact your
|
||||||
|
current scripts:
|
||||||
|
|
||||||
|
* Engine-q now uses a few new data structures, including a record syntax
|
||||||
|
that allows you to model key-value pairs similar to JSON objects.
|
||||||
|
* Environment variables can now contain more than just strings. Structured
|
||||||
|
values are converted to strings for external commands using converters.
|
||||||
|
* `if` will now use an `else` keyword before the else block.
|
||||||
|
* We're moving from "config.toml" to "config.nu". This means startup will
|
||||||
|
now be a script file.
|
||||||
|
* `config` and its subcommands are being replaced by a record that you can
|
||||||
|
update in the shell which contains all the settings under the variable
|
||||||
|
`$config`.
|
||||||
|
* bigint/bigdecimal values are now machine i64 and f64 values
|
||||||
|
* And more, you can read more about upcoming changes in the up-to-date list
|
||||||
|
at: https://github.com/nushell/engine-q/issues/522
|
||||||
|
"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(help: &str, engine_state: &EngineState, stack: &mut Stack, span: Span) -> PipelineData {
|
||||||
|
let help = help.split('`');
|
||||||
|
|
||||||
|
let mut build = String::new();
|
||||||
|
let mut code_mode = false;
|
||||||
|
|
||||||
|
for item in help {
|
||||||
|
if code_mode {
|
||||||
|
code_mode = false;
|
||||||
|
|
||||||
|
//TODO: support no-color mode
|
||||||
|
if let Some(highlighter) = engine_state.find_decl(b"nu-highlight") {
|
||||||
|
let decl = engine_state.get_decl(highlighter);
|
||||||
|
|
||||||
|
if let Ok(output) = decl.run(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
&Call::new(),
|
||||||
|
Value::String {
|
||||||
|
val: item.to_string(),
|
||||||
|
span: Span { start: 0, end: 0 },
|
||||||
|
}
|
||||||
|
.into_pipeline_data(),
|
||||||
|
) {
|
||||||
|
let result = output.into_value(Span { start: 0, end: 0 });
|
||||||
|
match result.as_string() {
|
||||||
|
Ok(s) => {
|
||||||
|
build.push_str(&s);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
build.push_str(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code_mode = true;
|
||||||
|
build.push_str(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::string(build, span).into_pipeline_data()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(Tutor)
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,12 +24,17 @@ impl Command for Dataframe {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: get_full_help(&Dataframe.signature(), &Dataframe.examples(), engine_state),
|
val: get_full_help(
|
||||||
|
&Dataframe.signature(),
|
||||||
|
&Dataframe.examples(),
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
|
|
|
@ -34,13 +34,13 @@ impl Command for Date {
|
||||||
|
|
||||||
fn date(
|
fn date(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
|
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: get_full_help(&Date.signature(), &Date.examples(), engine_state),
|
val: get_full_help(&Date.signature(), &Date.examples(), engine_state, stack),
|
||||||
span: head,
|
span: head,
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
||||||
Metadata,
|
Metadata,
|
||||||
Module,
|
Module,
|
||||||
Source,
|
Source,
|
||||||
|
Tutor,
|
||||||
Use,
|
Use,
|
||||||
Version,
|
Version,
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,12 +22,12 @@ impl Command for Hash {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: get_full_help(&Self.signature(), &Self.examples(), engine_state),
|
val: get_full_help(&Self.signature(), &Self.examples(), engine_state, stack),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl Command for MathCommand {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
@ -33,6 +33,7 @@ impl Command for MathCommand {
|
||||||
&MathCommand.signature(),
|
&MathCommand.signature(),
|
||||||
&MathCommand.examples(),
|
&MathCommand.examples(),
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
),
|
),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ impl Command for Url {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: get_full_help(&Url.signature(), &Url.examples(), engine_state),
|
val: get_full_help(&Url.signature(), &Url.examples(), engine_state, stack),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
|
|
|
@ -39,7 +39,7 @@ the path literal."#
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, nu_protocol::ShellError> {
|
) -> Result<PipelineData, nu_protocol::ShellError> {
|
||||||
|
@ -48,6 +48,7 @@ the path literal."#
|
||||||
&PathCommand.signature(),
|
&PathCommand.signature(),
|
||||||
&PathCommand.examples(),
|
&PathCommand.examples(),
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
),
|
),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl Command for RandomCommand {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
@ -33,6 +33,7 @@ impl Command for RandomCommand {
|
||||||
&RandomCommand.signature(),
|
&RandomCommand.signature(),
|
||||||
&RandomCommand.examples(),
|
&RandomCommand.examples(),
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
),
|
),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl Command for SplitCommand {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
@ -33,6 +33,7 @@ impl Command for SplitCommand {
|
||||||
&SplitCommand.signature(),
|
&SplitCommand.signature(),
|
||||||
&SplitCommand.examples(),
|
&SplitCommand.examples(),
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
),
|
),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ impl Command for Str {
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: get_full_help(&Str.signature(), &Str.examples(), engine_state),
|
val: get_full_help(&Str.signature(), &Str.examples(), engine_state, stack),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
}
|
}
|
||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nu_protocol::{engine::EngineState, Example, Signature, Span, Value};
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{EngineState, Stack},
|
||||||
|
Example, IntoPipelineData, Signature, Span, Value,
|
||||||
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
const COMMANDS_DOCS_DIR: &str = "docs/commands";
|
const COMMANDS_DOCS_DIR: &str = "docs/commands";
|
||||||
|
@ -13,7 +17,12 @@ pub struct DocumentationConfig {
|
||||||
brief: bool,
|
brief: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_doc(name: &str, engine_state: &EngineState, head: Span) -> (Vec<String>, Vec<Value>) {
|
fn generate_doc(
|
||||||
|
name: &str,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
head: Span,
|
||||||
|
) -> (Vec<String>, Vec<Value>) {
|
||||||
let mut cols = vec![];
|
let mut cols = vec![];
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
|
@ -48,6 +57,7 @@ fn generate_doc(name: &str, engine_state: &EngineState, head: Span) -> (Vec<Stri
|
||||||
&command.signature(),
|
&command.signature(),
|
||||||
&command.examples(),
|
&command.examples(),
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
&DocumentationConfig {
|
&DocumentationConfig {
|
||||||
no_subcommands: true,
|
no_subcommands: true,
|
||||||
no_color: true,
|
no_color: true,
|
||||||
|
@ -61,7 +71,7 @@ fn generate_doc(name: &str, engine_state: &EngineState, head: Span) -> (Vec<Stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate_docs gets the documentation from each command and returns a Table as output
|
// generate_docs gets the documentation from each command and returns a Table as output
|
||||||
pub fn generate_docs(engine_state: &EngineState, head: Span) -> Value {
|
pub fn generate_docs(engine_state: &EngineState, stack: &mut Stack, head: Span) -> Value {
|
||||||
let signatures = engine_state.get_signatures(true);
|
let signatures = engine_state.get_signatures(true);
|
||||||
|
|
||||||
// cmap will map parent commands to it's subcommands e.g. to -> [to csv, to yaml, to bson]
|
// cmap will map parent commands to it's subcommands e.g. to -> [to csv, to yaml, to bson]
|
||||||
|
@ -88,11 +98,11 @@ pub fn generate_docs(engine_state: &EngineState, head: Span) -> Value {
|
||||||
if !cmap.contains_key(&sig.name) {
|
if !cmap.contains_key(&sig.name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut row_entries = generate_doc(&sig.name, engine_state, head);
|
let mut row_entries = generate_doc(&sig.name, engine_state, stack, head);
|
||||||
// Iterate over all the subcommands of the parent command
|
// Iterate over all the subcommands of the parent command
|
||||||
let mut sub_table = Vec::new();
|
let mut sub_table = Vec::new();
|
||||||
for sub_name in cmap.get(&sig.name).unwrap_or(&Vec::new()) {
|
for sub_name in cmap.get(&sig.name).unwrap_or(&Vec::new()) {
|
||||||
let (cols, vals) = generate_doc(sub_name, engine_state, head);
|
let (cols, vals) = generate_doc(sub_name, engine_state, stack, head);
|
||||||
sub_table.push(Value::Record {
|
sub_table.push(Value::Record {
|
||||||
cols,
|
cols,
|
||||||
vals,
|
vals,
|
||||||
|
@ -139,6 +149,7 @@ pub fn get_documentation(
|
||||||
sig: &Signature,
|
sig: &Signature,
|
||||||
examples: &[Example],
|
examples: &[Example],
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
config: &DocumentationConfig,
|
config: &DocumentationConfig,
|
||||||
) -> String {
|
) -> String {
|
||||||
let cmd_name = &sig.name;
|
let cmd_name = &sig.name;
|
||||||
|
@ -206,14 +217,32 @@ pub fn get_documentation(
|
||||||
long_desc.push_str(" ");
|
long_desc.push_str(" ");
|
||||||
long_desc.push_str(example.description);
|
long_desc.push_str(example.description);
|
||||||
|
|
||||||
// if config.no_color {
|
if config.no_color {
|
||||||
long_desc.push_str(&format!("\n > {}\n", example.example));
|
long_desc.push_str(&format!("\n > {}\n", example.example));
|
||||||
// } else {
|
} else if let Some(highlighter) = engine_state.find_decl(b"nu-highlight") {
|
||||||
// let colored_example =
|
let decl = engine_state.get_decl(highlighter);
|
||||||
|
|
||||||
// crate::shell::painter::Painter::paint_string(example.example, scope, &palette);
|
if let Ok(output) = decl.run(
|
||||||
// long_desc.push_str(&format!("\n > {}\n", colored_example));
|
engine_state,
|
||||||
// }
|
stack,
|
||||||
|
&Call::new(),
|
||||||
|
Value::String {
|
||||||
|
val: example.example.to_string(),
|
||||||
|
span: Span { start: 0, end: 0 },
|
||||||
|
}
|
||||||
|
.into_pipeline_data(),
|
||||||
|
) {
|
||||||
|
let result = output.into_value(Span { start: 0, end: 0 });
|
||||||
|
match result.as_string() {
|
||||||
|
Ok(s) => {
|
||||||
|
long_desc.push_str(&format!("\n > {}\n", s));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
long_desc.push_str(&format!("\n > {}\n", example.example));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long_desc.push('\n');
|
long_desc.push('\n');
|
||||||
|
@ -294,11 +323,17 @@ fn get_flags_section(signature: &Signature) -> String {
|
||||||
long_desc
|
long_desc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brief_help(sig: &Signature, examples: &[Example], engine_state: &EngineState) -> String {
|
pub fn get_brief_help(
|
||||||
|
sig: &Signature,
|
||||||
|
examples: &[Example],
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
) -> String {
|
||||||
get_documentation(
|
get_documentation(
|
||||||
sig,
|
sig,
|
||||||
examples,
|
examples,
|
||||||
engine_state,
|
engine_state,
|
||||||
|
stack,
|
||||||
&DocumentationConfig {
|
&DocumentationConfig {
|
||||||
no_subcommands: false,
|
no_subcommands: false,
|
||||||
no_color: false,
|
no_color: false,
|
||||||
|
@ -307,6 +342,17 @@ pub fn get_brief_help(sig: &Signature, examples: &[Example], engine_state: &Engi
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_full_help(sig: &Signature, examples: &[Example], engine_state: &EngineState) -> String {
|
pub fn get_full_help(
|
||||||
get_documentation(sig, examples, engine_state, &DocumentationConfig::default())
|
sig: &Signature,
|
||||||
|
examples: &[Example],
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
) -> String {
|
||||||
|
get_documentation(
|
||||||
|
sig,
|
||||||
|
examples,
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
&DocumentationConfig::default(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,12 @@ fn eval_call(
|
||||||
let decl = engine_state.get_decl(call.decl_id);
|
let decl = engine_state.get_decl(call.decl_id);
|
||||||
|
|
||||||
if call.named.iter().any(|(flag, _)| flag.item == "help") {
|
if call.named.iter().any(|(flag, _)| flag.item == "help") {
|
||||||
let full_help = get_full_help(&decl.signature(), &decl.examples(), engine_state);
|
let full_help = get_full_help(
|
||||||
|
&decl.signature(),
|
||||||
|
&decl.examples(),
|
||||||
|
engine_state,
|
||||||
|
caller_stack,
|
||||||
|
);
|
||||||
Ok(Value::String {
|
Ok(Value::String {
|
||||||
val: full_help,
|
val: full_help,
|
||||||
span: call.head,
|
span: call.head,
|
||||||
|
|
|
@ -28,6 +28,15 @@ fn main() -> Result<()> {
|
||||||
let init_cwd = utils::get_init_cwd();
|
let init_cwd = utils::get_init_cwd();
|
||||||
let mut engine_state = create_default_context(&init_cwd);
|
let mut engine_state = create_default_context(&init_cwd);
|
||||||
|
|
||||||
|
// Custom additions
|
||||||
|
let delta = {
|
||||||
|
let mut working_set = nu_protocol::engine::StateWorkingSet::new(&engine_state);
|
||||||
|
working_set.add_decl(Box::new(nu_cli::NuHighlight));
|
||||||
|
|
||||||
|
working_set.render()
|
||||||
|
};
|
||||||
|
let _ = engine_state.merge_delta(delta, None, &init_cwd);
|
||||||
|
|
||||||
// TODO: make this conditional in the future
|
// TODO: make this conditional in the future
|
||||||
// Ctrl-c protection section
|
// Ctrl-c protection section
|
||||||
let ctrlc = Arc::new(AtomicBool::new(false));
|
let ctrlc = Arc::new(AtomicBool::new(false));
|
||||||
|
|
Loading…
Reference in a new issue