Add support for diffing description lists.
This commit is contained in:
@@ -182,6 +182,23 @@ impl<'s> DiffResult<'s> {
|
||||
}
|
||||
}
|
||||
|
||||
fn artificial_diff_scope<'s>(
|
||||
name: String,
|
||||
message: Option<String>,
|
||||
children: Vec<DiffResult<'s>>,
|
||||
emacs_token: &'s Token<'s>,
|
||||
rust_source: &'s str,
|
||||
) -> Result<DiffResult<'s>, Box<dyn std::error::Error>> {
|
||||
Ok(DiffResult {
|
||||
status: DiffStatus::Good,
|
||||
name,
|
||||
message,
|
||||
children,
|
||||
rust_source,
|
||||
emacs_token,
|
||||
})
|
||||
}
|
||||
|
||||
fn compare_element<'s>(
|
||||
source: &'s str,
|
||||
emacs: &'s Token<'s>,
|
||||
@@ -385,18 +402,10 @@ fn compare_heading<'s>(
|
||||
}
|
||||
|
||||
// Compare todo-keyword
|
||||
let todo_keyword = {
|
||||
let children = emacs.as_list()?;
|
||||
let attributes_child = children
|
||||
.iter()
|
||||
.nth(1)
|
||||
.ok_or("Should have an attributes child.")?;
|
||||
let attributes_map = attributes_child.as_map()?;
|
||||
let todo_keyword = attributes_map
|
||||
.get(":todo-keyword")
|
||||
.ok_or("Missing :todo-keyword attribute.");
|
||||
todo_keyword?.as_atom()?
|
||||
};
|
||||
let todo_keyword = get_property(emacs, ":todo-keyword")?
|
||||
.map(Token::as_atom)
|
||||
.map_or(Ok(None), |r| r.map(Some))?
|
||||
.unwrap_or("nil");
|
||||
match (todo_keyword, rust.todo_keyword, unquote(todo_keyword)) {
|
||||
("nil", None, _) => {}
|
||||
(_, Some(rust_todo), Ok(emacs_todo)) if emacs_todo == rust_todo => {}
|
||||
@@ -410,18 +419,7 @@ fn compare_heading<'s>(
|
||||
};
|
||||
|
||||
// Compare title
|
||||
let title = {
|
||||
let children = emacs.as_list()?;
|
||||
let attributes_child = children
|
||||
.iter()
|
||||
.nth(1)
|
||||
.ok_or("Should have an attributes child.")?;
|
||||
let attributes_map = attributes_child.as_map()?;
|
||||
let title = attributes_map
|
||||
.get(":title")
|
||||
.ok_or("Missing :title attribute.");
|
||||
*title?
|
||||
};
|
||||
let title = get_property(emacs, ":title")?.ok_or("Missing :title attribute.")?;
|
||||
for (emacs_child, rust_child) in title.as_list()?.iter().zip(rust.title.iter()) {
|
||||
child_status.push(compare_object(source, emacs_child, rust_child)?);
|
||||
}
|
||||
@@ -453,19 +451,12 @@ fn compare_heading<'s>(
|
||||
fn get_tags_from_heading<'s>(
|
||||
emacs: &'s Token<'s>,
|
||||
) -> Result<HashSet<String>, Box<dyn std::error::Error>> {
|
||||
let children = emacs.as_list()?;
|
||||
let attributes_child = children
|
||||
.iter()
|
||||
.nth(1)
|
||||
.ok_or("Should have an attributes child.")?;
|
||||
let attributes_map = attributes_child.as_map()?;
|
||||
let tags = attributes_map
|
||||
.get(":tags")
|
||||
.ok_or("Missing :tags attribute.")?;
|
||||
let tags = match get_property(emacs, ":tags")? {
|
||||
Some(prop) => prop,
|
||||
None => return Ok(HashSet::new()),
|
||||
};
|
||||
|
||||
match tags.as_atom() {
|
||||
Ok("nil") => {
|
||||
return Ok(HashSet::new());
|
||||
}
|
||||
Ok(val) => panic!("Unexpected value for tags: {:?}", val),
|
||||
Err(_) => {}
|
||||
};
|
||||
@@ -483,6 +474,26 @@ fn get_tags_from_heading<'s>(
|
||||
Ok(tags)
|
||||
}
|
||||
|
||||
fn get_property<'s, 'x>(
|
||||
emacs: &'s Token<'s>,
|
||||
key: &'x str,
|
||||
) -> Result<Option<&'s Token<'s>>, Box<dyn std::error::Error>> {
|
||||
let children = emacs.as_list()?;
|
||||
let attributes_child = children
|
||||
.iter()
|
||||
.nth(1)
|
||||
.ok_or("Should have an attributes child.")?;
|
||||
let attributes_map = attributes_child.as_map()?;
|
||||
let prop = attributes_map
|
||||
.get(key)
|
||||
.ok_or(format!("Missing {} attribute.", key))?;
|
||||
match prop.as_atom() {
|
||||
Ok("nil") => return Ok(None),
|
||||
_ => {}
|
||||
};
|
||||
Ok(Some(*prop))
|
||||
}
|
||||
|
||||
fn compare_paragraph<'s>(
|
||||
source: &'s str,
|
||||
emacs: &'s Token<'s>,
|
||||
@@ -553,6 +564,7 @@ fn compare_plain_list_item<'s>(
|
||||
let children = emacs.as_list()?;
|
||||
let mut child_status = Vec::new();
|
||||
let mut this_status = DiffStatus::Good;
|
||||
let mut message = None;
|
||||
let emacs_name = "item";
|
||||
if assert_name(emacs, emacs_name).is_err() {
|
||||
this_status = DiffStatus::Bad;
|
||||
@@ -562,14 +574,50 @@ fn compare_plain_list_item<'s>(
|
||||
this_status = DiffStatus::Bad;
|
||||
}
|
||||
|
||||
for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) {
|
||||
child_status.push(compare_element(source, emacs_child, rust_child)?);
|
||||
}
|
||||
// Compare tag
|
||||
let tag = get_property(emacs, ":tag")?;
|
||||
match (tag, rust.tag.is_empty()) {
|
||||
(None, true) => {}
|
||||
(None, false) | (Some(_), true) => {
|
||||
this_status = DiffStatus::Bad;
|
||||
message = Some("Mismatched tags".to_owned());
|
||||
}
|
||||
(Some(tag), false) => {
|
||||
let tag_status = tag
|
||||
.as_list()?
|
||||
.iter()
|
||||
.zip(rust.tag.iter())
|
||||
.map(|(emacs_child, rust_child)| compare_object(source, emacs_child, rust_child))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
child_status.push(artificial_diff_scope(
|
||||
"tag".to_owned(),
|
||||
None,
|
||||
tag_status,
|
||||
tag,
|
||||
rust.get_source(),
|
||||
)?);
|
||||
}
|
||||
};
|
||||
|
||||
// Compare contents
|
||||
let contents_status = children
|
||||
.iter()
|
||||
.skip(2)
|
||||
.zip(rust.children.iter())
|
||||
.map(|(emacs_child, rust_child)| compare_element(source, emacs_child, rust_child))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
child_status.push(artificial_diff_scope(
|
||||
"contents".to_owned(),
|
||||
None,
|
||||
contents_status,
|
||||
emacs,
|
||||
rust.get_source(),
|
||||
)?);
|
||||
|
||||
Ok(DiffResult {
|
||||
status: this_status,
|
||||
name: emacs_name.to_owned(),
|
||||
message: None,
|
||||
message,
|
||||
children: child_status,
|
||||
rust_source: rust.get_source(),
|
||||
emacs_token: emacs,
|
||||
@@ -1167,6 +1215,7 @@ fn compare_plain_text<'s>(
|
||||
) -> Result<DiffResult<'s>, Box<dyn std::error::Error>> {
|
||||
let mut this_status = DiffStatus::Good;
|
||||
let mut message = None;
|
||||
let rust_source = rust.get_source();
|
||||
let text = emacs.as_text()?;
|
||||
let start_ind: usize = text
|
||||
.properties
|
||||
@@ -1181,20 +1230,20 @@ fn compare_plain_text<'s>(
|
||||
.as_atom()?
|
||||
.parse()?;
|
||||
let emacs_text_length = end_ind - start_ind;
|
||||
if rust.source.len() != emacs_text_length {
|
||||
if rust_source.len() != emacs_text_length {
|
||||
this_status = DiffStatus::Bad;
|
||||
message = Some(format!(
|
||||
"(emacs len != rust len) {:?} != {:?}",
|
||||
emacs_text_length,
|
||||
rust.source.len()
|
||||
rust_source.len()
|
||||
));
|
||||
}
|
||||
let unquoted_text = unquote(text.text)?;
|
||||
if unquoted_text != rust.source {
|
||||
if unquoted_text != rust_source {
|
||||
this_status = DiffStatus::Bad;
|
||||
message = Some(format!(
|
||||
"(emacs != rust) {:?} != {:?}",
|
||||
unquoted_text, rust.source
|
||||
unquoted_text, rust_source
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1203,7 +1252,7 @@ fn compare_plain_text<'s>(
|
||||
name: "plain-text".to_owned(),
|
||||
message,
|
||||
children: Vec::new(),
|
||||
rust_source: rust.get_source(),
|
||||
rust_source,
|
||||
emacs_token: emacs,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user