use zenith_core::{Diagnostic, Document, Node};
use super::super::{node_id_of, record_affected};
#[derive(Copy, Clone)]
pub(in crate::engine) enum ReorderKind {
Forward,
Backward,
ToFront,
ToBack,
}
enum MoveOutcome {
NotFound,
NoChange,
Moved,
}
pub(in crate::engine) fn apply_reorder(
node_id: &str,
kind: ReorderKind,
doc: &mut Document,
diagnostics: &mut Vec<Diagnostic>,
affected: &mut Vec<String>,
) {
for page in doc.body.pages.iter_mut() {
match reorder_in(&mut page.children, node_id, kind) {
MoveOutcome::NotFound => {
}
MoveOutcome::Moved => {
record_affected(node_id, affected);
return;
}
MoveOutcome::NoChange => {
let msg = match kind {
ReorderKind::Forward | ReorderKind::ToFront => {
format!("node {:?} is already at the front of its parent", node_id)
}
ReorderKind::Backward | ReorderKind::ToBack => {
format!("node {:?} is already at the back of its parent", node_id)
}
};
diagnostics.push(Diagnostic::advisory(
"tx.noop",
msg,
None,
Some(node_id.to_owned()),
));
return;
}
}
}
diagnostics.push(Diagnostic::error(
"tx.unknown_node",
format!("node {:?} not found in document", node_id),
None,
Some(node_id.to_owned()),
));
}
fn reorder_in(children: &mut [Node], id: &str, kind: ReorderKind) -> MoveOutcome {
if let Some(i) = children.iter().position(|n| node_id_of(n) == Some(id)) {
let len = children.len();
match kind {
ReorderKind::Forward => {
if i + 1 >= len {
return MoveOutcome::NoChange;
}
children.swap(i, i + 1);
}
ReorderKind::Backward => {
if i == 0 {
return MoveOutcome::NoChange;
}
children.swap(i, i - 1);
}
ReorderKind::ToFront => {
if i + 1 >= len {
return MoveOutcome::NoChange;
}
children[i..].rotate_left(1);
}
ReorderKind::ToBack => {
if i == 0 {
return MoveOutcome::NoChange;
}
children[..=i].rotate_right(1);
}
}
return MoveOutcome::Moved;
}
for child in children.iter_mut() {
match child {
Node::Frame(f) => match reorder_in(&mut f.children, id, kind) {
MoveOutcome::NotFound => {}
other @ (MoveOutcome::NoChange | MoveOutcome::Moved) => return other,
},
Node::Group(g) => match reorder_in(&mut g.children, id, kind) {
MoveOutcome::NotFound => {}
other @ (MoveOutcome::NoChange | MoveOutcome::Moved) => return other,
},
Node::Table(t) => {
for row in &mut t.rows {
for cell in &mut row.cells {
match reorder_in(&mut cell.children, id, kind) {
MoveOutcome::NotFound => {}
other @ (MoveOutcome::NoChange | MoveOutcome::Moved) => return other,
}
}
}
}
Node::Unknown(u) => match reorder_in(&mut u.children, id, kind) {
MoveOutcome::NotFound => {}
other @ (MoveOutcome::NoChange | MoveOutcome::Moved) => return other,
},
Node::Rect(_)
| Node::Ellipse(_)
| Node::Line(_)
| Node::Text(_)
| Node::Code(_)
| Node::Image(_)
| Node::Polygon(_)
| Node::Polyline(_)
| Node::Instance(_)
| Node::Field(_)
| Node::Footnote(_)
| Node::Toc(_)
| Node::Shape(_)
| Node::Connector(_)
| Node::Pattern(_)
| Node::Chart(_)
| Node::Light(_)
| Node::Mesh(_) => {}
}
}
MoveOutcome::NotFound
}