use crate::doc::{Document, NodeDoc};
use crate::model::{MathClass, NodeId, Symbol, Tree};
use crate::ops::{SwapKind, SwapVariant};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MenuItemKind {
Delete,
Swap,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MenuItem {
pub label: String,
pub kind: MenuItemKind,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MenuView {
pub items: Vec<MenuItem>,
pub selected: usize,
pub query: String,
}
pub(crate) enum RowEffect<'a> {
Delete,
Swap(&'a SwapKind),
}
pub(crate) struct Menu {
pub(crate) anchor: NodeId,
variants: Vec<SwapVariant>,
pub(crate) query: String,
pub(crate) selected: usize,
}
impl Menu {
pub(crate) fn for_node(anchor: NodeId, variants: Vec<SwapVariant>) -> Self {
Self { anchor, variants, query: String::new(), selected: 0 }
}
fn visible_variants(&self) -> impl Iterator<Item = &SwapVariant> {
let q = self.query.to_lowercase();
self.variants.iter().filter(move |v| q.is_empty() || v.label.to_lowercase().contains(&q))
}
pub(crate) fn visible(&self) -> Vec<RowEffect<'_>> {
std::iter::once(RowEffect::Delete).chain(self.visible_variants().map(|v| RowEffect::Swap(&v.kind))).collect()
}
pub(crate) fn view(&self) -> MenuView {
let delete = MenuItem { label: "Delete".to_string(), kind: MenuItemKind::Delete };
let swaps = self.visible_variants().map(|v| MenuItem { label: v.label.clone(), kind: MenuItemKind::Swap });
MenuView { items: std::iter::once(delete).chain(swaps).collect(), selected: self.selected, query: self.query.clone() }
}
pub(crate) fn previews(&self, tree: &Tree) -> Vec<Option<Document>> {
let hollow = tree.node_to_doc(self.anchor).map(hollow);
let swaps = self.visible_variants().map(|v| hollow.as_ref().and_then(|h| preview(h, &v.kind)));
std::iter::once(None).chain(swaps).collect()
}
}
pub(crate) fn hollow(node: NodeDoc) -> NodeDoc {
let mut node = node;
for slot in node.slots_mut() {
slot.clear();
}
if let NodeDoc::Styled { content, .. } = &mut node {
content.push(NodeDoc::Atom(Symbol { latex: "A".to_string(), class: MathClass::Ord }));
}
node
}
fn preview(hollow: &NodeDoc, kind: &SwapKind) -> Option<Document> {
let mut tree = Tree::from_doc(&Document::new(vec![hollow.clone()]));
let node = *tree.items(tree.root()).first()?;
tree.apply_swap(node, kind);
Some(tree.to_doc())
}