replace codespan-reporting with miette 3.0

This commit is contained in:
Kat Marchán 2021-09-20 14:37:26 -07:00
parent cbe85cbeaf
commit a1d6cefdf8
No known key found for this signature in database
GPG Key ID: AEB529C08A3C7E9E
14 changed files with 514 additions and 578 deletions

219
Cargo.lock generated
View File

@ -34,6 +34,17 @@ dependencies = [
"wait-timeout", "wait-timeout",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.0.1" version = "1.0.1"
@ -77,13 +88,12 @@ dependencies = [
] ]
[[package]] [[package]]
name = "codespan-reporting" name = "ci_info"
version = "0.11.1" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" checksum = "1f0e2864372242f01b92c1b882a904f6fb8b57f16e81e148a35b6368b1ea7323"
dependencies = [ dependencies = [
"termcolor", "envmnt",
"unicode-width",
] ]
[[package]] [[package]]
@ -140,6 +150,12 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "dunce"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
@ -151,7 +167,7 @@ name = "engine-q"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"codespan-reporting", "miette",
"nu-cli", "nu-cli",
"nu-command", "nu-command",
"nu-engine", "nu-engine",
@ -163,6 +179,25 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "envmnt"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f96dd862f12fac698dec3932dff0e6fb34bffeb5515ae5932d620cfe076571e"
dependencies = [
"fsio",
"indexmap",
]
[[package]]
name = "fsio"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09e87827efaf94c7a44b562ff57de06930712fe21b530c3797cdede26e6377eb"
dependencies = [
"dunce",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.3" version = "0.2.3"
@ -180,6 +215,31 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.10" version = "0.1.10"
@ -234,6 +294,38 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "miette"
version = "3.0.0-alpha.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043a986fa0bf30fe00f6720e5c298ed1d67fe30ae77659744cbac206e8d2554c"
dependencies = [
"atty",
"ci_info",
"itertools",
"miette-derive",
"once_cell",
"owo-colors",
"supports-color",
"supports-hyperlinks",
"supports-unicode",
"term_size",
"textwrap",
"thiserror",
"unicode-width",
]
[[package]]
name = "miette-derive"
version = "3.0.0-alpha.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3027fb091be28062da879441b2ab8f43d0013d7cde5fcc3a48fb9da7e22a01"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.7.13" version = "0.7.13"
@ -280,12 +372,13 @@ dependencies = [
name = "nu-cli" name = "nu-cli"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"codespan-reporting", "miette",
"nu-ansi-term", "nu-ansi-term",
"nu-engine", "nu-engine",
"nu-parser", "nu-parser",
"nu-protocol", "nu-protocol",
"reedline", "reedline",
"thiserror",
] ]
[[package]] [[package]]
@ -310,15 +403,17 @@ dependencies = [
name = "nu-parser" name = "nu-parser"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"codespan-reporting", "miette",
"nu-protocol", "nu-protocol",
"thiserror",
] ]
[[package]] [[package]]
name = "nu-protocol" name = "nu-protocol"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"codespan-reporting", "miette",
"thiserror",
] ]
[[package]] [[package]]
@ -349,6 +444,12 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]] [[package]]
name = "output_vt100" name = "output_vt100"
version = "0.1.2" version = "0.1.2"
@ -364,6 +465,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owo-colors"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fe43bf372b08cc9ccee5144715db59c79ab00168bbe4cf0d274dc0d5f64d7f"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.2" version = "0.11.2"
@ -608,6 +715,42 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "smawk"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
[[package]]
name = "supports-color"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40bc06147993f379a124cc6373ad4022f5d9fd4a80019217c773f81a38e9023c"
dependencies = [
"atty",
"ci_info",
"lazy_static",
"regex",
]
[[package]]
name = "supports-hyperlinks"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "590b34f7c5f01ecc9d78dba4b3f445f31df750a67621cf31626f3b7441ce6406"
dependencies = [
"atty",
]
[[package]]
name = "supports-unicode"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5fa283a620b255940913bd962cda2e6320e3799041f96ac0d7191ff2b4622f"
dependencies = [
"atty",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.76" version = "1.0.76"
@ -634,12 +777,44 @@ dependencies = [
] ]
[[package]] [[package]]
name = "termcolor" name = "term_size"
version = "1.1.2" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
dependencies = [ dependencies = [
"winapi-util", "libc",
"winapi",
]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"smawk",
"unicode-linebreak",
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c"
dependencies = [
"proc-macro2",
"quote",
"syn",
] ]
[[package]] [[package]]
@ -659,6 +834,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
[[package]]
name = "unicode-linebreak"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
dependencies = [
"regex",
]
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.8.0" version = "1.8.0"
@ -708,15 +892,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View File

@ -10,14 +10,13 @@ members = ["crates/nu-cli", "crates/nu-engine", "crates/nu-parser", "crates/nu-c
[dependencies] [dependencies]
reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" }
codespan-reporting = "0.11.1"
nu-cli = { path="./crates/nu-cli" } nu-cli = { path="./crates/nu-cli" }
nu-command = { path="./crates/nu-command" } nu-command = { path="./crates/nu-command" }
nu-engine = { path="./crates/nu-engine" } nu-engine = { path="./crates/nu-engine" }
nu-parser = { path="./crates/nu-parser" } nu-parser = { path="./crates/nu-parser" }
nu-protocol = { path = "./crates/nu-protocol" } nu-protocol = { path = "./crates/nu-protocol" }
nu-table = { path = "./crates/nu-table" } nu-table = { path = "./crates/nu-table" }
miette = { version = "3.0.0-alpha.0" }
# mimalloc = { version = "*", default-features = false } # mimalloc = { version = "*", default-features = false }
[dev-dependencies] [dev-dependencies]

View File

@ -7,6 +7,7 @@ edition = "2018"
nu-engine = { path = "../nu-engine" } nu-engine = { path = "../nu-engine" }
nu-parser = { path = "../nu-parser" } nu-parser = { path = "../nu-parser" }
nu-protocol = { path = "../nu-protocol" } nu-protocol = { path = "../nu-protocol" }
codespan-reporting = "0.11.1" miette = { version = "3.0.0-alpha.0", features = ["fancy"] }
thiserror = "1.0.29"
nu-ansi-term = "0.36.0" nu-ansi-term = "0.36.0"
reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" } reedline = { git = "https://github.com/jntrnr/reedline", branch = "main" }

View File

@ -1,414 +1,53 @@
use core::ops::Range; use miette::{LabeledSpan, MietteHandler, ReportHandler, Severity, SourceCode};
use nu_protocol::engine::StateWorkingSet;
use thiserror::Error;
use codespan_reporting::diagnostic::{Diagnostic, Label}; /// This error exists so that we can defer SourceCode handling. It simply
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; /// forwards most methods, except for `.source_code()`, which we provide.
use nu_parser::ParseError; #[derive(Error)]
use nu_protocol::{engine::StateWorkingSet, ShellError, Span}; #[error("{0}")]
struct CliError<'src>(
&'src (dyn miette::Diagnostic + Send + Sync + 'static),
&'src StateWorkingSet<'src>,
);
fn convert_span_to_diag( impl std::fmt::Debug for CliError<'_> {
working_set: &StateWorkingSet, fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
span: &Span, MietteHandler::default().debug(self, f)?;
) -> Result<(usize, Range<usize>), Box<dyn std::error::Error>> { Ok(())
for (file_id, (_, start, end)) in working_set.files().enumerate() { }
if span.start >= *start && span.end <= *end { }
let new_start = span.start - start;
let new_end = span.end - start;
return Ok((file_id, new_start..new_end)); impl<'src> miette::Diagnostic for CliError<'src> {
} fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
self.0.code()
} }
if span.start == working_set.next_span_start() { fn severity(&self) -> Option<Severity> {
// We're trying to highlight the space after the end self.0.severity()
if let Some((file_id, (_, _, end))) = working_set.files().enumerate().last() {
return Ok((file_id, *end..(*end + 1)));
}
} }
panic!( fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
"internal error: can't find span in parser state: {:?}", self.0.help()
span }
)
fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
self.0.url()
}
fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
self.0.labels()
}
// Finally, we redirect the source_code method to our own source.
fn source_code(&self) -> Option<&dyn SourceCode> {
Some(&self.1)
}
} }
pub fn report_parsing_error( pub fn report_error(
working_set: &StateWorkingSet, working_set: &StateWorkingSet,
error: &ParseError, error: &(dyn miette::Diagnostic + Send + Sync + 'static),
) -> Result<(), Box<dyn std::error::Error>> { ) {
let writer = StandardStream::stderr(ColorChoice::Always); eprintln!("Error: {:?}", CliError(error, working_set));
let config = codespan_reporting::term::Config::default();
let diagnostic =
match error {
ParseError::Mismatch(expected, found, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Type mismatch during operation")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("expected {}, found {}", expected, found))])
}
ParseError::ExtraTokens(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Extra tokens in code")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("extra tokens")
])
}
ParseError::ExtraPositional(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Extra positional argument")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("extra positional argument")])
}
ParseError::UnexpectedEof(s, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unexpected end of code")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("expected {}", s))])
}
ParseError::Unclosed(delim, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unclosed delimiter")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("unclosed {}", delim))])
}
ParseError::UnknownStatement(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unknown statement")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("unknown statement")
])
}
ParseError::MultipleRestParams(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Multiple rest params")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("multiple rest params")])
}
ParseError::VariableNotFound(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Variable not found")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("variable not found")
])
}
ParseError::UnknownCommand(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unknown command")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("unknown command")
])
}
ParseError::UnknownFlag(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unknown flag")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("unknown flag")
])
}
ParseError::UnknownType(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unknown type")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("unknown type")
])
}
ParseError::MissingFlagParam(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Missing flag param")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("flag missing parameter")])
}
ParseError::ShortFlagBatchCantTakeArg(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Batches of short flags can't take arguments")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("short flag batches can't take args")])
}
ParseError::KeywordMissingArgument(name, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Missing argument to {}", name))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("missing value that follows {}", name))])
}
ParseError::MissingPositional(name, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Missing required positional arg")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("missing {}", name))])
}
ParseError::MissingType(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Missing type")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("expected type")
])
}
ParseError::MissingColumns(count, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Missing columns")
.with_labels(vec![Label::primary(diag_file_id, diag_range).with_message(
format!(
"expected {} column{}",
count,
if *count == 1 { "" } else { "s" }
),
)])
}
ParseError::ExtraColumns(count, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Extra columns")
.with_labels(vec![Label::primary(diag_file_id, diag_range).with_message(
format!(
"expected {} column{}",
count,
if *count == 1 { "" } else { "s" }
),
)])
}
ParseError::TypeMismatch(expected, found, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Type mismatch")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("expected {:?}, found {:?}", expected, found))])
}
ParseError::MissingRequiredFlag(name, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Missing required flag")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("missing required flag {}", name))])
}
ParseError::IncompleteMathExpression(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Incomplete math expresssion")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("incomplete math expression")])
}
ParseError::UnknownState(name, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Unknown state")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message(name.to_string())
])
}
ParseError::NonUtf8(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Non-UTF8 code")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("non-UTF8 code")
])
}
ParseError::Expected(expected, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Parse mismatch during operation")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("expected {}", expected))])
}
ParseError::UnsupportedOperation(op_span, lhs_span, lhs_ty, rhs_span, rhs_ty) => {
let (lhs_file_id, lhs_range) = convert_span_to_diag(working_set, lhs_span)?;
let (rhs_file_id, rhs_range) = convert_span_to_diag(working_set, rhs_span)?;
let (op_file_id, op_range) = convert_span_to_diag(working_set, op_span)?;
Diagnostic::error()
.with_message("Unsupported operation")
.with_labels(vec![
Label::primary(op_file_id, op_range)
.with_message("doesn't support these values"),
Label::secondary(lhs_file_id, lhs_range).with_message(lhs_ty.to_string()),
Label::secondary(rhs_file_id, rhs_range).with_message(rhs_ty.to_string()),
])
}
ParseError::ExpectedKeyword(expected, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Expected keyword")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("expected {}", expected))])
}
ParseError::IncompleteParser(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Parser incomplete")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("parser support missing for this expression")])
}
ParseError::RestNeedsName(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Rest parameter needs a name")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("needs a parameter name")])
}
ParseError::AssignmentMismatch(msg, label, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(msg)
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message(label)
])
}
};
// println!("DIAG");
// println!("{:?}", diagnostic);
codespan_reporting::term::emit(&mut writer.lock(), &config, working_set, &diagnostic)?;
Ok(())
}
pub fn report_shell_error(
working_set: &StateWorkingSet,
error: &ShellError,
) -> Result<(), Box<dyn std::error::Error>> {
let writer = StandardStream::stderr(ColorChoice::Always);
let config = codespan_reporting::term::Config::default();
let diagnostic =
match error {
ShellError::OperatorMismatch {
op_span,
lhs_ty,
lhs_span,
rhs_ty,
rhs_span,
} => {
let (lhs_file_id, lhs_range) = convert_span_to_diag(working_set, lhs_span)?;
let (rhs_file_id, rhs_range) = convert_span_to_diag(working_set, rhs_span)?;
let (op_file_id, op_range) = convert_span_to_diag(working_set, op_span)?;
Diagnostic::error()
.with_message("Type mismatch during operation")
.with_labels(vec![
Label::primary(op_file_id, op_range)
.with_message("type mismatch for operator"),
Label::secondary(lhs_file_id, lhs_range).with_message(lhs_ty.to_string()),
Label::secondary(rhs_file_id, rhs_range).with_message(rhs_ty.to_string()),
])
}
ShellError::UnsupportedOperator(op, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Unsupported operator: {}", op))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("unsupported operator")])
}
ShellError::UnknownOperator(op, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Unsupported operator: {}", op))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("unsupported operator")])
}
ShellError::ExternalNotSupported(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("External commands not yet supported")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("external not supported")])
}
ShellError::InternalError(s) => {
Diagnostic::error().with_message(format!("Internal error: {}", s))
}
ShellError::VariableNotFoundAtRuntime(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Variable not found")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("variable not found")
])
}
ShellError::CantConvert(s, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message(format!("Can't convert to {}", s))
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("can't convert to {}", s))])
}
ShellError::CannotCreateRange(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Can't convert range to countable values")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("can't convert to countable values")])
}
ShellError::DivisionByZero(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Division by zero")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("division by zero")
])
}
ShellError::AccessBeyondEnd(len, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Row number too large")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("row number too large (max: {})", *len))])
}
ShellError::AccessBeyondEndOfStream(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Row number too large")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message("row number too large")])
}
ShellError::IncompatiblePathAccess(name, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("Data cannot be accessed with a cell path")
.with_labels(vec![Label::primary(diag_file_id, diag_range)
.with_message(format!("{} doesn't support cell paths", name))])
}
ShellError::CantFindColumn(span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
//FIXME: add "did you mean"
Diagnostic::error()
.with_message("Cannot find column")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message("cannot find column")
])
}
ShellError::ExternalCommand(error, span) => {
let (diag_file_id, diag_range) = convert_span_to_diag(working_set, span)?;
Diagnostic::error()
.with_message("External command")
.with_labels(vec![
Label::primary(diag_file_id, diag_range).with_message(error.to_string())
])
}
};
// println!("DIAG");
// println!("{:?}", diagnostic);
codespan_reporting::term::emit(&mut writer.lock(), &config, working_set, &diagnostic)?;
Ok(())
} }

View File

@ -3,5 +3,5 @@ mod errors;
mod syntax_highlight; mod syntax_highlight;
pub use completions::NuCompleter; pub use completions::NuCompleter;
pub use errors::{report_parsing_error, report_shell_error}; pub use errors::report_error;
pub use syntax_highlight::NuHighlighter; pub use syntax_highlight::NuHighlighter;

View File

@ -4,5 +4,6 @@ version = "0.1.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
codespan-reporting = "0.11.1" miette = { version = "3.0.0-alpha.0" }
thiserror = "1.0.29"
nu-protocol = { path = "../nu-protocol"} nu-protocol = { path = "../nu-protocol"}

View File

@ -1,34 +1,150 @@
use miette::Diagnostic;
use nu_protocol::{Span, Type}; use nu_protocol::{Span, Type};
use thiserror::Error;
#[derive(Debug)] #[derive(Clone, Debug, Error, Diagnostic)]
pub enum ParseError { pub enum ParseError {
ExtraTokens(Span), /// The parser encountered unexpected tokens, when the code should have
ExtraPositional(Span), /// finished. You should remove these or finish adding what you intended
UnexpectedEof(String, Span), /// to add.
Unclosed(String, Span), #[error("Extra tokens in code.")]
UnknownStatement(Span), #[diagnostic(
Expected(String, Span), code(nu::parser::extra_tokens),
Mismatch(String, String, Span), // expected, found, span url(docsrs),
UnsupportedOperation(Span, Span, Type, Span, Type), help("Try removing them.")
ExpectedKeyword(String, Span), )]
MultipleRestParams(Span), ExtraTokens(#[label = "extra tokens"] Span),
VariableNotFound(Span),
UnknownCommand(Span), #[error("Extra positional argument.")]
NonUtf8(Span), #[diagnostic(code(nu::parser::extra_positional), url(docsrs))]
UnknownFlag(Span), ExtraPositional(#[label = "extra positional argument"] Span),
UnknownType(Span),
MissingFlagParam(Span), #[error("Unexpected end of code.")]
ShortFlagBatchCantTakeArg(Span), #[diagnostic(code(nu::parser::unexpected_eof), url(docsrs))]
MissingPositional(String, Span), UnexpectedEof(String, #[label("expected {0}")] Span),
KeywordMissingArgument(String, Span),
MissingType(Span), #[error("Unclosed delimiter.")]
TypeMismatch(Type, Type, Span), // expected, found, span #[diagnostic(code(nu::parser::unclosed_delimiter), url(docsrs))]
MissingRequiredFlag(String, Span), Unclosed(String, #[label("unclosed {0}")] Span),
IncompleteMathExpression(Span),
UnknownState(String, Span), #[error("Unknown statement.")]
IncompleteParser(Span), #[diagnostic(code(nu::parser::unknown_statement), url(docsrs))]
RestNeedsName(Span), UnknownStatement(#[label("unknown statement")] Span),
ExtraColumns(usize, Span),
MissingColumns(usize, Span), #[error("Parse mismatch during operation.")]
AssignmentMismatch(String, String, Span), #[diagnostic(code(nu::parser::parse_mismatch), url(docsrs))]
Expected(String, #[label("expected {0}")] Span),
#[error("Type mismatch during operation.")]
#[diagnostic(code(nu::parser::type_mismatch), url(docsrs))]
Mismatch(String, String, #[label("expected {0}, found {1}")] Span), // expected, found, span
#[error("Unsupported operation.")]
#[diagnostic(
code(nu::parser::unsupported_operation),
url(docsrs),
help("Change {2} or {4} to be the right types and try again.")
)]
UnsupportedOperation(
#[label = "doesn't support these values."] Span,
#[label("{2}")] Span,
Type,
#[label("{4}")] Span,
Type,
),
#[error("Expected keyword.")]
#[diagnostic(code(nu::parser::expected_keyword), url(docsrs))]
ExpectedKeyword(String, #[label("expected {0}")] Span),
#[error("Multiple rest params.")]
#[diagnostic(code(nu::parser::multiple_rest_params), url(docsrs))]
MultipleRestParams(#[label = "multiple rest params"] Span),
#[error("Variable not found.")]
#[diagnostic(code(nu::parser::variable_not_found), url(docsrs))]
VariableNotFound(#[label = "variable not found"] Span),
#[error("Unknown command.")]
#[diagnostic(
code(nu::parser::unknown_command),
url(docsrs),
// TODO: actual suggestions
// help("Did you mean `foo`?")
)]
UnknownCommand(#[label = "unknown command"] Span),
#[error("Non-UTF8 code.")]
#[diagnostic(code(nu::parser::non_utf8), url(docsrs))]
NonUtf8(#[label = "non-UTF8 code"] Span),
#[error("Unknown flag.")]
#[diagnostic(code(nu::parser::unknown_flag), url(docsrs))]
UnknownFlag(#[label = "unknown flag"] Span),
#[error("Unknown type.")]
#[diagnostic(code(nu::parser::unknown_type), url(docsrs))]
UnknownType(#[label = "unknown type"] Span),
#[error("Missing flag param.")]
#[diagnostic(code(nu::parser::missing_flag_param), url(docsrs))]
MissingFlagParam(#[label = "flag missing param"] Span),
#[error("Batches of short flags can't take arguments.")]
#[diagnostic(code(nu::parser::short_flag_arg_cant_take_arg), url(docsrs))]
ShortFlagBatchCantTakeArg(#[label = "short flag batches can't take args"] Span),
#[error("Missing required positional argument.")]
#[diagnostic(code(nu::parser::missing_positional), url(docsrs))]
MissingPositional(String, #[label("missing {0}")] Span),
#[error("Missing argument to `{0}`.")]
#[diagnostic(code(nu::parser::keyword_missing_arg), url(docsrs))]
KeywordMissingArgument(String, #[label("missing value that follows {0}")] Span),
#[error("Missing type.")]
#[diagnostic(code(nu::parser::missing_type), url(docsrs))]
MissingType(#[label = "expected type"] Span),
#[error("Type mismatch.")]
#[diagnostic(code(nu::parser::type_mismatch), url(docsrs))]
TypeMismatch(Type, Type, #[label("expected {0:?}, found {1:?}")] Span), // expected, found, span
#[error("Missing required flag.")]
#[diagnostic(code(nu::parser::missing_required_flag), url(docsrs))]
MissingRequiredFlag(String, #[label("missing required flag {0}")] Span),
#[error("Incomplete math expression.")]
#[diagnostic(code(nu::parser::incomplete_math_expression), url(docsrs))]
IncompleteMathExpression(#[label = "incomplete math expression"] Span),
#[error("Unknown state.")]
#[diagnostic(code(nu::parser::unknown_state), url(docsrs))]
UnknownState(String, #[label("{0}")] Span),
#[error("Parser incomplete.")]
#[diagnostic(code(nu::parser::parser_incomplete), url(docsrs))]
IncompleteParser(#[label = "parser support missing for this expression"] Span),
#[error("Rest parameter needs a name.")]
#[diagnostic(code(nu::parser::rest_needs_name), url(docsrs))]
RestNeedsName(#[label = "needs a parameter name"] Span),
#[error("Extra columns.")]
#[diagnostic(code(nu::parser::extra_columns), url(docsrs))]
ExtraColumns(
usize,
#[label("expected {0} column{}", if *.0 == 1 { "" } else { "s" })] Span,
),
#[error("Missing columns.")]
#[diagnostic(code(nu::parser::missing_columns), url(docsrs))]
MissingColumns(
usize,
#[label("expected {0} column{}", if *.0 == 1 { "" } else { "s" })] Span,
),
#[error("{0}")]
#[diagnostic(code(nu::parser::assignment_mismatch), url(docsrs))]
AssignmentMismatch(String, String, #[label("{1}")] Span),
} }

View File

@ -6,4 +6,5 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
codespan-reporting = "0.11.1" thiserror = "1.0.29"
miette = { version = "3.0.0-alpha.0" }

View File

@ -2,7 +2,7 @@ use crate::{ast::Call, value::Value, BlockId, Example, ShellError, Signature};
use super::EvaluationContext; use super::EvaluationContext;
pub trait Command { pub trait Command: Send + Sync {
fn name(&self) -> &str; fn name(&self) -> &str;
fn signature(&self) -> Signature { fn signature(&self) -> Signature {

View File

@ -1,7 +1,7 @@
use super::Command; use super::Command;
use crate::{ast::Block, BlockId, DeclId, Span, Type, VarId}; use crate::{ast::Block, BlockId, DeclId, Span, Type, VarId};
use core::panic; use core::panic;
use std::{collections::HashMap, ops::Range, slice::Iter}; use std::{collections::HashMap, slice::Iter};
pub struct EngineState { pub struct EngineState {
files: Vec<(String, usize, usize)>, files: Vec<(String, usize, usize)>,
@ -549,95 +549,42 @@ impl<'a> StateWorkingSet<'a> {
} }
} }
impl<'a> codespan_reporting::files::Files<'a> for StateWorkingSet<'a> { impl<'a> miette::SourceCode for &StateWorkingSet<'a> {
type FileId = usize; fn read_span<'b>(
&'b self,
type Name = String; span: &miette::SourceSpan,
context_lines_before: usize,
type Source = String; context_lines_after: usize,
) -> Result<Box<dyn miette::SpanContents + 'b>, miette::MietteError> {
fn name(&'a self, id: Self::FileId) -> Result<Self::Name, codespan_reporting::files::Error> { for (filename, start, end) in self.files() {
Ok(self.get_filename(id)) if span.offset() >= *start && span.offset() + span.len() <= *end {
} let our_span = Span {
start: *start,
fn source( end: *end,
&'a self, };
id: Self::FileId, // We need to move to a local span because we're only reading
) -> Result<Self::Source, codespan_reporting::files::Error> { // the specific file contents via self.get_span_contents.
Ok(self.get_file_source(id)) let local_span = (span.offset() - *start, span.len()).into();
} let span_contents = self.get_span_contents(our_span);
let span_contents = span_contents.read_span(
fn line_index( &local_span,
&'a self, context_lines_before,
id: Self::FileId, context_lines_after,
byte_index: usize, )?;
) -> Result<usize, codespan_reporting::files::Error> { let content_span = span_contents.span();
let source = self.get_file_source(id); // Back to "global" indexing
let retranslated = (content_span.offset() + start, content_span.len()).into();
let mut count = 0; return Ok(Box::new(miette::MietteSpanContents::new_named(
filename.clone(),
for byte in source.bytes().enumerate() { span_contents.data(),
if byte.0 == byte_index { retranslated,
// println!("count: {} for file: {} index: {}", count, id, byte_index); span_contents.line(),
return Ok(count); span_contents.column(),
} span_contents.line_count(),
if byte.1 == b'\n' { )));
count += 1;
} }
} }
Err(miette::MietteError::OutOfBounds)
// println!("count: {} for file: {} index: {}", count, id, byte_index);
Ok(count)
}
fn line_range(
&'a self,
id: Self::FileId,
line_index: usize,
) -> Result<Range<usize>, codespan_reporting::files::Error> {
let source = self.get_file_source(id);
let mut count = 0;
let mut start = Some(0);
let mut end = None;
for byte in source.bytes().enumerate() {
#[allow(clippy::comparison_chain)]
if count > line_index {
let start = start.expect("internal error: couldn't find line");
let end = end.expect("internal error: couldn't find line");
// println!(
// "Span: {}..{} for fileid: {} index: {}",
// start, end, id, line_index
// );
return Ok(start..end);
} else if count == line_index {
end = Some(byte.0 + 1);
}
#[allow(clippy::comparison_chain)]
if byte.1 == b'\n' {
count += 1;
if count > line_index {
break;
} else if count == line_index {
start = Some(byte.0 + 1);
}
}
}
match (start, end) {
(Some(start), Some(end)) => {
// println!(
// "Span: {}..{} for fileid: {} index: {}",
// start, end, id, line_index
// );
Ok(start..end)
}
_ => Err(codespan_reporting::files::Error::FileMissing),
}
} }
} }

View File

@ -1,25 +1,72 @@
use miette::Diagnostic;
use thiserror::Error;
use crate::{ast::Operator, Span, Type}; use crate::{ast::Operator, Span, Type};
#[derive(Debug, Clone)] #[derive(Debug, Clone, Error, Diagnostic)]
pub enum ShellError { pub enum ShellError {
#[error("Type mismatch during operation.")]
#[diagnostic(code(nu::shell::type_mismatch), url(docsrs))]
OperatorMismatch { OperatorMismatch {
#[label = "type mismatch for operator"]
op_span: Span, op_span: Span,
lhs_ty: Type, lhs_ty: Type,
#[label("{lhs_ty}")]
lhs_span: Span, lhs_span: Span,
rhs_ty: Type, rhs_ty: Type,
#[label("{rhs_ty}")]
rhs_span: Span, rhs_span: Span,
}, },
UnsupportedOperator(Operator, Span),
UnknownOperator(String, Span), #[error("Unsupported operator: {0}.")]
ExternalNotSupported(Span), #[diagnostic(code(nu::shell::unsupported_operator), url(docsrs))]
UnsupportedOperator(Operator, #[label = "unsupported operator"] Span),
#[error("Unsupported operator: {0}.")]
#[diagnostic(code(nu::shell::unknown_operator), url(docsrs))]
UnknownOperator(String, #[label = "unsupported operator"] Span),
#[error("External commands not yet supported")]
#[diagnostic(code(nu::shell::external_commands), url(docsrs))]
ExternalNotSupported(#[label = "external not supported"] Span),
#[error("Internal error: {0}.")]
#[diagnostic(code(nu::shell::internal_error), url(docsrs))]
InternalError(String), InternalError(String),
VariableNotFoundAtRuntime(Span),
CantConvert(String, Span), #[error("Variable not found")]
DivisionByZero(Span), #[diagnostic(code(nu::shell::variable_not_found), url(docsrs))]
CannotCreateRange(Span), VariableNotFoundAtRuntime(#[label = "variable not found"] Span),
AccessBeyondEnd(usize, Span),
AccessBeyondEndOfStream(Span), #[error("Can't convert to {0}.")]
IncompatiblePathAccess(String, Span), #[diagnostic(code(nu::shell::cant_convert), url(docsrs))]
CantFindColumn(Span), CantConvert(String, #[label("can't convert to {0}")] Span),
ExternalCommand(String, Span),
#[error("Division by zero.")]
#[diagnostic(code(nu::shell::division_by_zero), url(docsrs))]
DivisionByZero(#[label("division by zero")] Span),
#[error("Can't convert range to countable values")]
#[diagnostic(code(nu::shell::range_to_countable), url(docsrs))]
CannotCreateRange(#[label = "can't convert to countable values"] Span),
#[error("Row number too large (max: {0}).")]
#[diagnostic(code(nu::shell::access_beyond_end), url(docsrs))]
AccessBeyondEnd(usize, #[label = "too large"] Span),
#[error("Row number too large.")]
#[diagnostic(code(nu::shell::access_beyond_end_of_stream), url(docsrs))]
AccessBeyondEndOfStream(#[label = "too large"] Span),
#[error("Data cannot be accessed with a cell path")]
#[diagnostic(code(nu::shell::incompatible_path_access), url(docsrs))]
IncompatiblePathAccess(String, #[label("{0} doesn't support cell paths")] Span),
#[error("Cannot find column")]
#[diagnostic(code(nu::shell::column_not_found), url(docsrs))]
CantFindColumn(#[label = "cannot find column"] Span),
#[error("External command")]
#[diagnostic(code(nu::shell::external_command), url(docsrs))]
ExternalCommand(String, #[label("{0}")] Span),
} }

View File

@ -1,9 +1,17 @@
use miette::SourceSpan;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Span { pub struct Span {
pub start: usize, pub start: usize,
pub end: usize, pub end: usize,
} }
impl From<Span> for SourceSpan {
fn from(s: Span) -> Self {
Self::new(s.start.into(), (s.end - s.start).into())
}
}
impl Span { impl Span {
pub fn new(start: usize, end: usize) -> Span { pub fn new(start: usize, end: usize) -> Span {
Span { start, end } Span { start, end }

View File

@ -1,4 +1,5 @@
use nu_cli::{report_parsing_error, report_shell_error, NuCompleter, NuHighlighter}; use miette::{IntoDiagnostic, Result};
use nu_cli::{report_error, NuCompleter, NuHighlighter};
use nu_command::create_default_context; use nu_command::create_default_context;
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_parser::parse; use nu_parser::parse;
@ -11,18 +12,18 @@ use reedline::DefaultCompletionActionHandler;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
fn main() -> std::io::Result<()> { fn main() -> Result<()> {
let engine_state = create_default_context(); let engine_state = create_default_context();
if let Some(path) = std::env::args().nth(1) { if let Some(path) = std::env::args().nth(1) {
let file = std::fs::read(&path)?; let file = std::fs::read(&path).into_diagnostic()?;
let (block, delta) = { let (block, delta) = {
let engine_state = engine_state.borrow(); let engine_state = engine_state.borrow();
let mut working_set = StateWorkingSet::new(&*engine_state); let mut working_set = StateWorkingSet::new(&*engine_state);
let (output, err) = parse(&mut working_set, Some(&path), &file, false); let (output, err) = parse(&mut working_set, Some(&path), &file, false);
if let Some(err) = err { if let Some(err) = err {
let _ = report_parsing_error(&working_set, &err); report_error(&working_set, &err);
std::process::exit(1); std::process::exit(1);
} }
@ -44,7 +45,7 @@ fn main() -> std::io::Result<()> {
let engine_state = engine_state.borrow(); let engine_state = engine_state.borrow();
let working_set = StateWorkingSet::new(&*engine_state); let working_set = StateWorkingSet::new(&*engine_state);
let _ = report_shell_error(&working_set, &err); report_error(&working_set, &err);
std::process::exit(1); std::process::exit(1);
} }
@ -56,11 +57,12 @@ fn main() -> std::io::Result<()> {
let completer = NuCompleter::new(engine_state.clone()); let completer = NuCompleter::new(engine_state.clone());
let mut line_editor = Reedline::create()? let mut line_editor = Reedline::create()
.with_history(Box::new(FileBackedHistory::with_file( .into_diagnostic()?
1000, .with_history(Box::new(
"history.txt".into(), FileBackedHistory::with_file(1000, "history.txt".into()).into_diagnostic()?,
)?))? ))
.into_diagnostic()?
.with_highlighter(Box::new(NuHighlighter { .with_highlighter(Box::new(NuHighlighter {
engine_state: engine_state.clone(), engine_state: engine_state.clone(),
})) }))
@ -102,7 +104,7 @@ fn main() -> std::io::Result<()> {
false, false,
); );
if let Some(err) = err { if let Some(err) = err {
let _ = report_parsing_error(&working_set, &err); report_error(&working_set, &err);
continue; continue;
} }
(output, working_set.render()) (output, working_set.render())
@ -123,7 +125,7 @@ fn main() -> std::io::Result<()> {
let engine_state = engine_state.borrow(); let engine_state = engine_state.borrow();
let working_set = StateWorkingSet::new(&*engine_state); let working_set = StateWorkingSet::new(&*engine_state);
let _ = report_shell_error(&working_set, &err); report_error(&working_set, &err);
} }
} }
} }
@ -134,7 +136,7 @@ fn main() -> std::io::Result<()> {
break; break;
} }
Ok(Signal::CtrlL) => { Ok(Signal::CtrlL) => {
line_editor.clear_screen()?; line_editor.clear_screen().into_diagnostic()?;
} }
Err(err) => { Err(err) => {
let message = err.to_string(); let message = err.to_string();

View File

@ -133,7 +133,7 @@ fn if_elseif4() -> TestResult {
fn no_scope_leak1() -> TestResult { fn no_scope_leak1() -> TestResult {
fail_test( fail_test(
"if $false { let $x = 10 } else { let $x = 20 }; $x", "if $false { let $x = 10 } else { let $x = 20 }; $x",
"variable not found", "Variable not found",
) )
} }