Merge master

This commit is contained in:
Jonathan Turner 2019-08-31 10:13:09 +12:00
commit fa2c6ec227
76 changed files with 1759 additions and 1120 deletions

125
.circleci/config.yml Normal file
View File

@ -0,0 +1,125 @@
# CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/configuration-reference/ for more details
# See https://circleci.com/docs/2.0/config-intro/#section=configuration for spec
#
version: 2.1
# Commands
commands:
check_token:
description: Check that QUAY_TOKEN is provided in environment
steps:
- run:
if [[ -z "${QUAY_TOKEN}" ]]; then
echo "QUAY_TOKEN is undefined. Add to CircleCI environment to continue."
exit 1;
fi
pull_cache:
description: Pulls Quay.io docker images usable for our cache
steps:
- run: docker pull quay.io/nushell/nu:latest
- run: docker pull quay.io/nushell/nu-base:latest
orbs:
# https://circleci.com/orbs/registry/orb/circleci/docker
docker: circleci/docker@0.5.13
workflows:
version: 2.0
# This builds on all pull requests to test, and ignores master
build_without_deploy:
jobs:
- docker/publish:
deploy: false
image: nushell/nu-base
tag: latest
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest
filters:
branches:
ignore:
- master
before_build:
- check_token
- pull_cache
after_build:
- run:
name: Build Multistage (smaller) container
command: |
docker build -f docker/Dockerfile -t quay.io/nushell/nu .
- run:
name: Preview Docker Tag for Nushell Build
command: |
DOCKER_TAG=$(docker run quay.io/nushell/nu --version | cut -d' ' -f2)
echo "Version that would be used for Docker tag is v${DOCKER_TAG}"
# workflow publishes to Docker Hub, with each job having different triggers
build_with_deploy:
jobs:
# Deploy versioned and latest images on tags (releases) only.
- docker/publish:
image: nushell/nu-base
registry: quay.io
tag: latest
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest
filters:
branches:
ignore: /.*/
tags:
only: /^v.*/
before_build:
- check_token
- pull_cache
after_build:
- run:
name: Build Multistage (smaller) container
command: |
docker build -f docker/Dockerfile -t quay.io/nushell/nu .
- run:
name: Publish Docker Tag with Nushell Version
command: |
DOCKER_TAG=$(docker run quay.io/nushell/nu --version | cut -d' ' -f2)
echo "Version for Docker tag is ${DOCKER_TAG}"
docker tag quay.io/nushell/nu-base:latest quay.io/nushell/nu-base:${DOCKER_TAG}
docker tag quay.io/nushell/nu:latest quay.io/nushell/nu:${DOCKER_TAG}
docker login -u="nushell+circleci" -p="${QUAY_TOKEN}" quay.io
docker push quay.io/nushell/nu-base
docker push quay.io/nushell/nu
# publish devel to Docker Hub on merge to master
build_with_deploy_devel:
jobs:
# Deploy devel tag on merge to master
- docker/publish:
image: nushell/nu-base
registry: quay.io
tag: devel
dockerfile: docker/Dockerfile.nu-base
extra_build_args: --cache-from=quay.io/nushell/nu-base:latest,quay.io/nushell/nu:latest
before_build:
- check_token
- pull_cache
filters:
branches:
only: master
after_build:
- run:
name: Build Multistage (smaller) container
command: |
docker build --build-arg FROMTAG=devel -f docker/Dockerfile -t quay.io/nushell/nu:devel .
- run:
name: Publish Development Docker Tags
command: |
docker login -u="nushell+circleci" -p="${QUAY_TOKEN}" quay.io
docker push quay.io/nushell/nu-base:devel
docker push quay.io/nushell/nu:devel

478
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@ documentation = "https://book.nushell.sh"
[dependencies]
rustyline = "5.0.2"
sysinfo = "0.9"
chrono = { version = "0.4.7", features = ["serde"] }
derive-new = "0.5.7"
prettytable-rs = "0.8.0"
@ -27,16 +26,15 @@ indexmap = { version = "1.0.2", features = ["serde-1"] }
chrono-humanize = "0.0.11"
byte-unit = "3.0.1"
ordered-float = {version = "1.0.2", features = ["serde"]}
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.2"
futures-preview = { version = "=0.3.0-alpha.18", features = ["compat", "io-compat"] }
futures-async-stream = "=0.1.0-alpha.5"
futures_codec = "0.2.5"
term = "0.5.2"
bytes = "0.4.12"
log = "0.4.8"
pretty_env_logger = "0.3.1"
serde = { version = "1.0.98", features = ["derive"] }
bson = "0.13.0"
bson = "=0.13.0"
serde_json = "1.0.40"
serde-hjson = "0.9.1"
serde_yaml = "0.8"
@ -52,7 +50,7 @@ dirs = "2.0.2"
glob = "0.3.0"
ctrlc = "3.1.3"
ptree = "0.2"
surf = "1.0"
surf = "1.0.2"
url = "2.1.0"
roxmltree = "0.7.0"
nom5_locate = "0.1.1"
@ -71,13 +69,15 @@ semver = "0.9.0"
uuid = {version = "0.7.4", features = [ "v4", "serde" ]}
syntect = "3.2.0"
onig_sys = "=69.1.0"
heim = "0.0.6"
heim = "0.0.7"
which = "2.0.1"
battery = "0.7.4"
textwrap = {version = "0.11.0", features = ["term_size"]}
rawkey = {version = "0.1.2", optional = true }
clipboard = {version = "0.5", optional = true }
shellexpand = "1.0.0"
futures-timer = "0.3.0"
pin-utils = "0.1.0-alpha.4"
[features]
raw-key = ["rawkey", "neso"]

View File

@ -1,16 +0,0 @@
FROM rust:1.37-slim
# docker build -t nu .
# docker run -it nu
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y libssl-dev \
libxcb-composite0-dev \
libx11-dev \
pkg-config && \
mkdir -p /code
ADD . /code
WORKDIR /code
RUN cargo install nu
ENTRYPOINT ["nu"]

View File

@ -2,7 +2,7 @@
# Nu Shell
A modern, GitHub-era shell written in Rust
A modern shell for the GitHub era
![Example of nushell](images/nushell-autocomplete4.gif "Example of nushell")
@ -51,19 +51,40 @@ The following optional features are currently supported:
## Docker
Optionally, you can build a container with nu installed using the [Dockerfile](Dockerfile):
If you want to pull a pre-built container, you can browse tags for the [nushell organization](https://quay.io/organization/nushell)
on Quay.io. Pulling a container would come down to:
```bash
$ docker build -t nu .
$ docker pull quay.io/nushell/nu
$ docker pull quay.io/nushell/nu-base
```
Both "nu-base" and "nu" provide the nu binary, however nu-base also includes the source code at `/code`
in the container and all dependencies.
Optionally, you can also build the containers locally using the [dockerfiles provided](docker):
To build the base image:
```bash
$ docker build -f docker/Dockerfile.nu-base -t nushell/nu-base .
```
And then run the container:
And then to build the smaller container (using a Multistage build):
```bash
$ docker run -it nu
$ docker build -f docker/Dockerfile -t nushell/nu .
```
Either way, you can run either container as follows:
```bash
$ docker run -it nushell/nu-base
$ docker run -it nushell/nu
/> exit
```
The second container is a bit smaller, if size is important to you.
# Philosophy
Nu draws inspiration from projects like PowerShell, functional programming languages, and modern cli tools. Rather than thinking of files and services as raw streams of text, Nu looks at each input as something with structure. For example, when you list the contents of a directory, what you get back is a list of objects, where each object represents an item in that directory. These values can be piped through a series of steps, in a series of commands called a 'pipeline'.

5
docker/Dockerfile Normal file
View File

@ -0,0 +1,5 @@
ARG FROMTAG=latest
FROM quay.io/nushell/nu-base:${FROMTAG} as base
FROM rust:1.37-slim
COPY --from=base /usr/local/bin/nu /usr/local/bin/nu
ENTRYPOINT ["nu"]

18
docker/Dockerfile.nu-base Normal file
View File

@ -0,0 +1,18 @@
FROM rust:1.37-slim
# docker build -f docker/Dockerfile.nu-base -t nushell/nu-base .
# docker run -it nushell/nu-base
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y libssl-dev \
libxcb-composite0-dev \
libx11-dev \
pkg-config
RUN USER=root cargo new --bin /code
WORKDIR /code
ADD . /code
RUN cargo build --release && cargo run --release
RUN cp target/release/nu /usr/local/bin
ENTRYPOINT ["nu"]

View File

@ -7,7 +7,7 @@ use crate::commands::plugin::JsonRpc;
use crate::commands::plugin::{PluginCommand, PluginSink};
use crate::commands::whole_stream_command;
use crate::context::Context;
crate use crate::errors::ShellError;
pub(crate) use crate::errors::ShellError;
use crate::git::current_branch;
use crate::object::Value;
use crate::parser::registry::Signature;
@ -17,7 +17,7 @@ use crate::prelude::*;
use log::{debug, trace};
use regex::Regex;
use rustyline::error::ReadlineError;
use rustyline::{self, ColorMode, Config, Editor};
use rustyline::{self, ColorMode, Config, Editor, config::Configurer, config::EditMode};
use std::env;
use std::error::Error;
use std::io::{BufRead, BufReader, Write};
@ -30,7 +30,7 @@ pub enum MaybeOwned<'a, T> {
Borrowed(&'a T),
}
impl<T> MaybeOwned<'a, T> {
impl<T> MaybeOwned<'_, T> {
pub fn borrow(&self) -> &T {
match self {
MaybeOwned::Owned(v) => v,
@ -180,6 +180,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
whole_stream_command(ToCSV),
whole_stream_command(ToJSON),
whole_stream_command(ToTOML),
whole_stream_command(ToTSV),
whole_stream_command(ToYAML),
whole_stream_command(SortBy),
whole_stream_command(Tags),
@ -188,6 +189,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
whole_stream_command(FromArray),
whole_stream_command(FromArray),
whole_stream_command(FromCSV),
whole_stream_command(FromTSV),
whole_stream_command(FromINI),
whole_stream_command(FromBSON),
whole_stream_command(FromJSON),
@ -255,6 +257,17 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
context.shell_manager.clone(),
)));
let edit_mode = crate::object::config::config(Span::unknown())?
.get("edit_mode")
.map(|s| match s.as_string().unwrap().as_ref() {
"vi" => EditMode::Vi,
"emacs" => EditMode::Emacs,
_ => EditMode::Emacs,
})
.unwrap_or(EditMode::Emacs);
rl.set_edit_mode(edit_mode);
let readline = rl.readline(&format!(
"{}{}> ",
cwd,

View File

@ -1,118 +1,122 @@
#[macro_use]
crate mod macros;
pub(crate) mod macros;
crate mod args;
crate mod autoview;
crate mod cd;
crate mod classified;
crate mod clip;
crate mod command;
crate mod config;
crate mod cp;
crate mod date;
crate mod debug;
crate mod enter;
crate mod exit;
crate mod first;
crate mod from_array;
crate mod from_bson;
crate mod from_csv;
crate mod from_ini;
crate mod from_json;
crate mod from_toml;
crate mod from_xml;
crate mod from_yaml;
crate mod get;
crate mod last;
crate mod lines;
crate mod ls;
crate mod mkdir;
crate mod mv;
crate mod next;
crate mod nth;
crate mod open;
crate mod pick;
crate mod plugin;
crate mod prev;
crate mod ps;
crate mod reject;
crate mod reverse;
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 table;
crate mod tags;
crate mod to_array;
crate mod to_bson;
crate mod to_csv;
crate mod to_json;
crate mod to_toml;
crate mod to_yaml;
crate mod trim;
crate mod version;
crate mod vtable;
crate mod where_;
crate mod which_;
pub(crate) mod args;
pub(crate) mod autoview;
pub(crate) mod cd;
pub(crate) mod classified;
pub(crate) mod clip;
pub(crate) mod command;
pub(crate) mod config;
pub(crate) mod cp;
pub(crate) mod date;
pub(crate) mod debug;
pub(crate) mod enter;
pub(crate) mod exit;
pub(crate) mod first;
pub(crate) mod from_array;
pub(crate) mod from_bson;
pub(crate) mod from_csv;
pub(crate) mod from_ini;
pub(crate) mod from_json;
pub(crate) mod from_toml;
pub(crate) mod from_tsv;
pub(crate) mod from_xml;
pub(crate) mod from_yaml;
pub(crate) mod get;
pub(crate) mod last;
pub(crate) mod lines;
pub(crate) mod ls;
pub(crate) mod mkdir;
pub(crate) mod mv;
pub(crate) mod next;
pub(crate) mod nth;
pub(crate) mod open;
pub(crate) mod pick;
pub(crate) mod plugin;
pub(crate) mod prev;
pub(crate) mod ps;
pub(crate) mod reject;
pub(crate) mod reverse;
pub(crate) mod rm;
pub(crate) mod save;
pub(crate) mod shells;
pub(crate) mod size;
pub(crate) mod skip_while;
pub(crate) mod sort_by;
pub(crate) mod split_column;
pub(crate) mod split_row;
pub(crate) mod table;
pub(crate) mod tags;
pub(crate) mod to_array;
pub(crate) mod to_bson;
pub(crate) mod to_csv;
pub(crate) mod to_json;
pub(crate) mod to_toml;
pub(crate) mod to_tsv;
pub(crate) mod to_yaml;
pub(crate) mod trim;
pub(crate) mod version;
pub(crate) mod vtable;
pub(crate) mod where_;
pub(crate) mod which_;
crate use autoview::Autoview;
crate use cd::CD;
crate use command::{
pub(crate) use autoview::Autoview;
pub(crate) use cd::CD;
pub(crate) use command::{
per_item_command, whole_stream_command, Command, PerItemCommand, RawCommandArgs,
UnevaluatedCallInfo, WholeStreamCommand,
};
crate use config::Config;
crate use cp::Cpy;
crate use date::Date;
crate use debug::Debug;
crate use enter::Enter;
crate use exit::Exit;
crate use first::First;
crate use from_array::FromArray;
crate use from_bson::FromBSON;
crate use from_csv::FromCSV;
crate use from_ini::FromINI;
crate use from_json::FromJSON;
crate use from_toml::FromTOML;
crate use from_xml::FromXML;
crate use from_yaml::FromYAML;
crate use from_yaml::FromYML;
crate use get::Get;
crate use last::Last;
crate use lines::Lines;
crate use ls::LS;
crate use mkdir::Mkdir;
crate use mv::Move;
crate use next::Next;
crate use nth::Nth;
crate use open::Open;
crate use pick::Pick;
crate use prev::Previous;
crate use ps::PS;
crate use reject::Reject;
crate use reverse::Reverse;
crate use rm::Remove;
crate use save::Save;
crate use shells::Shells;
crate use size::Size;
crate use skip_while::SkipWhile;
crate use sort_by::SortBy;
crate use split_column::SplitColumn;
crate use split_row::SplitRow;
crate use table::Table;
crate use tags::Tags;
crate use to_array::ToArray;
crate use to_bson::ToBSON;
crate use to_csv::ToCSV;
crate use to_json::ToJSON;
crate use to_toml::ToTOML;
crate use to_yaml::ToYAML;
crate use trim::Trim;
crate use version::Version;
crate use vtable::VTable;
crate use where_::Where;
crate use which_::Which;
pub(crate) use config::Config;
pub(crate) use cp::Cpy;
pub(crate) use date::Date;
pub(crate) use debug::Debug;
pub(crate) use enter::Enter;
pub(crate) use exit::Exit;
pub(crate) use first::First;
pub(crate) use from_array::FromArray;
pub(crate) use from_bson::FromBSON;
pub(crate) use from_csv::FromCSV;
pub(crate) use from_ini::FromINI;
pub(crate) use from_json::FromJSON;
pub(crate) use from_toml::FromTOML;
pub(crate) use from_tsv::FromTSV;
pub(crate) use from_xml::FromXML;
pub(crate) use from_yaml::FromYAML;
pub(crate) use from_yaml::FromYML;
pub(crate) use get::Get;
pub(crate) use last::Last;
pub(crate) use lines::Lines;
pub(crate) use ls::LS;
pub(crate) use mkdir::Mkdir;
pub(crate) use mv::Move;
pub(crate) use next::Next;
pub(crate) use nth::Nth;
pub(crate) use open::Open;
pub(crate) use pick::Pick;
pub(crate) use prev::Previous;
pub(crate) use ps::PS;
pub(crate) use reject::Reject;
pub(crate) use reverse::Reverse;
pub(crate) use rm::Remove;
pub(crate) use save::Save;
pub(crate) use shells::Shells;
pub(crate) use size::Size;
pub(crate) use skip_while::SkipWhile;
pub(crate) use sort_by::SortBy;
pub(crate) use split_column::SplitColumn;
pub(crate) use split_row::SplitRow;
pub(crate) use table::Table;
pub(crate) use tags::Tags;
pub(crate) use to_array::ToArray;
pub(crate) use to_bson::ToBSON;
pub(crate) use to_csv::ToCSV;
pub(crate) use to_json::ToJSON;
pub(crate) use to_toml::ToTOML;
pub(crate) use to_tsv::ToTSV;
pub(crate) use to_yaml::ToYAML;
pub(crate) use trim::Trim;
pub(crate) use version::Version;
pub(crate) use vtable::VTable;
pub(crate) use where_::Where;
pub(crate) use which_::Which;

View File

@ -45,27 +45,27 @@ impl Decoder for LinesCodec {
}
}
crate struct ClassifiedInputStream {
crate objects: InputStream,
crate stdin: Option<std::fs::File>,
pub(crate) struct ClassifiedInputStream {
pub(crate) objects: InputStream,
pub(crate) stdin: Option<std::fs::File>,
}
impl ClassifiedInputStream {
crate fn new() -> ClassifiedInputStream {
pub(crate) fn new() -> ClassifiedInputStream {
ClassifiedInputStream {
objects: VecDeque::new().into(),
stdin: None,
}
}
crate fn from_input_stream(stream: impl Into<InputStream>) -> ClassifiedInputStream {
pub(crate) fn from_input_stream(stream: impl Into<InputStream>) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: stream.into(),
stdin: None,
}
}
crate fn from_stdout(stdout: std::fs::File) -> ClassifiedInputStream {
pub(crate) fn from_stdout(stdout: std::fs::File) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: VecDeque::new().into(),
stdin: Some(stdout),
@ -73,11 +73,11 @@ impl ClassifiedInputStream {
}
}
crate struct ClassifiedPipeline {
crate commands: Vec<ClassifiedCommand>,
pub(crate) struct ClassifiedPipeline {
pub(crate) commands: Vec<ClassifiedCommand>,
}
crate enum ClassifiedCommand {
pub(crate) enum ClassifiedCommand {
#[allow(unused)]
Expr(TokenNode),
Internal(InternalCommand),
@ -95,14 +95,14 @@ impl ClassifiedCommand {
}
}
crate struct InternalCommand {
crate command: Arc<Command>,
crate name_span: Span,
crate args: hir::Call,
pub(crate) struct InternalCommand {
pub(crate) command: Arc<Command>,
pub(crate) name_span: Span,
pub(crate) args: hir::Call,
}
impl InternalCommand {
crate async fn run(
pub(crate) async fn run(
self,
context: &mut Context,
input: ClassifiedInputStream,
@ -206,21 +206,21 @@ impl InternalCommand {
}
}
crate struct ExternalCommand {
crate name: String,
pub(crate) struct ExternalCommand {
pub(crate) name: String,
#[allow(unused)]
crate name_span: Span,
crate args: Vec<Tagged<String>>,
pub(crate) name_span: Span,
pub(crate) args: Vec<Tagged<String>>,
}
crate enum StreamNext {
pub(crate) enum StreamNext {
Last,
External,
Internal,
}
impl ExternalCommand {
crate async fn run(
pub(crate) async fn run(
self,
context: &mut Context,
input: ClassifiedInputStream,

View File

@ -111,6 +111,7 @@ pub fn config(
if result.contains_key(&key) {
result.remove(&key);
config::write_config(&result)?;
} else {
return Err(ShellError::string(&format!(
"{} does not exist in config",

View File

@ -3,7 +3,7 @@ use crate::{EntriesListView, GenericView, TreeView};
use futures::stream::{self, StreamExt};
use std::sync::{Arc, Mutex};
crate fn format(input: Vec<Value>, host: &mut dyn Host) {
pub(crate) fn format(input: Vec<Value>, host: &mut dyn Host) {
let last = input.len() - 1;
for (i, item) in input.iter().enumerate() {
let view = GenericView::new(item);

135
src/commands/from_tsv.rs Normal file
View File

@ -0,0 +1,135 @@
use crate::commands::WholeStreamCommand;
use crate::object::{Primitive, TaggedDictBuilder, Value};
use crate::prelude::*;
use csv::ReaderBuilder;
pub struct FromTSV;
#[derive(Deserialize)]
pub struct FromTSVArgs {
headerless: bool,
}
impl WholeStreamCommand for FromTSV {
fn name(&self) -> &str {
"from-tsv"
}
fn signature(&self) -> Signature {
Signature::build("from-tsv").switch("headerless")
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, from_tsv)?.run()
}
}
pub fn from_tsv_string_to_value(
s: String,
headerless: bool,
tag: impl Into<Tag>,
) -> Result<Tagged<Value>, csv::Error> {
let mut reader = ReaderBuilder::new()
.has_headers(false)
.delimiter(b'\t')
.from_reader(s.as_bytes());
let tag = tag.into();
let mut fields: VecDeque<String> = VecDeque::new();
let mut iter = reader.records();
let mut rows = vec![];
if let Some(result) = iter.next() {
let line = result?;
for (idx, item) in line.iter().enumerate() {
if headerless {
fields.push_back(format!("Column{}", idx + 1));
} else {
fields.push_back(item.to_string());
}
}
}
loop {
if let Some(row_values) = iter.next() {
let row_values = row_values?;
let mut row = TaggedDictBuilder::new(tag);
for (idx, entry) in row_values.iter().enumerate() {
row.insert_tagged(
fields.get(idx).unwrap(),
Value::Primitive(Primitive::String(String::from(entry))).tagged(tag),
);
}
rows.push(row.into_tagged_value());
} else {
break;
}
}
Ok(Tagged::from_item(Value::List(rows), tag))
}
fn from_tsv(
FromTSVArgs {
headerless: skip_headers,
}: FromTSVArgs,
RunnableContext { input, name, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let name_span = name;
let stream = async_stream_block! {
let values: Vec<Tagged<Value>> = input.values.collect().await;
let mut concat_string = String::new();
let mut latest_tag: Option<Tag> = None;
for value in values {
let value_tag = value.tag();
latest_tag = Some(value_tag);
match value.item {
Value::Primitive(Primitive::String(s)) => {
concat_string.push_str(&s);
concat_string.push_str("\n");
}
_ => yield Err(ShellError::labeled_error_with_secondary(
"Expected a string from pipeline",
"requires string input",
name_span,
"value originates from here",
value_tag.span,
)),
}
}
match from_tsv_string_to_value(concat_string, skip_headers, name_span) {
Ok(x) => match x {
Tagged { item: Value::List(list), .. } => {
for l in list {
yield ReturnSuccess::value(l);
}
}
x => yield ReturnSuccess::value(x),
},
Err(_) => if let Some(last_tag) = latest_tag {
yield Err(ShellError::labeled_error_with_secondary(
"Could not parse as TSV",
"input cannot be parsed as TSV",
name_span,
"value originates from here",
last_tag.span,
))
} ,
}
};
Ok(stream.to_output_stream())
}

View File

@ -1,8 +1,13 @@
use crate::commands::WholeStreamCommand;
use crate::errors::ShellError;
use crate::object::process::process_dict;
use crate::object::TaggedDictBuilder;
use crate::prelude::*;
use sysinfo::SystemExt;
use std::time::Duration;
use std::usize;
use futures::stream::{StreamExt, TryStreamExt};
use heim::process::{self as process, Process, ProcessResult};
use heim::units::{ratio, Ratio};
pub struct PS;
@ -24,28 +29,44 @@ impl WholeStreamCommand for PS {
}
}
fn ps(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let system;
async fn usage(process: Process) -> ProcessResult<(process::Process, Ratio)> {
let usage_1 = process.cpu_usage().await?;
futures_timer::Delay::new(Duration::from_millis(100)).await?;
let usage_2 = process.cpu_usage().await?;
#[cfg(target_os = "linux")]
{
system = sysinfo::System::new();
}
#[cfg(not(target_os = "linux"))]
{
use sysinfo::RefreshKind;
let mut sy = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes());
sy.refresh_processes();
system = sy;
}
let list = system.get_process_list();
let list = list
.into_iter()
.map(|(_, process)| process_dict(process, Tag::unknown_origin(args.call_info.name_span)))
.collect::<VecDeque<_>>();
Ok(list.from_input_stream())
Ok((process, usage_2 - usage_1))
}
fn ps(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let stream = async_stream_block! {
let processes = process::processes()
.map_ok(|process| {
// Note that there is no `.await` here,
// as we want to pass the returned future
// into the `.try_buffer_unordered`.
usage(process)
})
.try_buffer_unordered(usize::MAX);
pin_utils::pin_mut!(processes);
while let Some(res) = processes.next().await {
if let Ok((process, usage)) = res {
let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(span));
dict.insert("pid", Value::int(process.pid()));
if let Ok(name) = process.name().await {
dict.insert("name", Value::string(name));
}
if let Ok(status) = process.status().await {
dict.insert("status", Value::string(format!("{:?}", status)));
}
dict.insert("cpu", Value::float(usage.get::<ratio::percent>() as f64));
yield ReturnSuccess::value(dict.into_tagged_value());
}
}
};
Ok(stream.to_output_stream())
}

View File

@ -1,4 +1,5 @@
use crate::commands::to_csv::{to_string as to_csv_to_string, value_to_csv_value};
use crate::commands::to_tsv::{to_string as to_tsv_to_string, value_to_tsv_value};
use crate::commands::to_json::value_to_json_value;
use crate::commands::to_toml::value_to_toml_value;
use crate::commands::to_yaml::value_to_yaml_value;
@ -166,6 +167,14 @@ async fn to_string_for(
}
to_csv_to_string(&value_to_csv_value(&input[0]))?
}
Some(x) if x == "tsv" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to tsv requires a single object (or use --raw)",
));
}
to_tsv_to_string(&value_to_tsv_value(&input[0]))?
}
Some(x) if x == "toml" => {
if input.len() != 1 {
return Err(ShellError::string(

108
src/commands/to_tsv.rs Normal file
View File

@ -0,0 +1,108 @@
use crate::commands::WholeStreamCommand;
use crate::object::{Primitive, Value};
use crate::prelude::*;
use csv::WriterBuilder;
pub struct ToTSV;
#[derive(Deserialize)]
pub struct ToTSVArgs {
headerless: bool,
}
impl WholeStreamCommand for ToTSV {
fn name(&self) -> &str {
"to-tsv"
}
fn signature(&self) -> Signature {
Signature::build("to-tsv").switch("headerless")
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, to_tsv)?.run()
}
}
pub fn value_to_tsv_value(v: &Value) -> Value {
match v {
Value::Primitive(Primitive::String(s)) => Value::Primitive(Primitive::String(s.clone())),
Value::Primitive(Primitive::Nothing) => Value::Primitive(Primitive::Nothing),
Value::Primitive(Primitive::Boolean(b)) => Value::Primitive(Primitive::Boolean(b.clone())),
Value::Primitive(Primitive::Bytes(b)) => Value::Primitive(Primitive::Bytes(b.clone())),
Value::Primitive(Primitive::Date(d)) => Value::Primitive(Primitive::Date(d.clone())),
Value::Object(o) => Value::Object(o.clone()),
Value::List(l) => Value::List(l.clone()),
Value::Block(_) => Value::Primitive(Primitive::Nothing),
_ => Value::Primitive(Primitive::Nothing),
}
}
fn to_string_helper(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
match v {
Value::Primitive(Primitive::Date(d)) => Ok(d.to_string()),
Value::Primitive(Primitive::Bytes(b)) => Ok(format!("{}", *b as u64)),
Value::Primitive(Primitive::Boolean(_)) => Ok(v.as_string()?),
Value::List(_) => return Ok(String::from("[list list]")),
Value::Object(_) => return Ok(String::from("[object]")),
Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()),
_ => return Err("Bad input".into()),
}
}
pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
match v {
Value::Object(o) => {
let mut wtr = WriterBuilder::new().delimiter(b'\t').from_writer(vec![]);
let mut fields: VecDeque<String> = VecDeque::new();
let mut values: VecDeque<String> = VecDeque::new();
for (k, v) in o.entries.iter() {
fields.push_back(k.clone());
values.push_back(to_string_helper(&v)?);
}
wtr.write_record(fields).expect("can not write.");
wtr.write_record(values).expect("can not write.");
return Ok(String::from_utf8(wtr.into_inner()?)?);
}
_ => return to_string_helper(&v),
}
}
fn to_tsv(
ToTSVArgs { headerless }: ToTSVArgs,
RunnableContext { input, name, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let name_span = name;
let out = input;
Ok(out
.values
.map(move |a| match to_string(&value_to_tsv_value(&a.item)) {
Ok(x) => {
let converted = if headerless {
x.lines().skip(1).collect()
} else {
x
};
ReturnSuccess::value(
Value::Primitive(Primitive::String(converted)).simple_spanned(name_span),
)
}
_ => Err(ShellError::labeled_error_with_secondary(
"Expected an object with TSV-compatible structure from pipeline",
"requires TSV-compatible input",
name_span,
format!("{} originates from here", a.item.type_name()),
a.span(),
)),
})
.to_output_stream())
}

View File

@ -41,13 +41,13 @@ pub struct CommandRegistry {
}
impl CommandRegistry {
crate fn empty() -> CommandRegistry {
pub(crate) fn empty() -> CommandRegistry {
CommandRegistry {
registry: Arc::new(Mutex::new(IndexMap::default())),
}
}
crate fn get_command(&self, name: &str) -> Option<Arc<Command>> {
pub(crate) fn get_command(&self, name: &str) -> Option<Arc<Command>> {
let registry = self.registry.lock().unwrap();
registry.get(name).map(|c| c.clone())
@ -64,7 +64,7 @@ impl CommandRegistry {
registry.insert(name.into(), command);
}
crate fn names(&self) -> Vec<String> {
pub(crate) fn names(&self) -> Vec<String> {
let registry = self.registry.lock().unwrap();
registry.keys().cloned().collect()
}
@ -73,17 +73,17 @@ impl CommandRegistry {
#[derive(Clone)]
pub struct Context {
registry: CommandRegistry,
crate source_map: SourceMap,
pub(crate) source_map: SourceMap,
host: Arc<Mutex<dyn Host + Send>>,
crate shell_manager: ShellManager,
pub(crate) shell_manager: ShellManager,
}
impl Context {
crate fn registry(&self) -> &CommandRegistry {
pub(crate) fn registry(&self) -> &CommandRegistry {
&self.registry
}
crate fn basic() -> Result<Context, Box<dyn Error>> {
pub(crate) fn basic() -> Result<Context, Box<dyn Error>> {
let registry = CommandRegistry::new();
Ok(Context {
registry: registry.clone(),
@ -93,7 +93,7 @@ impl Context {
})
}
crate fn with_host(&mut self, block: impl FnOnce(&mut dyn Host)) {
pub(crate) fn with_host(&mut self, block: impl FnOnce(&mut dyn Host)) {
let mut host = self.host.lock().unwrap();
block(&mut *host)
@ -109,15 +109,15 @@ impl Context {
self.source_map.insert(uuid, span_source);
}
crate fn has_command(&self, name: &str) -> bool {
pub(crate) fn has_command(&self, name: &str) -> bool {
self.registry.has(name)
}
crate fn get_command(&self, name: &str) -> Arc<Command> {
pub(crate) fn get_command(&self, name: &str) -> Arc<Command> {
self.registry.get_command(name).unwrap()
}
crate fn run_command<'a>(
pub(crate) fn run_command<'a>(
&mut self,
command: Arc<Command>,
name_span: Span,

View File

@ -1,3 +1,3 @@
crate mod host;
pub(crate) mod host;
crate use self::host::Host;
pub(crate) use self::host::Host;

2
src/env/host.rs vendored
View File

@ -73,7 +73,7 @@ impl Host for BasicHost {
}
}
crate fn handle_unexpected<T>(
pub(crate) fn handle_unexpected<T>(
host: &mut dyn Host,
func: impl FnOnce(&mut dyn Host) -> Result<T, ShellError>,
) {

View File

@ -73,7 +73,7 @@ impl serde::de::Error for ShellError {
}
impl ShellError {
crate fn type_error(
pub(crate) fn type_error(
expected: impl Into<String>,
actual: Tagged<impl Into<String>>,
) -> ShellError {
@ -84,21 +84,21 @@ impl ShellError {
.start()
}
crate fn syntax_error(problem: Tagged<impl Into<String>>) -> ShellError {
pub(crate) fn syntax_error(problem: Tagged<impl Into<String>>) -> ShellError {
ProximateShellError::SyntaxError {
problem: problem.map(|p| p.into()),
}
.start()
}
crate fn invalid_command(problem: impl Into<Tag>) -> ShellError {
pub(crate) fn invalid_command(problem: impl Into<Tag>) -> ShellError {
ProximateShellError::InvalidCommand {
command: problem.into(),
}
.start()
}
crate fn coerce_error(
pub(crate) fn coerce_error(
left: Tagged<impl Into<String>>,
right: Tagged<impl Into<String>>,
) -> ShellError {
@ -109,11 +109,11 @@ impl ShellError {
.start()
}
crate fn missing_property(subpath: Description, expr: Description) -> ShellError {
pub(crate) fn missing_property(subpath: Description, expr: Description) -> ShellError {
ProximateShellError::MissingProperty { subpath, expr }.start()
}
crate fn missing_value(span: Option<Span>, reason: impl Into<String>) -> ShellError {
pub(crate) fn missing_value(span: Option<Span>, reason: impl Into<String>) -> ShellError {
ProximateShellError::MissingValue {
span,
reason: reason.into(),
@ -121,7 +121,7 @@ impl ShellError {
.start()
}
crate fn argument_error(
pub(crate) fn argument_error(
command: impl Into<String>,
kind: ArgumentError,
span: Span,
@ -134,7 +134,7 @@ impl ShellError {
.start()
}
crate fn parse_error(
pub(crate) fn parse_error(
error: nom::Err<(nom5_locate::LocatedSpan<&str>, nom::error::ErrorKind)>,
) -> ShellError {
use language_reporting::*;
@ -158,11 +158,11 @@ impl ShellError {
}
}
crate fn diagnostic(diagnostic: Diagnostic<Span>) -> ShellError {
pub(crate) fn diagnostic(diagnostic: Diagnostic<Span>) -> ShellError {
ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }).start()
}
crate fn to_diagnostic(self) -> Diagnostic<Span> {
pub(crate) fn to_diagnostic(self) -> Diagnostic<Span> {
match self.error {
ProximateShellError::String(StringError { title, .. }) => {
Diagnostic::new(Severity::Error, title)
@ -309,11 +309,11 @@ impl ShellError {
ProximateShellError::String(StringError::new(title.into(), Value::nothing())).start()
}
crate fn unimplemented(title: impl Into<String>) -> ShellError {
pub(crate) fn unimplemented(title: impl Into<String>) -> ShellError {
ShellError::string(&format!("Unimplemented: {}", title.into()))
}
crate fn unexpected(title: impl Into<String>) -> ShellError {
pub(crate) fn unexpected(title: impl Into<String>) -> ShellError {
ShellError::string(&format!("Unexpected: {}", title.into()))
}
}
@ -369,12 +369,12 @@ impl ToDebug for ProximateShellError {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ShellDiagnostic {
crate diagnostic: Diagnostic<Span>,
pub(crate) diagnostic: Diagnostic<Span>,
}
impl ShellDiagnostic {
#[allow(unused)]
crate fn simple_diagnostic(
pub(crate) fn simple_diagnostic(
span: impl Into<Span>,
source: impl Into<String>,
) -> ShellDiagnostic {

View File

@ -16,14 +16,14 @@ pub struct Scope {
}
impl Scope {
crate fn empty() -> Scope {
pub(crate) fn empty() -> Scope {
Scope {
it: Value::nothing().tagged_unknown(),
vars: IndexMap::new(),
}
}
crate fn it_value(value: Tagged<Value>) -> Scope {
pub(crate) fn it_value(value: Tagged<Value>) -> Scope {
Scope {
it: value,
vars: IndexMap::new(),
@ -31,7 +31,7 @@ impl Scope {
}
}
crate fn evaluate_baseline_expr(
pub(crate) fn evaluate_baseline_expr(
expr: &Expression,
registry: &CommandRegistry,
scope: &Scope,

View File

@ -1,3 +1,3 @@
crate mod evaluator;
pub(crate) mod evaluator;
crate use evaluator::{evaluate_baseline_expr, Scope};
pub(crate) use evaluator::{evaluate_baseline_expr, Scope};

View File

@ -1,21 +1,21 @@
crate mod entries;
crate mod generic;
crate mod list;
crate mod table;
crate mod vtable;
pub(crate) mod entries;
pub(crate) mod generic;
pub(crate) mod list;
pub(crate) mod table;
pub(crate) mod vtable;
use crate::prelude::*;
crate use entries::EntriesView;
pub(crate) use entries::EntriesView;
#[allow(unused)]
crate use generic::GenericView;
crate use table::TableView;
crate use vtable::VTableView;
pub(crate) use generic::GenericView;
pub(crate) use table::TableView;
pub(crate) use vtable::VTableView;
crate trait RenderView {
pub(crate) trait RenderView {
fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError>;
}
crate fn print_view(view: &impl RenderView, host: &mut dyn Host) -> Result<(), ShellError> {
pub(crate) fn print_view(view: &impl RenderView, host: &mut dyn Host) -> Result<(), ShellError> {
view.render_view(host)
}

View File

@ -14,7 +14,7 @@ pub struct EntriesView {
}
impl EntriesView {
crate fn from_value(value: &Value) -> EntriesView {
pub(crate) fn from_value(value: &Value) -> EntriesView {
let descs = value.data_descriptors();
let mut entries = vec![];

View File

@ -9,7 +9,7 @@ pub struct GenericView<'value> {
value: &'value Value,
}
impl RenderView for GenericView<'value> {
impl RenderView for GenericView<'_> {
fn render_view(&self, host: &mut dyn Host) -> Result<(), ShellError> {
match self.value {
Value::Primitive(p) => Ok(host.stdout(&p.format(None))),

View File

@ -1,5 +1,4 @@
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(generators)]
#![feature(specialization)]
#![feature(proc_macro_hygiene)]

View File

@ -1,13 +1,12 @@
crate mod base;
crate mod config;
crate mod dict;
crate mod files;
crate mod into;
crate mod meta;
crate mod process;
crate mod types;
pub(crate) mod base;
pub(crate) mod config;
pub(crate) mod dict;
pub(crate) mod files;
pub(crate) mod into;
pub(crate) mod meta;
pub(crate) mod types;
#[allow(unused)]
crate use base::{Block, Primitive, Switch, Value};
crate use dict::{Dictionary, TaggedDictBuilder};
crate use files::dir_entry_dict;
pub(crate) use base::{Block, Primitive, Switch, Value};
pub(crate) use dict::{Dictionary, TaggedDictBuilder};
pub(crate) use files::dir_entry_dict;

View File

@ -16,11 +16,11 @@ use std::time::SystemTime;
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, new, Serialize, Deserialize)]
pub struct OF64 {
crate inner: OrderedFloat<f64>,
pub(crate) inner: OrderedFloat<f64>,
}
impl OF64 {
crate fn into_inner(&self) -> f64 {
pub(crate) fn into_inner(&self) -> f64 {
self.inner.into_inner()
}
}
@ -49,7 +49,7 @@ pub enum Primitive {
}
impl Primitive {
crate fn type_name(&self) -> String {
pub(crate) fn type_name(&self) -> String {
use Primitive::*;
match self {
@ -67,7 +67,7 @@ impl Primitive {
.to_string()
}
crate fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
pub(crate) fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Primitive::*;
match self {
@ -130,16 +130,16 @@ impl Primitive {
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new, Serialize)]
pub struct Operation {
crate left: Value,
crate operator: Operator,
crate right: Value,
pub(crate) left: Value,
pub(crate) operator: Operator,
pub(crate) right: Value,
}
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Serialize, Deserialize, new)]
pub struct Block {
crate expressions: Vec<hir::Expression>,
crate source: Text,
crate span: Span,
pub(crate) expressions: Vec<hir::Expression>,
pub(crate) source: Text,
pub(crate) span: Span,
}
impl Block {
@ -176,7 +176,7 @@ pub enum Value {
Block(Block),
}
pub fn debug_list(values: &'a Vec<Tagged<Value>>) -> ValuesDebug<'a> {
pub fn debug_list(values: &Vec<Tagged<Value>>) -> ValuesDebug<'_> {
ValuesDebug { values }
}
@ -184,7 +184,7 @@ pub struct ValuesDebug<'a> {
values: &'a Vec<Tagged<Value>>,
}
impl fmt::Debug for ValuesDebug<'a> {
impl fmt::Debug for ValuesDebug<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list()
.entries(self.values.iter().map(|i| i.debug()))
@ -196,7 +196,7 @@ pub struct ValueDebug<'a> {
value: &'a Tagged<Value>,
}
impl fmt::Debug for ValueDebug<'a> {
impl fmt::Debug for ValueDebug<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.value.item() {
Value::Primitive(p) => p.debug(f),
@ -209,16 +209,16 @@ impl fmt::Debug for ValueDebug<'a> {
}
impl Tagged<Value> {
crate fn tagged_type_name(&self) -> Tagged<String> {
pub(crate) fn tagged_type_name(&self) -> Tagged<String> {
let name = self.type_name();
Tagged::from_item(name, self.tag())
}
}
impl std::convert::TryFrom<&'a Tagged<Value>> for Block {
impl std::convert::TryFrom<&Tagged<Value>> for Block {
type Error = ShellError;
fn try_from(value: &'a Tagged<Value>) -> Result<Block, ShellError> {
fn try_from(value: &Tagged<Value>) -> Result<Block, ShellError> {
match value.item() {
Value::Block(block) => Ok(block.clone()),
v => Err(ShellError::type_error(
@ -229,10 +229,10 @@ impl std::convert::TryFrom<&'a Tagged<Value>> for Block {
}
}
impl std::convert::TryFrom<&'a Tagged<Value>> for i64 {
impl std::convert::TryFrom<&Tagged<Value>> for i64 {
type Error = ShellError;
fn try_from(value: &'a Tagged<Value>) -> Result<i64, ShellError> {
fn try_from(value: &Tagged<Value>) -> Result<i64, ShellError> {
match value.item() {
Value::Primitive(Primitive::Int(int)) => Ok(*int),
v => Err(ShellError::type_error(
@ -243,10 +243,10 @@ impl std::convert::TryFrom<&'a Tagged<Value>> for i64 {
}
}
impl std::convert::TryFrom<&'a Tagged<Value>> for String {
impl std::convert::TryFrom<&Tagged<Value>> for String {
type Error = ShellError;
fn try_from(value: &'a Tagged<Value>) -> Result<String, ShellError> {
fn try_from(value: &Tagged<Value>) -> Result<String, ShellError> {
match value.item() {
Value::Primitive(Primitive::String(s)) => Ok(s.clone()),
v => Err(ShellError::type_error(
@ -257,10 +257,10 @@ impl std::convert::TryFrom<&'a Tagged<Value>> for String {
}
}
impl std::convert::TryFrom<&'a Tagged<Value>> for Vec<u8> {
impl std::convert::TryFrom<&Tagged<Value>> for Vec<u8> {
type Error = ShellError;
fn try_from(value: &'a Tagged<Value>) -> Result<Vec<u8>, ShellError> {
fn try_from(value: &Tagged<Value>) -> Result<Vec<u8>, ShellError> {
match value.item() {
Value::Binary(b) => Ok(b.clone()),
v => Err(ShellError::type_error(
@ -271,7 +271,7 @@ impl std::convert::TryFrom<&'a Tagged<Value>> for Vec<u8> {
}
}
impl std::convert::TryFrom<&'a Tagged<Value>> for &'a crate::object::Dictionary {
impl<'a> std::convert::TryFrom<&'a Tagged<Value>> for &'a crate::object::Dictionary {
type Error = ShellError;
fn try_from(value: &'a Tagged<Value>) -> Result<&'a crate::object::Dictionary, ShellError> {
@ -301,10 +301,10 @@ impl Switch {
}
}
impl std::convert::TryFrom<Option<&'a Tagged<Value>>> for Switch {
impl std::convert::TryFrom<Option<&Tagged<Value>>> for Switch {
type Error = ShellError;
fn try_from(value: Option<&'a Tagged<Value>>) -> Result<Switch, ShellError> {
fn try_from(value: Option<&Tagged<Value>>) -> Result<Switch, ShellError> {
match value {
None => Ok(Switch::Absent),
Some(value) => match value.item() {
@ -319,13 +319,13 @@ impl std::convert::TryFrom<Option<&'a Tagged<Value>>> for Switch {
}
impl Tagged<Value> {
crate fn debug(&'a self) -> ValueDebug<'a> {
pub(crate) fn debug(&self) -> ValueDebug<'_> {
ValueDebug { value: self }
}
}
impl Value {
crate fn type_name(&self) -> String {
pub(crate) fn type_name(&self) -> String {
match self {
Value::Primitive(p) => p.type_name(),
Value::Object(_) => format!("object"),
@ -351,7 +351,7 @@ impl Value {
}
}
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Tagged<Value>> {
pub(crate) fn get_data_by_key(&self, name: &str) -> Option<&Tagged<Value>> {
match self {
Value::Object(o) => o.get_data_by_key(name),
Value::List(l) => {
@ -374,14 +374,14 @@ impl Value {
}
#[allow(unused)]
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Tagged<Value>> {
pub(crate) fn get_data_by_index(&self, idx: usize) -> Option<&Tagged<Value>> {
match self {
Value::List(l) => l.iter().nth(idx),
_ => None,
}
}
pub fn get_data_by_path(&'a self, tag: Tag, path: &str) -> Option<Tagged<&Value>> {
pub fn get_data_by_path(&self, tag: Tag, path: &str) -> Option<Tagged<&Value>> {
let mut current = self;
for p in path.split(".") {
match current.get_data_by_key(p) {
@ -394,7 +394,7 @@ impl Value {
}
pub fn insert_data_at_path(
&'a self,
&self,
tag: Tag,
path: &str,
new_value: Value,
@ -447,7 +447,7 @@ impl Value {
}
pub fn replace_data_at_path(
&'a self,
&self,
tag: Tag,
path: &str,
replaced_value: Value,
@ -481,7 +481,7 @@ impl Value {
None
}
pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> {
match self {
p @ Value::Primitive(_) => MaybeOwned::Borrowed(p),
Value::Object(o) => o.get_data(desc),
@ -491,7 +491,7 @@ impl Value {
}
}
crate fn format_leaf(&self, desc: Option<&String>) -> String {
pub(crate) fn format_leaf(&self, desc: Option<&String>) -> String {
match self {
Value::Primitive(p) => p.format(desc),
Value::Block(b) => itertools::join(
@ -510,7 +510,7 @@ impl Value {
}
}
crate fn style_leaf(&self) -> &'static str {
pub(crate) fn style_leaf(&self) -> &'static str {
match self {
Value::Primitive(p) => p.style(),
_ => "",
@ -518,7 +518,7 @@ impl Value {
}
#[allow(unused)]
crate fn compare(&self, operator: &Operator, other: &Value) -> Result<bool, (String, String)> {
pub(crate) fn compare(&self, operator: &Operator, other: &Value) -> Result<bool, (String, String)> {
match operator {
_ => {
let coerced = coerce_compare(self, other)?;
@ -545,14 +545,14 @@ impl Value {
}
#[allow(unused)]
crate fn is_string(&self, expected: &str) -> bool {
pub(crate) fn is_string(&self, expected: &str) -> bool {
match self {
Value::Primitive(Primitive::String(s)) if s == expected => true,
other => false,
}
}
// crate fn as_pair(&self) -> Result<(Tagged<Value>, Tagged<Value>), ShellError> {
// pub(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!(
@ -562,7 +562,7 @@ impl Value {
// }
// }
crate fn as_string(&self) -> Result<String, ShellError> {
pub(crate) fn as_string(&self) -> Result<String, ShellError> {
match self {
Value::Primitive(Primitive::String(s)) => Ok(s.clone()),
Value::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)),
@ -577,7 +577,7 @@ impl Value {
}
}
crate fn as_i64(&self) -> Result<i64, ShellError> {
pub(crate) fn as_i64(&self) -> Result<i64, ShellError> {
match self {
Value::Primitive(Primitive::Int(i)) => Ok(*i),
Value::Primitive(Primitive::Bytes(b)) => Ok(*b as i64),
@ -589,7 +589,7 @@ impl Value {
}
}
crate fn is_true(&self) -> bool {
pub(crate) fn is_true(&self) -> bool {
match self {
Value::Primitive(Primitive::Boolean(true)) => true,
_ => false,
@ -640,7 +640,7 @@ impl Value {
}
impl Tagged<Value> {
crate fn as_path(&self) -> Result<PathBuf, ShellError> {
pub(crate) fn as_path(&self) -> Result<PathBuf, ShellError> {
match self.item() {
Value::Primitive(Primitive::Path(path)) => Ok(path.clone()),
other => Err(ShellError::type_error(
@ -651,7 +651,7 @@ impl Tagged<Value> {
}
}
crate fn select_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Tagged<Value> {
pub(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();
@ -666,7 +666,7 @@ crate fn select_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> T
out.into_tagged_value()
}
crate fn reject_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> Tagged<Value> {
pub(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();
@ -683,7 +683,7 @@ crate fn reject_fields(obj: &Value, fields: &[String], tag: impl Into<Tag>) -> T
}
#[allow(unused)]
crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
pub(crate) fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
let descs = obj.data_descriptors();
match descs.iter().find(|d| *d == field) {
None => false,

View File

@ -22,14 +22,14 @@ struct Config {
extra: IndexMap<String, Tagged<Value>>,
}
crate fn config_path() -> Result<PathBuf, ShellError> {
pub(crate) fn config_path() -> Result<PathBuf, ShellError> {
let location = app_root(AppDataType::UserConfig, &APP_INFO)
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
Ok(location.join("config.toml"))
}
crate fn write_config(config: &IndexMap<String, Tagged<Value>>) -> Result<(), ShellError> {
pub(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, Tagged<Value>>) -> Result<(), Sh
Ok(())
}
crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Tagged<Value>>, ShellError> {
pub(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)

View File

@ -72,14 +72,14 @@ impl PartialEq<Value> for Dictionary {
}
impl Dictionary {
pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
pub fn get_data(&self, desc: &String) -> MaybeOwned<'_, Value> {
match self.entries.get(desc) {
Some(v) => MaybeOwned::Borrowed(v),
None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)),
}
}
crate fn get_data_by_key(&self, name: &str) -> Option<&Tagged<Value>> {
pub(crate) fn get_data_by_key(&self, name: &str) -> Option<&Tagged<Value>> {
match self
.entries
.iter()
@ -90,7 +90,7 @@ impl Dictionary {
}
}
crate fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
pub(crate) fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut debug = f.debug_struct("Dictionary");
for (desc, value) in self.entries.iter() {
@ -146,6 +146,13 @@ impl TaggedDictBuilder {
dict: IndexMap::default(),
}
}
pub fn with_capacity(tag: impl Into<Tag>, n: usize) -> TaggedDictBuilder {
TaggedDictBuilder {
tag: tag.into(),
dict: IndexMap::with_capacity(n),
}
}
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
self.dict.insert(key.into(), value.into().tagged(self.tag));

View File

@ -9,7 +9,7 @@ pub enum FileType {
Symlink,
}
crate fn dir_entry_dict(
pub(crate) fn dir_entry_dict(
filename: &std::path::Path,
metadata: &std::fs::Metadata,
tag: impl Into<Tag>,

View File

@ -87,7 +87,7 @@ impl<T> Tagged<T> {
Tagged::from_item(mapped, tag.clone())
}
crate fn copy_span<U>(&self, output: U) -> Tagged<U> {
pub(crate) fn copy_span<U>(&self, output: U) -> Tagged<U> {
let span = self.span();
Tagged::from_simple_spanned_item(output, span)
@ -224,8 +224,8 @@ impl Tag {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
pub struct Span {
crate start: usize,
crate end: usize,
pub(crate) start: usize,
pub(crate) end: usize,
}
impl From<Option<Span>> for Span {
@ -256,7 +256,7 @@ impl Span {
self.start == 0 && self.end == 0
}
pub fn slice(&self, source: &'a str) -> &'a str {
pub fn slice<'a>(&self, source: &'a str) -> &'a str {
&source[self.start..self.end]
}
}

View File

@ -1,29 +0,0 @@
use crate::object::{TaggedDictBuilder, Value};
use crate::prelude::*;
use itertools::join;
use sysinfo::ProcessExt;
crate fn process_dict(proc: &sysinfo::Process, tag: impl Into<Tag>) -> Tagged<Value> {
let mut dict = TaggedDictBuilder::new(tag);
let cmd = proc.cmd();
let cmd_value = if cmd.len() == 0 {
Value::nothing()
} else {
Value::string(join(cmd, ""))
};
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_tagged_value()
}

View File

@ -1,14 +1,9 @@
use crate::object::base as value;
use crate::parser::hir;
use crate::prelude::*;
use log::trace;
pub trait ExtractType: Sized {
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 {
@ -19,14 +14,6 @@ impl<T> ExtractType for T {
name
)))
}
default fn check(_value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
Err(ShellError::unimplemented("ExtractType for T"))
}
default fn syntax_type() -> hir::SyntaxType {
hir::SyntaxType::Any
}
}
impl<T: ExtractType> ExtractType for Vec<Tagged<T>> {
@ -50,20 +37,6 @@ impl<T: ExtractType> ExtractType for Vec<Tagged<T>> {
)),
}
}
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().tagged(value.tag()),
)),
}
}
fn syntax_type() -> hir::SyntaxType {
hir::SyntaxType::List
}
}
impl<T: ExtractType, U: ExtractType> ExtractType for (T, U) {
@ -107,17 +80,6 @@ impl<T: ExtractType> ExtractType for Option<T> {
Ok(result)
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
match value.item() {
Value::Primitive(Primitive::Nothing) => Ok(value),
_ => T::check(value),
}
}
fn syntax_type() -> hir::SyntaxType {
T::syntax_type()
}
}
impl<T: ExtractType> ExtractType for Tagged<T> {
@ -127,14 +89,6 @@ impl<T: ExtractType> ExtractType for Tagged<T> {
Ok(T::extract(value)?.tagged(value.tag()))
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
T::check(value)
}
fn syntax_type() -> hir::SyntaxType {
T::syntax_type()
}
}
impl ExtractType for Value {
@ -143,22 +97,10 @@ impl ExtractType for Value {
Ok(value.item().clone())
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
Ok(value)
}
fn syntax_type() -> hir::SyntaxType {
SyntaxType::Any
}
}
impl ExtractType for bool {
fn syntax_type() -> hir::SyntaxType {
hir::SyntaxType::Boolean
}
fn extract(value: &'a Tagged<Value>) -> Result<bool, ShellError> {
fn extract(value: &Tagged<Value>) -> Result<bool, ShellError> {
trace!("Extracting {:?} for bool", value);
match &value {
@ -173,24 +115,10 @@ impl ExtractType for bool {
other => Err(ShellError::type_error("Boolean", other.tagged_type_name())),
}
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
match &value {
value @ Tagged {
item: Value::Primitive(Primitive::Boolean(_)),
..
} => Ok(value),
other => Err(ShellError::type_error("Boolean", other.tagged_type_name())),
}
}
}
impl ExtractType for std::path::PathBuf {
fn syntax_type() -> hir::SyntaxType {
hir::SyntaxType::Path
}
fn extract(value: &'a Tagged<Value>) -> Result<std::path::PathBuf, ShellError> {
fn extract(value: &Tagged<Value>) -> Result<std::path::PathBuf, ShellError> {
trace!("Extracting {:?} for PathBuf", value);
match &value {
@ -201,16 +129,6 @@ impl ExtractType for std::path::PathBuf {
other => Err(ShellError::type_error("Path", other.tagged_type_name())),
}
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
match &value {
v @ Tagged {
item: Value::Primitive(Primitive::Path(_)),
..
} => Ok(v),
other => Err(ShellError::type_error("Path", other.tagged_type_name())),
}
}
}
impl ExtractType for i64 {
@ -225,16 +143,6 @@ impl ExtractType for i64 {
other => Err(ShellError::type_error("Integer", other.tagged_type_name())),
}
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
match value {
v @ Tagged {
item: Value::Primitive(Primitive::Int(_)),
..
} => Ok(v),
other => Err(ShellError::type_error("Integer", other.tagged_type_name())),
}
}
}
impl ExtractType for String {
@ -249,31 +157,9 @@ impl ExtractType for String {
other => Err(ShellError::type_error("String", other.tagged_type_name())),
}
}
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
match value {
v @ Tagged {
item: Value::Primitive(Primitive::String(_)),
..
} => Ok(v),
other => Err(ShellError::type_error("String", other.tagged_type_name())),
}
}
}
impl ExtractType for value::Block {
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
trace!("Extracting {:?} for Block", value);
match value {
v @ Tagged {
item: Value::Block(_),
..
} => Ok(v),
other => Err(ShellError::type_error("Block", other.tagged_type_name())),
}
}
fn extract(value: &Tagged<Value>) -> Result<value::Block, ShellError> {
match value {
Tagged {

View File

@ -1,25 +1,25 @@
crate mod deserializer;
crate mod hir;
crate mod parse;
crate mod parse_command;
crate mod registry;
pub(crate) mod deserializer;
pub(crate) mod hir;
pub(crate) mod parse;
pub(crate) mod parse_command;
pub(crate) mod registry;
use crate::errors::ShellError;
crate use deserializer::ConfigDeserializer;
crate use hir::baseline_parse_tokens::baseline_parse_tokens;
crate use parse::call_node::CallNode;
crate use parse::files::Files;
crate use parse::flag::Flag;
crate use parse::operator::Operator;
crate use parse::parser::{nom_input, pipeline};
crate use parse::pipeline::{Pipeline, PipelineElement};
crate use parse::text::Text;
crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
crate use parse::tokens::{RawToken, Token};
crate use parse::unit::Unit;
crate use parse_command::parse_command;
crate use registry::CommandRegistry;
pub(crate) use deserializer::ConfigDeserializer;
pub(crate) use hir::baseline_parse_tokens::baseline_parse_tokens;
pub(crate) use parse::call_node::CallNode;
pub(crate) use parse::files::Files;
pub(crate) use parse::flag::Flag;
pub(crate) use parse::operator::Operator;
pub(crate) use parse::parser::{nom_input, pipeline};
pub(crate) use parse::pipeline::{Pipeline, PipelineElement};
pub(crate) use parse::text::Text;
pub(crate) use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
pub(crate) use parse::tokens::{RawToken, Token};
pub(crate) use parse::unit::Unit;
pub(crate) use parse_command::parse_command;
pub(crate) use registry::CommandRegistry;
pub fn parse(input: &str) -> Result<TokenNode, ShellError> {
let _ = pretty_env_logger::try_init();

View File

@ -16,7 +16,7 @@ pub struct ConfigDeserializer<'de> {
position: usize,
}
impl ConfigDeserializer<'de> {
impl<'de> ConfigDeserializer<'de> {
pub fn from_call_info(call: CallInfo) -> ConfigDeserializer<'de> {
ConfigDeserializer {
call,

View File

@ -1,9 +1,9 @@
crate mod baseline_parse;
crate mod baseline_parse_tokens;
crate mod binary;
crate mod external_command;
crate mod named;
crate mod path;
pub(crate) mod baseline_parse;
pub(crate) mod baseline_parse_tokens;
pub(crate) mod binary;
pub(crate) mod external_command;
pub(crate) mod named;
pub(crate) mod path;
use crate::parser::{registry, Unit};
use crate::prelude::*;
@ -15,15 +15,15 @@ use std::path::PathBuf;
use crate::evaluate::Scope;
crate use self::baseline_parse::{
pub(crate) use self::baseline_parse::{
baseline_parse_single_token, baseline_parse_token_as_number, baseline_parse_token_as_path,
baseline_parse_token_as_string,
};
crate use self::baseline_parse_tokens::{baseline_parse_next_expr, TokensIterator};
crate use self::binary::Binary;
crate use self::external_command::ExternalCommand;
crate use self::named::NamedArguments;
crate use self::path::Path;
pub(crate) use self::baseline_parse_tokens::{baseline_parse_next_expr, TokensIterator};
pub(crate) use self::binary::Binary;
pub(crate) use self::external_command::ExternalCommand;
pub(crate) use self::named::NamedArguments;
pub(crate) use self::path::Path;
pub use self::baseline_parse_tokens::SyntaxType;
@ -129,51 +129,51 @@ impl RawExpression {
pub type Expression = Tagged<RawExpression>;
impl Expression {
crate fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
pub(crate) fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
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 {
pub(crate) fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
span,
)
}
crate fn synthetic_string(s: impl Into<String>) -> Expression {
pub(crate) fn synthetic_string(s: impl Into<String>) -> Expression {
RawExpression::Synthetic(Synthetic::String(s.into())).tagged_unknown()
}
crate fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
pub(crate) fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(
RawExpression::Literal(Literal::String(inner.into())),
outer.into(),
)
}
crate fn file_path(path: impl Into<PathBuf>, outer: impl Into<Span>) -> Expression {
pub(crate) fn file_path(path: impl Into<PathBuf>, outer: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(RawExpression::FilePath(path.into()), outer.into())
}
crate fn bare(span: impl Into<Span>) -> Expression {
pub(crate) fn bare(span: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Bare), span.into())
}
crate fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
pub(crate) fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(
RawExpression::Variable(Variable::Other(inner.into())),
outer.into(),
)
}
crate fn external_command(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
pub(crate) fn external_command(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(
RawExpression::ExternalCommand(ExternalCommand::new(inner.into())),
outer.into(),
)
}
crate fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
pub(crate) fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
Tagged::from_simple_spanned_item(
RawExpression::Variable(Variable::It(inner.into())),
outer.into(),

View File

@ -331,7 +331,7 @@ pub struct TokensIterator<'a> {
seen: indexmap::IndexSet<usize>,
}
impl TokensIterator<'a> {
impl TokensIterator<'_> {
pub fn remove(&mut self, position: usize) {
self.seen.insert(position);
}
@ -404,7 +404,7 @@ impl TokensIterator<'a> {
}
}
impl Iterator for TokensIterator<'a> {
impl<'a> Iterator for TokensIterator<'a> {
type Item = &'a TokenNode;
fn next(&mut self) -> Option<&'a TokenNode> {

View File

@ -19,7 +19,7 @@ pub enum NamedValue {
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, new)]
pub struct NamedArguments {
#[new(default)]
crate named: IndexMap<String, NamedValue>,
pub(crate) named: IndexMap<String, NamedValue>,
}
impl ToDebug for NamedArguments {

View File

@ -1,12 +1,12 @@
crate mod call_node;
crate mod files;
crate mod flag;
crate mod operator;
crate mod parser;
crate mod pipeline;
crate mod text;
crate mod token_tree;
crate mod token_tree_builder;
crate mod tokens;
crate mod unit;
crate mod util;
pub(crate) mod call_node;
pub(crate) mod files;
pub(crate) mod flag;
pub(crate) mod operator;
pub(crate) mod parser;
pub(crate) mod pipeline;
pub(crate) mod text;
pub(crate) mod token_tree;
pub(crate) mod token_tree_builder;
pub(crate) mod tokens;
pub(crate) mod unit;
pub(crate) mod util;

View File

@ -23,7 +23,7 @@ use std::str::FromStr;
pub type NomSpan<'a> = LocatedSpan<&'a str>;
pub fn nom_input(s: &'a str) -> NomSpan<'a> {
pub fn nom_input(s: &str) -> NomSpan<'_> {
LocatedSpan::new(s)
}

View File

@ -5,8 +5,8 @@ use getset::Getters;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, new)]
pub struct Pipeline {
crate parts: Vec<PipelineElement>,
crate post_ws: Option<Span>,
pub(crate) parts: Vec<PipelineElement>,
pub(crate) post_ws: Option<Span>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Getters, new)]

View File

@ -213,7 +213,7 @@ impl Serialize for Text {
}
}
impl Deserialize<'de> for Text {
impl<'de> Deserialize<'de> for Text {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,

View File

@ -27,7 +27,7 @@ pub struct DebugTokenNode<'a> {
source: &'a Text,
}
impl fmt::Debug for DebugTokenNode<'a> {
impl fmt::Debug for DebugTokenNode<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.node {
TokenNode::Token(t) => write!(f, "{:?}", t.debug(self.source)),
@ -115,7 +115,7 @@ impl TokenNode {
.to_string()
}
pub fn debug(&'a self, source: &'a Text) -> DebugTokenNode<'a> {
pub fn debug<'a>(&'a self, source: &'a Text) -> DebugTokenNode<'a> {
DebugTokenNode { node: self, source }
}
@ -123,7 +123,7 @@ impl TokenNode {
self.span().slice(source).to_string()
}
pub fn source(&self, source: &'a Text) -> &'a str {
pub fn source<'a>(&self, source: &'a Text) -> &'a str {
self.span().slice(source)
}
@ -157,7 +157,7 @@ impl TokenNode {
}
}
crate fn as_flag(&self, value: &str, source: &Text) -> Option<Tagged<Flag>> {
pub(crate) fn as_flag(&self, value: &str, source: &Text) -> Option<Tagged<Flag>> {
match self {
TokenNode::Flag(
flag @ Tagged {

View File

@ -28,7 +28,7 @@ impl RawToken {
pub type Token = Tagged<RawToken>;
impl Token {
pub fn debug(&self, source: &'a Text) -> DebugToken<'a> {
pub fn debug<'a>(&self, source: &'a Text) -> DebugToken<'a> {
DebugToken {
node: *self,
source,
@ -41,7 +41,7 @@ pub struct DebugToken<'a> {
source: &'a Text,
}
impl fmt::Debug for DebugToken<'a> {
impl fmt::Debug for DebugToken<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.node.span().slice(self.source))
}

View File

@ -24,7 +24,7 @@ impl Unit {
}
}
crate fn compute(&self, size: i64) -> Value {
pub(crate) fn compute(&self, size: i64) -> Value {
Value::int(match self {
Unit::B => size,
Unit::KB => size * 1024,

View File

@ -205,7 +205,7 @@ fn extract_switch(name: &str, tokens: &mut hir::TokensIterator<'_>, source: &Tex
fn extract_mandatory(
config: &Signature,
name: &str,
tokens: &mut hir::TokensIterator<'a>,
tokens: &mut hir::TokensIterator<'_>,
source: &Text,
span: Span,
) -> Result<(usize, Tagged<Flag>), ShellError> {
@ -227,7 +227,7 @@ fn extract_mandatory(
fn extract_optional(
name: &str,
tokens: &mut hir::TokensIterator<'a>,
tokens: &mut hir::TokensIterator<'_>,
source: &Text,
) -> Result<(Option<(usize, Tagged<Flag>)>), ShellError> {
let flag = tokens.extract(|t| t.as_flag(name, source));
@ -241,7 +241,7 @@ fn extract_optional(
}
}
pub fn trace_remaining(desc: &'static str, tail: hir::TokensIterator<'a>, source: &Text) {
pub fn trace_remaining(desc: &'static str, tail: hir::TokensIterator<'_>, source: &Text) {
trace!(
"{} = {:?}",
desc,

View File

@ -1,5 +1,5 @@
// TODO: Temporary redirect
crate use crate::context::CommandRegistry;
pub(crate) use crate::context::CommandRegistry;
use crate::evaluate::{evaluate_baseline_expr, Scope};
use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode};
use crate::prelude::*;
@ -46,7 +46,7 @@ impl PositionalType {
}
#[allow(unused)]
crate fn to_coerce_hint(&self) -> Option<SyntaxType> {
pub(crate) fn to_coerce_hint(&self) -> Option<SyntaxType> {
match self {
PositionalType::Mandatory(_, SyntaxType::Block)
| PositionalType::Optional(_, SyntaxType::Block) => Some(SyntaxType::Block),
@ -54,14 +54,14 @@ impl PositionalType {
}
}
crate fn name(&self) -> &str {
pub(crate) fn name(&self) -> &str {
match self {
PositionalType::Mandatory(s, _) => s,
PositionalType::Optional(s, _) => s,
}
}
crate fn syntax_type(&self) -> SyntaxType {
pub(crate) fn syntax_type(&self) -> SyntaxType {
match *self {
PositionalType::Mandatory(_, t) => t,
PositionalType::Optional(_, t) => t,
@ -158,7 +158,7 @@ pub struct DebugEvaluatedPositional<'a> {
positional: &'a Option<Vec<Tagged<Value>>>,
}
impl fmt::Debug for DebugEvaluatedPositional<'a> {
impl fmt::Debug for DebugEvaluatedPositional<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.positional {
None => write!(f, "None"),
@ -175,7 +175,7 @@ pub struct DebugEvaluatedNamed<'a> {
named: &'a Option<IndexMap<String, Tagged<Value>>>,
}
impl fmt::Debug for DebugEvaluatedNamed<'a> {
impl fmt::Debug for DebugEvaluatedNamed<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.named {
None => write!(f, "None"),
@ -191,7 +191,7 @@ pub struct DebugEvaluatedArgs<'a> {
args: &'a EvaluatedArgs,
}
impl fmt::Debug for DebugEvaluatedArgs<'a> {
impl fmt::Debug for DebugEvaluatedArgs<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut s = f.debug_struct("Args");
@ -206,7 +206,7 @@ impl fmt::Debug for DebugEvaluatedArgs<'a> {
}
impl EvaluatedArgs {
pub fn debug(&'a self) -> DebugEvaluatedArgs<'a> {
pub fn debug(&self) -> DebugEvaluatedArgs<'_> {
DebugEvaluatedArgs { args: self }
}
@ -248,7 +248,7 @@ impl EvaluatedArgs {
}
}
pub fn positional_iter(&'a self) -> PositionalIter<'a> {
pub fn positional_iter(&self) -> PositionalIter<'_> {
match &self.positional {
None => PositionalIter::Empty,
Some(v) => {
@ -264,7 +264,7 @@ pub enum PositionalIter<'a> {
Array(std::slice::Iter<'a, Tagged<Value>>),
}
impl Iterator for PositionalIter<'a> {
impl<'a> Iterator for PositionalIter<'a> {
type Item = &'a Tagged<Value>;
fn next(&mut self) -> Option<Self::Item> {
@ -276,7 +276,7 @@ impl Iterator for PositionalIter<'a> {
}
impl Signature {
crate fn parse_args(
pub(crate) fn parse_args(
&self,
call: &Tagged<CallNode>,
context: &Context,
@ -290,12 +290,12 @@ impl Signature {
}
#[allow(unused)]
crate fn signature(&self) -> String {
pub(crate) fn signature(&self) -> String {
format!("TODO")
}
}
crate fn evaluate_args(
pub(crate) fn evaluate_args(
call: &hir::Call,
registry: &CommandRegistry,
scope: &Scope,

View File

@ -1,11 +1,13 @@
use std::ffi::OsStr;
use futures::executor::block_on;
use futures::stream::StreamExt;
use heim::{disk, memory, net};
use nu::{
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
Tag, Tagged, TaggedDictBuilder, Value,
};
use std::ffi::OsStr;
use heim::{disk, memory, net, sensors, host};
use heim::units::{frequency, information, time, thermodynamic_temperature};
struct Sys;
impl Sys {
@ -15,52 +17,65 @@ impl Sys {
}
async fn cpu(tag: Tag) -> Option<Tagged<Value>> {
if let (Ok(num_cpu), Ok(cpu_speed)) = (
heim::cpu::logical_count().await,
heim::cpu::frequency().await,
) {
let mut cpu_idx = TaggedDictBuilder::new(tag);
cpu_idx.insert("cores", Primitive::Int(num_cpu as i64));
match futures::future::try_join(
heim::cpu::logical_count(),
heim::cpu::frequency(),
).await {
Ok((num_cpu, cpu_speed)) => {
let mut cpu_idx = TaggedDictBuilder::with_capacity(tag, 4);
cpu_idx.insert("cores", Primitive::Int(num_cpu as i64));
let current_speed =
(cpu_speed.current().get() as f64 / 1000000000.0 * 100.0).round() / 100.0;
cpu_idx.insert("current ghz", Primitive::Float(current_speed.into()));
let current_speed =
(cpu_speed.current().get::<frequency::hertz>() as f64 / 1_000_000_000.0 * 100.0).round() / 100.0;
cpu_idx.insert("current ghz", Primitive::Float(current_speed.into()));
if let Some(min_speed) = cpu_speed.min() {
let min_speed = (min_speed.get() as f64 / 1000000000.0 * 100.0).round() / 100.0;
cpu_idx.insert("min ghz", Primitive::Float(min_speed.into()));
}
if let Some(min_speed) = cpu_speed.min() {
let min_speed = (min_speed.get::<frequency::hertz>() as f64 / 1_000_000_000.0 * 100.0).round() / 100.0;
cpu_idx.insert("min ghz", Primitive::Float(min_speed.into()));
}
if let Some(max_speed) = cpu_speed.max() {
let max_speed = (max_speed.get() as f64 / 1000000000.0 * 100.0).round() / 100.0;
cpu_idx.insert("max ghz", Primitive::Float(max_speed.into()));
}
Some(cpu_idx.into_tagged_value())
} else {
None
if let Some(max_speed) = cpu_speed.max() {
let max_speed = (max_speed.get::<frequency::hertz>() as f64 / 1_000_000_000.0 * 100.0).round() / 100.0;
cpu_idx.insert("max ghz", Primitive::Float(max_speed.into()));
}
Some(cpu_idx.into_tagged_value())
},
Err(_) => None,
}
}
async fn mem(tag: Tag) -> Tagged<Value> {
let mut dict = TaggedDictBuilder::new(tag);
let mut dict = TaggedDictBuilder::with_capacity(tag, 4);
if let Ok(memory) = memory::memory().await {
dict.insert("total", Value::bytes(memory.total().get()));
dict.insert("free", Value::bytes(memory.free().get()));
let (memory_result, swap_result) = futures::future::join(
memory::memory(),
memory::swap()
).await;
if let Ok(memory) = memory_result {
dict.insert("total", Value::bytes(memory.total().get::<information::byte>()));
dict.insert("free", Value::bytes(memory.free().get::<information::byte>()));
}
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()));
if let Ok(swap) = swap_result {
dict.insert("swap total", Value::bytes(swap.total().get::<information::byte>()));
dict.insert("swap free", Value::bytes(swap.free().get::<information::byte>()));
}
dict.into_tagged_value()
}
async fn host(tag: Tag) -> Tagged<Value> {
let mut dict = TaggedDictBuilder::new(tag);
let mut dict = TaggedDictBuilder::with_capacity(tag, 6);
let (platform_result, uptime_result) = futures::future::join(
host::platform(),
host::uptime(),
).await;
// OS
if let Ok(platform) = heim::host::platform().await {
if let Ok(platform) = platform_result {
dict.insert("name", Value::string(platform.system()));
dict.insert("release", Value::string(platform.release()));
dict.insert("hostname", Value::string(platform.hostname()));
@ -68,10 +83,10 @@ async fn host(tag: Tag) -> Tagged<Value> {
}
// Uptime
if let Ok(uptime) = heim::host::uptime().await {
let mut uptime_dict = TaggedDictBuilder::new(tag);
if let Ok(uptime) = uptime_result {
let mut uptime_dict = TaggedDictBuilder::with_capacity(tag, 4);
let uptime = uptime.get().round() as i64;
let uptime = uptime.get::<time::second>().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;
@ -82,11 +97,11 @@ async fn host(tag: Tag) -> Tagged<Value> {
uptime_dict.insert("mins", Value::int(minutes));
uptime_dict.insert("secs", Value::int(seconds));
dict.insert_tagged("uptime", uptime_dict.into_tagged_value());
dict.insert_tagged("uptime", uptime_dict);
}
// Users
let mut users = heim::host::users();
let mut users = host::users();
let mut user_vec = vec![];
while let Some(user) = users.next().await {
if let Ok(user) = user {
@ -104,7 +119,7 @@ async fn disks(tag: Tag) -> Option<Value> {
let mut partitions = disk::partitions_physical();
while let Some(part) = partitions.next().await {
if let Ok(part) = part {
let mut dict = TaggedDictBuilder::new(tag);
let mut dict = TaggedDictBuilder::with_capacity(tag, 6);
dict.insert(
"device",
Value::string(
@ -116,16 +131,18 @@ async fn disks(tag: Tag) -> Option<Value> {
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()));
dict.insert("total", Value::bytes(usage.total().get::<information::byte>()));
dict.insert("used", Value::bytes(usage.used().get::<information::byte>()));
dict.insert("free", Value::bytes(usage.free().get::<information::byte>()));
}
output.push(dict.into_tagged_value());
}
}
if output.len() > 0 {
if !output.is_empty() {
Some(Value::List(output))
} else {
None
@ -167,57 +184,56 @@ async fn battery(tag: Tag) -> Option<Value> {
}
}
if output.len() > 0 {
if !output.is_empty() {
Some(Value::List(output))
} else {
None
}
}
// FIXME: add back when heim releases new version
// async fn temp(tag: Tag) -> Option<Value> {
// let mut output = vec![];
async fn temp(tag: Tag) -> Option<Value> {
let mut output = vec![];
// let mut sensors = sensors::temperatures();
// while let Some(sensor) = sensors.next().await {
// if let Ok(sensor) = sensor {
// let mut dict = TaggedDictBuilder::new(tag);
// dict.insert("unit", Value::string(sensor.unit()));
// if let Some(label) = sensor.label() {
// dict.insert("label", Value::string(label));
// }
// dict.insert("temp", Value::float(sensor.current().get()));
// if let Some(high) = sensor.high() {
// dict.insert("high", Value::float(high.get()));
// }
// if let Some(critical) = sensor.critical() {
// dict.insert("critical", Value::float(critical.get()));
// }
let mut sensors = sensors::temperatures();
while let Some(sensor) = sensors.next().await {
if let Ok(sensor) = sensor {
let mut dict = TaggedDictBuilder::new(tag);
dict.insert("unit", Value::string(sensor.unit()));
if let Some(label) = sensor.label() {
dict.insert("label", Value::string(label));
}
dict.insert("temp", Value::float(sensor.current().get::<thermodynamic_temperature::degree_celsius>() as f64));
if let Some(high) = sensor.high() {
dict.insert("high", Value::float(high.get::<thermodynamic_temperature::degree_celsius>() as f64));
}
if let Some(critical) = sensor.critical() {
dict.insert("critical", Value::float(critical.get::<thermodynamic_temperature::degree_celsius>() as f64));
}
// output.push(dict.into_tagged_value());
// }
// }
output.push(dict.into_tagged_value());
}
}
// if output.len() > 0 {
// Some(Value::List(output))
// } else {
// None
// }
// }
if !output.is_empty() {
Some(Value::List(output))
} else {
None
}
}
async fn net(tag: Tag) -> Option<Value> {
let mut output = vec![];
let mut io_counters = net::io_counters();
while let Some(nic) = io_counters.next().await {
if let Ok(nic) = nic {
let mut network_idx = TaggedDictBuilder::new(tag);
let mut network_idx = TaggedDictBuilder::with_capacity(tag, 3);
network_idx.insert("name", Value::string(nic.interface()));
network_idx.insert("sent", Value::bytes(nic.bytes_sent().get()));
network_idx.insert("recv", Value::bytes(nic.bytes_recv().get()));
network_idx.insert("sent", Value::bytes(nic.bytes_sent().get::<information::byte>()));
network_idx.insert("recv", Value::bytes(nic.bytes_recv().get::<information::byte>()));
output.push(network_idx.into_tagged_value());
}
}
if output.len() > 0 {
if !output.is_empty() {
Some(Value::List(output))
} else {
None
@ -225,23 +241,35 @@ async fn net(tag: Tag) -> Option<Value> {
}
async fn sysinfo(tag: Tag) -> Vec<Tagged<Value>> {
let mut sysinfo = TaggedDictBuilder::new(tag);
let mut sysinfo = TaggedDictBuilder::with_capacity(tag, 7);
let (host, cpu, disks, memory, temp) = futures::future::join5(
host(tag),
cpu(tag),
disks(tag),
mem(tag),
temp(tag),
).await;
let (net, battery) = futures::future::join(
net(tag),
battery(tag),
).await;
sysinfo.insert_tagged("host", host(tag).await);
if let Some(cpu) = cpu(tag).await {
sysinfo.insert_tagged("host", host);
if let Some(cpu) = cpu {
sysinfo.insert_tagged("cpu", cpu);
}
if let Some(disks) = disks(tag).await {
if let Some(disks) = disks {
sysinfo.insert("disks", disks);
}
sysinfo.insert_tagged("mem", mem(tag).await);
// if let Some(temp) = temp(tag).await {
// sysinfo.insert("temp", temp);
// }
if let Some(net) = net(tag).await {
sysinfo.insert_tagged("mem", memory);
if let Some(temp) = temp {
sysinfo.insert("temp", temp);
}
if let Some(net) = net {
sysinfo.insert("net", net);
}
if let Some(battery) = battery(tag).await {
if let Some(battery) = battery {
sysinfo.insert("battery", battery);
}
@ -256,7 +284,7 @@ impl Plugin for Sys {
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))
.map(ReturnSuccess::value)
.collect())
}

View File

@ -54,13 +54,25 @@ fn paint_textview(
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;
if chr == '\t' {
for _ in 0..8 {
frame_buffer.push((
' ',
style.foreground.r,
style.foreground.g,
style.foreground.b,
));
}
pos += 8;
} else {
frame_buffer.push((
chr,
style.foreground.r,
style.foreground.g,
style.foreground.b,
));
pos += 1;
}
}
}
DrawCommand::NextLine => {

View File

@ -47,37 +47,38 @@ macro_rules! trace_out_stream {
}};
}
crate use crate::cli::MaybeOwned;
crate use crate::commands::command::{
pub(crate) use crate::cli::MaybeOwned;
pub(crate) use crate::commands::command::{
CallInfo, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
};
crate use crate::commands::{PerItemCommand, RawCommandArgs};
crate use crate::context::CommandRegistry;
crate use crate::context::{Context, SpanSource};
crate use crate::env::host::handle_unexpected;
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::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};
crate use futures_async_stream::async_stream_block;
pub(crate) use crate::commands::PerItemCommand;
pub(crate) use crate::commands::RawCommandArgs;
pub(crate) use crate::context::CommandRegistry;
pub(crate) use crate::context::{Context, SpanSource};
pub(crate) use crate::env::host::handle_unexpected;
pub(crate) use crate::env::Host;
pub(crate) use crate::errors::ShellError;
pub(crate) use crate::object::base as value;
pub(crate) use crate::object::meta::{Tag, Tagged, TaggedItem};
pub(crate) use crate::object::types::ExtractType;
pub(crate) use crate::object::{Primitive, Value};
pub(crate) use crate::parser::hir::SyntaxType;
pub(crate) use crate::parser::registry::Signature;
pub(crate) use crate::shell::filesystem_shell::FilesystemShell;
pub(crate) use crate::shell::shell_manager::ShellManager;
pub(crate) use crate::shell::value_shell::ValueShell;
pub(crate) use crate::stream::{InputStream, OutputStream};
pub(crate) use crate::traits::{HasSpan, ToDebug};
pub(crate) use crate::Span;
pub(crate) use crate::Text;
pub(crate) use futures::stream::BoxStream;
pub(crate) use futures::{FutureExt, Stream, StreamExt};
pub(crate) use futures_async_stream::async_stream_block;
#[allow(unused)]
crate use serde::{Deserialize, Serialize};
crate use std::collections::VecDeque;
crate use std::future::Future;
crate use std::sync::{Arc, Mutex};
pub(crate) use serde::{Deserialize, Serialize};
pub(crate) use std::collections::VecDeque;
pub(crate) use std::future::Future;
pub(crate) use std::sync::{Arc, Mutex};
pub trait FromInputStream {
fn from_input_stream(self) -> OutputStream;

View File

@ -1,8 +1,8 @@
crate mod completer;
crate mod filesystem_shell;
crate mod helper;
crate mod shell;
crate mod shell_manager;
crate mod value_shell;
pub(crate) mod completer;
pub(crate) mod filesystem_shell;
pub(crate) mod helper;
pub(crate) mod shell;
pub(crate) mod shell_manager;
pub(crate) mod value_shell;
crate use helper::Helper;
pub(crate) use helper::Helper;

View File

@ -3,7 +3,7 @@ use derive_new::new;
use rustyline::completion::{Completer, FilenameCompleter};
#[derive(new)]
crate struct NuCompleter {
pub(crate) struct NuCompleter {
pub file_completer: FilenameCompleter,
pub commands: CommandRegistry,
}

View File

@ -14,7 +14,7 @@ use rustyline::hint::{Hinter, HistoryHinter};
use std::path::{Path, PathBuf};
pub struct FilesystemShell {
crate path: String,
pub(crate) path: String,
completer: NuCompleter,
hinter: HistoryHinter,
}

View File

@ -11,12 +11,12 @@ use rustyline::highlight::Highlighter;
use rustyline::hint::Hinter;
use std::borrow::Cow::{self, Owned};
crate struct Helper {
pub(crate) struct Helper {
helper: ShellManager,
}
impl Helper {
crate fn new(helper: ShellManager) -> Helper {
pub(crate) fn new(helper: ShellManager) -> Helper {
Helper { helper }
}
}

View File

@ -14,8 +14,8 @@ use std::sync::{Arc, Mutex};
#[derive(Clone, Debug)]
pub struct ShellManager {
crate current_shell: usize,
crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
pub(crate) current_shell: usize,
pub(crate) shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
}
impl ShellManager {

View File

@ -11,8 +11,8 @@ use std::path::PathBuf;
#[derive(Clone, Debug)]
pub struct ValueShell {
crate path: String,
crate value: Tagged<Value>,
pub(crate) path: String,
pub(crate) value: Tagged<Value>,
}
impl ValueShell {

View File

@ -1,7 +1,7 @@
use crate::prelude::*;
pub struct InputStream {
crate values: BoxStream<'static, Tagged<Value>>,
pub(crate) values: BoxStream<'static, Tagged<Value>>,
}
impl InputStream {
@ -49,7 +49,7 @@ impl From<Vec<Tagged<Value>>> for InputStream {
}
pub struct OutputStream {
crate values: BoxStream<'static, ReturnValue>,
pub(crate) values: BoxStream<'static, ReturnValue>,
}
impl OutputStream {

View File

@ -6,7 +6,7 @@ pub struct Debuggable<'a, T: ToDebug> {
source: &'a str,
}
impl<T: ToDebug> fmt::Display for Debuggable<'a, T> {
impl<T: ToDebug> fmt::Display for Debuggable<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt_debug(f, self.source)
}
@ -17,7 +17,7 @@ pub trait HasSpan {
}
pub trait ToDebug: Sized {
fn debug(&'a self, source: &'a str) -> Debuggable<'a, Self> {
fn debug<'a>(&'a self, source: &'a str) -> Debuggable<'a, Self> {
Debuggable {
inner: self,
source,

View File

@ -185,7 +185,7 @@ impl FileStructure {
Ok(())
}
fn build(&mut self, src: &'a Path, lvl: usize) -> Result<(), ShellError> {
fn build(&mut self, src: &Path, lvl: usize) -> Result<(), ShellError> {
let source = dunce::canonicalize(src)?;
if source.is_dir() {
@ -250,6 +250,10 @@ mod tests {
loc: fixtures().join("caco3_plastics.csv"),
at: 0
},
Res {
loc: fixtures().join("caco3_plastics.tsv"),
at: 0
},
Res {
loc: fixtures().join("cargo_sample.toml"),
at: 0

View File

@ -1,10 +1,11 @@
mod helpers;
use helpers::in_directory as cwd;
#[test]
fn cd_directory_not_found() {
let actual = nu_error!(cwd("tests/fixtures"), "cd dir_that_does_not_exist");
let actual = nu_error!(
cwd: "tests/fixtures",
"cd dir_that_does_not_exist"
);
assert!(actual.contains("dir_that_does_not_exist"));
assert!(actual.contains("directory not found"));

View File

@ -1,19 +1,20 @@
mod helpers;
use helpers::{in_directory as cwd, dir_exists_at, file_exists_at, files_exist_at, Playground, Stub::*};
use nu::AbsoluteFile;
use std::path::{Path, PathBuf};
use helpers::{files_exist_at, Playground, Stub::*};
use std::path::Path;
#[test]
fn copies_a_file() {
Playground::setup("cp_test_1", |dirs, _| {
nu!(
cwd(dirs.root()),
cwd: dirs.root(),
"cp {} cp_test_1/sample.ini",
dirs.formats().join("sample.ini")
);
assert!(file_exists_at(dirs.test().join("sample.ini")));
assert!(dirs.test().join("sample.ini").exists());
});
}
@ -23,19 +24,22 @@ fn copies_the_file_inside_directory_if_path_to_copy_is_directory() {
let expected_file = AbsoluteFile::new(dirs.test().join("sample.ini"));
nu!(
cwd(dirs.formats()),
cwd: dirs.formats(),
"cp ../formats/sample.ini {}",
expected_file.dir()
);
assert!(file_exists_at(dirs.test().join("sample.ini")));
assert!(dirs.test().join("sample.ini").exists());
})
}
#[test]
fn error_if_attempting_to_copy_a_directory_to_another_directory() {
Playground::setup("cp_test_3", |dirs, _| {
let actual = nu_error!(dirs.formats(), "cp ../formats {}", dirs.test());
let actual = nu_error!(
cwd: dirs.formats(),
"cp ../formats {}", dirs.test()
);
assert!(actual.contains("../formats"));
assert!(actual.contains("is a directory (not copied)"));
@ -56,40 +60,25 @@ fn copies_the_directory_inside_directory_if_path_to_copy_is_directory_and_with_r
let expected_dir = dirs.test().join("expected").join("originals");
nu!(cwd(dirs.test()), "cp originals expected --recursive");
nu!(
cwd: dirs.test(),
"cp originals expected --recursive"
);
assert!(dir_exists_at(PathBuf::from(&expected_dir)));
assert!(expected_dir.exists());
assert!(files_exist_at(
vec![
Path::new("yehuda.txt"),
Path::new("jonathan.txt"),
Path::new("andres.txt")
],
PathBuf::from(&expected_dir)
expected_dir
));
})
}
#[test]
fn deep_copies_with_recursive_flag() {
r#"
Given these files and directories
originals
originals/manifest.txt
originals/contributors
originals/contributors/yehuda.txt
originals/contributors/jonathan.txt
originals/contributors/andres.txt
originals/contributors/jonathan
originals/contributors/jonathan/errors.txt
originals/contributors/jonathan/multishells.txt
originals/contributors/andres
originals/contributors/andres/coverage.txt
originals/contributors/andres/commands.txt
originals/contributors/yehuda
originals/contributors/yehuda/defer-evaluation.txt
"#;
Playground::setup("cp_test_5", |dirs, sandbox| {
sandbox
.within("originals")
@ -114,20 +103,23 @@ fn deep_copies_with_recursive_flag() {
let andres_expected_copied_dir = expected_dir.join("contributors").join("andres");
let yehudas_expected_copied_dir = expected_dir.join("contributors").join("yehuda");
nu!(cwd(dirs.test()), "cp originals expected --recursive");
nu!(
cwd: dirs.test(),
"cp originals expected --recursive"
);
assert!(dir_exists_at(PathBuf::from(&expected_dir)));
assert!(expected_dir.exists());
assert!(files_exist_at(
vec![Path::new("errors.txt"), Path::new("multishells.txt")],
PathBuf::from(&jonathans_expected_copied_dir)
jonathans_expected_copied_dir
));
assert!(files_exist_at(
vec![Path::new("coverage.txt"), Path::new("commands.txt")],
PathBuf::from(&andres_expected_copied_dir)
andres_expected_copied_dir
));
assert!(files_exist_at(
vec![Path::new("defer-evaluation.txt")],
PathBuf::from(&yehudas_expected_copied_dir)
yehudas_expected_copied_dir
));
})
}
@ -135,7 +127,10 @@ fn deep_copies_with_recursive_flag() {
#[test]
fn copies_using_path_with_wildcard() {
Playground::setup("cp_test_6", |dirs, _| {
nu!(cwd(dirs.formats()), "cp ../formats/* {}", dirs.test());
nu!(
cwd: dirs.formats(),
"cp ../formats/* {}", dirs.test()
);
assert!(files_exist_at(
vec![
@ -154,7 +149,10 @@ fn copies_using_path_with_wildcard() {
#[test]
fn copies_using_a_glob() {
Playground::setup("cp_test_7", |dirs, _| {
nu!(cwd(dirs.formats()), "cp * {}", dirs.test());
nu!(
cwd: dirs.formats(),
"cp * {}", dirs.test()
);
assert!(files_exist_at(
vec![

View File

@ -1,8 +1,9 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use std::path::{Path, PathBuf};
use helpers::{Playground, Stub::*};
use std::path::Path;
#[test]
fn knows_the_filesystems_entered() {
@ -28,47 +29,47 @@ fn knows_the_filesystems_entered() {
let expected_recycled = expected.join("recycled");
nu!(
cwd(dirs.test()),
cwd: dirs.test(),
r#"
enter expected
mkdir recycled
enter ../red_pill
mv jonathan.nu ../expected
enter ../blue_pill
cp *.nxt ../expected/recycled
p
p
mv ../red_pill/yehuda.nu .
n
mv andres.nu ../expected/andres.nu
exit
cd ..
rm red_pill --recursive
exit
n
rm blue_pill --recursive
exit
"#
enter expected
mkdir recycled
enter ../red_pill
mv jonathan.nu ../expected
enter ../blue_pill
cp *.nxt ../expected/recycled
p
p
mv ../red_pill/yehuda.nu .
n
mv andres.nu ../expected/andres.nu
exit
cd ..
rm red_pill --recursive
exit
n
rm blue_pill --recursive
exit
"#
);
assert!(!h::dir_exists_at(PathBuf::from(red_pill_dir)));
assert!(!red_pill_dir.exists());
assert!(h::files_exist_at(
vec![
Path::new("andres.nu"),
Path::new("jonathan.nu"),
Path::new("yehuda.nu"),
],
PathBuf::from(&expected)
expected
));
assert!(!h::dir_exists_at(PathBuf::from(blue_pill_dir)));
assert!(!blue_pill_dir.exists());
assert!(h::files_exist_at(
vec![
Path::new("bash.nxt"),
Path::new("korn.nxt"),
Path::new("powedsh.nxt"),
],
PathBuf::from(&expected_recycled)
expected_recycled
));
})
}

View File

@ -1,7 +1,7 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn ls_lists_regular_files() {
@ -14,17 +14,17 @@ fn ls_lists_regular_files() {
]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
r#"
ls
| get name
| lines
| split-column "."
| get Column2
| str --to-int
| sum
| echo $it
"#
cwd: dirs.test(), h::pipeline(
r#"
ls
| get name
| lines
| split-column "."
| get Column2
| str --to-int
| sum
| echo $it
"#
));
assert_eq!(actual, "30");
@ -43,17 +43,17 @@ fn ls_lists_regular_files_using_asterisk_wildcard() {
]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
r#"
ls *.txt
| get name
| lines
| split-column "."
| get Column2
| str --to-int
| sum
| echo $it
"#
cwd: dirs.test(), h::pipeline(
r#"
ls *.txt
| get name
| lines
| split-column "."
| get Column2
| str --to-int
| sum
| echo $it
"#
));
assert_eq!(actual, "3");
@ -72,17 +72,17 @@ fn ls_lists_regular_files_using_question_mark_wildcard() {
]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
r#"
ls *.??.txt
| get name
| lines
| split-column "."
| get Column2
| str --to-int
| sum
| echo $it
"#
cwd: dirs.test(), h::pipeline(
r#"
ls *.??.txt
| get name
| lines
| split-column "."
| get Column2
| str --to-int
| sum
| echo $it
"#
));
assert_eq!(actual, "30");

View File

@ -1,24 +1,31 @@
mod helpers;
use h::{in_directory as cwd, Playground};
use helpers as h;
use std::path::{Path, PathBuf};
use helpers::Playground;
use std::path::Path;
#[test]
fn creates_directory() {
Playground::setup("mkdir_test_1", |dirs, _| {
nu!(cwd(dirs.test()), "mkdir my_new_directory");
nu!(
cwd: dirs.test(),
"mkdir my_new_directory"
);
let expected = dirs.test().join("my_new_directory");
assert!(h::dir_exists_at(expected));
assert!(expected.exists());
})
}
#[test]
fn accepts_and_creates_directories() {
Playground::setup("mkdir_test_2", |dirs, _| {
nu!(cwd(dirs.test()), "mkdir dir_1 dir_2 dir_3");
nu!(
cwd: dirs.test(),
"mkdir dir_1 dir_2 dir_3"
);
assert!(h::files_exist_at(
vec![Path::new("dir_1"), Path::new("dir_2"), Path::new("dir_3")],
@ -30,11 +37,13 @@ fn accepts_and_creates_directories() {
#[test]
fn creates_intermediary_directories() {
Playground::setup("mkdir_test_3", |dirs, _| {
nu!(cwd(dirs.test()), "mkdir some_folder/another/deeper_one");
nu!(
cwd: dirs.test(),
"mkdir some_folder/another/deeper_one"
);
let mut expected = PathBuf::from(dirs.test());
expected.push("some_folder/another/deeper_one");
let expected = dirs.test().join("some_folder/another/deeper_one");
assert!(h::dir_exists_at(expected));
assert!(expected.exists());
})
}

View File

@ -1,7 +1,7 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn moves_a_file() {
@ -13,10 +13,13 @@ fn moves_a_file() {
let original = dirs.test().join("andres.txt");
let expected = dirs.test().join("expected/yehuda.txt");
nu!(cwd(dirs.test()), "mv andres.txt expected/yehuda.txt");
nu!(
cwd: dirs.test(),
"mv andres.txt expected/yehuda.txt"
);
assert!(!h::file_exists_at(original));
assert!(h::file_exists_at(expected));
assert!(!original.exists());
assert!(expected.exists());
})
}
@ -32,10 +35,13 @@ fn overwrites_if_moving_to_existing_file() {
let original = dirs.test().join("andres.txt");
let expected = dirs.test().join("jonathan.txt");
nu!(cwd(dirs.test()), "mv andres.txt jonathan.txt");
nu!(
cwd: dirs.test(),
"mv andres.txt jonathan.txt"
);
assert!(!h::file_exists_at(original));
assert!(h::file_exists_at(expected));
assert!(!original.exists());
assert!(expected.exists());
})
}
@ -47,10 +53,13 @@ fn moves_a_directory() {
let original_dir = dirs.test().join("empty_dir");
let expected = dirs.test().join("renamed_dir");
nu!(cwd(dirs.test()), "mv empty_dir renamed_dir");
nu!(
cwd: dirs.test(),
"mv empty_dir renamed_dir"
);
assert!(!h::dir_exists_at(original_dir));
assert!(h::dir_exists_at(expected));
assert!(!original_dir.exists());
assert!(expected.exists());
})
}
@ -64,10 +73,13 @@ fn moves_the_file_inside_directory_if_path_to_move_is_existing_directory() {
let original_dir = dirs.test().join("jonathan.txt");
let expected = dirs.test().join("expected/jonathan.txt");
nu!(dirs.test(), "mv jonathan.txt expected");
nu!(
cwd: dirs.test(),
"mv jonathan.txt expected"
);
assert!(!h::file_exists_at(original_dir));
assert!(h::file_exists_at(expected));
assert!(!original_dir.exists());
assert!(expected.exists());
})
}
@ -82,10 +94,13 @@ fn moves_the_directory_inside_directory_if_path_to_move_is_existing_directory()
let original_dir = dirs.test().join("contributors");
let expected = dirs.test().join("expected/contributors");
nu!(dirs.test(), "mv contributors expected");
nu!(
cwd: dirs.test(),
"mv contributors expected"
);
assert!(!h::dir_exists_at(original_dir));
assert!(h::file_exists_at(expected));
assert!(!original_dir.exists());
assert!(expected.exists());
})
}
@ -100,7 +115,7 @@ fn moves_the_directory_inside_directory_if_path_to_move_is_nonexistent_directory
let original_dir = dirs.test().join("contributors");
nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"mv contributors expected/this_dir_exists_now/los_tres_amigos"
);
@ -108,8 +123,8 @@ fn moves_the_directory_inside_directory_if_path_to_move_is_nonexistent_directory
.test()
.join("expected/this_dir_exists_now/los_tres_amigos");
assert!(!h::dir_exists_at(original_dir));
assert!(h::file_exists_at(expected));
assert!(!original_dir.exists());
assert!(expected.exists());
})
}
@ -135,7 +150,10 @@ fn moves_using_path_with_wildcard() {
let work_dir = dirs.test().join("work_dir");
let expected = dirs.test().join("expected");
nu!(cwd(work_dir), "mv ../originals/*.ini ../expected");
nu!(
cwd: work_dir,
"mv ../originals/*.ini ../expected"
);
assert!(h::files_exist_at(
vec!["yehuda.ini", "jonathan.ini", "sample.ini", "andres.ini",],
@ -161,9 +179,12 @@ fn moves_using_a_glob() {
let work_dir = dirs.test().join("work_dir");
let expected = dirs.test().join("expected");
nu!(cwd(work_dir), "mv ../meals/* ../expected");
nu!(
cwd: work_dir,
"mv ../meals/* ../expected"
);
assert!(h::dir_exists_at(meal_dir));
assert!(meal_dir.exists());
assert!(h::files_exist_at(
vec!["arepa.txt", "empanada.txt", "taquiza.txt",],
expected

View File

@ -1,7 +1,7 @@
mod helpers;
use helpers::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn recognizes_csv() {
@ -18,7 +18,7 @@ fn recognizes_csv() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open nu.zion.csv
| where author == "Andres N. Robalino"
@ -34,7 +34,7 @@ fn recognizes_csv() {
#[test]
fn open_can_parse_bson_1() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open sample.bson | get root | nth 0 | get b | echo $it"
);
@ -44,16 +44,16 @@ fn open_can_parse_bson_1() {
#[test]
fn open_can_parse_bson_2() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
r#"
open sample.bson
| get root
| nth 6
| get b
| get '$binary_subtype'
| echo $it
"#
));
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open sample.bson
| get root
| nth 6
| get b
| get '$binary_subtype'
| echo $it
"#
));
assert_eq!(actual, "function");
}
@ -61,17 +61,32 @@ fn open_can_parse_bson_2() {
#[test]
fn open_can_parse_toml() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open cargo_sample.toml | get package.edition | echo $it"
);
assert_eq!(actual, "2018");
}
#[test]
fn open_can_parse_tsv() {
let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open caco3_plastics.tsv
| first 1
| get origin
| echo $it
"#
));
assert_eq!(actual, "SPAIN")
}
#[test]
fn open_can_parse_json() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open sgml_description.json
| get glossary.GlossDiv.GlossList.GlossEntry.GlossSee
@ -85,7 +100,7 @@ fn open_can_parse_json() {
#[test]
fn open_can_parse_xml() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open jonathan.xml | get rss.channel.item.link | echo $it"
);
@ -98,7 +113,7 @@ fn open_can_parse_xml() {
#[test]
fn open_can_parse_ini() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open sample.ini | get SectionOne.integer | echo $it"
);
@ -108,7 +123,7 @@ fn open_can_parse_ini() {
#[test]
fn open_can_parse_utf16_ini() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open utf16.ini | get .ShellClassInfo | get IconIndex | echo $it"
);
@ -118,7 +133,7 @@ fn open_can_parse_utf16_ini() {
#[test]
fn errors_if_file_not_found() {
let actual = nu_error!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open i_dont_exist.txt | echo $it"
);

View File

@ -1,7 +1,7 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn rm_removes_a_file() {
@ -10,11 +10,14 @@ fn rm_removes_a_file() {
.with_files(vec![EmptyFile("i_will_be_deleted.txt")
]);
nu!(cwd(dirs.root()), "rm rm_test_1/i_will_be_deleted.txt");
nu!(
cwd: dirs.root(),
"rm rm_test_1/i_will_be_deleted.txt"
);
let path = dirs.test().join("i_will_be_deleted.txt");
assert!(!h::file_exists_at(path));
assert!(!path.exists());
})
}
@ -38,7 +41,10 @@ fn rm_removes_files_with_wildcard() {
EmptyFile("baseline_parse_tokens.rs")
]);
nu!(cwd(dirs.test()), r#"rm "src/*/*/*.rs""#);
nu!(
cwd: dirs.test(),
r#"rm "src/*/*/*.rs""#
);
assert!(!h::files_exist_at(
vec![
@ -76,7 +82,10 @@ fn rm_removes_deeply_nested_directories_with_wildcard_and_recursive_flag() {
EmptyFile("baseline_parse_tokens.rs")
]);
nu!(cwd(dirs.test()), "rm src/* --recursive");
nu!(
cwd: dirs.test(),
"rm src/* --recursive"
);
assert!(!h::files_exist_at(
vec!["src/parser/parse", "src/parser/hir"],
@ -88,9 +97,12 @@ fn rm_removes_deeply_nested_directories_with_wildcard_and_recursive_flag() {
#[test]
fn rm_removes_directory_contents_without_recursive_flag_if_empty() {
Playground::setup("rm_test_4", |dirs, _| {
nu!(cwd(dirs.root()), "rm rm_test_4");
nu!(
cwd: dirs.root(),
"rm rm_test_4"
);
assert!(!h::file_exists_at(dirs.test()));
assert!(!dirs.test().exists());
})
}
@ -104,9 +116,12 @@ fn rm_removes_directory_contents_with_recursive_flag() {
EmptyFile("andres.txt")
]);
nu!(cwd(dirs.root()), "rm rm_test_5 --recursive");
nu!(
cwd: dirs.root(),
"rm rm_test_5 --recursive"
);
assert!(!h::file_exists_at(dirs.test()));
assert!(!dirs.test().exists());
})
}
@ -118,11 +133,11 @@ fn rm_errors_if_attempting_to_delete_a_directory_with_content_without_recursive_
]);
let actual = nu_error!(
cwd(dirs.root()),
cwd: dirs.root(),
"rm rm_test_6"
);
assert!(h::file_exists_at(dirs.test()));
assert!(dirs.test().exists());
assert!(actual.contains("is a directory"));
})
}
@ -130,7 +145,10 @@ fn rm_errors_if_attempting_to_delete_a_directory_with_content_without_recursive_
#[test]
fn rm_errors_if_attempting_to_delete_single_dot_as_argument() {
Playground::setup("rm_test_7", |dirs, _| {
let actual = nu_error!(cwd(dirs.root()), "rm .");
let actual = nu_error!(
cwd: dirs.root(),
"rm ."
);
assert!(actual.contains("may not be removed"));
})
@ -139,7 +157,10 @@ fn rm_errors_if_attempting_to_delete_single_dot_as_argument() {
#[test]
fn rm_errors_if_attempting_to_delete_two_dot_as_argument() {
Playground::setup("rm_test_8", |dirs, _| {
let actual = nu_error!(cwd(dirs.root()), "rm ..");
let actual = nu_error!(
cwd: dirs.root(),
"rm .."
);
assert!(actual.contains("may not be removed"));
})

View File

@ -1,14 +1,24 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn lines() {
let actual = nu!(
cwd("tests/fixtures/formats"),
r#"open cargo_sample.toml --raw | lines | skip-while $it != "[dependencies]" | skip 1 | first 1 | split-column "=" | get Column1 | trim | echo $it"#
);
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open cargo_sample.toml --raw
| lines
| skip-while $it != "[dependencies]"
| skip 1
| first 1
| split-column "="
| get Column1
| trim
| echo $it
"#
));
assert_eq!(actual, "rustyline");
}
@ -32,7 +42,7 @@ fn save_figures_out_intelligently_where_to_write_out_with_metadata() {
let subject_file = dirs.test().join("cargo_sample.toml");
nu!(
cwd(dirs.root()),
cwd: dirs.root(),
"open save_test_1/cargo_sample.toml | inc package.version --minor | save"
);
@ -47,7 +57,7 @@ fn save_can_write_out_csv() {
let expected_file = dirs.test().join("cargo_sample.csv");
nu!(
dirs.root(),
cwd: dirs.root(),
"open {}/cargo_sample.toml | inc package.version --minor | get package | save save_test_2/cargo_sample.csv",
dirs.formats()
);

View File

@ -1,10 +1,11 @@
mod helpers;
use helpers::in_directory as cwd;
#[test]
fn external_command() {
let actual = nu!(cwd("tests/fixtures"), "echo 1");
let actual = nu!(
cwd: "tests/fixtures",
"echo 1"
);
assert!(actual.contains("1"));
}

View File

@ -1,12 +1,11 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn can_only_apply_one() {
let actual = nu_error!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open cargo_sample.toml | first 1 | inc package.version --major --minor"
);
@ -26,7 +25,7 @@ fn by_one_with_field_passed() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | inc package.edition | get package.edition | echo $it"
);
@ -47,7 +46,7 @@ fn by_one_with_no_field_passed() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | get package.contributors | inc | echo $it"
);
@ -68,7 +67,7 @@ fn semversion_major_inc() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | inc package.version --major | get package.version | echo $it"
);
@ -89,7 +88,7 @@ fn semversion_minor_inc() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | inc package.version --minor | get package.version | echo $it"
);
@ -110,7 +109,7 @@ fn semversion_patch_inc() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | inc package.version --patch | get package.version | echo $it"
);
@ -131,7 +130,7 @@ fn semversion_without_passing_field() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | get package.version | inc --patch | echo $it"
);

View File

@ -1,12 +1,12 @@
mod helpers;
use h::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use h::{Playground, Stub::*};
#[test]
fn can_only_apply_one() {
let actual = nu_error!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open caco3_plastics.csv | first 1 | str origin --downcase --upcase"
);
@ -28,7 +28,7 @@ fn acts_without_passing_field() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.yml | get environment.global.PROJECT_NAME | str --upcase | echo $it"
);
@ -49,7 +49,7 @@ fn downcases() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | str dependency.name --downcase | get dependency.name | echo $it"
);
@ -70,7 +70,7 @@ fn upcases() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open sample.toml | str package.name --upcase | get package.name | echo $it"
);
@ -81,15 +81,15 @@ fn upcases() {
#[test]
fn converts_to_int() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
r#"
open caco3_plastics.csv
| first 1
| str tariff_item --to-int
| where tariff_item == 2509000000
| get tariff_item
| echo $it
"#
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open caco3_plastics.csv
| first 1
| str tariff_item --to-int
| where tariff_item == 2509000000
| get tariff_item
| echo $it
"#
));
assert_eq!(actual, "2509000000");
@ -108,7 +108,7 @@ fn replaces() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open sample.toml
| str package.name --replace wykittenshell
@ -134,7 +134,7 @@ fn find_and_replaces() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open sample.toml
| str fortune.teller.phone --find-replace KATZ "5289"
@ -160,7 +160,7 @@ fn find_and_replaces_without_passing_field() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open sample.toml
| get fortune.teller.phone

View File

@ -1,12 +1,12 @@
mod helpers;
use helpers::{in_directory as cwd, Playground, Stub::*};
use helpers as h;
use helpers::{Playground, Stub::*};
#[test]
fn can_convert_table_to_csv_text_and_from_csv_text_back_into_table() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open caco3_plastics.csv | to-csv | from-csv | first 1 | get origin | echo $it"
);
@ -27,7 +27,7 @@ fn converts_structured_table_to_csv_text() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open csv_text_sample.txt
| lines
@ -58,7 +58,7 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open csv_text_sample.txt
| lines
@ -88,7 +88,7 @@ fn converts_from_csv_text_to_structured_table() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open los_tres_amigos.txt
| from-csv
@ -118,7 +118,7 @@ fn converts_from_csv_text_skipping_headers_to_structured_table() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open los_tres_amigos.txt
| from-csv --headerless
@ -136,7 +136,7 @@ fn converts_from_csv_text_skipping_headers_to_structured_table() {
#[test]
fn can_convert_table_to_json_text_and_from_json_text_back_into_table() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open sgml_description.json
| to-json
@ -168,7 +168,7 @@ fn converts_from_json_text_to_structured_table() {
)]);
let actual = nu!(
cwd(dirs.test()),
cwd: dirs.test(),
"open katz.txt | from-json | get katz | get rusty_luck | sum | echo $it"
);
@ -192,7 +192,7 @@ fn converts_from_json_text_recognizing_objects_independendtly_to_structured_tabl
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open katz.txt
| from-json --objects
@ -219,7 +219,7 @@ fn converts_structured_table_to_json_text() {
)]);
let actual = nu!(
cwd(dirs.test()), h::pipeline(
cwd: dirs.test(), h::pipeline(
r#"
open sample.txt
| lines
@ -237,10 +237,140 @@ fn converts_structured_table_to_json_text() {
})
}
#[test]
fn can_convert_table_to_tsv_text_and_from_tsv_text_back_into_table() {
let actual = nu!(
cwd: "tests/fixtures/formats",
"open caco3_plastics.tsv | to-tsv | from-tsv | first 1 | get origin | echo $it"
);
assert_eq!(actual, "SPAIN");
}
#[test]
fn converts_structured_table_to_tsv_text() {
Playground::setup("filter_to_tsv_test_1", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContentToBeTrimmed(
"tsv_text_sample.txt",
r#"
importer shipper tariff_item name origin
Plasticos Rival Reverte 2509000000 Calcium carbonate Spain
Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia
"#
)]);
let actual = nu!(
cwd: dirs.test(), h::pipeline(
r#"
open tsv_text_sample.txt
| lines
| split-column "\t" a b c d origin
| last 1
| to-tsv
| lines
| nth 1
| echo "$it"
"#
));
assert!(actual.contains("Colombia"));
})
}
#[test]
fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() {
Playground::setup("filter_to_tsv_test_2", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContentToBeTrimmed(
"tsv_text_sample.txt",
r#"
importer shipper tariff_item name origin
Plasticos Rival Reverte 2509000000 Calcium carbonate Spain
Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia
"#
)]);
let actual = nu!(
cwd: dirs.test(), h::pipeline(
r#"
open tsv_text_sample.txt
| lines
| split-column "\t" a b c d origin
| last 1
| to-tsv --headerless
| echo "$it"
"#
));
assert!(actual.contains("Colombia"));
})
}
#[test]
fn converts_from_tsv_text_to_structured_table() {
Playground::setup("filter_from_tsv_test_1", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContentToBeTrimmed(
"los_tres_amigos.txt",
r#"
first Name Last Name rusty_luck
Andrés Robalino 1
Jonathan Turner 1
Yehuda Katz 1
"#,
)]);
let actual = nu!(
cwd: dirs.test(), h::pipeline(
r#"
open los_tres_amigos.txt
| from-tsv
| get rusty_luck
| str --to-int
| sum
| echo $it
"#
));
assert_eq!(actual, "3");
})
}
#[test]
fn converts_from_tsv_text_skipping_headers_to_structured_table() {
Playground::setup("filter_from_tsv_test_2", |dirs, sandbox| {
sandbox
.with_files(vec![FileWithContentToBeTrimmed(
"los_tres_amigos.txt",
r#"
first Name Last Name rusty_luck
Andrés Robalino 1
Jonathan Turner 1
Yehuda Katz 1
"#,
)]);
let actual = nu!(
cwd: dirs.test(), h::pipeline(
r#"
open los_tres_amigos.txt
| from-tsv --headerless
| get Column3
| str --to-int
| sum
| echo $it
"#
));
assert_eq!(actual, "3");
})
}
#[test]
fn can_convert_json_text_to_bson_and_back_into_table() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open sample.bson | to-bson | from-bson | get root | nth 1 | get b | echo $it"
);
@ -250,7 +380,7 @@ fn can_convert_json_text_to_bson_and_back_into_table() {
#[test]
fn can_convert_table_to_toml_text_and_from_toml_text_back_into_table() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open cargo_sample.toml | to-toml | from-toml | get package.name | echo $it"
);
@ -260,7 +390,7 @@ fn can_convert_table_to_toml_text_and_from_toml_text_back_into_table() {
#[test]
fn can_convert_table_to_yaml_text_and_from_yaml_text_back_into_table() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open appveyor.yml
| to-yaml
@ -276,7 +406,7 @@ fn can_convert_table_to_yaml_text_and_from_yaml_text_back_into_table() {
#[test]
fn can_sort_by_column() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open cargo_sample.toml --raw
| lines
@ -298,7 +428,7 @@ fn can_sort_by_column() {
#[test]
fn can_split_by_column() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open cargo_sample.toml --raw
| lines
@ -317,7 +447,7 @@ fn can_split_by_column() {
#[test]
fn can_sum() {
let actual = nu!(
cwd("tests/fixtures/formats"), h::pipeline(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open sgml_description.json
| get glossary.GlossDiv.GlossList.GlossEntry.Sections
@ -332,17 +462,17 @@ fn can_sum() {
#[test]
fn can_filter_by_unit_size_comparison() {
let actual = nu!(
cwd("tests/fixtures/formats"),
"ls | where size > 1kb | sort-by size | get name | skip 1 | trim | echo $it"
cwd: "tests/fixtures/formats",
"ls | where size > 1kb | sort-by size | get name | first 1 | trim | echo $it"
);
assert_eq!(actual, "caco3_plastics.csv");
assert_eq!(actual, "cargo_sample.toml");
}
#[test]
fn can_get_last() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"ls | sort-by name | last 1 | get name | trim | echo $it"
);
@ -352,7 +482,7 @@ fn can_get_last() {
#[test]
fn can_get_reverse_first() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"ls | sort-by name | reverse | first 1 | get name | trim | echo $it"
);

View File

@ -0,0 +1,10 @@
importer shipper tariff_item name origin shipped_at arrived_at net_weight fob_price cif_price cif_per_net_weight
PLASTICOS RIVAL CIA LTDA S A REVERTE 2509000000 CARBONATO DE CALCIO TIPO CALCIPORE 160 T AL SPAIN 18/03/2016 17/04/2016 81,000.00 14,417.58 18,252.34 0.23
MEXICHEM ECUADOR S.A. OMYA ANDINA S A 2836500000 CARBONATO COLOMBIA 07/07/2016 10/07/2016 26,000.00 7,072.00 8,127.18 0.31
PLASTIAZUAY SA SA REVERTE 2836500000 CARBONATO DE CALCIO SPAIN 27/07/2016 09/08/2016 81,000.00 8,100.00 11,474.55 0.14
PLASTICOS RIVAL CIA LTDA AND ENDUSTRIYEL HAMMADDELER DIS TCARET LTD.STI. 2836500000 CALCIUM CARBONATE ANADOLU ANDCARB CT-1 TURKEY 04/10/2016 11/11/2016 100,000.00 17,500.00 22,533.75 0.23
QUIMICA COMERCIAL QUIMICIAL CIA. LTDA. SA REVERTE 2836500000 CARBONATO DE CALCIO SPAIN 24/06/2016 12/07/2016 27,000.00 3,258.90 5,585.00 0.21
PICA PLASTICOS INDUSTRIALES C.A. OMYA ANDINA S.A 3824909999 CARBONATO DE CALCIO COLOMBIA 01/01/1900 18/01/2016 66,500.00 12,635.00 18,670.52 0.28
PLASTIQUIM S.A. OMYA ANDINA S.A NIT 830.027.386-6 3824909999 CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYA CARB 1T CG BBS 1000 COLOMBIA 01/01/1900 25/10/2016 33,000.00 6,270.00 9,999.00 0.30
QUIMICOS ANDINOS QUIMANDI S.A. SIBELCO COLOMBIA SAS 3824909999 CARBONATO DE CALCIO RECUBIERTO COLOMBIA 01/11/2016 03/11/2016 52,000.00 8,944.00 13,039.05 0.25
TIGRE ECUADOR S.A. ECUATIGRE OMYA ANDINA S.A NIT 830.027.386-6 3824909999 CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYACARB 1T CG BPA 25 NO COLOMBIA 01/01/1900 28/10/2016 66,000.00 11,748.00 18,216.00 0.28
1 importer shipper tariff_item name origin shipped_at arrived_at net_weight fob_price cif_price cif_per_net_weight
2 PLASTICOS RIVAL CIA LTDA S A REVERTE 2509000000 CARBONATO DE CALCIO TIPO CALCIPORE 160 T AL SPAIN 18/03/2016 17/04/2016 81,000.00 14,417.58 18,252.34 0.23
3 MEXICHEM ECUADOR S.A. OMYA ANDINA S A 2836500000 CARBONATO COLOMBIA 07/07/2016 10/07/2016 26,000.00 7,072.00 8,127.18 0.31
4 PLASTIAZUAY SA SA REVERTE 2836500000 CARBONATO DE CALCIO SPAIN 27/07/2016 09/08/2016 81,000.00 8,100.00 11,474.55 0.14
5 PLASTICOS RIVAL CIA LTDA AND ENDUSTRIYEL HAMMADDELER DIS TCARET LTD.STI. 2836500000 CALCIUM CARBONATE ANADOLU ANDCARB CT-1 TURKEY 04/10/2016 11/11/2016 100,000.00 17,500.00 22,533.75 0.23
6 QUIMICA COMERCIAL QUIMICIAL CIA. LTDA. SA REVERTE 2836500000 CARBONATO DE CALCIO SPAIN 24/06/2016 12/07/2016 27,000.00 3,258.90 5,585.00 0.21
7 PICA PLASTICOS INDUSTRIALES C.A. OMYA ANDINA S.A 3824909999 CARBONATO DE CALCIO COLOMBIA 01/01/1900 18/01/2016 66,500.00 12,635.00 18,670.52 0.28
8 PLASTIQUIM S.A. OMYA ANDINA S.A NIT 830.027.386-6 3824909999 CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYA CARB 1T CG BBS 1000 COLOMBIA 01/01/1900 25/10/2016 33,000.00 6,270.00 9,999.00 0.30
9 QUIMICOS ANDINOS QUIMANDI S.A. SIBELCO COLOMBIA SAS 3824909999 CARBONATO DE CALCIO RECUBIERTO COLOMBIA 01/11/2016 03/11/2016 52,000.00 8,944.00 13,039.05 0.25
10 TIGRE ECUADOR S.A. ECUATIGRE OMYA ANDINA S.A NIT 830.027.386-6 3824909999 CARBONATO DE CALCIO RECUBIERTO CON ACIDO ESTEARICO OMYACARB 1T CG BPA 25 NO COLOMBIA 01/01/1900 28/10/2016 66,000.00 11,748.00 18,216.00 0.28

View File

@ -50,7 +50,7 @@ impl DisplayPath for nu::AbsolutePath {
#[macro_export]
macro_rules! nu {
($cwd:expr, $path:expr, $($part:expr),*) => {{
(cwd: $cwd:expr, $path:expr, $($part:expr),*) => {{
use $crate::helpers::DisplayPath;
let path = format!($path, $(
@ -60,6 +60,10 @@ macro_rules! nu {
nu!($cwd, &path)
}};
(cwd: $cwd:expr, $path:expr) => {{
nu!($cwd, $path)
}};
($cwd:expr, $path:expr) => {{
pub use std::error::Error;
pub use std::io::prelude::*;
@ -101,7 +105,7 @@ macro_rules! nu {
#[macro_export]
macro_rules! nu_error {
($cwd:expr, $path:expr, $($part:expr),*) => {{
(cwd: $cwd:expr, $path:expr, $($part:expr),*) => {{
use $crate::helpers::DisplayPath;
let path = format!($path, $(
@ -111,17 +115,22 @@ macro_rules! nu_error {
nu_error!($cwd, &path)
}};
(cwd: $cwd:expr, $path:expr) => {{
nu_error!($cwd, $path)
}};
($cwd:expr, $commands:expr) => {{
use std::io::prelude::*;
use std::process::{Command, Stdio};
($cwd:expr, $path:expr) => {{
pub use std::error::Error;
pub use std::io::prelude::*;
pub use std::process::{Command, Stdio};
let commands = &*format!(
"
cd {}
{}
exit",
$crate::helpers::in_directory($cwd), $commands
$crate::helpers::in_directory($cwd),
$crate::helpers::DisplayPath::display_path(&$path)
);
let mut process = Command::new(helpers::executable_path())
@ -140,7 +149,6 @@ macro_rules! nu_error {
.expect("couldn't read from stderr");
let out = String::from_utf8_lossy(&output.stderr);
out.into_owned()
}};
}
@ -345,14 +353,6 @@ pub fn files_exist_at(files: Vec<impl AsRef<Path>>, path: impl AsRef<Path>) -> b
})
}
pub fn file_exists_at(path: impl AsRef<Path>) -> bool {
path.as_ref().exists()
}
pub fn dir_exists_at(path: impl AsRef<Path>) -> bool {
path.as_ref().exists()
}
pub fn delete_directory_at(full_path: &str) {
std::fs::remove_dir_all(PathBuf::from(full_path)).expect("can not remove directory");
}

View File

@ -1,6 +1,5 @@
mod helpers;
use helpers::{in_directory as cwd};
use helpers as h;
#[test]
@ -21,7 +20,7 @@ fn pipeline_helper() {
#[test]
fn external_num() {
let actual = nu!(
cwd("tests/fixtures/formats"),
cwd: "tests/fixtures/formats",
"open sgml_description.json | get glossary.GlossDiv.GlossList.GlossEntry.Height | echo $it"
);
@ -30,7 +29,10 @@ fn external_num() {
#[test]
fn external_has_correct_quotes() {
let actual = nu!(cwd("."), r#"echo "hello world""#);
let actual = nu!(
cwd: ".",
r#"echo "hello world""#
);
let actual = h::normalize_string(&actual);
@ -40,9 +42,14 @@ fn external_has_correct_quotes() {
#[test]
fn add_plugin() {
let actual = nu!(
cwd("tests/fixtures/formats"),
r#"open cargo_sample.toml | add dev-dependencies.newdep "1" | get dev-dependencies.newdep | echo $it"#
);
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open cargo_sample.toml
| add dev-dependencies.newdep "1"
| get dev-dependencies.newdep
| echo $it
"#
));
assert_eq!(actual, "1");
}
@ -50,9 +57,14 @@ fn add_plugin() {
#[test]
fn edit_plugin() {
let actual = nu!(
cwd("tests/fixtures/formats"),
r#"open cargo_sample.toml | edit dev-dependencies.pretty_assertions "7" | get dev-dependencies.pretty_assertions | echo $it"#
);
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open cargo_sample.toml
| edit dev-dependencies.pretty_assertions "7"
| get dev-dependencies.pretty_assertions
| echo $it
"#
));
assert_eq!(actual, "7");
}