ok/jj
1
0
Fork 0
forked from mirrors/jj

revset: add origin field to RevsetParseError to chain alias errors

This could be embedded in a variant of RevsetParseErrorKind, but I want to
keep the enum comparable.
This commit is contained in:
Yuya Nishihara 2022-11-25 18:46:30 +09:00
parent 7632466cc0
commit 5df25cd834
2 changed files with 33 additions and 1 deletions

View file

@ -198,6 +198,7 @@ pub struct RevsetParser;
pub struct RevsetParseError { pub struct RevsetParseError {
kind: RevsetParseErrorKind, kind: RevsetParseErrorKind,
pest_error: Option<Box<pest::error::Error<Rule>>>, pest_error: Option<Box<pest::error::Error<Rule>>>,
origin: Option<Box<RevsetParseError>>,
} }
#[derive(Debug, Error, PartialEq, Eq)] #[derive(Debug, Error, PartialEq, Eq)]
@ -219,6 +220,7 @@ impl RevsetParseError {
RevsetParseError { RevsetParseError {
kind, kind,
pest_error: None, pest_error: None,
origin: None,
} }
} }
@ -232,12 +234,36 @@ impl RevsetParseError {
RevsetParseError { RevsetParseError {
kind, kind,
pest_error: Some(Box::new(err)), pest_error: Some(Box::new(err)),
origin: None,
}
}
fn with_span_and_origin(
kind: RevsetParseErrorKind,
span: pest::Span<'_>,
origin: Self,
) -> Self {
let err = pest::error::Error::new_from_span(
pest::error::ErrorVariant::CustomError {
message: kind.to_string(),
},
span,
);
RevsetParseError {
kind,
pest_error: Some(Box::new(err)),
origin: Some(Box::new(origin)),
} }
} }
pub fn kind(&self) -> &RevsetParseErrorKind { pub fn kind(&self) -> &RevsetParseErrorKind {
&self.kind &self.kind
} }
/// Original parsing error which typically occurred in an alias expression.
pub fn origin(&self) -> Option<&Self> {
self.origin.as_deref()
}
} }
impl From<pest::error::Error<Rule>> for RevsetParseError { impl From<pest::error::Error<Rule>> for RevsetParseError {
@ -245,6 +271,7 @@ impl From<pest::error::Error<Rule>> for RevsetParseError {
RevsetParseError { RevsetParseError {
kind: RevsetParseErrorKind::SyntaxError, kind: RevsetParseErrorKind::SyntaxError,
pest_error: Some(Box::new(err)), pest_error: Some(Box::new(err)),
origin: None,
} }
} }
} }
@ -261,6 +288,9 @@ impl fmt::Display for RevsetParseError {
impl error::Error for RevsetParseError { impl error::Error for RevsetParseError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> { fn source(&self) -> Option<&(dyn error::Error + 'static)> {
if let Some(e) = self.origin() {
return Some(e as &dyn error::Error);
}
match &self.kind { match &self.kind {
// SyntaxError is a wrapper for pest::error::Error. // SyntaxError is a wrapper for pest::error::Error.
RevsetParseErrorKind::SyntaxError => { RevsetParseErrorKind::SyntaxError => {

View file

@ -16,6 +16,7 @@ use std::collections::{HashSet, VecDeque};
use std::env::ArgsOs; use std::env::ArgsOs;
use std::ffi::OsString; use std::ffi::OsString;
use std::fmt::Debug; use std::fmt::Debug;
use std::iter;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -175,7 +176,8 @@ impl From<GitExportError> for CommandError {
impl From<RevsetParseError> for CommandError { impl From<RevsetParseError> for CommandError {
fn from(err: RevsetParseError) -> Self { fn from(err: RevsetParseError) -> Self {
user_error(format!("Failed to parse revset: {err}")) let message = iter::successors(Some(&err), |e| e.origin()).join("\n");
user_error(format!("Failed to parse revset: {message}"))
} }
} }