use super::Point;
use crate::Error;
use ::markdown::{mdast, unist};
use ::std::ops::Range;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct Position {
pub start: Point,
pub end: Point,
}
impl Position {
pub fn extend(&mut self, other: &Position) {
if other.start < self.start {
self.start = other.start.clone();
}
if other.end > self.end {
self.end = other.end.clone();
}
}
pub fn find_substring<'a>(&self, string: &'a str) -> Result<&'a str, Error> {
let Some(substring) = string.get(self.start.offset..self.end.offset) else {
return Err(Error::InvalidOffset {
data: string.into(),
position: Box::new(self.clone()),
});
};
Ok(substring)
}
pub fn range_between(&self, other: &Self) -> Option<Range<usize>> {
self.exclusive_with(other).then(|| {
if self.end < other.start {
self.end.offset..other.start.offset
} else {
other.end.offset..self.start.offset
}
})
}
pub fn exclusive_with(&self, other: &Self) -> bool {
self.start > other.end || self.end < other.start
}
pub fn contains_line(&self, line: usize) -> bool {
self.start.line <= line && self.end.line >= line
}
}
impl From<unist::Position> for Position {
fn from(value: unist::Position) -> Self {
Self {
start: value.start.into(),
end: value.end.into(),
}
}
}
impl From<&unist::Position> for Position {
fn from(value: &unist::Position) -> Self {
Self {
start: Point::from(&value.start),
end: Point::from(&value.end),
}
}
}
impl TryFrom<&mdast::Code> for Position {
type Error = Error;
fn try_from(value: &mdast::Code) -> Result<Self, Self::Error> {
let Some(position) = value.position.as_ref() else {
return Err(Error::MissingPosition {
node: Box::new(mdast::Node::Code(value.clone())),
});
};
Ok(position.into())
}
}
impl TryFrom<&mdast::Root> for Position {
type Error = Error;
fn try_from(value: &mdast::Root) -> Result<Self, Self::Error> {
let Some(position) = value.position.as_ref() else {
return Err(Error::MissingPosition {
node: Box::new(mdast::Node::Root(value.clone())),
});
};
Ok(position.into())
}
}
impl TryFrom<&mdast::Heading> for Position {
type Error = Error;
fn try_from(value: &mdast::Heading) -> Result<Self, Self::Error> {
let Some(position) = value.position.as_ref() else {
return Err(Error::MissingPosition {
node: Box::new(mdast::Node::Heading(value.clone())),
});
};
Ok(position.into())
}
}