mirror of
https://github.com/nushell/nushell.git
synced 2025-01-21 21:58:39 +01:00
Merge master
This commit is contained in:
commit
aadacc2d36
1596
Cargo.lock
generated
1596
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
44
Cargo.toml
44
Cargo.toml
@ -13,7 +13,7 @@ homepage = "https://github.com/nushell/nushell"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[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 New Issue
Block a user