use std::collections::HashMap;
use std::fmt;
use std::ops::Range;
use serde_json::Value;
use crate::{parser::iter::BranchIter, trim::TrimHint};
static WHITESPACE: &str = "~";
static ROOT: &str = "@root";
pub trait Slice<'source>: fmt::Display + fmt::Debug {
fn as_str(&self) -> &'source str;
fn source(&self) -> &'source str;
}
pub trait Lines {
fn lines(&self) -> &Range<usize>;
fn lines_mut(&mut self) -> &mut Range<usize>;
fn lines_end(&mut self, line: &usize) {
self.lines_mut().end = line.clone() + 1;
}
}
pub trait Element<'source> {
fn open(&self) -> &'source str;
fn close(&self) -> &'source str;
fn open_span(&self) -> &Range<usize>;
fn close_span(&self) -> &Option<Range<usize>>;
fn is_closed(&self) -> bool;
fn exit(&mut self, close: Range<usize>);
fn span(&self) -> Range<usize> {
if let Some(ref close) = self.close_span() {
self.open_span().start..close.end
} else {
self.open_span().clone()
}
}
}
#[derive(Eq, PartialEq)]
pub enum Node<'source> {
Document(Document<'source>),
Text(Text<'source>),
Statement(Call<'source>),
Block(Block<'source>),
RawStatement(TextBlock<'source>),
RawComment(TextBlock<'source>),
Comment(TextBlock<'source>),
Link(Link<'source>),
}
impl Default for Node<'_> {
fn default() -> Self {
Node::Document(Document("", vec![]))
}
}
impl<'source> Node<'source> {
pub fn trim(&self) -> TrimHint {
TrimHint {
before: self.trim_before(),
after: self.trim_after(),
}
}
fn trim_before(&self) -> bool {
match *self {
Self::Document(_)
| Self::Text(_)
| Self::RawStatement(_)
| Self::RawComment(_)
| Self::Comment(_)
| Self::Link(_) => false,
Self::Statement(ref n) => n.trim_before(),
Self::Block(ref n) => n.trim_before(),
}
}
fn trim_after(&self) -> bool {
match *self {
Self::Document(_)
| Self::Text(_)
| Self::RawStatement(_)
| Self::RawComment(_)
| Self::Comment(_)
| Self::Link(_) => false,
Self::Statement(ref n) => n.trim_after(),
Self::Block(ref n) => n.trim_after(),
}
}
pub fn into_iter<'a>(&'a self) -> BranchIter<'a> {
BranchIter::new(self)
}
}
impl<'source> Slice<'source> for Node<'source> {
fn as_str(&self) -> &'source str {
match *self {
Self::Document(ref n) => n.as_str(),
Self::Text(ref n) => n.as_str(),
Self::Statement(ref n) => n.as_str(),
Self::Block(ref n) => n.as_str(),
Self::Link(ref n) => n.as_str(),
Self::RawStatement(ref n)
| Self::RawComment(ref n)
| Self::Comment(ref n) => n.as_str(),
}
}
fn source(&self) -> &'source str {
match *self {
Self::Document(ref n) => n.source(),
Self::Text(ref n) => n.source(),
Self::RawStatement(ref n) => n.source(),
Self::RawComment(ref n) => n.source(),
Self::Comment(ref n) => n.source(),
Self::Statement(ref n) => n.source(),
Self::Block(ref n) => n.source(),
Self::Link(ref n) => n.source(),
}
}
}
impl fmt::Display for Node<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Document(ref n) => n.fmt(f),
Self::Text(ref n) => n.fmt(f),
Self::Statement(ref n) => n.fmt(f),
Self::Block(ref n) => n.fmt(f),
Self::Link(ref n) => n.fmt(f),
Self::RawStatement(ref n)
| Self::RawComment(ref n)
| Self::Comment(ref n) => n.fmt(f),
}
}
}
impl fmt::Debug for Node<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Document(ref n) => fmt::Debug::fmt(n, f),
Self::Text(ref n) => fmt::Debug::fmt(n, f),
Self::Statement(ref n) => fmt::Debug::fmt(n, f),
Self::Block(ref n) => fmt::Debug::fmt(n, f),
Self::Link(ref n) => fmt::Debug::fmt(n, f),
Self::RawStatement(ref n)
| Self::RawComment(ref n)
| Self::Comment(ref n) => fmt::Debug::fmt(n, f),
}
}
}
#[derive(Eq, PartialEq)]
pub struct Text<'source> {
source: &'source str,
span: Range<usize>,
line: Range<usize>,
}
impl<'source> Text<'source> {
pub fn new(
source: &'source str,
span: Range<usize>,
line: Range<usize>,
) -> Self {
Self { source, span, line }
}
}
impl<'source> Lines for Text<'source> {
fn lines(&self) -> &Range<usize> {
&self.line
}
fn lines_mut(&mut self) -> &mut Range<usize> {
&mut self.line
}
}
impl<'source> Slice<'source> for Text<'source> {
fn as_str(&self) -> &'source str {
&self.source[self.span.start..self.span.end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl fmt::Display for Text<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for Text<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Text")
.field("source", &self.as_str())
.field("span", &self.span)
.field("line", &self.line)
.finish()
}
}
#[derive(Eq, PartialEq)]
pub struct TextBlock<'source> {
source: &'source str,
text: Text<'source>,
open: Range<usize>,
close: Range<usize>,
}
impl<'source> TextBlock<'source> {
pub fn new(
source: &'source str,
text: Text<'source>,
open: Range<usize>,
close: Range<usize>,
) -> Self {
Self {
source,
text,
open,
close,
}
}
}
impl<'source> Slice<'source> for TextBlock<'source> {
fn as_str(&self) -> &'source str {
&self.source[self.open.start..self.close.end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl<'source> Lines for TextBlock<'source> {
fn lines(&self) -> &Range<usize> {
self.text.lines()
}
fn lines_mut(&mut self) -> &mut Range<usize> {
self.text.lines_mut()
}
}
impl<'source> Into<Text<'source>> for TextBlock<'source> {
fn into(self) -> Text<'source> {
self.text
}
}
impl fmt::Display for TextBlock<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for TextBlock<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TextBlock")
.field("source", &self.as_str())
.field("open", &self.open)
.field("close", &self.close)
.field("line", self.lines())
.finish()
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum RawIdType {
Single,
Double,
Array,
}
#[derive(Debug, Eq, PartialEq)]
pub enum ComponentType {
Parent,
ThisKeyword,
ThisDotSlash,
Identifier,
LocalIdentifier,
RawIdentifier(RawIdType),
Delimiter,
}
#[derive(Eq, PartialEq)]
pub struct Component<'source> {
source: &'source str,
kind: ComponentType,
span: Range<usize>,
value: Option<String>,
}
impl<'source> Component<'source> {
pub fn new(
source: &'source str,
kind: ComponentType,
span: Range<usize>,
value: Option<String>,
) -> Self {
Self {
source,
kind,
span,
value,
}
}
pub fn is_root(&self) -> bool {
self.as_str() == ROOT
}
pub fn kind(&self) -> &ComponentType {
&self.kind
}
pub fn span(&self) -> &Range<usize> {
&self.span
}
pub fn is_local(&self) -> bool {
&ComponentType::LocalIdentifier == self.kind()
}
pub fn is_identifier(&self) -> bool {
&ComponentType::Identifier == self.kind()
}
pub fn is_explicit(&self) -> bool {
&ComponentType::ThisKeyword == self.kind()
|| self.is_explicit_dot_slash()
}
pub fn is_explicit_dot_slash(&self) -> bool {
&ComponentType::ThisDotSlash == self.kind()
}
pub fn as_value(&self) -> &str {
if let Some(ref value) = self.value {
return value;
}
self.as_str()
}
}
impl<'source> Slice<'source> for Component<'source> {
fn as_str(&self) -> &'source str {
&self.source[self.span().start..self.span().end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl fmt::Display for Component<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for Component<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Component")
.field("source", &self.as_str())
.field("kind", &self.kind)
.field("span", &self.span)
.finish()
}
}
#[derive(Eq, PartialEq)]
pub struct Path<'source> {
source: &'source str,
components: Vec<Component<'source>>,
parents: u8,
explicit: bool,
root: bool,
span: Range<usize>,
line: Range<usize>,
}
impl<'source> Path<'source> {
pub fn new(
source: &'source str,
span: Range<usize>,
line: Range<usize>,
) -> Self {
Self {
source,
components: Vec::new(),
parents: 0,
explicit: false,
root: false,
span,
line,
}
}
pub fn span(&self) -> &Range<usize> {
&self.span
}
pub fn span_mut(&mut self) -> &mut Range<usize> {
&mut self.span
}
pub fn add_component(&mut self, part: Component<'source>) {
self.components.push(part);
}
pub fn components(&self) -> &Vec<Component<'source>> {
&self.components
}
pub fn parents(&self) -> u8 {
self.parents
}
pub fn set_parents(&mut self, parents: u8) {
self.parents = parents;
}
pub fn is_root(&self) -> bool {
self.root
}
pub fn set_root(&mut self, root: bool) {
self.root = root;
}
pub fn is_explicit(&self) -> bool {
self.explicit
}
pub fn set_explicit(&mut self, explicit: bool) {
self.explicit = explicit;
}
pub fn is_empty(&self) -> bool {
self.components.is_empty()
}
pub fn is_local(&self) -> bool {
return !self.components.is_empty()
&& self.components.first().unwrap().is_local();
}
pub fn is_simple(&self) -> bool {
return self.components.len() == 1
&& self.components.first().unwrap().kind
== ComponentType::Identifier;
}
}
impl<'source> Slice<'source> for Path<'source> {
fn as_str(&self) -> &'source str {
&self.source[self.span.start..self.span.end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl<'source> Lines for Path<'source> {
fn lines(&self) -> &Range<usize> {
&self.line
}
fn lines_mut(&mut self) -> &mut Range<usize> {
&mut self.line
}
}
impl fmt::Display for Path<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for Path<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Path")
.field("source", &self.as_str())
.field("components", &self.components)
.field("parents", &self.parents)
.field("explicit", &self.explicit)
.field("root", &self.root)
.field("line", &self.line)
.finish()
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum ParameterValue<'source> {
Path(Path<'source>),
Json {
source: &'source str,
value: Value,
span: Range<usize>,
line: Range<usize>,
},
SubExpr(Call<'source>),
}
impl<'source> From<(&'source str, Value, Range<usize>, Range<usize>)>
for ParameterValue<'source>
{
fn from(value: (&'source str, Value, Range<usize>, Range<usize>)) -> Self {
ParameterValue::Json {
source: value.0,
value: value.1,
span: value.2,
line: value.3,
}
}
}
impl<'source> Slice<'source> for ParameterValue<'source> {
fn as_str(&self) -> &'source str {
match *self {
Self::Path(ref path) => path.as_str(),
Self::Json {
source, ref span, ..
} => &source[span.start..span.end],
Self::SubExpr(ref call) => call.as_str(),
}
}
fn source(&self) -> &'source str {
match *self {
Self::Path(ref path) => path.source(),
Self::Json { source, .. } => source,
Self::SubExpr(ref call) => call.source(),
}
}
}
impl<'source> Lines for ParameterValue<'source> {
fn lines(&self) -> &Range<usize> {
match *self {
ParameterValue::Path(ref path) => path.lines(),
ParameterValue::Json { ref line, .. } => line,
ParameterValue::SubExpr(ref call) => call.lines(),
}
}
fn lines_mut(&mut self) -> &mut Range<usize> {
match *self {
ParameterValue::Path(ref mut path) => path.lines_mut(),
ParameterValue::Json { ref mut line, .. } => line,
ParameterValue::SubExpr(ref mut call) => call.lines_mut(),
}
}
}
impl fmt::Display for ParameterValue<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum CallTarget<'source> {
Path(Path<'source>),
SubExpr(Box<Call<'source>>),
}
impl<'source> CallTarget<'source> {
pub fn is_empty(&self) -> bool {
match *self {
Self::Path(ref path) => path.is_empty(),
Self::SubExpr(ref call) => call.is_empty(),
}
}
pub fn span(&self) -> &Range<usize> {
match *self {
Self::Path(ref path) => path.span(),
Self::SubExpr(ref call) => call.open_span(),
}
}
}
impl<'source> Slice<'source> for CallTarget<'source> {
fn as_str(&self) -> &'source str {
match *self {
Self::Path(ref path) => path.as_str(),
Self::SubExpr(ref call) => call.as_str(),
}
}
fn source(&self) -> &'source str {
match *self {
Self::Path(ref path) => path.source(),
Self::SubExpr(ref call) => call.source(),
}
}
}
impl<'source> Lines for CallTarget<'source> {
fn lines(&self) -> &Range<usize> {
match *self {
Self::Path(ref path) => path.lines(),
Self::SubExpr(ref call) => call.lines(),
}
}
fn lines_mut(&mut self) -> &mut Range<usize> {
match *self {
Self::Path(ref mut path) => path.lines_mut(),
Self::SubExpr(ref mut call) => call.lines_mut(),
}
}
}
impl fmt::Display for CallTarget<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl Default for CallTarget<'_> {
fn default() -> Self {
CallTarget::Path(Path::new("", 0..0, 0..0))
}
}
#[derive(Default, Eq, PartialEq)]
pub struct Call<'source> {
source: &'source str,
partial: bool,
conditional: bool,
open: Range<usize>,
close: Option<Range<usize>>,
target: CallTarget<'source>,
arguments: Vec<ParameterValue<'source>>,
parameters: HashMap<&'source str, ParameterValue<'source>>,
line: Range<usize>,
}
impl<'source> Call<'source> {
pub fn new(
source: &'source str,
open: Range<usize>,
line: Range<usize>,
) -> Self {
Self {
source,
partial: false,
conditional: false,
open,
close: None,
target: CallTarget::Path(Path::new(source, 0..0, 0..0)),
arguments: Vec::new(),
parameters: HashMap::new(),
line,
}
}
pub fn is_empty(&self) -> bool {
self.target.is_empty()
}
pub fn target(&self) -> &CallTarget<'source> {
&self.target
}
pub fn has_target(&self) -> bool {
self.target.as_str() != ""
}
pub fn set_target(&mut self, target: CallTarget<'source>) {
self.target = target;
}
pub fn add_argument(&mut self, arg: ParameterValue<'source>) {
self.arguments.push(arg);
}
pub fn arguments(&self) -> &Vec<ParameterValue<'source>> {
&self.arguments
}
pub fn add_parameter(
&mut self,
key: &'source str,
val: ParameterValue<'source>,
) {
self.parameters.insert(key, val);
}
pub fn parameters(
&self,
) -> &HashMap<&'source str, ParameterValue<'source>> {
&self.parameters
}
pub fn is_partial(&self) -> bool {
self.partial
}
pub fn set_partial(&mut self, partial: bool) {
self.partial = partial;
}
pub fn is_conditional(&self) -> bool {
self.conditional
}
pub fn set_conditional(&mut self, conditional: bool) {
self.conditional = conditional;
}
pub fn is_escaped(&self) -> bool {
!self.open().starts_with("{{{")
}
fn trim_before(&self) -> bool {
self.open().ends_with(WHITESPACE)
}
fn trim_after(&self) -> bool {
self.close().starts_with(WHITESPACE)
}
}
impl<'source> Slice<'source> for Call<'source> {
fn as_str(&self) -> &'source str {
if let Some(ref close) = self.close {
return &self.source[self.open.start..close.end];
}
&self.source[self.open.start..self.open.end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl<'source> Lines for Call<'source> {
fn lines(&self) -> &Range<usize> {
&self.line
}
fn lines_mut(&mut self) -> &mut Range<usize> {
&mut self.line
}
}
impl<'source> Element<'source> for Call<'source> {
fn open(&self) -> &'source str {
&self.source[self.open.start..self.open.end]
}
fn close(&self) -> &'source str {
if let Some(ref close) = self.close {
return &self.source[close.start..close.end];
}
""
}
fn open_span(&self) -> &Range<usize> {
&self.open
}
fn close_span(&self) -> &Option<Range<usize>> {
&self.close
}
fn is_closed(&self) -> bool {
self.close.is_some()
}
fn exit(&mut self, close: Range<usize>) {
self.close = Some(close);
}
}
impl fmt::Display for Call<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for Call<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Call")
.field("source", &self.as_str())
.field("partial", &self.partial)
.field("open", &self.open)
.field("close", &self.close)
.field("target", &self.target)
.field("arguments", &self.arguments)
.field("parameters", &self.parameters)
.finish()
}
}
#[derive(Eq, PartialEq)]
pub struct Document<'source>(pub &'source str, pub Vec<Node<'source>>);
impl<'source> Document<'source> {
pub fn nodes(&self) -> &Vec<Node<'source>> {
&self.1
}
pub fn nodes_mut(&mut self) -> &mut Vec<Node<'source>> {
&mut self.1
}
}
impl<'source> Slice<'source> for Document<'source> {
fn as_str(&self) -> &'source str {
self.0
}
fn source(&self) -> &'source str {
self.0
}
}
impl fmt::Display for Document<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for Document<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Document").field("nodes", &self.1).finish()
}
}
#[derive(Eq, PartialEq)]
pub struct Block<'source> {
source: &'source str,
nodes: Vec<Node<'source>>,
raw: bool,
open: Range<usize>,
close: Option<Range<usize>>,
call: Call<'source>,
conditionals: Vec<Node<'source>>,
line: Range<usize>,
}
impl<'source> Block<'source> {
pub fn new(
source: &'source str,
open: Range<usize>,
raw: bool,
line: Range<usize>,
) -> Self {
Self {
source,
nodes: Vec::new(),
raw,
open,
close: None,
call: Default::default(),
conditionals: Vec::new(),
line,
}
}
pub fn call(&self) -> &Call<'source> {
&self.call
}
pub fn set_call(&mut self, call: Call<'source>) {
self.call = call;
}
pub fn name(&self) -> Option<&'source str> {
match self.call.target() {
CallTarget::Path(ref path) => {
if path.is_simple() {
let id = path.components().first().unwrap();
Some(id.as_str())
} else {
None
}
}
CallTarget::SubExpr(_) => None,
}
}
pub fn is_raw(&self) -> bool {
self.raw
}
pub fn add_condition(&mut self, condition: Block<'source>) {
self.close_condition(condition.call.open.clone());
self.conditionals.push(Node::Block(condition));
}
pub fn conditions(&self) -> &Vec<Node<'source>> {
&self.conditionals
}
pub fn push(&mut self, node: Node<'source>) {
if !self.conditionals.is_empty() {
let mut last = self.conditionals.last_mut().unwrap();
match &mut last {
Node::Block(ref mut condition) => {
condition.nodes.push(node);
}
_ => {}
}
} else {
self.nodes.push(node);
}
}
pub fn nodes(&self) -> &'source Vec<Node> {
&self.nodes
}
pub fn trim_close(&self) -> TrimHint {
TrimHint {
before: self.trim_before_close(),
after: self.trim_after_close(),
}
}
fn close_condition(&mut self, span: Range<usize>) {
if !self.conditionals.is_empty() {
if span.start > 0 {
let close = span.start - 1..span.start;
let mut last = self.conditionals.last_mut().unwrap();
match &mut last {
Node::Block(ref mut condition) => {
condition.close = Some(close);
}
_ => {}
}
}
}
}
fn trim_before(&self) -> bool {
let open = self.open();
if self.is_raw() {
open.len() > 4 && WHITESPACE == &open[4..5]
} else {
open.len() > 2 && WHITESPACE == &open[2..3]
}
}
fn trim_after(&self) -> bool {
self.call.trim_after()
}
fn trim_before_close(&self) -> bool {
let close = self.close();
if self.is_raw() {
close.len() > 4 && WHITESPACE == &close[4..5]
} else {
close.len() > 2 && WHITESPACE == &close[2..3]
}
}
fn trim_after_close(&self) -> bool {
let close = self.close();
if self.is_raw() {
if close.len() > 5 {
let index = close.len() - 5;
close.len() > 4 && WHITESPACE == &close[index..index + 1]
} else {
false
}
} else {
if close.len() > 3 {
let index = close.len() - 3;
close.len() > 2 && WHITESPACE == &close[index..index + 1]
} else {
false
}
}
}
}
impl<'source> Slice<'source> for Block<'source> {
fn as_str(&self) -> &'source str {
let close = self.close.clone().unwrap_or(0..self.source.len());
&self.source[self.open.start..close.end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl<'source> Lines for Block<'source> {
fn lines(&self) -> &Range<usize> {
&self.line
}
fn lines_mut(&mut self) -> &mut Range<usize> {
&mut self.line
}
}
impl<'source> Element<'source> for Block<'source> {
fn open(&self) -> &'source str {
&self.source[self.open.start..self.open.end]
}
fn close(&self) -> &'source str {
if let Some(ref close) = self.close {
&self.source[close.start..close.end]
} else {
""
}
}
fn open_span(&self) -> &Range<usize> {
&self.open
}
fn close_span(&self) -> &Option<Range<usize>> {
&self.close
}
fn is_closed(&self) -> bool {
self.close.is_some()
}
fn exit(&mut self, span: Range<usize>) {
if !self.conditionals.is_empty() {
let mut last = self.conditionals.last_mut().unwrap();
match &mut last {
Node::Block(ref mut condition) => {
condition.close = Some(span.clone());
}
_ => {}
}
}
self.close = Some(span);
}
}
impl fmt::Display for Block<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for t in self.nodes() {
t.fmt(f)?;
}
Ok(())
}
}
impl fmt::Debug for Block<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Block")
.field("line", &self.line)
.field("open", &self.open)
.field("close", &self.close)
.field("call", &self.call)
.field("nodes", &self.nodes)
.finish()
}
}
#[derive(Eq, PartialEq)]
pub struct Link<'source> {
source: &'source str,
open: Range<usize>,
close: Option<Range<usize>>,
line: Range<usize>,
href_span: Range<usize>,
label_span: Range<usize>,
title_span: Range<usize>,
href: Option<String>,
label: Option<String>,
title: Option<String>,
}
impl<'source> Link<'source> {
pub fn new(
source: &'source str,
open: Range<usize>,
line: Range<usize>,
) -> Self {
Self {
source,
href_span: open.end..open.end,
label_span: open.end..open.end,
title_span: open.end..open.end,
open,
line,
close: None,
href: None,
label: None,
title: None,
}
}
pub fn href(&self) -> &str {
if let Some(ref href) = self.href {
return href;
}
&self.source[self.href_span.start..self.href_span.end]
}
pub fn label(&self) -> &str {
let lbl = if let Some(ref label) = self.label {
return label;
} else {
&self.source[self.label_span.start..self.label_span.end]
};
lbl
}
pub fn title(&self) -> &str {
let title = if let Some(ref title) = self.title {
return title;
} else {
&self.source[self.title_span.start..self.title_span.end]
};
title
}
pub fn href_span(&self) -> &Range<usize> {
&self.href_span
}
pub fn label_span(&self) -> &Range<usize> {
&self.label_span
}
pub fn title_span(&self) -> &Range<usize> {
&self.title_span
}
pub fn href_end(&mut self, end: usize) {
self.href_span.end = end;
}
pub fn label_start(&mut self, start: usize) {
self.label_span.start = start;
}
pub fn label_end(&mut self, end: usize) {
self.label_span.end = end;
}
pub fn title_start(&mut self, start: usize) {
self.title_span.start = start;
}
pub fn title_end(&mut self, end: usize) {
self.title_span.end = end;
}
pub fn set_href(&mut self, value: String) {
self.href = Some(value);
}
pub fn set_label(&mut self, value: String) {
self.label = Some(value);
}
pub fn set_title(&mut self, value: String) {
self.title = Some(value);
}
pub fn is_escaped(&self) -> bool {
self.open().starts_with("\\")
}
pub(crate) fn after_escape(&self) -> &'source str {
let close = self.close.clone().unwrap_or(0..self.open.len());
&self.source[self.open.start + 1..close.end]
}
}
impl<'source> Slice<'source> for Link<'source> {
fn as_str(&self) -> &'source str {
let close = self.close.clone().unwrap_or(0..self.open.len());
&self.source[self.open.start..close.end]
}
fn source(&self) -> &'source str {
self.source
}
}
impl<'source> Lines for Link<'source> {
fn lines(&self) -> &Range<usize> {
&self.line
}
fn lines_mut(&mut self) -> &mut Range<usize> {
&mut self.line
}
}
impl<'source> Element<'source> for Link<'source> {
fn open(&self) -> &'source str {
&self.source[self.open.start..self.open.end]
}
fn close(&self) -> &'source str {
if let Some(ref close) = self.close {
&self.source[close.start..close.end]
} else {
""
}
}
fn open_span(&self) -> &Range<usize> {
&self.open
}
fn close_span(&self) -> &Option<Range<usize>> {
&self.close
}
fn is_closed(&self) -> bool {
self.close.is_some()
}
fn exit(&mut self, span: Range<usize>) {
self.close = Some(span);
}
}
impl fmt::Display for Link<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for Link<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Link")
.field("open", &self.open)
.field("close", &self.close)
.field("href", &self.href)
.field("label", &self.label)
.finish()
}
}