mirror of
https://github.com/nushell/nushell.git
synced 2025-01-22 06:08:47 +01:00
Merge master
This commit is contained in:
commit
aadacc2d36
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,10 +281,20 @@ impl ExternalCommand {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for arg in &self.args {
|
for arg in &self.args {
|
||||||
|
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());
|
process = process.arg(arg.item.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
{
|
{
|
||||||
let mut new_arg_string = self.name.to_string();
|
let mut new_arg_string = self.name.to_string();
|
||||||
@ -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)) => {
|
||||||
|
match from_csv_string_to_value(s, value_tag) {
|
||||||
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Could not parse as CSV",
|
"Could not parse as CSV",
|
||||||
"piped data failed CSV parse",
|
"input cannot be parsed as CSV",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
}
|
||||||
"Expected string values from pipeline",
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"expects strings from pipeline",
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.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)) => {
|
||||||
|
match from_ini_string_to_value(s, value_tag) {
|
||||||
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Could not parse as INI",
|
"Could not parse as INI",
|
||||||
format!("{:#?}", e),
|
"input cannot be parsed as INI",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
}
|
||||||
"Expected string values from pipeline",
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"expects strings from pipeline",
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.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)) => {
|
||||||
|
match from_json_string_to_value(s, value_tag) {
|
||||||
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Could not parse as JSON",
|
"Could not parse as JSON",
|
||||||
"piped data failed JSON parse",
|
"input cannot be parsed as JSON",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
}
|
||||||
"Expected string values from pipeline",
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"expects strings from pipeline",
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.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)) => {
|
||||||
|
match from_toml_string_to_value(s, value_tag) {
|
||||||
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Could not parse as TOML",
|
"Could not parse as TOML",
|
||||||
"piped data failed TOML parse",
|
"input cannot be parsed as TOML",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
}
|
||||||
"Expected string values from pipeline",
|
x => Err(ShellError::labeled_error_with_secondary(
|
||||||
"expects strings from pipeline",
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
format!("{} originates from here", x.type_name()),
|
||||||
|
value_tag.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)) => {
|
||||||
|
match from_xml_string_to_value(s, value_tag) {
|
||||||
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Could not parse as XML",
|
"Could not parse as XML",
|
||||||
"piped data failed XML parse",
|
"input cannot be parsed as XML",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
}
|
||||||
"Expected string values from pipeline",
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"expects strings from pipeline",
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.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)) => {
|
||||||
|
match from_yaml_string_to_value(s, value_tag) {
|
||||||
|
Ok(x) => ReturnSuccess::value(x),
|
||||||
|
Err(_) => Err(ShellError::labeled_error_with_secondary(
|
||||||
"Could not parse as YAML",
|
"Could not parse as YAML",
|
||||||
"piped data failed YAML parse",
|
"input cannot be parsed as YAML",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
value_tag.span,
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
_ => Err(ShellError::maybe_labeled_error(
|
}
|
||||||
"Expected string values from pipeline",
|
_ => Err(ShellError::labeled_error_with_secondary(
|
||||||
"expects strings from pipeline",
|
"Expected a string from pipeline",
|
||||||
|
"requires string input",
|
||||||
span,
|
span,
|
||||||
|
"value originates from here",
|
||||||
|
a.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(
|
|
||||||
"Could not open as CSV",
|
|
||||||
"could not open as CSV",
|
|
||||||
name_span,
|
|
||||||
)
|
)
|
||||||
})
|
|
||||||
}
|
|
||||||
Some(x) if x == "toml" => {
|
|
||||||
crate::commands::from_toml::from_toml_string_to_value(contents, contents_span)
|
|
||||||
.map(|c| c.spanned(contents_span))
|
|
||||||
.map_err(move |_| {
|
.map_err(move |_| {
|
||||||
ShellError::maybe_labeled_error(
|
ShellError::labeled_error("Could not open as CSV", "could not open as CSV", name_span)
|
||||||
|
}),
|
||||||
|
Some(x) if x == "toml" => {
|
||||||
|
crate::commands::from_toml::from_toml_string_to_value(contents, contents_tag).map_err(
|
||||||
|
move |_| {
|
||||||
|
ShellError::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) => {
|
Err(e) => {
|
||||||
return Err(ShellError::string(format!(
|
let mut result = VecDeque::new();
|
||||||
"Error while processing input: {:?} {}",
|
result.push_back(Err(ShellError::string(format!(
|
||||||
|
"Error while processing begin_filter response: {:?} {}",
|
||||||
e, input
|
e, input
|
||||||
)));
|
))));
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::string(format!(
|
||||||
|
"Error while reading begin_filter response: {:?}",
|
||||||
|
e
|
||||||
|
))));
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let mut eos: VecDeque<Spanned<Value>> = VecDeque::new();
|
Tagged {
|
||||||
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 entries.is_err() {
|
||||||
|
return Err(ShellError::string("Invalid pattern."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let entries = entries.unwrap();
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
match entry {
|
||||||
|
Ok(path) => {
|
||||||
|
if path.is_dir() {
|
||||||
if !recursive {
|
if !recursive {
|
||||||
return Err(ShellError::maybe_labeled_error(
|
return Err(ShellError::string(
|
||||||
"is a directory",
|
"is a directory",
|
||||||
"",
|
// "is a directory",
|
||||||
context.name,
|
// args.call_info.name_span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
std::fs::remove_dir_all(&full_path).expect("can not remove directory");
|
std::fs::remove_dir_all(&path).expect("can not remove directory");
|
||||||
} else if full_path.is_file() {
|
} else if path.is_file() {
|
||||||
std::fs::remove_file(&full_path).expect("can not remove file");
|
std::fs::remove_file(&path).expect("can not remove file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => return Err(ShellError::string(&format!("{:?}", e))),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
self.item,
|
||||||
|
Tag {
|
||||||
span: span.into(),
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
self.tag.span
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
pub fn tag(&self) -> Tag {
|
||||||
pub struct Span {
|
self.tag
|
||||||
crate start: usize,
|
|
||||||
crate end: usize,
|
|
||||||
pub source: Option<Uuid>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Option<Span>> for Span {
|
pub fn origin(&self) -> Option<uuid::Uuid> {
|
||||||
fn from(input: Option<Span>) -> Span {
|
self.tag.origin
|
||||||
match input {
|
|
||||||
None => Span {
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
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.into_spanned_value()
|
//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_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,
|
|
||||||
}
|
}
|
||||||
}
|
Tagged {
|
||||||
Spanned {
|
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
}
|
Tagged {
|
||||||
Spanned {
|
|
||||||
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 New Issue
Block a user