mirror of
https://github.com/nushell/nushell
synced 2025-01-14 06:04:09 +00:00
Merge master
This commit is contained in:
commit
aadacc2d36
115 changed files with 5328 additions and 2164 deletions
1596
Cargo.lock
generated
1596
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
44
Cargo.toml
44
Cargo.toml
|
@ -13,7 +13,7 @@ homepage = "https://github.com/nushell/nushell"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustyline = "5.0.0"
|
rustyline = "5.0.1"
|
||||||
sysinfo = "0.9"
|
sysinfo = "0.9"
|
||||||
chrono = { version = "0.4.7", features = ["serde"] }
|
chrono = { version = "0.4.7", features = ["serde"] }
|
||||||
chrono-tz = "0.5.1"
|
chrono-tz = "0.5.1"
|
||||||
|
@ -25,19 +25,19 @@ nom = "5.0.0"
|
||||||
dunce = "1.0.0"
|
dunce = "1.0.0"
|
||||||
indexmap = { version = "1.0.2", features = ["serde-1"] }
|
indexmap = { version = "1.0.2", features = ["serde-1"] }
|
||||||
chrono-humanize = "0.0.11"
|
chrono-humanize = "0.0.11"
|
||||||
byte-unit = "2.1.0"
|
byte-unit = "3.0.1"
|
||||||
ordered-float = {version = "1.0.2", features = ["serde"]}
|
ordered-float = {version = "1.0.2", features = ["serde"]}
|
||||||
prettyprint = "0.7.0"
|
prettyprint = "0.7.0"
|
||||||
futures-preview = { version = "=0.3.0-alpha.17", features = ["compat", "io-compat"] }
|
futures-preview = { version = "=0.3.0-alpha.17", features = ["compat", "io-compat"] }
|
||||||
futures-sink-preview = "=0.3.0-alpha.17"
|
futures-sink-preview = "=0.3.0-alpha.17"
|
||||||
futures-async-stream = "0.1.0-alpha.1"
|
futures-async-stream = "0.1.0-alpha.1"
|
||||||
async-trait = ""
|
async-trait = "0.1.7"
|
||||||
futures_codec = "0.2.5"
|
futures_codec = "0.2.5"
|
||||||
term = "0.5.2"
|
term = "0.5.2"
|
||||||
bytes = "0.4.12"
|
bytes = "0.4.12"
|
||||||
log = "0.4.7"
|
log = "0.4.8"
|
||||||
pretty_env_logger = "0.3.0"
|
pretty_env_logger = "0.3.0"
|
||||||
serde = { version = "1.0.94", features = ["derive"] }
|
serde = { version = "1.0.98", features = ["derive"] }
|
||||||
serde_json = "1.0.40"
|
serde_json = "1.0.40"
|
||||||
serde-hjson = "0.9.0"
|
serde-hjson = "0.9.0"
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
|
@ -54,8 +54,9 @@ clap = "2.33.0"
|
||||||
enum_derive = "0.1.7"
|
enum_derive = "0.1.7"
|
||||||
adhoc_derive = "0.1.2"
|
adhoc_derive = "0.1.2"
|
||||||
lazy_static = "1.3.0"
|
lazy_static = "1.3.0"
|
||||||
git2 = "0.9.1"
|
git2 = "0.9.2"
|
||||||
dirs = "2.0.1"
|
dirs = "2.0.2"
|
||||||
|
glob = "0.3.0"
|
||||||
ctrlc = "3.1.3"
|
ctrlc = "3.1.3"
|
||||||
ptree = "0.2"
|
ptree = "0.2"
|
||||||
clipboard = "0.5"
|
clipboard = "0.5"
|
||||||
|
@ -64,21 +65,24 @@ roxmltree = "0.6.1"
|
||||||
nom5_locate = "0.1.1"
|
nom5_locate = "0.1.1"
|
||||||
derive_more = "0.15.0"
|
derive_more = "0.15.0"
|
||||||
enum-utils = "0.1.1"
|
enum-utils = "0.1.1"
|
||||||
unicode-xid = "0.1.0"
|
unicode-xid = "0.2.0"
|
||||||
serde_ini = "0.2.0"
|
serde_ini = "0.2.0"
|
||||||
subprocess = "0.1.18"
|
subprocess = "0.1.18"
|
||||||
sys-info = "0.5.7"
|
sys-info = "0.5.7"
|
||||||
mime = "0.3.13"
|
mime = "0.3.13"
|
||||||
regex = "1.1.9"
|
regex = "1.2.1"
|
||||||
pretty-hex = "0.1.0"
|
pretty-hex = "0.1.0"
|
||||||
neso = "0.5.0"
|
neso = "0.5.0"
|
||||||
rawkey = "0.1.1"
|
rawkey = "0.1.2"
|
||||||
crossterm = "0.9.6"
|
crossterm = "0.10.2"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
image = "0.21.2"
|
image = "0.22.1"
|
||||||
semver = "0.9.0"
|
semver = "0.9.0"
|
||||||
uuid = {version = "0.7.4", features = [ "v4", "serde" ]}
|
uuid = {version = "0.7.4", features = [ "v4", "serde" ]}
|
||||||
syntect = "3.2.0"
|
syntect = "3.2.0"
|
||||||
|
strip-ansi-escapes = "0.1.0"
|
||||||
|
onig_sys = "=69.1"
|
||||||
|
heim = "0.0.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
pretty_assertions = "0.6.1"
|
pretty_assertions = "0.6.1"
|
||||||
|
@ -92,6 +96,10 @@ path = "src/lib.rs"
|
||||||
name = "nu_plugin_inc"
|
name = "nu_plugin_inc"
|
||||||
path = "src/plugins/inc.rs"
|
path = "src/plugins/inc.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "nu_plugin_sum"
|
||||||
|
path = "src/plugins/sum.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "nu_plugin_add"
|
name = "nu_plugin_add"
|
||||||
path = "src/plugins/add.rs"
|
path = "src/plugins/add.rs"
|
||||||
|
@ -100,10 +108,18 @@ path = "src/plugins/add.rs"
|
||||||
name = "nu_plugin_edit"
|
name = "nu_plugin_edit"
|
||||||
path = "src/plugins/edit.rs"
|
path = "src/plugins/edit.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "nu_plugin_str"
|
||||||
|
path = "src/plugins/str.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "nu_plugin_skip"
|
name = "nu_plugin_skip"
|
||||||
path = "src/plugins/skip.rs"
|
path = "src/plugins/skip.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "nu_plugin_sys"
|
||||||
|
path = "src/plugins/sys.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "nu_plugin_tree"
|
name = "nu_plugin_tree"
|
||||||
path = "src/plugins/tree.rs"
|
path = "src/plugins/tree.rs"
|
||||||
|
@ -112,6 +128,10 @@ path = "src/plugins/tree.rs"
|
||||||
name = "nu_plugin_binaryview"
|
name = "nu_plugin_binaryview"
|
||||||
path = "src/plugins/binaryview.rs"
|
path = "src/plugins/binaryview.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "nu_plugin_textview"
|
||||||
|
path = "src/plugins/textview.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "nu"
|
name = "nu"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
26
README.md
26
README.md
|
@ -79,7 +79,7 @@ We can pipeline this into a command that gets the contents of one of the columns
|
||||||
-------------+----------------------------+---------+---------+------+---------
|
-------------+----------------------------+---------+---------+------+---------
|
||||||
authors | description | edition | license | name | version
|
authors | description | edition | license | name | version
|
||||||
-------------+----------------------------+---------+---------+------+---------
|
-------------+----------------------------+---------+---------+------+---------
|
||||||
[list List] | A shell for the GitHub era | 2018 | MIT | nu | 0.1.2
|
[list List] | A shell for the GitHub era | 2018 | MIT | nu | 0.1.3
|
||||||
-------------+----------------------------+---------+---------+------+---------
|
-------------+----------------------------+---------+---------+------+---------
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -87,11 +87,18 @@ Finally, we can use commands outside of Nu once we have the data we want:
|
||||||
|
|
||||||
```
|
```
|
||||||
/home/jonathan/Source/nushell(master)> open Cargo.toml | get package.version | echo $it
|
/home/jonathan/Source/nushell(master)> open Cargo.toml | get package.version | echo $it
|
||||||
0.1.2
|
0.1.3
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we use the variable `$it` to refer to the value being piped to the external command.
|
Here we use the variable `$it` to refer to the value being piped to the external command.
|
||||||
|
|
||||||
|
## Shells
|
||||||
|
|
||||||
|
By default, Nu will work inside of a single directory and allow you to navigate around your filesystem. Sometimes, you'll want to work in multiple directories at the same time. For this, Nu offers a way of adding additional working directories that you can jump between.
|
||||||
|
|
||||||
|
To do so, use the `enter` command, which will allow you create a new "shell" and enter it at the specified path. You can toggle between this new shell and the original shell with the `p` (for previous) and `n` (for next), allowing you to navigate around a ring buffer of shells. Once you're done with a shell, you can `exit` it and remove it from the ring buffer.
|
||||||
|
|
||||||
|
Finally, to get a list of all the current shells, you can use the `shells` command.
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
|
||||||
|
@ -120,12 +127,19 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
|
||||||
| command | description |
|
| command | description |
|
||||||
| ------------- | ------------- |
|
| ------------- | ------------- |
|
||||||
| cd path | Change to a new path |
|
| cd path | Change to a new path |
|
||||||
|
| cp source path | Copy files |
|
||||||
| ls (path) | View the contents of the current or given path |
|
| ls (path) | View the contents of the current or given path |
|
||||||
|
| mkdir path | Make directories, creates intermediary directories as required. |
|
||||||
|
| date (--utc) | Get the current datetime |
|
||||||
| ps | View current processes |
|
| ps | View current processes |
|
||||||
| sysinfo | View information about the current system |
|
| sys | View information about the current system |
|
||||||
| open {filename or url} | Load a file into a cell, convert to table if possible (avoid by appending '--raw') |
|
| open {filename or url} | Load a file into a cell, convert to table if possible (avoid by appending '--raw') |
|
||||||
| rm {file or directory} | Remove a file, (for removing directory append '--recursive') |
|
| rm {file or directory} | Remove a file, (for removing directory append '--recursive') |
|
||||||
| exit | Exit the shell |
|
| exit (--now) | Exit the current shell (or all shells) |
|
||||||
|
| enter (path) | Create a new shell and begin at this path |
|
||||||
|
| p | Go to previous shell |
|
||||||
|
| n | Go to next shell |
|
||||||
|
| shells | Display the list of current shells |
|
||||||
|
|
||||||
## Filters on tables (structured data)
|
## Filters on tables (structured data)
|
||||||
| command | description |
|
| command | description |
|
||||||
|
@ -137,13 +151,17 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
|
||||||
| where condition | Filter table to match the condition |
|
| where condition | Filter table to match the condition |
|
||||||
| inc (field) | Increment a value or version. Optional use the field of a table |
|
| inc (field) | Increment a value or version. Optional use the field of a table |
|
||||||
| add field value | Add a new field to the table |
|
| add field value | Add a new field to the table |
|
||||||
|
| sum | Sum a column of values |
|
||||||
| edit field value | Edit an existing field to have a new value |
|
| edit field value | Edit an existing field to have a new value |
|
||||||
| skip amount | Skip a number of rows |
|
| skip amount | Skip a number of rows |
|
||||||
| first amount | Show only the first number of rows |
|
| first amount | Show only the first number of rows |
|
||||||
|
| str (field) | Apply string function. Optional use the field of a table |
|
||||||
|
| tags | Read the tags (metadata) for values |
|
||||||
| to-array | Collapse rows into a single list |
|
| to-array | Collapse rows into a single list |
|
||||||
| to-json | Convert table into .json text |
|
| to-json | Convert table into .json text |
|
||||||
| to-toml | Convert table into .toml text |
|
| to-toml | Convert table into .toml text |
|
||||||
| to-yaml | Convert table into .yaml text |
|
| to-yaml | Convert table into .yaml text |
|
||||||
|
| to-csv | Convert table into .csv text |
|
||||||
|
|
||||||
## Filters on text (unstructured data)
|
## Filters on text (unstructured data)
|
||||||
| command | description |
|
| command | description |
|
||||||
|
|
41
src/cli.rs
41
src/cli.rs
|
@ -5,12 +5,11 @@ use crate::commands::classified::{
|
||||||
};
|
};
|
||||||
use crate::commands::plugin::JsonRpc;
|
use crate::commands::plugin::JsonRpc;
|
||||||
use crate::commands::plugin::PluginCommand;
|
use crate::commands::plugin::PluginCommand;
|
||||||
use crate::commands::{static_command, Command};
|
use crate::commands::static_command;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
use crate::git::current_branch;
|
use crate::git::current_branch;
|
||||||
use crate::object::Value;
|
use crate::object::Value;
|
||||||
use crate::parser::parse::span::Spanned;
|
|
||||||
use crate::parser::registry::Signature;
|
use crate::parser::registry::Signature;
|
||||||
use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
|
use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
@ -150,11 +149,14 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
command("from-xml", Box::new(from_xml::from_xml)),
|
command("from-xml", Box::new(from_xml::from_xml)),
|
||||||
command("ps", Box::new(ps::ps)),
|
command("ps", Box::new(ps::ps)),
|
||||||
command("ls", Box::new(ls::ls)),
|
command("ls", Box::new(ls::ls)),
|
||||||
command("sysinfo", Box::new(sysinfo::sysinfo)),
|
|
||||||
command("size", Box::new(size::size)),
|
command("size", Box::new(size::size)),
|
||||||
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
||||||
command("exit", Box::new(exit::exit)),
|
command("enter", Box::new(enter::enter)),
|
||||||
|
command("n", Box::new(next::next)),
|
||||||
|
command("p", Box::new(prev::prev)),
|
||||||
command("lines", Box::new(lines::lines)),
|
command("lines", Box::new(lines::lines)),
|
||||||
|
command("pick", Box::new(pick::pick)),
|
||||||
|
command("shells", Box::new(shells::shells)),
|
||||||
command("split-column", Box::new(split_column::split_column)),
|
command("split-column", Box::new(split_column::split_column)),
|
||||||
command("split-row", Box::new(split_row::split_row)),
|
command("split-row", Box::new(split_row::split_row)),
|
||||||
command("lines", Box::new(lines::lines)),
|
command("lines", Box::new(lines::lines)),
|
||||||
|
@ -166,6 +168,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
command("to-toml", Box::new(to_toml::to_toml)),
|
command("to-toml", Box::new(to_toml::to_toml)),
|
||||||
command("to-yaml", Box::new(to_yaml::to_yaml)),
|
command("to-yaml", Box::new(to_yaml::to_yaml)),
|
||||||
command("sort-by", Box::new(sort_by::sort_by)),
|
command("sort-by", Box::new(sort_by::sort_by)),
|
||||||
|
command("tags", Box::new(tags::tags)),
|
||||||
static_command(Get),
|
static_command(Get),
|
||||||
static_command(Cd),
|
static_command(Cd),
|
||||||
static_command(Remove),
|
static_command(Remove),
|
||||||
|
@ -173,8 +176,12 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
static_command(Where),
|
static_command(Where),
|
||||||
static_command(Config),
|
static_command(Config),
|
||||||
static_command(SkipWhile),
|
static_command(SkipWhile),
|
||||||
|
static_command(Exit),
|
||||||
static_command(Clip),
|
static_command(Clip),
|
||||||
static_command(Autoview),
|
static_command(Autoview),
|
||||||
|
static_command(Copycp),
|
||||||
|
static_command(Date),
|
||||||
|
static_command(Mkdir),
|
||||||
static_command(Save),
|
static_command(Save),
|
||||||
static_command(Table),
|
static_command(Table),
|
||||||
static_command(VTable),
|
static_command(VTable),
|
||||||
|
@ -183,15 +190,15 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
let _ = load_plugins(&mut context);
|
let _ = load_plugins(&mut context);
|
||||||
|
|
||||||
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
||||||
let h = crate::shell::Helper::new(context.clone_commands());
|
//let h = crate::shell::Helper::new(context.clone_commands());
|
||||||
let mut rl: Editor<crate::shell::Helper> = Editor::with_config(config);
|
let mut rl: Editor<_> = Editor::with_config(config);
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
let _ = ansi_term::enable_ansi_support();
|
let _ = ansi_term::enable_ansi_support();
|
||||||
}
|
}
|
||||||
|
|
||||||
rl.set_helper(Some(h));
|
//rl.set_helper(Some(h));
|
||||||
let _ = rl.load_history("history.txt");
|
let _ = rl.load_history("history.txt");
|
||||||
|
|
||||||
let ctrl_c = Arc::new(AtomicBool::new(false));
|
let ctrl_c = Arc::new(AtomicBool::new(false));
|
||||||
|
@ -207,10 +214,12 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = {
|
let cwd = context.shell_manager.path();
|
||||||
let env = context.env.lock().unwrap();
|
|
||||||
env.path().display().to_string()
|
rl.set_helper(Some(crate::shell::Helper::new(
|
||||||
};
|
context.shell_manager.clone(),
|
||||||
|
)));
|
||||||
|
|
||||||
let readline = rl.readline(&format!(
|
let readline = rl.readline(&format!(
|
||||||
"{}{}> ",
|
"{}{}> ",
|
||||||
cwd,
|
cwd,
|
||||||
|
@ -336,7 +345,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||||
.commands
|
.commands
|
||||||
.push(ClassifiedCommand::Internal(InternalCommand {
|
.push(ClassifiedCommand::Internal(InternalCommand {
|
||||||
command: static_command(autoview::Autoview),
|
command: static_command(autoview::Autoview),
|
||||||
name_span: None,
|
name_span: Span::unknown(),
|
||||||
source_map: ctx.source_map.clone(),
|
source_map: ctx.source_map.clone(),
|
||||||
args: hir::Call::new(
|
args: hir::Call::new(
|
||||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||||
|
@ -473,19 +482,19 @@ fn classify_command(
|
||||||
|
|
||||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||||
command,
|
command,
|
||||||
name_span: Some(head.span().clone()),
|
name_span: head.span().clone(),
|
||||||
source_map: context.source_map.clone(),
|
source_map: context.source_map.clone(),
|
||||||
args,
|
args,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
let arg_list_strings: Vec<Spanned<String>> = match call.children() {
|
let arg_list_strings: Vec<Tagged<String>> = match call.children() {
|
||||||
//Some(args) => args.iter().map(|i| i.as_external_arg(source)).collect(),
|
//Some(args) => args.iter().map(|i| i.as_external_arg(source)).collect(),
|
||||||
Some(args) => args
|
Some(args) => args
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|i| match i {
|
.filter_map(|i| match i {
|
||||||
TokenNode::Whitespace(_) => None,
|
TokenNode::Whitespace(_) => None,
|
||||||
other => Some(Spanned::from_item(
|
other => Some(Tagged::from_simple_spanned_item(
|
||||||
other.as_external_arg(source),
|
other.as_external_arg(source),
|
||||||
other.span(),
|
other.span(),
|
||||||
)),
|
)),
|
||||||
|
@ -496,7 +505,7 @@ fn classify_command(
|
||||||
|
|
||||||
Ok(ClassifiedCommand::External(ExternalCommand {
|
Ok(ClassifiedCommand::External(ExternalCommand {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
name_span: Some(head.span().clone()),
|
name_span: head.span().clone(),
|
||||||
args: arg_list_strings,
|
args: arg_list_strings,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@ crate mod classified;
|
||||||
crate mod clip;
|
crate mod clip;
|
||||||
crate mod command;
|
crate mod command;
|
||||||
crate mod config;
|
crate mod config;
|
||||||
|
crate mod cp;
|
||||||
|
crate mod date;
|
||||||
|
crate mod enter;
|
||||||
crate mod exit;
|
crate mod exit;
|
||||||
crate mod first;
|
crate mod first;
|
||||||
crate mod from_csv;
|
crate mod from_csv;
|
||||||
|
@ -19,20 +22,24 @@ crate mod from_yaml;
|
||||||
crate mod get;
|
crate mod get;
|
||||||
crate mod lines;
|
crate mod lines;
|
||||||
crate mod ls;
|
crate mod ls;
|
||||||
|
crate mod mkdir;
|
||||||
|
crate mod next;
|
||||||
crate mod open;
|
crate mod open;
|
||||||
crate mod pick;
|
crate mod pick;
|
||||||
crate mod plugin;
|
crate mod plugin;
|
||||||
|
crate mod prev;
|
||||||
crate mod ps;
|
crate mod ps;
|
||||||
crate mod reject;
|
crate mod reject;
|
||||||
crate mod rm;
|
crate mod rm;
|
||||||
crate mod save;
|
crate mod save;
|
||||||
|
crate mod shells;
|
||||||
crate mod size;
|
crate mod size;
|
||||||
crate mod skip_while;
|
crate mod skip_while;
|
||||||
crate mod sort_by;
|
crate mod sort_by;
|
||||||
crate mod split_column;
|
crate mod split_column;
|
||||||
crate mod split_row;
|
crate mod split_row;
|
||||||
crate mod sysinfo;
|
|
||||||
crate mod table;
|
crate mod table;
|
||||||
|
crate mod tags;
|
||||||
crate mod to_array;
|
crate mod to_array;
|
||||||
crate mod to_csv;
|
crate mod to_csv;
|
||||||
crate mod to_json;
|
crate mod to_json;
|
||||||
|
@ -50,7 +57,11 @@ crate use command::{
|
||||||
UnevaluatedCallInfo,
|
UnevaluatedCallInfo,
|
||||||
};
|
};
|
||||||
crate use config::Config;
|
crate use config::Config;
|
||||||
|
crate use cp::Copycp;
|
||||||
|
crate use date::Date;
|
||||||
|
crate use exit::Exit;
|
||||||
crate use get::Get;
|
crate use get::Get;
|
||||||
|
crate use mkdir::Mkdir;
|
||||||
crate use open::Open;
|
crate use open::Open;
|
||||||
crate use rm::Remove;
|
crate use rm::Remove;
|
||||||
crate use save::Save;
|
crate use save::Save;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::commands::{RawCommandArgs, StaticCommand};
|
use crate::commands::{RawCommandArgs, StaticCommand};
|
||||||
use crate::context::{SourceMap, SpanSource};
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
pub struct Autoview;
|
pub struct Autoview;
|
||||||
|
|
||||||
|
@ -36,15 +34,15 @@ pub fn autoview(
|
||||||
let input = context.input.drain_vec().await;
|
let input = context.input.drain_vec().await;
|
||||||
|
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
if let Spanned {
|
if let Tagged {
|
||||||
item: Value::Binary(_),
|
item: Value::Binary(_),
|
||||||
..
|
..
|
||||||
} = input[0]
|
} = input[0usize]
|
||||||
{
|
{
|
||||||
let binary = context.expect_command("binaryview");
|
let binary = context.expect_command("binaryview");
|
||||||
binary.run(raw.with_input(input), &context.commands).await;
|
binary.run(raw.with_input(input), &context.commands).await;
|
||||||
} else if is_single_text_value(&input) {
|
} else if is_single_text_value(&input) {
|
||||||
view_text_value(&input[0], &raw.call_info.source_map);
|
//view_text_value(&input[0], &raw.call_info.source_map);
|
||||||
} else if equal_shapes(&input) {
|
} else if equal_shapes(&input) {
|
||||||
let table = context.expect_command("table");
|
let table = context.expect_command("table");
|
||||||
let result = table.run(raw.with_input(input), &context.commands).await.unwrap();
|
let result = table.run(raw.with_input(input), &context.commands).await.unwrap();
|
||||||
|
@ -63,7 +61,7 @@ pub fn autoview(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {
|
fn equal_shapes(input: &Vec<Tagged<Value>>) -> bool {
|
||||||
let mut items = input.iter();
|
let mut items = input.iter();
|
||||||
|
|
||||||
let item = match items.next() {
|
let item = match items.next() {
|
||||||
|
@ -82,11 +80,11 @@ fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_single_text_value(input: &Vec<Spanned<Value>>) -> bool {
|
fn is_single_text_value(input: &Vec<Tagged<Value>>) -> bool {
|
||||||
if input.len() != 1 {
|
if input.len() != 1 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if let Spanned {
|
if let Tagged {
|
||||||
item: Value::Primitive(Primitive::String(_)),
|
item: Value::Primitive(Primitive::String(_)),
|
||||||
..
|
..
|
||||||
} = input[0]
|
} = input[0]
|
||||||
|
@ -96,63 +94,3 @@ fn is_single_text_value(input: &Vec<Spanned<Value>>) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_text_value(value: &Spanned<Value>, source_map: &SourceMap) {
|
|
||||||
match value {
|
|
||||||
Spanned {
|
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
|
||||||
span,
|
|
||||||
} => {
|
|
||||||
let source = span.source.map(|x| source_map.get(&x)).flatten();
|
|
||||||
|
|
||||||
if let Some(source) = source {
|
|
||||||
match source {
|
|
||||||
SpanSource::File(file) => {
|
|
||||||
let path = Path::new(file);
|
|
||||||
match path.extension() {
|
|
||||||
Some(extension) => {
|
|
||||||
use syntect::easy::HighlightLines;
|
|
||||||
use syntect::highlighting::{Style, ThemeSet};
|
|
||||||
use syntect::parsing::SyntaxSet;
|
|
||||||
use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};
|
|
||||||
|
|
||||||
// Load these once at the start of your program
|
|
||||||
let ps: SyntaxSet = syntect::dumps::from_binary(include_bytes!(
|
|
||||||
"../../assets/syntaxes.bin"
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(syntax) =
|
|
||||||
ps.find_syntax_by_extension(extension.to_str().unwrap())
|
|
||||||
{
|
|
||||||
let ts: ThemeSet = syntect::dumps::from_binary(include_bytes!(
|
|
||||||
"../../assets/themes.bin"
|
|
||||||
));
|
|
||||||
let mut h =
|
|
||||||
HighlightLines::new(syntax, &ts.themes["OneHalfDark"]);
|
|
||||||
|
|
||||||
for line in LinesWithEndings::from(s) {
|
|
||||||
let ranges: Vec<(Style, &str)> = h.highlight(line, &ps);
|
|
||||||
let escaped =
|
|
||||||
as_24_bit_terminal_escaped(&ranges[..], false);
|
|
||||||
print!("{}", escaped);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("{}", s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub struct Cd;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct CdArgs {
|
pub struct CdArgs {
|
||||||
target: Option<Spanned<PathBuf>>,
|
target: Option<Tagged<PathBuf>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StaticCommand for Cd {
|
impl StaticCommand for Cd {
|
||||||
|
@ -39,7 +39,7 @@ pub fn cd(CdArgs { target }: CdArgs, context: RunnableContext) -> Result<OutputS
|
||||||
None => match dirs::home_dir() {
|
None => match dirs::home_dir() {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Can not change to home directory",
|
"Can not change to home directory",
|
||||||
"can not go to home",
|
"can not go to home",
|
||||||
context.name,
|
context.name,
|
||||||
|
@ -54,7 +54,7 @@ pub fn cd(CdArgs { target }: CdArgs, context: RunnableContext) -> Result<OutputS
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Can not change to directory",
|
"Can not change to directory",
|
||||||
"directory not found",
|
"directory not found",
|
||||||
v.span.clone(),
|
v.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,18 @@ pub fn cd(CdArgs { target }: CdArgs, context: RunnableContext) -> Result<OutputS
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Can not change to directory",
|
"Can not change to directory",
|
||||||
"directory not found",
|
"directory not found",
|
||||||
path.span,
|
path.span(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::string("Can not change to directory"));
|
return Err(ShellError::string("Can not change to directory"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stream.push_back(ReturnSuccess::change_cwd(path));
|
stream.push_back(ReturnSuccess::change_cwd(
|
||||||
|
path.to_string_lossy().to_string(),
|
||||||
|
));
|
||||||
Ok(stream.into())
|
Ok(stream.into())
|
||||||
|
|
||||||
|
// pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
// args.shell_manager.cd(args.call_info, args.input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::commands::Command;
|
use crate::commands::Command;
|
||||||
use crate::context::SourceMap;
|
use crate::context::SourceMap;
|
||||||
use crate::parser::{hir, Span, Spanned, TokenNode};
|
use crate::parser::{hir, TokenNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
@ -98,7 +98,7 @@ impl ClassifiedCommand {
|
||||||
|
|
||||||
crate struct InternalCommand {
|
crate struct InternalCommand {
|
||||||
crate command: Arc<Command>,
|
crate command: Arc<Command>,
|
||||||
crate name_span: Option<Span>,
|
crate name_span: Span,
|
||||||
crate source_map: SourceMap,
|
crate source_map: SourceMap,
|
||||||
crate args: hir::Call,
|
crate args: hir::Call,
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ impl InternalCommand {
|
||||||
.run_command(
|
.run_command(
|
||||||
self.command,
|
self.command,
|
||||||
self.name_span.clone(),
|
self.name_span.clone(),
|
||||||
self.source_map,
|
context.source_map.clone(),
|
||||||
self.args,
|
self.args,
|
||||||
source,
|
source,
|
||||||
objects,
|
objects,
|
||||||
|
@ -137,12 +137,62 @@ impl InternalCommand {
|
||||||
match item? {
|
match item? {
|
||||||
ReturnSuccess::Action(action) => match action {
|
ReturnSuccess::Action(action) => match action {
|
||||||
CommandAction::ChangePath(path) => {
|
CommandAction::ChangePath(path) => {
|
||||||
context.env.lock().unwrap().path = path;
|
context.shell_manager.set_path(path);
|
||||||
}
|
}
|
||||||
CommandAction::AddSpanSource(uuid, span_source) => {
|
CommandAction::AddSpanSource(uuid, span_source) => {
|
||||||
context.add_span_source(uuid, span_source);
|
context.add_span_source(uuid, span_source);
|
||||||
}
|
}
|
||||||
CommandAction::Exit => std::process::exit(0),
|
CommandAction::Exit => std::process::exit(0),
|
||||||
|
CommandAction::EnterShell(location) => {
|
||||||
|
let path = std::path::Path::new(&location);
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
// If it's a directory, add a new filesystem shell
|
||||||
|
context
|
||||||
|
.shell_manager
|
||||||
|
.push(Box::new(FilesystemShell::with_location(location)?));
|
||||||
|
} else {
|
||||||
|
// If it's a file, attempt to open the file as a value and enter it
|
||||||
|
let cwd = context.shell_manager.path();
|
||||||
|
|
||||||
|
let full_path = std::path::PathBuf::from(cwd);
|
||||||
|
|
||||||
|
let (file_extension, contents, contents_tag, _) =
|
||||||
|
crate::commands::open::fetch(
|
||||||
|
&full_path,
|
||||||
|
&location,
|
||||||
|
Span::unknown(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
match contents {
|
||||||
|
Value::Primitive(Primitive::String(string)) => {
|
||||||
|
let value = crate::commands::open::parse_as_value(
|
||||||
|
file_extension,
|
||||||
|
string,
|
||||||
|
contents_tag,
|
||||||
|
Span::unknown(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
context.shell_manager.push(Box::new(ValueShell::new(value)));
|
||||||
|
}
|
||||||
|
value => context
|
||||||
|
.shell_manager
|
||||||
|
.push(Box::new(ValueShell::new(value.tagged(Tag::unknown())))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandAction::PreviousShell => {
|
||||||
|
context.shell_manager.prev();
|
||||||
|
}
|
||||||
|
CommandAction::NextShell => {
|
||||||
|
context.shell_manager.next();
|
||||||
|
}
|
||||||
|
CommandAction::LeaveShell => {
|
||||||
|
context.shell_manager.pop();
|
||||||
|
if context.shell_manager.is_empty() {
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ReturnSuccess::Value(v) => {
|
ReturnSuccess::Value(v) => {
|
||||||
|
@ -158,8 +208,8 @@ impl InternalCommand {
|
||||||
crate struct ExternalCommand {
|
crate struct ExternalCommand {
|
||||||
crate name: String,
|
crate name: String,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
crate name_span: Option<Span>,
|
crate name_span: Span,
|
||||||
crate args: Vec<Spanned<String>>,
|
crate args: Vec<Tagged<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate enum StreamNext {
|
crate enum StreamNext {
|
||||||
|
@ -176,7 +226,7 @@ impl ExternalCommand {
|
||||||
stream_next: StreamNext,
|
stream_next: StreamNext,
|
||||||
) -> Result<ClassifiedInputStream, ShellError> {
|
) -> Result<ClassifiedInputStream, ShellError> {
|
||||||
let stdin = input.stdin;
|
let stdin = input.stdin;
|
||||||
let inputs: Vec<Spanned<Value>> = input.objects.into_vec().await;
|
let inputs: Vec<Tagged<Value>> = input.objects.into_vec().await;
|
||||||
let name_span = self.name_span.clone();
|
let name_span = self.name_span.clone();
|
||||||
|
|
||||||
trace!(target: "nu::run::external", "-> {}", self.name);
|
trace!(target: "nu::run::external", "-> {}", self.name);
|
||||||
|
@ -201,7 +251,7 @@ impl ExternalCommand {
|
||||||
let mut span = None;
|
let mut span = None;
|
||||||
for arg in &self.args {
|
for arg in &self.args {
|
||||||
if arg.item.contains("$it") {
|
if arg.item.contains("$it") {
|
||||||
span = Some(arg.span);
|
span = Some(arg.span());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(span) = span {
|
if let Some(span) = span {
|
||||||
|
@ -231,7 +281,17 @@ impl ExternalCommand {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for arg in &self.args {
|
for arg in &self.args {
|
||||||
process = process.arg(arg.item.clone());
|
let arg_chars: Vec<_> = arg.chars().collect();
|
||||||
|
if arg_chars.len() > 1
|
||||||
|
&& arg_chars[0] == '"'
|
||||||
|
&& arg_chars[arg_chars.len() - 1] == '"'
|
||||||
|
{
|
||||||
|
// quoted string
|
||||||
|
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
|
||||||
|
process = process.arg(new_arg);
|
||||||
|
} else {
|
||||||
|
process = process.arg(arg.item.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,13 +303,13 @@ impl ExternalCommand {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for i in &inputs {
|
for i in &inputs {
|
||||||
if i.as_string().is_err() {
|
if i.as_string().is_err() {
|
||||||
let mut span = None;
|
let mut span = name_span;
|
||||||
for arg in &self.args {
|
for arg in &self.args {
|
||||||
if arg.item.contains("$it") {
|
if arg.item.contains("$it") {
|
||||||
span = Some(arg.span);
|
span = arg.span();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"External $it needs string data",
|
"External $it needs string data",
|
||||||
"given object instead of string data",
|
"given object instead of string data",
|
||||||
span,
|
span,
|
||||||
|
@ -280,7 +340,7 @@ impl ExternalCommand {
|
||||||
|
|
||||||
process = Exec::shell(new_arg_string);
|
process = Exec::shell(new_arg_string);
|
||||||
}
|
}
|
||||||
process = process.cwd(context.env.lock().unwrap().path());
|
process = process.cwd(context.shell_manager.path());
|
||||||
|
|
||||||
let mut process = match stream_next {
|
let mut process = match stream_next {
|
||||||
StreamNext::Last => process,
|
StreamNext::Last => process,
|
||||||
|
@ -308,10 +368,11 @@ impl ExternalCommand {
|
||||||
let stdout = popen.stdout.take().unwrap();
|
let stdout = popen.stdout.take().unwrap();
|
||||||
let file = futures::io::AllowStdIo::new(stdout);
|
let file = futures::io::AllowStdIo::new(stdout);
|
||||||
let stream = Framed::new(file, LinesCodec {});
|
let stream = Framed::new(file, LinesCodec {});
|
||||||
let stream =
|
let stream = stream.map(move |line| {
|
||||||
stream.map(move |line| Value::string(line.unwrap()).spanned(name_span));
|
Tagged::from_simple_spanned_item(Value::string(line.unwrap()), name_span)
|
||||||
|
});
|
||||||
Ok(ClassifiedInputStream::from_input_stream(
|
Ok(ClassifiedInputStream::from_input_stream(
|
||||||
stream.boxed() as BoxStream<'static, Spanned<Value>>
|
stream.boxed() as BoxStream<'static, Tagged<Value>>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub fn clip(
|
||||||
RunnableContext { input, name, .. }: RunnableContext,
|
RunnableContext { input, name, .. }: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream_block! {
|
let stream = async_stream_block! {
|
||||||
let values: Vec<Spanned<Value>> = input.values.collect().await;
|
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
||||||
|
|
||||||
inner_clip(values, name).await;
|
inner_clip(values, name).await;
|
||||||
};
|
};
|
||||||
|
@ -43,7 +43,7 @@ pub fn clip(
|
||||||
Ok(OutputStream::from(stream))
|
Ok(OutputStream::from(stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inner_clip(input: Vec<Spanned<Value>>, name: Option<Span>) -> OutputStream {
|
async fn inner_clip(input: Vec<Tagged<Value>>, name: Span) -> OutputStream {
|
||||||
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||||
let mut new_copy_data = String::new();
|
let mut new_copy_data = String::new();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::errors::ShellError;
|
||||||
use crate::evaluate::Scope;
|
use crate::evaluate::Scope;
|
||||||
use crate::object::Value;
|
use crate::object::Value;
|
||||||
use crate::parser::hir;
|
use crate::parser::hir;
|
||||||
use crate::parser::{registry, ConfigDeserializer, Span, Spanned};
|
use crate::parser::{registry, ConfigDeserializer};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
|
@ -18,7 +18,7 @@ pub struct UnevaluatedCallInfo {
|
||||||
pub args: hir::Call,
|
pub args: hir::Call,
|
||||||
pub source: Text,
|
pub source: Text,
|
||||||
pub source_map: SourceMap,
|
pub source_map: SourceMap,
|
||||||
pub name_span: Option<Span>,
|
pub name_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToDebug for UnevaluatedCallInfo {
|
impl ToDebug for UnevaluatedCallInfo {
|
||||||
|
@ -43,19 +43,22 @@ impl UnevaluatedCallInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct CallInfo {
|
pub struct CallInfo {
|
||||||
pub args: registry::EvaluatedArgs,
|
pub args: registry::EvaluatedArgs,
|
||||||
pub source_map: SourceMap,
|
pub source_map: SourceMap,
|
||||||
pub name_span: Option<Span>,
|
pub name_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Getters)]
|
#[derive(Getters)]
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct CommandArgs {
|
pub struct CommandArgs {
|
||||||
pub host: Arc<Mutex<dyn Host>>,
|
pub host: Arc<Mutex<dyn Host>>,
|
||||||
pub env: Arc<Mutex<Environment>>,
|
pub shell_manager: ShellManager,
|
||||||
pub call_info: UnevaluatedCallInfo,
|
pub call_info: UnevaluatedCallInfo,
|
||||||
|
// pub host: Arc<Mutex<dyn Host + Send>>,
|
||||||
|
// pub shell_manager: ShellManager,
|
||||||
|
// pub call_info: CallInfo,
|
||||||
pub input: InputStream,
|
pub input: InputStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,15 +66,15 @@ pub struct CommandArgs {
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct RawCommandArgs {
|
pub struct RawCommandArgs {
|
||||||
pub host: Arc<Mutex<dyn Host>>,
|
pub host: Arc<Mutex<dyn Host>>,
|
||||||
pub env: Arc<Mutex<Environment>>,
|
pub shell_manager: ShellManager,
|
||||||
pub call_info: UnevaluatedCallInfo,
|
pub call_info: UnevaluatedCallInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawCommandArgs {
|
impl RawCommandArgs {
|
||||||
pub fn with_input(self, input: Vec<Spanned<Value>>) -> CommandArgs {
|
pub fn with_input(self, input: Vec<Tagged<Value>>) -> CommandArgs {
|
||||||
CommandArgs {
|
CommandArgs {
|
||||||
host: self.host,
|
host: self.host,
|
||||||
env: self.env,
|
shell_manager: self.shell_manager,
|
||||||
call_info: self.call_info,
|
call_info: self.call_info,
|
||||||
input: input.into(),
|
input: input.into(),
|
||||||
}
|
}
|
||||||
|
@ -90,14 +93,19 @@ impl CommandArgs {
|
||||||
registry: ®istry::CommandRegistry,
|
registry: ®istry::CommandRegistry,
|
||||||
) -> Result<EvaluatedStaticCommandArgs, ShellError> {
|
) -> Result<EvaluatedStaticCommandArgs, ShellError> {
|
||||||
let host = self.host.clone();
|
let host = self.host.clone();
|
||||||
let env = self.env.clone();
|
let shell_manager = self.shell_manager.clone();
|
||||||
let input = self.input;
|
let input = self.input;
|
||||||
let call_info = self.call_info.evaluate(registry, &Scope::empty())?;
|
let call_info = self.call_info.evaluate(registry, &Scope::empty())?;
|
||||||
|
|
||||||
Ok(EvaluatedStaticCommandArgs::new(host, env, call_info, input))
|
Ok(EvaluatedStaticCommandArgs::new(
|
||||||
|
host,
|
||||||
|
shell_manager,
|
||||||
|
call_info,
|
||||||
|
input,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_span(&self) -> Option<Span> {
|
pub fn name_span(&self) -> Span {
|
||||||
self.call_info.name_span
|
self.call_info.name_span
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +114,7 @@ impl CommandArgs {
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
|
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
|
||||||
) -> Result<RunnableArgs<T>, ShellError> {
|
) -> Result<RunnableArgs<T>, ShellError> {
|
||||||
let env = self.env.clone();
|
let shell_manager = self.shell_manager.clone();
|
||||||
let host = self.host.clone();
|
let host = self.host.clone();
|
||||||
let args = self.evaluate_once(registry)?;
|
let args = self.evaluate_once(registry)?;
|
||||||
let (input, args) = args.split();
|
let (input, args) = args.split();
|
||||||
|
@ -118,7 +126,7 @@ impl CommandArgs {
|
||||||
context: RunnableContext {
|
context: RunnableContext {
|
||||||
input: input,
|
input: input,
|
||||||
commands: registry.clone(),
|
commands: registry.clone(),
|
||||||
env,
|
shell_manager,
|
||||||
name: name_span,
|
name: name_span,
|
||||||
host,
|
host,
|
||||||
},
|
},
|
||||||
|
@ -133,11 +141,11 @@ impl CommandArgs {
|
||||||
) -> Result<RunnableRawArgs<T>, ShellError> {
|
) -> Result<RunnableRawArgs<T>, ShellError> {
|
||||||
let raw_args = RawCommandArgs {
|
let raw_args = RawCommandArgs {
|
||||||
host: self.host.clone(),
|
host: self.host.clone(),
|
||||||
env: self.env.clone(),
|
shell_manager: self.shell_manager.clone(),
|
||||||
call_info: self.call_info.clone(),
|
call_info: self.call_info.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let env = self.env.clone();
|
let shell_manager = self.shell_manager.clone();
|
||||||
let host = self.host.clone();
|
let host = self.host.clone();
|
||||||
let args = self.evaluate_once(registry)?;
|
let args = self.evaluate_once(registry)?;
|
||||||
let (input, args) = args.split();
|
let (input, args) = args.split();
|
||||||
|
@ -149,7 +157,7 @@ impl CommandArgs {
|
||||||
context: RunnableContext {
|
context: RunnableContext {
|
||||||
input: input,
|
input: input,
|
||||||
commands: registry.clone(),
|
commands: registry.clone(),
|
||||||
env,
|
shell_manager,
|
||||||
name: name_span,
|
name: name_span,
|
||||||
host,
|
host,
|
||||||
},
|
},
|
||||||
|
@ -161,18 +169,15 @@ impl CommandArgs {
|
||||||
|
|
||||||
pub struct RunnableContext {
|
pub struct RunnableContext {
|
||||||
pub input: InputStream,
|
pub input: InputStream,
|
||||||
pub env: Arc<Mutex<Environment>>,
|
pub shell_manager: ShellManager,
|
||||||
pub host: Arc<Mutex<dyn Host>>,
|
pub host: Arc<Mutex<dyn Host>>,
|
||||||
pub commands: CommandRegistry,
|
pub commands: CommandRegistry,
|
||||||
pub name: Option<Span>,
|
pub name: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunnableContext {
|
impl RunnableContext {
|
||||||
pub fn cwd(&self) -> PathBuf {
|
pub fn cwd(&self) -> PathBuf {
|
||||||
let env = self.env.clone();
|
PathBuf::from(self.shell_manager.path())
|
||||||
let env = env.lock().unwrap();
|
|
||||||
|
|
||||||
env.path.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_command(&self, name: &str) -> Arc<Command> {
|
pub fn expect_command(&self, name: &str) -> Arc<Command> {
|
||||||
|
@ -222,21 +227,21 @@ impl Deref for EvaluatedStaticCommandArgs {
|
||||||
impl EvaluatedStaticCommandArgs {
|
impl EvaluatedStaticCommandArgs {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
host: Arc<Mutex<dyn Host>>,
|
host: Arc<Mutex<dyn Host>>,
|
||||||
env: Arc<Mutex<Environment>>,
|
shell_manager: ShellManager,
|
||||||
call_info: CallInfo,
|
call_info: CallInfo,
|
||||||
input: impl Into<InputStream>,
|
input: impl Into<InputStream>,
|
||||||
) -> EvaluatedStaticCommandArgs {
|
) -> EvaluatedStaticCommandArgs {
|
||||||
EvaluatedStaticCommandArgs {
|
EvaluatedStaticCommandArgs {
|
||||||
args: EvaluatedCommandArgs {
|
args: EvaluatedCommandArgs {
|
||||||
host,
|
host,
|
||||||
env,
|
shell_manager,
|
||||||
call_info,
|
call_info,
|
||||||
},
|
},
|
||||||
input: input.into(),
|
input: input.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_span(&self) -> Option<Span> {
|
pub fn name_span(&self) -> Span {
|
||||||
self.args.call_info.name_span
|
self.args.call_info.name_span
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +263,7 @@ impl EvaluatedStaticCommandArgs {
|
||||||
pub struct EvaluatedFilterCommandArgs {
|
pub struct EvaluatedFilterCommandArgs {
|
||||||
args: EvaluatedCommandArgs,
|
args: EvaluatedCommandArgs,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
input: Spanned<Value>,
|
input: Tagged<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for EvaluatedFilterCommandArgs {
|
impl Deref for EvaluatedFilterCommandArgs {
|
||||||
|
@ -271,14 +276,14 @@ impl Deref for EvaluatedFilterCommandArgs {
|
||||||
impl EvaluatedFilterCommandArgs {
|
impl EvaluatedFilterCommandArgs {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
host: Arc<Mutex<dyn Host>>,
|
host: Arc<Mutex<dyn Host>>,
|
||||||
env: Arc<Mutex<Environment>>,
|
shell_manager: ShellManager,
|
||||||
call_info: CallInfo,
|
call_info: CallInfo,
|
||||||
input: Spanned<Value>,
|
input: Tagged<Value>,
|
||||||
) -> EvaluatedFilterCommandArgs {
|
) -> EvaluatedFilterCommandArgs {
|
||||||
EvaluatedFilterCommandArgs {
|
EvaluatedFilterCommandArgs {
|
||||||
args: EvaluatedCommandArgs {
|
args: EvaluatedCommandArgs {
|
||||||
host,
|
host,
|
||||||
env,
|
shell_manager,
|
||||||
call_info,
|
call_info,
|
||||||
},
|
},
|
||||||
input,
|
input,
|
||||||
|
@ -290,7 +295,7 @@ impl EvaluatedFilterCommandArgs {
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct EvaluatedCommandArgs {
|
pub struct EvaluatedCommandArgs {
|
||||||
pub host: Arc<Mutex<dyn Host>>,
|
pub host: Arc<Mutex<dyn Host>>,
|
||||||
pub env: Arc<Mutex<Environment>>,
|
pub shell_manager: ShellManager,
|
||||||
pub call_info: CallInfo,
|
pub call_info: CallInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,11 +304,11 @@ impl EvaluatedCommandArgs {
|
||||||
&self.call_info.args
|
&self.call_info.args
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
|
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
||||||
self.call_info.args.nth(pos)
|
self.call_info.args.nth(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_nth(&self, pos: usize) -> Result<&Spanned<Value>, ShellError> {
|
pub fn expect_nth(&self, pos: usize) -> Result<&Tagged<Value>, ShellError> {
|
||||||
self.call_info.args.expect_nth(pos)
|
self.call_info.args.expect_nth(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,11 +316,11 @@ impl EvaluatedCommandArgs {
|
||||||
self.call_info.args.len()
|
self.call_info.args.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> Option<&Spanned<Value>> {
|
pub fn get(&self, name: &str) -> Option<&Tagged<Value>> {
|
||||||
self.call_info.args.get(name)
|
self.call_info.args.get(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice_from(&self, from: usize) -> Vec<Spanned<Value>> {
|
pub fn slice_from(&self, from: usize) -> Vec<Tagged<Value>> {
|
||||||
let positional = &self.call_info.args.positional;
|
let positional = &self.call_info.args.positional;
|
||||||
|
|
||||||
match positional {
|
match positional {
|
||||||
|
@ -332,31 +337,35 @@ impl EvaluatedCommandArgs {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum CommandAction {
|
pub enum CommandAction {
|
||||||
ChangePath(PathBuf),
|
ChangePath(String),
|
||||||
AddSpanSource(Uuid, SpanSource),
|
AddSpanSource(Uuid, SpanSource),
|
||||||
Exit,
|
Exit,
|
||||||
|
EnterShell(String),
|
||||||
|
PreviousShell,
|
||||||
|
NextShell,
|
||||||
|
LeaveShell,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum ReturnSuccess {
|
pub enum ReturnSuccess {
|
||||||
Value(Spanned<Value>),
|
Value(Tagged<Value>),
|
||||||
Action(CommandAction),
|
Action(CommandAction),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
||||||
|
|
||||||
impl From<Spanned<Value>> for ReturnValue {
|
impl From<Tagged<Value>> for ReturnValue {
|
||||||
fn from(input: Spanned<Value>) -> ReturnValue {
|
fn from(input: Tagged<Value>) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::Value(input))
|
Ok(ReturnSuccess::Value(input))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReturnSuccess {
|
impl ReturnSuccess {
|
||||||
pub fn change_cwd(path: PathBuf) -> ReturnValue {
|
pub fn change_cwd(path: String) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
|
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(input: impl Into<Spanned<Value>>) -> ReturnValue {
|
pub fn value(input: impl Into<Tagged<Value>>) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::Value(input.into()))
|
Ok(ReturnSuccess::Value(input.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +374,9 @@ impl ReturnSuccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_value(input: Value, span: Span) -> ReturnValue {
|
pub fn spanned_value(input: Value, span: Span) -> ReturnValue {
|
||||||
Ok(ReturnSuccess::Value(Spanned::from_item(input, span)))
|
Ok(ReturnSuccess::Value(Tagged::from_simple_spanned_item(
|
||||||
|
input, span,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,13 +446,13 @@ impl StaticCommand for FnFilterCommand {
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let CommandArgs {
|
let CommandArgs {
|
||||||
host,
|
host,
|
||||||
env,
|
shell_manager,
|
||||||
call_info,
|
call_info,
|
||||||
input,
|
input,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
let host: Arc<Mutex<dyn Host>> = host.clone();
|
let host: Arc<Mutex<dyn Host>> = host.clone();
|
||||||
let env: Arc<Mutex<Environment>> = env.clone();
|
let shell_manager = shell_manager.clone();
|
||||||
let registry: registry::CommandRegistry = registry.clone();
|
let registry: registry::CommandRegistry = registry.clone();
|
||||||
let func = self.func;
|
let func = self.func;
|
||||||
|
|
||||||
|
@ -455,7 +466,8 @@ impl StaticCommand for FnFilterCommand {
|
||||||
Ok(args) => args,
|
Ok(args) => args,
|
||||||
};
|
};
|
||||||
|
|
||||||
let args = EvaluatedFilterCommandArgs::new(host.clone(), env.clone(), call_info, it);
|
let args =
|
||||||
|
EvaluatedFilterCommandArgs::new(host.clone(), shell_manager.clone(), call_info, it);
|
||||||
|
|
||||||
match func(args) {
|
match func(args) {
|
||||||
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
||||||
|
|
|
@ -11,11 +11,11 @@ pub struct Config;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ConfigArgs {
|
pub struct ConfigArgs {
|
||||||
set: Option<(Spanned<String>, Spanned<Value>)>,
|
set: Option<(Tagged<String>, Tagged<Value>)>,
|
||||||
get: Option<Spanned<String>>,
|
get: Option<Tagged<String>>,
|
||||||
clear: Spanned<bool>,
|
clear: Tagged<bool>,
|
||||||
remove: Option<Spanned<String>>,
|
remove: Option<Tagged<String>>,
|
||||||
path: Spanned<bool>,
|
path: Tagged<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StaticCommand for Config {
|
impl StaticCommand for Config {
|
||||||
|
@ -69,29 +69,41 @@ pub fn config(
|
||||||
|
|
||||||
config::write_config(&result)?;
|
config::write_config(&result)?;
|
||||||
|
|
||||||
return Ok(stream![Spanned::from_item(
|
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||||
Value::Object(result.into()),
|
Value::Object(result.into()),
|
||||||
value.span()
|
value.span()
|
||||||
)]
|
)]
|
||||||
.from_input_stream());
|
.from_input_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Spanned { item: true, span } = clear {
|
if let Tagged {
|
||||||
|
item: true,
|
||||||
|
tag: Tag { span, .. },
|
||||||
|
} = clear
|
||||||
|
{
|
||||||
result.clear();
|
result.clear();
|
||||||
|
|
||||||
config::write_config(&result)?;
|
config::write_config(&result)?;
|
||||||
|
|
||||||
return Ok(
|
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||||
stream![Spanned::from_item(Value::Object(result.into()), span)].from_input_stream(),
|
Value::Object(result.into()),
|
||||||
);
|
span
|
||||||
|
)]
|
||||||
|
.from_input_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Spanned { item: true, span } = path {
|
if let Tagged {
|
||||||
|
item: true,
|
||||||
|
tag: Tag { span, .. },
|
||||||
|
} = path
|
||||||
|
{
|
||||||
let path = config::config_path()?;
|
let path = config::config_path()?;
|
||||||
|
|
||||||
return Ok(
|
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||||
stream![Value::Primitive(Primitive::Path(path)).spanned(span)].from_input_stream(),
|
Value::Primitive(Primitive::Path(path)),
|
||||||
);
|
span
|
||||||
|
)]
|
||||||
|
.from_input_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(v) = remove {
|
if let Some(v) = remove {
|
||||||
|
@ -106,9 +118,9 @@ pub fn config(
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v.span())]);
|
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).simple_spanned(v.span())]);
|
||||||
return Ok(obj.from_input_stream());
|
return Ok(obj.from_input_stream());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(vec![Value::Object(result.into()).spanned(name)].into());
|
return Ok(vec![Value::Object(result.into()).simple_spanned(name)].into());
|
||||||
}
|
}
|
||||||
|
|
401
src/commands/cp.rs
Normal file
401
src/commands/cp.rs
Normal file
|
@ -0,0 +1,401 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::parser::hir::SyntaxType;
|
||||||
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub struct Copycp;
|
||||||
|
|
||||||
|
impl StaticCommand for Copycp {
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
args: CommandArgs,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
cp(args, registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"cp"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("cp")
|
||||||
|
.named("file", SyntaxType::Any)
|
||||||
|
.switch("recursive")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub struct Res {
|
||||||
|
pub loc: PathBuf,
|
||||||
|
pub at: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Res {}
|
||||||
|
|
||||||
|
pub struct FileStructure {
|
||||||
|
root: PathBuf,
|
||||||
|
resources: Vec<Res>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileStructure {
|
||||||
|
pub fn new() -> FileStructure {
|
||||||
|
FileStructure {
|
||||||
|
root: PathBuf::new(),
|
||||||
|
resources: Vec::<Res>::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_root(&mut self, path: &Path) {
|
||||||
|
self.root = path.to_path_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paths_applying_with<F>(&mut self, to: F) -> Vec<(PathBuf, PathBuf)>
|
||||||
|
where
|
||||||
|
F: Fn((PathBuf, usize)) -> (PathBuf, PathBuf),
|
||||||
|
{
|
||||||
|
self.resources
|
||||||
|
.iter()
|
||||||
|
.map(|f| (PathBuf::from(&f.loc), f.at))
|
||||||
|
.map(|f| to(f))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_decorate(&mut self, start_path: &Path) {
|
||||||
|
self.set_root(&dunce::canonicalize(start_path).unwrap());
|
||||||
|
self.resources = Vec::<Res>::new();
|
||||||
|
self.build(start_path, 0);
|
||||||
|
self.resources.sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(&mut self, src: &'a Path, lvl: usize) {
|
||||||
|
let source = dunce::canonicalize(src).unwrap();
|
||||||
|
|
||||||
|
if source.is_dir() {
|
||||||
|
for entry in std::fs::read_dir(&source).unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
self.build(&path, lvl + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.resources.push(Res {
|
||||||
|
loc: path.to_path_buf(),
|
||||||
|
at: lvl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.resources.push(Res {
|
||||||
|
loc: source,
|
||||||
|
at: lvl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let mut source = PathBuf::from(args.shell_manager.path());
|
||||||
|
let mut destination = PathBuf::from(args.shell_manager.path());
|
||||||
|
let name_span = args.call_info.name_span;
|
||||||
|
let args = args.evaluate_once(registry)?;
|
||||||
|
|
||||||
|
match args
|
||||||
|
.nth(0)
|
||||||
|
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||||
|
.as_string()?
|
||||||
|
.as_str()
|
||||||
|
{
|
||||||
|
file => {
|
||||||
|
source.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match args
|
||||||
|
.nth(1)
|
||||||
|
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||||
|
.as_string()?
|
||||||
|
.as_str()
|
||||||
|
{
|
||||||
|
file => {
|
||||||
|
destination.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sources = glob::glob(&source.to_string_lossy());
|
||||||
|
|
||||||
|
if sources.is_err() {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Invalid pattern.",
|
||||||
|
"Invalid pattern.",
|
||||||
|
args.nth(0).unwrap().span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let sources: Vec<_> = sources.unwrap().collect();
|
||||||
|
|
||||||
|
if sources.len() == 1 {
|
||||||
|
if let Ok(entry) = &sources[0] {
|
||||||
|
if entry.is_dir() && !args.has("recursive") {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"is a directory (not copied). Try using \"--recursive\".",
|
||||||
|
"is a directory (not copied). Try using \"--recursive\".",
|
||||||
|
args.nth(0).unwrap().span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sources: FileStructure = FileStructure::new();
|
||||||
|
|
||||||
|
sources.walk_decorate(&entry);
|
||||||
|
|
||||||
|
if entry.is_file() {
|
||||||
|
let strategy = |(source_file, _depth_level)| {
|
||||||
|
if destination.exists() {
|
||||||
|
let mut new_dst = dunce::canonicalize(destination.clone()).unwrap();
|
||||||
|
new_dst.push(entry.file_name().unwrap());
|
||||||
|
(source_file, new_dst)
|
||||||
|
} else {
|
||||||
|
(source_file, destination.clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
||||||
|
if src.is_file() {
|
||||||
|
match std::fs::copy(src, dst) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.is_dir() {
|
||||||
|
if !destination.exists() {
|
||||||
|
match std::fs::create_dir_all(&destination) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
|
||||||
|
let strategy = |(source_file, depth_level)| {
|
||||||
|
let mut new_dst = destination.clone();
|
||||||
|
let path = dunce::canonicalize(&source_file).unwrap();
|
||||||
|
|
||||||
|
let mut comps: Vec<_> = path
|
||||||
|
.components()
|
||||||
|
.map(|fragment| fragment.as_os_str())
|
||||||
|
.rev()
|
||||||
|
.take(1 + depth_level)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
comps.reverse();
|
||||||
|
|
||||||
|
for fragment in comps.iter() {
|
||||||
|
new_dst.push(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
(PathBuf::from(&source_file), PathBuf::from(new_dst))
|
||||||
|
};
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
||||||
|
if src.is_dir() {
|
||||||
|
if !dst.exists() {
|
||||||
|
match std::fs::create_dir_all(dst) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if src.is_file() {
|
||||||
|
match std::fs::copy(src, dst) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
destination.push(entry.file_name().unwrap());
|
||||||
|
|
||||||
|
match std::fs::create_dir_all(&destination) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
|
||||||
|
let strategy = |(source_file, depth_level)| {
|
||||||
|
let mut new_dst = dunce::canonicalize(&destination).unwrap();
|
||||||
|
let path = dunce::canonicalize(&source_file).unwrap();
|
||||||
|
|
||||||
|
let mut comps: Vec<_> = path
|
||||||
|
.components()
|
||||||
|
.map(|fragment| fragment.as_os_str())
|
||||||
|
.rev()
|
||||||
|
.take(1 + depth_level)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
comps.reverse();
|
||||||
|
|
||||||
|
for fragment in comps.iter() {
|
||||||
|
new_dst.push(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
(PathBuf::from(&source_file), PathBuf::from(new_dst))
|
||||||
|
};
|
||||||
|
|
||||||
|
for (ref src, ref dst) in sources.paths_applying_with(strategy) {
|
||||||
|
if src.is_dir() {
|
||||||
|
if !dst.exists() {
|
||||||
|
match std::fs::create_dir_all(dst) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if src.is_file() {
|
||||||
|
match std::fs::copy(src, dst) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if destination.exists() {
|
||||||
|
if !sources.iter().all(|x| (x.as_ref().unwrap()).is_file()) && !args.has("recursive") {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Copy aborted (directories found). Try using \"--recursive\".",
|
||||||
|
"Copy aborted (directories found). Try using \"--recursive\".",
|
||||||
|
args.nth(0).unwrap().span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in sources {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
let mut to = PathBuf::from(&destination);
|
||||||
|
to.push(&entry.file_name().unwrap());
|
||||||
|
|
||||||
|
match std::fs::copy(&entry, &to) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
format!(
|
||||||
|
"Copy aborted. (Does {:?} exist?)",
|
||||||
|
&destination.file_name().unwrap()
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"Copy aborted. (Does {:?} exist?)",
|
||||||
|
&destination.file_name().unwrap()
|
||||||
|
),
|
||||||
|
args.nth(1).unwrap().span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(OutputStream::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::{FileStructure, Res};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn fixtures() -> PathBuf {
|
||||||
|
let mut sdx = PathBuf::new();
|
||||||
|
sdx.push("tests");
|
||||||
|
sdx.push("fixtures");
|
||||||
|
sdx.push("formats");
|
||||||
|
dunce::canonicalize(sdx).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prepares_and_decorates_source_files_for_copying() {
|
||||||
|
let mut res = FileStructure::new();
|
||||||
|
res.walk_decorate(fixtures().as_path());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res.resources,
|
||||||
|
vec![
|
||||||
|
Res {
|
||||||
|
loc: fixtures().join("appveyor.yml"),
|
||||||
|
at: 0
|
||||||
|
},
|
||||||
|
Res {
|
||||||
|
loc: fixtures().join("caco3_plastics.csv"),
|
||||||
|
at: 0
|
||||||
|
},
|
||||||
|
Res {
|
||||||
|
loc: fixtures().join("cargo_sample.toml"),
|
||||||
|
at: 0
|
||||||
|
},
|
||||||
|
Res {
|
||||||
|
loc: fixtures().join("jonathan.xml"),
|
||||||
|
at: 0
|
||||||
|
},
|
||||||
|
Res {
|
||||||
|
loc: fixtures().join("sample.ini"),
|
||||||
|
at: 0
|
||||||
|
},
|
||||||
|
Res {
|
||||||
|
loc: fixtures().join("sgml_description.json"),
|
||||||
|
at: 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
88
src/commands/date.rs
Normal file
88
src/commands/date.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::{Dictionary, Value};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use chrono::{DateTime, Local, Utc};
|
||||||
|
|
||||||
|
use crate::commands::StaticCommand;
|
||||||
|
use crate::parser::registry::Signature;
|
||||||
|
use chrono::{Datelike, TimeZone, Timelike};
|
||||||
|
use core::fmt::Display;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
|
pub struct Date;
|
||||||
|
|
||||||
|
impl StaticCommand for Date {
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
args: CommandArgs,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
date(args, registry)
|
||||||
|
}
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"date"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("mkdir").switch("utc").switch("local")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn date_to_value<T: TimeZone>(dt: DateTime<T>, span: Span) -> Tagged<Value>
|
||||||
|
where
|
||||||
|
T::Offset: Display,
|
||||||
|
{
|
||||||
|
let mut indexmap = IndexMap::new();
|
||||||
|
|
||||||
|
indexmap.insert(
|
||||||
|
"year".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::int(dt.year()), span),
|
||||||
|
);
|
||||||
|
indexmap.insert(
|
||||||
|
"month".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::int(dt.month()), span),
|
||||||
|
);
|
||||||
|
indexmap.insert(
|
||||||
|
"day".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::int(dt.day()), span),
|
||||||
|
);
|
||||||
|
indexmap.insert(
|
||||||
|
"hour".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::int(dt.hour()), span),
|
||||||
|
);
|
||||||
|
indexmap.insert(
|
||||||
|
"minute".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::int(dt.minute()), span),
|
||||||
|
);
|
||||||
|
indexmap.insert(
|
||||||
|
"second".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::int(dt.second()), span),
|
||||||
|
);
|
||||||
|
|
||||||
|
let tz = dt.offset();
|
||||||
|
indexmap.insert(
|
||||||
|
"timezone".to_string(),
|
||||||
|
Tagged::from_simple_spanned_item(Value::string(format!("{}", tz)), span),
|
||||||
|
);
|
||||||
|
|
||||||
|
Tagged::from_simple_spanned_item(Value::Object(Dictionary::from(indexmap)), span)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let args = args.evaluate_once(registry)?;
|
||||||
|
|
||||||
|
let mut date_out = VecDeque::new();
|
||||||
|
let span = args.call_info.name_span;
|
||||||
|
|
||||||
|
let value = if args.has("utc") {
|
||||||
|
let utc: DateTime<Utc> = Utc::now();
|
||||||
|
date_to_value(utc, span)
|
||||||
|
} else {
|
||||||
|
let local: DateTime<Local> = Local::now();
|
||||||
|
date_to_value(local, span)
|
||||||
|
};
|
||||||
|
|
||||||
|
date_out.push_back(value);
|
||||||
|
|
||||||
|
Ok(date_out.to_output_stream())
|
||||||
|
}
|
23
src/commands/enter.rs
Normal file
23
src/commands/enter.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::commands::command::CommandAction;
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn enter(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let args = args.evaluate_once(registry)?;
|
||||||
|
|
||||||
|
//TODO: We could also enter a value in the stream
|
||||||
|
if args.len() == 0 {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Enter requires a path",
|
||||||
|
"needs parameter",
|
||||||
|
args.call_info.name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let location = args.expect_nth(0)?.as_string()?;
|
||||||
|
|
||||||
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
|
||||||
|
location,
|
||||||
|
)))]
|
||||||
|
.into())
|
||||||
|
}
|
|
@ -1,7 +1,34 @@
|
||||||
use crate::commands::command::CommandAction;
|
use crate::commands::command::{CommandAction, StaticCommand};
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn exit(_args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
pub struct Exit;
|
||||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
|
||||||
|
impl StaticCommand for Exit {
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
args: CommandArgs,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
exit(args, registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"exit"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("exit").switch("now")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let args = args.evaluate_once(registry)?;
|
||||||
|
|
||||||
|
if args.call_info.args.has("now") {
|
||||||
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||||
|
} else {
|
||||||
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::LeaveShell))].into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
|
|
||||||
if args.len() == 0 {
|
if args.len() == 0 {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"First requires an amount",
|
"First requires an amount",
|
||||||
"needs parameter",
|
"needs parameter",
|
||||||
args.name_span(),
|
args.name_span(),
|
||||||
|
@ -23,7 +23,7 @@ pub fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Value is not a number",
|
"Value is not a number",
|
||||||
"expected integer",
|
"expected integer",
|
||||||
args.expect_nth(0)?.span,
|
args.expect_nth(0)?.span(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use csv::ReaderBuilder;
|
use csv::ReaderBuilder;
|
||||||
|
|
||||||
pub fn from_csv_string_to_value(
|
pub fn from_csv_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||||
let mut reader = ReaderBuilder::new()
|
let mut reader = ReaderBuilder::new()
|
||||||
.has_headers(false)
|
.has_headers(false)
|
||||||
.from_reader(s.as_bytes());
|
.from_reader(s.as_bytes());
|
||||||
let span = span.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
let mut fields: VecDeque<String> = VecDeque::new();
|
let mut fields: VecDeque<String> = VecDeque::new();
|
||||||
let mut iter = reader.records();
|
let mut iter = reader.records();
|
||||||
|
@ -27,25 +27,22 @@ pub fn from_csv_string_to_value(
|
||||||
if let Some(row_values) = iter.next() {
|
if let Some(row_values) = iter.next() {
|
||||||
let row_values = row_values?;
|
let row_values = row_values?;
|
||||||
|
|
||||||
let mut row = SpannedDictBuilder::new(span);
|
let mut row = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (idx, entry) in row_values.iter().enumerate() {
|
for (idx, entry) in row_values.iter().enumerate() {
|
||||||
row.insert_spanned(
|
row.insert_tagged(
|
||||||
fields.get(idx).unwrap(),
|
fields.get(idx).unwrap(),
|
||||||
Value::Primitive(Primitive::String(String::from(entry))).spanned(span),
|
Value::Primitive(Primitive::String(String::from(entry))).tagged(tag),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.push(row.into_spanned_value());
|
rows.push(row.into_tagged_value());
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Spanned {
|
Ok(Tagged::from_item(Value::List(rows), tag))
|
||||||
item: Value::List(rows),
|
|
||||||
span,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
pub fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
@ -55,20 +52,29 @@ pub fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match a.item {
|
.map(move |a| {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_csv_string_to_value(s, span) {
|
let value_tag = a.tag();
|
||||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
match a.item {
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
"Could not parse as CSV",
|
match from_csv_string_to_value(s, value_tag) {
|
||||||
"piped data failed CSV parse",
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Could not parse as CSV",
|
||||||
|
"input cannot be parsed as CSV",
|
||||||
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
|
||||||
"expects strings from pipeline",
|
|
||||||
span,
|
|
||||||
)),
|
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn convert_ini_second_to_nu_value(
|
fn convert_ini_second_to_nu_value(
|
||||||
v: &HashMap<String, String>,
|
v: &HashMap<String, String>,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> Spanned<Value> {
|
) -> Tagged<Value> {
|
||||||
let mut second = SpannedDictBuilder::new(span);
|
let mut second = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (key, value) in v.into_iter() {
|
for (key, value) in v.into_iter() {
|
||||||
second.insert(key.clone(), Primitive::String(value.clone()));
|
second.insert(key.clone(), Primitive::String(value.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
second.into_spanned_value()
|
second.into_tagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_ini_top_to_nu_value(
|
fn convert_ini_top_to_nu_value(
|
||||||
v: &HashMap<String, HashMap<String, String>>,
|
v: &HashMap<String, HashMap<String, String>>,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> Spanned<Value> {
|
) -> Tagged<Value> {
|
||||||
let span = span.into();
|
let tag = tag.into();
|
||||||
let mut top_level = SpannedDictBuilder::new(span);
|
let mut top_level = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (key, value) in v.iter() {
|
for (key, value) in v.iter() {
|
||||||
top_level.insert_spanned(key.clone(), convert_ini_second_to_nu_value(value, span));
|
top_level.insert_tagged(key.clone(), convert_ini_second_to_nu_value(value, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
top_level.into_spanned_value()
|
top_level.into_tagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_ini_string_to_value(
|
pub fn from_ini_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||||
let v: HashMap<String, HashMap<String, String>> = serde_ini::from_str(&s)?;
|
let v: HashMap<String, HashMap<String, String>> = serde_ini::from_str(&s)?;
|
||||||
Ok(convert_ini_top_to_nu_value(&v, span))
|
Ok(convert_ini_top_to_nu_value(&v, tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
@ -44,20 +44,29 @@ pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match a.item {
|
.map(move |a| {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s, span) {
|
let value_tag = a.tag();
|
||||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
match a.item {
|
||||||
Err(e) => Err(ShellError::maybe_labeled_error(
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
"Could not parse as INI",
|
match from_ini_string_to_value(s, value_tag) {
|
||||||
format!("{:#?}", e),
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Could not parse as INI",
|
||||||
|
"input cannot be parsed as INI",
|
||||||
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
|
||||||
"expects strings from pipeline",
|
|
||||||
span,
|
|
||||||
)),
|
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
use crate::object::base::OF64;
|
use crate::object::base::OF64;
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into<Span>) -> Spanned<Value> {
|
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let span = span.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
serde_hjson::Value::Null => {
|
serde_hjson::Value::Null => {
|
||||||
Value::Primitive(Primitive::String(String::from(""))).spanned(span)
|
Value::Primitive(Primitive::String(String::from(""))).tagged(tag)
|
||||||
}
|
}
|
||||||
serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag),
|
||||||
serde_hjson::Value::F64(n) => {
|
serde_hjson::Value::F64(n) => {
|
||||||
Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span)
|
Value::Primitive(Primitive::Float(OF64::from(*n))).tagged(tag)
|
||||||
}
|
}
|
||||||
serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span),
|
serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)).tagged(tag),
|
||||||
serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span),
|
serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)).tagged(tag),
|
||||||
serde_hjson::Value::String(s) => {
|
serde_hjson::Value::String(s) => {
|
||||||
Value::Primitive(Primitive::String(String::from(s))).spanned(span)
|
Value::Primitive(Primitive::String(String::from(s))).tagged(tag)
|
||||||
}
|
}
|
||||||
serde_hjson::Value::Array(a) => Value::List(
|
serde_hjson::Value::Array(a) => Value::List(
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|x| convert_json_value_to_nu_value(x, span))
|
.map(|x| convert_json_value_to_nu_value(x, tag))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.spanned(span),
|
.tagged(tag),
|
||||||
serde_hjson::Value::Object(o) => {
|
serde_hjson::Value::Object(o) => {
|
||||||
let mut collected = SpannedDictBuilder::new(span);
|
let mut collected = TaggedDictBuilder::new(tag);
|
||||||
for (k, v) in o.iter() {
|
for (k, v) in o.iter() {
|
||||||
collected.insert_spanned(k.clone(), convert_json_value_to_nu_value(v, span));
|
collected.insert_tagged(k.clone(), convert_json_value_to_nu_value(v, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
collected.into_spanned_value()
|
collected.into_tagged_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_json_string_to_value(
|
pub fn from_json_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> serde_hjson::Result<Spanned<Value>> {
|
) -> serde_hjson::Result<Tagged<Value>> {
|
||||||
let v: serde_hjson::Value = serde_hjson::from_str(&s)?;
|
let v: serde_hjson::Value = serde_hjson::from_str(&s)?;
|
||||||
Ok(convert_json_value_to_nu_value(&v, span))
|
Ok(convert_json_value_to_nu_value(&v, tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_json(
|
pub fn from_json(
|
||||||
|
@ -53,20 +53,29 @@ pub fn from_json(
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match a.item {
|
.map(move |a| {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s, span) {
|
let value_tag = a.tag();
|
||||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
match a.item {
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
"Could not parse as JSON",
|
match from_json_string_to_value(s, value_tag) {
|
||||||
"piped data failed JSON parse",
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Could not parse as JSON",
|
||||||
|
"input cannot be parsed as JSON",
|
||||||
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
|
||||||
"expects strings from pipeline",
|
|
||||||
span,
|
|
||||||
)),
|
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,42 @@
|
||||||
use crate::object::base::OF64;
|
use crate::object::base::OF64;
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into<Span>) -> Spanned<Value> {
|
pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let span = span.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag),
|
||||||
toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).spanned(span),
|
toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).tagged(tag),
|
||||||
toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span),
|
toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).tagged(tag),
|
||||||
toml::Value::String(s) => {
|
toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))).tagged(tag),
|
||||||
Value::Primitive(Primitive::String(String::from(s))).spanned(span)
|
|
||||||
}
|
|
||||||
toml::Value::Array(a) => Value::List(
|
toml::Value::Array(a) => Value::List(
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|x| convert_toml_value_to_nu_value(x, span))
|
.map(|x| convert_toml_value_to_nu_value(x, tag))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.spanned(span),
|
.tagged(tag),
|
||||||
toml::Value::Datetime(dt) => {
|
toml::Value::Datetime(dt) => {
|
||||||
Value::Primitive(Primitive::String(dt.to_string())).spanned(span)
|
Value::Primitive(Primitive::String(dt.to_string())).tagged(tag)
|
||||||
}
|
}
|
||||||
toml::Value::Table(t) => {
|
toml::Value::Table(t) => {
|
||||||
let mut collected = SpannedDictBuilder::new(span);
|
let mut collected = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (k, v) in t.iter() {
|
for (k, v) in t.iter() {
|
||||||
collected.insert_spanned(k.clone(), convert_toml_value_to_nu_value(v, span));
|
collected.insert_tagged(k.clone(), convert_toml_value_to_nu_value(v, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
collected.into_spanned_value()
|
collected.into_tagged_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_toml_string_to_value(
|
pub fn from_toml_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||||
let v: toml::Value = s.parse::<toml::Value>()?;
|
let v: toml::Value = s.parse::<toml::Value>()?;
|
||||||
Ok(convert_toml_value_to_nu_value(&v, span))
|
Ok(convert_toml_value_to_nu_value(&v, tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_toml(
|
pub fn from_toml(
|
||||||
|
@ -51,20 +49,29 @@ pub fn from_toml(
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match a.item {
|
.map(move |a| {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s, span) {
|
let value_tag = a.tag();
|
||||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
match a.item {
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
"Could not parse as TOML",
|
match from_toml_string_to_value(s, value_tag) {
|
||||||
"piped data failed TOML parse",
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Could not parse as TOML",
|
||||||
|
"input cannot be parsed as TOML",
|
||||||
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
format!("{} originates from here", x.type_name()),
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
|
||||||
"expects strings from pipeline",
|
|
||||||
span,
|
|
||||||
)),
|
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,21 @@
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
fn from_node_to_value<'a, 'd>(
|
fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
n: &roxmltree::Node<'a, 'd>,
|
let tag = tag.into();
|
||||||
span: impl Into<Span>,
|
|
||||||
) -> Spanned<Value> {
|
|
||||||
let span = span.into();
|
|
||||||
|
|
||||||
if n.is_element() {
|
if n.is_element() {
|
||||||
let name = n.tag_name().name().trim().to_string();
|
let name = n.tag_name().name().trim().to_string();
|
||||||
|
|
||||||
let mut children_values = vec![];
|
let mut children_values = vec![];
|
||||||
for c in n.children() {
|
for c in n.children() {
|
||||||
children_values.push(from_node_to_value(&c, span));
|
children_values.push(from_node_to_value(&c, tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
let children_values: Vec<Spanned<Value>> = children_values
|
let children_values: Vec<Tagged<Value>> = children_values
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|x| match x {
|
.filter(|x| match x {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::String(f)),
|
item: Value::Primitive(Primitive::String(f)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -32,31 +29,31 @@ fn from_node_to_value<'a, 'd>(
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut collected = SpannedDictBuilder::new(span);
|
let mut collected = TaggedDictBuilder::new(tag);
|
||||||
collected.insert(name.clone(), Value::List(children_values));
|
collected.insert(name.clone(), Value::List(children_values));
|
||||||
|
|
||||||
collected.into_spanned_value()
|
collected.into_tagged_value()
|
||||||
} else if n.is_comment() {
|
} else if n.is_comment() {
|
||||||
Value::string("<comment>").spanned(span)
|
Value::string("<comment>").tagged(tag)
|
||||||
} else if n.is_pi() {
|
} else if n.is_pi() {
|
||||||
Value::string("<processing_instruction>").spanned(span)
|
Value::string("<processing_instruction>").tagged(tag)
|
||||||
} else if n.is_text() {
|
} else if n.is_text() {
|
||||||
Value::string(n.text().unwrap()).spanned(span)
|
Value::string(n.text().unwrap()).tagged(tag)
|
||||||
} else {
|
} else {
|
||||||
Value::string("<unknown>").spanned(span)
|
Value::string("<unknown>").tagged(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_document_to_value(d: &roxmltree::Document, span: impl Into<Span>) -> Spanned<Value> {
|
fn from_document_to_value(d: &roxmltree::Document, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
from_node_to_value(&d.root_element(), span)
|
from_node_to_value(&d.root_element(), tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_xml_string_to_value(
|
pub fn from_xml_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||||
let parsed = roxmltree::Document::parse(&s)?;
|
let parsed = roxmltree::Document::parse(&s)?;
|
||||||
Ok(from_document_to_value(&parsed, span))
|
Ok(from_document_to_value(&parsed, tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
@ -65,20 +62,29 @@ pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
|
||||||
let out = args.input;
|
let out = args.input;
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match a.item {
|
.map(move |a| {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s, span) {
|
let value_tag = a.tag();
|
||||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
match a.item {
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
"Could not parse as XML",
|
match from_xml_string_to_value(s, value_tag) {
|
||||||
"piped data failed XML parse",
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Could not parse as XML",
|
||||||
|
"input cannot be parsed as XML",
|
||||||
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
|
||||||
"expects strings from pipeline",
|
|
||||||
span,
|
|
||||||
)),
|
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,51 +1,50 @@
|
||||||
use crate::object::base::OF64;
|
use crate::object::base::OF64;
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into<Span>) -> Spanned<Value> {
|
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let span = span.into();
|
let tag = tag.into();
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag),
|
||||||
serde_yaml::Value::Number(n) if n.is_i64() => {
|
serde_yaml::Value::Number(n) if n.is_i64() => {
|
||||||
Value::Primitive(Primitive::Int(n.as_i64().unwrap())).spanned(span)
|
Value::Primitive(Primitive::Int(n.as_i64().unwrap())).tagged(tag)
|
||||||
}
|
}
|
||||||
serde_yaml::Value::Number(n) if n.is_f64() => {
|
serde_yaml::Value::Number(n) if n.is_f64() => {
|
||||||
Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))).spanned(span)
|
Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))).tagged(tag)
|
||||||
}
|
}
|
||||||
serde_yaml::Value::String(s) => Value::string(s).spanned(span),
|
serde_yaml::Value::String(s) => Value::string(s).tagged(tag),
|
||||||
serde_yaml::Value::Sequence(a) => Value::List(
|
serde_yaml::Value::Sequence(a) => Value::List(
|
||||||
a.iter()
|
a.iter()
|
||||||
.map(|x| convert_yaml_value_to_nu_value(x, span))
|
.map(|x| convert_yaml_value_to_nu_value(x, tag))
|
||||||
.collect(),
|
.collect(),
|
||||||
)
|
)
|
||||||
.spanned(span),
|
.tagged(tag),
|
||||||
serde_yaml::Value::Mapping(t) => {
|
serde_yaml::Value::Mapping(t) => {
|
||||||
let mut collected = SpannedDictBuilder::new(span);
|
let mut collected = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
for (k, v) in t.iter() {
|
for (k, v) in t.iter() {
|
||||||
match k {
|
match k {
|
||||||
serde_yaml::Value::String(k) => {
|
serde_yaml::Value::String(k) => {
|
||||||
collected
|
collected.insert_tagged(k.clone(), convert_yaml_value_to_nu_value(v, tag));
|
||||||
.insert_spanned(k.clone(), convert_yaml_value_to_nu_value(v, span));
|
|
||||||
}
|
}
|
||||||
_ => unimplemented!("Unknown key type"),
|
_ => unimplemented!("Unknown key type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
collected.into_spanned_value()
|
collected.into_tagged_value()
|
||||||
}
|
}
|
||||||
serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing).spanned(span),
|
serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing).tagged(tag),
|
||||||
x => unimplemented!("Unsupported yaml case: {:?}", x),
|
x => unimplemented!("Unsupported yaml case: {:?}", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_yaml_string_to_value(
|
pub fn from_yaml_string_to_value(
|
||||||
s: String,
|
s: String,
|
||||||
span: impl Into<Span>,
|
tag: impl Into<Tag>,
|
||||||
) -> serde_yaml::Result<Spanned<Value>> {
|
) -> serde_yaml::Result<Tagged<Value>> {
|
||||||
let v: serde_yaml::Value = serde_yaml::from_str(&s)?;
|
let v: serde_yaml::Value = serde_yaml::from_str(&s)?;
|
||||||
Ok(convert_yaml_value_to_nu_value(&v, span))
|
Ok(convert_yaml_value_to_nu_value(&v, tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_yaml(
|
pub fn from_yaml(
|
||||||
|
@ -57,20 +56,29 @@ pub fn from_yaml(
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match a.item {
|
.map(move |a| {
|
||||||
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s, span) {
|
let value_tag = a.tag();
|
||||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
match a.item {
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
"Could not parse as YAML",
|
match from_yaml_string_to_value(s, value_tag) {
|
||||||
"piped data failed YAML parse",
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Could not parse as YAML",
|
||||||
|
"input cannot be parsed as YAML",
|
||||||
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
|
||||||
"Expected string values from pipeline",
|
|
||||||
"expects strings from pipeline",
|
|
||||||
span,
|
|
||||||
)),
|
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub struct Get;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct GetArgs {
|
pub struct GetArgs {
|
||||||
rest: Vec<Spanned<String>>,
|
rest: Vec<Tagged<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StaticCommand for Get {
|
impl StaticCommand for Get {
|
||||||
|
@ -27,7 +27,7 @@ impl StaticCommand for Get {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_member(path: &Spanned<String>, obj: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
|
fn get_member(path: &Tagged<String>, obj: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||||
let mut current = obj;
|
let mut current = obj;
|
||||||
for p in path.split(".") {
|
for p in path.split(".") {
|
||||||
match current.get_data_by_key(p) {
|
match current.get_data_by_key(p) {
|
||||||
|
@ -36,7 +36,7 @@ fn get_member(path: &Spanned<String>, obj: &Spanned<Value>) -> Result<Spanned<Va
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Unknown field",
|
"Unknown field",
|
||||||
"object missing field",
|
"object missing field",
|
||||||
path.span,
|
path.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ pub fn get(
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
for field in &fields {
|
for field in &fields {
|
||||||
match get_member(field, &item) {
|
match get_member(field, &item) {
|
||||||
Ok(Spanned {
|
Ok(Tagged {
|
||||||
item: Value::List(l),
|
item: Value::List(l),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
@ -23,17 +23,19 @@ pub fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
for s in split_result {
|
for s in split_result {
|
||||||
result.push_back(ReturnSuccess::value(
|
result.push_back(ReturnSuccess::value(
|
||||||
Value::Primitive(Primitive::String(s.into())).spanned_unknown(),
|
Value::Primitive(Primitive::String(s.into())).tagged_unknown(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(Err(ShellError::maybe_labeled_error(
|
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected string values from pipeline",
|
"Expected a string from pipeline",
|
||||||
"expects strings from pipeline",
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
v.span(),
|
||||||
)));
|
)));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{dir_entry_dict, Primitive, Value};
|
use crate::object::dir_entry_dict;
|
||||||
use crate::parser::Spanned;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let env = args.env.clone();
|
|
||||||
let env = env.lock().unwrap();
|
|
||||||
let args = args.evaluate_once(registry)?;
|
let args = args.evaluate_once(registry)?;
|
||||||
let path = env.path.to_path_buf();
|
let path = PathBuf::from(args.shell_manager.path());
|
||||||
let mut full_path = PathBuf::from(path);
|
let mut full_path = PathBuf::from(path);
|
||||||
match &args.nth(0) {
|
match &args.nth(0) {
|
||||||
Some(Spanned {
|
Some(Tagged {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
}) => full_path.push(Path::new(&s)),
|
}) => full_path.push(Path::new(&s)),
|
||||||
|
@ -26,10 +23,10 @@ pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
s.span,
|
s.span(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
args.name_span(),
|
args.name_span(),
|
||||||
|
@ -42,8 +39,19 @@ pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||||
let mut shell_entries = VecDeque::new();
|
let mut shell_entries = VecDeque::new();
|
||||||
|
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
let value = dir_entry_dict(&entry?, args.name_span())?;
|
let entry = entry?;
|
||||||
|
let filepath = entry.path();
|
||||||
|
let filename = filepath.strip_prefix(&full_path).unwrap();
|
||||||
|
let value = dir_entry_dict(
|
||||||
|
filename,
|
||||||
|
&entry.metadata()?,
|
||||||
|
Tag::unknown_origin(args.call_info.name_span),
|
||||||
|
)?;
|
||||||
shell_entries.push_back(ReturnSuccess::value(value))
|
shell_entries.push_back(ReturnSuccess::value(value))
|
||||||
}
|
}
|
||||||
Ok(shell_entries.to_output_stream())
|
Ok(shell_entries.to_output_stream())
|
||||||
|
|
||||||
|
// pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
// let args = args.evaluate_once(registry)?;
|
||||||
|
// args.shell_manager.ls(args, args.input)
|
||||||
}
|
}
|
||||||
|
|
45
src/commands/mkdir.rs
Normal file
45
src/commands/mkdir.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::parser::hir::SyntaxType;
|
||||||
|
use crate::parser::registry::{CommandRegistry, Signature};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub struct Mkdir;
|
||||||
|
|
||||||
|
impl StaticCommand for Mkdir {
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
args: CommandArgs,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
mkdir(args, registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"mkdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("mkdir").named("file", SyntaxType::Any)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mkdir(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let args = args.evaluate_once(registry)?;
|
||||||
|
|
||||||
|
let mut full_path = PathBuf::from(args.shell_manager.path());
|
||||||
|
|
||||||
|
match &args.nth(0) {
|
||||||
|
Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match std::fs::create_dir_all(full_path) {
|
||||||
|
Err(reason) => Err(ShellError::labeled_error(
|
||||||
|
reason.to_string(),
|
||||||
|
reason.to_string(),
|
||||||
|
args.nth(0).unwrap().span(),
|
||||||
|
)),
|
||||||
|
Ok(_) => Ok(OutputStream::empty()),
|
||||||
|
}
|
||||||
|
}
|
7
src/commands/next.rs
Normal file
7
src/commands/next.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use crate::commands::command::CommandAction;
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn next(_args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::NextShell))].into())
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ use crate::context::SpanSource;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{Primitive, Value};
|
use crate::object::{Primitive, Value};
|
||||||
use crate::parser::hir::SyntaxType;
|
use crate::parser::hir::SyntaxType;
|
||||||
use crate::parser::parse::span::Span;
|
|
||||||
use crate::parser::registry::{self, Signature};
|
use crate::parser::registry::{self, Signature};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
|
@ -15,7 +14,7 @@ pub struct Open;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct OpenArgs {
|
pub struct OpenArgs {
|
||||||
path: Spanned<PathBuf>,
|
path: Tagged<PathBuf>,
|
||||||
raw: bool,
|
raw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,24 +40,28 @@ impl StaticCommand for Open {
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
OpenArgs { raw, path }: OpenArgs,
|
OpenArgs { raw, path }: OpenArgs,
|
||||||
RunnableContext { env, name, .. }: RunnableContext,
|
RunnableContext {
|
||||||
|
shell_manager,
|
||||||
|
name,
|
||||||
|
..
|
||||||
|
}: RunnableContext,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let cwd = env.lock().unwrap().path().to_path_buf();
|
let cwd = PathBuf::from(shell_manager.path());
|
||||||
let full_path = PathBuf::from(cwd);
|
let full_path = PathBuf::from(cwd);
|
||||||
|
|
||||||
let path_str = path.to_str().ok_or(ShellError::type_error(
|
let path_str = path.to_str().ok_or(ShellError::type_error(
|
||||||
"Path",
|
"Path",
|
||||||
"invalid path".spanned(path.span),
|
"invalid path".tagged(path.tag()),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let (file_extension, contents, contents_span, span_source) =
|
let (file_extension, contents, contents_tag, span_source) =
|
||||||
fetch(&full_path, path_str, path.span)?;
|
fetch(&full_path, path_str, path.span())?;
|
||||||
|
|
||||||
let file_extension = if raw { None } else { file_extension };
|
let file_extension = if raw { None } else { file_extension };
|
||||||
|
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
|
|
||||||
if let Some(uuid) = contents_span.source {
|
if let Some(uuid) = contents_tag.origin {
|
||||||
// If we have loaded something, track its source
|
// If we have loaded something, track its source
|
||||||
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
|
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
|
||||||
uuid,
|
uuid,
|
||||||
|
@ -68,10 +71,10 @@ fn run(
|
||||||
|
|
||||||
match contents {
|
match contents {
|
||||||
Value::Primitive(Primitive::String(string)) => {
|
Value::Primitive(Primitive::String(string)) => {
|
||||||
let value = parse_as_value(file_extension, string, contents_span, name)?;
|
let value = parse_as_value(file_extension, string, contents_tag, name)?;
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::List(list),
|
item: Value::List(list),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -83,7 +86,7 @@ fn run(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))),
|
other => stream.push_back(ReturnSuccess::value(other.tagged(contents_tag))),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(stream.boxed().to_output_stream())
|
Ok(stream.boxed().to_output_stream())
|
||||||
|
@ -149,7 +152,7 @@ pub fn fetch(
|
||||||
cwd: &PathBuf,
|
cwd: &PathBuf,
|
||||||
location: &str,
|
location: &str,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(Option<String>, Value, Span, SpanSource), ShellError> {
|
) -> Result<(Option<String>, Value, Tag, SpanSource), ShellError> {
|
||||||
let mut cwd = cwd.clone();
|
let mut cwd = cwd.clone();
|
||||||
if location.starts_with("http:") || location.starts_with("https:") {
|
if location.starts_with("http:") || location.starts_with("https:") {
|
||||||
let response = reqwest::get(location);
|
let response = reqwest::get(location);
|
||||||
|
@ -161,13 +164,19 @@ pub fn fetch(
|
||||||
(mime::APPLICATION, mime::XML) => Ok((
|
(mime::APPLICATION, mime::XML) => Ok((
|
||||||
Some("xml".to_string()),
|
Some("xml".to_string()),
|
||||||
Value::string(r.text().unwrap()),
|
Value::string(r.text().unwrap()),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
)),
|
)),
|
||||||
(mime::APPLICATION, mime::JSON) => Ok((
|
(mime::APPLICATION, mime::JSON) => Ok((
|
||||||
Some("json".to_string()),
|
Some("json".to_string()),
|
||||||
Value::string(r.text().unwrap()),
|
Value::string(r.text().unwrap()),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
)),
|
)),
|
||||||
(mime::APPLICATION, mime::OCTET_STREAM) => {
|
(mime::APPLICATION, mime::OCTET_STREAM) => {
|
||||||
|
@ -182,7 +191,10 @@ pub fn fetch(
|
||||||
Ok((
|
Ok((
|
||||||
None,
|
None,
|
||||||
Value::Binary(buf),
|
Value::Binary(buf),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -198,14 +210,20 @@ pub fn fetch(
|
||||||
Ok((
|
Ok((
|
||||||
Some(image_ty.to_string()),
|
Some(image_ty.to_string()),
|
||||||
Value::Binary(buf),
|
Value::Binary(buf),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
(mime::TEXT, mime::HTML) => Ok((
|
(mime::TEXT, mime::HTML) => Ok((
|
||||||
Some("html".to_string()),
|
Some("html".to_string()),
|
||||||
Value::string(r.text().unwrap()),
|
Value::string(r.text().unwrap()),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
)),
|
)),
|
||||||
(mime::TEXT, mime::PLAIN) => {
|
(mime::TEXT, mime::PLAIN) => {
|
||||||
|
@ -223,14 +241,23 @@ pub fn fetch(
|
||||||
Ok((
|
Ok((
|
||||||
path_extension,
|
path_extension,
|
||||||
Value::string(r.text().unwrap()),
|
Value::string(r.text().unwrap()),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
(ty, sub_ty) => Ok((
|
(ty, sub_ty) => Ok((
|
||||||
None,
|
None,
|
||||||
Value::string(format!("Not yet support MIME type: {} {}", ty, sub_ty)),
|
Value::string(format!(
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
"Not yet supported MIME type: {} {}",
|
||||||
|
ty, sub_ty
|
||||||
|
)),
|
||||||
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
@ -238,7 +265,10 @@ pub fn fetch(
|
||||||
None => Ok((
|
None => Ok((
|
||||||
None,
|
None,
|
||||||
Value::string(format!("No content type found")),
|
Value::string(format!("No content type found")),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::Url(r.url().to_string()),
|
SpanSource::Url(r.url().to_string()),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
@ -258,13 +288,19 @@ pub fn fetch(
|
||||||
cwd.extension()
|
cwd.extension()
|
||||||
.map(|name| name.to_string_lossy().to_string()),
|
.map(|name| name.to_string_lossy().to_string()),
|
||||||
Value::string(s),
|
Value::string(s),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::File(cwd.to_string_lossy().to_string()),
|
SpanSource::File(cwd.to_string_lossy().to_string()),
|
||||||
)),
|
)),
|
||||||
Err(_) => Ok((
|
Err(_) => Ok((
|
||||||
None,
|
None,
|
||||||
Value::Binary(bytes),
|
Value::Binary(bytes),
|
||||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
Tag {
|
||||||
|
span,
|
||||||
|
origin: Some(Uuid::new_v4()),
|
||||||
|
},
|
||||||
SpanSource::File(cwd.to_string_lossy().to_string()),
|
SpanSource::File(cwd.to_string_lossy().to_string()),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
@ -282,69 +318,57 @@ pub fn fetch(
|
||||||
pub fn parse_as_value(
|
pub fn parse_as_value(
|
||||||
extension: Option<String>,
|
extension: Option<String>,
|
||||||
contents: String,
|
contents: String,
|
||||||
contents_span: Span,
|
contents_tag: Tag,
|
||||||
name_span: Option<Span>,
|
name_span: Span,
|
||||||
) -> Result<Spanned<Value>, ShellError> {
|
) -> Result<Tagged<Value>, ShellError> {
|
||||||
match extension {
|
match extension {
|
||||||
Some(x) if x == "csv" => {
|
Some(x) if x == "csv" => crate::commands::from_csv::from_csv_string_to_value(
|
||||||
crate::commands::from_csv::from_csv_string_to_value(contents, contents_span)
|
contents,
|
||||||
.map(|c| c.spanned(contents_span))
|
contents_tag,
|
||||||
.map_err(move |_| {
|
)
|
||||||
ShellError::maybe_labeled_error(
|
.map_err(move |_| {
|
||||||
"Could not open as CSV",
|
ShellError::labeled_error("Could not open as CSV", "could not open as CSV", name_span)
|
||||||
"could not open as CSV",
|
}),
|
||||||
name_span,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Some(x) if x == "toml" => {
|
Some(x) if x == "toml" => {
|
||||||
crate::commands::from_toml::from_toml_string_to_value(contents, contents_span)
|
crate::commands::from_toml::from_toml_string_to_value(contents, contents_tag).map_err(
|
||||||
.map(|c| c.spanned(contents_span))
|
move |_| {
|
||||||
.map_err(move |_| {
|
ShellError::labeled_error(
|
||||||
ShellError::maybe_labeled_error(
|
|
||||||
"Could not open as TOML",
|
"Could not open as TOML",
|
||||||
"could not open as TOML",
|
"could not open as TOML",
|
||||||
name_span,
|
name_span,
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
|
||||||
Some(x) if x == "json" => {
|
|
||||||
crate::commands::from_json::from_json_string_to_value(contents, contents_span)
|
|
||||||
.map(|c| c.spanned(contents_span))
|
|
||||||
.map_err(move |_| {
|
|
||||||
ShellError::maybe_labeled_error(
|
|
||||||
"Could not open as JSON",
|
|
||||||
"could not open as JSON",
|
|
||||||
name_span,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Some(x) if x == "ini" => {
|
|
||||||
crate::commands::from_ini::from_ini_string_to_value(contents, contents_span)
|
|
||||||
.map(|c| c.spanned(contents_span))
|
|
||||||
.map_err(move |_| {
|
|
||||||
ShellError::maybe_labeled_error(
|
|
||||||
"Could not open as INI",
|
|
||||||
"could not open as INI",
|
|
||||||
name_span,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Some(x) if x == "xml" => {
|
|
||||||
crate::commands::from_xml::from_xml_string_to_value(contents, contents_span).map_err(
|
|
||||||
move |_| {
|
|
||||||
ShellError::maybe_labeled_error(
|
|
||||||
"Could not open as XML",
|
|
||||||
"could not open as XML",
|
|
||||||
name_span,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Some(x) if x == "yml" => {
|
Some(x) if x == "json" => {
|
||||||
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err(
|
crate::commands::from_json::from_json_string_to_value(contents, contents_tag).map_err(
|
||||||
move |_| {
|
move |_| {
|
||||||
ShellError::maybe_labeled_error(
|
ShellError::labeled_error(
|
||||||
|
"Could not open as JSON",
|
||||||
|
"could not open as JSON",
|
||||||
|
name_span,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(
|
||||||
|
contents,
|
||||||
|
contents_tag,
|
||||||
|
)
|
||||||
|
.map_err(move |_| {
|
||||||
|
ShellError::labeled_error("Could not open as INI", "could not open as INI", name_span)
|
||||||
|
}),
|
||||||
|
Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(
|
||||||
|
contents,
|
||||||
|
contents_tag,
|
||||||
|
)
|
||||||
|
.map_err(move |_| {
|
||||||
|
ShellError::labeled_error("Could not open as XML", "could not open as XML", name_span)
|
||||||
|
}),
|
||||||
|
Some(x) if x == "yml" => {
|
||||||
|
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_tag).map_err(
|
||||||
|
move |_| {
|
||||||
|
ShellError::labeled_error(
|
||||||
"Could not open as YAML",
|
"Could not open as YAML",
|
||||||
"could not open as YAML",
|
"could not open as YAML",
|
||||||
name_span,
|
name_span,
|
||||||
|
@ -353,9 +377,9 @@ pub fn parse_as_value(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Some(x) if x == "yaml" => {
|
Some(x) if x == "yaml" => {
|
||||||
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err(
|
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_tag).map_err(
|
||||||
move |_| {
|
move |_| {
|
||||||
ShellError::maybe_labeled_error(
|
ShellError::labeled_error(
|
||||||
"Could not open as YAML",
|
"Could not open as YAML",
|
||||||
"could not open as YAML",
|
"could not open as YAML",
|
||||||
name_span,
|
name_span,
|
||||||
|
@ -363,6 +387,6 @@ pub fn parse_as_value(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => Ok(Value::string(contents).spanned(contents_span)),
|
_ => Ok(Value::string(contents).tagged(contents_tag)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
||||||
let (input, args) = args.parts();
|
let (input, args) = args.parts();
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Pick requires fields",
|
"Pick requires fields",
|
||||||
"needs parameter",
|
"needs parameter",
|
||||||
span,
|
span,
|
||||||
|
@ -28,7 +28,7 @@ pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
||||||
|
|
||||||
let objects = input
|
let objects = input
|
||||||
.values
|
.values
|
||||||
.map(move |value| select_fields(&value.item, &fields, value.span));
|
.map(move |value| select_fields(&value.item, &fields, value.tag()));
|
||||||
|
|
||||||
Ok(objects.from_input_stream())
|
Ok(objects.from_input_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ pub fn filter_plugin(
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("Failed to spawn child process");
|
.expect("Failed to spawn child process");
|
||||||
|
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||||
|
@ -90,41 +91,117 @@ pub fn filter_plugin(
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
|
*/
|
||||||
|
let mut bos: VecDeque<Tagged<Value>> = VecDeque::new();
|
||||||
|
bos.push_back(Value::Primitive(Primitive::BeginningOfStream).tagged_unknown());
|
||||||
|
|
||||||
|
let mut eos: VecDeque<Tagged<Value>> = VecDeque::new();
|
||||||
|
eos.push_back(Value::Primitive(Primitive::EndOfStream).tagged_unknown());
|
||||||
|
|
||||||
|
let call_info = args.call_info.clone();
|
||||||
|
|
||||||
|
let stream = bos
|
||||||
|
.chain(args.input.values)
|
||||||
|
.chain(eos)
|
||||||
|
.map(move |v| match v {
|
||||||
|
Tagged {
|
||||||
|
item: Value::Primitive(Primitive::BeginningOfStream),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
|
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||||
|
|
||||||
|
let mut reader = BufReader::new(stdout);
|
||||||
|
|
||||||
|
let request = JsonRpc::new("begin_filter", call_info.clone());
|
||||||
|
let request_raw = serde_json::to_string(&request).unwrap();
|
||||||
|
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||||
|
|
||||||
|
let mut input = String::new();
|
||||||
|
match reader.read_line(&mut input) {
|
||||||
|
Ok(_) => {
|
||||||
|
let response = serde_json::from_str::<NuResult>(&input);
|
||||||
|
match response {
|
||||||
|
Ok(NuResult::response { params }) => match params {
|
||||||
|
Ok(params) => params,
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(ReturnValue::Err(e));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::string(format!(
|
||||||
|
"Error while processing begin_filter response: {:?} {}",
|
||||||
|
e, input
|
||||||
|
))));
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(ShellError::string(format!(
|
let mut result = VecDeque::new();
|
||||||
"Error while processing input: {:?} {}",
|
result.push_back(Err(ShellError::string(format!(
|
||||||
e, input
|
"Error while reading begin_filter response: {:?}",
|
||||||
)));
|
e
|
||||||
|
))));
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
Tagged {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut eos: VecDeque<Spanned<Value>> = VecDeque::new();
|
|
||||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).spanned_unknown());
|
|
||||||
|
|
||||||
let stream = args
|
|
||||||
.input
|
|
||||||
.values
|
|
||||||
.chain(eos)
|
|
||||||
.map(move |v| match v {
|
|
||||||
Spanned {
|
|
||||||
item: Value::Primitive(Primitive::EndOfStream),
|
item: Value::Primitive(Primitive::EndOfStream),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||||
|
|
||||||
let _ = BufReader::new(stdout);
|
let mut reader = BufReader::new(stdout);
|
||||||
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]);
|
|
||||||
|
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("end_filter", vec![]);
|
||||||
let request_raw = serde_json::to_string(&request).unwrap();
|
let request_raw = serde_json::to_string(&request).unwrap();
|
||||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||||
|
|
||||||
VecDeque::new()
|
let mut input = String::new();
|
||||||
|
match reader.read_line(&mut input) {
|
||||||
|
Ok(_) => {
|
||||||
|
let response = serde_json::from_str::<NuResult>(&input);
|
||||||
|
match response {
|
||||||
|
Ok(NuResult::response { params }) => match params {
|
||||||
|
Ok(params) => {
|
||||||
|
let request: JsonRpc<std::vec::Vec<Value>> =
|
||||||
|
JsonRpc::new("quit", vec![]);
|
||||||
|
let request_raw = serde_json::to_string(&request).unwrap();
|
||||||
|
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||||
|
|
||||||
|
params
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(ReturnValue::Err(e));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::string(format!(
|
||||||
|
"Error while processing end_filter response: {:?} {}",
|
||||||
|
e, input
|
||||||
|
))));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::string(format!(
|
||||||
|
"Error while reading end_filter: {:?}",
|
||||||
|
e
|
||||||
|
))));
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||||
|
@ -152,7 +229,7 @@ pub fn filter_plugin(
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(Err(ShellError::string(format!(
|
result.push_back(Err(ShellError::string(format!(
|
||||||
"Error while processing input: {:?} {}",
|
"Error while processing filter response: {:?} {}",
|
||||||
e, input
|
e, input
|
||||||
))));
|
))));
|
||||||
result
|
result
|
||||||
|
@ -162,7 +239,7 @@ pub fn filter_plugin(
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(Err(ShellError::string(format!(
|
result.push_back(Err(ShellError::string(format!(
|
||||||
"Error while processing input: {:?}",
|
"Error while reading filter response: {:?}",
|
||||||
e
|
e
|
||||||
))));
|
))));
|
||||||
result
|
result
|
||||||
|
|
7
src/commands/prev.rs
Normal file
7
src/commands/prev.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use crate::commands::command::CommandAction;
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn prev(_args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::PreviousShell))].into())
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ pub fn ps(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream
|
||||||
|
|
||||||
let list = list
|
let list = list
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(_, process)| process_dict(process, args.name_span()))
|
.map(|(_, process)| process_dict(process, Tag::unknown_origin(args.call_info.name_span)))
|
||||||
.collect::<VecDeque<_>>();
|
.collect::<VecDeque<_>>();
|
||||||
|
|
||||||
Ok(list.from_input_stream())
|
Ok(list.from_input_stream())
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
|
||||||
let (input, args) = args.parts();
|
let (input, args) = args.parts();
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Reject requires fields",
|
"Reject requires fields",
|
||||||
"needs parameter",
|
"needs parameter",
|
||||||
span,
|
span,
|
||||||
|
@ -26,11 +26,9 @@ pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
|
||||||
|
|
||||||
let fields = fields?;
|
let fields = fields?;
|
||||||
|
|
||||||
let stream = input.values.map(move |item| {
|
let stream = input
|
||||||
reject_fields(&item, &fields, item.span)
|
.values
|
||||||
.into_spanned_value()
|
.map(move |item| reject_fields(&item, &fields, item.tag()).into_tagged_value());
|
||||||
.spanned(name_span)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(stream.from_input_stream())
|
Ok(stream.from_input_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,15 @@ use crate::commands::StaticCommand;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::hir::SyntaxType;
|
use crate::parser::hir::SyntaxType;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use glob::glob;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub struct Remove;
|
pub struct Remove;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RemoveArgs {
|
pub struct RemoveArgs {
|
||||||
path: Spanned<PathBuf>,
|
path: Tagged<PathBuf>,
|
||||||
recursive: bool,
|
recursive: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,17 +45,32 @@ pub fn rm(
|
||||||
file => full_path.push(file),
|
file => full_path.push(file),
|
||||||
}
|
}
|
||||||
|
|
||||||
if full_path.is_dir() {
|
let entries = glob(&full_path.to_string_lossy());
|
||||||
if !recursive {
|
|
||||||
return Err(ShellError::maybe_labeled_error(
|
if entries.is_err() {
|
||||||
"is a directory",
|
return Err(ShellError::string("Invalid pattern."));
|
||||||
"",
|
}
|
||||||
context.name,
|
|
||||||
));
|
let entries = entries.unwrap();
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
match entry {
|
||||||
|
Ok(path) => {
|
||||||
|
if path.is_dir() {
|
||||||
|
if !recursive {
|
||||||
|
return Err(ShellError::string(
|
||||||
|
"is a directory",
|
||||||
|
// "is a directory",
|
||||||
|
// args.call_info.name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
std::fs::remove_dir_all(&path).expect("can not remove directory");
|
||||||
|
} else if path.is_file() {
|
||||||
|
std::fs::remove_file(&path).expect("can not remove file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => return Err(ShellError::string(&format!("{:?}", e))),
|
||||||
}
|
}
|
||||||
std::fs::remove_dir_all(&full_path).expect("can not remove directory");
|
|
||||||
} else if full_path.is_file() {
|
|
||||||
std::fs::remove_file(&full_path).expect("can not remove file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(OutputStream::empty())
|
Ok(OutputStream::empty())
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::commands::to_yaml::value_to_yaml_value;
|
||||||
use crate::commands::StaticCommand;
|
use crate::commands::StaticCommand;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::Value;
|
use crate::object::Value;
|
||||||
use crate::parser::Spanned;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ pub struct Save;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct SaveArgs {
|
pub struct SaveArgs {
|
||||||
path: Spanned<PathBuf>,
|
path: Tagged<PathBuf>,
|
||||||
raw: bool,
|
raw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ pub fn save(
|
||||||
full_path.push(path.item());
|
full_path.push(path.item());
|
||||||
|
|
||||||
let stream = async_stream_block! {
|
let stream = async_stream_block! {
|
||||||
let input: Vec<Spanned<Value>> = context.input.values.collect().await;
|
let input: Vec<Tagged<Value>> = context.input.values.collect().await;
|
||||||
|
|
||||||
let contents = match full_path.extension() {
|
let contents = match full_path.extension() {
|
||||||
Some(x) if x == "csv" && !save_raw => {
|
Some(x) if x == "csv" && !save_raw => {
|
||||||
|
|
18
src/commands/shells.rs
Normal file
18
src/commands/shells.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::TaggedDictBuilder;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let mut shells_out = VecDeque::new();
|
||||||
|
let span = args.call_info.name_span;
|
||||||
|
|
||||||
|
for shell in args.shell_manager.shells.lock().unwrap().iter() {
|
||||||
|
let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(span));
|
||||||
|
dict.insert("name", shell.name());
|
||||||
|
dict.insert("path", shell.path());
|
||||||
|
|
||||||
|
shells_out.push_back(dict.into_tagged_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(shells_out.to_output_stream())
|
||||||
|
}
|
|
@ -1,23 +1,26 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{SpannedDictBuilder, Value};
|
use crate::object::{TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
pub fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
let span = args.call_info.name_span;
|
||||||
Ok(input
|
Ok(input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.item {
|
||||||
Value::Primitive(Primitive::String(s)) => ReturnSuccess::value(count(&s, v.span)),
|
Value::Primitive(Primitive::String(ref s)) => ReturnSuccess::value(count(s, v.tag())),
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected string values from pipeline",
|
"Expected a string from pipeline",
|
||||||
"expects strings from pipeline",
|
"requires string input",
|
||||||
Some(v.span),
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
v.span(),
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count(contents: &str, span: impl Into<Span>) -> Spanned<Value> {
|
fn count(contents: &str, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let mut lines: i64 = 0;
|
let mut lines: i64 = 0;
|
||||||
let mut words: i64 = 0;
|
let mut words: i64 = 0;
|
||||||
let mut chars: i64 = 0;
|
let mut chars: i64 = 0;
|
||||||
|
@ -42,7 +45,7 @@ fn count(contents: &str, span: impl Into<Span>) -> Spanned<Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dict = SpannedDictBuilder::new(span);
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
//TODO: add back in name when we have it in the span
|
//TODO: add back in name when we have it in the span
|
||||||
//dict.insert("name", Value::string(name));
|
//dict.insert("name", Value::string(name));
|
||||||
dict.insert("lines", Value::int(lines));
|
dict.insert("lines", Value::int(lines));
|
||||||
|
@ -50,5 +53,5 @@ fn count(contents: &str, span: impl Into<Span>) -> Spanned<Value> {
|
||||||
dict.insert("chars", Value::int(chars));
|
dict.insert("chars", Value::int(chars));
|
||||||
dict.insert("max length", Value::int(bytes));
|
dict.insert("max length", Value::int(bytes));
|
||||||
|
|
||||||
dict.into_spanned_value()
|
dict.into_tagged_value()
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn sort_by(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||||
fields
|
fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| item.get_data_by_key(f).map(|i| i.clone()))
|
.map(|f| item.get_data_by_key(f).map(|i| i.clone()))
|
||||||
.collect::<Vec<Option<Spanned<Value>>>>()
|
.collect::<Vec<Option<Tagged<Value>>>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
vec.into_iter().collect::<VecDeque<_>>()
|
vec.into_iter().collect::<VecDeque<_>>()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ pub fn split_column(
|
||||||
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
|
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
|
||||||
|
|
||||||
if positional.len() == 0 {
|
if positional.len() == 0 {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Split-column needs more information",
|
"Split-column needs more information",
|
||||||
"needs parameter (eg split-column \",\")",
|
"needs parameter (eg split-column \",\")",
|
||||||
span,
|
span,
|
||||||
|
@ -24,7 +24,7 @@ pub fn split_column(
|
||||||
Ok(input
|
Ok(input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.item {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
Value::Primitive(Primitive::String(ref s)) => {
|
||||||
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
||||||
trace!("splitting with {:?}", splitter);
|
trace!("splitting with {:?}", splitter);
|
||||||
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
|
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
|
||||||
|
@ -38,33 +38,35 @@ pub fn split_column(
|
||||||
gen_columns.push(format!("Column{}", i + 1));
|
gen_columns.push(format!("Column{}", i + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dict = SpannedDictBuilder::new(v.span);
|
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||||
for (&k, v) in split_result.iter().zip(gen_columns.iter()) {
|
for (&k, v) in split_result.iter().zip(gen_columns.iter()) {
|
||||||
dict.insert(v.clone(), Primitive::String(k.into()));
|
dict.insert(v.clone(), Primitive::String(k.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnSuccess::value(dict.into_spanned_value())
|
ReturnSuccess::value(dict.into_tagged_value())
|
||||||
} else if split_result.len() == (positional.len() - 1) {
|
} else if split_result.len() == (positional.len() - 1) {
|
||||||
let mut dict = SpannedDictBuilder::new(v.span);
|
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||||
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
|
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
|
||||||
dict.insert(
|
dict.insert(
|
||||||
v.as_string().unwrap(),
|
v.as_string().unwrap(),
|
||||||
Value::Primitive(Primitive::String(k.into())),
|
Value::Primitive(Primitive::String(k.into())),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ReturnSuccess::value(dict.into_spanned_value())
|
ReturnSuccess::value(dict.into_tagged_value())
|
||||||
} else {
|
} else {
|
||||||
let mut dict = SpannedDictBuilder::new(v.span);
|
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||||
for k in positional.iter().skip(1) {
|
for k in positional.iter().skip(1) {
|
||||||
dict.insert(k.as_string().unwrap().trim(), Primitive::String("".into()));
|
dict.insert(k.as_string().unwrap().trim(), Primitive::String("".into()));
|
||||||
}
|
}
|
||||||
ReturnSuccess::value(dict.into_spanned_value())
|
ReturnSuccess::value(dict.into_tagged_value())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected string values from pipeline",
|
"Expected a string from pipeline",
|
||||||
"expects strings from pipeline",
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
v.span(),
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{Primitive, Value};
|
use crate::object::{Primitive, Value};
|
||||||
use crate::parser::Spanned;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
|
@ -13,10 +12,10 @@ pub fn split_row(
|
||||||
let len = args.len();
|
let len = args.len();
|
||||||
let (input, args) = args.parts();
|
let (input, args) = args.parts();
|
||||||
|
|
||||||
let positional: Vec<Spanned<Value>> = args.positional.iter().flatten().cloned().collect();
|
let positional: Vec<Tagged<Value>> = args.positional.iter().flatten().cloned().collect();
|
||||||
|
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Split-row needs more information",
|
"Split-row needs more information",
|
||||||
"needs parameter (eg split-row \"\\n\")",
|
"needs parameter (eg split-row \"\\n\")",
|
||||||
span,
|
span,
|
||||||
|
@ -26,7 +25,7 @@ pub fn split_row(
|
||||||
let stream = input
|
let stream = input
|
||||||
.values
|
.values
|
||||||
.map(move |v| match v.item {
|
.map(move |v| match v.item {
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
Value::Primitive(Primitive::String(ref s)) => {
|
||||||
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
|
||||||
trace!("splitting with {:?}", splitter);
|
trace!("splitting with {:?}", splitter);
|
||||||
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
|
let split_result: Vec<_> = s.split(&splitter).filter(|s| s.trim() != "").collect();
|
||||||
|
@ -36,17 +35,19 @@ pub fn split_row(
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
for s in split_result {
|
for s in split_result {
|
||||||
result.push_back(ReturnSuccess::value(
|
result.push_back(ReturnSuccess::value(
|
||||||
Value::Primitive(Primitive::String(s.into())).spanned(v.span),
|
Value::Primitive(Primitive::String(s.into())).tagged(v.tag()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(Err(ShellError::maybe_labeled_error(
|
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
||||||
"Expected string values from pipeline",
|
"Expected a string from pipeline",
|
||||||
"expects strings from pipeline",
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
v.span(),
|
||||||
)));
|
)));
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
use crate::errors::ShellError;
|
|
||||||
use crate::object::base::OF64;
|
|
||||||
use crate::object::SpannedDictBuilder;
|
|
||||||
use crate::object::{Primitive, Value};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use sys_info::*;
|
|
||||||
use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt};
|
|
||||||
|
|
||||||
pub fn sysinfo(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
|
||||||
let name_span = args.name_span();
|
|
||||||
let mut idx = SpannedDictBuilder::new(name_span);
|
|
||||||
|
|
||||||
if let (Ok(name), Ok(version)) = (os_type(), os_release()) {
|
|
||||||
let mut os_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
os_idx.insert("name", Primitive::String(name));
|
|
||||||
os_idx.insert("version", Primitive::String(version));
|
|
||||||
|
|
||||||
idx.insert_spanned("os", os_idx.into_spanned_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let (Ok(num_cpu), Ok(cpu_speed)) = (cpu_num(), cpu_speed()) {
|
|
||||||
let mut cpu_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
cpu_idx.insert("num", Primitive::Int(num_cpu as i64));
|
|
||||||
cpu_idx.insert("speed", Primitive::Int(cpu_speed as i64));
|
|
||||||
|
|
||||||
idx.insert_spanned("cpu", cpu_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(x) = loadavg() {
|
|
||||||
let mut load_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
|
|
||||||
load_idx.insert("1min", Primitive::Float(OF64::from(x.one)));
|
|
||||||
load_idx.insert("5min", Primitive::Float(OF64::from(x.five)));
|
|
||||||
load_idx.insert("15min", Primitive::Float(OF64::from(x.fifteen)));
|
|
||||||
|
|
||||||
idx.insert_spanned("load avg", load_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(x) = mem_info() {
|
|
||||||
let mut mem_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
|
|
||||||
mem_idx.insert("total", Primitive::Bytes(x.total as u64 * 1024));
|
|
||||||
mem_idx.insert("free", Primitive::Bytes(x.free as u64 * 1024));
|
|
||||||
mem_idx.insert("avail", Primitive::Bytes(x.avail as u64 * 1024));
|
|
||||||
mem_idx.insert("buffers", Primitive::Bytes(x.buffers as u64 * 1024));
|
|
||||||
mem_idx.insert("cached", Primitive::Bytes(x.cached as u64 * 1024));
|
|
||||||
mem_idx.insert("swap total", Primitive::Bytes(x.swap_total as u64 * 1024));
|
|
||||||
mem_idx.insert("swap free", Primitive::Bytes(x.swap_free as u64 * 1024));
|
|
||||||
|
|
||||||
idx.insert_spanned("mem", mem_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if let Ok(x) = disk_info() {
|
|
||||||
let mut disk_idx = indexmap::IndexMap::new();
|
|
||||||
disk_idx.insert(
|
|
||||||
"total".to_string(),
|
|
||||||
Value::Primitive(Primitive::Bytes(x.total as u128 * 1024)),
|
|
||||||
);
|
|
||||||
disk_idx.insert(
|
|
||||||
"free".to_string(),
|
|
||||||
Value::Primitive(Primitive::Bytes(x.free as u128 * 1024)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if let Ok(x) = hostname() {
|
|
||||||
idx.insert("hostname", Primitive::String(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
{
|
|
||||||
if let Ok(x) = boottime() {
|
|
||||||
let mut boottime_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
boottime_idx.insert("days", Primitive::Int(x.tv_sec / (24 * 3600)));
|
|
||||||
boottime_idx.insert("hours", Primitive::Int((x.tv_sec / 3600) % 24));
|
|
||||||
boottime_idx.insert("mins", Primitive::Int((x.tv_sec / 60) % 60));
|
|
||||||
|
|
||||||
idx.insert_spanned("uptime", boottime_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let system = sysinfo::System::new_with_specifics(RefreshKind::everything().without_processes());
|
|
||||||
let components_list = system.get_components_list();
|
|
||||||
if components_list.len() > 0 {
|
|
||||||
let mut v: Vec<Spanned<Value>> = vec![];
|
|
||||||
for component in components_list {
|
|
||||||
let mut component_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
component_idx.insert("name", Primitive::String(component.get_label().to_string()));
|
|
||||||
component_idx.insert(
|
|
||||||
"temp",
|
|
||||||
Primitive::Float(OF64::from(component.get_temperature() as f64)),
|
|
||||||
);
|
|
||||||
component_idx.insert(
|
|
||||||
"max",
|
|
||||||
Primitive::Float(OF64::from(component.get_max() as f64)),
|
|
||||||
);
|
|
||||||
if let Some(critical) = component.get_critical() {
|
|
||||||
component_idx.insert("critical", Primitive::Float(OF64::from(critical as f64)));
|
|
||||||
}
|
|
||||||
v.push(component_idx.into());
|
|
||||||
}
|
|
||||||
idx.insert("temps", Value::List(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
let disks = system.get_disks();
|
|
||||||
if disks.len() > 0 {
|
|
||||||
let mut v = vec![];
|
|
||||||
|
|
||||||
for disk in disks {
|
|
||||||
let mut disk_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
disk_idx.insert("name", Value::string(disk.get_name().to_string_lossy()));
|
|
||||||
disk_idx.insert("available", Value::bytes(disk.get_available_space()));
|
|
||||||
disk_idx.insert("total", Value::bytes(disk.get_total_space()));
|
|
||||||
v.push(disk_idx.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
idx.insert("disks", Value::List(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
let network = system.get_network();
|
|
||||||
let incoming = network.get_income();
|
|
||||||
let outgoing = network.get_outcome();
|
|
||||||
|
|
||||||
let mut network_idx = SpannedDictBuilder::new(name_span);
|
|
||||||
network_idx.insert("incoming", Value::bytes(incoming));
|
|
||||||
network_idx.insert("outgoing", Value::bytes(outgoing));
|
|
||||||
idx.insert_spanned("network", network_idx);
|
|
||||||
|
|
||||||
let stream = stream![idx.into_spanned_value()];
|
|
||||||
|
|
||||||
Ok(stream.from_input_stream())
|
|
||||||
}
|
|
|
@ -27,7 +27,7 @@ impl StaticCommand for Table {
|
||||||
|
|
||||||
pub fn table(_args: TableArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
pub fn table(_args: TableArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||||
let stream = async_stream_block! {
|
let stream = async_stream_block! {
|
||||||
let input: Vec<Spanned<Value>> = context.input.into_vec().await;
|
let input: Vec<Tagged<Value>> = context.input.into_vec().await;
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
let mut host = context.host.lock().unwrap();
|
let mut host = context.host.lock().unwrap();
|
||||||
let view = TableView::from_list(&input);
|
let view = TableView::from_list(&input);
|
||||||
|
|
33
src/commands/tags.rs
Normal file
33
src/commands/tags.rs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::{TaggedDictBuilder, Value};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub fn tags(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||||
|
let source_map = args.call_info.source_map.clone();
|
||||||
|
Ok(args
|
||||||
|
.input
|
||||||
|
.values
|
||||||
|
.map(move |v| {
|
||||||
|
let mut tags = TaggedDictBuilder::new(v.tag());
|
||||||
|
{
|
||||||
|
let origin = v.origin();
|
||||||
|
let span = v.span();
|
||||||
|
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||||
|
dict.insert("start", Value::int(span.start as i64));
|
||||||
|
dict.insert("end", Value::int(span.end as i64));
|
||||||
|
match origin.map(|x| source_map.get(&x)).flatten() {
|
||||||
|
Some(SpanSource::File(source)) => {
|
||||||
|
dict.insert("origin", Value::string(source));
|
||||||
|
}
|
||||||
|
Some(SpanSource::Url(source)) => {
|
||||||
|
dict.insert("origin", Value::string(source));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
tags.insert_tagged("span", dict.into_tagged_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
tags.into_tagged_value()
|
||||||
|
})
|
||||||
|
.to_output_stream())
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ pub fn to_array(
|
||||||
let out = args.input.values.collect();
|
let out = args.input.values.collect();
|
||||||
|
|
||||||
Ok(out
|
Ok(out
|
||||||
.map(|vec: Vec<_>| stream![Value::List(vec).spanned_unknown()]) // TODO: args.input should have a span
|
.map(|vec: Vec<_>| stream![Value::List(vec).tagged_unknown()]) // TODO: args.input should have a span
|
||||||
.flatten_stream()
|
.flatten_stream()
|
||||||
.from_input_stream())
|
.from_input_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use crate::object::{Primitive, Value};
|
use crate::object::{Primitive, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use csv::WriterBuilder;
|
use csv::WriterBuilder;
|
||||||
use log::debug;
|
|
||||||
|
|
||||||
pub fn value_to_csv_value(v: &Value) -> Value {
|
pub fn value_to_csv_value(v: &Value) -> Value {
|
||||||
debug!("value_to_csv_value(Value::Object(v)) where v = {:?}", v);
|
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Value::Primitive(Primitive::String(s)) => Value::Primitive(Primitive::String(s.clone())),
|
Value::Primitive(Primitive::String(s)) => Value::Primitive(Primitive::String(s.clone())),
|
||||||
Value::Primitive(Primitive::Nothing) => Value::Primitive(Primitive::Nothing),
|
Value::Primitive(Primitive::Nothing) => Value::Primitive(Primitive::Nothing),
|
||||||
|
@ -20,8 +17,6 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
match v {
|
match v {
|
||||||
Value::List(_l) => return Ok(String::from("[list list]")),
|
Value::List(_l) => return Ok(String::from("[list list]")),
|
||||||
Value::Object(o) => {
|
Value::Object(o) => {
|
||||||
debug!("to_csv:to_string(Value::Object(v)) where v = {:?}", v);
|
|
||||||
|
|
||||||
let mut wtr = WriterBuilder::new().from_writer(vec![]);
|
let mut wtr = WriterBuilder::new().from_writer(vec![]);
|
||||||
let mut fields: VecDeque<String> = VecDeque::new();
|
let mut fields: VecDeque<String> = VecDeque::new();
|
||||||
let mut values: VecDeque<String> = VecDeque::new();
|
let mut values: VecDeque<String> = VecDeque::new();
|
||||||
|
@ -49,13 +44,15 @@ pub fn to_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
|
||||||
Ok(out
|
Ok(out
|
||||||
.values
|
.values
|
||||||
.map(move |a| match to_string(&value_to_csv_value(&a.item)) {
|
.map(move |a| match to_string(&value_to_csv_value(&a.item)) {
|
||||||
Ok(x) => {
|
Ok(x) => ReturnSuccess::value(
|
||||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
|
||||||
}
|
),
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Can not convert to CSV string",
|
"Expected an object with CSV-compatible structure from pipeline",
|
||||||
"can not convert piped data to CSV string",
|
"requires CSV-compatible input",
|
||||||
name_span,
|
name_span,
|
||||||
|
format!("{} originates from here", a.item.type_name()),
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
Value::Primitive(Primitive::Date(d)) => serde_json::Value::String(d.to_string()),
|
||||||
Value::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
Value::Primitive(Primitive::EndOfStream) => serde_json::Value::Null,
|
||||||
|
Value::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
||||||
Value::Primitive(Primitive::Float(f)) => {
|
Value::Primitive(Primitive::Float(f)) => {
|
||||||
serde_json::Value::Number(serde_json::Number::from_f64(f.into_inner()).unwrap())
|
serde_json::Value::Number(serde_json::Number::from_f64(f.into_inner()).unwrap())
|
||||||
}
|
}
|
||||||
|
@ -49,13 +50,15 @@ pub fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||||
.values
|
.values
|
||||||
.map(
|
.map(
|
||||||
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
|
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
|
||||||
Ok(x) => {
|
Ok(x) => ReturnSuccess::value(
|
||||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
|
||||||
}
|
),
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Can not convert to JSON string",
|
"Expected an object with JSON-compatible structure from pipeline",
|
||||||
"can not convert piped data to JSON string",
|
"requires JSON-compatible input",
|
||||||
name_span,
|
name_span,
|
||||||
|
format!("{} originates from here", a.item.type_name()),
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,6 +9,9 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
||||||
Value::Primitive(Primitive::EndOfStream) => {
|
Value::Primitive(Primitive::EndOfStream) => {
|
||||||
toml::Value::String("<End of Stream>".to_string())
|
toml::Value::String("<End of Stream>".to_string())
|
||||||
}
|
}
|
||||||
|
Value::Primitive(Primitive::BeginningOfStream) => {
|
||||||
|
toml::Value::String("<Beginning of Stream>".to_string())
|
||||||
|
}
|
||||||
Value::Primitive(Primitive::Float(f)) => toml::Value::Float(f.into_inner()),
|
Value::Primitive(Primitive::Float(f)) => toml::Value::Float(f.into_inner()),
|
||||||
Value::Primitive(Primitive::Int(i)) => toml::Value::Integer(*i),
|
Value::Primitive(Primitive::Int(i)) => toml::Value::Integer(*i),
|
||||||
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
|
Value::Primitive(Primitive::Nothing) => toml::Value::String("<Nothing>".to_string()),
|
||||||
|
@ -40,13 +43,15 @@ pub fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||||
.map(move |a| match toml::to_string(&value_to_toml_value(&a)) {
|
.map(move |a| match toml::to_string(&value_to_toml_value(&a)) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
return ReturnSuccess::value(
|
return ReturnSuccess::value(
|
||||||
Value::Primitive(Primitive::String(val)).spanned(name_span),
|
Value::Primitive(Primitive::String(val)).simple_spanned(name_span),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
Err(err) => Err(ShellError::type_error(
|
"Expected an object with TOML-compatible structure from pipeline",
|
||||||
"Can not convert to a TOML string",
|
"requires TOML-compatible input",
|
||||||
format!("{:?} - {:?}", a.type_name(), err).spanned(name_span),
|
name_span,
|
||||||
|
format!("{} originates from here", a.item.type_name()),
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
|
|
|
@ -9,6 +9,7 @@ pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value {
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()),
|
Value::Primitive(Primitive::Date(d)) => serde_yaml::Value::String(d.to_string()),
|
||||||
Value::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null,
|
Value::Primitive(Primitive::EndOfStream) => serde_yaml::Value::Null,
|
||||||
|
Value::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null,
|
||||||
Value::Primitive(Primitive::Float(f)) => {
|
Value::Primitive(Primitive::Float(f)) => {
|
||||||
serde_yaml::Value::Number(serde_yaml::Number::from(f.into_inner()))
|
serde_yaml::Value::Number(serde_yaml::Number::from(f.into_inner()))
|
||||||
}
|
}
|
||||||
|
@ -46,13 +47,15 @@ pub fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||||
.values
|
.values
|
||||||
.map(
|
.map(
|
||||||
move |a| match serde_yaml::to_string(&value_to_yaml_value(&a)) {
|
move |a| match serde_yaml::to_string(&value_to_yaml_value(&a)) {
|
||||||
Ok(x) => {
|
Ok(x) => ReturnSuccess::value(
|
||||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
|
||||||
}
|
),
|
||||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Can not convert to YAML string",
|
"Expected an object with YAML-compatible structure from pipeline",
|
||||||
"can not convert piped data to YAML string",
|
"requires YAML-compatible input",
|
||||||
name_span,
|
name_span,
|
||||||
|
format!("{} originates from here", a.item.type_name()),
|
||||||
|
a.span(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub fn trim(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStre
|
||||||
.values
|
.values
|
||||||
.map(move |v| {
|
.map(move |v| {
|
||||||
let string = String::extract(&v)?;
|
let string = String::extract(&v)?;
|
||||||
ReturnSuccess::value(Value::string(string.trim()).spanned(v.span))
|
ReturnSuccess::value(Value::string(string.trim()).simple_spanned(v.span()))
|
||||||
})
|
})
|
||||||
.to_output_stream())
|
.to_output_stream())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::commands::{Command, UnevaluatedCallInfo};
|
use crate::commands::{Command, UnevaluatedCallInfo};
|
||||||
use crate::parser::{hir, Span};
|
use crate::parser::hir;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
@ -75,7 +75,7 @@ pub struct Context {
|
||||||
registry: CommandRegistry,
|
registry: CommandRegistry,
|
||||||
crate source_map: SourceMap,
|
crate source_map: SourceMap,
|
||||||
crate host: Arc<Mutex<dyn Host + Send>>,
|
crate host: Arc<Mutex<dyn Host + Send>>,
|
||||||
crate env: Arc<Mutex<Environment>>,
|
crate shell_manager: ShellManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
@ -88,7 +88,7 @@ impl Context {
|
||||||
registry: CommandRegistry::new(),
|
registry: CommandRegistry::new(),
|
||||||
source_map: SourceMap::new(),
|
source_map: SourceMap::new(),
|
||||||
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
||||||
env: Arc::new(Mutex::new(Environment::basic()?)),
|
shell_manager: ShellManager::basic()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,13 +117,25 @@ impl Context {
|
||||||
crate async fn run_command(
|
crate async fn run_command(
|
||||||
&mut self,
|
&mut self,
|
||||||
command: Arc<Command>,
|
command: Arc<Command>,
|
||||||
name_span: Option<Span>,
|
name_span: Span,
|
||||||
source_map: SourceMap,
|
source_map: SourceMap,
|
||||||
args: hir::Call,
|
args: hir::Call,
|
||||||
source: Text,
|
source: Text,
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let command_args = self.command_args(args, input, source, source_map, name_span);
|
let command_args = self.command_args(args, input, source, source_map, name_span);
|
||||||
|
/*
|
||||||
|
let command_args = CommandArgs {
|
||||||
|
host: self.host.clone(),
|
||||||
|
shell_manager: self.shell_manager.clone(),
|
||||||
|
call_info: CallInfo {
|
||||||
|
name_span,
|
||||||
|
source_map,
|
||||||
|
args,
|
||||||
|
},
|
||||||
|
input,
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
command.run(command_args, self.registry()).await
|
command.run(command_args, self.registry()).await
|
||||||
}
|
}
|
||||||
|
@ -133,7 +145,7 @@ impl Context {
|
||||||
args: hir::Call,
|
args: hir::Call,
|
||||||
source: Text,
|
source: Text,
|
||||||
source_map: SourceMap,
|
source_map: SourceMap,
|
||||||
name_span: Option<Span>,
|
name_span: Span,
|
||||||
) -> UnevaluatedCallInfo {
|
) -> UnevaluatedCallInfo {
|
||||||
UnevaluatedCallInfo {
|
UnevaluatedCallInfo {
|
||||||
args,
|
args,
|
||||||
|
@ -149,11 +161,11 @@ impl Context {
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
source: Text,
|
source: Text,
|
||||||
source_map: SourceMap,
|
source_map: SourceMap,
|
||||||
name_span: Option<Span>,
|
name_span: Span,
|
||||||
) -> CommandArgs {
|
) -> CommandArgs {
|
||||||
CommandArgs {
|
CommandArgs {
|
||||||
host: self.host.clone(),
|
host: self.host.clone(),
|
||||||
env: self.env.clone(),
|
shell_manager: self.shell_manager.clone(),
|
||||||
call_info: self.call_info(args, source, source_map, name_span),
|
call_info: self.call_info(args, source, source_map, name_span),
|
||||||
input,
|
input,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
crate mod environment;
|
|
||||||
crate mod host;
|
crate mod host;
|
||||||
|
|
||||||
crate use self::environment::Environment;
|
|
||||||
crate use self::host::Host;
|
crate use self::host::Host;
|
||||||
|
|
18
src/env/environment.rs
vendored
18
src/env/environment.rs
vendored
|
@ -1,18 +0,0 @@
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Environment {
|
|
||||||
crate path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Environment {
|
|
||||||
pub fn basic() -> Result<Environment, std::io::Error> {
|
|
||||||
let path = std::env::current_dir()?;
|
|
||||||
|
|
||||||
Ok(Environment { path })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> &Path {
|
|
||||||
self.path.as_path()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::parser::{Span, Spanned};
|
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use language_reporting::{Diagnostic, Label, Severity};
|
use language_reporting::{Diagnostic, Label, Severity};
|
||||||
|
@ -9,23 +8,18 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
pub enum Description {
|
pub enum Description {
|
||||||
Source(Spanned<String>),
|
Source(Tagged<String>),
|
||||||
Synthetic(String),
|
Synthetic(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Description {
|
impl Description {
|
||||||
pub fn from(item: Spanned<impl Into<String>>) -> Description {
|
pub fn from(value: Tagged<impl Into<String>>) -> Description {
|
||||||
match item {
|
let value_span = value.span();
|
||||||
Spanned {
|
let value_tag = value.tag();
|
||||||
span:
|
|
||||||
Span {
|
match value_span {
|
||||||
start: 0,
|
Span { start: 0, end: 0 } => Description::Synthetic(value.item.into()),
|
||||||
end: 0,
|
_ => Description::Source(Tagged::from_item(value.item.into(), value_tag)),
|
||||||
source: None,
|
|
||||||
},
|
|
||||||
item,
|
|
||||||
} => Description::Synthetic(item.into()),
|
|
||||||
Spanned { span, item } => Description::Source(Spanned::from_item(item.into(), span)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +27,7 @@ impl Description {
|
||||||
impl Description {
|
impl Description {
|
||||||
fn into_label(self) -> Result<Label<Span>, String> {
|
fn into_label(self) -> Result<Label<Span>, String> {
|
||||||
match self {
|
match self {
|
||||||
Description::Source(s) => Ok(Label::new_primary(s.span).with_message(s.item)),
|
Description::Source(s) => Ok(Label::new_primary(s.span()).with_message(s.item)),
|
||||||
Description::Synthetic(s) => Err(s),
|
Description::Synthetic(s) => Err(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,13 +41,13 @@ pub enum ArgumentError {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn labelled(
|
pub fn labelled(
|
||||||
span: impl Into<Option<Span>>,
|
span: impl Into<Span>,
|
||||||
heading: &'a str,
|
heading: &'a str,
|
||||||
span_message: &'a str,
|
span_message: &'a str,
|
||||||
) -> impl FnOnce(ShellError) -> ShellError + 'a {
|
) -> impl FnOnce(ShellError) -> ShellError + 'a {
|
||||||
let span = span.into();
|
let span = span.into();
|
||||||
|
|
||||||
move |_| ShellError::maybe_labeled_error(heading, span_message, span)
|
move |_| ShellError::labeled_error(heading, span_message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
|
@ -74,7 +68,7 @@ impl serde::de::Error for ShellError {
|
||||||
impl ShellError {
|
impl ShellError {
|
||||||
crate fn type_error(
|
crate fn type_error(
|
||||||
expected: impl Into<String>,
|
expected: impl Into<String>,
|
||||||
actual: Spanned<impl Into<String>>,
|
actual: Tagged<impl Into<String>>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ProximateShellError::TypeError {
|
ProximateShellError::TypeError {
|
||||||
expected: expected.into(),
|
expected: expected.into(),
|
||||||
|
@ -84,8 +78,8 @@ impl ShellError {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn coerce_error(
|
crate fn coerce_error(
|
||||||
left: Spanned<impl Into<String>>,
|
left: Tagged<impl Into<String>>,
|
||||||
right: Spanned<impl Into<String>>,
|
right: Tagged<impl Into<String>>,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
ProximateShellError::CoerceError {
|
ProximateShellError::CoerceError {
|
||||||
left: left.map(|l| l.into()),
|
left: left.map(|l| l.into()),
|
||||||
|
@ -175,9 +169,9 @@ impl ShellError {
|
||||||
ProximateShellError::TypeError {
|
ProximateShellError::TypeError {
|
||||||
expected,
|
expected,
|
||||||
actual:
|
actual:
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Some(actual),
|
item: Some(actual),
|
||||||
span,
|
tag: Tag { span, .. },
|
||||||
},
|
},
|
||||||
} => Diagnostic::new(Severity::Error, "Type Error").with_label(
|
} => Diagnostic::new(Severity::Error, "Type Error").with_label(
|
||||||
Label::new_primary(span)
|
Label::new_primary(span)
|
||||||
|
@ -186,7 +180,11 @@ impl ShellError {
|
||||||
|
|
||||||
ProximateShellError::TypeError {
|
ProximateShellError::TypeError {
|
||||||
expected,
|
expected,
|
||||||
actual: Spanned { item: None, span },
|
actual:
|
||||||
|
Tagged {
|
||||||
|
item: None,
|
||||||
|
tag: Tag { span, .. },
|
||||||
|
},
|
||||||
} => Diagnostic::new(Severity::Error, "Type Error")
|
} => Diagnostic::new(Severity::Error, "Type Error")
|
||||||
.with_label(Label::new_primary(span).with_message(expected)),
|
.with_label(Label::new_primary(span).with_message(expected)),
|
||||||
|
|
||||||
|
@ -211,8 +209,8 @@ impl ShellError {
|
||||||
ProximateShellError::Diagnostic(diag) => diag.diagnostic,
|
ProximateShellError::Diagnostic(diag) => diag.diagnostic,
|
||||||
ProximateShellError::CoerceError { left, right } => {
|
ProximateShellError::CoerceError { left, right } => {
|
||||||
Diagnostic::new(Severity::Error, "Coercion error")
|
Diagnostic::new(Severity::Error, "Coercion error")
|
||||||
.with_label(Label::new_primary(left.span).with_message(left.item))
|
.with_label(Label::new_primary(left.span()).with_message(left.item))
|
||||||
.with_label(Label::new_secondary(right.span).with_message(right.item))
|
.with_label(Label::new_secondary(right.span()).with_message(right.item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,18 +226,20 @@ impl ShellError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maybe_labeled_error(
|
pub fn labeled_error_with_secondary(
|
||||||
msg: impl Into<String>,
|
msg: impl Into<String>,
|
||||||
label: impl Into<String>,
|
primary_label: impl Into<String>,
|
||||||
span: Option<Span>,
|
primary_span: Span,
|
||||||
|
secondary_label: impl Into<String>,
|
||||||
|
secondary_span: Span,
|
||||||
) -> ShellError {
|
) -> ShellError {
|
||||||
match span {
|
ShellError::diagnostic(
|
||||||
Some(span) => ShellError::diagnostic(
|
Diagnostic::new_error(msg.into())
|
||||||
Diagnostic::new(Severity::Error, msg.into())
|
.with_label(Label::new_primary(primary_span).with_message(primary_label.into()))
|
||||||
.with_label(Label::new_primary(span).with_message(label.into())),
|
.with_label(
|
||||||
),
|
Label::new_secondary(secondary_span).with_message(secondary_label.into()),
|
||||||
None => ShellError::string(msg),
|
),
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string(title: impl Into<String>) -> ShellError {
|
pub fn string(title: impl Into<String>) -> ShellError {
|
||||||
|
@ -260,7 +260,7 @@ pub enum ProximateShellError {
|
||||||
String(StringError),
|
String(StringError),
|
||||||
TypeError {
|
TypeError {
|
||||||
expected: String,
|
expected: String,
|
||||||
actual: Spanned<Option<String>>,
|
actual: Tagged<Option<String>>,
|
||||||
},
|
},
|
||||||
MissingProperty {
|
MissingProperty {
|
||||||
subpath: Description,
|
subpath: Description,
|
||||||
|
@ -273,8 +273,8 @@ pub enum ProximateShellError {
|
||||||
},
|
},
|
||||||
Diagnostic(ShellDiagnostic),
|
Diagnostic(ShellDiagnostic),
|
||||||
CoerceError {
|
CoerceError {
|
||||||
left: Spanned<String>,
|
left: Tagged<String>,
|
||||||
right: Spanned<String>,
|
right: Tagged<String>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
impl ProximateShellError {
|
impl ProximateShellError {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::Description;
|
||||||
use crate::object::base::Block;
|
use crate::object::base::Block;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
hir::{self, Expression, RawExpression},
|
hir::{self, Expression, RawExpression},
|
||||||
CommandRegistry, Spanned, Text,
|
CommandRegistry, Text,
|
||||||
};
|
};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
@ -10,20 +10,20 @@ use indexmap::IndexMap;
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
it: Spanned<Value>,
|
it: Tagged<Value>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
vars: IndexMap<String, Spanned<Value>>,
|
vars: IndexMap<String, Tagged<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
impl Scope {
|
||||||
crate fn empty() -> Scope {
|
crate fn empty() -> Scope {
|
||||||
Scope {
|
Scope {
|
||||||
it: Value::nothing().spanned_unknown(),
|
it: Value::nothing().tagged_unknown(),
|
||||||
vars: IndexMap::new(),
|
vars: IndexMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn it_value(value: Spanned<Value>) -> Scope {
|
crate fn it_value(value: Tagged<Value>) -> Scope {
|
||||||
Scope {
|
Scope {
|
||||||
it: value,
|
it: value,
|
||||||
vars: IndexMap::new(),
|
vars: IndexMap::new(),
|
||||||
|
@ -36,19 +36,20 @@ crate fn evaluate_baseline_expr(
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<Spanned<Value>, ShellError> {
|
) -> Result<Tagged<Value>, ShellError> {
|
||||||
match &expr.item {
|
match &expr.item {
|
||||||
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
|
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
|
||||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => {
|
RawExpression::Synthetic(hir::Synthetic::String(s)) => Ok(Value::string(s).tagged_unknown()),
|
||||||
Ok(Value::string(s).spanned_unknown())
|
|
||||||
}
|
|
||||||
RawExpression::Variable(var) => evaluate_reference(var, scope, source),
|
RawExpression::Variable(var) => evaluate_reference(var, scope, source),
|
||||||
RawExpression::Binary(binary) => {
|
RawExpression::Binary(binary) => {
|
||||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||||
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
|
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
|
||||||
|
|
||||||
match left.compare(binary.op(), &*right) {
|
match left.compare(binary.op(), &*right) {
|
||||||
Ok(result) => Ok(Spanned::from_item(Value::boolean(result), *expr.span())),
|
Ok(result) => Ok(Tagged::from_simple_spanned_item(
|
||||||
|
Value::boolean(result),
|
||||||
|
expr.span(),
|
||||||
|
)),
|
||||||
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
||||||
binary.left().copy_span(left_type),
|
binary.left().copy_span(left_type),
|
||||||
binary.right().copy_span(right_type),
|
binary.right().copy_span(right_type),
|
||||||
|
@ -63,10 +64,10 @@ crate fn evaluate_baseline_expr(
|
||||||
exprs.push(expr);
|
exprs.push(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::List(exprs).spanned(expr.span()))
|
Ok(Value::List(exprs).tagged(Tag::unknown_origin(expr.span())))
|
||||||
}
|
}
|
||||||
RawExpression::Block(block) => Ok(Spanned::from_item(
|
RawExpression::Block(block) => Ok(Tagged::from_simple_spanned_item(
|
||||||
Value::Block(Block::new(block.clone(), source.clone(), *expr.span())),
|
Value::Block(Block::new(block.clone(), source.clone(), expr.span())),
|
||||||
expr.span(),
|
expr.span(),
|
||||||
)),
|
)),
|
||||||
RawExpression::Path(path) => {
|
RawExpression::Path(path) => {
|
||||||
|
@ -79,12 +80,12 @@ crate fn evaluate_baseline_expr(
|
||||||
match next {
|
match next {
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::missing_property(
|
return Err(ShellError::missing_property(
|
||||||
Description::from(item.spanned_type_name()),
|
Description::from(item.tagged_type_name()),
|
||||||
Description::from(name.clone()),
|
Description::from(name.clone()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
item = Spanned::from_item(
|
item = Tagged::from_simple_spanned_item(
|
||||||
next.clone().item,
|
next.clone().item,
|
||||||
(expr.span().start, name.span().end),
|
(expr.span().start, name.span().end),
|
||||||
)
|
)
|
||||||
|
@ -92,13 +93,16 @@ crate fn evaluate_baseline_expr(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Spanned::from_item(item.item().clone(), expr.span()))
|
Ok(Tagged::from_simple_spanned_item(
|
||||||
|
item.item().clone(),
|
||||||
|
expr.span(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
RawExpression::Boolean(_boolean) => unimplemented!(),
|
RawExpression::Boolean(_boolean) => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_literal(literal: Spanned<hir::Literal>, source: &Text) -> Spanned<Value> {
|
fn evaluate_literal(literal: Tagged<hir::Literal>, source: &Text) -> Tagged<Value> {
|
||||||
let result = match literal.item {
|
let result = match literal.item {
|
||||||
hir::Literal::Integer(int) => Value::int(int),
|
hir::Literal::Integer(int) => Value::int(int),
|
||||||
hir::Literal::Size(int, unit) => unit.compute(int),
|
hir::Literal::Size(int, unit) => unit.compute(int),
|
||||||
|
@ -113,13 +117,13 @@ fn evaluate_reference(
|
||||||
name: &hir::Variable,
|
name: &hir::Variable,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<Spanned<Value>, ShellError> {
|
) -> Result<Tagged<Value>, ShellError> {
|
||||||
match name {
|
match name {
|
||||||
hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item.clone(), span)),
|
hir::Variable::It(span) => Ok(scope.it.item.clone().simple_spanned(span)),
|
||||||
hir::Variable::Other(span) => Ok(scope
|
hir::Variable::Other(span) => Ok(scope
|
||||||
.vars
|
.vars
|
||||||
.get(span.slice(source))
|
.get(span.slice(source))
|
||||||
.map(|v| v.clone())
|
.map(|v| v.clone())
|
||||||
.unwrap_or_else(|| Value::nothing().spanned(span))),
|
.unwrap_or_else(|| Value::nothing().simple_spanned(span))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub struct TableView {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableView {
|
impl TableView {
|
||||||
fn merge_descriptors(values: &[Spanned<Value>]) -> Vec<String> {
|
fn merge_descriptors(values: &[Tagged<Value>]) -> Vec<String> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
for value in values {
|
for value in values {
|
||||||
for desc in value.data_descriptors() {
|
for desc in value.data_descriptors() {
|
||||||
|
@ -26,7 +26,7 @@ impl TableView {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_list(values: &[Spanned<Value>]) -> Option<TableView> {
|
pub fn from_list(values: &[Tagged<Value>]) -> Option<TableView> {
|
||||||
if values.len() == 0 {
|
if values.len() == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct VTableView {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VTableView {
|
impl VTableView {
|
||||||
pub fn from_list(values: &[Spanned<Value>]) -> Option<VTableView> {
|
pub fn from_list(values: &[Tagged<Value>]) -> Option<VTableView> {
|
||||||
if values.len() == 0 {
|
if values.len() == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,15 @@ mod traits;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
|
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
|
||||||
pub use crate::context::SpanSource;
|
pub use crate::context::{SourceMap, SpanSource};
|
||||||
pub use crate::env::host::BasicHost;
|
pub use crate::env::host::BasicHost;
|
||||||
pub use crate::parser::parse::span::SpannedItem;
|
pub use crate::object::base::OF64;
|
||||||
pub use crate::parser::Spanned;
|
|
||||||
pub use crate::plugin::{serve_plugin, Plugin};
|
pub use crate::plugin::{serve_plugin, Plugin};
|
||||||
pub use crate::utils::{AbsolutePath, RelativePath};
|
pub use crate::utils::{AbsolutePath, RelativePath};
|
||||||
pub use cli::cli;
|
pub use cli::cli;
|
||||||
pub use errors::ShellError;
|
pub use errors::ShellError;
|
||||||
pub use object::base::{Primitive, Value};
|
pub use object::base::{Primitive, Value};
|
||||||
|
pub use object::dict::{Dictionary, TaggedDictBuilder};
|
||||||
|
pub use object::meta::{Span, Tag, Tagged, TaggedItem};
|
||||||
pub use parser::parse::text::Text;
|
pub use parser::parse::text::Text;
|
||||||
pub use parser::registry::{EvaluatedArgs, NamedType, PositionalType, Signature};
|
pub use parser::registry::{EvaluatedArgs, NamedType, PositionalType, Signature};
|
||||||
|
|
|
@ -3,10 +3,11 @@ crate mod config;
|
||||||
crate mod dict;
|
crate mod dict;
|
||||||
crate mod files;
|
crate mod files;
|
||||||
crate mod into;
|
crate mod into;
|
||||||
|
crate mod meta;
|
||||||
crate mod process;
|
crate mod process;
|
||||||
crate mod types;
|
crate mod types;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
crate use base::{Block, Primitive, Switch, Value};
|
crate use base::{Block, Primitive, Switch, Value};
|
||||||
crate use dict::{Dictionary, SpannedDictBuilder};
|
crate use dict::{Dictionary, TaggedDictBuilder};
|
||||||
crate use files::dir_entry_dict;
|
crate use files::dir_entry_dict;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::context::CommandRegistry;
|
use crate::context::CommandRegistry;
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||||
use crate::object::SpannedDictBuilder;
|
use crate::object::TaggedDictBuilder;
|
||||||
use crate::parser::{hir, Operator, Span, Spanned};
|
use crate::parser::{hir, Operator};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Text;
|
use crate::Text;
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
|
@ -44,6 +44,8 @@ pub enum Primitive {
|
||||||
Date(DateTime<Utc>),
|
Date(DateTime<Utc>),
|
||||||
Path(PathBuf),
|
Path(PathBuf),
|
||||||
|
|
||||||
|
// Stream markers (used as bookend markers rather than actual values)
|
||||||
|
BeginningOfStream,
|
||||||
EndOfStream,
|
EndOfStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +55,7 @@ impl Primitive {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Nothing => "nothing",
|
Nothing => "nothing",
|
||||||
|
BeginningOfStream => "beginning-of-stream",
|
||||||
EndOfStream => "end-of-stream",
|
EndOfStream => "end-of-stream",
|
||||||
Path(_) => "path",
|
Path(_) => "path",
|
||||||
Int(_) => "int",
|
Int(_) => "int",
|
||||||
|
@ -70,6 +73,7 @@ impl Primitive {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Nothing => write!(f, "Nothing"),
|
Nothing => write!(f, "Nothing"),
|
||||||
|
BeginningOfStream => write!(f, "BeginningOfStream"),
|
||||||
EndOfStream => write!(f, "EndOfStream"),
|
EndOfStream => write!(f, "EndOfStream"),
|
||||||
Int(int) => write!(f, "{}", int),
|
Int(int) => write!(f, "{}", int),
|
||||||
Path(path) => write!(f, "{}", path.display()),
|
Path(path) => write!(f, "{}", path.display()),
|
||||||
|
@ -84,6 +88,7 @@ impl Primitive {
|
||||||
pub fn format(&self, field_name: Option<&String>) -> String {
|
pub fn format(&self, field_name: Option<&String>) -> String {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
|
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
|
||||||
|
Primitive::BeginningOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||||
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
|
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||||
Primitive::Path(p) => format!("{}", p.display()),
|
Primitive::Path(p) => format!("{}", p.display()),
|
||||||
Primitive::Bytes(b) => {
|
Primitive::Bytes(b) => {
|
||||||
|
@ -131,11 +136,11 @@ pub struct Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn invoke(&self, value: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
|
pub fn invoke(&self, value: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||||
let scope = Scope::new(value.clone());
|
let scope = Scope::new(value.clone());
|
||||||
|
|
||||||
if self.expressions.len() == 0 {
|
if self.expressions.len() == 0 {
|
||||||
return Ok(Spanned::from_item(Value::nothing(), self.span));
|
return Ok(Value::nothing().simple_spanned(self.span));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut last = None;
|
let mut last = None;
|
||||||
|
@ -159,17 +164,17 @@ pub enum Value {
|
||||||
Object(crate::object::Dictionary),
|
Object(crate::object::Dictionary),
|
||||||
#[serde(with = "serde_bytes")]
|
#[serde(with = "serde_bytes")]
|
||||||
Binary(Vec<u8>),
|
Binary(Vec<u8>),
|
||||||
List(Vec<Spanned<Value>>),
|
List(Vec<Tagged<Value>>),
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Block(Block),
|
Block(Block),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_list(values: &'a Vec<Spanned<Value>>) -> ValuesDebug<'a> {
|
pub fn debug_list(values: &'a Vec<Tagged<Value>>) -> ValuesDebug<'a> {
|
||||||
ValuesDebug { values }
|
ValuesDebug { values }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ValuesDebug<'a> {
|
pub struct ValuesDebug<'a> {
|
||||||
values: &'a Vec<Spanned<Value>>,
|
values: &'a Vec<Tagged<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ValuesDebug<'a> {
|
impl fmt::Debug for ValuesDebug<'a> {
|
||||||
|
@ -181,7 +186,7 @@ impl fmt::Debug for ValuesDebug<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ValueDebug<'a> {
|
pub struct ValueDebug<'a> {
|
||||||
value: &'a Spanned<Value>,
|
value: &'a Tagged<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ValueDebug<'a> {
|
impl fmt::Debug for ValueDebug<'a> {
|
||||||
|
@ -196,17 +201,17 @@ impl fmt::Debug for ValueDebug<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spanned<Value> {
|
impl Tagged<Value> {
|
||||||
crate fn spanned_type_name(&self) -> Spanned<String> {
|
crate fn tagged_type_name(&self) -> Tagged<String> {
|
||||||
let name = self.type_name();
|
let name = self.type_name();
|
||||||
Spanned::from_item(name, self.span)
|
Tagged::from_simple_spanned_item(name, self.span())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::TryFrom<&'a Spanned<Value>> for Block {
|
impl std::convert::TryFrom<&'a Tagged<Value>> for Block {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
fn try_from(value: &'a Spanned<Value>) -> Result<Block, ShellError> {
|
fn try_from(value: &'a Tagged<Value>) -> Result<Block, ShellError> {
|
||||||
match value.item() {
|
match value.item() {
|
||||||
Value::Block(block) => Ok(block.clone()),
|
Value::Block(block) => Ok(block.clone()),
|
||||||
v => Err(ShellError::type_error(
|
v => Err(ShellError::type_error(
|
||||||
|
@ -217,10 +222,10 @@ impl std::convert::TryFrom<&'a Spanned<Value>> for Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::TryFrom<&'a Spanned<Value>> for i64 {
|
impl std::convert::TryFrom<&'a Tagged<Value>> for i64 {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
fn try_from(value: &'a Spanned<Value>) -> Result<i64, ShellError> {
|
fn try_from(value: &'a Tagged<Value>) -> Result<i64, ShellError> {
|
||||||
match value.item() {
|
match value.item() {
|
||||||
Value::Primitive(Primitive::Int(int)) => Ok(*int),
|
Value::Primitive(Primitive::Int(int)) => Ok(*int),
|
||||||
v => Err(ShellError::type_error(
|
v => Err(ShellError::type_error(
|
||||||
|
@ -247,10 +252,10 @@ impl Switch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::TryFrom<Option<&'a Spanned<Value>>> for Switch {
|
impl std::convert::TryFrom<Option<&'a Tagged<Value>>> for Switch {
|
||||||
type Error = ShellError;
|
type Error = ShellError;
|
||||||
|
|
||||||
fn try_from(value: Option<&'a Spanned<Value>>) -> Result<Switch, ShellError> {
|
fn try_from(value: Option<&'a Tagged<Value>>) -> Result<Switch, ShellError> {
|
||||||
match value {
|
match value {
|
||||||
None => Ok(Switch::Absent),
|
None => Ok(Switch::Absent),
|
||||||
Some(value) => match value.item() {
|
Some(value) => match value.item() {
|
||||||
|
@ -264,7 +269,7 @@ impl std::convert::TryFrom<Option<&'a Spanned<Value>>> for Switch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spanned<Value> {
|
impl Tagged<Value> {
|
||||||
crate fn debug(&'a self) -> ValueDebug<'a> {
|
crate fn debug(&'a self) -> ValueDebug<'a> {
|
||||||
ValueDebug { value: self }
|
ValueDebug { value: self }
|
||||||
}
|
}
|
||||||
|
@ -296,13 +301,13 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Spanned<Value>> {
|
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Tagged<Value>> {
|
||||||
match self {
|
match self {
|
||||||
Value::Object(o) => o.get_data_by_key(name),
|
Value::Object(o) => o.get_data_by_key(name),
|
||||||
Value::List(l) => {
|
Value::List(l) => {
|
||||||
for item in l {
|
for item in l {
|
||||||
match item {
|
match item {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Object(o),
|
item: Value::Object(o),
|
||||||
..
|
..
|
||||||
} => match o.get_data_by_key(name) {
|
} => match o.get_data_by_key(name) {
|
||||||
|
@ -319,14 +324,14 @@ impl Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Spanned<Value>> {
|
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Tagged<Value>> {
|
||||||
match self {
|
match self {
|
||||||
Value::List(l) => l.iter().nth(idx),
|
Value::List(l) => l.iter().nth(idx),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_data_by_path(&'a self, span: Span, path: &str) -> Option<Spanned<&Value>> {
|
pub fn get_data_by_path(&'a self, tag: Tag, path: &str) -> Option<Tagged<&Value>> {
|
||||||
let mut current = self;
|
let mut current = self;
|
||||||
for p in path.split(".") {
|
for p in path.split(".") {
|
||||||
match current.get_data_by_key(p) {
|
match current.get_data_by_key(p) {
|
||||||
|
@ -335,18 +340,15 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Spanned {
|
Some(Tagged::from_item(current, tag))
|
||||||
item: current,
|
|
||||||
span,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_data_at_path(
|
pub fn insert_data_at_path(
|
||||||
&'a self,
|
&'a self,
|
||||||
span: Span,
|
tag: Tag,
|
||||||
path: &str,
|
path: &str,
|
||||||
new_value: Value,
|
new_value: Value,
|
||||||
) -> Option<Spanned<Value>> {
|
) -> Option<Tagged<Value>> {
|
||||||
let mut new_obj = self.clone();
|
let mut new_obj = self.clone();
|
||||||
|
|
||||||
let split_path: Vec<_> = path.split(".").collect();
|
let split_path: Vec<_> = path.split(".").collect();
|
||||||
|
@ -361,19 +363,13 @@ impl Value {
|
||||||
Value::Object(o) => {
|
Value::Object(o) => {
|
||||||
o.entries.insert(
|
o.entries.insert(
|
||||||
split_path[idx + 1].to_string(),
|
split_path[idx + 1].to_string(),
|
||||||
Spanned {
|
Tagged::from_item(new_value, tag),
|
||||||
item: new_value,
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(Spanned {
|
return Some(Tagged::from_item(new_obj, tag));
|
||||||
item: new_obj,
|
|
||||||
span,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
match next.item {
|
match next.item {
|
||||||
Value::Object(ref mut o) => {
|
Value::Object(ref mut o) => {
|
||||||
|
@ -393,10 +389,10 @@ impl Value {
|
||||||
|
|
||||||
pub fn replace_data_at_path(
|
pub fn replace_data_at_path(
|
||||||
&'a self,
|
&'a self,
|
||||||
span: Span,
|
tag: Tag,
|
||||||
path: &str,
|
path: &str,
|
||||||
replaced_value: Value,
|
replaced_value: Value,
|
||||||
) -> Option<Spanned<Value>> {
|
) -> Option<Tagged<Value>> {
|
||||||
let mut new_obj = self.clone();
|
let mut new_obj = self.clone();
|
||||||
|
|
||||||
let split_path: Vec<_> = path.split(".").collect();
|
let split_path: Vec<_> = path.split(".").collect();
|
||||||
|
@ -407,14 +403,8 @@ impl Value {
|
||||||
match current.entries.get_mut(split_path[idx]) {
|
match current.entries.get_mut(split_path[idx]) {
|
||||||
Some(next) => {
|
Some(next) => {
|
||||||
if idx == (split_path.len() - 1) {
|
if idx == (split_path.len() - 1) {
|
||||||
*next = Spanned {
|
*next = Tagged::from_item(replaced_value, tag);
|
||||||
item: replaced_value,
|
return Some(Tagged::from_item(new_obj, tag));
|
||||||
span,
|
|
||||||
};
|
|
||||||
return Some(Spanned {
|
|
||||||
item: new_obj,
|
|
||||||
span,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
match next.item {
|
match next.item {
|
||||||
Value::Object(ref mut o) => {
|
Value::Object(ref mut o) => {
|
||||||
|
@ -451,8 +441,12 @@ impl Value {
|
||||||
.map(|e| e.source(&b.source).to_string()),
|
.map(|e| e.source(&b.source).to_string()),
|
||||||
"; ",
|
"; ",
|
||||||
),
|
),
|
||||||
Value::Object(_) => format!("[object Object]"),
|
Value::Object(_) => format!("[{}]", self.type_name()),
|
||||||
Value::List(_) => format!("[list List]"),
|
Value::List(l) => format!(
|
||||||
|
"[{} {}]",
|
||||||
|
l.len(),
|
||||||
|
if l.len() == 1 { "item" } else { "items" }
|
||||||
|
),
|
||||||
Value::Binary(_) => format!("<binary>"),
|
Value::Binary(_) => format!("<binary>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,6 +486,16 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn as_pair(&self) -> Result<(Tagged<Value>, Tagged<Value>), ShellError> {
|
||||||
|
match self {
|
||||||
|
Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
|
||||||
|
other => Err(ShellError::string(format!(
|
||||||
|
"Expected pair, got {:?}",
|
||||||
|
other
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crate fn as_string(&self) -> Result<String, ShellError> {
|
crate fn as_string(&self) -> Result<String, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
Value::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
||||||
|
@ -565,8 +569,8 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn select_fields(obj: &Value, fields: &[String], span: impl Into<Span>) -> Spanned<Value> {
|
crate fn select_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let mut out = SpannedDictBuilder::new(span);
|
let mut out = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
let descs = obj.data_descriptors();
|
let descs = obj.data_descriptors();
|
||||||
|
|
||||||
|
@ -577,11 +581,11 @@ crate fn select_fields(obj: &Value, fields: &[String], span: impl Into<Span>) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.into_spanned_value()
|
out.into_tagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn reject_fields(obj: &Value, fields: &[String], span: impl Into<Span>) -> Spanned<Value> {
|
crate fn reject_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let mut out = SpannedDictBuilder::new(span);
|
let mut out = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
let descs = obj.data_descriptors();
|
let descs = obj.data_descriptors();
|
||||||
|
|
||||||
|
@ -592,7 +596,7 @@ crate fn reject_fields(obj: &Value, fields: &[String], span: impl Into<Span>) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.into_spanned_value()
|
out.into_tagged_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
|
|
@ -19,7 +19,7 @@ const APP_INFO: AppInfo = AppInfo {
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct Config {
|
struct Config {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
extra: IndexMap<String, Value>,
|
extra: IndexMap<String, Tagged<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn config_path() -> Result<PathBuf, ShellError> {
|
crate fn config_path() -> Result<PathBuf, ShellError> {
|
||||||
|
@ -29,7 +29,7 @@ crate fn config_path() -> Result<PathBuf, ShellError> {
|
||||||
Ok(location.join("config.toml"))
|
Ok(location.join("config.toml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn write_config(config: &IndexMap<String, Spanned<Value>>) -> Result<(), ShellError> {
|
crate fn write_config(config: &IndexMap<String, Tagged<Value>>) -> Result<(), ShellError> {
|
||||||
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||||
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ crate fn write_config(config: &IndexMap<String, Spanned<Value>>) -> Result<(), S
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Spanned<Value>>, ShellError> {
|
crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Tagged<Value>>, ShellError> {
|
||||||
let span = span.into();
|
let span = span.into();
|
||||||
|
|
||||||
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||||
|
@ -57,19 +57,19 @@ crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Spanned<Value>
|
||||||
trace!("config file = {}", filename.display());
|
trace!("config file = {}", filename.display());
|
||||||
|
|
||||||
let contents = fs::read_to_string(filename)
|
let contents = fs::read_to_string(filename)
|
||||||
.map(|v| v.spanned(span))
|
.map(|v| v.simple_spanned(span))
|
||||||
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
|
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
|
||||||
|
|
||||||
let parsed: toml::Value = toml::from_str(&contents)
|
let parsed: toml::Value = toml::from_str(&contents)
|
||||||
.map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
|
.map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
|
||||||
|
|
||||||
let value = convert_toml_value_to_nu_value(&parsed, span);
|
let value = convert_toml_value_to_nu_value(&parsed, Tag::unknown_origin(span));
|
||||||
|
let tag = value.tag();
|
||||||
match value.item {
|
match value.item {
|
||||||
Value::Object(Dictionary { entries }) => Ok(entries),
|
Value::Object(Dictionary { entries }) => Ok(entries),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
"Dictionary",
|
"Dictionary",
|
||||||
other.type_name().spanned(value.span),
|
other.type_name().tagged(tag),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)]
|
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)]
|
||||||
pub struct Dictionary {
|
pub struct Dictionary {
|
||||||
pub entries: IndexMap<String, Spanned<Value>>,
|
pub entries: IndexMap<String, Tagged<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Dictionary {
|
impl PartialOrd for Dictionary {
|
||||||
|
@ -28,8 +28,8 @@ impl PartialOrd for Dictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IndexMap<String, Spanned<Value>>> for Dictionary {
|
impl From<IndexMap<String, Tagged<Value>>> for Dictionary {
|
||||||
fn from(input: IndexMap<String, Spanned<Value>>) -> Dictionary {
|
fn from(input: IndexMap<String, Tagged<Value>>) -> Dictionary {
|
||||||
let mut out = IndexMap::default();
|
let mut out = IndexMap::default();
|
||||||
|
|
||||||
for (key, value) in input {
|
for (key, value) in input {
|
||||||
|
@ -79,7 +79,7 @@ impl Dictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn get_data_by_key(&self, name: &str) -> Option<&Spanned<Value>> {
|
crate fn get_data_by_key(&self, name: &str) -> Option<&Tagged<Value>> {
|
||||||
match self
|
match self
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -101,72 +101,71 @@ impl Dictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SpannedListBuilder {
|
pub struct TaggedListBuilder {
|
||||||
span: Span,
|
tag: Tag,
|
||||||
list: Vec<Spanned<Value>>,
|
list: Vec<Tagged<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpannedListBuilder {
|
impl TaggedListBuilder {
|
||||||
pub fn new(span: impl Into<Span>) -> SpannedListBuilder {
|
pub fn new(tag: impl Into<Tag>) -> TaggedListBuilder {
|
||||||
SpannedListBuilder {
|
TaggedListBuilder {
|
||||||
span: span.into(),
|
tag: tag.into(),
|
||||||
list: vec![],
|
list: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, value: impl Into<Value>) {
|
pub fn push(&mut self, value: impl Into<Value>) {
|
||||||
self.list.push(value.into().spanned(self.span));
|
self.list.push(value.into().tagged(self.tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_spanned(&mut self, value: impl Into<Spanned<Value>>) {
|
pub fn insert_tagged(&mut self, value: impl Into<Tagged<Value>>) {
|
||||||
self.list.push(value.into());
|
self.list.push(value.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
pub fn into_tagged_value(self) -> Tagged<Value> {
|
||||||
Value::List(self.list).spanned(self.span)
|
Value::List(self.list).tagged(self.tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SpannedListBuilder> for Spanned<Value> {
|
impl From<TaggedListBuilder> for Tagged<Value> {
|
||||||
fn from(input: SpannedListBuilder) -> Spanned<Value> {
|
fn from(input: TaggedListBuilder) -> Tagged<Value> {
|
||||||
input.into_spanned_value()
|
input.into_tagged_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SpannedDictBuilder {
|
pub struct TaggedDictBuilder {
|
||||||
span: Span,
|
tag: Tag,
|
||||||
dict: IndexMap<String, Spanned<Value>>,
|
dict: IndexMap<String, Tagged<Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpannedDictBuilder {
|
impl TaggedDictBuilder {
|
||||||
pub fn new(span: impl Into<Span>) -> SpannedDictBuilder {
|
pub fn new(tag: impl Into<Tag>) -> TaggedDictBuilder {
|
||||||
SpannedDictBuilder {
|
TaggedDictBuilder {
|
||||||
span: span.into(),
|
tag: tag.into(),
|
||||||
dict: IndexMap::default(),
|
dict: IndexMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
|
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
|
||||||
self.dict
|
self.dict.insert(key.into(), value.into().tagged(self.tag));
|
||||||
.insert(key.into(), value.into().spanned(self.span));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_spanned(&mut self, key: impl Into<String>, value: impl Into<Spanned<Value>>) {
|
pub fn insert_tagged(&mut self, key: impl Into<String>, value: impl Into<Tagged<Value>>) {
|
||||||
self.dict.insert(key.into(), value.into());
|
self.dict.insert(key.into(), value.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
pub fn into_tagged_value(self) -> Tagged<Value> {
|
||||||
self.into_spanned_dict().map(Value::Object)
|
self.into_tagged_dict().map(Value::Object)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_spanned_dict(self) -> Spanned<Dictionary> {
|
pub fn into_tagged_dict(self) -> Tagged<Dictionary> {
|
||||||
Dictionary { entries: self.dict }.spanned(self.span)
|
Dictionary { entries: self.dict }.tagged(self.tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SpannedDictBuilder> for Spanned<Value> {
|
impl From<TaggedDictBuilder> for Tagged<Value> {
|
||||||
fn from(input: SpannedDictBuilder) -> Spanned<Value> {
|
fn from(input: TaggedDictBuilder) -> Tagged<Value> {
|
||||||
input.into_spanned_value()
|
input.into_tagged_value()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::object::{SpannedDictBuilder, Value};
|
use crate::object::{TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -10,15 +10,13 @@ pub enum FileType {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn dir_entry_dict(
|
crate fn dir_entry_dict(
|
||||||
entry: &std::fs::DirEntry,
|
filename: &std::path::Path,
|
||||||
span: impl Into<Span>,
|
metadata: &std::fs::Metadata,
|
||||||
) -> Result<Spanned<Value>, ShellError> {
|
tag: impl Into<Tag>,
|
||||||
let mut dict = SpannedDictBuilder::new(span);
|
) -> Result<Tagged<Value>, ShellError> {
|
||||||
let filename = entry.file_name();
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
dict.insert("name", Value::string(filename.to_string_lossy()));
|
dict.insert("name", Value::string(filename.to_string_lossy()));
|
||||||
|
|
||||||
let metadata = entry.metadata()?;
|
|
||||||
|
|
||||||
let kind = if metadata.is_dir() {
|
let kind = if metadata.is_dir() {
|
||||||
FileType::Directory
|
FileType::Directory
|
||||||
} else if metadata.is_file() {
|
} else if metadata.is_file() {
|
||||||
|
@ -50,5 +48,5 @@ crate fn dir_entry_dict(
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(dict.into_spanned_value())
|
Ok(dict.into_tagged_value())
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,10 @@ impl From<String> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Into<Value>> Spanned<T> {
|
impl<T: Into<Value>> Tagged<T> {
|
||||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
pub fn into_tagged_value(self) -> Tagged<Value> {
|
||||||
let Spanned { item, span } = self;
|
let value_span = self.span();
|
||||||
|
let value = self.item.into();
|
||||||
let value = item.into();
|
value.simple_spanned(value_span)
|
||||||
value.spanned(span)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,43 +6,44 @@ use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(
|
#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters,
|
pub struct Tagged<T> {
|
||||||
)]
|
pub tag: Tag,
|
||||||
#[get = "crate"]
|
|
||||||
pub struct Spanned<T> {
|
|
||||||
pub span: Span,
|
|
||||||
pub item: T,
|
pub item: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HasSpan for Spanned<T> {
|
impl<T> HasSpan for Tagged<T> {
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
self.span
|
self.tag.span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Spanned<T> {
|
pub trait TaggedItem: Sized {
|
||||||
pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> {
|
fn tagged(self, tag: impl Into<Tag>) -> Tagged<Self> {
|
||||||
Spanned::from_item(self.item, span.into())
|
Tagged::from_item(self, tag.into())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub trait SpannedItem: Sized {
|
fn simple_spanned(self, span: impl Into<Span>) -> Tagged<Self> {
|
||||||
fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
|
Tagged::from_simple_spanned_item(self, span.into())
|
||||||
Spanned::from_item(self, span.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now, this is a temporary facility. In many cases, there are other useful spans that we
|
// For now, this is a temporary facility. In many cases, there are other useful spans that we
|
||||||
// could be using, such as the original source spans of JSON or Toml files, but we don't yet
|
// could be using, such as the original source spans of JSON or Toml files, but we don't yet
|
||||||
// have the infrastructure to make that work.
|
// have the infrastructure to make that work.
|
||||||
fn spanned_unknown(self) -> Spanned<Self> {
|
fn tagged_unknown(self) -> Tagged<Self> {
|
||||||
Spanned::from_item(self, (0, 0))
|
Tagged::from_item(
|
||||||
|
self,
|
||||||
|
Tag {
|
||||||
|
span: Span::unknown(),
|
||||||
|
origin: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SpannedItem for T {}
|
impl<T> TaggedItem for T {}
|
||||||
|
|
||||||
impl<T> std::ops::Deref for Spanned<T> {
|
impl<T> std::ops::Deref for Tagged<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &T {
|
fn deref(&self) -> &T {
|
||||||
|
@ -50,58 +51,71 @@ impl<T> std::ops::Deref for Spanned<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Spanned<T> {
|
impl<T> Tagged<T> {
|
||||||
crate fn from_item(item: T, span: impl Into<Span>) -> Spanned<T> {
|
pub fn spanned(self, span: impl Into<Span>) -> Tagged<T> {
|
||||||
Spanned {
|
Tagged::from_item(
|
||||||
span: span.into(),
|
self.item,
|
||||||
|
Tag {
|
||||||
|
span: span.into(),
|
||||||
|
origin: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_item(item: T, tag: impl Into<Tag>) -> Tagged<T> {
|
||||||
|
Tagged {
|
||||||
item,
|
item,
|
||||||
|
tag: tag.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Spanned<U> {
|
pub fn from_simple_spanned_item(item: T, span: impl Into<Span>) -> Tagged<T> {
|
||||||
let Spanned { span, item } = self;
|
Tagged::from_item(
|
||||||
|
item,
|
||||||
let mapped = input(item);
|
Tag {
|
||||||
Spanned { span, item: mapped }
|
span: span.into(),
|
||||||
|
origin: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn copy_span<U>(&self, output: U) -> Spanned<U> {
|
pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Tagged<U> {
|
||||||
let Spanned { span, .. } = self;
|
let tag = self.tag();
|
||||||
|
|
||||||
Spanned {
|
let mapped = input(self.item);
|
||||||
span: *span,
|
Tagged::from_item(mapped, tag.clone())
|
||||||
item: output,
|
}
|
||||||
}
|
|
||||||
|
crate fn copy_span<U>(&self, output: U) -> Tagged<U> {
|
||||||
|
let span = self.span();
|
||||||
|
|
||||||
|
Tagged::from_simple_spanned_item(output, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source(&self, source: &Text) -> Text {
|
pub fn source(&self, source: &Text) -> Text {
|
||||||
Text::from(self.span().slice(source))
|
Text::from(self.span().slice(source))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
pub fn span(&self) -> Span {
|
||||||
pub struct Span {
|
self.tag.span
|
||||||
crate start: usize,
|
}
|
||||||
crate end: usize,
|
|
||||||
pub source: Option<Uuid>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Option<Span>> for Span {
|
pub fn tag(&self) -> Tag {
|
||||||
fn from(input: Option<Span>) -> Span {
|
self.tag
|
||||||
match input {
|
}
|
||||||
None => Span {
|
|
||||||
start: 0,
|
pub fn origin(&self) -> Option<uuid::Uuid> {
|
||||||
end: 0,
|
self.tag.origin
|
||||||
source: None,
|
}
|
||||||
},
|
|
||||||
Some(span) => span,
|
pub fn item(&self) -> &T {
|
||||||
}
|
&self.item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<&Spanned<T>> for Span {
|
impl<T> From<&Tagged<T>> for Span {
|
||||||
fn from(input: &Spanned<T>) -> Span {
|
fn from(input: &Tagged<T>) -> Span {
|
||||||
input.span
|
input.span()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +130,6 @@ impl From<nom5_locate::LocatedSpan<&str>> for Span {
|
||||||
Span {
|
Span {
|
||||||
start: input.offset,
|
start: input.offset,
|
||||||
end: input.offset + input.fragment.len(),
|
end: input.offset + input.fragment.len(),
|
||||||
source: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +139,6 @@ impl<T> From<(nom5_locate::LocatedSpan<T>, nom5_locate::LocatedSpan<T>)> for Spa
|
||||||
Span {
|
Span {
|
||||||
start: input.0.offset,
|
start: input.0.offset,
|
||||||
end: input.1.offset,
|
end: input.1.offset,
|
||||||
source: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +148,6 @@ impl From<(usize, usize)> for Span {
|
||||||
Span {
|
Span {
|
||||||
start: input.0,
|
start: input.0,
|
||||||
end: input.1,
|
end: input.1,
|
||||||
source: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,20 +157,52 @@ impl From<&std::ops::Range<usize>> for Span {
|
||||||
Span {
|
Span {
|
||||||
start: input.start,
|
start: input.start,
|
||||||
end: input.end,
|
end: input.end,
|
||||||
source: None,
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters,
|
||||||
|
)]
|
||||||
|
pub struct Tag {
|
||||||
|
pub origin: Option<Uuid>,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tag {
|
||||||
|
pub fn unknown_origin(span: Span) -> Tag {
|
||||||
|
Tag { origin: None, span }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unknown() -> Tag {
|
||||||
|
Tag {
|
||||||
|
origin: None,
|
||||||
|
span: Span::unknown(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
|
pub struct Span {
|
||||||
|
crate start: usize,
|
||||||
|
crate end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<Span>> for Span {
|
||||||
|
fn from(input: Option<Span>) -> Span {
|
||||||
|
match input {
|
||||||
|
None => Span { start: 0, end: 0 },
|
||||||
|
Some(span) => span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
pub fn unknown() -> Span {
|
pub fn unknown() -> Span {
|
||||||
Span {
|
Span { start: 0, end: 0 }
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
source: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn unknown_with_uuid(uuid: Uuid) -> Span {
|
pub fn unknown_with_uuid(uuid: Uuid) -> Span {
|
||||||
Span {
|
Span {
|
||||||
start: 0,
|
start: 0,
|
||||||
|
@ -167,6 +210,7 @@ impl Span {
|
||||||
source: Some(uuid),
|
source: Some(uuid),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub fn is_unknown(&self) -> bool {
|
pub fn is_unknown(&self) -> bool {
|
||||||
self.start == 0 && self.end == 0
|
self.start == 0 && self.end == 0
|
||||||
|
@ -182,7 +226,6 @@ impl language_reporting::ReportingSpan for Span {
|
||||||
Span {
|
Span {
|
||||||
start,
|
start,
|
||||||
end: self.end,
|
end: self.end,
|
||||||
source: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +233,6 @@ impl language_reporting::ReportingSpan for Span {
|
||||||
Span {
|
Span {
|
||||||
start: self.start,
|
start: self.start,
|
||||||
end,
|
end,
|
||||||
source: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::object::{SpannedDictBuilder, Value};
|
use crate::object::{TaggedDictBuilder, Value};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use itertools::join;
|
use itertools::join;
|
||||||
use sysinfo::ProcessExt;
|
use sysinfo::ProcessExt;
|
||||||
|
|
||||||
crate fn process_dict(proc: &sysinfo::Process, span: impl Into<Span>) -> Spanned<Value> {
|
crate fn process_dict(proc: &sysinfo::Process, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||||
let mut dict = SpannedDictBuilder::new(span);
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
dict.insert("name", Value::string(proc.name()));
|
|
||||||
|
|
||||||
let cmd = proc.cmd();
|
let cmd = proc.cmd();
|
||||||
|
|
||||||
|
@ -15,10 +14,16 @@ crate fn process_dict(proc: &sysinfo::Process, span: impl Into<Span>) -> Spanned
|
||||||
Value::string(join(cmd, ""))
|
Value::string(join(cmd, ""))
|
||||||
};
|
};
|
||||||
|
|
||||||
dict.insert("cmd", cmd_value);
|
|
||||||
dict.insert("cpu", Value::float(proc.cpu_usage() as f64));
|
|
||||||
dict.insert("pid", Value::int(proc.pid() as i64));
|
dict.insert("pid", Value::int(proc.pid() as i64));
|
||||||
dict.insert("status", Value::string(proc.status().to_string()));
|
dict.insert("status", Value::string(proc.status().to_string()));
|
||||||
|
dict.insert("cpu", Value::float(proc.cpu_usage() as f64));
|
||||||
|
//dict.insert("name", Value::string(proc.name()));
|
||||||
|
match cmd_value {
|
||||||
|
Value::Primitive(Primitive::Nothing) => {
|
||||||
|
dict.insert("name", Value::string(proc.name()));
|
||||||
|
}
|
||||||
|
_ => dict.insert("name", cmd_value),
|
||||||
|
}
|
||||||
|
|
||||||
dict.into_spanned_value()
|
dict.into_tagged_value()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,15 @@ use log::trace;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub trait ExtractType: Sized {
|
pub trait ExtractType: Sized {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError>;
|
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError>;
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError>;
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError>;
|
||||||
fn syntax_type() -> hir::SyntaxType {
|
fn syntax_type() -> hir::SyntaxType {
|
||||||
hir::SyntaxType::Any
|
hir::SyntaxType::Any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ExtractType for T {
|
impl<T> ExtractType for T {
|
||||||
default fn extract(_value: &Spanned<Value>) -> Result<T, ShellError> {
|
default fn extract(_value: &Tagged<Value>) -> Result<T, ShellError> {
|
||||||
let name = std::intrinsics::type_name::<T>();
|
let name = std::intrinsics::type_name::<T>();
|
||||||
Err(ShellError::unimplemented(format!(
|
Err(ShellError::unimplemented(format!(
|
||||||
"<T> ExtractType for {}",
|
"<T> ExtractType for {}",
|
||||||
|
@ -21,7 +21,7 @@ impl<T> ExtractType for T {
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
default fn check(_value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
default fn check(_value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
Err(ShellError::unimplemented("ExtractType for T"))
|
Err(ShellError::unimplemented("ExtractType for T"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ impl<T> ExtractType for T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ExtractType> ExtractType for Vec<Spanned<T>> {
|
impl<T: ExtractType> ExtractType for Vec<Tagged<T>> {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError> {
|
||||||
let name = std::intrinsics::type_name::<T>();
|
let name = std::intrinsics::type_name::<T>();
|
||||||
trace!("<Vec> Extracting {:?} for Vec<{}>", value, name);
|
trace!("<Vec> Extracting {:?} for Vec<{}>", value, name);
|
||||||
|
|
||||||
|
@ -40,24 +40,24 @@ impl<T: ExtractType> ExtractType for Vec<Spanned<T>> {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
out.push(T::extract(item)?.spanned(item.span));
|
out.push(T::extract(item)?.tagged(item.tag()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
"Vec",
|
"Vec",
|
||||||
other.type_name().spanned(value.span),
|
other.type_name().tagged(value.tag()),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
match value.item() {
|
match value.item() {
|
||||||
Value::List(_) => Ok(value),
|
Value::List(_) => Ok(value),
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
"Vec",
|
"Vec",
|
||||||
other.type_name().spanned(value.span),
|
other.type_name().tagged(value.tag()),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ impl<T: ExtractType> ExtractType for Vec<Spanned<T>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ExtractType, U: ExtractType> ExtractType for (T, U) {
|
impl<T: ExtractType, U: ExtractType> ExtractType for (T, U) {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<(T, U), ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<(T, U), ShellError> {
|
||||||
let t_name = std::intrinsics::type_name::<T>();
|
let t_name = std::intrinsics::type_name::<T>();
|
||||||
let u_name = std::intrinsics::type_name::<U>();
|
let u_name = std::intrinsics::type_name::<U>();
|
||||||
|
|
||||||
|
@ -84,20 +84,20 @@ impl<T: ExtractType, U: ExtractType> ExtractType for (T, U) {
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::type_error(
|
Err(ShellError::type_error(
|
||||||
"two-element-tuple",
|
"two-element-tuple",
|
||||||
"not-two".spanned(value.span),
|
"not-two".tagged(value.tag()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => Err(ShellError::type_error(
|
other => Err(ShellError::type_error(
|
||||||
"two-element-tuple",
|
"two-element-tuple",
|
||||||
other.type_name().spanned(value.span),
|
other.type_name().tagged(value.tag()),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ExtractType> ExtractType for Option<T> {
|
impl<T: ExtractType> ExtractType for Option<T> {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<Option<T>, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<Option<T>, ShellError> {
|
||||||
let name = std::intrinsics::type_name::<T>();
|
let name = std::intrinsics::type_name::<T>();
|
||||||
trace!("<Option> Extracting {:?} for Option<{}>", value, name);
|
trace!("<Option> Extracting {:?} for Option<{}>", value, name);
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ impl<T: ExtractType> ExtractType for Option<T> {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
match value.item() {
|
match value.item() {
|
||||||
Value::Primitive(Primitive::Nothing) => Ok(value),
|
Value::Primitive(Primitive::Nothing) => Ok(value),
|
||||||
_ => T::check(value),
|
_ => T::check(value),
|
||||||
|
@ -121,15 +121,15 @@ impl<T: ExtractType> ExtractType for Option<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ExtractType> ExtractType for Spanned<T> {
|
impl<T: ExtractType> ExtractType for Tagged<T> {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<Spanned<T>, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<Tagged<T>, ShellError> {
|
||||||
let name = std::intrinsics::type_name::<T>();
|
let name = std::intrinsics::type_name::<T>();
|
||||||
trace!("<Spanned> Extracting {:?} for Spanned<{}>", value, name);
|
trace!("<Tagged> Extracting {:?} for Tagged<{}>", value, name);
|
||||||
|
|
||||||
Ok(T::extract(value)?.spanned(value.span))
|
Ok(T::extract(value)?.tagged(value.tag()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
T::check(value)
|
T::check(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,13 +139,13 @@ impl<T: ExtractType> ExtractType for Spanned<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for Value {
|
impl ExtractType for Value {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<Value, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<Value, ShellError> {
|
||||||
trace!("<Spanned> Extracting {:?} for Value", value);
|
trace!("<Tagged> Extracting {:?} for Value", value);
|
||||||
|
|
||||||
Ok(value.item().clone())
|
Ok(value.item().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,29 +159,29 @@ impl ExtractType for bool {
|
||||||
hir::SyntaxType::Boolean
|
hir::SyntaxType::Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(value: &'a Spanned<Value>) -> Result<bool, ShellError> {
|
fn extract(value: &'a Tagged<Value>) -> Result<bool, ShellError> {
|
||||||
trace!("Extracting {:?} for bool", value);
|
trace!("Extracting {:?} for bool", value);
|
||||||
|
|
||||||
match &value {
|
match &value {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::Boolean(b)),
|
item: Value::Primitive(Primitive::Boolean(b)),
|
||||||
..
|
..
|
||||||
} => Ok(*b),
|
} => Ok(*b),
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::Nothing),
|
item: Value::Primitive(Primitive::Nothing),
|
||||||
..
|
..
|
||||||
} => Ok(false),
|
} => Ok(false),
|
||||||
other => Err(ShellError::type_error("Boolean", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Boolean", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
match &value {
|
match &value {
|
||||||
value @ Spanned {
|
value @ Tagged {
|
||||||
item: Value::Primitive(Primitive::Boolean(_)),
|
item: Value::Primitive(Primitive::Boolean(_)),
|
||||||
..
|
..
|
||||||
} => Ok(value),
|
} => Ok(value),
|
||||||
other => Err(ShellError::type_error("Boolean", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Boolean", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,97 +191,97 @@ impl ExtractType for std::path::PathBuf {
|
||||||
hir::SyntaxType::Path
|
hir::SyntaxType::Path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(value: &'a Spanned<Value>) -> Result<std::path::PathBuf, ShellError> {
|
fn extract(value: &'a Tagged<Value>) -> Result<std::path::PathBuf, ShellError> {
|
||||||
trace!("Extracting {:?} for PathBuf", value);
|
trace!("Extracting {:?} for PathBuf", value);
|
||||||
|
|
||||||
match &value {
|
match &value {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::String(p)),
|
item: Value::Primitive(Primitive::String(p)),
|
||||||
..
|
..
|
||||||
} => Ok(PathBuf::from(p)),
|
} => Ok(PathBuf::from(p)),
|
||||||
other => Err(ShellError::type_error("Path", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Path", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
match &value {
|
match &value {
|
||||||
v @ Spanned {
|
v @ Tagged {
|
||||||
item: Value::Primitive(Primitive::Path(_)),
|
item: Value::Primitive(Primitive::Path(_)),
|
||||||
..
|
..
|
||||||
} => Ok(v),
|
} => Ok(v),
|
||||||
other => Err(ShellError::type_error("Path", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Path", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for i64 {
|
impl ExtractType for i64 {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<i64, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<i64, ShellError> {
|
||||||
trace!("Extracting {:?} for i64", value);
|
trace!("Extracting {:?} for i64", value);
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
&Spanned {
|
&Tagged {
|
||||||
item: Value::Primitive(Primitive::Int(int)),
|
item: Value::Primitive(Primitive::Int(int)),
|
||||||
..
|
..
|
||||||
} => Ok(int),
|
} => Ok(int),
|
||||||
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Integer", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
match value {
|
match value {
|
||||||
v @ Spanned {
|
v @ Tagged {
|
||||||
item: Value::Primitive(Primitive::Int(_)),
|
item: Value::Primitive(Primitive::Int(_)),
|
||||||
..
|
..
|
||||||
} => Ok(v),
|
} => Ok(v),
|
||||||
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Integer", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for String {
|
impl ExtractType for String {
|
||||||
fn extract(value: &Spanned<Value>) -> Result<String, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<String, ShellError> {
|
||||||
trace!("Extracting {:?} for String", value);
|
trace!("Extracting {:?} for String", value);
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::String(string)),
|
item: Value::Primitive(Primitive::String(string)),
|
||||||
..
|
..
|
||||||
} => Ok(string.clone()),
|
} => Ok(string.clone()),
|
||||||
other => Err(ShellError::type_error("String", other.spanned_type_name())),
|
other => Err(ShellError::type_error("String", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
match value {
|
match value {
|
||||||
v @ Spanned {
|
v @ Tagged {
|
||||||
item: Value::Primitive(Primitive::String(_)),
|
item: Value::Primitive(Primitive::String(_)),
|
||||||
..
|
..
|
||||||
} => Ok(v),
|
} => Ok(v),
|
||||||
other => Err(ShellError::type_error("String", other.spanned_type_name())),
|
other => Err(ShellError::type_error("String", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtractType for value::Block {
|
impl ExtractType for value::Block {
|
||||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
|
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||||
trace!("Extracting {:?} for Block", value);
|
trace!("Extracting {:?} for Block", value);
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
v @ Spanned {
|
v @ Tagged {
|
||||||
item: Value::Block(_),
|
item: Value::Block(_),
|
||||||
..
|
..
|
||||||
} => Ok(v),
|
} => Ok(v),
|
||||||
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Block", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(value: &Spanned<Value>) -> Result<value::Block, ShellError> {
|
fn extract(value: &Tagged<Value>) -> Result<value::Block, ShellError> {
|
||||||
match value {
|
match value {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Block(block),
|
item: Value::Block(block),
|
||||||
..
|
..
|
||||||
} => Ok(block.clone()),
|
} => Ok(block.clone()),
|
||||||
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
|
other => Err(ShellError::type_error("Block", other.tagged_type_name())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ crate use parse::flag::Flag;
|
||||||
crate use parse::operator::Operator;
|
crate use parse::operator::Operator;
|
||||||
crate use parse::parser::{nom_input, pipeline};
|
crate use parse::parser::{nom_input, pipeline};
|
||||||
crate use parse::pipeline::{Pipeline, PipelineElement};
|
crate use parse::pipeline::{Pipeline, PipelineElement};
|
||||||
pub use parse::span::{Span, Spanned, SpannedItem};
|
|
||||||
crate use parse::text::Text;
|
crate use parse::text::Text;
|
||||||
crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
|
crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
|
||||||
crate use parse::tokens::{RawToken, Token};
|
crate use parse::tokens::{RawToken, Token};
|
||||||
|
|
|
@ -7,7 +7,7 @@ use serde::{de, forward_to_deserialize_any};
|
||||||
pub struct DeserializerItem<'de> {
|
pub struct DeserializerItem<'de> {
|
||||||
key: String,
|
key: String,
|
||||||
struct_field: &'de str,
|
struct_field: &'de str,
|
||||||
val: Spanned<Value>,
|
val: Tagged<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConfigDeserializer<'de> {
|
pub struct ConfigDeserializer<'de> {
|
||||||
|
@ -28,10 +28,10 @@ impl ConfigDeserializer<'de> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> {
|
pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> {
|
||||||
let value: Option<Spanned<Value>> = if name == "rest" {
|
let value: Option<Tagged<Value>> = if name == "rest" {
|
||||||
let positional = self.args.slice_from(self.position);
|
let positional = self.args.slice_from(self.position);
|
||||||
self.position += positional.len();
|
self.position += positional.len();
|
||||||
Some(Value::List(positional).spanned_unknown()) // TODO: correct span
|
Some(Value::List(positional).tagged_unknown()) // TODO: correct span
|
||||||
} else {
|
} else {
|
||||||
if self.args.has(name) {
|
if self.args.has(name) {
|
||||||
self.args.get(name).map(|x| x.clone())
|
self.args.get(name).map(|x| x.clone())
|
||||||
|
@ -47,7 +47,9 @@ impl ConfigDeserializer<'de> {
|
||||||
self.stack.push(DeserializerItem {
|
self.stack.push(DeserializerItem {
|
||||||
key: name.to_string(),
|
key: name.to_string(),
|
||||||
struct_field: name,
|
struct_field: name,
|
||||||
val: value.unwrap_or_else(|| Value::nothing().spanned(self.args.call_info.name_span)),
|
val: value.unwrap_or_else(|| {
|
||||||
|
Value::nothing().tagged(Tag::unknown_origin(self.args.call_info.name_span))
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -5,7 +5,7 @@ crate mod named;
|
||||||
crate mod path;
|
crate mod path;
|
||||||
|
|
||||||
use crate::evaluate::Scope;
|
use crate::evaluate::Scope;
|
||||||
use crate::parser::{registry, Span, Spanned, Unit};
|
use crate::parser::{registry, Unit};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
|
@ -18,7 +18,7 @@ crate use binary::Binary;
|
||||||
crate use named::NamedArguments;
|
crate use named::NamedArguments;
|
||||||
crate use path::Path;
|
crate use path::Path;
|
||||||
|
|
||||||
pub fn path(head: impl Into<Expression>, tail: Vec<Spanned<impl Into<String>>>) -> Path {
|
pub fn path(head: impl Into<Expression>, tail: Vec<Tagged<impl Into<String>>>) -> Path {
|
||||||
Path::new(
|
Path::new(
|
||||||
head.into(),
|
head.into(),
|
||||||
tail.into_iter()
|
tail.into_iter()
|
||||||
|
@ -111,44 +111,44 @@ impl RawExpression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Expression = Spanned<RawExpression>;
|
pub type Expression = Tagged<RawExpression>;
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
crate fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
|
crate fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
|
||||||
Spanned::from_item(RawExpression::Literal(Literal::Integer(i.into())), span)
|
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Integer(i.into())), span)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
|
crate fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
|
||||||
Spanned::from_item(
|
Tagged::from_simple_spanned_item(
|
||||||
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
|
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
|
||||||
span,
|
span,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn synthetic_string(s: impl Into<String>) -> Expression {
|
crate fn synthetic_string(s: impl Into<String>) -> Expression {
|
||||||
RawExpression::Synthetic(Synthetic::String(s.into())).spanned_unknown()
|
RawExpression::Synthetic(Synthetic::String(s.into())).tagged_unknown()
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
crate fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||||
Spanned::from_item(
|
Tagged::from_simple_spanned_item(
|
||||||
RawExpression::Literal(Literal::String(inner.into())),
|
RawExpression::Literal(Literal::String(inner.into())),
|
||||||
outer.into(),
|
outer.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn bare(span: impl Into<Span>) -> Expression {
|
crate fn bare(span: impl Into<Span>) -> Expression {
|
||||||
Spanned::from_item(RawExpression::Literal(Literal::Bare), span.into())
|
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Bare), span.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
crate fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||||
Spanned::from_item(
|
Tagged::from_simple_spanned_item(
|
||||||
RawExpression::Variable(Variable::Other(inner.into())),
|
RawExpression::Variable(Variable::Other(inner.into())),
|
||||||
outer.into(),
|
outer.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
crate fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||||
Spanned::from_item(
|
Tagged::from_simple_spanned_item(
|
||||||
RawExpression::Variable(Variable::It(inner.into())),
|
RawExpression::Variable(Variable::It(inner.into())),
|
||||||
outer.into(),
|
outer.into(),
|
||||||
)
|
)
|
||||||
|
@ -158,7 +158,7 @@ impl Expression {
|
||||||
impl ToDebug for Expression {
|
impl ToDebug for Expression {
|
||||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||||
match self.item() {
|
match self.item() {
|
||||||
RawExpression::Literal(l) => write!(f, "{}", l.spanned(self.span()).debug(source)),
|
RawExpression::Literal(l) => write!(f, "{:?}", l),
|
||||||
RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{:?}", s),
|
RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{:?}", s),
|
||||||
RawExpression::Variable(Variable::It(_)) => write!(f, "$it"),
|
RawExpression::Variable(Variable::It(_)) => write!(f, "$it"),
|
||||||
RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)),
|
RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)),
|
||||||
|
@ -188,8 +188,8 @@ impl ToDebug for Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Spanned<Path>> for Expression {
|
impl From<Tagged<Path>> for Expression {
|
||||||
fn from(path: Spanned<Path>) -> Expression {
|
fn from(path: Tagged<Path>) -> Expression {
|
||||||
path.map(|p| RawExpression::Path(Box::new(p)))
|
path.map(|p| RawExpression::Path(Box::new(p)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ pub enum Literal {
|
||||||
Bare,
|
Bare,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToDebug for Spanned<&Literal> {
|
impl ToDebug for Tagged<&Literal> {
|
||||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||||
match self.item() {
|
match self.item() {
|
||||||
Literal::Integer(int) => write!(f, "{}", *int),
|
Literal::Integer(int) => write!(f, "{}", *int),
|
||||||
|
|
|
@ -3,26 +3,26 @@ use crate::Text;
|
||||||
|
|
||||||
pub fn baseline_parse_single_token(token: &Token, source: &Text) -> hir::Expression {
|
pub fn baseline_parse_single_token(token: &Token, source: &Text) -> hir::Expression {
|
||||||
match *token.item() {
|
match *token.item() {
|
||||||
RawToken::Integer(int) => hir::Expression::int(int, token.span),
|
RawToken::Integer(int) => hir::Expression::int(int, token.span()),
|
||||||
RawToken::Size(int, unit) => hir::Expression::size(int, unit, token.span),
|
RawToken::Size(int, unit) => hir::Expression::size(int, unit, token.span()),
|
||||||
RawToken::String(span) => hir::Expression::string(span, token.span),
|
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
||||||
RawToken::Variable(span) if span.slice(source) == "it" => {
|
RawToken::Variable(span) if span.slice(source) == "it" => {
|
||||||
hir::Expression::it_variable(span, token.span)
|
hir::Expression::it_variable(span, token.span())
|
||||||
}
|
}
|
||||||
RawToken::Variable(span) => hir::Expression::variable(span, token.span),
|
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
||||||
RawToken::Bare => hir::Expression::bare(token.span),
|
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn baseline_parse_token_as_string(token: &Token, source: &Text) -> hir::Expression {
|
pub fn baseline_parse_token_as_string(token: &Token, source: &Text) -> hir::Expression {
|
||||||
match *token.item() {
|
match *token.item() {
|
||||||
RawToken::Variable(span) if span.slice(source) == "it" => {
|
RawToken::Variable(span) if span.slice(source) == "it" => {
|
||||||
hir::Expression::it_variable(span, token.span)
|
hir::Expression::it_variable(span, token.span())
|
||||||
}
|
}
|
||||||
RawToken::Variable(span) => hir::Expression::variable(span, token.span),
|
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
||||||
RawToken::Integer(_) => hir::Expression::bare(token.span),
|
RawToken::Integer(_) => hir::Expression::bare(token.span()),
|
||||||
RawToken::Size(_, _) => hir::Expression::bare(token.span),
|
RawToken::Size(_, _) => hir::Expression::bare(token.span()),
|
||||||
RawToken::Bare => hir::Expression::bare(token.span),
|
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||||
RawToken::String(span) => hir::Expression::string(span, token.span),
|
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ use crate::parser::registry::CommandRegistry;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
hir,
|
hir,
|
||||||
hir::{baseline_parse_single_token, baseline_parse_token_as_string},
|
hir::{baseline_parse_single_token, baseline_parse_token_as_string},
|
||||||
DelimitedNode, Delimiter, PathNode, RawToken, Span, Spanned, TokenNode,
|
DelimitedNode, Delimiter, PathNode, RawToken, TokenNode,
|
||||||
};
|
};
|
||||||
use crate::{SpannedItem, Text};
|
use crate::{Span, Tag, Tagged, TaggedItem, Text};
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -62,7 +62,7 @@ pub fn baseline_parse_next_expr(
|
||||||
(SyntaxType::Path, token) => {
|
(SyntaxType::Path, token) => {
|
||||||
return Err(ShellError::type_error(
|
return Err(ShellError::type_error(
|
||||||
"Path",
|
"Path",
|
||||||
token.type_name().spanned(token.span()),
|
token.type_name().simple_spanned(token.span()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +82,10 @@ pub fn baseline_parse_next_expr(
|
||||||
|
|
||||||
let second = match tokens.next() {
|
let second = match tokens.next() {
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Expected something after an operator",
|
"Expected something after an operator",
|
||||||
"operator",
|
"operator",
|
||||||
Some(op.span),
|
op.span(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Some(token) => baseline_parse_semantic_token(token, registry, source)?,
|
Some(token) => baseline_parse_semantic_token(token, registry, source)?,
|
||||||
|
@ -95,25 +95,26 @@ pub fn baseline_parse_next_expr(
|
||||||
|
|
||||||
match syntax_type {
|
match syntax_type {
|
||||||
SyntaxType::Any => {
|
SyntaxType::Any => {
|
||||||
let span = (first.span.start, second.span.end);
|
let span = (first.span().start, second.span().end);
|
||||||
let binary = hir::Binary::new(first, op, second);
|
let binary = hir::Binary::new(first, op, second);
|
||||||
let binary = hir::RawExpression::Binary(Box::new(binary));
|
let binary = hir::RawExpression::Binary(Box::new(binary));
|
||||||
let binary = Spanned::from_item(binary, span);
|
let binary = Tagged::from_simple_spanned_item(binary, span);
|
||||||
|
|
||||||
Ok(binary)
|
Ok(binary)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxType::Block => {
|
SyntaxType::Block => {
|
||||||
let span = (first.span.start, second.span.end);
|
let span = (first.span().start, second.span().end);
|
||||||
|
|
||||||
let path: Spanned<hir::RawExpression> = match first {
|
let path: Tagged<hir::RawExpression> = match first {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: hir::RawExpression::Literal(hir::Literal::Bare),
|
item: hir::RawExpression::Literal(hir::Literal::Bare),
|
||||||
span,
|
tag: Tag { span, .. },
|
||||||
} => {
|
} => {
|
||||||
let string = Spanned::from_item(span.slice(source).to_string(), span);
|
let string =
|
||||||
|
Tagged::from_simple_spanned_item(span.slice(source).to_string(), span);
|
||||||
let path = hir::Path::new(
|
let path = hir::Path::new(
|
||||||
Spanned::from_item(
|
Tagged::from_simple_spanned_item(
|
||||||
// TODO: Deal with synthetic nodes that have no representation at all in source
|
// TODO: Deal with synthetic nodes that have no representation at all in source
|
||||||
hir::RawExpression::Variable(hir::Variable::It(Span::from((0, 0)))),
|
hir::RawExpression::Variable(hir::Variable::It(Span::from((0, 0)))),
|
||||||
(0, 0),
|
(0, 0),
|
||||||
|
@ -121,18 +122,16 @@ pub fn baseline_parse_next_expr(
|
||||||
vec![string],
|
vec![string],
|
||||||
);
|
);
|
||||||
let path = hir::RawExpression::Path(Box::new(path));
|
let path = hir::RawExpression::Path(Box::new(path));
|
||||||
Spanned {
|
Tagged::from_simple_spanned_item(path, first.span())
|
||||||
item: path,
|
|
||||||
span: first.span,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Spanned {
|
Tagged {
|
||||||
item: hir::RawExpression::Literal(hir::Literal::String(inner)),
|
item: hir::RawExpression::Literal(hir::Literal::String(inner)),
|
||||||
span,
|
tag: Tag { span, .. },
|
||||||
} => {
|
} => {
|
||||||
let string = Spanned::from_item(inner.slice(source).to_string(), span);
|
let string =
|
||||||
|
Tagged::from_simple_spanned_item(inner.slice(source).to_string(), span);
|
||||||
let path = hir::Path::new(
|
let path = hir::Path::new(
|
||||||
Spanned::from_item(
|
Tagged::from_simple_spanned_item(
|
||||||
// TODO: Deal with synthetic nodes that have no representation at all in source
|
// TODO: Deal with synthetic nodes that have no representation at all in source
|
||||||
hir::RawExpression::Variable(hir::Variable::It(Span::from((0, 0)))),
|
hir::RawExpression::Variable(hir::Variable::It(Span::from((0, 0)))),
|
||||||
(0, 0),
|
(0, 0),
|
||||||
|
@ -140,16 +139,16 @@ pub fn baseline_parse_next_expr(
|
||||||
vec![string],
|
vec![string],
|
||||||
);
|
);
|
||||||
let path = hir::RawExpression::Path(Box::new(path));
|
let path = hir::RawExpression::Path(Box::new(path));
|
||||||
Spanned {
|
Tagged::from_simple_spanned_item(path, first.span())
|
||||||
item: path,
|
|
||||||
span: first.span,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Spanned {
|
Tagged {
|
||||||
item: hir::RawExpression::Variable(..),
|
item: hir::RawExpression::Variable(..),
|
||||||
..
|
..
|
||||||
} => first,
|
} => first,
|
||||||
Spanned { span, item } => {
|
Tagged {
|
||||||
|
tag: Tag { span, .. },
|
||||||
|
item,
|
||||||
|
} => {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"The first part of an un-braced block must be a column name",
|
"The first part of an un-braced block must be a column name",
|
||||||
item.type_name(),
|
item.type_name(),
|
||||||
|
@ -160,10 +159,10 @@ pub fn baseline_parse_next_expr(
|
||||||
|
|
||||||
let binary = hir::Binary::new(path, op, second);
|
let binary = hir::Binary::new(path, op, second);
|
||||||
let binary = hir::RawExpression::Binary(Box::new(binary));
|
let binary = hir::RawExpression::Binary(Box::new(binary));
|
||||||
let binary = Spanned::from_item(binary, span);
|
let binary = Tagged::from_simple_spanned_item(binary, span);
|
||||||
|
|
||||||
let block = hir::RawExpression::Block(vec![binary]);
|
let block = hir::RawExpression::Block(vec![binary]);
|
||||||
let block = Spanned::from_item(block, span);
|
let block = Tagged::from_simple_spanned_item(block, span);
|
||||||
|
|
||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
@ -197,7 +196,7 @@ pub fn baseline_parse_semantic_token(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn baseline_parse_delimited(
|
pub fn baseline_parse_delimited(
|
||||||
token: &Spanned<DelimitedNode>,
|
token: &Tagged<DelimitedNode>,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<hir::Expression, ShellError> {
|
) -> Result<hir::Expression, ShellError> {
|
||||||
|
@ -208,7 +207,7 @@ pub fn baseline_parse_delimited(
|
||||||
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
||||||
|
|
||||||
let expr = hir::RawExpression::Block(exprs);
|
let expr = hir::RawExpression::Block(exprs);
|
||||||
Ok(Spanned::from_item(expr, token.span()))
|
Ok(Tagged::from_simple_spanned_item(expr, token.span()))
|
||||||
}
|
}
|
||||||
Delimiter::Paren => unimplemented!(),
|
Delimiter::Paren => unimplemented!(),
|
||||||
Delimiter::Square => {
|
Delimiter::Square => {
|
||||||
|
@ -217,13 +216,13 @@ pub fn baseline_parse_delimited(
|
||||||
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
||||||
|
|
||||||
let expr = hir::RawExpression::List(exprs);
|
let expr = hir::RawExpression::List(exprs);
|
||||||
Ok(expr.spanned(token.span()))
|
Ok(expr.tagged(Tag::unknown_origin(token.span())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn baseline_parse_path(
|
pub fn baseline_parse_path(
|
||||||
token: &Spanned<PathNode>,
|
token: &Tagged<PathNode>,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<hir::Expression, ShellError> {
|
) -> Result<hir::Expression, ShellError> {
|
||||||
|
@ -239,7 +238,7 @@ pub fn baseline_parse_path(
|
||||||
RawToken::Integer(_) | RawToken::Size(..) | RawToken::Variable(_) => {
|
RawToken::Integer(_) | RawToken::Size(..) | RawToken::Variable(_) => {
|
||||||
return Err(ShellError::type_error(
|
return Err(ShellError::type_error(
|
||||||
"String",
|
"String",
|
||||||
token.type_name().spanned(part),
|
token.type_name().simple_spanned(part),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -251,10 +250,10 @@ pub fn baseline_parse_path(
|
||||||
}
|
}
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
tail.push(string.spanned(part));
|
tail.push(string.simple_spanned(part));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(hir::path(head, tail).spanned(token).into())
|
Ok(hir::path(head, tail).simple_spanned(token).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, new)]
|
#[derive(Debug, new)]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::parser::{hir::Expression, Operator, Spanned};
|
use crate::parser::{hir::Expression, Operator};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::Tagged;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -11,7 +12,7 @@ use std::fmt;
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct Binary {
|
pub struct Binary {
|
||||||
left: Expression,
|
left: Expression,
|
||||||
op: Spanned<Operator>,
|
op: Tagged<Operator>,
|
||||||
right: Expression,
|
right: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::parser::hir::Expression;
|
use crate::parser::hir::Expression;
|
||||||
use crate::parser::{Flag, Span};
|
use crate::parser::Flag;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::Span;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::parser::{hir::Expression, Spanned};
|
use crate::parser::hir::Expression;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::Tagged;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -11,7 +12,7 @@ use std::fmt;
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
head: Expression,
|
head: Expression,
|
||||||
tail: Vec<Spanned<String>>,
|
tail: Vec<Tagged<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToDebug for Path {
|
impl ToDebug for Path {
|
||||||
|
|
|
@ -4,7 +4,6 @@ crate mod flag;
|
||||||
crate mod operator;
|
crate mod operator;
|
||||||
crate mod parser;
|
crate mod parser;
|
||||||
crate mod pipeline;
|
crate mod pipeline;
|
||||||
crate mod span;
|
|
||||||
crate mod text;
|
crate mod text;
|
||||||
crate mod token_tree;
|
crate mod token_tree;
|
||||||
crate mod token_tree_builder;
|
crate mod token_tree_builder;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::parser::parse::span::Span;
|
use crate::Span;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use language_reporting::{FileName, Location};
|
use language_reporting::{FileName, Location};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::parser::Span;
|
use crate::Span;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use crate::parser::parse::{
|
use crate::parser::parse::{
|
||||||
call_node::*, flag::*, operator::*, pipeline::*, span::*, token_tree::*, token_tree_builder::*,
|
call_node::*, flag::*, operator::*, pipeline::*, token_tree::*, token_tree_builder::*,
|
||||||
tokens::*, unit::*,
|
tokens::*, unit::*,
|
||||||
};
|
};
|
||||||
|
use crate::{Span, Tagged};
|
||||||
use nom;
|
use nom;
|
||||||
use nom::branch::*;
|
use nom::branch::*;
|
||||||
use nom::bytes::complete::*;
|
use nom::bytes::complete::*;
|
||||||
|
@ -67,7 +68,7 @@ fn trace_step<'a, T: Debug>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_integer(input: NomSpan) -> IResult<NomSpan, Spanned<i64>> {
|
pub fn raw_integer(input: NomSpan) -> IResult<NomSpan, Tagged<i64>> {
|
||||||
let start = input.offset;
|
let start = input.offset;
|
||||||
trace_step(input, "raw_integer", move |input| {
|
trace_step(input, "raw_integer", move |input| {
|
||||||
let (input, neg) = opt(tag("-"))(input)?;
|
let (input, neg) = opt(tag("-"))(input)?;
|
||||||
|
@ -76,7 +77,7 @@ pub fn raw_integer(input: NomSpan) -> IResult<NomSpan, Spanned<i64>> {
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
Spanned::from_item(int(num.fragment, neg), (start, end)),
|
Tagged::from_simple_spanned_item(int(num.fragment, neg), (start, end)),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -85,7 +86,7 @@ pub fn integer(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
trace_step(input, "integer", move |input| {
|
trace_step(input, "integer", move |input| {
|
||||||
let (input, int) = raw_integer(input)?;
|
let (input, int) = raw_integer(input)?;
|
||||||
|
|
||||||
Ok((input, TokenTreeBuilder::spanned_int(*int, int.span)))
|
Ok((input, TokenTreeBuilder::spanned_int(*int, int.span())))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -202,7 +203,7 @@ pub fn shorthand(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_unit(input: NomSpan) -> IResult<NomSpan, Spanned<Unit>> {
|
pub fn raw_unit(input: NomSpan) -> IResult<NomSpan, Tagged<Unit>> {
|
||||||
trace_step(input, "raw_unit", move |input| {
|
trace_step(input, "raw_unit", move |input| {
|
||||||
let start = input.offset;
|
let start = input.offset;
|
||||||
let (input, unit) = alt((
|
let (input, unit) = alt((
|
||||||
|
@ -230,7 +231,7 @@ pub fn raw_unit(input: NomSpan) -> IResult<NomSpan, Spanned<Unit>> {
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
Spanned::from_item(Unit::from(unit.fragment), (start, end)),
|
Tagged::from_simple_spanned_item(Unit::from(unit.fragment), (start, end)),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -408,7 +409,7 @@ pub fn delimited_brace(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw_call(input: NomSpan) -> IResult<NomSpan, Spanned<CallNode>> {
|
pub fn raw_call(input: NomSpan) -> IResult<NomSpan, Tagged<CallNode>> {
|
||||||
trace_step(input, "raw_call", move |input| {
|
trace_step(input, "raw_call", move |input| {
|
||||||
let left = input.offset;
|
let left = input.offset;
|
||||||
let (input, items) = token_list(input)?;
|
let (input, items) = token_list(input)?;
|
||||||
|
@ -484,10 +485,10 @@ pub fn pipeline(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_call_list(
|
fn make_call_list(
|
||||||
head: Option<(Spanned<CallNode>, Option<NomSpan>, Option<NomSpan>)>,
|
head: Option<(Tagged<CallNode>, Option<NomSpan>, Option<NomSpan>)>,
|
||||||
items: Vec<(
|
items: Vec<(
|
||||||
Option<NomSpan>,
|
Option<NomSpan>,
|
||||||
Spanned<CallNode>,
|
Tagged<CallNode>,
|
||||||
Option<NomSpan>,
|
Option<NomSpan>,
|
||||||
Option<NomSpan>,
|
Option<NomSpan>,
|
||||||
)>,
|
)>,
|
||||||
|
@ -531,6 +532,8 @@ fn is_start_bare_char(c: char) -> bool {
|
||||||
'_' => true,
|
'_' => true,
|
||||||
'-' => true,
|
'-' => true,
|
||||||
'@' => true,
|
'@' => true,
|
||||||
|
'*' => true,
|
||||||
|
'?' => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -545,6 +548,8 @@ fn is_bare_char(c: char) -> bool {
|
||||||
'_' => true,
|
'_' => true,
|
||||||
'-' => true,
|
'-' => true,
|
||||||
'@' => true,
|
'@' => true,
|
||||||
|
'*' => true,
|
||||||
|
'?' => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -701,12 +706,12 @@ mod tests {
|
||||||
fn test_flag() {
|
fn test_flag() {
|
||||||
// assert_leaf! {
|
// assert_leaf! {
|
||||||
// parsers [ flag ]
|
// parsers [ flag ]
|
||||||
// "--hello" -> 0..7 { Flag(Spanned::from_item(FlagKind::Longhand, span(2, 7))) }
|
// "--hello" -> 0..7 { Flag(Tagged::from_item(FlagKind::Longhand, span(2, 7))) }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// assert_leaf! {
|
// assert_leaf! {
|
||||||
// parsers [ flag ]
|
// parsers [ flag ]
|
||||||
// "--hello-world" -> 0..13 { Flag(Spanned::from_item(FlagKind::Longhand, span(2, 13))) }
|
// "--hello-world" -> 0..13 { Flag(Tagged::from_item(FlagKind::Longhand, span(2, 13))) }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,7 +719,7 @@ mod tests {
|
||||||
fn test_shorthand() {
|
fn test_shorthand() {
|
||||||
// assert_leaf! {
|
// assert_leaf! {
|
||||||
// parsers [ shorthand ]
|
// parsers [ shorthand ]
|
||||||
// "-alt" -> 0..4 { Flag(Spanned::from_item(FlagKind::Shorthand, span(1, 4))) }
|
// "-alt" -> 0..4 { Flag(Tagged::from_item(FlagKind::Shorthand, span(1, 4))) }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,7 +1029,7 @@ mod tests {
|
||||||
right: usize,
|
right: usize,
|
||||||
) -> TokenNode {
|
) -> TokenNode {
|
||||||
let node = DelimitedNode::new(delimiter, children);
|
let node = DelimitedNode::new(delimiter, children);
|
||||||
let spanned = Spanned::from_item(node, (left, right));
|
let spanned = Tagged::from_simple_spanned_item(node, (left, right));
|
||||||
TokenNode::Delimited(spanned)
|
TokenNode::Delimited(spanned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1033,16 +1038,16 @@ mod tests {
|
||||||
Box::new(head),
|
Box::new(head),
|
||||||
tail.into_iter().map(TokenNode::Token).collect(),
|
tail.into_iter().map(TokenNode::Token).collect(),
|
||||||
);
|
);
|
||||||
let spanned = Spanned::from_item(node, (left, right));
|
let spanned = Tagged::from_simple_spanned_item(node, (left, right));
|
||||||
TokenNode::Path(spanned)
|
TokenNode::Path(spanned)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leaf_token(token: RawToken, left: usize, right: usize) -> TokenNode {
|
fn leaf_token(token: RawToken, left: usize, right: usize) -> TokenNode {
|
||||||
TokenNode::Token(Spanned::from_item(token, (left, right)))
|
TokenNode::Token(Tagged::from_simple_spanned_item(token, (left, right)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token(token: RawToken, left: usize, right: usize) -> TokenNode {
|
fn token(token: RawToken, left: usize, right: usize) -> TokenNode {
|
||||||
TokenNode::Token(Spanned::from_item(token, (left, right)))
|
TokenNode::Token(Tagged::from_simple_spanned_item(token, (left, right)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build<T>(block: CurriedNode<T>) -> T {
|
fn build<T>(block: CurriedNode<T>) -> T {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::parser::{CallNode, Span, Spanned};
|
use crate::parser::CallNode;
|
||||||
|
use crate::{Span, Tagged};
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
|
|
||||||
|
@ -12,7 +13,7 @@ pub struct Pipeline {
|
||||||
pub struct PipelineElement {
|
pub struct PipelineElement {
|
||||||
pub pre_ws: Option<Span>,
|
pub pre_ws: Option<Span>,
|
||||||
#[get = "crate"]
|
#[get = "crate"]
|
||||||
call: Spanned<CallNode>,
|
call: Tagged<CallNode>,
|
||||||
pub post_ws: Option<Span>,
|
pub post_ws: Option<Span>,
|
||||||
pub post_pipe: Option<Span>,
|
pub post_pipe: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use crate::parser::parse::{call_node::*, flag::*, operator::*, pipeline::*, span::*, tokens::*};
|
use crate::parser::parse::{call_node::*, flag::*, operator::*, pipeline::*, tokens::*};
|
||||||
use crate::Text;
|
use crate::{Span, Tagged, Text};
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use enum_utils::FromStr;
|
use enum_utils::FromStr;
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
|
@ -10,16 +10,16 @@ use std::fmt;
|
||||||
pub enum TokenNode {
|
pub enum TokenNode {
|
||||||
Token(Token),
|
Token(Token),
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Call(Spanned<CallNode>),
|
Call(Tagged<CallNode>),
|
||||||
Delimited(Spanned<DelimitedNode>),
|
Delimited(Tagged<DelimitedNode>),
|
||||||
Pipeline(Spanned<Pipeline>),
|
Pipeline(Tagged<Pipeline>),
|
||||||
Operator(Spanned<Operator>),
|
Operator(Tagged<Operator>),
|
||||||
Flag(Spanned<Flag>),
|
Flag(Tagged<Flag>),
|
||||||
Member(Span),
|
Member(Span),
|
||||||
Whitespace(Span),
|
Whitespace(Span),
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
Error(Spanned<Box<ShellError>>),
|
Error(Tagged<Box<ShellError>>),
|
||||||
Path(Spanned<PathNode>),
|
Path(Tagged<PathNode>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DebugTokenNode<'a> {
|
pub struct DebugTokenNode<'a> {
|
||||||
|
@ -86,16 +86,16 @@ impl From<&TokenNode> for Span {
|
||||||
impl TokenNode {
|
impl TokenNode {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
TokenNode::Token(t) => t.span,
|
TokenNode::Token(t) => t.span(),
|
||||||
TokenNode::Call(s) => s.span,
|
TokenNode::Call(s) => s.span(),
|
||||||
TokenNode::Delimited(s) => s.span,
|
TokenNode::Delimited(s) => s.span(),
|
||||||
TokenNode::Pipeline(s) => s.span,
|
TokenNode::Pipeline(s) => s.span(),
|
||||||
TokenNode::Operator(s) => s.span,
|
TokenNode::Operator(s) => s.span(),
|
||||||
TokenNode::Flag(s) => s.span,
|
TokenNode::Flag(s) => s.span(),
|
||||||
TokenNode::Member(s) => *s,
|
TokenNode::Member(s) => *s,
|
||||||
TokenNode::Whitespace(s) => *s,
|
TokenNode::Whitespace(s) => *s,
|
||||||
TokenNode::Error(s) => s.span,
|
TokenNode::Error(s) => s.span(),
|
||||||
TokenNode::Path(s) => s.span,
|
TokenNode::Path(s) => s.span(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ impl TokenNode {
|
||||||
|
|
||||||
pub fn is_bare(&self) -> bool {
|
pub fn is_bare(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::Bare,
|
item: RawToken::Bare,
|
||||||
..
|
..
|
||||||
}) => true,
|
}) => true,
|
||||||
|
@ -137,10 +137,10 @@ impl TokenNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn as_flag(&self, value: &str, source: &Text) -> Option<Spanned<Flag>> {
|
crate fn as_flag(&self, value: &str, source: &Text) -> Option<Tagged<Flag>> {
|
||||||
match self {
|
match self {
|
||||||
TokenNode::Flag(
|
TokenNode::Flag(
|
||||||
flag @ Spanned {
|
flag @ Tagged {
|
||||||
item: Flag { .. }, ..
|
item: Flag { .. }, ..
|
||||||
},
|
},
|
||||||
) if value == flag.name().slice(source) => Some(*flag),
|
) if value == flag.name().slice(source) => Some(*flag),
|
||||||
|
@ -150,7 +150,7 @@ impl TokenNode {
|
||||||
|
|
||||||
pub fn as_pipeline(&self) -> Result<Pipeline, ShellError> {
|
pub fn as_pipeline(&self) -> Result<Pipeline, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
TokenNode::Pipeline(Spanned { item, .. }) => Ok(item.clone()),
|
TokenNode::Pipeline(Tagged { item, .. }) => Ok(item.clone()),
|
||||||
_ => Err(ShellError::string("unimplemented")),
|
_ => Err(ShellError::string("unimplemented")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ use crate::prelude::*;
|
||||||
use crate::parser::parse::flag::{Flag, FlagKind};
|
use crate::parser::parse::flag::{Flag, FlagKind};
|
||||||
use crate::parser::parse::operator::Operator;
|
use crate::parser::parse::operator::Operator;
|
||||||
use crate::parser::parse::pipeline::{Pipeline, PipelineElement};
|
use crate::parser::parse::pipeline::{Pipeline, PipelineElement};
|
||||||
use crate::parser::parse::span::{Span, Spanned};
|
|
||||||
use crate::parser::parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
|
use crate::parser::parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
|
||||||
use crate::parser::parse::tokens::{RawToken, Token};
|
use crate::parser::parse::tokens::{RawToken, Token};
|
||||||
use crate::parser::parse::unit::Unit;
|
use crate::parser::parse::unit::Unit;
|
||||||
use crate::parser::CallNode;
|
use crate::parser::CallNode;
|
||||||
|
use crate::Span;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
|
@ -20,7 +20,7 @@ pub struct TokenTreeBuilder {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub type CurriedNode<T> = Box<dyn FnOnce(&mut TokenTreeBuilder) -> T + 'static>;
|
pub type CurriedNode<T> = Box<dyn FnOnce(&mut TokenTreeBuilder) -> T + 'static>;
|
||||||
pub type CurriedToken = Box<dyn FnOnce(&mut TokenTreeBuilder) -> TokenNode + 'static>;
|
pub type CurriedToken = Box<dyn FnOnce(&mut TokenTreeBuilder) -> TokenNode + 'static>;
|
||||||
pub type CurriedCall = Box<dyn FnOnce(&mut TokenTreeBuilder) -> Spanned<CallNode> + 'static>;
|
pub type CurriedCall = Box<dyn FnOnce(&mut TokenTreeBuilder) -> Tagged<CallNode> + 'static>;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
impl TokenTreeBuilder {
|
impl TokenTreeBuilder {
|
||||||
|
@ -92,7 +92,7 @@ impl TokenTreeBuilder {
|
||||||
input: (Vec<PipelineElement>, Option<Span>),
|
input: (Vec<PipelineElement>, Option<Span>),
|
||||||
span: impl Into<Span>,
|
span: impl Into<Span>,
|
||||||
) -> TokenNode {
|
) -> TokenNode {
|
||||||
TokenNode::Pipeline(Spanned::from_item(
|
TokenNode::Pipeline(Tagged::from_simple_spanned_item(
|
||||||
Pipeline::new(input.0, input.1.into()),
|
Pipeline::new(input.0, input.1.into()),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
|
@ -111,7 +111,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_op(input: impl Into<Operator>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_op(input: impl Into<Operator>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Operator(Spanned::from_item(input.into(), span.into()))
|
TokenNode::Operator(Tagged::from_simple_spanned_item(input.into(), span.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string(input: impl Into<String>) -> CurriedToken {
|
pub fn string(input: impl Into<String>) -> CurriedToken {
|
||||||
|
@ -128,7 +128,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_string(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_string(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Token(Spanned::from_item(
|
TokenNode::Token(Tagged::from_simple_spanned_item(
|
||||||
RawToken::String(input.into()),
|
RawToken::String(input.into()),
|
||||||
span.into(),
|
span.into(),
|
||||||
))
|
))
|
||||||
|
@ -146,7 +146,10 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_bare(input: impl Into<Span>) -> TokenNode {
|
pub fn spanned_bare(input: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Token(Spanned::from_item(RawToken::Bare, input.into()))
|
TokenNode::Token(Tagged::from_simple_spanned_item(
|
||||||
|
RawToken::Bare,
|
||||||
|
input.into(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn int(input: impl Into<i64>) -> CurriedToken {
|
pub fn int(input: impl Into<i64>) -> CurriedToken {
|
||||||
|
@ -161,7 +164,10 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_int(input: impl Into<i64>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_int(input: impl Into<i64>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Token(Token::from_item(RawToken::Integer(input.into()), span))
|
TokenNode::Token(Token::from_simple_spanned_item(
|
||||||
|
RawToken::Integer(input.into()),
|
||||||
|
span,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(int: impl Into<i64>, unit: impl Into<Unit>) -> CurriedToken {
|
pub fn size(int: impl Into<i64>, unit: impl Into<Unit>) -> CurriedToken {
|
||||||
|
@ -183,7 +189,10 @@ impl TokenTreeBuilder {
|
||||||
) -> TokenNode {
|
) -> TokenNode {
|
||||||
let (int, unit) = (input.0.into(), input.1.into());
|
let (int, unit) = (input.0.into(), input.1.into());
|
||||||
|
|
||||||
TokenNode::Token(Spanned::from_item(RawToken::Size(int, unit), span))
|
TokenNode::Token(Tagged::from_simple_spanned_item(
|
||||||
|
RawToken::Size(int, unit),
|
||||||
|
span,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(head: CurriedToken, tail: Vec<CurriedToken>) -> CurriedToken {
|
pub fn path(head: CurriedToken, tail: Vec<CurriedToken>) -> CurriedToken {
|
||||||
|
@ -206,7 +215,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_path(input: (TokenNode, Vec<TokenNode>), span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_path(input: (TokenNode, Vec<TokenNode>), span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Path(Spanned::from_item(
|
TokenNode::Path(Tagged::from_simple_spanned_item(
|
||||||
PathNode::new(Box::new(input.0), input.1),
|
PathNode::new(Box::new(input.0), input.1),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
|
@ -224,7 +233,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_var(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_var(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Token(Spanned::from_item(
|
TokenNode::Token(Tagged::from_simple_spanned_item(
|
||||||
RawToken::Variable(input.into()),
|
RawToken::Variable(input.into()),
|
||||||
span.into(),
|
span.into(),
|
||||||
))
|
))
|
||||||
|
@ -242,7 +251,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_flag(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_flag(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Flag(Spanned::from_item(
|
TokenNode::Flag(Tagged::from_simple_spanned_item(
|
||||||
Flag::new(FlagKind::Longhand, input.into()),
|
Flag::new(FlagKind::Longhand, input.into()),
|
||||||
span.into(),
|
span.into(),
|
||||||
))
|
))
|
||||||
|
@ -260,7 +269,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_shorthand(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_shorthand(input: impl Into<Span>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Flag(Spanned::from_item(
|
TokenNode::Flag(Tagged::from_simple_spanned_item(
|
||||||
Flag::new(FlagKind::Shorthand, input.into()),
|
Flag::new(FlagKind::Shorthand, input.into()),
|
||||||
span.into(),
|
span.into(),
|
||||||
))
|
))
|
||||||
|
@ -296,7 +305,7 @@ impl TokenTreeBuilder {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_call(input: Vec<TokenNode>, span: impl Into<Span>) -> Spanned<CallNode> {
|
pub fn spanned_call(input: Vec<TokenNode>, span: impl Into<Span>) -> Tagged<CallNode> {
|
||||||
if input.len() == 0 {
|
if input.len() == 0 {
|
||||||
panic!("BUG: spanned call (TODO)")
|
panic!("BUG: spanned call (TODO)")
|
||||||
}
|
}
|
||||||
|
@ -306,7 +315,7 @@ impl TokenTreeBuilder {
|
||||||
let head = input.next().unwrap();
|
let head = input.next().unwrap();
|
||||||
let tail = input.collect();
|
let tail = input.collect();
|
||||||
|
|
||||||
Spanned::from_item(CallNode::new(Box::new(head), tail), span)
|
Tagged::from_simple_spanned_item(CallNode::new(Box::new(head), tail), span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parens(input: Vec<CurriedToken>) -> CurriedToken {
|
pub fn parens(input: Vec<CurriedToken>) -> CurriedToken {
|
||||||
|
@ -324,7 +333,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_parens(input: impl Into<Vec<TokenNode>>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_parens(input: impl Into<Vec<TokenNode>>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Delimited(Spanned::from_item(
|
TokenNode::Delimited(Tagged::from_simple_spanned_item(
|
||||||
DelimitedNode::new(Delimiter::Paren, input.into()),
|
DelimitedNode::new(Delimiter::Paren, input.into()),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
|
@ -345,7 +354,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_square(input: impl Into<Vec<TokenNode>>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_square(input: impl Into<Vec<TokenNode>>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Delimited(Spanned::from_item(
|
TokenNode::Delimited(Tagged::from_simple_spanned_item(
|
||||||
DelimitedNode::new(Delimiter::Square, input.into()),
|
DelimitedNode::new(Delimiter::Square, input.into()),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
|
@ -366,7 +375,7 @@ impl TokenTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spanned_brace(input: impl Into<Vec<TokenNode>>, span: impl Into<Span>) -> TokenNode {
|
pub fn spanned_brace(input: impl Into<Vec<TokenNode>>, span: impl Into<Span>) -> TokenNode {
|
||||||
TokenNode::Delimited(Spanned::from_item(
|
TokenNode::Delimited(Tagged::from_simple_spanned_item(
|
||||||
DelimitedNode::new(Delimiter::Brace, input.into()),
|
DelimitedNode::new(Delimiter::Brace, input.into()),
|
||||||
span,
|
span,
|
||||||
))
|
))
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::parser::parse::span::*;
|
|
||||||
use crate::parser::parse::unit::*;
|
use crate::parser::parse::unit::*;
|
||||||
use crate::Text;
|
use crate::{Span, Tagged, Text};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
@ -24,7 +23,7 @@ impl RawToken {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Token = Spanned<RawToken>;
|
pub type Token = Tagged<RawToken>;
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
pub fn debug(&self, source: &'a Text) -> DebugToken<'a> {
|
pub fn debug(&self, source: &'a Text) -> DebugToken<'a> {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
use crate::errors::{ArgumentError, ShellError};
|
use crate::errors::{ArgumentError, ShellError};
|
||||||
use crate::parser::registry::{Signature, CommandRegistry, NamedType, PositionalType};
|
use crate::parser::registry::{CommandRegistry, NamedType, PositionalType, Signature};
|
||||||
use crate::parser::{baseline_parse_tokens, CallNode, Span, Spanned};
|
use crate::parser::{baseline_parse_tokens, CallNode};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
hir::{self, NamedArguments},
|
hir::{self, NamedArguments},
|
||||||
Flag, RawToken, TokenNode,
|
Flag, RawToken, TokenNode,
|
||||||
};
|
};
|
||||||
use crate::Text;
|
use crate::{Span, Tag, Tagged, Text};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
pub fn parse_command(
|
pub fn parse_command(
|
||||||
config: &Signature,
|
config: &Signature,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
call: &Spanned<CallNode>,
|
call: &Tagged<CallNode>,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<hir::Call, ShellError> {
|
) -> Result<hir::Call, ShellError> {
|
||||||
let Spanned { item: raw_call, .. } = call;
|
let Tagged { item: raw_call, .. } = call;
|
||||||
|
|
||||||
trace!("Processing {:?}", config);
|
trace!("Processing {:?}", config);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ pub fn parse_command(
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|
||||||
match parse_command_tail(&config, registry, children, source, call.span)? {
|
match parse_command_tail(&config, registry, children, source, call.span())? {
|
||||||
None => Ok(hir::Call::new(Box::new(head), None, None)),
|
None => Ok(hir::Call::new(Box::new(head), None, None)),
|
||||||
Some((positional, named)) => Ok(hir::Call::new(Box::new(head), positional, named)),
|
Some((positional, named)) => Ok(hir::Call::new(Box::new(head), positional, named)),
|
||||||
}
|
}
|
||||||
|
@ -40,16 +40,16 @@ pub fn parse_command(
|
||||||
fn parse_command_head(head: &TokenNode) -> Result<hir::Expression, ShellError> {
|
fn parse_command_head(head: &TokenNode) -> Result<hir::Expression, ShellError> {
|
||||||
match head {
|
match head {
|
||||||
TokenNode::Token(
|
TokenNode::Token(
|
||||||
spanned @ Spanned {
|
spanned @ Tagged {
|
||||||
item: RawToken::Bare,
|
item: RawToken::Bare,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
) => Ok(spanned.map(|_| hir::RawExpression::Literal(hir::Literal::Bare))),
|
) => Ok(spanned.map(|_| hir::RawExpression::Literal(hir::Literal::Bare))),
|
||||||
|
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::String(inner_span),
|
item: RawToken::String(inner_span),
|
||||||
span,
|
tag: Tag { span, origin: None },
|
||||||
}) => Ok(Spanned::from_item(
|
}) => Ok(Tagged::from_simple_spanned_item(
|
||||||
hir::RawExpression::Literal(hir::Literal::String(*inner_span)),
|
hir::RawExpression::Literal(hir::Literal::String(*inner_span)),
|
||||||
*span,
|
*span,
|
||||||
)),
|
)),
|
||||||
|
@ -96,7 +96,7 @@ fn parse_command_tail(
|
||||||
return Err(ShellError::argument_error(
|
return Err(ShellError::argument_error(
|
||||||
config.name.clone(),
|
config.name.clone(),
|
||||||
ArgumentError::MissingValueForName(name.to_string()),
|
ArgumentError::MissingValueForName(name.to_string()),
|
||||||
flag.span,
|
flag.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ fn parse_command_tail(
|
||||||
return Err(ShellError::argument_error(
|
return Err(ShellError::argument_error(
|
||||||
config.name.clone(),
|
config.name.clone(),
|
||||||
ArgumentError::MissingValueForName(name.to_string()),
|
ArgumentError::MissingValueForName(name.to_string()),
|
||||||
flag.span,
|
flag.span(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ fn extract_mandatory(
|
||||||
tokens: &mut hir::TokensIterator<'a>,
|
tokens: &mut hir::TokensIterator<'a>,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Result<(usize, Spanned<Flag>), ShellError> {
|
) -> Result<(usize, Tagged<Flag>), ShellError> {
|
||||||
let flag = tokens.extract(|t| t.as_flag(name, source));
|
let flag = tokens.extract(|t| t.as_flag(name, source));
|
||||||
|
|
||||||
match flag {
|
match flag {
|
||||||
|
@ -223,7 +223,7 @@ fn extract_optional(
|
||||||
name: &str,
|
name: &str,
|
||||||
tokens: &mut hir::TokensIterator<'a>,
|
tokens: &mut hir::TokensIterator<'a>,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<(Option<(usize, Spanned<Flag>)>), ShellError> {
|
) -> Result<(Option<(usize, Tagged<Flag>)>), ShellError> {
|
||||||
let flag = tokens.extract(|t| t.as_flag(name, source));
|
let flag = tokens.extract(|t| t.as_flag(name, source));
|
||||||
|
|
||||||
match flag {
|
match flag {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// TODO: Temporary redirect
|
// TODO: Temporary redirect
|
||||||
crate use crate::context::CommandRegistry;
|
crate use crate::context::CommandRegistry;
|
||||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||||
use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode, Spanned};
|
use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
@ -136,15 +136,15 @@ impl Signature {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, new, Serialize, Deserialize)]
|
#[derive(Debug, Default, new, Serialize, Deserialize, Clone)]
|
||||||
pub struct EvaluatedArgs {
|
pub struct EvaluatedArgs {
|
||||||
pub positional: Option<Vec<Spanned<Value>>>,
|
pub positional: Option<Vec<Tagged<Value>>>,
|
||||||
pub named: Option<IndexMap<String, Spanned<Value>>>,
|
pub named: Option<IndexMap<String, Tagged<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct DebugEvaluatedPositional<'a> {
|
pub struct DebugEvaluatedPositional<'a> {
|
||||||
positional: &'a Option<Vec<Spanned<Value>>>,
|
positional: &'a Option<Vec<Tagged<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
||||||
|
@ -161,7 +161,7 @@ impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct DebugEvaluatedNamed<'a> {
|
pub struct DebugEvaluatedNamed<'a> {
|
||||||
named: &'a Option<IndexMap<String, Spanned<Value>>>,
|
named: &'a Option<IndexMap<String, Tagged<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for DebugEvaluatedNamed<'a> {
|
impl fmt::Debug for DebugEvaluatedNamed<'a> {
|
||||||
|
@ -199,14 +199,14 @@ impl EvaluatedArgs {
|
||||||
DebugEvaluatedArgs { args: self }
|
DebugEvaluatedArgs { args: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
|
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
||||||
match &self.positional {
|
match &self.positional {
|
||||||
None => None,
|
None => None,
|
||||||
Some(array) => array.iter().nth(pos),
|
Some(array) => array.iter().nth(pos),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_nth(&self, pos: usize) -> Result<&Spanned<Value>, ShellError> {
|
pub fn expect_nth(&self, pos: usize) -> Result<&Tagged<Value>, ShellError> {
|
||||||
match &self.positional {
|
match &self.positional {
|
||||||
None => Err(ShellError::unimplemented("Better error: expect_nth")),
|
None => Err(ShellError::unimplemented("Better error: expect_nth")),
|
||||||
Some(array) => match array.iter().nth(pos) {
|
Some(array) => match array.iter().nth(pos) {
|
||||||
|
@ -230,7 +230,7 @@ impl EvaluatedArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, name: &str) -> Option<&Spanned<Value>> {
|
pub fn get(&self, name: &str) -> Option<&Tagged<Value>> {
|
||||||
match &self.named {
|
match &self.named {
|
||||||
None => None,
|
None => None,
|
||||||
Some(named) => named.get(name),
|
Some(named) => named.get(name),
|
||||||
|
@ -250,11 +250,11 @@ impl EvaluatedArgs {
|
||||||
|
|
||||||
pub enum PositionalIter<'a> {
|
pub enum PositionalIter<'a> {
|
||||||
Empty,
|
Empty,
|
||||||
Array(std::slice::Iter<'a, Spanned<Value>>),
|
Array(std::slice::Iter<'a, Tagged<Value>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for PositionalIter<'a> {
|
impl Iterator for PositionalIter<'a> {
|
||||||
type Item = &'a Spanned<Value>;
|
type Item = &'a Tagged<Value>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -267,7 +267,7 @@ impl Iterator for PositionalIter<'a> {
|
||||||
impl Signature {
|
impl Signature {
|
||||||
crate fn parse_args(
|
crate fn parse_args(
|
||||||
&self,
|
&self,
|
||||||
call: &Spanned<CallNode>,
|
call: &Tagged<CallNode>,
|
||||||
registry: &CommandRegistry,
|
registry: &CommandRegistry,
|
||||||
source: &Text,
|
source: &Text,
|
||||||
) -> Result<hir::Call, ShellError> {
|
) -> Result<hir::Call, ShellError> {
|
||||||
|
@ -302,7 +302,7 @@ crate fn evaluate_args(
|
||||||
|
|
||||||
let positional = positional?;
|
let positional = positional?;
|
||||||
|
|
||||||
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = call
|
let named: Result<Option<IndexMap<String, Tagged<Value>>>, ShellError> = call
|
||||||
.named()
|
.named()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|n| {
|
.map(|n| {
|
||||||
|
@ -313,7 +313,7 @@ crate fn evaluate_args(
|
||||||
hir::named::NamedValue::PresentSwitch(span) => {
|
hir::named::NamedValue::PresentSwitch(span) => {
|
||||||
results.insert(
|
results.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
Spanned::from_item(Value::boolean(true), *span),
|
Tagged::from_simple_spanned_item(Value::boolean(true), *span),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hir::named::NamedValue::Value(expr) => {
|
hir::named::NamedValue::Value(expr) => {
|
||||||
|
|
|
@ -1,25 +1,28 @@
|
||||||
use crate::{CallInfo, Signature, ReturnValue, ShellError, Spanned, Value};
|
use crate::Signature;
|
||||||
|
use crate::Tagged;
|
||||||
|
use crate::{CallInfo, ReturnValue, ShellError, Value};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
pub trait Plugin {
|
pub trait Plugin {
|
||||||
fn config(&mut self) -> Result<Signature, ShellError>;
|
fn config(&mut self) -> Result<Signature, ShellError>;
|
||||||
#[allow(unused)]
|
|
||||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
|
||||||
Err(ShellError::string(
|
|
||||||
"`begin_filter` not implemented in plugin",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
|
||||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
|
||||||
Err(ShellError::string("`filter` not implemented in plugin"))
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
|
||||||
fn sink(&mut self, call_info: CallInfo, input: Vec<Spanned<Value>>) {}
|
|
||||||
|
|
||||||
fn quit(&mut self) {
|
#[allow(unused)]
|
||||||
return;
|
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
#[allow(unused)]
|
||||||
|
fn sink(&mut self, call_info: CallInfo, input: Vec<Tagged<Value>>) {}
|
||||||
|
|
||||||
|
fn quit(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
||||||
|
@ -33,15 +36,15 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
||||||
send_response(plugin.config());
|
send_response(plugin.config());
|
||||||
}
|
}
|
||||||
Ok(NuCommand::begin_filter { params }) => {
|
Ok(NuCommand::begin_filter { params }) => {
|
||||||
send_response(
|
send_response(plugin.begin_filter(params));
|
||||||
plugin
|
|
||||||
.begin_filter(params)
|
|
||||||
.map(|_| Vec::<ReturnValue>::new()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(NuCommand::filter { params }) => {
|
Ok(NuCommand::filter { params }) => {
|
||||||
send_response(plugin.filter(params));
|
send_response(plugin.filter(params));
|
||||||
}
|
}
|
||||||
|
Ok(NuCommand::end_filter) => {
|
||||||
|
send_response(plugin.end_filter());
|
||||||
|
}
|
||||||
|
|
||||||
Ok(NuCommand::sink { params }) => {
|
Ok(NuCommand::sink { params }) => {
|
||||||
plugin.sink(params.0, params.1);
|
plugin.sink(params.0, params.1);
|
||||||
return;
|
return;
|
||||||
|
@ -70,15 +73,14 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
||||||
send_response(plugin.config());
|
send_response(plugin.config());
|
||||||
}
|
}
|
||||||
Ok(NuCommand::begin_filter { params }) => {
|
Ok(NuCommand::begin_filter { params }) => {
|
||||||
send_response(
|
send_response(plugin.begin_filter(params));
|
||||||
plugin
|
|
||||||
.begin_filter(params)
|
|
||||||
.map(|_| Vec::<ReturnValue>::new()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(NuCommand::filter { params }) => {
|
Ok(NuCommand::filter { params }) => {
|
||||||
send_response(plugin.filter(params));
|
send_response(plugin.filter(params));
|
||||||
}
|
}
|
||||||
|
Ok(NuCommand::end_filter) => {
|
||||||
|
send_response(plugin.end_filter());
|
||||||
|
}
|
||||||
Ok(NuCommand::sink { params }) => {
|
Ok(NuCommand::sink { params }) => {
|
||||||
plugin.sink(params.0, params.1);
|
plugin.sink(params.0, params.1);
|
||||||
break;
|
break;
|
||||||
|
@ -138,10 +140,11 @@ pub enum NuCommand {
|
||||||
params: CallInfo,
|
params: CallInfo,
|
||||||
},
|
},
|
||||||
filter {
|
filter {
|
||||||
params: Spanned<Value>,
|
params: Tagged<Value>,
|
||||||
},
|
},
|
||||||
|
end_filter,
|
||||||
sink {
|
sink {
|
||||||
params: (CallInfo, Vec<Spanned<Value>>),
|
params: (CallInfo, Vec<Tagged<Value>>),
|
||||||
},
|
},
|
||||||
quit,
|
quit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{
|
use nu::{
|
||||||
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
||||||
ShellError, Signature, Spanned, Value,
|
ShellError, Signature, Tagged, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Add {
|
struct Add {
|
||||||
|
@ -16,10 +16,11 @@ impl Add {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
|
fn add(&self, value: Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||||
|
let value_tag = value.tag();
|
||||||
match (value.item, self.value.clone()) {
|
match (value.item, self.value.clone()) {
|
||||||
(obj @ Value::Object(_), Some(v)) => match &self.field {
|
(obj @ Value::Object(_), Some(v)) => match &self.field {
|
||||||
Some(f) => match obj.insert_data_at_path(value.span, &f, v) {
|
Some(f) => match obj.insert_data_at_path(value_tag, &f, v) {
|
||||||
Some(v) => return Ok(v),
|
Some(v) => return Ok(v),
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::string(
|
return Err(ShellError::string(
|
||||||
|
@ -52,10 +53,10 @@ impl Plugin for Add {
|
||||||
rest_positional: true,
|
rest_positional: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
if let Some(args) = call_info.args.positional {
|
if let Some(args) = call_info.args.positional {
|
||||||
match &args[0] {
|
match &args[0] {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -69,16 +70,16 @@ impl Plugin for Add {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match &args[1] {
|
match &args[1] {
|
||||||
Spanned { item: v, .. } => {
|
Tagged { item: v, .. } => {
|
||||||
self.value = Some(v.clone());
|
self.value = Some(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
Ok(vec![ReturnSuccess::value(self.add(input)?)])
|
Ok(vec![ReturnSuccess::value(self.add(input)?)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{
|
use nu::{
|
||||||
serve_plugin, CallInfo, NamedType, Plugin, ShellError, Signature, SpanSource, Spanned, Value,
|
serve_plugin, CallInfo, NamedType, Plugin, ShellError, Signature, SpanSource, Tagged, Value,
|
||||||
};
|
};
|
||||||
use pretty_hex::*;
|
use pretty_hex::*;
|
||||||
|
|
||||||
|
@ -27,14 +27,12 @@ impl Plugin for BinaryView {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink(&mut self, call_info: CallInfo, input: Vec<Spanned<Value>>) {
|
fn sink(&mut self, call_info: CallInfo, input: Vec<Tagged<Value>>) {
|
||||||
for v in input {
|
for v in input {
|
||||||
match v {
|
let value_origin = v.origin();
|
||||||
Spanned {
|
match v.item {
|
||||||
item: Value::Binary(b),
|
Value::Binary(b) => {
|
||||||
span,
|
let source = value_origin.map(|x| call_info.source_map.get(&x)).flatten();
|
||||||
} => {
|
|
||||||
let source = span.source.map(|x| call_info.source_map.get(&x)).flatten();
|
|
||||||
let _ = view_binary(&b, source, call_info.args.has("lores"));
|
let _ = view_binary(&b, source, call_info.args.has("lores"));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -195,11 +193,11 @@ impl RenderContext {
|
||||||
let cursor = cursor();
|
let cursor = cursor();
|
||||||
cursor.hide()?;
|
cursor.hide()?;
|
||||||
|
|
||||||
self.width = terminal_size.0 as usize + 1;
|
self.width = terminal_size.0 as usize;
|
||||||
self.height = if self.lores_mode {
|
self.height = if self.lores_mode {
|
||||||
terminal_size.1 as usize
|
terminal_size.1 as usize - 1
|
||||||
} else {
|
} else {
|
||||||
terminal_size.1 as usize * 2
|
(terminal_size.1 as usize - 1) * 2
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +354,7 @@ pub fn view_contents_interactive(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut nes = neso::Nes::new(48000.0);
|
let mut nes = neso::Nes::new(0.0);
|
||||||
let rawkey = RawKey::new();
|
let rawkey = RawKey::new();
|
||||||
nes.load_rom(&buffer);
|
nes.load_rom(&buffer);
|
||||||
|
|
||||||
|
@ -375,10 +373,10 @@ pub fn view_contents_interactive(
|
||||||
let cursor = cursor();
|
let cursor = cursor();
|
||||||
|
|
||||||
let buttons = vec![
|
let buttons = vec![
|
||||||
KeyCode::LShift,
|
KeyCode::Alt,
|
||||||
KeyCode::LControl,
|
KeyCode::LeftControl,
|
||||||
KeyCode::Tab,
|
KeyCode::Tab,
|
||||||
KeyCode::Back,
|
KeyCode::BackSpace,
|
||||||
KeyCode::UpArrow,
|
KeyCode::UpArrow,
|
||||||
KeyCode::DownArrow,
|
KeyCode::DownArrow,
|
||||||
KeyCode::LeftArrow,
|
KeyCode::LeftArrow,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{
|
use nu::{
|
||||||
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
||||||
ShellError, Signature, Spanned, Value,
|
ShellError, Signature, Tagged, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Edit {
|
struct Edit {
|
||||||
|
@ -16,10 +16,11 @@ impl Edit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
|
fn edit(&self, value: Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||||
|
let value_tag = value.tag();
|
||||||
match (value.item, self.value.clone()) {
|
match (value.item, self.value.clone()) {
|
||||||
(obj @ Value::Object(_), Some(v)) => match &self.field {
|
(obj @ Value::Object(_), Some(v)) => match &self.field {
|
||||||
Some(f) => match obj.replace_data_at_path(value.span, &f, v) {
|
Some(f) => match obj.replace_data_at_path(value_tag, &f, v) {
|
||||||
Some(v) => return Ok(v),
|
Some(v) => return Ok(v),
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::string(
|
return Err(ShellError::string(
|
||||||
|
@ -52,10 +53,10 @@ impl Plugin for Edit {
|
||||||
rest_positional: true,
|
rest_positional: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
if let Some(args) = call_info.args.positional {
|
if let Some(args) = call_info.args.positional {
|
||||||
match &args[0] {
|
match &args[0] {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -69,16 +70,16 @@ impl Plugin for Edit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match &args[1] {
|
match &args[1] {
|
||||||
Spanned { item: v, .. } => {
|
Tagged { item: v, .. } => {
|
||||||
self.value = Some(v.clone());
|
self.value = Some(v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
Ok(vec![ReturnSuccess::value(self.edit(input)?)])
|
Ok(vec![ReturnSuccess::value(self.edit(input)?)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{
|
use nu::{
|
||||||
serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess,
|
serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||||
ReturnValue, ShellError, Signature, Spanned, SpannedItem, Value,
|
ReturnValue, ShellError, Signature, Tagged, TaggedItem, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Inc {
|
struct Inc {
|
||||||
|
@ -22,20 +22,20 @@ impl Inc {
|
||||||
|
|
||||||
fn inc(
|
fn inc(
|
||||||
&self,
|
&self,
|
||||||
value: Spanned<Value>,
|
value: Tagged<Value>,
|
||||||
field: &Option<String>,
|
field: &Option<String>,
|
||||||
) -> Result<Spanned<Value>, ShellError> {
|
) -> Result<Tagged<Value>, ShellError> {
|
||||||
match value.item {
|
match value.item {
|
||||||
Value::Primitive(Primitive::Int(i)) => Ok(Value::int(i + 1).spanned(value.span)),
|
Value::Primitive(Primitive::Int(i)) => Ok(Value::int(i + 1).tagged(value.tag())),
|
||||||
Value::Primitive(Primitive::Bytes(b)) => {
|
Value::Primitive(Primitive::Bytes(b)) => {
|
||||||
Ok(Value::bytes(b + 1 as u64).spanned(value.span))
|
Ok(Value::bytes(b + 1 as u64).tagged(value.tag()))
|
||||||
}
|
}
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
Value::Primitive(Primitive::String(ref s)) => {
|
||||||
if let Ok(i) = s.parse::<u64>() {
|
if let Ok(i) = s.parse::<u64>() {
|
||||||
Ok(Spanned {
|
Ok(Tagged::from_item(
|
||||||
item: Value::string(format!("{}", i + 1)),
|
Value::string(format!("{}", i + 1)),
|
||||||
span: value.span,
|
value.tag(),
|
||||||
})
|
))
|
||||||
} else if let Ok(mut ver) = semver::Version::parse(&s) {
|
} else if let Ok(mut ver) = semver::Version::parse(&s) {
|
||||||
if self.major {
|
if self.major {
|
||||||
ver.increment_major();
|
ver.increment_major();
|
||||||
|
@ -45,17 +45,17 @@ impl Inc {
|
||||||
self.patch;
|
self.patch;
|
||||||
ver.increment_patch();
|
ver.increment_patch();
|
||||||
}
|
}
|
||||||
Ok(Spanned {
|
Ok(Tagged::from_item(
|
||||||
item: Value::string(ver.to_string()),
|
Value::string(ver.to_string()),
|
||||||
span: value.span,
|
value.tag(),
|
||||||
})
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::string("string could not be incremented"))
|
Err(ShellError::string("string could not be incremented"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::Object(_) => match field {
|
Value::Object(_) => match field {
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
let replacement = match value.item.get_data_by_path(value.span, f) {
|
let replacement = match value.item.get_data_by_path(value.tag(), f) {
|
||||||
Some(result) => self.inc(result.map(|x| x.clone()), &None)?,
|
Some(result) => self.inc(result.map(|x| x.clone()), &None)?,
|
||||||
None => {
|
None => {
|
||||||
return Err(ShellError::string("inc could not find field to replace"))
|
return Err(ShellError::string("inc could not find field to replace"))
|
||||||
|
@ -63,7 +63,7 @@ impl Inc {
|
||||||
};
|
};
|
||||||
match value
|
match value
|
||||||
.item
|
.item
|
||||||
.replace_data_at_path(value.span, f, replacement.item.clone())
|
.replace_data_at_path(value.tag(), f, replacement.item.clone())
|
||||||
{
|
{
|
||||||
Some(v) => return Ok(v),
|
Some(v) => return Ok(v),
|
||||||
None => {
|
None => {
|
||||||
|
@ -98,7 +98,7 @@ impl Plugin for Inc {
|
||||||
rest_positional: true,
|
rest_positional: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
if call_info.args.has("major") {
|
if call_info.args.has("major") {
|
||||||
self.major = true;
|
self.major = true;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ impl Plugin for Inc {
|
||||||
if let Some(args) = call_info.args.positional {
|
if let Some(args) = call_info.args.positional {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
match arg {
|
match arg {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::String(s)),
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -128,10 +128,10 @@ impl Plugin for Inc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
Ok(vec![ReturnSuccess::value(self.inc(input, &self.field)?)])
|
Ok(vec![ReturnSuccess::value(self.inc(input, &self.field)?)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{
|
use nu::{
|
||||||
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||||
Spanned, Value,
|
Tagged, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NewSkip {
|
struct Skip {
|
||||||
skip_amount: i64,
|
skip_amount: i64,
|
||||||
}
|
}
|
||||||
impl NewSkip {
|
impl Skip {
|
||||||
fn new() -> NewSkip {
|
fn new() -> Skip {
|
||||||
NewSkip { skip_amount: 0 }
|
Skip { skip_amount: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for NewSkip {
|
impl Plugin for Skip {
|
||||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
Ok(Signature {
|
Ok(Signature {
|
||||||
name: "skip".to_string(),
|
name: "skip".to_string(),
|
||||||
|
@ -23,11 +23,11 @@ impl Plugin for NewSkip {
|
||||||
rest_positional: true,
|
rest_positional: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<(), ShellError> {
|
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
if let Some(args) = call_info.args.positional {
|
if let Some(args) = call_info.args.positional {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
match arg {
|
match arg {
|
||||||
Spanned {
|
Tagged {
|
||||||
item: Value::Primitive(Primitive::Int(i)),
|
item: Value::Primitive(Primitive::Int(i)),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
@ -37,17 +37,17 @@ impl Plugin for NewSkip {
|
||||||
return Err(ShellError::labeled_error(
|
return Err(ShellError::labeled_error(
|
||||||
"Unrecognized type in params",
|
"Unrecognized type in params",
|
||||||
"expected an integer",
|
"expected an integer",
|
||||||
arg.span,
|
arg.span(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter(&mut self, input: Spanned<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
if self.skip_amount == 0 {
|
if self.skip_amount == 0 {
|
||||||
Ok(vec![ReturnSuccess::value(input)])
|
Ok(vec![ReturnSuccess::value(input)])
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,5 +58,5 @@ impl Plugin for NewSkip {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
serve_plugin(&mut NewSkip::new());
|
serve_plugin(&mut Skip::new());
|
||||||
}
|
}
|
||||||
|
|
430
src/plugins/str.rs
Normal file
430
src/plugins/str.rs
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use nu::{
|
||||||
|
serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||||
|
ReturnValue, ShellError, Signature, Tagged, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
Downcase,
|
||||||
|
Upcase,
|
||||||
|
ToInteger,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Str {
|
||||||
|
field: Option<String>,
|
||||||
|
error: Option<String>,
|
||||||
|
action: Option<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Str {
|
||||||
|
fn new() -> Str {
|
||||||
|
Str {
|
||||||
|
field: None,
|
||||||
|
error: None,
|
||||||
|
action: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(&self, input: &str) -> Value {
|
||||||
|
match self.action {
|
||||||
|
Some(Action::Downcase) => Value::string(input.to_ascii_lowercase()),
|
||||||
|
Some(Action::Upcase) => Value::string(input.to_ascii_uppercase()),
|
||||||
|
Some(Action::ToInteger) => match input.trim().parse::<i64>() {
|
||||||
|
Ok(v) => Value::int(v),
|
||||||
|
Err(_) => Value::string(input),
|
||||||
|
},
|
||||||
|
None => Value::string(input.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_input(&mut self, field: String) {
|
||||||
|
self.field = Some(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permit(&mut self) -> bool {
|
||||||
|
self.action.is_none()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_error(&mut self, message: &str) {
|
||||||
|
self.error = Some(message.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_to_int(&mut self) {
|
||||||
|
if self.permit() {
|
||||||
|
self.action = Some(Action::ToInteger);
|
||||||
|
} else {
|
||||||
|
self.log_error("can only apply one");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_downcase(&mut self) {
|
||||||
|
if self.permit() {
|
||||||
|
self.action = Some(Action::Downcase);
|
||||||
|
} else {
|
||||||
|
self.log_error("can only apply one");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_upcase(&mut self) {
|
||||||
|
if self.permit() {
|
||||||
|
self.action = Some(Action::Upcase);
|
||||||
|
} else {
|
||||||
|
self.log_error("can only apply one");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &'static str {
|
||||||
|
"Usage: str field [--downcase|--upcase|--to-int]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Str {
|
||||||
|
fn strutils(
|
||||||
|
&self,
|
||||||
|
value: Tagged<Value>,
|
||||||
|
field: &Option<String>,
|
||||||
|
) -> Result<Tagged<Value>, ShellError> {
|
||||||
|
match value.item {
|
||||||
|
Value::Primitive(Primitive::String(ref s)) => {
|
||||||
|
Ok(Tagged::from_item(self.apply(&s), value.tag()))
|
||||||
|
}
|
||||||
|
Value::Object(_) => match field {
|
||||||
|
Some(f) => {
|
||||||
|
let replacement = match value.item.get_data_by_path(value.tag(), f) {
|
||||||
|
Some(result) => self.strutils(result.map(|x| x.clone()), &None)?,
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::string("str could not find field to replace"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match value
|
||||||
|
.item
|
||||||
|
.replace_data_at_path(value.tag(), f, replacement.item.clone())
|
||||||
|
{
|
||||||
|
Some(v) => return Ok(v),
|
||||||
|
None => {
|
||||||
|
return Err(ShellError::string("str could not find field to replace"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err(ShellError::string(format!(
|
||||||
|
"{}: {}",
|
||||||
|
"str needs a field when applying it to a value in an object",
|
||||||
|
self.usage()
|
||||||
|
))),
|
||||||
|
},
|
||||||
|
x => Err(ShellError::string(format!(
|
||||||
|
"Unrecognized type in stream: {:?}",
|
||||||
|
x
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for Str {
|
||||||
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
|
let mut named = IndexMap::new();
|
||||||
|
named.insert("downcase".to_string(), NamedType::Switch);
|
||||||
|
named.insert("upcase".to_string(), NamedType::Switch);
|
||||||
|
named.insert("to-int".to_string(), NamedType::Switch);
|
||||||
|
|
||||||
|
Ok(Signature {
|
||||||
|
name: "str".to_string(),
|
||||||
|
positional: vec![PositionalType::optional_any("Field")],
|
||||||
|
is_filter: true,
|
||||||
|
named,
|
||||||
|
rest_positional: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
if call_info.args.has("downcase") {
|
||||||
|
self.for_downcase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if call_info.args.has("upcase") {
|
||||||
|
self.for_upcase();
|
||||||
|
}
|
||||||
|
|
||||||
|
if call_info.args.has("to-int") {
|
||||||
|
self.for_to_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(args) = call_info.args.positional {
|
||||||
|
for arg in args {
|
||||||
|
match arg {
|
||||||
|
Tagged {
|
||||||
|
item: Value::Primitive(Primitive::String(s)),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
self.for_input(s);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::string(format!(
|
||||||
|
"Unrecognized type in params: {:?}",
|
||||||
|
arg
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match &self.error {
|
||||||
|
Some(reason) => {
|
||||||
|
return Err(ShellError::string(format!("{}: {}", reason, self.usage())))
|
||||||
|
}
|
||||||
|
None => Ok(vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(vec![ReturnSuccess::value(
|
||||||
|
self.strutils(input, &self.field)?,
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
serve_plugin(&mut Str::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::Str;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use nu::{
|
||||||
|
CallInfo, EvaluatedArgs, Plugin, ReturnSuccess, SourceMap, Span, Tag, Tagged,
|
||||||
|
TaggedDictBuilder, TaggedItem, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CallStub {
|
||||||
|
positionals: Vec<Tagged<Value>>,
|
||||||
|
flags: IndexMap<String, Tagged<Value>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallStub {
|
||||||
|
fn new() -> CallStub {
|
||||||
|
CallStub {
|
||||||
|
positionals: vec![],
|
||||||
|
flags: indexmap::IndexMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_long_flag(&mut self, name: &str) -> &mut Self {
|
||||||
|
self.flags.insert(
|
||||||
|
name.to_string(),
|
||||||
|
Value::boolean(true).simple_spanned(Span::unknown()),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_parameter(&mut self, name: &str) -> &mut Self {
|
||||||
|
self.positionals
|
||||||
|
.push(Value::string(name.to_string()).simple_spanned(Span::unknown()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, name_span: Span) -> CallInfo {
|
||||||
|
CallInfo {
|
||||||
|
args: EvaluatedArgs::new(Some(self.positionals.clone()), Some(self.flags.clone())),
|
||||||
|
source_map: SourceMap::new(),
|
||||||
|
name_span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sample_record(key: &str, value: &str) -> Tagged<Value> {
|
||||||
|
let mut record = TaggedDictBuilder::new(Tag::unknown());
|
||||||
|
record.insert(key.clone(), Value::string(value));
|
||||||
|
record.into_tagged_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_configuration_flags_wired() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
let configured = plugin.config().unwrap();
|
||||||
|
|
||||||
|
for action_flag in &["downcase", "upcase", "to-int"] {
|
||||||
|
assert!(configured.named.get(*action_flag).is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_accepts_downcase() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("downcase")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
assert!(plugin.action.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_accepts_upcase() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("upcase")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
assert!(plugin.action.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_accepts_to_int() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("to-int")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
assert!(plugin.action.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_accepts_field() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_parameter("package.description")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
assert_eq!(plugin.field, Some("package.description".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_accepts_only_one_action() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("upcase")
|
||||||
|
.with_long_flag("downcase")
|
||||||
|
.with_long_flag("to-int")
|
||||||
|
.create(Span::unknown()),
|
||||||
|
)
|
||||||
|
.is_err());
|
||||||
|
assert_eq!(plugin.error, Some("can only apply one".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_downcases() {
|
||||||
|
let mut strutils = Str::new();
|
||||||
|
strutils.for_downcase();
|
||||||
|
assert_eq!(strutils.apply("ANDRES"), Value::string("andres"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_upcases() {
|
||||||
|
let mut strutils = Str::new();
|
||||||
|
strutils.for_upcase();
|
||||||
|
assert_eq!(strutils.apply("andres"), Value::string("ANDRES"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_to_int() {
|
||||||
|
let mut strutils = Str::new();
|
||||||
|
strutils.for_to_int();
|
||||||
|
assert_eq!(strutils.apply("9999"), Value::int(9999 as i64));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_applies_upcase() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("upcase")
|
||||||
|
.with_parameter("name")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
let subject = sample_record("name", "jotandrehuda");
|
||||||
|
let output = plugin.filter(subject).unwrap();
|
||||||
|
|
||||||
|
match output[0].as_ref().unwrap() {
|
||||||
|
ReturnSuccess::Value(Tagged {
|
||||||
|
item: Value::Object(o),
|
||||||
|
..
|
||||||
|
}) => assert_eq!(
|
||||||
|
*o.get_data(&String::from("name")).borrow(),
|
||||||
|
Value::string(String::from("JOTANDREHUDA"))
|
||||||
|
),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_applies_downcase() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("downcase")
|
||||||
|
.with_parameter("name")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
let subject = sample_record("name", "JOTANDREHUDA");
|
||||||
|
let output = plugin.filter(subject).unwrap();
|
||||||
|
|
||||||
|
match output[0].as_ref().unwrap() {
|
||||||
|
ReturnSuccess::Value(Tagged {
|
||||||
|
item: Value::Object(o),
|
||||||
|
..
|
||||||
|
}) => assert_eq!(
|
||||||
|
*o.get_data(&String::from("name")).borrow(),
|
||||||
|
Value::string(String::from("jotandrehuda"))
|
||||||
|
),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn str_plugin_applies_to_int() {
|
||||||
|
let mut plugin = Str::new();
|
||||||
|
|
||||||
|
assert!(plugin
|
||||||
|
.begin_filter(
|
||||||
|
CallStub::new()
|
||||||
|
.with_long_flag("to-int")
|
||||||
|
.with_parameter("Nu_birthday")
|
||||||
|
.create(Span::unknown())
|
||||||
|
)
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
let subject = sample_record("Nu_birthday", "10");
|
||||||
|
let output = plugin.filter(subject).unwrap();
|
||||||
|
|
||||||
|
match output[0].as_ref().unwrap() {
|
||||||
|
ReturnSuccess::Value(Tagged {
|
||||||
|
item: Value::Object(o),
|
||||||
|
..
|
||||||
|
}) => assert_eq!(
|
||||||
|
*o.get_data(&String::from("Nu_birthday")).borrow(),
|
||||||
|
Value::int(10)
|
||||||
|
),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
src/plugins/sum.rs
Normal file
94
src/plugins/sum.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use nu::{
|
||||||
|
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||||
|
Tag, Tagged, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sum {
|
||||||
|
total: Option<Tagged<Value>>,
|
||||||
|
}
|
||||||
|
impl Sum {
|
||||||
|
fn new() -> Sum {
|
||||||
|
Sum { total: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sum(&mut self, value: Tagged<Value>) -> Result<(), ShellError> {
|
||||||
|
match value.item {
|
||||||
|
Value::Primitive(Primitive::Int(i)) => {
|
||||||
|
match self.total {
|
||||||
|
Some(Tagged {
|
||||||
|
item: Value::Primitive(Primitive::Int(j)),
|
||||||
|
tag: Tag { span, .. },
|
||||||
|
}) => {
|
||||||
|
//TODO: handle overflow
|
||||||
|
self.total =
|
||||||
|
Some(Tagged::from_simple_spanned_item(Value::int(i + j), span));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.total = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::string(format!(
|
||||||
|
"Could not sum non-integer or unrelated types"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::Primitive(Primitive::Bytes(b)) => {
|
||||||
|
match self.total {
|
||||||
|
Some(Tagged {
|
||||||
|
item: Value::Primitive(Primitive::Bytes(j)),
|
||||||
|
tag: Tag { span, .. },
|
||||||
|
}) => {
|
||||||
|
//TODO: handle overflow
|
||||||
|
self.total =
|
||||||
|
Some(Tagged::from_simple_spanned_item(Value::bytes(b + j), span));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.total = Some(value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(ShellError::string(format!(
|
||||||
|
"Could not sum non-integer or unrelated types"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => Err(ShellError::string(format!(
|
||||||
|
"Unrecognized type in stream: {:?}",
|
||||||
|
x
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for Sum {
|
||||||
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
|
Ok(Signature {
|
||||||
|
name: "sum".to_string(),
|
||||||
|
positional: vec![],
|
||||||
|
is_filter: true,
|
||||||
|
named: IndexMap::new(),
|
||||||
|
rest_positional: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn begin_filter(&mut self, _: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter(&mut self, input: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
self.sum(input)?;
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end_filter(&mut self) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
match self.total {
|
||||||
|
None => Ok(vec![]),
|
||||||
|
Some(ref v) => Ok(vec![ReturnSuccess::value(v.clone())]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
serve_plugin(&mut Sum::new());
|
||||||
|
}
|
201
src/plugins/sys.rs
Normal file
201
src/plugins/sys.rs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
#![feature(async_await)]
|
||||||
|
|
||||||
|
use futures::executor::block_on;
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
use heim::{disk, memory};
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use nu::{
|
||||||
|
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||||
|
Tag, Tagged, TaggedDictBuilder, Value, OF64,
|
||||||
|
};
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
struct Sys;
|
||||||
|
impl Sys {
|
||||||
|
fn new() -> Sys {
|
||||||
|
Sys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: add more error checking
|
||||||
|
|
||||||
|
async fn cpu(tag: Tag) -> Option<Tagged<Value>> {
|
||||||
|
if let (Ok(num_cpu), Ok(cpu_speed)) = (sys_info::cpu_num(), sys_info::cpu_speed()) {
|
||||||
|
let mut cpu_idx = TaggedDictBuilder::new(tag);
|
||||||
|
cpu_idx.insert("cores", Primitive::Int(num_cpu as i64));
|
||||||
|
cpu_idx.insert("speed", Primitive::Int(cpu_speed as i64));
|
||||||
|
Some(cpu_idx.into_tagged_value())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn mem(tag: Tag) -> Tagged<Value> {
|
||||||
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
|
if let Ok(memory) = memory::memory().await {
|
||||||
|
dict.insert("total", Value::bytes(memory.total().get()));
|
||||||
|
dict.insert("free", Value::bytes(memory.free().get()));
|
||||||
|
}
|
||||||
|
if let Ok(swap) = memory::swap().await {
|
||||||
|
dict.insert("swap total", Value::bytes(swap.total().get()));
|
||||||
|
dict.insert("swap free", Value::bytes(swap.free().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
dict.into_tagged_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn host(tag: Tag) -> Tagged<Value> {
|
||||||
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
|
// OS
|
||||||
|
if let Ok(platform) = heim::host::platform().await {
|
||||||
|
dict.insert("name", Value::string(platform.system()));
|
||||||
|
dict.insert("release", Value::string(platform.release()));
|
||||||
|
dict.insert("hostname", Value::string(platform.hostname()));
|
||||||
|
dict.insert("arch", Value::string(platform.architecture().as_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uptime
|
||||||
|
if let Ok(uptime) = heim::host::uptime().await {
|
||||||
|
let mut uptime_dict = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
|
let uptime = uptime.get().round() as i64;
|
||||||
|
let days = uptime / (60 * 60 * 24);
|
||||||
|
let hours = (uptime - days * 60 * 60 * 24) / (60 * 60);
|
||||||
|
let minutes = (uptime - days * 60 * 60 * 24 - hours * 60 * 60) / 60;
|
||||||
|
let seconds = uptime % 60;
|
||||||
|
|
||||||
|
uptime_dict.insert("days", Value::int(days));
|
||||||
|
uptime_dict.insert("hours", Value::int(hours));
|
||||||
|
uptime_dict.insert("mins", Value::int(minutes));
|
||||||
|
uptime_dict.insert("secs", Value::int(seconds));
|
||||||
|
|
||||||
|
dict.insert_tagged("uptime", uptime_dict.into_tagged_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Users
|
||||||
|
let mut users = heim::host::users();
|
||||||
|
let mut user_vec = vec![];
|
||||||
|
while let Some(user) = users.next().await {
|
||||||
|
if let Ok(user) = user {
|
||||||
|
user_vec.push(Tagged::from_item(Value::string(user.username()), tag));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let user_list = Value::List(user_vec);
|
||||||
|
dict.insert("users", user_list);
|
||||||
|
|
||||||
|
dict.into_tagged_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn disks(tag: Tag) -> Value {
|
||||||
|
let mut output = vec![];
|
||||||
|
let mut partitions = disk::partitions_physical();
|
||||||
|
while let Some(part) = partitions.next().await {
|
||||||
|
if let Ok(part) = part {
|
||||||
|
let mut dict = TaggedDictBuilder::new(tag);
|
||||||
|
dict.insert(
|
||||||
|
"device",
|
||||||
|
Value::string(
|
||||||
|
part.device()
|
||||||
|
.unwrap_or_else(|| OsStr::new("N/A"))
|
||||||
|
.to_string_lossy(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
dict.insert("type", Value::string(part.file_system().as_str()));
|
||||||
|
dict.insert("mount", Value::string(part.mount_point().to_string_lossy()));
|
||||||
|
if let Ok(usage) = disk::usage(part.mount_point().to_path_buf()).await {
|
||||||
|
dict.insert("total", Value::bytes(usage.total().get()));
|
||||||
|
dict.insert("used", Value::bytes(usage.used().get()));
|
||||||
|
dict.insert("free", Value::bytes(usage.free().get()));
|
||||||
|
}
|
||||||
|
output.push(dict.into_tagged_value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::List(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn temp(tag: Tag) -> Value {
|
||||||
|
use sysinfo::{ComponentExt, RefreshKind, SystemExt};
|
||||||
|
let system = sysinfo::System::new_with_specifics(RefreshKind::new().with_system());
|
||||||
|
let components_list = system.get_components_list();
|
||||||
|
if components_list.len() > 0 {
|
||||||
|
let mut v: Vec<Tagged<Value>> = vec![];
|
||||||
|
for component in components_list {
|
||||||
|
let mut component_idx = TaggedDictBuilder::new(tag);
|
||||||
|
component_idx.insert("name", Primitive::String(component.get_label().to_string()));
|
||||||
|
component_idx.insert(
|
||||||
|
"temp",
|
||||||
|
Primitive::Float(OF64::from(component.get_temperature() as f64)),
|
||||||
|
);
|
||||||
|
component_idx.insert(
|
||||||
|
"max",
|
||||||
|
Primitive::Float(OF64::from(component.get_max() as f64)),
|
||||||
|
);
|
||||||
|
if let Some(critical) = component.get_critical() {
|
||||||
|
component_idx.insert("critical", Primitive::Float(OF64::from(critical as f64)));
|
||||||
|
}
|
||||||
|
v.push(component_idx.into());
|
||||||
|
}
|
||||||
|
Value::List(v)
|
||||||
|
} else {
|
||||||
|
Value::List(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn net(tag: Tag) -> Tagged<Value> {
|
||||||
|
use sysinfo::{NetworkExt, RefreshKind, SystemExt};
|
||||||
|
let system = sysinfo::System::new_with_specifics(RefreshKind::new().with_network());
|
||||||
|
|
||||||
|
let network = system.get_network();
|
||||||
|
let incoming = network.get_income();
|
||||||
|
let outgoing = network.get_outcome();
|
||||||
|
|
||||||
|
let mut network_idx = TaggedDictBuilder::new(tag);
|
||||||
|
network_idx.insert("incoming", Value::bytes(incoming));
|
||||||
|
network_idx.insert("outgoing", Value::bytes(outgoing));
|
||||||
|
network_idx.into_tagged_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn sysinfo(tag: Tag) -> Vec<Tagged<Value>> {
|
||||||
|
let mut sysinfo = TaggedDictBuilder::new(tag);
|
||||||
|
|
||||||
|
sysinfo.insert_tagged("host", host(tag).await);
|
||||||
|
if let Some(cpu) = cpu(tag).await {
|
||||||
|
sysinfo.insert_tagged("cpu", cpu);
|
||||||
|
}
|
||||||
|
sysinfo.insert("disks", disks(tag).await);
|
||||||
|
sysinfo.insert_tagged("mem", mem(tag).await);
|
||||||
|
sysinfo.insert("temp", temp(tag).await);
|
||||||
|
sysinfo.insert_tagged("net", net(tag).await);
|
||||||
|
|
||||||
|
vec![sysinfo.into_tagged_value()]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for Sys {
|
||||||
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
|
Ok(Signature {
|
||||||
|
name: "sys".to_string(),
|
||||||
|
positional: vec![],
|
||||||
|
is_filter: true,
|
||||||
|
named: IndexMap::new(),
|
||||||
|
rest_positional: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn begin_filter(&mut self, callinfo: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(block_on(sysinfo(Tag::unknown_origin(callinfo.name_span)))
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| ReturnSuccess::value(x))
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter(&mut self, _: Tagged<Value>) -> Result<Vec<ReturnValue>, ShellError> {
|
||||||
|
Ok(vec![])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
serve_plugin(&mut Sys::new());
|
||||||
|
}
|
287
src/plugins/textview.rs
Normal file
287
src/plugins/textview.rs
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
#![feature(option_flattening)]
|
||||||
|
|
||||||
|
use crossterm::{cursor, terminal, RawScreen};
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use nu::{
|
||||||
|
serve_plugin, CallInfo, Plugin, Primitive, ShellError, Signature, SourceMap, SpanSource,
|
||||||
|
Tagged, Value,
|
||||||
|
};
|
||||||
|
use rawkey::RawKey;
|
||||||
|
|
||||||
|
use syntect::easy::HighlightLines;
|
||||||
|
use syntect::highlighting::{Style, ThemeSet};
|
||||||
|
use syntect::parsing::SyntaxSet;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
|
enum DrawCommand {
|
||||||
|
DrawString(Style, String),
|
||||||
|
NextLine,
|
||||||
|
}
|
||||||
|
struct TextView;
|
||||||
|
|
||||||
|
impl TextView {
|
||||||
|
fn new() -> TextView {
|
||||||
|
TextView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for TextView {
|
||||||
|
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||||
|
Ok(Signature {
|
||||||
|
name: "textview".to_string(),
|
||||||
|
positional: vec![],
|
||||||
|
is_filter: false,
|
||||||
|
named: IndexMap::new(),
|
||||||
|
rest_positional: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sink(&mut self, call_info: CallInfo, input: Vec<Tagged<Value>>) {
|
||||||
|
view_text_value(&input[0], &call_info.source_map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_textview(
|
||||||
|
draw_commands: &Vec<DrawCommand>,
|
||||||
|
starting_row: usize,
|
||||||
|
use_color_buffer: bool,
|
||||||
|
) -> usize {
|
||||||
|
let terminal = terminal();
|
||||||
|
let cursor = cursor();
|
||||||
|
|
||||||
|
let size = terminal.terminal_size();
|
||||||
|
|
||||||
|
// render
|
||||||
|
let mut pos = 0;
|
||||||
|
let width = size.0 as usize;
|
||||||
|
let height = size.1 as usize - 1;
|
||||||
|
let mut frame_buffer = vec![];
|
||||||
|
|
||||||
|
for command in draw_commands {
|
||||||
|
match command {
|
||||||
|
DrawCommand::DrawString(style, string) => {
|
||||||
|
for chr in string.chars() {
|
||||||
|
frame_buffer.push((
|
||||||
|
chr,
|
||||||
|
style.foreground.r,
|
||||||
|
style.foreground.g,
|
||||||
|
style.foreground.b,
|
||||||
|
));
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DrawCommand::NextLine => {
|
||||||
|
for _ in 0..(width - pos % width) {
|
||||||
|
frame_buffer.push((' ', 0, 0, 0));
|
||||||
|
}
|
||||||
|
pos += width - pos % width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_frame_buffer_rows = frame_buffer.len() / width;
|
||||||
|
let buffer_needs_scrolling = num_frame_buffer_rows > height;
|
||||||
|
|
||||||
|
// display
|
||||||
|
let mut ansi_strings = vec![];
|
||||||
|
let mut normal_chars = vec![];
|
||||||
|
|
||||||
|
for c in
|
||||||
|
&frame_buffer[starting_row * width..std::cmp::min(pos, (starting_row + height) * width)]
|
||||||
|
{
|
||||||
|
if use_color_buffer {
|
||||||
|
ansi_strings.push(ansi_term::Colour::RGB(c.1, c.2, c.3).paint(format!("{}", c.0)));
|
||||||
|
} else {
|
||||||
|
normal_chars.push(c.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer_needs_scrolling {
|
||||||
|
let _ = cursor.goto(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if use_color_buffer {
|
||||||
|
print!("{}", ansi_term::ANSIStrings(&ansi_strings));
|
||||||
|
} else {
|
||||||
|
let s: String = normal_chars.into_iter().collect();
|
||||||
|
print!("{}", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if buffer_needs_scrolling {
|
||||||
|
let _ = cursor.goto(0, size.1);
|
||||||
|
print!(
|
||||||
|
"{}",
|
||||||
|
ansi_term::Colour::Blue.paint("[ESC to quit, arrow keys to move]")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = std::io::stdout().flush();
|
||||||
|
|
||||||
|
num_frame_buffer_rows
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scroll_view_lines_if_needed(draw_commands: Vec<DrawCommand>, use_color_buffer: bool) {
|
||||||
|
let mut starting_row = 0;
|
||||||
|
let rawkey = RawKey::new();
|
||||||
|
|
||||||
|
if let Ok(_raw) = RawScreen::into_raw_mode() {
|
||||||
|
let cursor = cursor();
|
||||||
|
let _ = cursor.hide();
|
||||||
|
|
||||||
|
let input = crossterm::input();
|
||||||
|
let _ = input.read_async();
|
||||||
|
|
||||||
|
let terminal = terminal();
|
||||||
|
let mut size = terminal.terminal_size();
|
||||||
|
let height = size.1 as usize - 1;
|
||||||
|
|
||||||
|
let mut max_bottom_line = paint_textview(&draw_commands, starting_row, use_color_buffer);
|
||||||
|
|
||||||
|
// Only scroll if needed
|
||||||
|
if max_bottom_line > height as usize {
|
||||||
|
loop {
|
||||||
|
if rawkey.is_pressed(rawkey::KeyCode::Escape) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if rawkey.is_pressed(rawkey::KeyCode::UpArrow) {
|
||||||
|
if starting_row > 0 {
|
||||||
|
starting_row -= 1;
|
||||||
|
max_bottom_line =
|
||||||
|
paint_textview(&draw_commands, starting_row, use_color_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rawkey.is_pressed(rawkey::KeyCode::DownArrow) {
|
||||||
|
if starting_row < (max_bottom_line - height) {
|
||||||
|
starting_row += 1;
|
||||||
|
}
|
||||||
|
max_bottom_line =
|
||||||
|
paint_textview(&draw_commands, starting_row, use_color_buffer);
|
||||||
|
}
|
||||||
|
if rawkey.is_pressed(rawkey::KeyCode::PageUp) {
|
||||||
|
starting_row -= std::cmp::min(height, starting_row);
|
||||||
|
max_bottom_line =
|
||||||
|
paint_textview(&draw_commands, starting_row, use_color_buffer);
|
||||||
|
}
|
||||||
|
if rawkey.is_pressed(rawkey::KeyCode::PageDown) {
|
||||||
|
if starting_row < (max_bottom_line - height) {
|
||||||
|
starting_row += height;
|
||||||
|
|
||||||
|
if starting_row > (max_bottom_line - height) {
|
||||||
|
starting_row = max_bottom_line - height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_bottom_line =
|
||||||
|
paint_textview(&draw_commands, starting_row, use_color_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::sleep(Duration::from_millis(50));
|
||||||
|
|
||||||
|
let new_size = terminal.terminal_size();
|
||||||
|
if size != new_size {
|
||||||
|
size = new_size;
|
||||||
|
let _ = terminal.clear(crossterm::ClearType::All);
|
||||||
|
max_bottom_line =
|
||||||
|
paint_textview(&draw_commands, starting_row, use_color_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cursor = cursor();
|
||||||
|
let _ = cursor.show();
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
let screen = RawScreen::disable_raw_mode();
|
||||||
|
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scroll_view(s: &str) {
|
||||||
|
let mut v = vec![];
|
||||||
|
for line in s.lines() {
|
||||||
|
v.push(DrawCommand::DrawString(Style::default(), line.to_string()));
|
||||||
|
v.push(DrawCommand::NextLine);
|
||||||
|
}
|
||||||
|
scroll_view_lines_if_needed(v, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_text_value(value: &Tagged<Value>, source_map: &SourceMap) {
|
||||||
|
let value_origin = value.origin();
|
||||||
|
match value.item {
|
||||||
|
Value::Primitive(Primitive::String(ref s)) => {
|
||||||
|
let source = value_origin.map(|x| source_map.get(&x)).flatten();
|
||||||
|
|
||||||
|
if let Some(source) = source {
|
||||||
|
let extension: Option<String> = match source {
|
||||||
|
SpanSource::File(file) => {
|
||||||
|
let path = Path::new(file);
|
||||||
|
path.extension().map(|x| x.to_string_lossy().to_string())
|
||||||
|
}
|
||||||
|
SpanSource::Url(url) => {
|
||||||
|
let url = reqwest::Url::parse(url);
|
||||||
|
if let Ok(url) = url {
|
||||||
|
let url = url.clone();
|
||||||
|
if let Some(mut segments) = url.path_segments() {
|
||||||
|
if let Some(file) = segments.next_back() {
|
||||||
|
let path = Path::new(file);
|
||||||
|
path.extension().map(|x| x.to_string_lossy().to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//FIXME: this probably isn't correct
|
||||||
|
SpanSource::Source(source) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match extension {
|
||||||
|
Some(extension) => {
|
||||||
|
// Load these once at the start of your program
|
||||||
|
let ps: SyntaxSet = syntect::dumps::from_binary(include_bytes!(
|
||||||
|
"../../assets/syntaxes.bin"
|
||||||
|
));
|
||||||
|
|
||||||
|
if let Some(syntax) = ps.find_syntax_by_extension(&extension) {
|
||||||
|
let ts: ThemeSet = syntect::dumps::from_binary(include_bytes!(
|
||||||
|
"../../assets/themes.bin"
|
||||||
|
));
|
||||||
|
let mut h = HighlightLines::new(syntax, &ts.themes["OneHalfDark"]);
|
||||||
|
|
||||||
|
let mut v = vec![];
|
||||||
|
for line in s.lines() {
|
||||||
|
let ranges: Vec<(Style, &str)> = h.highlight(line, &ps);
|
||||||
|
|
||||||
|
for range in ranges {
|
||||||
|
v.push(DrawCommand::DrawString(range.0, range.1.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
v.push(DrawCommand::NextLine);
|
||||||
|
}
|
||||||
|
scroll_view_lines_if_needed(v, true);
|
||||||
|
} else {
|
||||||
|
scroll_view(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
scroll_view(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scroll_view(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
serve_plugin(&mut TextView::new());
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use nu::{serve_plugin, CallInfo, Plugin, ShellError, Signature, Spanned, Value};
|
use nu::{serve_plugin, CallInfo, Plugin, ShellError, Signature, Tagged, Value};
|
||||||
use ptree::item::StringItem;
|
use ptree::item::StringItem;
|
||||||
use ptree::output::print_tree_with;
|
use ptree::output::print_tree_with;
|
||||||
use ptree::print_config::PrintConfig;
|
use ptree::print_config::PrintConfig;
|
||||||
|
@ -90,15 +90,13 @@ impl Plugin for TreeViewer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink(&mut self, _call_info: CallInfo, input: Vec<Spanned<Value>>) {
|
fn sink(&mut self, _call_info: CallInfo, input: Vec<Tagged<Value>>) {
|
||||||
if input.len() > 0 {
|
if input.len() > 0 {
|
||||||
for i in input.iter() {
|
for i in input.iter() {
|
||||||
let view = TreeView::from_value(&i);
|
let view = TreeView::from_value(&i);
|
||||||
let _ = view.render_view();
|
let _ = view.render_view();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,17 +36,24 @@ crate use crate::cli::MaybeOwned;
|
||||||
crate use crate::commands::command::{
|
crate use crate::commands::command::{
|
||||||
CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
|
CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
|
||||||
};
|
};
|
||||||
crate use crate::context::{CommandRegistry, Context};
|
crate use crate::commands::StaticCommand;
|
||||||
|
crate use crate::context::CommandRegistry;
|
||||||
|
crate use crate::context::{Context, SpanSource};
|
||||||
crate use crate::env::host::handle_unexpected;
|
crate use crate::env::host::handle_unexpected;
|
||||||
crate use crate::env::{Environment, Host};
|
crate use crate::env::Host;
|
||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
crate use crate::object::base as value;
|
crate use crate::object::base as value;
|
||||||
|
crate use crate::object::meta::{Tag, Tagged, TaggedItem};
|
||||||
crate use crate::object::types::ExtractType;
|
crate use crate::object::types::ExtractType;
|
||||||
crate use crate::object::{Primitive, Value};
|
crate use crate::object::{Primitive, Value};
|
||||||
|
crate use crate::parser::hir::SyntaxType;
|
||||||
crate use crate::parser::registry::Signature;
|
crate use crate::parser::registry::Signature;
|
||||||
crate use crate::parser::{hir::SyntaxType, Span, Spanned, SpannedItem};
|
crate use crate::shell::filesystem_shell::FilesystemShell;
|
||||||
|
crate use crate::shell::shell_manager::ShellManager;
|
||||||
|
crate use crate::shell::value_shell::ValueShell;
|
||||||
crate use crate::stream::{InputStream, OutputStream};
|
crate use crate::stream::{InputStream, OutputStream};
|
||||||
crate use crate::traits::{HasSpan, ToDebug};
|
crate use crate::traits::{HasSpan, ToDebug};
|
||||||
|
crate use crate::Span;
|
||||||
crate use crate::Text;
|
crate use crate::Text;
|
||||||
crate use futures::stream::BoxStream;
|
crate use futures::stream::BoxStream;
|
||||||
crate use futures::{FutureExt, Stream, StreamExt};
|
crate use futures::{FutureExt, Stream, StreamExt};
|
||||||
|
@ -63,7 +70,7 @@ pub trait FromInputStream {
|
||||||
|
|
||||||
impl<T> FromInputStream for T
|
impl<T> FromInputStream for T
|
||||||
where
|
where
|
||||||
T: Stream<Item = Spanned<Value>> + Send + 'static,
|
T: Stream<Item = Tagged<Value>> + Send + 'static,
|
||||||
{
|
{
|
||||||
fn from_input_stream(self) -> OutputStream {
|
fn from_input_stream(self) -> OutputStream {
|
||||||
OutputStream {
|
OutputStream {
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
crate mod completer;
|
crate mod completer;
|
||||||
|
crate mod filesystem_shell;
|
||||||
crate mod helper;
|
crate mod helper;
|
||||||
|
crate mod shell;
|
||||||
|
crate mod shell_manager;
|
||||||
|
crate mod value_shell;
|
||||||
|
|
||||||
crate use helper::Helper;
|
crate use helper::Helper;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::context::CommandRegistry;
|
|
||||||
|
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use rustyline::completion::Completer;
|
use rustyline::completion::Completer;
|
||||||
use rustyline::completion::{self, FilenameCompleter};
|
use rustyline::completion::{self, FilenameCompleter};
|
||||||
|
@ -8,19 +6,32 @@ use rustyline::line_buffer::LineBuffer;
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
crate struct NuCompleter {
|
crate struct NuCompleter {
|
||||||
pub file_completer: FilenameCompleter,
|
pub file_completer: FilenameCompleter,
|
||||||
pub commands: CommandRegistry,
|
//pub commands: indexmap::IndexMap<String, Arc<dyn Command>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Completer for NuCompleter {
|
pub struct CompletionPair {
|
||||||
type Candidate = completion::Pair;
|
pub display: String,
|
||||||
|
pub replacement: String,
|
||||||
|
}
|
||||||
|
|
||||||
fn complete(
|
impl Into<completion::Pair> for CompletionPair {
|
||||||
|
fn into(self) -> completion::Pair {
|
||||||
|
completion::Pair {
|
||||||
|
display: self.display,
|
||||||
|
replacement: self.replacement,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NuCompleter {
|
||||||
|
/*
|
||||||
|
pub fn complete(
|
||||||
&self,
|
&self,
|
||||||
line: &str,
|
line: &str,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
context: &rustyline::Context,
|
context: &rustyline::Context,
|
||||||
) -> rustyline::Result<(usize, Vec<completion::Pair>)> {
|
) -> rustyline::Result<(usize, Vec<CompletionPair>)> {
|
||||||
let commands: Vec<String> = self.commands.names();
|
//let commands: Vec<String> = self.commands.keys().cloned().collect();
|
||||||
|
|
||||||
let mut completions = self.file_completer.complete(line, pos, context)?.1;
|
let mut completions = self.file_completer.complete(line, pos, context)?.1;
|
||||||
|
|
||||||
|
@ -51,6 +62,7 @@ impl Completer for NuCompleter {
|
||||||
replace_pos -= 1;
|
replace_pos -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
for command in commands.iter() {
|
for command in commands.iter() {
|
||||||
let mut pos = replace_pos;
|
let mut pos = replace_pos;
|
||||||
let mut matched = true;
|
let mut matched = true;
|
||||||
|
@ -68,15 +80,17 @@ impl Completer for NuCompleter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if matched {
|
if matched {
|
||||||
completions.push(completion::Pair {
|
completions.push(CompletionPair {
|
||||||
display: command.clone(),
|
display: command.clone(),
|
||||||
replacement: command.clone(),
|
replacement: command.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
Ok((replace_pos, completions))
|
Ok((replace_pos, completions))
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
||||||
let end = line.pos();
|
let end = line.pos();
|
||||||
|
|
212
src/shell/filesystem_shell.rs
Normal file
212
src/shell/filesystem_shell.rs
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
use crate::commands::command::CallInfo;
|
||||||
|
use crate::object::dir_entry_dict;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::shell::completer::{CompletionPair, NuCompleter};
|
||||||
|
use crate::shell::shell::Shell;
|
||||||
|
use rustyline::completion::{Completer, FilenameCompleter};
|
||||||
|
use rustyline::error::ReadlineError;
|
||||||
|
use rustyline::hint::{Hinter, HistoryHinter};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
pub struct FilesystemShell {
|
||||||
|
crate path: String,
|
||||||
|
completer: NuCompleter,
|
||||||
|
hinter: HistoryHinter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for FilesystemShell {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
FilesystemShell {
|
||||||
|
path: self.path.clone(),
|
||||||
|
completer: NuCompleter {
|
||||||
|
file_completer: FilenameCompleter::new(),
|
||||||
|
},
|
||||||
|
hinter: HistoryHinter {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilesystemShell {
|
||||||
|
pub fn basic() -> Result<FilesystemShell, std::io::Error> {
|
||||||
|
let path = std::env::current_dir()?;
|
||||||
|
|
||||||
|
Ok(FilesystemShell {
|
||||||
|
path: path.to_string_lossy().to_string(),
|
||||||
|
completer: NuCompleter {
|
||||||
|
file_completer: FilenameCompleter::new(),
|
||||||
|
},
|
||||||
|
hinter: HistoryHinter {},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_location(path: String) -> Result<FilesystemShell, std::io::Error> {
|
||||||
|
Ok(FilesystemShell {
|
||||||
|
path,
|
||||||
|
completer: NuCompleter {
|
||||||
|
file_completer: FilenameCompleter::new(),
|
||||||
|
},
|
||||||
|
hinter: HistoryHinter {},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shell for FilesystemShell {
|
||||||
|
fn name(&self) -> String {
|
||||||
|
"filesystem".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ls(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||||
|
let cwd = self.path.clone();
|
||||||
|
let mut full_path = PathBuf::from(&self.path);
|
||||||
|
match &call_info.args.nth(0) {
|
||||||
|
Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let entries = glob::glob(&full_path.to_string_lossy());
|
||||||
|
|
||||||
|
if entries.is_err() {
|
||||||
|
return Err(ShellError::string("Invalid pattern."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut shell_entries = VecDeque::new();
|
||||||
|
let entries: Vec<_> = entries.unwrap().collect();
|
||||||
|
|
||||||
|
// If this is a single entry, try to display the contents of the entry if it's a directory
|
||||||
|
if entries.len() == 1 {
|
||||||
|
if let Ok(entry) = &entries[0] {
|
||||||
|
if entry.is_dir() {
|
||||||
|
let entries = std::fs::read_dir(&full_path);
|
||||||
|
|
||||||
|
let entries = match entries {
|
||||||
|
Err(e) => {
|
||||||
|
if let Some(s) = call_info.args.nth(0) {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
s.span(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
e.to_string(),
|
||||||
|
e.to_string(),
|
||||||
|
call_info.name_span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(o) => o,
|
||||||
|
};
|
||||||
|
for entry in entries {
|
||||||
|
let entry = entry?;
|
||||||
|
let filepath = entry.path();
|
||||||
|
let filename = filepath.strip_prefix(&cwd).unwrap();
|
||||||
|
let value = dir_entry_dict(
|
||||||
|
filename,
|
||||||
|
&entry.metadata()?,
|
||||||
|
Tag::unknown_origin(call_info.name_span),
|
||||||
|
)?;
|
||||||
|
shell_entries.push_back(ReturnSuccess::value(value))
|
||||||
|
}
|
||||||
|
return Ok(shell_entries.to_output_stream());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate the entries from the glob and add each
|
||||||
|
for entry in entries {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
let filename = entry.strip_prefix(&cwd).unwrap();
|
||||||
|
let metadata = std::fs::metadata(&entry)?;
|
||||||
|
let value = dir_entry_dict(
|
||||||
|
filename,
|
||||||
|
&metadata,
|
||||||
|
Tag::unknown_origin(call_info.name_span),
|
||||||
|
)?;
|
||||||
|
shell_entries.push_back(ReturnSuccess::value(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(shell_entries.to_output_stream())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cd(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||||
|
let path = match call_info.args.nth(0) {
|
||||||
|
None => match dirs::home_dir() {
|
||||||
|
Some(o) => o,
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Can not change to home directory",
|
||||||
|
"can not go to home",
|
||||||
|
call_info.name_span,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(v) => {
|
||||||
|
let target = v.as_string()?;
|
||||||
|
let path = PathBuf::from(self.path());
|
||||||
|
match dunce::canonicalize(path.join(target).as_path()) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Can not change to directory",
|
||||||
|
"directory not found",
|
||||||
|
v.span().clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stream = VecDeque::new();
|
||||||
|
match std::env::set_current_dir(&path) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => {
|
||||||
|
if call_info.args.len() > 0 {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Can not change to directory",
|
||||||
|
"directory not found",
|
||||||
|
call_info.args.nth(0).unwrap().span().clone(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::string("Can not change to directory"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.push_back(ReturnSuccess::change_cwd(
|
||||||
|
path.to_string_lossy().to_string(),
|
||||||
|
));
|
||||||
|
Ok(stream.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> String {
|
||||||
|
self.path.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_path(&mut self, path: String) {
|
||||||
|
let pathbuf = PathBuf::from(&path);
|
||||||
|
let path = match dunce::canonicalize(pathbuf.as_path()) {
|
||||||
|
Ok(path) => {
|
||||||
|
let _ = std::env::set_current_dir(&path);
|
||||||
|
path
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// TODO: handle the case where the path cannot be canonicalized
|
||||||
|
pathbuf
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.path = path.to_string_lossy().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn complete(
|
||||||
|
&self,
|
||||||
|
line: &str,
|
||||||
|
pos: usize,
|
||||||
|
ctx: &rustyline::Context<'_>,
|
||||||
|
) -> Result<(usize, Vec<CompletionPair>), ReadlineError> {
|
||||||
|
self.completer.complete(line, pos, ctx)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||||
|
self.hinter.hint(line, pos, ctx)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,50 +1,60 @@
|
||||||
use crate::parser::nom_input;
|
use crate::parser::nom_input;
|
||||||
use crate::parser::parse::span::Spanned;
|
|
||||||
use crate::parser::parse::token_tree::TokenNode;
|
use crate::parser::parse::token_tree::TokenNode;
|
||||||
use crate::parser::parse::tokens::RawToken;
|
use crate::parser::parse::tokens::RawToken;
|
||||||
use crate::parser::{Pipeline, PipelineElement};
|
use crate::parser::{Pipeline, PipelineElement};
|
||||||
use crate::prelude::*;
|
use crate::shell::completer::CompletionPair;
|
||||||
use crate::shell::completer::NuCompleter;
|
use crate::shell::shell_manager::ShellManager;
|
||||||
|
use crate::Tagged;
|
||||||
use ansi_term::Color;
|
use ansi_term::Color;
|
||||||
use rustyline::completion::{self, Completer, FilenameCompleter};
|
use rustyline::completion::Completer;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::highlight::Highlighter;
|
use rustyline::highlight::Highlighter;
|
||||||
use rustyline::hint::{Hinter, HistoryHinter};
|
use rustyline::hint::Hinter;
|
||||||
use std::borrow::Cow::{self, Owned};
|
use std::borrow::Cow::{self, Owned};
|
||||||
|
|
||||||
crate struct Helper {
|
crate struct Helper {
|
||||||
completer: NuCompleter,
|
helper: ShellManager,
|
||||||
hinter: HistoryHinter,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Helper {
|
impl Helper {
|
||||||
crate fn new(commands: CommandRegistry) -> Helper {
|
crate fn new(helper: ShellManager) -> Helper {
|
||||||
Helper {
|
Helper { helper }
|
||||||
completer: NuCompleter {
|
|
||||||
file_completer: FilenameCompleter::new(),
|
|
||||||
commands,
|
|
||||||
},
|
|
||||||
hinter: HistoryHinter {},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Completer for Helper {
|
impl Completer for Helper {
|
||||||
type Candidate = completion::Pair;
|
type Candidate = rustyline::completion::Pair;
|
||||||
|
fn complete(
|
||||||
|
&self,
|
||||||
|
line: &str,
|
||||||
|
pos: usize,
|
||||||
|
ctx: &rustyline::Context<'_>,
|
||||||
|
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||||
|
//FIXME: Add back completions
|
||||||
|
Ok((0, vec![]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
impl Completer for Helper {
|
||||||
|
type Candidate = rustyline::completion::Pair;
|
||||||
|
|
||||||
fn complete(
|
fn complete(
|
||||||
&self,
|
&self,
|
||||||
line: &str,
|
line: &str,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
ctx: &rustyline::Context<'_>,
|
ctx: &rustyline::Context<'_>,
|
||||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||||
self.completer.complete(line, pos, ctx)
|
let result = self.helper.complete(line, pos, ctx);
|
||||||
|
|
||||||
|
result.map(|(x, y)| (x, y.iter().map(|z| z.into()).collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
impl Hinter for Helper {
|
impl Hinter for Helper {
|
||||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||||
self.hinter.hint(line, pos, ctx)
|
self.helper.hint(line, pos, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,23 +117,23 @@ fn paint_token_node(token_node: &TokenNode, line: &str) -> String {
|
||||||
TokenNode::Delimited(..) => Color::White.paint(token_node.span().slice(line)),
|
TokenNode::Delimited(..) => Color::White.paint(token_node.span().slice(line)),
|
||||||
TokenNode::Operator(..) => Color::White.normal().paint(token_node.span().slice(line)),
|
TokenNode::Operator(..) => Color::White.normal().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Pipeline(..) => Color::Blue.normal().paint(token_node.span().slice(line)),
|
TokenNode::Pipeline(..) => Color::Blue.normal().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::Integer(..),
|
item: RawToken::Integer(..),
|
||||||
..
|
..
|
||||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::Size(..),
|
item: RawToken::Size(..),
|
||||||
..
|
..
|
||||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::String(..),
|
item: RawToken::String(..),
|
||||||
..
|
..
|
||||||
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::Variable(..),
|
item: RawToken::Variable(..),
|
||||||
..
|
..
|
||||||
}) => Color::Yellow.bold().paint(token_node.span().slice(line)),
|
}) => Color::Yellow.bold().paint(token_node.span().slice(line)),
|
||||||
TokenNode::Token(Spanned {
|
TokenNode::Token(Tagged {
|
||||||
item: RawToken::Bare,
|
item: RawToken::Bare,
|
||||||
..
|
..
|
||||||
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue