mirror of
https://github.com/nushell/nushell.git
synced 2025-02-16 18:41:44 +01:00
Add nuon format for fun (#4401)
* Add nuon format for fun * more fun * More nuon fixes, allow comments, improve errors
This commit is contained in:
parent
2ba12afb01
commit
fd22211737
@ -76,7 +76,7 @@ itertools = "0.10.3"
|
|||||||
plugin = ["nu-plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"]
|
plugin = ["nu-plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"]
|
||||||
default = ["plugin", "inc", "example", "which"]
|
default = ["plugin", "inc", "example", "which"]
|
||||||
stable = ["default"]
|
stable = ["default"]
|
||||||
extra = [ "default", "dataframe", "gstat", "zip-support", "query", ]
|
extra = ["default", "dataframe", "gstat", "zip-support", "query", "trash-support"]
|
||||||
wasi = ["inc"]
|
wasi = ["inc"]
|
||||||
trash-support = ["nu-command/trash-support"]
|
trash-support = ["nu-command/trash-support"]
|
||||||
|
|
||||||
|
@ -235,6 +235,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
|||||||
FromIcs,
|
FromIcs,
|
||||||
FromIni,
|
FromIni,
|
||||||
FromJson,
|
FromJson,
|
||||||
|
FromNuon,
|
||||||
FromOds,
|
FromOds,
|
||||||
FromSsv,
|
FromSsv,
|
||||||
FromToml,
|
FromToml,
|
||||||
@ -250,6 +251,7 @@ pub fn create_default_context(cwd: impl AsRef<Path>) -> EngineState {
|
|||||||
ToHtml,
|
ToHtml,
|
||||||
ToJson,
|
ToJson,
|
||||||
ToMd,
|
ToMd,
|
||||||
|
ToNuon,
|
||||||
ToToml,
|
ToToml,
|
||||||
ToTsv,
|
ToTsv,
|
||||||
ToCsv,
|
ToCsv,
|
||||||
|
@ -142,7 +142,7 @@ impl Command for Open {
|
|||||||
Some(converter_id) => engine_state.get_decl(converter_id).run(
|
Some(converter_id) => engine_state.get_decl(converter_id).run(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
&Call::new(call_span),
|
&Call::new(arg_span),
|
||||||
output,
|
output,
|
||||||
),
|
),
|
||||||
None => Ok(output),
|
None => Ok(output),
|
||||||
|
@ -26,7 +26,7 @@ impl Command for FromJson {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
example: "'{ a:1 }' | from json",
|
example: r#"'{ "a": 1 }' | from json"#,
|
||||||
description: "Converts json formatted string to table",
|
description: "Converts json formatted string to table",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["a".to_string()],
|
cols: vec!["a".to_string()],
|
||||||
@ -38,7 +38,7 @@ impl Command for FromJson {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
example: "'{ a:1, b: [1, 2] }' | from json",
|
example: r#"'{ "a": 1, "b": [1, 2] }' | from json"#,
|
||||||
description: "Converts json formatted string to table",
|
description: "Converts json formatted string to table",
|
||||||
result: Some(Value::Record {
|
result: Some(Value::Record {
|
||||||
cols: vec!["a".to_string(), "b".to_string()],
|
cols: vec!["a".to_string(), "b".to_string()],
|
||||||
|
@ -5,6 +5,7 @@ mod eml;
|
|||||||
mod ics;
|
mod ics;
|
||||||
mod ini;
|
mod ini;
|
||||||
mod json;
|
mod json;
|
||||||
|
mod nuon;
|
||||||
mod ods;
|
mod ods;
|
||||||
mod ssv;
|
mod ssv;
|
||||||
mod toml;
|
mod toml;
|
||||||
@ -23,6 +24,7 @@ pub use eml::FromEml;
|
|||||||
pub use ics::FromIcs;
|
pub use ics::FromIcs;
|
||||||
pub use ini::FromIni;
|
pub use ini::FromIni;
|
||||||
pub use json::FromJson;
|
pub use json::FromJson;
|
||||||
|
pub use nuon::FromNuon;
|
||||||
pub use ods::FromOds;
|
pub use ods::FromOds;
|
||||||
pub use ssv::FromSsv;
|
pub use ssv::FromSsv;
|
||||||
pub use tsv::FromTsv;
|
pub use tsv::FromTsv;
|
||||||
|
187
crates/nu-command/src/formats/from/nuon.rs
Normal file
187
crates/nu-command/src/formats/from/nuon.rs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use nu_engine::{current_dir, eval_expression};
|
||||||
|
use nu_protocol::ast::{Call, Expr, Expression};
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack, StateWorkingSet};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Type, Value,
|
||||||
|
CONFIG_VARIABLE_ID,
|
||||||
|
};
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FromNuon;
|
||||||
|
|
||||||
|
impl Command for FromNuon {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"from nuon"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Convert from nuon to structured data"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("from nuon").category(Category::Experimental)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
example: "'{ a:1 }' | from nuon",
|
||||||
|
description: "Converts nuon formatted string to table",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["a".to_string()],
|
||||||
|
vals: vec![Value::Int {
|
||||||
|
val: 1,
|
||||||
|
span: Span::test_data(),
|
||||||
|
}],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
example: "'{ a:1, b: [1, 2] }' | from nuon",
|
||||||
|
description: "Converts nuon formatted string to table",
|
||||||
|
result: Some(Value::Record {
|
||||||
|
cols: vec!["a".to_string(), "b".to_string()],
|
||||||
|
vals: vec![
|
||||||
|
Value::Int {
|
||||||
|
val: 1,
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::List {
|
||||||
|
vals: vec![
|
||||||
|
Value::Int {
|
||||||
|
val: 1,
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
Value::Int {
|
||||||
|
val: 2,
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
span: Span::test_data(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let config = stack.get_config().unwrap_or_default();
|
||||||
|
let string_input = input.collect_string("", &config)?;
|
||||||
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut engine_state = EngineState::new();
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
let mut stack = stack.captures_to_stack(&HashMap::new());
|
||||||
|
|
||||||
|
let _ = working_set.add_file("nuon file".to_string(), string_input.as_bytes());
|
||||||
|
|
||||||
|
let mut error = None;
|
||||||
|
|
||||||
|
let (lexed, err) =
|
||||||
|
nu_parser::lex(string_input.as_bytes(), 0, &[b'\n', b'\r'], &[], true);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
|
let (lite_block, err) = nu_parser::lite_parse(&lexed);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
|
let (block, err) = nu_parser::parse_block(&mut working_set, &lite_block, true);
|
||||||
|
error = error.or(err);
|
||||||
|
|
||||||
|
if block.pipelines.get(1).is_some() {
|
||||||
|
return Err(ShellError::SpannedLabeledError(
|
||||||
|
"error when loading".into(),
|
||||||
|
"excess values when loading".into(),
|
||||||
|
head,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let expr = if let Some(pipeline) = block.pipelines.get(0) {
|
||||||
|
if pipeline.expressions.get(1).is_some() {
|
||||||
|
return Err(ShellError::SpannedLabeledError(
|
||||||
|
"error when loading".into(),
|
||||||
|
"detected a pipeline in nuon file".into(),
|
||||||
|
head,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(expr) = pipeline.expressions.get(0) {
|
||||||
|
expr.clone()
|
||||||
|
} else {
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Nothing,
|
||||||
|
span: head,
|
||||||
|
custom_completion: None,
|
||||||
|
ty: Type::Nothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Expression {
|
||||||
|
expr: Expr::Nothing,
|
||||||
|
span: head,
|
||||||
|
custom_completion: None,
|
||||||
|
ty: Type::Nothing,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(err) = error {
|
||||||
|
return Err(ShellError::SpannedLabeledError(
|
||||||
|
"error when loading".into(),
|
||||||
|
err.to_string(),
|
||||||
|
head,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = working_set.render();
|
||||||
|
|
||||||
|
engine_state.merge_delta(delta, Some(&mut stack), &cwd)?;
|
||||||
|
|
||||||
|
stack.add_var(
|
||||||
|
CONFIG_VARIABLE_ID,
|
||||||
|
Value::Record {
|
||||||
|
cols: vec![],
|
||||||
|
vals: vec![],
|
||||||
|
span: head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = eval_expression(&engine_state, &mut stack, &expr);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(result) => Ok(result.into_pipeline_data()),
|
||||||
|
Err(ShellError::ExternalNotSupported(..)) => Err(ShellError::SpannedLabeledError(
|
||||||
|
"error when loading".into(),
|
||||||
|
"running commands not supported in nuon".into(),
|
||||||
|
head,
|
||||||
|
)),
|
||||||
|
Err(err) => Err(ShellError::SpannedLabeledError(
|
||||||
|
"error when loading".into(),
|
||||||
|
err.to_string(),
|
||||||
|
head,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(FromNuon {})
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ mod delimited;
|
|||||||
mod html;
|
mod html;
|
||||||
mod json;
|
mod json;
|
||||||
mod md;
|
mod md;
|
||||||
|
mod nuon;
|
||||||
mod toml;
|
mod toml;
|
||||||
mod tsv;
|
mod tsv;
|
||||||
mod url;
|
mod url;
|
||||||
@ -17,6 +18,7 @@ pub use command::To;
|
|||||||
pub use html::ToHtml;
|
pub use html::ToHtml;
|
||||||
pub use json::ToJson;
|
pub use json::ToJson;
|
||||||
pub use md::ToMd;
|
pub use md::ToMd;
|
||||||
|
pub use nuon::ToNuon;
|
||||||
pub use tsv::ToTsv;
|
pub use tsv::ToTsv;
|
||||||
pub use xml::ToXml;
|
pub use xml::ToXml;
|
||||||
pub use yaml::ToYaml;
|
pub use yaml::ToYaml;
|
||||||
|
98
crates/nu-command/src/formats/to/nuon.rs
Normal file
98
crates/nu-command/src/formats/to/nuon.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
use nu_protocol::ast::{Call, RangeInclusion};
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ToNuon;
|
||||||
|
|
||||||
|
impl Command for ToNuon {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"to nuon"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("to nuon").category(Category::Experimental)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Converts table data into Nuon (Nushell Object Notation) text."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
_engine_state: &EngineState,
|
||||||
|
_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, ShellError> {
|
||||||
|
Ok(Value::String {
|
||||||
|
val: to_nuon(call, input)?,
|
||||||
|
span: call.head,
|
||||||
|
}
|
||||||
|
.into_pipeline_data())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Outputs a nuon string representing the contents of this table",
|
||||||
|
example: "[1 2 3] | to nuon",
|
||||||
|
result: Some(Value::test_string("[1, 2, 3]")),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_to_string(v: &Value, span: Span) -> Result<String, ShellError> {
|
||||||
|
match v {
|
||||||
|
Value::Binary { .. } => Err(ShellError::UnsupportedInput("binary".into(), span)),
|
||||||
|
Value::Block { .. } => Err(ShellError::UnsupportedInput("block".into(), span)),
|
||||||
|
Value::Bool { val, .. } => {
|
||||||
|
if *val {
|
||||||
|
Ok("$true".to_string())
|
||||||
|
} else {
|
||||||
|
Ok("$false".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::CellPath { .. } => Err(ShellError::UnsupportedInput("cellpath".to_string(), span)),
|
||||||
|
Value::CustomValue { .. } => Err(ShellError::UnsupportedInput("custom".to_string(), span)),
|
||||||
|
Value::Date { .. } => Err(ShellError::UnsupportedInput("date".to_string(), span)),
|
||||||
|
Value::Duration { val, .. } => Ok(format!("{}ns", *val)),
|
||||||
|
Value::Error { .. } => Err(ShellError::UnsupportedInput("error".to_string(), span)),
|
||||||
|
Value::Filesize { val, .. } => Ok(format!("{}b", *val)),
|
||||||
|
Value::Float { val, .. } => Ok(format!("{}", *val)),
|
||||||
|
Value::Int { val, .. } => Ok(format!("{}", *val)),
|
||||||
|
Value::List { vals, .. } => {
|
||||||
|
let mut collection = vec![];
|
||||||
|
for val in vals {
|
||||||
|
collection.push(value_to_string(val, span)?);
|
||||||
|
}
|
||||||
|
Ok(format!("[{}]", collection.join(", ")))
|
||||||
|
}
|
||||||
|
Value::Nothing { .. } => Ok("$nothing".to_string()),
|
||||||
|
Value::Range { val, .. } => Ok(format!(
|
||||||
|
"{}..{}{}",
|
||||||
|
value_to_string(&val.from, span)?,
|
||||||
|
if val.inclusion == RangeInclusion::RightExclusive {
|
||||||
|
"<"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
},
|
||||||
|
value_to_string(&val.to, span)?
|
||||||
|
)),
|
||||||
|
Value::Record { cols, vals, .. } => {
|
||||||
|
let mut collection = vec![];
|
||||||
|
for (col, val) in cols.iter().zip(vals) {
|
||||||
|
collection.push(format!("\"{}\": {}", col, value_to_string(val, span)?));
|
||||||
|
}
|
||||||
|
Ok(format!("{{{}}}", collection.join(", ")))
|
||||||
|
}
|
||||||
|
Value::String { val, .. } => Ok(format!("\"{}\"", val)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_nuon(call: &Call, input: PipelineData) -> Result<String, ShellError> {
|
||||||
|
let v = input.into_value(call.head);
|
||||||
|
|
||||||
|
value_to_string(&v, call.head)
|
||||||
|
}
|
@ -74,7 +74,7 @@ pub enum ShellError {
|
|||||||
#[diagnostic(code(nu::shell::feature_not_enabled), url(docsrs))]
|
#[diagnostic(code(nu::shell::feature_not_enabled), url(docsrs))]
|
||||||
FeatureNotEnabled(#[label = "feature not enabled"] Span),
|
FeatureNotEnabled(#[label = "feature not enabled"] Span),
|
||||||
|
|
||||||
#[error("External commands not yet supported")]
|
#[error("Running external commands not supported")]
|
||||||
#[diagnostic(code(nu::shell::external_commands), url(docsrs))]
|
#[diagnostic(code(nu::shell::external_commands), url(docsrs))]
|
||||||
ExternalNotSupported(#[label = "external not supported"] Span),
|
ExternalNotSupported(#[label = "external not supported"] Span),
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ pub enum ShellError {
|
|||||||
|
|
||||||
#[error("Unsupported input")]
|
#[error("Unsupported input")]
|
||||||
#[diagnostic(code(nu::shell::unsupported_input), url(docsrs))]
|
#[diagnostic(code(nu::shell::unsupported_input), url(docsrs))]
|
||||||
UnsupportedInput(String, #[label("{0}")] Span),
|
UnsupportedInput(String, #[label("{0} not supported")] Span),
|
||||||
|
|
||||||
#[error("Network failure")]
|
#[error("Network failure")]
|
||||||
#[diagnostic(code(nu::shell::network_failure), url(docsrs))]
|
#[diagnostic(code(nu::shell::network_failure), url(docsrs))]
|
||||||
|
@ -137,7 +137,7 @@ let $config = {
|
|||||||
animate_prompt: $false # redraw the prompt every second
|
animate_prompt: $false # redraw the prompt every second
|
||||||
float_precision: 2
|
float_precision: 2
|
||||||
use_ansi_coloring: $true
|
use_ansi_coloring: $true
|
||||||
filesize_format: "b" # b, kb, kib, mb, mib, gb, gib, tb, tib, pb, pib, eb, eib, zb, zib, auto
|
filesize_format: "auto" # b, kb, kib, mb, mib, gb, gib, tb, tib, pb, pib, eb, eib, zb, zib, auto
|
||||||
edit_mode: emacs # emacs, vi
|
edit_mode: emacs # emacs, vi
|
||||||
max_history_size: 10000
|
max_history_size: 10000
|
||||||
menu_config: {
|
menu_config: {
|
||||||
|
Loading…
Reference in New Issue
Block a user