mirror of
https://github.com/nushell/nushell
synced 2025-01-13 21:55:07 +00:00
Merge master
This commit is contained in:
commit
aadacc2d36
115 changed files with 5328 additions and 2164 deletions
1596
Cargo.lock
generated
1596
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
44
Cargo.toml
44
Cargo.toml
|
@ -13,7 +13,7 @@ homepage = "https://github.com/nushell/nushell"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rustyline = "5.0.0"
|
||||
rustyline = "5.0.1"
|
||||
sysinfo = "0.9"
|
||||
chrono = { version = "0.4.7", features = ["serde"] }
|
||||
chrono-tz = "0.5.1"
|
||||
|
@ -25,19 +25,19 @@ nom = "5.0.0"
|
|||
dunce = "1.0.0"
|
||||
indexmap = { version = "1.0.2", features = ["serde-1"] }
|
||||
chrono-humanize = "0.0.11"
|
||||
byte-unit = "2.1.0"
|
||||
byte-unit = "3.0.1"
|
||||
ordered-float = {version = "1.0.2", features = ["serde"]}
|
||||
prettyprint = "0.7.0"
|
||||
futures-preview = { version = "=0.3.0-alpha.17", features = ["compat", "io-compat"] }
|
||||
futures-sink-preview = "=0.3.0-alpha.17"
|
||||
futures-async-stream = "0.1.0-alpha.1"
|
||||
async-trait = ""
|
||||
async-trait = "0.1.7"
|
||||
futures_codec = "0.2.5"
|
||||
term = "0.5.2"
|
||||
bytes = "0.4.12"
|
||||
log = "0.4.7"
|
||||
log = "0.4.8"
|
||||
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-hjson = "0.9.0"
|
||||
serde_yaml = "0.8"
|
||||
|
@ -54,8 +54,9 @@ clap = "2.33.0"
|
|||
enum_derive = "0.1.7"
|
||||
adhoc_derive = "0.1.2"
|
||||
lazy_static = "1.3.0"
|
||||
git2 = "0.9.1"
|
||||
dirs = "2.0.1"
|
||||
git2 = "0.9.2"
|
||||
dirs = "2.0.2"
|
||||
glob = "0.3.0"
|
||||
ctrlc = "3.1.3"
|
||||
ptree = "0.2"
|
||||
clipboard = "0.5"
|
||||
|
@ -64,21 +65,24 @@ roxmltree = "0.6.1"
|
|||
nom5_locate = "0.1.1"
|
||||
derive_more = "0.15.0"
|
||||
enum-utils = "0.1.1"
|
||||
unicode-xid = "0.1.0"
|
||||
unicode-xid = "0.2.0"
|
||||
serde_ini = "0.2.0"
|
||||
subprocess = "0.1.18"
|
||||
sys-info = "0.5.7"
|
||||
mime = "0.3.13"
|
||||
regex = "1.1.9"
|
||||
regex = "1.2.1"
|
||||
pretty-hex = "0.1.0"
|
||||
neso = "0.5.0"
|
||||
rawkey = "0.1.1"
|
||||
crossterm = "0.9.6"
|
||||
rawkey = "0.1.2"
|
||||
crossterm = "0.10.2"
|
||||
tempfile = "3.1.0"
|
||||
image = "0.21.2"
|
||||
image = "0.22.1"
|
||||
semver = "0.9.0"
|
||||
uuid = {version = "0.7.4", features = [ "v4", "serde" ]}
|
||||
syntect = "3.2.0"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
onig_sys = "=69.1"
|
||||
heim = "0.0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.6.1"
|
||||
|
@ -92,6 +96,10 @@ path = "src/lib.rs"
|
|||
name = "nu_plugin_inc"
|
||||
path = "src/plugins/inc.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_sum"
|
||||
path = "src/plugins/sum.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_add"
|
||||
path = "src/plugins/add.rs"
|
||||
|
@ -100,10 +108,18 @@ path = "src/plugins/add.rs"
|
|||
name = "nu_plugin_edit"
|
||||
path = "src/plugins/edit.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_str"
|
||||
path = "src/plugins/str.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_skip"
|
||||
path = "src/plugins/skip.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_sys"
|
||||
path = "src/plugins/sys.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_tree"
|
||||
path = "src/plugins/tree.rs"
|
||||
|
@ -112,6 +128,10 @@ path = "src/plugins/tree.rs"
|
|||
name = "nu_plugin_binaryview"
|
||||
path = "src/plugins/binaryview.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_textview"
|
||||
path = "src/plugins/textview.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "nu"
|
||||
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
|
||||
-------------+----------------------------+---------+---------+------+---------
|
||||
[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
|
||||
0.1.2
|
||||
0.1.3
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
|
@ -120,12 +127,19 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat
|
|||
| command | description |
|
||||
| ------------- | ------------- |
|
||||
| cd path | Change to a new path |
|
||||
| cp source path | Copy files |
|
||||
| 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 |
|
||||
| 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') |
|
||||
| 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)
|
||||
| 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 |
|
||||
| inc (field) | Increment a value or version. Optional use the field of a 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 |
|
||||
| skip amount | Skip a 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-json | Convert table into .json text |
|
||||
| to-toml | Convert table into .toml text |
|
||||
| to-yaml | Convert table into .yaml text |
|
||||
| to-csv | Convert table into .csv text |
|
||||
|
||||
## Filters on text (unstructured data)
|
||||
| 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::PluginCommand;
|
||||
use crate::commands::{static_command, Command};
|
||||
use crate::commands::static_command;
|
||||
use crate::context::Context;
|
||||
crate use crate::errors::ShellError;
|
||||
use crate::git::current_branch;
|
||||
use crate::object::Value;
|
||||
use crate::parser::parse::span::Spanned;
|
||||
use crate::parser::registry::Signature;
|
||||
use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
|
||||
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("ps", Box::new(ps::ps)),
|
||||
command("ls", Box::new(ls::ls)),
|
||||
command("sysinfo", Box::new(sysinfo::sysinfo)),
|
||||
command("size", Box::new(size::size)),
|
||||
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("pick", Box::new(pick::pick)),
|
||||
command("shells", Box::new(shells::shells)),
|
||||
command("split-column", Box::new(split_column::split_column)),
|
||||
command("split-row", Box::new(split_row::split_row)),
|
||||
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-yaml", Box::new(to_yaml::to_yaml)),
|
||||
command("sort-by", Box::new(sort_by::sort_by)),
|
||||
command("tags", Box::new(tags::tags)),
|
||||
static_command(Get),
|
||||
static_command(Cd),
|
||||
static_command(Remove),
|
||||
|
@ -173,8 +176,12 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
static_command(Where),
|
||||
static_command(Config),
|
||||
static_command(SkipWhile),
|
||||
static_command(Exit),
|
||||
static_command(Clip),
|
||||
static_command(Autoview),
|
||||
static_command(Copycp),
|
||||
static_command(Date),
|
||||
static_command(Mkdir),
|
||||
static_command(Save),
|
||||
static_command(Table),
|
||||
static_command(VTable),
|
||||
|
@ -183,15 +190,15 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
let _ = load_plugins(&mut context);
|
||||
|
||||
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
||||
let h = crate::shell::Helper::new(context.clone_commands());
|
||||
let mut rl: Editor<crate::shell::Helper> = Editor::with_config(config);
|
||||
//let h = crate::shell::Helper::new(context.clone_commands());
|
||||
let mut rl: Editor<_> = Editor::with_config(config);
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let _ = ansi_term::enable_ansi_support();
|
||||
}
|
||||
|
||||
rl.set_helper(Some(h));
|
||||
//rl.set_helper(Some(h));
|
||||
let _ = rl.load_history("history.txt");
|
||||
|
||||
let ctrl_c = Arc::new(AtomicBool::new(false));
|
||||
|
@ -207,10 +214,12 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let cwd = {
|
||||
let env = context.env.lock().unwrap();
|
||||
env.path().display().to_string()
|
||||
};
|
||||
let cwd = context.shell_manager.path();
|
||||
|
||||
rl.set_helper(Some(crate::shell::Helper::new(
|
||||
context.shell_manager.clone(),
|
||||
)));
|
||||
|
||||
let readline = rl.readline(&format!(
|
||||
"{}{}> ",
|
||||
cwd,
|
||||
|
@ -336,7 +345,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||
.commands
|
||||
.push(ClassifiedCommand::Internal(InternalCommand {
|
||||
command: static_command(autoview::Autoview),
|
||||
name_span: None,
|
||||
name_span: Span::unknown(),
|
||||
source_map: ctx.source_map.clone(),
|
||||
args: hir::Call::new(
|
||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||
|
@ -473,19 +482,19 @@ fn classify_command(
|
|||
|
||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||
command,
|
||||
name_span: Some(head.span().clone()),
|
||||
name_span: head.span().clone(),
|
||||
source_map: context.source_map.clone(),
|
||||
args,
|
||||
}))
|
||||
}
|
||||
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()
|
||||
.filter_map(|i| match i {
|
||||
TokenNode::Whitespace(_) => None,
|
||||
other => Some(Spanned::from_item(
|
||||
other => Some(Tagged::from_simple_spanned_item(
|
||||
other.as_external_arg(source),
|
||||
other.span(),
|
||||
)),
|
||||
|
@ -496,7 +505,7 @@ fn classify_command(
|
|||
|
||||
Ok(ClassifiedCommand::External(ExternalCommand {
|
||||
name: name.to_string(),
|
||||
name_span: Some(head.span().clone()),
|
||||
name_span: head.span().clone(),
|
||||
args: arg_list_strings,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ crate mod classified;
|
|||
crate mod clip;
|
||||
crate mod command;
|
||||
crate mod config;
|
||||
crate mod cp;
|
||||
crate mod date;
|
||||
crate mod enter;
|
||||
crate mod exit;
|
||||
crate mod first;
|
||||
crate mod from_csv;
|
||||
|
@ -19,20 +22,24 @@ crate mod from_yaml;
|
|||
crate mod get;
|
||||
crate mod lines;
|
||||
crate mod ls;
|
||||
crate mod mkdir;
|
||||
crate mod next;
|
||||
crate mod open;
|
||||
crate mod pick;
|
||||
crate mod plugin;
|
||||
crate mod prev;
|
||||
crate mod ps;
|
||||
crate mod reject;
|
||||
crate mod rm;
|
||||
crate mod save;
|
||||
crate mod shells;
|
||||
crate mod size;
|
||||
crate mod skip_while;
|
||||
crate mod sort_by;
|
||||
crate mod split_column;
|
||||
crate mod split_row;
|
||||
crate mod sysinfo;
|
||||
crate mod table;
|
||||
crate mod tags;
|
||||
crate mod to_array;
|
||||
crate mod to_csv;
|
||||
crate mod to_json;
|
||||
|
@ -50,7 +57,11 @@ crate use command::{
|
|||
UnevaluatedCallInfo,
|
||||
};
|
||||
crate use config::Config;
|
||||
crate use cp::Copycp;
|
||||
crate use date::Date;
|
||||
crate use exit::Exit;
|
||||
crate use get::Get;
|
||||
crate use mkdir::Mkdir;
|
||||
crate use open::Open;
|
||||
crate use rm::Remove;
|
||||
crate use save::Save;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use crate::commands::{RawCommandArgs, StaticCommand};
|
||||
use crate::context::{SourceMap, SpanSource};
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct Autoview;
|
||||
|
||||
|
@ -36,15 +34,15 @@ pub fn autoview(
|
|||
let input = context.input.drain_vec().await;
|
||||
|
||||
if input.len() > 0 {
|
||||
if let Spanned {
|
||||
if let Tagged {
|
||||
item: Value::Binary(_),
|
||||
..
|
||||
} = input[0]
|
||||
} = input[0usize]
|
||||
{
|
||||
let binary = context.expect_command("binaryview");
|
||||
binary.run(raw.with_input(input), &context.commands).await;
|
||||
} 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) {
|
||||
let table = context.expect_command("table");
|
||||
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 item = match items.next() {
|
||||
|
@ -82,11 +80,11 @@ fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {
|
|||
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 {
|
||||
return false;
|
||||
}
|
||||
if let Spanned {
|
||||
if let Tagged {
|
||||
item: Value::Primitive(Primitive::String(_)),
|
||||
..
|
||||
} = input[0]
|
||||
|
@ -96,63 +94,3 @@ fn is_single_text_value(input: &Vec<Spanned<Value>>) -> bool {
|
|||
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)]
|
||||
pub struct CdArgs {
|
||||
target: Option<Spanned<PathBuf>>,
|
||||
target: Option<Tagged<PathBuf>>,
|
||||
}
|
||||
|
||||
impl StaticCommand for Cd {
|
||||
|
@ -39,7 +39,7 @@ pub fn cd(CdArgs { target }: CdArgs, context: RunnableContext) -> Result<OutputS
|
|||
None => match dirs::home_dir() {
|
||||
Some(o) => o,
|
||||
_ => {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to home directory",
|
||||
"can not go to home",
|
||||
context.name,
|
||||
|
@ -54,7 +54,7 @@ pub fn cd(CdArgs { target }: CdArgs, context: RunnableContext) -> Result<OutputS
|
|||
return Err(ShellError::labeled_error(
|
||||
"Can not change to directory",
|
||||
"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(
|
||||
"Can not change to directory",
|
||||
"directory not found",
|
||||
path.span,
|
||||
path.span(),
|
||||
));
|
||||
} else {
|
||||
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())
|
||||
|
||||
// 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::context::SourceMap;
|
||||
use crate::parser::{hir, Span, Spanned, TokenNode};
|
||||
use crate::parser::{hir, TokenNode};
|
||||
use crate::prelude::*;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::stream::StreamExt;
|
||||
|
@ -98,7 +98,7 @@ impl ClassifiedCommand {
|
|||
|
||||
crate struct InternalCommand {
|
||||
crate command: Arc<Command>,
|
||||
crate name_span: Option<Span>,
|
||||
crate name_span: Span,
|
||||
crate source_map: SourceMap,
|
||||
crate args: hir::Call,
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ impl InternalCommand {
|
|||
.run_command(
|
||||
self.command,
|
||||
self.name_span.clone(),
|
||||
self.source_map,
|
||||
context.source_map.clone(),
|
||||
self.args,
|
||||
source,
|
||||
objects,
|
||||
|
@ -137,12 +137,62 @@ impl InternalCommand {
|
|||
match item? {
|
||||
ReturnSuccess::Action(action) => match action {
|
||||
CommandAction::ChangePath(path) => {
|
||||
context.env.lock().unwrap().path = path;
|
||||
context.shell_manager.set_path(path);
|
||||
}
|
||||
CommandAction::AddSpanSource(uuid, span_source) => {
|
||||
context.add_span_source(uuid, span_source);
|
||||
}
|
||||
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) => {
|
||||
|
@ -158,8 +208,8 @@ impl InternalCommand {
|
|||
crate struct ExternalCommand {
|
||||
crate name: String,
|
||||
#[allow(unused)]
|
||||
crate name_span: Option<Span>,
|
||||
crate args: Vec<Spanned<String>>,
|
||||
crate name_span: Span,
|
||||
crate args: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
crate enum StreamNext {
|
||||
|
@ -176,7 +226,7 @@ impl ExternalCommand {
|
|||
stream_next: StreamNext,
|
||||
) -> Result<ClassifiedInputStream, ShellError> {
|
||||
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();
|
||||
|
||||
trace!(target: "nu::run::external", "-> {}", self.name);
|
||||
|
@ -201,7 +251,7 @@ impl ExternalCommand {
|
|||
let mut span = None;
|
||||
for arg in &self.args {
|
||||
if arg.item.contains("$it") {
|
||||
span = Some(arg.span);
|
||||
span = Some(arg.span());
|
||||
}
|
||||
}
|
||||
if let Some(span) = span {
|
||||
|
@ -231,7 +281,17 @@ impl ExternalCommand {
|
|||
}
|
||||
} else {
|
||||
for arg in &self.args {
|
||||
process = process.arg(arg.item.clone());
|
||||
let arg_chars: Vec<_> = arg.chars().collect();
|
||||
if arg_chars.len() > 1
|
||||
&& arg_chars[0] == '"'
|
||||
&& arg_chars[arg_chars.len() - 1] == '"'
|
||||
{
|
||||
// quoted string
|
||||
let new_arg: String = arg_chars[1..arg_chars.len() - 1].iter().collect();
|
||||
process = process.arg(new_arg);
|
||||
} else {
|
||||
process = process.arg(arg.item.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,13 +303,13 @@ impl ExternalCommand {
|
|||
let mut first = true;
|
||||
for i in &inputs {
|
||||
if i.as_string().is_err() {
|
||||
let mut span = None;
|
||||
let mut span = name_span;
|
||||
for arg in &self.args {
|
||||
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",
|
||||
"given object instead of string data",
|
||||
span,
|
||||
|
@ -280,7 +340,7 @@ impl ExternalCommand {
|
|||
|
||||
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 {
|
||||
StreamNext::Last => process,
|
||||
|
@ -308,10 +368,11 @@ impl ExternalCommand {
|
|||
let stdout = popen.stdout.take().unwrap();
|
||||
let file = futures::io::AllowStdIo::new(stdout);
|
||||
let stream = Framed::new(file, LinesCodec {});
|
||||
let stream =
|
||||
stream.map(move |line| Value::string(line.unwrap()).spanned(name_span));
|
||||
let stream = stream.map(move |line| {
|
||||
Tagged::from_simple_spanned_item(Value::string(line.unwrap()), name_span)
|
||||
});
|
||||
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,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
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;
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ pub fn clip(
|
|||
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 new_copy_data = String::new();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::errors::ShellError;
|
|||
use crate::evaluate::Scope;
|
||||
use crate::object::Value;
|
||||
use crate::parser::hir;
|
||||
use crate::parser::{registry, ConfigDeserializer, Span, Spanned};
|
||||
use crate::parser::{registry, ConfigDeserializer};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
|
@ -18,7 +18,7 @@ pub struct UnevaluatedCallInfo {
|
|||
pub args: hir::Call,
|
||||
pub source: Text,
|
||||
pub source_map: SourceMap,
|
||||
pub name_span: Option<Span>,
|
||||
pub name_span: Span,
|
||||
}
|
||||
|
||||
impl ToDebug for UnevaluatedCallInfo {
|
||||
|
@ -43,19 +43,22 @@ impl UnevaluatedCallInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct CallInfo {
|
||||
pub args: registry::EvaluatedArgs,
|
||||
pub source_map: SourceMap,
|
||||
pub name_span: Option<Span>,
|
||||
pub name_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "crate"]
|
||||
pub struct CommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub env: Arc<Mutex<Environment>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
// pub host: Arc<Mutex<dyn Host + Send>>,
|
||||
// pub shell_manager: ShellManager,
|
||||
// pub call_info: CallInfo,
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
|
@ -63,15 +66,15 @@ pub struct CommandArgs {
|
|||
#[get = "crate"]
|
||||
pub struct RawCommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub env: Arc<Mutex<Environment>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
}
|
||||
|
||||
impl RawCommandArgs {
|
||||
pub fn with_input(self, input: Vec<Spanned<Value>>) -> CommandArgs {
|
||||
pub fn with_input(self, input: Vec<Tagged<Value>>) -> CommandArgs {
|
||||
CommandArgs {
|
||||
host: self.host,
|
||||
env: self.env,
|
||||
shell_manager: self.shell_manager,
|
||||
call_info: self.call_info,
|
||||
input: input.into(),
|
||||
}
|
||||
|
@ -90,14 +93,19 @@ impl CommandArgs {
|
|||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<EvaluatedStaticCommandArgs, ShellError> {
|
||||
let host = self.host.clone();
|
||||
let env = self.env.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let input = self.input;
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -106,7 +114,7 @@ impl CommandArgs {
|
|||
registry: &CommandRegistry,
|
||||
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
|
||||
) -> Result<RunnableArgs<T>, ShellError> {
|
||||
let env = self.env.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let host = self.host.clone();
|
||||
let args = self.evaluate_once(registry)?;
|
||||
let (input, args) = args.split();
|
||||
|
@ -118,7 +126,7 @@ impl CommandArgs {
|
|||
context: RunnableContext {
|
||||
input: input,
|
||||
commands: registry.clone(),
|
||||
env,
|
||||
shell_manager,
|
||||
name: name_span,
|
||||
host,
|
||||
},
|
||||
|
@ -133,11 +141,11 @@ impl CommandArgs {
|
|||
) -> Result<RunnableRawArgs<T>, ShellError> {
|
||||
let raw_args = RawCommandArgs {
|
||||
host: self.host.clone(),
|
||||
env: self.env.clone(),
|
||||
shell_manager: self.shell_manager.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 args = self.evaluate_once(registry)?;
|
||||
let (input, args) = args.split();
|
||||
|
@ -149,7 +157,7 @@ impl CommandArgs {
|
|||
context: RunnableContext {
|
||||
input: input,
|
||||
commands: registry.clone(),
|
||||
env,
|
||||
shell_manager,
|
||||
name: name_span,
|
||||
host,
|
||||
},
|
||||
|
@ -161,18 +169,15 @@ impl CommandArgs {
|
|||
|
||||
pub struct RunnableContext {
|
||||
pub input: InputStream,
|
||||
pub env: Arc<Mutex<Environment>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub commands: CommandRegistry,
|
||||
pub name: Option<Span>,
|
||||
pub name: Span,
|
||||
}
|
||||
|
||||
impl RunnableContext {
|
||||
pub fn cwd(&self) -> PathBuf {
|
||||
let env = self.env.clone();
|
||||
let env = env.lock().unwrap();
|
||||
|
||||
env.path.clone()
|
||||
PathBuf::from(self.shell_manager.path())
|
||||
}
|
||||
|
||||
pub fn expect_command(&self, name: &str) -> Arc<Command> {
|
||||
|
@ -222,21 +227,21 @@ impl Deref for EvaluatedStaticCommandArgs {
|
|||
impl EvaluatedStaticCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<Mutex<dyn Host>>,
|
||||
env: Arc<Mutex<Environment>>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
input: impl Into<InputStream>,
|
||||
) -> EvaluatedStaticCommandArgs {
|
||||
EvaluatedStaticCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
env,
|
||||
shell_manager,
|
||||
call_info,
|
||||
},
|
||||
input: input.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_span(&self) -> Option<Span> {
|
||||
pub fn name_span(&self) -> Span {
|
||||
self.args.call_info.name_span
|
||||
}
|
||||
|
||||
|
@ -258,7 +263,7 @@ impl EvaluatedStaticCommandArgs {
|
|||
pub struct EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs,
|
||||
#[allow(unused)]
|
||||
input: Spanned<Value>,
|
||||
input: Tagged<Value>,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedFilterCommandArgs {
|
||||
|
@ -271,14 +276,14 @@ impl Deref for EvaluatedFilterCommandArgs {
|
|||
impl EvaluatedFilterCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<Mutex<dyn Host>>,
|
||||
env: Arc<Mutex<Environment>>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
input: Spanned<Value>,
|
||||
input: Tagged<Value>,
|
||||
) -> EvaluatedFilterCommandArgs {
|
||||
EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
env,
|
||||
shell_manager,
|
||||
call_info,
|
||||
},
|
||||
input,
|
||||
|
@ -290,7 +295,7 @@ impl EvaluatedFilterCommandArgs {
|
|||
#[get = "crate"]
|
||||
pub struct EvaluatedCommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub env: Arc<Mutex<Environment>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: CallInfo,
|
||||
}
|
||||
|
||||
|
@ -299,11 +304,11 @@ impl EvaluatedCommandArgs {
|
|||
&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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -311,11 +316,11 @@ impl EvaluatedCommandArgs {
|
|||
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)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
match positional {
|
||||
|
@ -332,31 +337,35 @@ impl EvaluatedCommandArgs {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CommandAction {
|
||||
ChangePath(PathBuf),
|
||||
ChangePath(String),
|
||||
AddSpanSource(Uuid, SpanSource),
|
||||
Exit,
|
||||
EnterShell(String),
|
||||
PreviousShell,
|
||||
NextShell,
|
||||
LeaveShell,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ReturnSuccess {
|
||||
Value(Spanned<Value>),
|
||||
Value(Tagged<Value>),
|
||||
Action(CommandAction),
|
||||
}
|
||||
|
||||
pub type ReturnValue = Result<ReturnSuccess, ShellError>;
|
||||
|
||||
impl From<Spanned<Value>> for ReturnValue {
|
||||
fn from(input: Spanned<Value>) -> ReturnValue {
|
||||
impl From<Tagged<Value>> for ReturnValue {
|
||||
fn from(input: Tagged<Value>) -> ReturnValue {
|
||||
Ok(ReturnSuccess::Value(input))
|
||||
}
|
||||
}
|
||||
|
||||
impl ReturnSuccess {
|
||||
pub fn change_cwd(path: PathBuf) -> ReturnValue {
|
||||
pub fn change_cwd(path: String) -> ReturnValue {
|
||||
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()))
|
||||
}
|
||||
|
||||
|
@ -365,7 +374,9 @@ impl ReturnSuccess {
|
|||
}
|
||||
|
||||
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> {
|
||||
let CommandArgs {
|
||||
host,
|
||||
env,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
} = args;
|
||||
|
||||
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 func = self.func;
|
||||
|
||||
|
@ -455,7 +466,8 @@ impl StaticCommand for FnFilterCommand {
|
|||
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) {
|
||||
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
||||
|
|
|
@ -11,11 +11,11 @@ pub struct Config;
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ConfigArgs {
|
||||
set: Option<(Spanned<String>, Spanned<Value>)>,
|
||||
get: Option<Spanned<String>>,
|
||||
clear: Spanned<bool>,
|
||||
remove: Option<Spanned<String>>,
|
||||
path: Spanned<bool>,
|
||||
set: Option<(Tagged<String>, Tagged<Value>)>,
|
||||
get: Option<Tagged<String>>,
|
||||
clear: Tagged<bool>,
|
||||
remove: Option<Tagged<String>>,
|
||||
path: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl StaticCommand for Config {
|
||||
|
@ -69,29 +69,41 @@ pub fn config(
|
|||
|
||||
config::write_config(&result)?;
|
||||
|
||||
return Ok(stream![Spanned::from_item(
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
Value::Object(result.into()),
|
||||
value.span()
|
||||
)]
|
||||
.from_input_stream());
|
||||
}
|
||||
|
||||
if let Spanned { item: true, span } = clear {
|
||||
if let Tagged {
|
||||
item: true,
|
||||
tag: Tag { span, .. },
|
||||
} = clear
|
||||
{
|
||||
result.clear();
|
||||
|
||||
config::write_config(&result)?;
|
||||
|
||||
return Ok(
|
||||
stream![Spanned::from_item(Value::Object(result.into()), span)].from_input_stream(),
|
||||
);
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
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()?;
|
||||
|
||||
return Ok(
|
||||
stream![Value::Primitive(Primitive::Path(path)).spanned(span)].from_input_stream(),
|
||||
);
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
Value::Primitive(Primitive::Path(path)),
|
||||
span
|
||||
)]
|
||||
.from_input_stream());
|
||||
}
|
||||
|
||||
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(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::parser::registry::{CommandRegistry, Signature};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn exit(_args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||
pub struct Exit;
|
||||
|
||||
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)?;
|
||||
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"First requires an amount",
|
||||
"needs parameter",
|
||||
args.name_span(),
|
||||
|
@ -23,7 +23,7 @@ pub fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
|||
return Err(ShellError::labeled_error(
|
||||
"Value is not a number",
|
||||
"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 csv::ReaderBuilder;
|
||||
|
||||
pub fn from_csv_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||
let mut reader = ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.from_reader(s.as_bytes());
|
||||
let span = span.into();
|
||||
let tag = tag.into();
|
||||
|
||||
let mut fields: VecDeque<String> = VecDeque::new();
|
||||
let mut iter = reader.records();
|
||||
|
@ -27,25 +27,22 @@ pub fn from_csv_string_to_value(
|
|||
if let Some(row_values) = iter.next() {
|
||||
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() {
|
||||
row.insert_spanned(
|
||||
row.insert_tagged(
|
||||
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 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Spanned {
|
||||
item: Value::List(rows),
|
||||
span,
|
||||
})
|
||||
Ok(Tagged::from_item(Value::List(rows), tag))
|
||||
}
|
||||
|
||||
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
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_csv_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as CSV",
|
||||
"piped data failed CSV parse",
|
||||
.map(move |a| {
|
||||
let value_tag = a.tag();
|
||||
match a.item {
|
||||
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",
|
||||
"input cannot be parsed as CSV",
|
||||
span,
|
||||
"value originates from here",
|
||||
value_tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
a.span(),
|
||||
)),
|
||||
},
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn convert_ini_second_to_nu_value(
|
||||
v: &HashMap<String, String>,
|
||||
span: impl Into<Span>,
|
||||
) -> Spanned<Value> {
|
||||
let mut second = SpannedDictBuilder::new(span);
|
||||
tag: impl Into<Tag>,
|
||||
) -> Tagged<Value> {
|
||||
let mut second = TaggedDictBuilder::new(tag);
|
||||
|
||||
for (key, value) in v.into_iter() {
|
||||
second.insert(key.clone(), Primitive::String(value.clone()));
|
||||
}
|
||||
|
||||
second.into_spanned_value()
|
||||
second.into_tagged_value()
|
||||
}
|
||||
|
||||
fn convert_ini_top_to_nu_value(
|
||||
v: &HashMap<String, HashMap<String, String>>,
|
||||
span: impl Into<Span>,
|
||||
) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
let mut top_level = SpannedDictBuilder::new(span);
|
||||
tag: impl Into<Tag>,
|
||||
) -> Tagged<Value> {
|
||||
let tag = tag.into();
|
||||
let mut top_level = TaggedDictBuilder::new(tag);
|
||||
|
||||
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(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||
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> {
|
||||
|
@ -44,20 +44,29 @@ pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
|
|||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(e) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as INI",
|
||||
format!("{:#?}", e),
|
||||
.map(move |a| {
|
||||
let value_tag = a.tag();
|
||||
match a.item {
|
||||
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",
|
||||
"input cannot be parsed as INI",
|
||||
span,
|
||||
"value originates from here",
|
||||
value_tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
a.span(),
|
||||
)),
|
||||
},
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,46 +1,46 @@
|
|||
use crate::object::base::OF64;
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let tag = tag.into();
|
||||
|
||||
match v {
|
||||
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) => {
|
||||
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::I64(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)).tagged(tag),
|
||||
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(
|
||||
a.iter()
|
||||
.map(|x| convert_json_value_to_nu_value(x, span))
|
||||
.map(|x| convert_json_value_to_nu_value(x, tag))
|
||||
.collect(),
|
||||
)
|
||||
.spanned(span),
|
||||
.tagged(tag),
|
||||
serde_hjson::Value::Object(o) => {
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
let mut collected = TaggedDictBuilder::new(tag);
|
||||
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(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> serde_hjson::Result<Spanned<Value>> {
|
||||
tag: impl Into<Tag>,
|
||||
) -> serde_hjson::Result<Tagged<Value>> {
|
||||
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(
|
||||
|
@ -53,20 +53,29 @@ pub fn from_json(
|
|||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as JSON",
|
||||
"piped data failed JSON parse",
|
||||
.map(move |a| {
|
||||
let value_tag = a.tag();
|
||||
match a.item {
|
||||
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",
|
||||
"input cannot be parsed as JSON",
|
||||
span,
|
||||
"value originates from here",
|
||||
value_tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
a.span(),
|
||||
)),
|
||||
},
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,44 +1,42 @@
|
|||
use crate::object::base::OF64;
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let tag = tag.into();
|
||||
|
||||
match v {
|
||||
toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span),
|
||||
toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).spanned(span),
|
||||
toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span),
|
||||
toml::Value::String(s) => {
|
||||
Value::Primitive(Primitive::String(String::from(s))).spanned(span)
|
||||
}
|
||||
toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag),
|
||||
toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).tagged(tag),
|
||||
toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).tagged(tag),
|
||||
toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))).tagged(tag),
|
||||
toml::Value::Array(a) => Value::List(
|
||||
a.iter()
|
||||
.map(|x| convert_toml_value_to_nu_value(x, span))
|
||||
.map(|x| convert_toml_value_to_nu_value(x, tag))
|
||||
.collect(),
|
||||
)
|
||||
.spanned(span),
|
||||
.tagged(tag),
|
||||
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) => {
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
let mut collected = TaggedDictBuilder::new(tag);
|
||||
|
||||
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(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||
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(
|
||||
|
@ -51,20 +49,29 @@ pub fn from_toml(
|
|||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as TOML",
|
||||
"piped data failed TOML parse",
|
||||
.map(move |a| {
|
||||
let value_tag = a.tag();
|
||||
match a.item {
|
||||
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",
|
||||
"input cannot be parsed as TOML",
|
||||
span,
|
||||
"value originates from here",
|
||||
value_tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
x => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
format!("{} originates from here", x.type_name()),
|
||||
value_tag.span,
|
||||
)),
|
||||
},
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn from_node_to_value<'a, 'd>(
|
||||
n: &roxmltree::Node<'a, 'd>,
|
||||
span: impl Into<Span>,
|
||||
) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let tag = tag.into();
|
||||
|
||||
if n.is_element() {
|
||||
let name = n.tag_name().name().trim().to_string();
|
||||
|
||||
let mut children_values = vec![];
|
||||
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()
|
||||
.filter(|x| match x {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(f)),
|
||||
..
|
||||
} => {
|
||||
|
@ -32,31 +29,31 @@ fn from_node_to_value<'a, 'd>(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
let mut collected = TaggedDictBuilder::new(tag);
|
||||
collected.insert(name.clone(), Value::List(children_values));
|
||||
|
||||
collected.into_spanned_value()
|
||||
collected.into_tagged_value()
|
||||
} else if n.is_comment() {
|
||||
Value::string("<comment>").spanned(span)
|
||||
Value::string("<comment>").tagged(tag)
|
||||
} else if n.is_pi() {
|
||||
Value::string("<processing_instruction>").spanned(span)
|
||||
Value::string("<processing_instruction>").tagged(tag)
|
||||
} else if n.is_text() {
|
||||
Value::string(n.text().unwrap()).spanned(span)
|
||||
Value::string(n.text().unwrap()).tagged(tag)
|
||||
} 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> {
|
||||
from_node_to_value(&d.root_element(), span)
|
||||
fn from_document_to_value(d: &roxmltree::Document, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
from_node_to_value(&d.root_element(), tag)
|
||||
}
|
||||
|
||||
pub fn from_xml_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Tagged<Value>, Box<dyn std::error::Error>> {
|
||||
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> {
|
||||
|
@ -65,20 +62,29 @@ pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputS
|
|||
let out = args.input;
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as XML",
|
||||
"piped data failed XML parse",
|
||||
.map(move |a| {
|
||||
let value_tag = a.tag();
|
||||
match a.item {
|
||||
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",
|
||||
"input cannot be parsed as XML",
|
||||
span,
|
||||
"value originates from here",
|
||||
value_tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
a.span(),
|
||||
)),
|
||||
},
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -1,51 +1,50 @@
|
|||
use crate::object::base::OF64;
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let span = span.into();
|
||||
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let tag = tag.into();
|
||||
|
||||
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() => {
|
||||
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() => {
|
||||
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(
|
||||
a.iter()
|
||||
.map(|x| convert_yaml_value_to_nu_value(x, span))
|
||||
.map(|x| convert_yaml_value_to_nu_value(x, tag))
|
||||
.collect(),
|
||||
)
|
||||
.spanned(span),
|
||||
.tagged(tag),
|
||||
serde_yaml::Value::Mapping(t) => {
|
||||
let mut collected = SpannedDictBuilder::new(span);
|
||||
let mut collected = TaggedDictBuilder::new(tag);
|
||||
|
||||
for (k, v) in t.iter() {
|
||||
match k {
|
||||
serde_yaml::Value::String(k) => {
|
||||
collected
|
||||
.insert_spanned(k.clone(), convert_yaml_value_to_nu_value(v, span));
|
||||
collected.insert_tagged(k.clone(), convert_yaml_value_to_nu_value(v, tag));
|
||||
}
|
||||
_ => 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),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_yaml_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> serde_yaml::Result<Spanned<Value>> {
|
||||
tag: impl Into<Tag>,
|
||||
) -> serde_yaml::Result<Tagged<Value>> {
|
||||
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(
|
||||
|
@ -57,20 +56,29 @@ pub fn from_yaml(
|
|||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s, span) {
|
||||
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Could not parse as YAML",
|
||||
"piped data failed YAML parse",
|
||||
.map(move |a| {
|
||||
let value_tag = a.tag();
|
||||
match a.item {
|
||||
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",
|
||||
"input cannot be parsed as YAML",
|
||||
span,
|
||||
"value originates from here",
|
||||
value_tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
a.span(),
|
||||
)),
|
||||
},
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
span,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ pub struct Get;
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetArgs {
|
||||
rest: Vec<Spanned<String>>,
|
||||
rest: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
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;
|
||||
for p in path.split(".") {
|
||||
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(
|
||||
"Unknown field",
|
||||
"object missing field",
|
||||
path.span,
|
||||
path.span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ pub fn get(
|
|||
let mut result = VecDeque::new();
|
||||
for field in &fields {
|
||||
match get_member(field, &item) {
|
||||
Ok(Spanned {
|
||||
Ok(Tagged {
|
||||
item: Value::List(l),
|
||||
..
|
||||
}) => {
|
||||
|
|
|
@ -23,17 +23,19 @@ pub fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
|||
let mut result = VecDeque::new();
|
||||
for s in split_result {
|
||||
result.push_back(ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(s.into())).spanned_unknown(),
|
||||
Value::Primitive(Primitive::String(s.into())).tagged_unknown(),
|
||||
));
|
||||
}
|
||||
result
|
||||
}
|
||||
_ => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
v.span(),
|
||||
)));
|
||||
result
|
||||
}
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{dir_entry_dict, Primitive, Value};
|
||||
use crate::parser::Spanned;
|
||||
use crate::object::dir_entry_dict;
|
||||
use crate::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
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 path = env.path.to_path_buf();
|
||||
let path = PathBuf::from(args.shell_manager.path());
|
||||
let mut full_path = PathBuf::from(path);
|
||||
match &args.nth(0) {
|
||||
Some(Spanned {
|
||||
Some(Tagged {
|
||||
item: Value::Primitive(Primitive::String(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(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
s.span,
|
||||
s.span(),
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
args.name_span(),
|
||||
|
@ -42,8 +39,19 @@ pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
|||
let mut shell_entries = VecDeque::new();
|
||||
|
||||
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))
|
||||
}
|
||||
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::object::{Primitive, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::parse::span::Span;
|
||||
use crate::parser::registry::{self, Signature};
|
||||
use crate::prelude::*;
|
||||
use mime::Mime;
|
||||
|
@ -15,7 +14,7 @@ pub struct Open;
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct OpenArgs {
|
||||
path: Spanned<PathBuf>,
|
||||
path: Tagged<PathBuf>,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
|
@ -41,24 +40,28 @@ impl StaticCommand for Open {
|
|||
|
||||
fn run(
|
||||
OpenArgs { raw, path }: OpenArgs,
|
||||
RunnableContext { env, name, .. }: RunnableContext,
|
||||
RunnableContext {
|
||||
shell_manager,
|
||||
name,
|
||||
..
|
||||
}: RunnableContext,
|
||||
) -> 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 path_str = path.to_str().ok_or(ShellError::type_error(
|
||||
"Path",
|
||||
"invalid path".spanned(path.span),
|
||||
"invalid path".tagged(path.tag()),
|
||||
))?;
|
||||
|
||||
let (file_extension, contents, contents_span, span_source) =
|
||||
fetch(&full_path, path_str, path.span)?;
|
||||
let (file_extension, contents, contents_tag, span_source) =
|
||||
fetch(&full_path, path_str, path.span())?;
|
||||
|
||||
let file_extension = if raw { None } else { file_extension };
|
||||
|
||||
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
|
||||
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
|
||||
uuid,
|
||||
|
@ -68,10 +71,10 @@ fn run(
|
|||
|
||||
match contents {
|
||||
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 {
|
||||
Spanned {
|
||||
Tagged {
|
||||
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())
|
||||
|
@ -149,7 +152,7 @@ pub fn fetch(
|
|||
cwd: &PathBuf,
|
||||
location: &str,
|
||||
span: Span,
|
||||
) -> Result<(Option<String>, Value, Span, SpanSource), ShellError> {
|
||||
) -> Result<(Option<String>, Value, Tag, SpanSource), ShellError> {
|
||||
let mut cwd = cwd.clone();
|
||||
if location.starts_with("http:") || location.starts_with("https:") {
|
||||
let response = reqwest::get(location);
|
||||
|
@ -161,13 +164,19 @@ pub fn fetch(
|
|||
(mime::APPLICATION, mime::XML) => Ok((
|
||||
Some("xml".to_string()),
|
||||
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()),
|
||||
)),
|
||||
(mime::APPLICATION, mime::JSON) => Ok((
|
||||
Some("json".to_string()),
|
||||
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()),
|
||||
)),
|
||||
(mime::APPLICATION, mime::OCTET_STREAM) => {
|
||||
|
@ -182,7 +191,10 @@ pub fn fetch(
|
|||
Ok((
|
||||
None,
|
||||
Value::Binary(buf),
|
||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
||||
Tag {
|
||||
span,
|
||||
origin: Some(Uuid::new_v4()),
|
||||
},
|
||||
SpanSource::Url(r.url().to_string()),
|
||||
))
|
||||
}
|
||||
|
@ -198,14 +210,20 @@ pub fn fetch(
|
|||
Ok((
|
||||
Some(image_ty.to_string()),
|
||||
Value::Binary(buf),
|
||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
||||
Tag {
|
||||
span,
|
||||
origin: Some(Uuid::new_v4()),
|
||||
},
|
||||
SpanSource::Url(r.url().to_string()),
|
||||
))
|
||||
}
|
||||
(mime::TEXT, mime::HTML) => Ok((
|
||||
Some("html".to_string()),
|
||||
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()),
|
||||
)),
|
||||
(mime::TEXT, mime::PLAIN) => {
|
||||
|
@ -223,14 +241,23 @@ pub fn fetch(
|
|||
Ok((
|
||||
path_extension,
|
||||
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()),
|
||||
))
|
||||
}
|
||||
(ty, sub_ty) => Ok((
|
||||
None,
|
||||
Value::string(format!("Not yet support MIME type: {} {}", ty, sub_ty)),
|
||||
Span::unknown_with_uuid(Uuid::new_v4()),
|
||||
Value::string(format!(
|
||||
"Not yet supported MIME type: {} {}",
|
||||
ty, sub_ty
|
||||
)),
|
||||
Tag {
|
||||
span,
|
||||
origin: Some(Uuid::new_v4()),
|
||||
},
|
||||
SpanSource::Url(r.url().to_string()),
|
||||
)),
|
||||
}
|
||||
|
@ -238,7 +265,10 @@ pub fn fetch(
|
|||
None => Ok((
|
||||
None,
|
||||
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()),
|
||||
)),
|
||||
},
|
||||
|
@ -258,13 +288,19 @@ pub fn fetch(
|
|||
cwd.extension()
|
||||
.map(|name| name.to_string_lossy().to_string()),
|
||||
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()),
|
||||
)),
|
||||
Err(_) => Ok((
|
||||
None,
|
||||
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()),
|
||||
)),
|
||||
},
|
||||
|
@ -282,69 +318,57 @@ pub fn fetch(
|
|||
pub fn parse_as_value(
|
||||
extension: Option<String>,
|
||||
contents: String,
|
||||
contents_span: Span,
|
||||
name_span: Option<Span>,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
contents_tag: Tag,
|
||||
name_span: Span,
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
match extension {
|
||||
Some(x) if x == "csv" => {
|
||||
crate::commands::from_csv::from_csv_string_to_value(contents, contents_span)
|
||||
.map(|c| c.spanned(contents_span))
|
||||
.map_err(move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
"Could not open as CSV",
|
||||
"could not open as CSV",
|
||||
name_span,
|
||||
)
|
||||
})
|
||||
}
|
||||
Some(x) if x == "csv" => crate::commands::from_csv::from_csv_string_to_value(
|
||||
contents,
|
||||
contents_tag,
|
||||
)
|
||||
.map_err(move |_| {
|
||||
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_span)
|
||||
.map(|c| c.spanned(contents_span))
|
||||
.map_err(move |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
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",
|
||||
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" => {
|
||||
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err(
|
||||
Some(x) if x == "json" => {
|
||||
crate::commands::from_json::from_json_string_to_value(contents, contents_tag).map_err(
|
||||
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",
|
||||
name_span,
|
||||
|
@ -353,9 +377,9 @@ pub fn parse_as_value(
|
|||
)
|
||||
}
|
||||
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 |_| {
|
||||
ShellError::maybe_labeled_error(
|
||||
ShellError::labeled_error(
|
||||
"Could not open as YAML",
|
||||
"could not open as YAML",
|
||||
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();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Pick requires fields",
|
||||
"needs parameter",
|
||||
span,
|
||||
|
@ -28,7 +28,7 @@ pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStrea
|
|||
|
||||
let objects = input
|
||||
.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())
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ pub fn filter_plugin(
|
|||
.spawn()
|
||||
.expect("Failed to spawn child process");
|
||||
|
||||
/*
|
||||
{
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
@ -90,41 +91,117 @@ pub fn filter_plugin(
|
|||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
*/
|
||||
let mut bos: VecDeque<Tagged<Value>> = VecDeque::new();
|
||||
bos.push_back(Value::Primitive(Primitive::BeginningOfStream).tagged_unknown());
|
||||
|
||||
let mut eos: VecDeque<Tagged<Value>> = VecDeque::new();
|
||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).tagged_unknown());
|
||||
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
let stream = bos
|
||||
.chain(args.input.values)
|
||||
.chain(eos)
|
||||
.map(move |v| match v {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::BeginningOfStream),
|
||||
..
|
||||
} => {
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("begin_filter", call_info.clone());
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||
|
||||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response = serde_json::from_str::<NuResult>(&input);
|
||||
match response {
|
||||
Ok(NuResult::response { params }) => match params {
|
||||
Ok(params) => params,
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(ReturnValue::Err(e));
|
||||
result
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing begin_filter response: {:?} {}",
|
||||
e, input
|
||||
))));
|
||||
result
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
e, input
|
||||
)));
|
||||
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();
|
||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).spanned_unknown());
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
.values
|
||||
.chain(eos)
|
||||
.map(move |v| match v {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::EndOfStream),
|
||||
..
|
||||
} => {
|
||||
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
|
||||
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
|
||||
|
||||
let _ = BufReader::new(stdout);
|
||||
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]);
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("end_filter", vec![]);
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
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");
|
||||
|
@ -152,7 +229,7 @@ pub fn filter_plugin(
|
|||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?} {}",
|
||||
"Error while processing filter response: {:?} {}",
|
||||
e, input
|
||||
))));
|
||||
result
|
||||
|
@ -162,7 +239,7 @@ pub fn filter_plugin(
|
|||
Err(e) => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::string(format!(
|
||||
"Error while processing input: {:?}",
|
||||
"Error while reading filter response: {:?}",
|
||||
e
|
||||
))));
|
||||
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
|
||||
.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<_>>();
|
||||
|
||||
Ok(list.from_input_stream())
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
|
|||
let (input, args) = args.parts();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Reject requires fields",
|
||||
"needs parameter",
|
||||
span,
|
||||
|
@ -26,11 +26,9 @@ pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStr
|
|||
|
||||
let fields = fields?;
|
||||
|
||||
let stream = input.values.map(move |item| {
|
||||
reject_fields(&item, &fields, item.span)
|
||||
.into_spanned_value()
|
||||
.spanned(name_span)
|
||||
});
|
||||
let stream = input
|
||||
.values
|
||||
.map(move |item| reject_fields(&item, &fields, item.tag()).into_tagged_value());
|
||||
|
||||
Ok(stream.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -2,13 +2,15 @@ use crate::commands::StaticCommand;
|
|||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::prelude::*;
|
||||
|
||||
use glob::glob;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Remove;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RemoveArgs {
|
||||
path: Spanned<PathBuf>,
|
||||
path: Tagged<PathBuf>,
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
|
@ -43,17 +45,32 @@ pub fn rm(
|
|||
file => full_path.push(file),
|
||||
}
|
||||
|
||||
if full_path.is_dir() {
|
||||
if !recursive {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"is a directory",
|
||||
"",
|
||||
context.name,
|
||||
));
|
||||
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 {
|
||||
return Err(ShellError::string(
|
||||
"is a directory",
|
||||
// "is a directory",
|
||||
// args.call_info.name_span,
|
||||
));
|
||||
}
|
||||
std::fs::remove_dir_all(&path).expect("can not remove directory");
|
||||
} else if path.is_file() {
|
||||
std::fs::remove_file(&path).expect("can not remove file");
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(ShellError::string(&format!("{:?}", e))),
|
||||
}
|
||||
std::fs::remove_dir_all(&full_path).expect("can not remove directory");
|
||||
} else if full_path.is_file() {
|
||||
std::fs::remove_file(&full_path).expect("can not remove file");
|
||||
}
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
|
|
|
@ -5,7 +5,6 @@ use crate::commands::to_yaml::value_to_yaml_value;
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::parser::Spanned;
|
||||
use crate::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -13,7 +12,7 @@ pub struct Save;
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SaveArgs {
|
||||
path: Spanned<PathBuf>,
|
||||
path: Tagged<PathBuf>,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
|
@ -48,7 +47,7 @@ pub fn save(
|
|||
full_path.push(path.item());
|
||||
|
||||
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() {
|
||||
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::object::{SpannedDictBuilder, Value};
|
||||
use crate::object::{TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
Ok(input
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
Value::Primitive(Primitive::String(s)) => ReturnSuccess::value(count(&s, v.span)),
|
||||
_ => Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
Some(v.span),
|
||||
Value::Primitive(Primitive::String(ref s)) => ReturnSuccess::value(count(s, v.tag())),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
v.span(),
|
||||
)),
|
||||
})
|
||||
.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 words: 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
|
||||
//dict.insert("name", Value::string(name));
|
||||
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("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
|
||||
.iter()
|
||||
.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<_>>()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
|
@ -14,7 +14,7 @@ pub fn split_column(
|
|||
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
|
||||
|
||||
if positional.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Split-column needs more information",
|
||||
"needs parameter (eg split-column \",\")",
|
||||
span,
|
||||
|
@ -24,7 +24,7 @@ pub fn split_column(
|
|||
Ok(input
|
||||
.values
|
||||
.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");
|
||||
trace!("splitting with {:?}", splitter);
|
||||
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));
|
||||
}
|
||||
|
||||
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()) {
|
||||
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) {
|
||||
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)) {
|
||||
dict.insert(
|
||||
v.as_string().unwrap(),
|
||||
Value::Primitive(Primitive::String(k.into())),
|
||||
);
|
||||
}
|
||||
ReturnSuccess::value(dict.into_spanned_value())
|
||||
ReturnSuccess::value(dict.into_tagged_value())
|
||||
} else {
|
||||
let mut dict = SpannedDictBuilder::new(v.span);
|
||||
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||
for k in positional.iter().skip(1) {
|
||||
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(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
v.span(),
|
||||
)),
|
||||
})
|
||||
.to_output_stream())
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::parser::Spanned;
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
|
@ -13,10 +12,10 @@ pub fn split_row(
|
|||
let len = args.len();
|
||||
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 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Split-row needs more information",
|
||||
"needs parameter (eg split-row \"\\n\")",
|
||||
span,
|
||||
|
@ -26,7 +25,7 @@ pub fn split_row(
|
|||
let stream = input
|
||||
.values
|
||||
.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");
|
||||
trace!("splitting with {:?}", splitter);
|
||||
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();
|
||||
for s in split_result {
|
||||
result.push_back(ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(s.into())).spanned(v.span),
|
||||
Value::Primitive(Primitive::String(s.into())).tagged(v.tag()),
|
||||
));
|
||||
}
|
||||
result
|
||||
}
|
||||
_ => {
|
||||
let mut result = VecDeque::new();
|
||||
result.push_back(Err(ShellError::maybe_labeled_error(
|
||||
"Expected string values from pipeline",
|
||||
"expects strings from pipeline",
|
||||
result.push_back(Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected a string from pipeline",
|
||||
"requires string input",
|
||||
span,
|
||||
"value originates from here",
|
||||
v.span(),
|
||||
)));
|
||||
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> {
|
||||
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 {
|
||||
let mut host = context.host.lock().unwrap();
|
||||
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();
|
||||
|
||||
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()
|
||||
.from_input_stream())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use crate::object::{Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
use csv::WriterBuilder;
|
||||
use log::debug;
|
||||
|
||||
pub fn value_to_csv_value(v: &Value) -> Value {
|
||||
debug!("value_to_csv_value(Value::Object(v)) where v = {:?}", v);
|
||||
|
||||
match v {
|
||||
Value::Primitive(Primitive::String(s)) => Value::Primitive(Primitive::String(s.clone())),
|
||||
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 {
|
||||
Value::List(_l) => return Ok(String::from("[list list]")),
|
||||
Value::Object(o) => {
|
||||
debug!("to_csv:to_string(Value::Object(v)) where v = {:?}", v);
|
||||
|
||||
let mut wtr = WriterBuilder::new().from_writer(vec![]);
|
||||
let mut fields: 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
|
||||
.values
|
||||
.map(move |a| match to_string(&value_to_csv_value(&a.item)) {
|
||||
Ok(x) => {
|
||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
||||
}
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Can not convert to CSV string",
|
||||
"can not convert piped data to CSV string",
|
||||
Ok(x) => ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
|
||||
),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected an object with CSV-compatible structure from pipeline",
|
||||
"requires CSV-compatible input",
|
||||
name_span,
|
||||
format!("{} originates from here", a.item.type_name()),
|
||||
a.span(),
|
||||
)),
|
||||
})
|
||||
.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::EndOfStream) => serde_json::Value::Null,
|
||||
Value::Primitive(Primitive::BeginningOfStream) => serde_json::Value::Null,
|
||||
Value::Primitive(Primitive::Float(f)) => {
|
||||
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
|
||||
.map(
|
||||
move |a| match serde_json::to_string(&value_to_json_value(&a)) {
|
||||
Ok(x) => {
|
||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
||||
}
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Can not convert to JSON string",
|
||||
"can not convert piped data to JSON string",
|
||||
Ok(x) => ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
|
||||
),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected an object with JSON-compatible structure from pipeline",
|
||||
"requires JSON-compatible input",
|
||||
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) => {
|
||||
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::Int(i)) => toml::Value::Integer(*i),
|
||||
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)) {
|
||||
Ok(val) => {
|
||||
return ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(val)).spanned(name_span),
|
||||
Value::Primitive(Primitive::String(val)).simple_spanned(name_span),
|
||||
)
|
||||
}
|
||||
|
||||
Err(err) => Err(ShellError::type_error(
|
||||
"Can not convert to a TOML string",
|
||||
format!("{:?} - {:?}", a.type_name(), err).spanned(name_span),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected an object with TOML-compatible structure from pipeline",
|
||||
"requires TOML-compatible input",
|
||||
name_span,
|
||||
format!("{} originates from here", a.item.type_name()),
|
||||
a.span(),
|
||||
)),
|
||||
})
|
||||
.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::EndOfStream) => serde_yaml::Value::Null,
|
||||
Value::Primitive(Primitive::BeginningOfStream) => serde_yaml::Value::Null,
|
||||
Value::Primitive(Primitive::Float(f)) => {
|
||||
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
|
||||
.map(
|
||||
move |a| match serde_yaml::to_string(&value_to_yaml_value(&a)) {
|
||||
Ok(x) => {
|
||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
||||
}
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Can not convert to YAML string",
|
||||
"can not convert piped data to YAML string",
|
||||
Ok(x) => ReturnSuccess::value(
|
||||
Value::Primitive(Primitive::String(x)).simple_spanned(name_span),
|
||||
),
|
||||
_ => Err(ShellError::labeled_error_with_secondary(
|
||||
"Expected an object with YAML-compatible structure from pipeline",
|
||||
"requires YAML-compatible input",
|
||||
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
|
||||
.map(move |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())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::commands::{Command, UnevaluatedCallInfo};
|
||||
use crate::parser::{hir, Span};
|
||||
use crate::parser::hir;
|
||||
use crate::prelude::*;
|
||||
|
||||
use derive_new::new;
|
||||
|
@ -75,7 +75,7 @@ pub struct Context {
|
|||
registry: CommandRegistry,
|
||||
crate source_map: SourceMap,
|
||||
crate host: Arc<Mutex<dyn Host + Send>>,
|
||||
crate env: Arc<Mutex<Environment>>,
|
||||
crate shell_manager: ShellManager,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
@ -88,7 +88,7 @@ impl Context {
|
|||
registry: CommandRegistry::new(),
|
||||
source_map: SourceMap::new(),
|
||||
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(
|
||||
&mut self,
|
||||
command: Arc<Command>,
|
||||
name_span: Option<Span>,
|
||||
name_span: Span,
|
||||
source_map: SourceMap,
|
||||
args: hir::Call,
|
||||
source: Text,
|
||||
input: InputStream,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
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
|
||||
}
|
||||
|
@ -133,7 +145,7 @@ impl Context {
|
|||
args: hir::Call,
|
||||
source: Text,
|
||||
source_map: SourceMap,
|
||||
name_span: Option<Span>,
|
||||
name_span: Span,
|
||||
) -> UnevaluatedCallInfo {
|
||||
UnevaluatedCallInfo {
|
||||
args,
|
||||
|
@ -149,11 +161,11 @@ impl Context {
|
|||
input: InputStream,
|
||||
source: Text,
|
||||
source_map: SourceMap,
|
||||
name_span: Option<Span>,
|
||||
name_span: Span,
|
||||
) -> CommandArgs {
|
||||
CommandArgs {
|
||||
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),
|
||||
input,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
crate mod environment;
|
||||
crate mod host;
|
||||
|
||||
crate use self::environment::Environment;
|
||||
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)]
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::parser::{Span, Spanned};
|
||||
use ansi_term::Color;
|
||||
use derive_new::new;
|
||||
use language_reporting::{Diagnostic, Label, Severity};
|
||||
|
@ -9,23 +8,18 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum Description {
|
||||
Source(Spanned<String>),
|
||||
Source(Tagged<String>),
|
||||
Synthetic(String),
|
||||
}
|
||||
|
||||
impl Description {
|
||||
pub fn from(item: Spanned<impl Into<String>>) -> Description {
|
||||
match item {
|
||||
Spanned {
|
||||
span:
|
||||
Span {
|
||||
start: 0,
|
||||
end: 0,
|
||||
source: None,
|
||||
},
|
||||
item,
|
||||
} => Description::Synthetic(item.into()),
|
||||
Spanned { span, item } => Description::Source(Spanned::from_item(item.into(), span)),
|
||||
pub fn from(value: Tagged<impl Into<String>>) -> Description {
|
||||
let value_span = value.span();
|
||||
let value_tag = value.tag();
|
||||
|
||||
match value_span {
|
||||
Span { start: 0, end: 0 } => Description::Synthetic(value.item.into()),
|
||||
_ => Description::Source(Tagged::from_item(value.item.into(), value_tag)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +27,7 @@ impl Description {
|
|||
impl Description {
|
||||
fn into_label(self) -> Result<Label<Span>, String> {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
@ -47,13 +41,13 @@ pub enum ArgumentError {
|
|||
}
|
||||
|
||||
pub fn labelled(
|
||||
span: impl Into<Option<Span>>,
|
||||
span: impl Into<Span>,
|
||||
heading: &'a str,
|
||||
span_message: &'a str,
|
||||
) -> impl FnOnce(ShellError) -> ShellError + 'a {
|
||||
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)]
|
||||
|
@ -74,7 +68,7 @@ impl serde::de::Error for ShellError {
|
|||
impl ShellError {
|
||||
crate fn type_error(
|
||||
expected: impl Into<String>,
|
||||
actual: Spanned<impl Into<String>>,
|
||||
actual: Tagged<impl Into<String>>,
|
||||
) -> ShellError {
|
||||
ProximateShellError::TypeError {
|
||||
expected: expected.into(),
|
||||
|
@ -84,8 +78,8 @@ impl ShellError {
|
|||
}
|
||||
|
||||
crate fn coerce_error(
|
||||
left: Spanned<impl Into<String>>,
|
||||
right: Spanned<impl Into<String>>,
|
||||
left: Tagged<impl Into<String>>,
|
||||
right: Tagged<impl Into<String>>,
|
||||
) -> ShellError {
|
||||
ProximateShellError::CoerceError {
|
||||
left: left.map(|l| l.into()),
|
||||
|
@ -175,9 +169,9 @@ impl ShellError {
|
|||
ProximateShellError::TypeError {
|
||||
expected,
|
||||
actual:
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Some(actual),
|
||||
span,
|
||||
tag: Tag { span, .. },
|
||||
},
|
||||
} => Diagnostic::new(Severity::Error, "Type Error").with_label(
|
||||
Label::new_primary(span)
|
||||
|
@ -186,7 +180,11 @@ impl ShellError {
|
|||
|
||||
ProximateShellError::TypeError {
|
||||
expected,
|
||||
actual: Spanned { item: None, span },
|
||||
actual:
|
||||
Tagged {
|
||||
item: None,
|
||||
tag: Tag { span, .. },
|
||||
},
|
||||
} => Diagnostic::new(Severity::Error, "Type Error")
|
||||
.with_label(Label::new_primary(span).with_message(expected)),
|
||||
|
||||
|
@ -211,8 +209,8 @@ impl ShellError {
|
|||
ProximateShellError::Diagnostic(diag) => diag.diagnostic,
|
||||
ProximateShellError::CoerceError { left, right } => {
|
||||
Diagnostic::new(Severity::Error, "Coercion error")
|
||||
.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_primary(left.span()).with_message(left.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>,
|
||||
label: impl Into<String>,
|
||||
span: Option<Span>,
|
||||
primary_label: impl Into<String>,
|
||||
primary_span: Span,
|
||||
secondary_label: impl Into<String>,
|
||||
secondary_span: Span,
|
||||
) -> ShellError {
|
||||
match span {
|
||||
Some(span) => ShellError::diagnostic(
|
||||
Diagnostic::new(Severity::Error, msg.into())
|
||||
.with_label(Label::new_primary(span).with_message(label.into())),
|
||||
),
|
||||
None => ShellError::string(msg),
|
||||
}
|
||||
ShellError::diagnostic(
|
||||
Diagnostic::new_error(msg.into())
|
||||
.with_label(Label::new_primary(primary_span).with_message(primary_label.into()))
|
||||
.with_label(
|
||||
Label::new_secondary(secondary_span).with_message(secondary_label.into()),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn string(title: impl Into<String>) -> ShellError {
|
||||
|
@ -260,7 +260,7 @@ pub enum ProximateShellError {
|
|||
String(StringError),
|
||||
TypeError {
|
||||
expected: String,
|
||||
actual: Spanned<Option<String>>,
|
||||
actual: Tagged<Option<String>>,
|
||||
},
|
||||
MissingProperty {
|
||||
subpath: Description,
|
||||
|
@ -273,8 +273,8 @@ pub enum ProximateShellError {
|
|||
},
|
||||
Diagnostic(ShellDiagnostic),
|
||||
CoerceError {
|
||||
left: Spanned<String>,
|
||||
right: Spanned<String>,
|
||||
left: Tagged<String>,
|
||||
right: Tagged<String>,
|
||||
},
|
||||
}
|
||||
impl ProximateShellError {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::Description;
|
|||
use crate::object::base::Block;
|
||||
use crate::parser::{
|
||||
hir::{self, Expression, RawExpression},
|
||||
CommandRegistry, Spanned, Text,
|
||||
CommandRegistry, Text,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
|
@ -10,20 +10,20 @@ use indexmap::IndexMap;
|
|||
|
||||
#[derive(new)]
|
||||
pub struct Scope {
|
||||
it: Spanned<Value>,
|
||||
it: Tagged<Value>,
|
||||
#[new(default)]
|
||||
vars: IndexMap<String, Spanned<Value>>,
|
||||
vars: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
crate fn empty() -> Scope {
|
||||
Scope {
|
||||
it: Value::nothing().spanned_unknown(),
|
||||
it: Value::nothing().tagged_unknown(),
|
||||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn it_value(value: Spanned<Value>) -> Scope {
|
||||
crate fn it_value(value: Tagged<Value>) -> Scope {
|
||||
Scope {
|
||||
it: value,
|
||||
vars: IndexMap::new(),
|
||||
|
@ -36,19 +36,20 @@ crate fn evaluate_baseline_expr(
|
|||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
match &expr.item {
|
||||
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
|
||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => {
|
||||
Ok(Value::string(s).spanned_unknown())
|
||||
}
|
||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => Ok(Value::string(s).tagged_unknown()),
|
||||
RawExpression::Variable(var) => evaluate_reference(var, scope, source),
|
||||
RawExpression::Binary(binary) => {
|
||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
|
||||
|
||||
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(
|
||||
binary.left().copy_span(left_type),
|
||||
binary.right().copy_span(right_type),
|
||||
|
@ -63,10 +64,10 @@ crate fn evaluate_baseline_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(
|
||||
Value::Block(Block::new(block.clone(), source.clone(), *expr.span())),
|
||||
RawExpression::Block(block) => Ok(Tagged::from_simple_spanned_item(
|
||||
Value::Block(Block::new(block.clone(), source.clone(), expr.span())),
|
||||
expr.span(),
|
||||
)),
|
||||
RawExpression::Path(path) => {
|
||||
|
@ -79,12 +80,12 @@ crate fn evaluate_baseline_expr(
|
|||
match next {
|
||||
None => {
|
||||
return Err(ShellError::missing_property(
|
||||
Description::from(item.spanned_type_name()),
|
||||
Description::from(item.tagged_type_name()),
|
||||
Description::from(name.clone()),
|
||||
))
|
||||
}
|
||||
Some(next) => {
|
||||
item = Spanned::from_item(
|
||||
item = Tagged::from_simple_spanned_item(
|
||||
next.clone().item,
|
||||
(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!(),
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
hir::Literal::Integer(int) => Value::int(int),
|
||||
hir::Literal::Size(int, unit) => unit.compute(int),
|
||||
|
@ -113,13 +117,13 @@ fn evaluate_reference(
|
|||
name: &hir::Variable,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
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
|
||||
.vars
|
||||
.get(span.slice(source))
|
||||
.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 {
|
||||
fn merge_descriptors(values: &[Spanned<Value>]) -> Vec<String> {
|
||||
fn merge_descriptors(values: &[Tagged<Value>]) -> Vec<String> {
|
||||
let mut ret = vec![];
|
||||
for value in values {
|
||||
for desc in value.data_descriptors() {
|
||||
|
@ -26,7 +26,7 @@ impl TableView {
|
|||
ret
|
||||
}
|
||||
|
||||
pub fn from_list(values: &[Spanned<Value>]) -> Option<TableView> {
|
||||
pub fn from_list(values: &[Tagged<Value>]) -> Option<TableView> {
|
||||
if values.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ pub struct 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 {
|
||||
return None;
|
||||
}
|
||||
|
|
|
@ -31,14 +31,15 @@ mod traits;
|
|||
mod utils;
|
||||
|
||||
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::parser::parse::span::SpannedItem;
|
||||
pub use crate::parser::Spanned;
|
||||
pub use crate::object::base::OF64;
|
||||
pub use crate::plugin::{serve_plugin, Plugin};
|
||||
pub use crate::utils::{AbsolutePath, RelativePath};
|
||||
pub use cli::cli;
|
||||
pub use errors::ShellError;
|
||||
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::registry::{EvaluatedArgs, NamedType, PositionalType, Signature};
|
||||
|
|
|
@ -3,10 +3,11 @@ crate mod config;
|
|||
crate mod dict;
|
||||
crate mod files;
|
||||
crate mod into;
|
||||
crate mod meta;
|
||||
crate mod process;
|
||||
crate mod types;
|
||||
|
||||
#[allow(unused)]
|
||||
crate use base::{Block, Primitive, Switch, Value};
|
||||
crate use dict::{Dictionary, SpannedDictBuilder};
|
||||
crate use dict::{Dictionary, TaggedDictBuilder};
|
||||
crate use files::dir_entry_dict;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::context::CommandRegistry;
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||
use crate::object::SpannedDictBuilder;
|
||||
use crate::parser::{hir, Operator, Span, Spanned};
|
||||
use crate::object::TaggedDictBuilder;
|
||||
use crate::parser::{hir, Operator};
|
||||
use crate::prelude::*;
|
||||
use crate::Text;
|
||||
use ansi_term::Color;
|
||||
|
@ -44,6 +44,8 @@ pub enum Primitive {
|
|||
Date(DateTime<Utc>),
|
||||
Path(PathBuf),
|
||||
|
||||
// Stream markers (used as bookend markers rather than actual values)
|
||||
BeginningOfStream,
|
||||
EndOfStream,
|
||||
}
|
||||
|
||||
|
@ -53,6 +55,7 @@ impl Primitive {
|
|||
|
||||
match self {
|
||||
Nothing => "nothing",
|
||||
BeginningOfStream => "beginning-of-stream",
|
||||
EndOfStream => "end-of-stream",
|
||||
Path(_) => "path",
|
||||
Int(_) => "int",
|
||||
|
@ -70,6 +73,7 @@ impl Primitive {
|
|||
|
||||
match self {
|
||||
Nothing => write!(f, "Nothing"),
|
||||
BeginningOfStream => write!(f, "BeginningOfStream"),
|
||||
EndOfStream => write!(f, "EndOfStream"),
|
||||
Int(int) => write!(f, "{}", int),
|
||||
Path(path) => write!(f, "{}", path.display()),
|
||||
|
@ -84,6 +88,7 @@ impl Primitive {
|
|||
pub fn format(&self, field_name: Option<&String>) -> String {
|
||||
match self {
|
||||
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::BeginningOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
|
||||
Primitive::Path(p) => format!("{}", p.display()),
|
||||
Primitive::Bytes(b) => {
|
||||
|
@ -131,11 +136,11 @@ pub struct 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());
|
||||
|
||||
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;
|
||||
|
@ -159,17 +164,17 @@ pub enum Value {
|
|||
Object(crate::object::Dictionary),
|
||||
#[serde(with = "serde_bytes")]
|
||||
Binary(Vec<u8>),
|
||||
List(Vec<Spanned<Value>>),
|
||||
List(Vec<Tagged<Value>>),
|
||||
#[allow(unused)]
|
||||
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 }
|
||||
}
|
||||
|
||||
pub struct ValuesDebug<'a> {
|
||||
values: &'a Vec<Spanned<Value>>,
|
||||
values: &'a Vec<Tagged<Value>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ValuesDebug<'a> {
|
||||
|
@ -181,7 +186,7 @@ impl fmt::Debug for ValuesDebug<'a> {
|
|||
}
|
||||
|
||||
pub struct ValueDebug<'a> {
|
||||
value: &'a Spanned<Value>,
|
||||
value: &'a Tagged<Value>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ValueDebug<'a> {
|
||||
|
@ -196,17 +201,17 @@ impl fmt::Debug for ValueDebug<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Spanned<Value> {
|
||||
crate fn spanned_type_name(&self) -> Spanned<String> {
|
||||
impl Tagged<Value> {
|
||||
crate fn tagged_type_name(&self) -> Tagged<String> {
|
||||
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;
|
||||
|
||||
fn try_from(value: &'a Spanned<Value>) -> Result<Block, ShellError> {
|
||||
fn try_from(value: &'a Tagged<Value>) -> Result<Block, ShellError> {
|
||||
match value.item() {
|
||||
Value::Block(block) => Ok(block.clone()),
|
||||
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;
|
||||
|
||||
fn try_from(value: &'a Spanned<Value>) -> Result<i64, ShellError> {
|
||||
fn try_from(value: &'a Tagged<Value>) -> Result<i64, ShellError> {
|
||||
match value.item() {
|
||||
Value::Primitive(Primitive::Int(int)) => Ok(*int),
|
||||
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;
|
||||
|
||||
fn try_from(value: Option<&'a Spanned<Value>>) -> Result<Switch, ShellError> {
|
||||
fn try_from(value: Option<&'a Tagged<Value>>) -> Result<Switch, ShellError> {
|
||||
match value {
|
||||
None => Ok(Switch::Absent),
|
||||
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> {
|
||||
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 {
|
||||
Value::Object(o) => o.get_data_by_key(name),
|
||||
Value::List(l) => {
|
||||
for item in l {
|
||||
match item {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Object(o),
|
||||
..
|
||||
} => match o.get_data_by_key(name) {
|
||||
|
@ -319,14 +324,14 @@ impl Value {
|
|||
}
|
||||
|
||||
#[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 {
|
||||
Value::List(l) => l.iter().nth(idx),
|
||||
_ => 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;
|
||||
for p in path.split(".") {
|
||||
match current.get_data_by_key(p) {
|
||||
|
@ -335,18 +340,15 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
Some(Spanned {
|
||||
item: current,
|
||||
span,
|
||||
})
|
||||
Some(Tagged::from_item(current, tag))
|
||||
}
|
||||
|
||||
pub fn insert_data_at_path(
|
||||
&'a self,
|
||||
span: Span,
|
||||
tag: Tag,
|
||||
path: &str,
|
||||
new_value: Value,
|
||||
) -> Option<Spanned<Value>> {
|
||||
) -> Option<Tagged<Value>> {
|
||||
let mut new_obj = self.clone();
|
||||
|
||||
let split_path: Vec<_> = path.split(".").collect();
|
||||
|
@ -361,19 +363,13 @@ impl Value {
|
|||
Value::Object(o) => {
|
||||
o.entries.insert(
|
||||
split_path[idx + 1].to_string(),
|
||||
Spanned {
|
||||
item: new_value,
|
||||
span,
|
||||
},
|
||||
Tagged::from_item(new_value, tag),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
return Some(Spanned {
|
||||
item: new_obj,
|
||||
span,
|
||||
});
|
||||
return Some(Tagged::from_item(new_obj, tag));
|
||||
} else {
|
||||
match next.item {
|
||||
Value::Object(ref mut o) => {
|
||||
|
@ -393,10 +389,10 @@ impl Value {
|
|||
|
||||
pub fn replace_data_at_path(
|
||||
&'a self,
|
||||
span: Span,
|
||||
tag: Tag,
|
||||
path: &str,
|
||||
replaced_value: Value,
|
||||
) -> Option<Spanned<Value>> {
|
||||
) -> Option<Tagged<Value>> {
|
||||
let mut new_obj = self.clone();
|
||||
|
||||
let split_path: Vec<_> = path.split(".").collect();
|
||||
|
@ -407,14 +403,8 @@ impl Value {
|
|||
match current.entries.get_mut(split_path[idx]) {
|
||||
Some(next) => {
|
||||
if idx == (split_path.len() - 1) {
|
||||
*next = Spanned {
|
||||
item: replaced_value,
|
||||
span,
|
||||
};
|
||||
return Some(Spanned {
|
||||
item: new_obj,
|
||||
span,
|
||||
});
|
||||
*next = Tagged::from_item(replaced_value, tag);
|
||||
return Some(Tagged::from_item(new_obj, tag));
|
||||
} else {
|
||||
match next.item {
|
||||
Value::Object(ref mut o) => {
|
||||
|
@ -451,8 +441,12 @@ impl Value {
|
|||
.map(|e| e.source(&b.source).to_string()),
|
||||
"; ",
|
||||
),
|
||||
Value::Object(_) => format!("[object Object]"),
|
||||
Value::List(_) => format!("[list List]"),
|
||||
Value::Object(_) => format!("[{}]", self.type_name()),
|
||||
Value::List(l) => format!(
|
||||
"[{} {}]",
|
||||
l.len(),
|
||||
if l.len() == 1 { "item" } else { "items" }
|
||||
),
|
||||
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> {
|
||||
match self {
|
||||
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> {
|
||||
let mut out = SpannedDictBuilder::new(span);
|
||||
crate fn select_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let mut out = TaggedDictBuilder::new(tag);
|
||||
|
||||
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> {
|
||||
let mut out = SpannedDictBuilder::new(span);
|
||||
crate fn reject_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let mut out = TaggedDictBuilder::new(tag);
|
||||
|
||||
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)]
|
||||
|
|
|
@ -19,7 +19,7 @@ const APP_INFO: AppInfo = AppInfo {
|
|||
#[derive(Deserialize, Serialize)]
|
||||
struct Config {
|
||||
#[serde(flatten)]
|
||||
extra: IndexMap<String, Value>,
|
||||
extra: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
|
||||
crate fn config_path() -> Result<PathBuf, ShellError> {
|
||||
|
@ -29,7 +29,7 @@ crate fn config_path() -> Result<PathBuf, ShellError> {
|
|||
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)
|
||||
.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(())
|
||||
}
|
||||
|
||||
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 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());
|
||||
|
||||
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)))?;
|
||||
|
||||
let parsed: toml::Value = toml::from_str(&contents)
|
||||
.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 {
|
||||
Value::Object(Dictionary { entries }) => Ok(entries),
|
||||
other => Err(ShellError::type_error(
|
||||
"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)]
|
||||
pub struct Dictionary {
|
||||
pub entries: IndexMap<String, Spanned<Value>>,
|
||||
pub entries: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
|
||||
impl PartialOrd for Dictionary {
|
||||
|
@ -28,8 +28,8 @@ impl PartialOrd for Dictionary {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<IndexMap<String, Spanned<Value>>> for Dictionary {
|
||||
fn from(input: IndexMap<String, Spanned<Value>>) -> Dictionary {
|
||||
impl From<IndexMap<String, Tagged<Value>>> for Dictionary {
|
||||
fn from(input: IndexMap<String, Tagged<Value>>) -> Dictionary {
|
||||
let mut out = IndexMap::default();
|
||||
|
||||
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
|
||||
.entries
|
||||
.iter()
|
||||
|
@ -101,72 +101,71 @@ impl Dictionary {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SpannedListBuilder {
|
||||
span: Span,
|
||||
list: Vec<Spanned<Value>>,
|
||||
pub struct TaggedListBuilder {
|
||||
tag: Tag,
|
||||
list: Vec<Tagged<Value>>,
|
||||
}
|
||||
|
||||
impl SpannedListBuilder {
|
||||
pub fn new(span: impl Into<Span>) -> SpannedListBuilder {
|
||||
SpannedListBuilder {
|
||||
span: span.into(),
|
||||
impl TaggedListBuilder {
|
||||
pub fn new(tag: impl Into<Tag>) -> TaggedListBuilder {
|
||||
TaggedListBuilder {
|
||||
tag: tag.into(),
|
||||
list: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
||||
Value::List(self.list).spanned(self.span)
|
||||
pub fn into_tagged_value(self) -> Tagged<Value> {
|
||||
Value::List(self.list).tagged(self.tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpannedListBuilder> for Spanned<Value> {
|
||||
fn from(input: SpannedListBuilder) -> Spanned<Value> {
|
||||
input.into_spanned_value()
|
||||
impl From<TaggedListBuilder> for Tagged<Value> {
|
||||
fn from(input: TaggedListBuilder) -> Tagged<Value> {
|
||||
input.into_tagged_value()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SpannedDictBuilder {
|
||||
span: Span,
|
||||
dict: IndexMap<String, Spanned<Value>>,
|
||||
pub struct TaggedDictBuilder {
|
||||
tag: Tag,
|
||||
dict: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
|
||||
impl SpannedDictBuilder {
|
||||
pub fn new(span: impl Into<Span>) -> SpannedDictBuilder {
|
||||
SpannedDictBuilder {
|
||||
span: span.into(),
|
||||
impl TaggedDictBuilder {
|
||||
pub fn new(tag: impl Into<Tag>) -> TaggedDictBuilder {
|
||||
TaggedDictBuilder {
|
||||
tag: tag.into(),
|
||||
dict: IndexMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
|
||||
self.dict
|
||||
.insert(key.into(), value.into().spanned(self.span));
|
||||
self.dict.insert(key.into(), value.into().tagged(self.tag));
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
||||
self.into_spanned_dict().map(Value::Object)
|
||||
pub fn into_tagged_value(self) -> Tagged<Value> {
|
||||
self.into_tagged_dict().map(Value::Object)
|
||||
}
|
||||
|
||||
pub fn into_spanned_dict(self) -> Spanned<Dictionary> {
|
||||
Dictionary { entries: self.dict }.spanned(self.span)
|
||||
pub fn into_tagged_dict(self) -> Tagged<Dictionary> {
|
||||
Dictionary { entries: self.dict }.tagged(self.tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpannedDictBuilder> for Spanned<Value> {
|
||||
fn from(input: SpannedDictBuilder) -> Spanned<Value> {
|
||||
input.into_spanned_value()
|
||||
impl From<TaggedDictBuilder> for Tagged<Value> {
|
||||
fn from(input: TaggedDictBuilder) -> Tagged<Value> {
|
||||
input.into_tagged_value()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::object::{SpannedDictBuilder, Value};
|
||||
use crate::object::{TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -10,15 +10,13 @@ pub enum FileType {
|
|||
}
|
||||
|
||||
crate fn dir_entry_dict(
|
||||
entry: &std::fs::DirEntry,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
let filename = entry.file_name();
|
||||
filename: &std::path::Path,
|
||||
metadata: &std::fs::Metadata,
|
||||
tag: impl Into<Tag>,
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
let mut dict = TaggedDictBuilder::new(tag);
|
||||
dict.insert("name", Value::string(filename.to_string_lossy()));
|
||||
|
||||
let metadata = entry.metadata()?;
|
||||
|
||||
let kind = if metadata.is_dir() {
|
||||
FileType::Directory
|
||||
} else if metadata.is_file() {
|
||||
|
@ -50,5 +48,5 @@ crate fn dir_entry_dict(
|
|||
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> {
|
||||
pub fn into_spanned_value(self) -> Spanned<Value> {
|
||||
let Spanned { item, span } = self;
|
||||
|
||||
let value = item.into();
|
||||
value.spanned(span)
|
||||
impl<T: Into<Value>> Tagged<T> {
|
||||
pub fn into_tagged_value(self) -> Tagged<Value> {
|
||||
let value_span = self.span();
|
||||
let value = self.item.into();
|
||||
value.simple_spanned(value_span)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,43 +6,44 @@ use serde::Deserialize;
|
|||
use serde::Serialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(
|
||||
new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters,
|
||||
)]
|
||||
#[get = "crate"]
|
||||
pub struct Spanned<T> {
|
||||
pub span: Span,
|
||||
#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
pub struct Tagged<T> {
|
||||
pub tag: Tag,
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
impl<T> HasSpan for Spanned<T> {
|
||||
impl<T> HasSpan for Tagged<T> {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
self.tag.span
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Spanned<T> {
|
||||
pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> {
|
||||
Spanned::from_item(self.item, span.into())
|
||||
pub trait TaggedItem: Sized {
|
||||
fn tagged(self, tag: impl Into<Tag>) -> Tagged<Self> {
|
||||
Tagged::from_item(self, tag.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpannedItem: Sized {
|
||||
fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
|
||||
Spanned::from_item(self, span.into())
|
||||
fn simple_spanned(self, span: impl Into<Span>) -> Tagged<Self> {
|
||||
Tagged::from_simple_spanned_item(self, span.into())
|
||||
}
|
||||
|
||||
// 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
|
||||
// have the infrastructure to make that work.
|
||||
fn spanned_unknown(self) -> Spanned<Self> {
|
||||
Spanned::from_item(self, (0, 0))
|
||||
fn tagged_unknown(self) -> Tagged<Self> {
|
||||
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;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
|
@ -50,58 +51,71 @@ impl<T> std::ops::Deref for Spanned<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Spanned<T> {
|
||||
crate fn from_item(item: T, span: impl Into<Span>) -> Spanned<T> {
|
||||
Spanned {
|
||||
span: span.into(),
|
||||
impl<T> Tagged<T> {
|
||||
pub fn spanned(self, span: impl Into<Span>) -> Tagged<T> {
|
||||
Tagged::from_item(
|
||||
self.item,
|
||||
Tag {
|
||||
span: span.into(),
|
||||
origin: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from_item(item: T, tag: impl Into<Tag>) -> Tagged<T> {
|
||||
Tagged {
|
||||
item,
|
||||
tag: tag.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Spanned<U> {
|
||||
let Spanned { span, item } = self;
|
||||
|
||||
let mapped = input(item);
|
||||
Spanned { span, item: mapped }
|
||||
pub fn from_simple_spanned_item(item: T, span: impl Into<Span>) -> Tagged<T> {
|
||||
Tagged::from_item(
|
||||
item,
|
||||
Tag {
|
||||
span: span.into(),
|
||||
origin: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
crate fn copy_span<U>(&self, output: U) -> Spanned<U> {
|
||||
let Spanned { span, .. } = self;
|
||||
pub fn map<U>(self, input: impl FnOnce(T) -> U) -> Tagged<U> {
|
||||
let tag = self.tag();
|
||||
|
||||
Spanned {
|
||||
span: *span,
|
||||
item: output,
|
||||
}
|
||||
let mapped = input(self.item);
|
||||
Tagged::from_item(mapped, tag.clone())
|
||||
}
|
||||
|
||||
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 {
|
||||
Text::from(self.span().slice(source))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
pub struct Span {
|
||||
crate start: usize,
|
||||
crate end: usize,
|
||||
pub source: Option<Uuid>,
|
||||
}
|
||||
pub fn span(&self) -> Span {
|
||||
self.tag.span
|
||||
}
|
||||
|
||||
impl From<Option<Span>> for Span {
|
||||
fn from(input: Option<Span>) -> Span {
|
||||
match input {
|
||||
None => Span {
|
||||
start: 0,
|
||||
end: 0,
|
||||
source: None,
|
||||
},
|
||||
Some(span) => span,
|
||||
}
|
||||
pub fn tag(&self) -> Tag {
|
||||
self.tag
|
||||
}
|
||||
|
||||
pub fn origin(&self) -> Option<uuid::Uuid> {
|
||||
self.tag.origin
|
||||
}
|
||||
|
||||
pub fn item(&self) -> &T {
|
||||
&self.item
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&Spanned<T>> for Span {
|
||||
fn from(input: &Spanned<T>) -> Span {
|
||||
input.span
|
||||
impl<T> From<&Tagged<T>> for Span {
|
||||
fn from(input: &Tagged<T>) -> Span {
|
||||
input.span()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +130,6 @@ impl From<nom5_locate::LocatedSpan<&str>> for Span {
|
|||
Span {
|
||||
start: input.offset,
|
||||
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 {
|
||||
start: input.0.offset,
|
||||
end: input.1.offset,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +148,6 @@ impl From<(usize, usize)> for Span {
|
|||
Span {
|
||||
start: input.0,
|
||||
end: input.1,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,20 +157,52 @@ impl From<&std::ops::Range<usize>> for Span {
|
|||
Span {
|
||||
start: input.start,
|
||||
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 {
|
||||
pub fn unknown() -> Span {
|
||||
Span {
|
||||
start: 0,
|
||||
end: 0,
|
||||
source: None,
|
||||
}
|
||||
Span { start: 0, end: 0 }
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn unknown_with_uuid(uuid: Uuid) -> Span {
|
||||
Span {
|
||||
start: 0,
|
||||
|
@ -167,6 +210,7 @@ impl Span {
|
|||
source: Some(uuid),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn is_unknown(&self) -> bool {
|
||||
self.start == 0 && self.end == 0
|
||||
|
@ -182,7 +226,6 @@ impl language_reporting::ReportingSpan for Span {
|
|||
Span {
|
||||
start,
|
||||
end: self.end,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +233,6 @@ impl language_reporting::ReportingSpan for Span {
|
|||
Span {
|
||||
start: self.start,
|
||||
end,
|
||||
source: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
use crate::object::{SpannedDictBuilder, Value};
|
||||
use crate::object::{TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use itertools::join;
|
||||
use sysinfo::ProcessExt;
|
||||
|
||||
crate fn process_dict(proc: &sysinfo::Process, span: impl Into<Span>) -> Spanned<Value> {
|
||||
let mut dict = SpannedDictBuilder::new(span);
|
||||
dict.insert("name", Value::string(proc.name()));
|
||||
crate fn process_dict(proc: &sysinfo::Process, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let mut dict = TaggedDictBuilder::new(tag);
|
||||
|
||||
let cmd = proc.cmd();
|
||||
|
||||
|
@ -15,10 +14,16 @@ crate fn process_dict(proc: &sysinfo::Process, span: impl Into<Span>) -> Spanned
|
|||
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("status", Value::string(proc.status().to_string()));
|
||||
dict.insert("cpu", Value::float(proc.cpu_usage() as f64));
|
||||
//dict.insert("name", Value::string(proc.name()));
|
||||
match cmd_value {
|
||||
Value::Primitive(Primitive::Nothing) => {
|
||||
dict.insert("name", Value::string(proc.name()));
|
||||
}
|
||||
_ => dict.insert("name", cmd_value),
|
||||
}
|
||||
|
||||
dict.into_spanned_value()
|
||||
dict.into_tagged_value()
|
||||
}
|
||||
|
|
|
@ -5,15 +5,15 @@ use log::trace;
|
|||
use std::path::PathBuf;
|
||||
|
||||
pub trait ExtractType: Sized {
|
||||
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError>;
|
||||
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError>;
|
||||
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError>;
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError>;
|
||||
fn syntax_type() -> hir::SyntaxType {
|
||||
hir::SyntaxType::Any
|
||||
}
|
||||
}
|
||||
|
||||
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>();
|
||||
Err(ShellError::unimplemented(format!(
|
||||
"<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"))
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,8 @@ impl<T> ExtractType for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ExtractType> ExtractType for Vec<Spanned<T>> {
|
||||
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError> {
|
||||
impl<T: ExtractType> ExtractType for Vec<Tagged<T>> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError> {
|
||||
let name = std::intrinsics::type_name::<T>();
|
||||
trace!("<Vec> Extracting {:?} for Vec<{}>", value, name);
|
||||
|
||||
|
@ -40,24 +40,24 @@ impl<T: ExtractType> ExtractType for Vec<Spanned<T>> {
|
|||
let mut out = vec![];
|
||||
|
||||
for item in items {
|
||||
out.push(T::extract(item)?.spanned(item.span));
|
||||
out.push(T::extract(item)?.tagged(item.tag()));
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
other => Err(ShellError::type_error(
|
||||
"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() {
|
||||
Value::List(_) => Ok(value),
|
||||
other => Err(ShellError::type_error(
|
||||
"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) {
|
||||
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 u_name = std::intrinsics::type_name::<U>();
|
||||
|
||||
|
@ -84,20 +84,20 @@ impl<T: ExtractType, U: ExtractType> ExtractType for (T, U) {
|
|||
} else {
|
||||
Err(ShellError::type_error(
|
||||
"two-element-tuple",
|
||||
"not-two".spanned(value.span),
|
||||
"not-two".tagged(value.tag()),
|
||||
))
|
||||
}
|
||||
}
|
||||
other => Err(ShellError::type_error(
|
||||
"two-element-tuple",
|
||||
other.type_name().spanned(value.span),
|
||||
other.type_name().tagged(value.tag()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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>();
|
||||
trace!("<Option> Extracting {:?} for Option<{}>", value, name);
|
||||
|
||||
|
@ -109,7 +109,7 @@ impl<T: ExtractType> ExtractType for Option<T> {
|
|||
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() {
|
||||
Value::Primitive(Primitive::Nothing) => Ok(value),
|
||||
_ => T::check(value),
|
||||
|
@ -121,15 +121,15 @@ impl<T: ExtractType> ExtractType for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: ExtractType> ExtractType for Spanned<T> {
|
||||
fn extract(value: &Spanned<Value>) -> Result<Spanned<T>, ShellError> {
|
||||
impl<T: ExtractType> ExtractType for Tagged<T> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Tagged<T>, ShellError> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -139,13 +139,13 @@ impl<T: ExtractType> ExtractType for Spanned<T> {
|
|||
}
|
||||
|
||||
impl ExtractType for Value {
|
||||
fn extract(value: &Spanned<Value>) -> Result<Value, ShellError> {
|
||||
trace!("<Spanned> Extracting {:?} for Value", value);
|
||||
fn extract(value: &Tagged<Value>) -> Result<Value, ShellError> {
|
||||
trace!("<Tagged> Extracting {:?} for Value", value);
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -159,29 +159,29 @@ impl ExtractType for bool {
|
|||
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);
|
||||
|
||||
match &value {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::Boolean(b)),
|
||||
..
|
||||
} => Ok(*b),
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::Nothing),
|
||||
..
|
||||
} => 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 {
|
||||
value @ Spanned {
|
||||
value @ Tagged {
|
||||
item: Value::Primitive(Primitive::Boolean(_)),
|
||||
..
|
||||
} => 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
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
match &value {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(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 {
|
||||
v @ Spanned {
|
||||
v @ Tagged {
|
||||
item: Value::Primitive(Primitive::Path(_)),
|
||||
..
|
||||
} => 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 {
|
||||
fn extract(value: &Spanned<Value>) -> Result<i64, ShellError> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<i64, ShellError> {
|
||||
trace!("Extracting {:?} for i64", value);
|
||||
|
||||
match value {
|
||||
&Spanned {
|
||||
&Tagged {
|
||||
item: Value::Primitive(Primitive::Int(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 {
|
||||
v @ Spanned {
|
||||
v @ Tagged {
|
||||
item: Value::Primitive(Primitive::Int(_)),
|
||||
..
|
||||
} => 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 {
|
||||
fn extract(value: &Spanned<Value>) -> Result<String, ShellError> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<String, ShellError> {
|
||||
trace!("Extracting {:?} for String", value);
|
||||
|
||||
match value {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(string)),
|
||||
..
|
||||
} => 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 {
|
||||
v @ Spanned {
|
||||
v @ Tagged {
|
||||
item: Value::Primitive(Primitive::String(_)),
|
||||
..
|
||||
} => 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 {
|
||||
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);
|
||||
|
||||
match value {
|
||||
v @ Spanned {
|
||||
v @ Tagged {
|
||||
item: Value::Block(_),
|
||||
..
|
||||
} => 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 {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Block(block),
|
||||
..
|
||||
} => 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::parser::{nom_input, pipeline};
|
||||
crate use parse::pipeline::{Pipeline, PipelineElement};
|
||||
pub use parse::span::{Span, Spanned, SpannedItem};
|
||||
crate use parse::text::Text;
|
||||
crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
|
||||
crate use parse::tokens::{RawToken, Token};
|
||||
|
|
|
@ -7,7 +7,7 @@ use serde::{de, forward_to_deserialize_any};
|
|||
pub struct DeserializerItem<'de> {
|
||||
key: String,
|
||||
struct_field: &'de str,
|
||||
val: Spanned<Value>,
|
||||
val: Tagged<Value>,
|
||||
}
|
||||
|
||||
pub struct ConfigDeserializer<'de> {
|
||||
|
@ -28,10 +28,10 @@ impl ConfigDeserializer<'de> {
|
|||
}
|
||||
|
||||
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);
|
||||
self.position += positional.len();
|
||||
Some(Value::List(positional).spanned_unknown()) // TODO: correct span
|
||||
Some(Value::List(positional).tagged_unknown()) // TODO: correct span
|
||||
} else {
|
||||
if self.args.has(name) {
|
||||
self.args.get(name).map(|x| x.clone())
|
||||
|
@ -47,7 +47,9 @@ impl ConfigDeserializer<'de> {
|
|||
self.stack.push(DeserializerItem {
|
||||
key: name.to_string(),
|
||||
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(())
|
||||
|
|
|
@ -5,7 +5,7 @@ crate mod named;
|
|||
crate mod path;
|
||||
|
||||
use crate::evaluate::Scope;
|
||||
use crate::parser::{registry, Span, Spanned, Unit};
|
||||
use crate::parser::{registry, Unit};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
|
@ -18,7 +18,7 @@ crate use binary::Binary;
|
|||
crate use named::NamedArguments;
|
||||
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(
|
||||
head.into(),
|
||||
tail.into_iter()
|
||||
|
@ -111,44 +111,44 @@ impl RawExpression {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Expression = Spanned<RawExpression>;
|
||||
pub type Expression = Tagged<RawExpression>;
|
||||
|
||||
impl 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 {
|
||||
Spanned::from_item(
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
Spanned::from_item(
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Literal(Literal::String(inner.into())),
|
||||
outer.into(),
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
Spanned::from_item(
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Variable(Variable::Other(inner.into())),
|
||||
outer.into(),
|
||||
)
|
||||
}
|
||||
|
||||
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())),
|
||||
outer.into(),
|
||||
)
|
||||
|
@ -158,7 +158,7 @@ impl Expression {
|
|||
impl ToDebug for Expression {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
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::Variable(Variable::It(_)) => write!(f, "$it"),
|
||||
RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)),
|
||||
|
@ -188,8 +188,8 @@ impl ToDebug for Expression {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Spanned<Path>> for Expression {
|
||||
fn from(path: Spanned<Path>) -> Expression {
|
||||
impl From<Tagged<Path>> for Expression {
|
||||
fn from(path: Tagged<Path>) -> Expression {
|
||||
path.map(|p| RawExpression::Path(Box::new(p)))
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ pub enum Literal {
|
|||
Bare,
|
||||
}
|
||||
|
||||
impl ToDebug for Spanned<&Literal> {
|
||||
impl ToDebug for Tagged<&Literal> {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
match self.item() {
|
||||
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 {
|
||||
match *token.item() {
|
||||
RawToken::Integer(int) => hir::Expression::int(int, token.span),
|
||||
RawToken::Size(int, unit) => hir::Expression::size(int, unit, token.span),
|
||||
RawToken::String(span) => hir::Expression::string(span, token.span),
|
||||
RawToken::Integer(int) => hir::Expression::int(int, token.span()),
|
||||
RawToken::Size(int, unit) => hir::Expression::size(int, unit, token.span()),
|
||||
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
||||
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::Bare => hir::Expression::bare(token.span),
|
||||
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
||||
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn baseline_parse_token_as_string(token: &Token, source: &Text) -> hir::Expression {
|
||||
match *token.item() {
|
||||
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::Integer(_) => hir::Expression::bare(token.span),
|
||||
RawToken::Size(_, _) => hir::Expression::bare(token.span),
|
||||
RawToken::Bare => hir::Expression::bare(token.span),
|
||||
RawToken::String(span) => hir::Expression::string(span, token.span),
|
||||
RawToken::Variable(span) => hir::Expression::variable(span, token.span()),
|
||||
RawToken::Integer(_) => hir::Expression::bare(token.span()),
|
||||
RawToken::Size(_, _) => hir::Expression::bare(token.span()),
|
||||
RawToken::Bare => hir::Expression::bare(token.span()),
|
||||
RawToken::String(span) => hir::Expression::string(span, token.span()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ use crate::parser::registry::CommandRegistry;
|
|||
use crate::parser::{
|
||||
hir,
|
||||
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 log::trace;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -62,7 +62,7 @@ pub fn baseline_parse_next_expr(
|
|||
(SyntaxType::Path, token) => {
|
||||
return Err(ShellError::type_error(
|
||||
"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() {
|
||||
None => {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected something after an operator",
|
||||
"operator",
|
||||
Some(op.span),
|
||||
op.span(),
|
||||
))
|
||||
}
|
||||
Some(token) => baseline_parse_semantic_token(token, registry, source)?,
|
||||
|
@ -95,25 +95,26 @@ pub fn baseline_parse_next_expr(
|
|||
|
||||
match syntax_type {
|
||||
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::RawExpression::Binary(Box::new(binary));
|
||||
let binary = Spanned::from_item(binary, span);
|
||||
let binary = Tagged::from_simple_spanned_item(binary, span);
|
||||
|
||||
Ok(binary)
|
||||
}
|
||||
|
||||
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 {
|
||||
Spanned {
|
||||
let path: Tagged<hir::RawExpression> = match first {
|
||||
Tagged {
|
||||
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(
|
||||
Spanned::from_item(
|
||||
Tagged::from_simple_spanned_item(
|
||||
// TODO: Deal with synthetic nodes that have no representation at all in source
|
||||
hir::RawExpression::Variable(hir::Variable::It(Span::from((0, 0)))),
|
||||
(0, 0),
|
||||
|
@ -121,18 +122,16 @@ pub fn baseline_parse_next_expr(
|
|||
vec![string],
|
||||
);
|
||||
let path = hir::RawExpression::Path(Box::new(path));
|
||||
Spanned {
|
||||
item: path,
|
||||
span: first.span,
|
||||
}
|
||||
Tagged::from_simple_spanned_item(path, first.span())
|
||||
}
|
||||
Spanned {
|
||||
Tagged {
|
||||
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(
|
||||
Spanned::from_item(
|
||||
Tagged::from_simple_spanned_item(
|
||||
// TODO: Deal with synthetic nodes that have no representation at all in source
|
||||
hir::RawExpression::Variable(hir::Variable::It(Span::from((0, 0)))),
|
||||
(0, 0),
|
||||
|
@ -140,16 +139,16 @@ pub fn baseline_parse_next_expr(
|
|||
vec![string],
|
||||
);
|
||||
let path = hir::RawExpression::Path(Box::new(path));
|
||||
Spanned {
|
||||
item: path,
|
||||
span: first.span,
|
||||
}
|
||||
Tagged::from_simple_spanned_item(path, first.span())
|
||||
}
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: hir::RawExpression::Variable(..),
|
||||
..
|
||||
} => first,
|
||||
Spanned { span, item } => {
|
||||
Tagged {
|
||||
tag: Tag { span, .. },
|
||||
item,
|
||||
} => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"The first part of an un-braced block must be a column 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::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 = Spanned::from_item(block, span);
|
||||
let block = Tagged::from_simple_spanned_item(block, span);
|
||||
|
||||
Ok(block)
|
||||
}
|
||||
|
@ -197,7 +196,7 @@ pub fn baseline_parse_semantic_token(
|
|||
}
|
||||
|
||||
pub fn baseline_parse_delimited(
|
||||
token: &Spanned<DelimitedNode>,
|
||||
token: &Tagged<DelimitedNode>,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
|
@ -208,7 +207,7 @@ pub fn baseline_parse_delimited(
|
|||
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
||||
|
||||
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::Square => {
|
||||
|
@ -217,13 +216,13 @@ pub fn baseline_parse_delimited(
|
|||
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
||||
|
||||
let expr = hir::RawExpression::List(exprs);
|
||||
Ok(expr.spanned(token.span()))
|
||||
Ok(expr.tagged(Tag::unknown_origin(token.span())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn baseline_parse_path(
|
||||
token: &Spanned<PathNode>,
|
||||
token: &Tagged<PathNode>,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
|
@ -239,7 +238,7 @@ pub fn baseline_parse_path(
|
|||
RawToken::Integer(_) | RawToken::Size(..) | RawToken::Variable(_) => {
|
||||
return Err(ShellError::type_error(
|
||||
"String",
|
||||
token.type_name().spanned(part),
|
||||
token.type_name().simple_spanned(part),
|
||||
))
|
||||
}
|
||||
},
|
||||
|
@ -251,10 +250,10 @@ pub fn baseline_parse_path(
|
|||
}
|
||||
.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)]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::parser::{hir::Expression, Operator, Spanned};
|
||||
use crate::parser::{hir::Expression, Operator};
|
||||
use crate::prelude::*;
|
||||
use crate::Tagged;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -11,7 +12,7 @@ use std::fmt;
|
|||
#[get = "crate"]
|
||||
pub struct Binary {
|
||||
left: Expression,
|
||||
op: Spanned<Operator>,
|
||||
op: Tagged<Operator>,
|
||||
right: Expression,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::parser::hir::Expression;
|
||||
use crate::parser::{Flag, Span};
|
||||
use crate::parser::Flag;
|
||||
use crate::prelude::*;
|
||||
use crate::Span;
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::parser::{hir::Expression, Spanned};
|
||||
use crate::parser::hir::Expression;
|
||||
use crate::prelude::*;
|
||||
use crate::Tagged;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -11,7 +12,7 @@ use std::fmt;
|
|||
#[get = "crate"]
|
||||
pub struct Path {
|
||||
head: Expression,
|
||||
tail: Vec<Spanned<String>>,
|
||||
tail: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
impl ToDebug for Path {
|
||||
|
|
|
@ -4,7 +4,6 @@ crate mod flag;
|
|||
crate mod operator;
|
||||
crate mod parser;
|
||||
crate mod pipeline;
|
||||
crate mod span;
|
||||
crate mod text;
|
||||
crate mod token_tree;
|
||||
crate mod token_tree_builder;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::parser::parse::span::Span;
|
||||
use crate::Span;
|
||||
use derive_new::new;
|
||||
use language_reporting::{FileName, Location};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::parser::Span;
|
||||
use crate::Span;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#![allow(unused)]
|
||||
|
||||
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::*,
|
||||
};
|
||||
use crate::{Span, Tagged};
|
||||
use nom;
|
||||
use nom::branch::*;
|
||||
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;
|
||||
trace_step(input, "raw_integer", move |input| {
|
||||
let (input, neg) = opt(tag("-"))(input)?;
|
||||
|
@ -76,7 +77,7 @@ pub fn raw_integer(input: NomSpan) -> IResult<NomSpan, Spanned<i64>> {
|
|||
|
||||
Ok((
|
||||
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| {
|
||||
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| {
|
||||
let start = input.offset;
|
||||
let (input, unit) = alt((
|
||||
|
@ -230,7 +231,7 @@ pub fn raw_unit(input: NomSpan) -> IResult<NomSpan, Spanned<Unit>> {
|
|||
|
||||
Ok((
|
||||
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| {
|
||||
let left = input.offset;
|
||||
let (input, items) = token_list(input)?;
|
||||
|
@ -484,10 +485,10 @@ pub fn pipeline(input: NomSpan) -> IResult<NomSpan, TokenNode> {
|
|||
}
|
||||
|
||||
fn make_call_list(
|
||||
head: Option<(Spanned<CallNode>, Option<NomSpan>, Option<NomSpan>)>,
|
||||
head: Option<(Tagged<CallNode>, Option<NomSpan>, Option<NomSpan>)>,
|
||||
items: Vec<(
|
||||
Option<NomSpan>,
|
||||
Spanned<CallNode>,
|
||||
Tagged<CallNode>,
|
||||
Option<NomSpan>,
|
||||
Option<NomSpan>,
|
||||
)>,
|
||||
|
@ -531,6 +532,8 @@ fn is_start_bare_char(c: char) -> bool {
|
|||
'_' => true,
|
||||
'-' => true,
|
||||
'@' => true,
|
||||
'*' => true,
|
||||
'?' => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -545,6 +548,8 @@ fn is_bare_char(c: char) -> bool {
|
|||
'_' => true,
|
||||
'-' => true,
|
||||
'@' => true,
|
||||
'*' => true,
|
||||
'?' => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -701,12 +706,12 @@ mod tests {
|
|||
fn test_flag() {
|
||||
// assert_leaf! {
|
||||
// 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! {
|
||||
// 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() {
|
||||
// assert_leaf! {
|
||||
// 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,
|
||||
) -> TokenNode {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -1033,16 +1038,16 @@ mod tests {
|
|||
Box::new(head),
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::parser::{CallNode, Span, Spanned};
|
||||
use crate::parser::CallNode;
|
||||
use crate::{Span, Tagged};
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
|
||||
|
@ -12,7 +13,7 @@ pub struct Pipeline {
|
|||
pub struct PipelineElement {
|
||||
pub pre_ws: Option<Span>,
|
||||
#[get = "crate"]
|
||||
call: Spanned<CallNode>,
|
||||
call: Tagged<CallNode>,
|
||||
pub post_ws: Option<Span>,
|
||||
pub post_pipe: Option<Span>,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::parser::parse::{call_node::*, flag::*, operator::*, pipeline::*, span::*, tokens::*};
|
||||
use crate::Text;
|
||||
use crate::parser::parse::{call_node::*, flag::*, operator::*, pipeline::*, tokens::*};
|
||||
use crate::{Span, Tagged, Text};
|
||||
use derive_new::new;
|
||||
use enum_utils::FromStr;
|
||||
use getset::Getters;
|
||||
|
@ -10,16 +10,16 @@ use std::fmt;
|
|||
pub enum TokenNode {
|
||||
Token(Token),
|
||||
#[allow(unused)]
|
||||
Call(Spanned<CallNode>),
|
||||
Delimited(Spanned<DelimitedNode>),
|
||||
Pipeline(Spanned<Pipeline>),
|
||||
Operator(Spanned<Operator>),
|
||||
Flag(Spanned<Flag>),
|
||||
Call(Tagged<CallNode>),
|
||||
Delimited(Tagged<DelimitedNode>),
|
||||
Pipeline(Tagged<Pipeline>),
|
||||
Operator(Tagged<Operator>),
|
||||
Flag(Tagged<Flag>),
|
||||
Member(Span),
|
||||
Whitespace(Span),
|
||||
#[allow(unused)]
|
||||
Error(Spanned<Box<ShellError>>),
|
||||
Path(Spanned<PathNode>),
|
||||
Error(Tagged<Box<ShellError>>),
|
||||
Path(Tagged<PathNode>),
|
||||
}
|
||||
|
||||
pub struct DebugTokenNode<'a> {
|
||||
|
@ -86,16 +86,16 @@ impl From<&TokenNode> for Span {
|
|||
impl TokenNode {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
TokenNode::Token(t) => t.span,
|
||||
TokenNode::Call(s) => s.span,
|
||||
TokenNode::Delimited(s) => s.span,
|
||||
TokenNode::Pipeline(s) => s.span,
|
||||
TokenNode::Operator(s) => s.span,
|
||||
TokenNode::Flag(s) => s.span,
|
||||
TokenNode::Token(t) => t.span(),
|
||||
TokenNode::Call(s) => s.span(),
|
||||
TokenNode::Delimited(s) => s.span(),
|
||||
TokenNode::Pipeline(s) => s.span(),
|
||||
TokenNode::Operator(s) => s.span(),
|
||||
TokenNode::Flag(s) => s.span(),
|
||||
TokenNode::Member(s) => *s,
|
||||
TokenNode::Whitespace(s) => *s,
|
||||
TokenNode::Error(s) => s.span,
|
||||
TokenNode::Path(s) => s.span,
|
||||
TokenNode::Error(s) => s.span(),
|
||||
TokenNode::Path(s) => s.span(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ impl TokenNode {
|
|||
|
||||
pub fn is_bare(&self) -> bool {
|
||||
match self {
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Bare,
|
||||
..
|
||||
}) => 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 {
|
||||
TokenNode::Flag(
|
||||
flag @ Spanned {
|
||||
flag @ Tagged {
|
||||
item: Flag { .. }, ..
|
||||
},
|
||||
) if value == flag.name().slice(source) => Some(*flag),
|
||||
|
@ -150,7 +150,7 @@ impl TokenNode {
|
|||
|
||||
pub fn as_pipeline(&self) -> Result<Pipeline, ShellError> {
|
||||
match self {
|
||||
TokenNode::Pipeline(Spanned { item, .. }) => Ok(item.clone()),
|
||||
TokenNode::Pipeline(Tagged { item, .. }) => Ok(item.clone()),
|
||||
_ => Err(ShellError::string("unimplemented")),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ use crate::prelude::*;
|
|||
use crate::parser::parse::flag::{Flag, FlagKind};
|
||||
use crate::parser::parse::operator::Operator;
|
||||
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::tokens::{RawToken, Token};
|
||||
use crate::parser::parse::unit::Unit;
|
||||
use crate::parser::CallNode;
|
||||
use crate::Span;
|
||||
use derive_new::new;
|
||||
|
||||
#[derive(new)]
|
||||
|
@ -20,7 +20,7 @@ pub struct TokenTreeBuilder {
|
|||
#[allow(unused)]
|
||||
pub type CurriedNode<T> = Box<dyn FnOnce(&mut TokenTreeBuilder) -> T + '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)]
|
||||
impl TokenTreeBuilder {
|
||||
|
@ -92,7 +92,7 @@ impl TokenTreeBuilder {
|
|||
input: (Vec<PipelineElement>, Option<Span>),
|
||||
span: impl Into<Span>,
|
||||
) -> TokenNode {
|
||||
TokenNode::Pipeline(Spanned::from_item(
|
||||
TokenNode::Pipeline(Tagged::from_simple_spanned_item(
|
||||
Pipeline::new(input.0, input.1.into()),
|
||||
span,
|
||||
))
|
||||
|
@ -111,7 +111,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -128,7 +128,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
span.into(),
|
||||
))
|
||||
|
@ -146,7 +146,10 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -161,7 +164,10 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -183,7 +189,10 @@ impl TokenTreeBuilder {
|
|||
) -> TokenNode {
|
||||
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 {
|
||||
|
@ -206,7 +215,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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),
|
||||
span,
|
||||
))
|
||||
|
@ -224,7 +233,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
span.into(),
|
||||
))
|
||||
|
@ -242,7 +251,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
span.into(),
|
||||
))
|
||||
|
@ -260,7 +269,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
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 {
|
||||
panic!("BUG: spanned call (TODO)")
|
||||
}
|
||||
|
@ -306,7 +315,7 @@ impl TokenTreeBuilder {
|
|||
let head = input.next().unwrap();
|
||||
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 {
|
||||
|
@ -324,7 +333,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
span,
|
||||
))
|
||||
|
@ -345,7 +354,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
span,
|
||||
))
|
||||
|
@ -366,7 +375,7 @@ impl TokenTreeBuilder {
|
|||
}
|
||||
|
||||
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()),
|
||||
span,
|
||||
))
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::parser::parse::span::*;
|
||||
use crate::parser::parse::unit::*;
|
||||
use crate::Text;
|
||||
use crate::{Span, Tagged, Text};
|
||||
use std::fmt;
|
||||
|
||||
#[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 {
|
||||
pub fn debug(&self, source: &'a Text) -> DebugToken<'a> {
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
use crate::errors::{ArgumentError, ShellError};
|
||||
use crate::parser::registry::{Signature, CommandRegistry, NamedType, PositionalType};
|
||||
use crate::parser::{baseline_parse_tokens, CallNode, Span, Spanned};
|
||||
use crate::parser::registry::{CommandRegistry, NamedType, PositionalType, Signature};
|
||||
use crate::parser::{baseline_parse_tokens, CallNode};
|
||||
use crate::parser::{
|
||||
hir::{self, NamedArguments},
|
||||
Flag, RawToken, TokenNode,
|
||||
};
|
||||
use crate::Text;
|
||||
use crate::{Span, Tag, Tagged, Text};
|
||||
use log::trace;
|
||||
|
||||
pub fn parse_command(
|
||||
config: &Signature,
|
||||
registry: &CommandRegistry,
|
||||
call: &Spanned<CallNode>,
|
||||
call: &Tagged<CallNode>,
|
||||
source: &Text,
|
||||
) -> Result<hir::Call, ShellError> {
|
||||
let Spanned { item: raw_call, .. } = call;
|
||||
let Tagged { item: raw_call, .. } = call;
|
||||
|
||||
trace!("Processing {:?}", config);
|
||||
|
||||
|
@ -31,7 +31,7 @@ pub fn parse_command(
|
|||
.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)),
|
||||
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> {
|
||||
match head {
|
||||
TokenNode::Token(
|
||||
spanned @ Spanned {
|
||||
spanned @ Tagged {
|
||||
item: RawToken::Bare,
|
||||
..
|
||||
},
|
||||
) => Ok(spanned.map(|_| hir::RawExpression::Literal(hir::Literal::Bare))),
|
||||
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::String(inner_span),
|
||||
span,
|
||||
}) => Ok(Spanned::from_item(
|
||||
tag: Tag { span, origin: None },
|
||||
}) => Ok(Tagged::from_simple_spanned_item(
|
||||
hir::RawExpression::Literal(hir::Literal::String(*inner_span)),
|
||||
*span,
|
||||
)),
|
||||
|
@ -96,7 +96,7 @@ fn parse_command_tail(
|
|||
return Err(ShellError::argument_error(
|
||||
config.name.clone(),
|
||||
ArgumentError::MissingValueForName(name.to_string()),
|
||||
flag.span,
|
||||
flag.span(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ fn parse_command_tail(
|
|||
return Err(ShellError::argument_error(
|
||||
config.name.clone(),
|
||||
ArgumentError::MissingValueForName(name.to_string()),
|
||||
flag.span,
|
||||
flag.span(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ fn extract_mandatory(
|
|||
tokens: &mut hir::TokensIterator<'a>,
|
||||
source: &Text,
|
||||
span: Span,
|
||||
) -> Result<(usize, Spanned<Flag>), ShellError> {
|
||||
) -> Result<(usize, Tagged<Flag>), ShellError> {
|
||||
let flag = tokens.extract(|t| t.as_flag(name, source));
|
||||
|
||||
match flag {
|
||||
|
@ -223,7 +223,7 @@ fn extract_optional(
|
|||
name: &str,
|
||||
tokens: &mut hir::TokensIterator<'a>,
|
||||
source: &Text,
|
||||
) -> Result<(Option<(usize, Spanned<Flag>)>), ShellError> {
|
||||
) -> Result<(Option<(usize, Tagged<Flag>)>), ShellError> {
|
||||
let flag = tokens.extract(|t| t.as_flag(name, source));
|
||||
|
||||
match flag {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// TODO: Temporary redirect
|
||||
crate use crate::context::CommandRegistry;
|
||||
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 derive_new::new;
|
||||
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 positional: Option<Vec<Spanned<Value>>>,
|
||||
pub named: Option<IndexMap<String, Spanned<Value>>>,
|
||||
pub positional: Option<Vec<Tagged<Value>>>,
|
||||
pub named: Option<IndexMap<String, Tagged<Value>>>,
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DebugEvaluatedPositional<'a> {
|
||||
positional: &'a Option<Vec<Spanned<Value>>>,
|
||||
positional: &'a Option<Vec<Tagged<Value>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
||||
|
@ -161,7 +161,7 @@ impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
|||
|
||||
#[derive(new)]
|
||||
pub struct DebugEvaluatedNamed<'a> {
|
||||
named: &'a Option<IndexMap<String, Spanned<Value>>>,
|
||||
named: &'a Option<IndexMap<String, Tagged<Value>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugEvaluatedNamed<'a> {
|
||||
|
@ -199,14 +199,14 @@ impl EvaluatedArgs {
|
|||
DebugEvaluatedArgs { args: self }
|
||||
}
|
||||
|
||||
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
|
||||
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
||||
match &self.positional {
|
||||
None => None,
|
||||
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 {
|
||||
None => Err(ShellError::unimplemented("Better error: expect_nth")),
|
||||
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 {
|
||||
None => None,
|
||||
Some(named) => named.get(name),
|
||||
|
@ -250,11 +250,11 @@ impl EvaluatedArgs {
|
|||
|
||||
pub enum PositionalIter<'a> {
|
||||
Empty,
|
||||
Array(std::slice::Iter<'a, Spanned<Value>>),
|
||||
Array(std::slice::Iter<'a, Tagged<Value>>),
|
||||
}
|
||||
|
||||
impl Iterator for PositionalIter<'a> {
|
||||
type Item = &'a Spanned<Value>;
|
||||
type Item = &'a Tagged<Value>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
|
@ -267,7 +267,7 @@ impl Iterator for PositionalIter<'a> {
|
|||
impl Signature {
|
||||
crate fn parse_args(
|
||||
&self,
|
||||
call: &Spanned<CallNode>,
|
||||
call: &Tagged<CallNode>,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Call, ShellError> {
|
||||
|
@ -302,7 +302,7 @@ crate fn evaluate_args(
|
|||
|
||||
let positional = positional?;
|
||||
|
||||
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = call
|
||||
let named: Result<Option<IndexMap<String, Tagged<Value>>>, ShellError> = call
|
||||
.named()
|
||||
.as_ref()
|
||||
.map(|n| {
|
||||
|
@ -313,7 +313,7 @@ crate fn evaluate_args(
|
|||
hir::named::NamedValue::PresentSwitch(span) => {
|
||||
results.insert(
|
||||
name.clone(),
|
||||
Spanned::from_item(Value::boolean(true), *span),
|
||||
Tagged::from_simple_spanned_item(Value::boolean(true), *span),
|
||||
);
|
||||
}
|
||||
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 std::io;
|
||||
|
||||
pub trait Plugin {
|
||||
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) {
|
||||
return;
|
||||
#[allow(unused)]
|
||||
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) {
|
||||
|
@ -33,15 +36,15 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
|||
send_response(plugin.config());
|
||||
}
|
||||
Ok(NuCommand::begin_filter { params }) => {
|
||||
send_response(
|
||||
plugin
|
||||
.begin_filter(params)
|
||||
.map(|_| Vec::<ReturnValue>::new()),
|
||||
);
|
||||
send_response(plugin.begin_filter(params));
|
||||
}
|
||||
Ok(NuCommand::filter { params }) => {
|
||||
send_response(plugin.filter(params));
|
||||
}
|
||||
Ok(NuCommand::end_filter) => {
|
||||
send_response(plugin.end_filter());
|
||||
}
|
||||
|
||||
Ok(NuCommand::sink { params }) => {
|
||||
plugin.sink(params.0, params.1);
|
||||
return;
|
||||
|
@ -70,15 +73,14 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) {
|
|||
send_response(plugin.config());
|
||||
}
|
||||
Ok(NuCommand::begin_filter { params }) => {
|
||||
send_response(
|
||||
plugin
|
||||
.begin_filter(params)
|
||||
.map(|_| Vec::<ReturnValue>::new()),
|
||||
);
|
||||
send_response(plugin.begin_filter(params));
|
||||
}
|
||||
Ok(NuCommand::filter { params }) => {
|
||||
send_response(plugin.filter(params));
|
||||
}
|
||||
Ok(NuCommand::end_filter) => {
|
||||
send_response(plugin.end_filter());
|
||||
}
|
||||
Ok(NuCommand::sink { params }) => {
|
||||
plugin.sink(params.0, params.1);
|
||||
break;
|
||||
|
@ -138,10 +140,11 @@ pub enum NuCommand {
|
|||
params: CallInfo,
|
||||
},
|
||||
filter {
|
||||
params: Spanned<Value>,
|
||||
params: Tagged<Value>,
|
||||
},
|
||||
end_filter,
|
||||
sink {
|
||||
params: (CallInfo, Vec<Spanned<Value>>),
|
||||
params: (CallInfo, Vec<Tagged<Value>>),
|
||||
},
|
||||
quit,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Signature, Spanned, Value,
|
||||
ShellError, Signature, Tagged, Value,
|
||||
};
|
||||
|
||||
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()) {
|
||||
(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),
|
||||
None => {
|
||||
return Err(ShellError::string(
|
||||
|
@ -52,10 +53,10 @@ impl Plugin for Add {
|
|||
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 {
|
||||
match &args[0] {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(s)),
|
||||
..
|
||||
} => {
|
||||
|
@ -69,16 +70,16 @@ impl Plugin for Add {
|
|||
}
|
||||
}
|
||||
match &args[1] {
|
||||
Spanned { item: v, .. } => {
|
||||
Tagged { item: v, .. } => {
|
||||
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)?)])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
||||
use indexmap::IndexMap;
|
||||
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::*;
|
||||
|
||||
|
@ -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 {
|
||||
match v {
|
||||
Spanned {
|
||||
item: Value::Binary(b),
|
||||
span,
|
||||
} => {
|
||||
let source = span.source.map(|x| call_info.source_map.get(&x)).flatten();
|
||||
let value_origin = v.origin();
|
||||
match v.item {
|
||||
Value::Binary(b) => {
|
||||
let source = value_origin.map(|x| call_info.source_map.get(&x)).flatten();
|
||||
let _ = view_binary(&b, source, call_info.args.has("lores"));
|
||||
}
|
||||
_ => {}
|
||||
|
@ -195,11 +193,11 @@ impl RenderContext {
|
|||
let cursor = cursor();
|
||||
cursor.hide()?;
|
||||
|
||||
self.width = terminal_size.0 as usize + 1;
|
||||
self.width = terminal_size.0 as usize;
|
||||
self.height = if self.lores_mode {
|
||||
terminal_size.1 as usize
|
||||
terminal_size.1 as usize - 1
|
||||
} else {
|
||||
terminal_size.1 as usize * 2
|
||||
(terminal_size.1 as usize - 1) * 2
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -356,7 +354,7 @@ pub fn view_contents_interactive(
|
|||
None
|
||||
};
|
||||
|
||||
let mut nes = neso::Nes::new(48000.0);
|
||||
let mut nes = neso::Nes::new(0.0);
|
||||
let rawkey = RawKey::new();
|
||||
nes.load_rom(&buffer);
|
||||
|
||||
|
@ -375,10 +373,10 @@ pub fn view_contents_interactive(
|
|||
let cursor = cursor();
|
||||
|
||||
let buttons = vec![
|
||||
KeyCode::LShift,
|
||||
KeyCode::LControl,
|
||||
KeyCode::Alt,
|
||||
KeyCode::LeftControl,
|
||||
KeyCode::Tab,
|
||||
KeyCode::Back,
|
||||
KeyCode::BackSpace,
|
||||
KeyCode::UpArrow,
|
||||
KeyCode::DownArrow,
|
||||
KeyCode::LeftArrow,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Signature, Spanned, Value,
|
||||
ShellError, Signature, Tagged, Value,
|
||||
};
|
||||
|
||||
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()) {
|
||||
(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),
|
||||
None => {
|
||||
return Err(ShellError::string(
|
||||
|
@ -52,10 +53,10 @@ impl Plugin for Edit {
|
|||
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 {
|
||||
match &args[0] {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(s)),
|
||||
..
|
||||
} => {
|
||||
|
@ -69,16 +70,16 @@ impl Plugin for Edit {
|
|||
}
|
||||
}
|
||||
match &args[1] {
|
||||
Spanned { item: v, .. } => {
|
||||
Tagged { item: v, .. } => {
|
||||
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)?)])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||
ReturnValue, ShellError, Signature, Spanned, SpannedItem, Value,
|
||||
ReturnValue, ShellError, Signature, Tagged, TaggedItem, Value,
|
||||
};
|
||||
|
||||
struct Inc {
|
||||
|
@ -22,20 +22,20 @@ impl Inc {
|
|||
|
||||
fn inc(
|
||||
&self,
|
||||
value: Spanned<Value>,
|
||||
value: Tagged<Value>,
|
||||
field: &Option<String>,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
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)) => {
|
||||
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>() {
|
||||
Ok(Spanned {
|
||||
item: Value::string(format!("{}", i + 1)),
|
||||
span: value.span,
|
||||
})
|
||||
Ok(Tagged::from_item(
|
||||
Value::string(format!("{}", i + 1)),
|
||||
value.tag(),
|
||||
))
|
||||
} else if let Ok(mut ver) = semver::Version::parse(&s) {
|
||||
if self.major {
|
||||
ver.increment_major();
|
||||
|
@ -45,17 +45,17 @@ impl Inc {
|
|||
self.patch;
|
||||
ver.increment_patch();
|
||||
}
|
||||
Ok(Spanned {
|
||||
item: Value::string(ver.to_string()),
|
||||
span: value.span,
|
||||
})
|
||||
Ok(Tagged::from_item(
|
||||
Value::string(ver.to_string()),
|
||||
value.tag(),
|
||||
))
|
||||
} else {
|
||||
Err(ShellError::string("string could not be incremented"))
|
||||
}
|
||||
}
|
||||
Value::Object(_) => match field {
|
||||
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)?,
|
||||
None => {
|
||||
return Err(ShellError::string("inc could not find field to replace"))
|
||||
|
@ -63,7 +63,7 @@ impl Inc {
|
|||
};
|
||||
match value
|
||||
.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),
|
||||
None => {
|
||||
|
@ -98,7 +98,7 @@ impl Plugin for Inc {
|
|||
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") {
|
||||
self.major = true;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ impl Plugin for Inc {
|
|||
if let Some(args) = call_info.args.positional {
|
||||
for arg in args {
|
||||
match arg {
|
||||
Spanned {
|
||||
Tagged {
|
||||
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)?)])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||
Spanned, Value,
|
||||
Tagged, Value,
|
||||
};
|
||||
|
||||
struct NewSkip {
|
||||
struct Skip {
|
||||
skip_amount: i64,
|
||||
}
|
||||
impl NewSkip {
|
||||
fn new() -> NewSkip {
|
||||
NewSkip { skip_amount: 0 }
|
||||
impl Skip {
|
||||
fn new() -> Skip {
|
||||
Skip { skip_amount: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for NewSkip {
|
||||
impl Plugin for Skip {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "skip".to_string(),
|
||||
|
@ -23,11 +23,11 @@ impl Plugin for NewSkip {
|
|||
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 {
|
||||
for arg in args {
|
||||
match arg {
|
||||
Spanned {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::Int(i)),
|
||||
..
|
||||
} => {
|
||||
|
@ -37,17 +37,17 @@ impl Plugin for NewSkip {
|
|||
return Err(ShellError::labeled_error(
|
||||
"Unrecognized type in params",
|
||||
"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 {
|
||||
Ok(vec![ReturnSuccess::value(input)])
|
||||
} else {
|
||||
|
@ -58,5 +58,5 @@ impl Plugin for NewSkip {
|
|||
}
|
||||
|
||||
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 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::output::print_tree_with;
|
||||
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 {
|
||||
for i in input.iter() {
|
||||
let view = TreeView::from_value(&i);
|
||||
let _ = view.render_view();
|
||||
}
|
||||
}
|
||||
|
||||
//Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,17 +36,24 @@ crate use crate::cli::MaybeOwned;
|
|||
crate use crate::commands::command::{
|
||||
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::{Environment, Host};
|
||||
crate use crate::env::Host;
|
||||
crate use crate::errors::ShellError;
|
||||
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::{Primitive, Value};
|
||||
crate use crate::parser::hir::SyntaxType;
|
||||
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::traits::{HasSpan, ToDebug};
|
||||
crate use crate::Span;
|
||||
crate use crate::Text;
|
||||
crate use futures::stream::BoxStream;
|
||||
crate use futures::{FutureExt, Stream, StreamExt};
|
||||
|
@ -63,7 +70,7 @@ pub trait FromInputStream {
|
|||
|
||||
impl<T> FromInputStream for T
|
||||
where
|
||||
T: Stream<Item = Spanned<Value>> + Send + 'static,
|
||||
T: Stream<Item = Tagged<Value>> + Send + 'static,
|
||||
{
|
||||
fn from_input_stream(self) -> OutputStream {
|
||||
OutputStream {
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
crate mod completer;
|
||||
crate mod filesystem_shell;
|
||||
crate mod helper;
|
||||
crate mod shell;
|
||||
crate mod shell_manager;
|
||||
crate mod value_shell;
|
||||
|
||||
crate use helper::Helper;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use crate::context::CommandRegistry;
|
||||
|
||||
use derive_new::new;
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::completion::{self, FilenameCompleter};
|
||||
|
@ -8,19 +6,32 @@ use rustyline::line_buffer::LineBuffer;
|
|||
#[derive(new)]
|
||||
crate struct NuCompleter {
|
||||
pub file_completer: FilenameCompleter,
|
||||
pub commands: CommandRegistry,
|
||||
//pub commands: indexmap::IndexMap<String, Arc<dyn Command>>,
|
||||
}
|
||||
|
||||
impl Completer for NuCompleter {
|
||||
type Candidate = completion::Pair;
|
||||
pub struct CompletionPair {
|
||||
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,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
context: &rustyline::Context,
|
||||
) -> rustyline::Result<(usize, Vec<completion::Pair>)> {
|
||||
let commands: Vec<String> = self.commands.names();
|
||||
) -> rustyline::Result<(usize, Vec<CompletionPair>)> {
|
||||
//let commands: Vec<String> = self.commands.keys().cloned().collect();
|
||||
|
||||
let mut completions = self.file_completer.complete(line, pos, context)?.1;
|
||||
|
||||
|
@ -51,6 +62,7 @@ impl Completer for NuCompleter {
|
|||
replace_pos -= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
for command in commands.iter() {
|
||||
let mut pos = replace_pos;
|
||||
let mut matched = true;
|
||||
|
@ -68,15 +80,17 @@ impl Completer for NuCompleter {
|
|||
}
|
||||
|
||||
if matched {
|
||||
completions.push(completion::Pair {
|
||||
completions.push(CompletionPair {
|
||||
display: command.clone(),
|
||||
replacement: command.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Ok((replace_pos, completions))
|
||||
}
|
||||
*/
|
||||
|
||||
fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
||||
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::parse::span::Spanned;
|
||||
use crate::parser::parse::token_tree::TokenNode;
|
||||
use crate::parser::parse::tokens::RawToken;
|
||||
use crate::parser::{Pipeline, PipelineElement};
|
||||
use crate::prelude::*;
|
||||
use crate::shell::completer::NuCompleter;
|
||||
use crate::shell::completer::CompletionPair;
|
||||
use crate::shell::shell_manager::ShellManager;
|
||||
use crate::Tagged;
|
||||
use ansi_term::Color;
|
||||
use rustyline::completion::{self, Completer, FilenameCompleter};
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::highlight::Highlighter;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
use rustyline::hint::Hinter;
|
||||
use std::borrow::Cow::{self, Owned};
|
||||
|
||||
crate struct Helper {
|
||||
completer: NuCompleter,
|
||||
hinter: HistoryHinter,
|
||||
helper: ShellManager,
|
||||
}
|
||||
|
||||
impl Helper {
|
||||
crate fn new(commands: CommandRegistry) -> Helper {
|
||||
Helper {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
}
|
||||
crate fn new(helper: ShellManager) -> Helper {
|
||||
Helper { 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(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
||||
self.completer.complete(line, pos, ctx)
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
let result = self.helper.complete(line, pos, ctx);
|
||||
|
||||
result.map(|(x, y)| (x, y.iter().map(|z| z.into()).collect()))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Hinter for Helper {
|
||||
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::Operator(..) => Color::White.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(..),
|
||||
..
|
||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Size(..),
|
||||
..
|
||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::String(..),
|
||||
..
|
||||
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Variable(..),
|
||||
..
|
||||
}) => Color::Yellow.bold().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Bare,
|
||||
..
|
||||
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue