use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RdInlineSpanKind {
Emph,
Strong,
Bold,
Code,
Special,
Verb,
Url,
Email,
File,
Pkg,
Samp,
SQuote,
DQuote,
Kbd,
Var,
Env,
Command,
Option,
Acronym,
Abbr,
Cite,
Dfn,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RdInlineSpan<'a> {
path: RdPath,
kind: RdInlineSpanKind,
body: &'a [RdNode],
}
impl<'a> RdInlineSpan<'a> {
pub fn path(&self) -> &RdPath {
&self.path
}
pub fn kind(&self) -> RdInlineSpanKind {
self.kind
}
pub fn body(&self) -> &'a [RdNode] {
self.body
}
}
fn inline_span_kind(tag: &RdTag) -> Option<RdInlineSpanKind> {
Some(match tag {
RdTag::Emph => RdInlineSpanKind::Emph,
RdTag::Strong => RdInlineSpanKind::Strong,
RdTag::Bold => RdInlineSpanKind::Bold,
RdTag::Code => RdInlineSpanKind::Code,
RdTag::Special => RdInlineSpanKind::Special,
RdTag::Verb => RdInlineSpanKind::Verb,
RdTag::Url => RdInlineSpanKind::Url,
RdTag::Email => RdInlineSpanKind::Email,
RdTag::File => RdInlineSpanKind::File,
RdTag::Pkg => RdInlineSpanKind::Pkg,
RdTag::Samp => RdInlineSpanKind::Samp,
RdTag::SQuote => RdInlineSpanKind::SQuote,
RdTag::DQuote => RdInlineSpanKind::DQuote,
RdTag::Kbd => RdInlineSpanKind::Kbd,
RdTag::Var => RdInlineSpanKind::Var,
RdTag::Env => RdInlineSpanKind::Env,
RdTag::Command => RdInlineSpanKind::Command,
RdTag::Option => RdInlineSpanKind::Option,
RdTag::Acronym => RdInlineSpanKind::Acronym,
RdTag::Abbr => RdInlineSpanKind::Abbr,
RdTag::Cite => RdInlineSpanKind::Cite,
RdTag::Dfn => RdInlineSpanKind::Dfn,
_ => return None,
})
}
impl RdNode {
pub fn inline_span(&self, base_path: &RdPath) -> Option<RdInlineSpan<'_>> {
let tagged = self.as_tagged()?;
let kind = inline_span_kind(tagged.tag())?;
tagged.option().is_none().then(|| RdInlineSpan {
path: base_path.clone(),
kind,
body: tagged.children(),
})
}
pub fn inspect_inline_span(
&self,
base_path: &RdPath,
) -> Result<Option<RdInlineSpan<'_>>, RdShapeError> {
match self {
RdNode::Tagged(tagged) => {
let Some(kind) = inline_span_kind(tagged.tag()) else {
return Ok(None);
};
if tagged.option().is_some() {
return Err(shape(
base_path.clone(),
Some(tagged.tag().clone()),
RdShapeErrorKind::UnexpectedOption,
));
}
Ok(Some(RdInlineSpan {
path: base_path.clone(),
kind,
body: tagged.children(),
}))
}
RdNode::Raw(raw) => {
let Some(tag) = raw.tag().map(RdTag::from_rd_tag) else {
return Ok(None);
};
if inline_span_kind(&tag).is_none() {
return Ok(None);
}
Err(shape(
base_path.clone(),
Some(tag),
RdShapeErrorKind::UnexpectedNode {
expected: RdExpectedNode::Tagged,
actual: RdNodeKind::Raw,
},
))
}
_ => Ok(None),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RdTextSymbolKind {
R,
Dots,
LDots,
}
impl RdTextSymbolKind {
pub const fn fallback_text(self) -> &'static str {
match self {
Self::R => "R",
Self::Dots | Self::LDots => "...",
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RdTextSymbol {
path: RdPath,
kind: RdTextSymbolKind,
}
impl RdTextSymbol {
pub fn path(&self) -> &RdPath {
&self.path
}
pub fn kind(&self) -> RdTextSymbolKind {
self.kind
}
pub const fn fallback_text(&self) -> &'static str {
self.kind.fallback_text()
}
}
fn text_symbol_kind(tag: &RdTag) -> Option<RdTextSymbolKind> {
match tag {
RdTag::R => Some(RdTextSymbolKind::R),
RdTag::Dots => Some(RdTextSymbolKind::Dots),
RdTag::LDots => Some(RdTextSymbolKind::LDots),
_ => None,
}
}
impl RdNode {
pub fn text_symbol(&self, base_path: &RdPath) -> Option<RdTextSymbol> {
let tagged = self.as_tagged()?;
let kind = text_symbol_kind(tagged.tag())?;
(tagged.option().is_none() && tagged.children().is_empty()).then(|| RdTextSymbol {
path: base_path.clone(),
kind,
})
}
pub fn inspect_text_symbol(
&self,
base_path: &RdPath,
) -> Result<Option<RdTextSymbol>, RdShapeError> {
match self {
RdNode::Tagged(tagged) => {
let Some(kind) = text_symbol_kind(tagged.tag()) else {
return Ok(None);
};
if tagged.option().is_some() {
return Err(shape(
base_path.clone(),
Some(tagged.tag().clone()),
RdShapeErrorKind::UnexpectedOption,
));
}
if !tagged.children().is_empty() {
return Err(shape(
base_path.clone(),
Some(tagged.tag().clone()),
RdShapeErrorKind::WrongArity {
expected: RdArity::Exactly(0),
actual: tagged.children().len(),
},
));
}
Ok(Some(RdTextSymbol {
path: base_path.clone(),
kind,
}))
}
RdNode::Raw(raw) => {
let Some(tag) = raw.tag().map(RdTag::from_rd_tag) else {
return Ok(None);
};
if text_symbol_kind(&tag).is_none() {
return Ok(None);
}
Err(shape(
base_path.clone(),
Some(tag),
RdShapeErrorKind::UnexpectedNode {
expected: RdExpectedNode::Tagged,
actual: RdNodeKind::Raw,
},
))
}
_ => Ok(None),
}
}
}