mirror of
https://github.com/typst/typst
synced 2025-06-15 16:46:24 +08:00
Introduce QueryError
This commit is contained in:
parent
ea145ff33b
commit
3a12749bf1
@ -1,14 +1,13 @@
|
|||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoVec};
|
use ecow::{eco_format, EcoString, EcoVec};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::diag::{bail, StrResult};
|
|
||||||
use crate::foundations::{Content, Label, Repr, Selector};
|
use crate::foundations::{Content, Label, Repr, Selector};
|
||||||
use crate::introspection::{Location, TagKind};
|
use crate::introspection::{Location, TagKind};
|
||||||
use crate::layout::{Frame, FrameItem, Page, Point, Position, Transform};
|
use crate::layout::{Frame, FrameItem, Page, Point, Position, Transform};
|
||||||
@ -221,34 +220,31 @@ impl Introspector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Query for the first element that matches the selector.
|
/// Query for the first element that matches the selector.
|
||||||
pub fn query_unique(&self, selector: &Selector) -> StrResult<Content> {
|
pub fn query_unique(&self, selector: &Selector) -> Result<Content, QueryError> {
|
||||||
match selector {
|
match selector {
|
||||||
Selector::Location(location) => self
|
Selector::Location(location) => {
|
||||||
.get(location)
|
self.get(location).cloned().ok_or(QueryError::MissingMatch)
|
||||||
.cloned()
|
}
|
||||||
.ok_or_else(|| "element does not exist in the document".into()),
|
|
||||||
Selector::Label(label) => self.query_label(*label).cloned(),
|
Selector::Label(label) => self.query_label(*label).cloned(),
|
||||||
_ => {
|
_ => {
|
||||||
let elems = self.query(selector);
|
let elems = self.query(selector);
|
||||||
if elems.len() > 1 {
|
if elems.len() > 1 {
|
||||||
bail!("selector matches multiple elements",);
|
return Err(QueryError::MultipleMatches);
|
||||||
}
|
}
|
||||||
elems
|
elems.into_iter().next().ok_or(QueryError::MissingMatch)
|
||||||
.into_iter()
|
|
||||||
.next()
|
|
||||||
.ok_or_else(|| "selector does not match any element".into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query for a unique element with the label.
|
/// Query for a unique element with the label.
|
||||||
pub fn query_label(&self, label: Label) -> StrResult<&Content> {
|
pub fn query_label(&self, label: Label) -> Result<&Content, QueryError> {
|
||||||
let indices = self.labels.get(&label).ok_or_else(|| {
|
let indices = self
|
||||||
eco_format!("label `{}` does not exist in the document", label.repr())
|
.labels
|
||||||
})?;
|
.get(&label)
|
||||||
|
.ok_or_else(|| QueryError::MissingLabel(label))?;
|
||||||
|
|
||||||
if indices.len() > 1 {
|
if indices.len() > 1 {
|
||||||
bail!("label `{}` occurs multiple times in the document", label.repr());
|
return Err(QueryError::MultipleLabels(label));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(&self.elems[indices[0]].0)
|
Ok(&self.elems[indices[0]].0)
|
||||||
@ -340,3 +336,39 @@ impl Clone for QueryCache {
|
|||||||
Self(RwLock::new(self.0.read().unwrap().clone()))
|
Self(RwLock::new(self.0.read().unwrap().clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error that occured while querying a selector.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub enum QueryError {
|
||||||
|
MissingMatch,
|
||||||
|
MultipleMatches,
|
||||||
|
MissingLabel(Label),
|
||||||
|
MultipleLabels(Label),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for QueryError {}
|
||||||
|
|
||||||
|
impl Display for QueryError {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::MissingMatch => f.pad("selector does not match any element"),
|
||||||
|
Self::MultipleMatches => f.pad("selector matches multiple elements"),
|
||||||
|
Self::MissingLabel(label) => {
|
||||||
|
write!(f, "label `{}` does not exist in the document", label.repr())
|
||||||
|
}
|
||||||
|
Self::MultipleLabels(label) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"label `{}` occurs multiple times in the document",
|
||||||
|
label.repr()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<QueryError> for EcoString {
|
||||||
|
fn from(err: QueryError) -> Self {
|
||||||
|
eco_format!("{err}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user