use crate::Result;
pub const DEFAULT_INDENT: usize = 4;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Sequence {
Initial,
SelfClosing,
Opening,
Closing,
Text,
LineFeed,
}
#[derive(Debug, Clone)]
pub struct TagSequence(pub Sequence, pub String);
impl<'s> TagSequence {
pub fn self_closing(tag: &'s str) -> TagSequence {
TagSequence(Sequence::SelfClosing, tag.to_string())
}
pub fn opening(tag: &'s str) -> TagSequence {
TagSequence(Sequence::Opening, tag.to_string())
}
pub fn closing(tag: &'s str) -> TagSequence {
TagSequence(Sequence::Closing, tag.to_string())
}
pub fn text() -> TagSequence {
TagSequence(Sequence::Text, String::new())
}
pub fn linefeed() -> TagSequence {
TagSequence(Sequence::LineFeed, String::new())
}
pub fn initial() -> TagSequence {
TagSequence(Sequence::Initial, String::new())
}
pub fn from(seq: &Sequence, tag: &'s str) -> TagSequence {
match seq {
Sequence::SelfClosing | Sequence::Opening | Sequence::Closing => {
TagSequence(seq.clone(), tag.to_string())
}
_ => TagSequence(seq.clone(), String::new()),
}
}
}
#[derive(Debug)]
pub struct SequenceState {
pub tag_stack: Vec<String>,
pub last: TagSequence,
pub next: TagSequence,
pub indent: usize,
}
impl SequenceState {
pub fn new() -> SequenceState {
SequenceState {
tag_stack: Vec::new(),
last: TagSequence::initial(),
next: TagSequence::text(),
indent: 0,
}
}
#[cfg(test)]
pub(crate) fn teststate(last: TagSequence, next: TagSequence) -> SequenceState {
SequenceState {
tag_stack: Vec::new(),
last,
next,
indent: DEFAULT_INDENT,
}
}
#[cfg(test)]
pub(crate) fn initial_open(next: &str) -> SequenceState {
Self::teststate(TagSequence::initial(), TagSequence::opening(next))
}
#[cfg(test)]
pub(crate) fn open_open(last: &str, next: &str) -> SequenceState {
Self::teststate(TagSequence::opening(last), TagSequence::opening(next))
}
#[cfg(test)]
pub(crate) fn open_close(last: &str, next: &str) -> SequenceState {
Self::teststate(TagSequence::opening(last), TagSequence::closing(next))
}
#[cfg(test)]
pub(crate) fn open_text(last: &str) -> SequenceState {
Self::teststate(TagSequence::opening(last), TagSequence::text())
}
#[cfg(test)]
pub(crate) fn open_lf(last: &str) -> SequenceState {
Self::teststate(TagSequence::opening(last), TagSequence::linefeed())
}
#[cfg(test)]
pub(crate) fn open_self_closing(last: &str, next: &str) -> SequenceState {
Self::teststate(TagSequence::opening(last), TagSequence::self_closing(next))
}
#[cfg(test)]
pub(crate) fn close_close(last: &str, next: &str) -> SequenceState {
Self::teststate(TagSequence::closing(last), TagSequence::closing(next))
}
#[cfg(test)]
pub(crate) fn close_text(last: &str) -> SequenceState {
Self::teststate(TagSequence::closing(last), TagSequence::text())
}
#[cfg(test)]
pub(crate) fn lf_self_closing(next: &str) -> SequenceState {
Self::teststate(TagSequence::linefeed(), TagSequence::self_closing(next))
}
#[cfg(test)]
pub(crate) fn self_closing_close(last: &str, next: &str) -> SequenceState {
Self::teststate(TagSequence::self_closing(last), TagSequence::closing(next))
}
#[cfg(test)]
pub(crate) fn text_close(last: &str) -> SequenceState {
Self::teststate(TagSequence::text(), TagSequence::closing(last))
}
}
impl Default for SequenceState {
fn default() -> SequenceState {
SequenceState::new()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FormatChanges {
pub new_line: bool,
pub new_indent: Option<usize>,
}
impl FormatChanges {
pub fn nothing() -> FormatChanges {
FormatChanges {
new_line: false,
new_indent: None,
}
}
pub fn lf() -> FormatChanges {
FormatChanges {
new_line: true,
new_indent: None,
}
}
pub fn may_lf(new_line: bool) -> FormatChanges {
FormatChanges {
new_line,
new_indent: None,
}
}
pub fn indent_more(indent: usize, step: usize) -> FormatChanges {
FormatChanges {
new_line: true,
new_indent: Some(indent + step),
}
}
pub fn indent_less(indent: usize, step: usize) -> FormatChanges {
let new_indent = if step > indent {
Some(0)
} else {
Some(indent - step)
};
FormatChanges {
new_line: true,
new_indent,
}
}
}
pub trait Formatter: std::fmt::Debug {
fn new() -> Self
where
Self: Sized;
fn set_indent_step_size(&mut self, _step_size: usize) {}
fn get_indent_step_size(&self) -> usize {
DEFAULT_INDENT
}
fn optional_fixed_ruleset(&mut self) -> Option<&mut dyn FixedRuleset> {
None
}
fn reset_to_defaults(&mut self) {}
fn check(&mut self, state: &SequenceState) -> FormatChanges;
}
#[derive(Copy, Clone, Debug)]
pub enum FixedRule {
IndentAlways,
LfAlways,
LfClosing,
}
pub trait FixedRuleset: Formatter {
fn add_tags_to_rule(&mut self, tags: &[&str], rule: FixedRule) -> Result<()>;
fn reset_ruleset(&mut self) -> Result<()>;
}