use ra_ap_syntax::{AstToken, SyntaxElement, TextRange, TextSize};
pub use name::MetaName;
pub use option::MetaOption;
pub use separator::MetaSeparator;
pub use value::MetaValue;
mod name;
mod option;
mod separator;
mod value;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MetaNameValue {
name: MetaOption<MetaName>,
eq: Option<MetaSeparator>,
value: MetaOption<MetaValue>,
offset: TextSize,
}
impl MetaNameValue {
pub fn new(
name: MetaOption<MetaName>,
eq: Option<MetaSeparator>,
value: MetaOption<MetaValue>,
offset: TextSize,
) -> Self {
Self {
name,
eq,
value,
offset,
}
}
pub fn empty(offset: TextSize) -> Self {
Self::new(MetaOption::None, None, MetaOption::None, offset)
}
pub fn is_empty(&self) -> bool {
self.name.is_none() && self.eq.is_none() && self.value.is_none()
}
pub fn name(&self) -> &MetaOption<MetaName> {
&self.name
}
pub fn eq(&self) -> &Option<MetaSeparator> {
&self.eq
}
pub fn value(&self) -> &MetaOption<MetaValue> {
&self.value
}
pub fn text_range(&self) -> TextRange {
let mut start: Option<TextSize> = None;
let mut end: Option<TextSize> = None;
let mut update_start_and_end = |range: TextRange| {
if start.is_none() {
start = Some(range.start());
}
end = Some(range.end());
};
let get_items_text_range = |items: &[SyntaxElement]| -> Option<TextRange> {
Some(TextRange::new(
items.first()?.text_range().start(),
items.last()?.text_range().end(),
))
};
match &self.name {
MetaOption::Ok(meta_name) => {
update_start_and_end(meta_name.syntax().text_range());
}
MetaOption::Err(items) => {
if let Some(range) = get_items_text_range(items) {
update_start_and_end(range);
}
}
_ => (),
}
if let Some(token) = &self.eq {
update_start_and_end(token.syntax().text_range());
}
match &self.value {
MetaOption::Ok(meta_value) => {
update_start_and_end(meta_value.text_range());
}
MetaOption::Err(items) => {
if let Some(range) = get_items_text_range(items) {
update_start_and_end(range);
}
}
_ => (),
}
TextRange::new(
start.unwrap_or(self.offset),
end.unwrap_or(self.offset + TextSize::from(1)),
)
}
}