use crate::prelude::*;
use beet_core::prelude::*;
use bevy::ecs::system::SystemParam;
pub type RootComponents = (
SnippetRoot,
BeetRoot,
StaticRoot,
InstanceRoot,
ExprIdx,
DomIdx,
RequiresDomIdx,
);
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Reflect, Component)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
#[reflect(Component)]
pub struct BeetRoot;
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Reflect, Component)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
#[reflect(Component)]
#[require(FragmentNode)]
pub struct SnippetRoot {
pub file: WsPathBuf,
pub start: LineCol,
}
impl std::fmt::Display for SnippetRoot {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.file, self.start)
}
}
impl SnippetRoot {
pub fn new(file: WsPathBuf, start: LineCol) -> Self { Self { file, start } }
pub fn new_file_line_col(file: &str, line: u32, col: u32) -> Self {
Self {
file: WsPathBuf::new(file),
start: LineCol::new(line, col),
}
}
#[cfg(feature = "tokens")]
pub fn new_from_tokens(
file: WsPathBuf,
token: &proc_macro2::TokenStream,
) -> Self {
use syn::spanned::Spanned;
Self {
file,
start: token.span().start().into(),
}
}
}
#[derive(
Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Component, Reflect,
)]
#[reflect(Default, Component)]
#[require(SnippetRoot)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
pub struct StaticRoot;
#[derive(
Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Component, Reflect,
)]
#[reflect(Default, Component)]
#[require(SnippetRoot)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
pub struct InstanceRoot;
#[derive(SystemParam)]
pub struct NodeLocation<'w, 's> {
parents: Query<'w, 's, &'static ChildOf>,
roots: Query<'w, 's, &'static SnippetRoot>,
}
impl NodeLocation<'_, '_> {
pub fn get_snippet_root(&self, entity: Entity) -> Option<&SnippetRoot> {
self.parents
.iter_ancestors_inclusive(entity)
.find_map(|e| self.roots.get(e).ok())
}
pub fn stringify(&self, entity: Entity) -> String {
self.get_snippet_root(entity)
.map(|idx| idx.to_string())
.unwrap_or_else(|| format!("Entity without location: {entity:?}"))
}
}