Add node introspection API
Closes #1110 Test Plan: query the introspectNode Endpoint from js Reviewers: Pull Request: https://github.com/GraphiteEditor/Graphite/pull/1183
This commit is contained in:
parent
0af42ee6f9
commit
bea7cc8dd0
|
|
@ -8,12 +8,12 @@ use graphene_core::text::Font;
|
||||||
pub struct Dispatcher {
|
pub struct Dispatcher {
|
||||||
message_queues: Vec<VecDeque<Message>>,
|
message_queues: Vec<VecDeque<Message>>,
|
||||||
pub responses: Vec<FrontendMessage>,
|
pub responses: Vec<FrontendMessage>,
|
||||||
message_handlers: DispatcherMessageHandlers,
|
pub message_handlers: DispatcherMessageHandlers,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[remain::sorted]
|
#[remain::sorted]
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct DispatcherMessageHandlers {
|
pub struct DispatcherMessageHandlers {
|
||||||
broadcast_message_handler: BroadcastMessageHandler,
|
broadcast_message_handler: BroadcastMessageHandler,
|
||||||
debug_message_handler: DebugMessageHandler,
|
debug_message_handler: DebugMessageHandler,
|
||||||
dialog_message_handler: DialogMessageHandler,
|
dialog_message_handler: DialogMessageHandler,
|
||||||
|
|
@ -21,7 +21,7 @@ struct DispatcherMessageHandlers {
|
||||||
input_preprocessor_message_handler: InputPreprocessorMessageHandler,
|
input_preprocessor_message_handler: InputPreprocessorMessageHandler,
|
||||||
key_mapping_message_handler: KeyMappingMessageHandler,
|
key_mapping_message_handler: KeyMappingMessageHandler,
|
||||||
layout_message_handler: LayoutMessageHandler,
|
layout_message_handler: LayoutMessageHandler,
|
||||||
portfolio_message_handler: PortfolioMessageHandler,
|
pub portfolio_message_handler: PortfolioMessageHandler,
|
||||||
preferences_message_handler: PreferencesMessageHandler,
|
preferences_message_handler: PreferencesMessageHandler,
|
||||||
tool_message_handler: ToolMessageHandler,
|
tool_message_handler: ToolMessageHandler,
|
||||||
workspace_message_handler: WorkspaceMessageHandler,
|
workspace_message_handler: WorkspaceMessageHandler,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ use document_legacy::layers::layer_info::LayerDataType;
|
||||||
use document_legacy::layers::style::RenderData;
|
use document_legacy::layers::style::RenderData;
|
||||||
use document_legacy::Operation as DocumentOperation;
|
use document_legacy::Operation as DocumentOperation;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::NodeInput;
|
use graph_craft::document::{NodeId, NodeInput};
|
||||||
use graphene_core::raster::Image;
|
use graphene_core::raster::Image;
|
||||||
use graphene_core::text::Font;
|
use graphene_core::text::Font;
|
||||||
|
|
||||||
|
|
@ -606,6 +606,10 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PortfolioMessageHandler {
|
impl PortfolioMessageHandler {
|
||||||
|
pub fn introspect_node(&self, node_path: &[NodeId]) -> Option<String> {
|
||||||
|
self.executor.introspect_node(node_path)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn document(&self, document_id: u64) -> Option<&DocumentMessageHandler> {
|
pub fn document(&self, document_id: u64) -> Option<&DocumentMessageHandler> {
|
||||||
self.documents.get(&document_id)
|
self.documents.get(&document_id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ impl NodeGraphExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn introspect_node(&self, path: &[NodeId]) -> Option<String> {
|
||||||
|
self.executor.introspect(path).flatten()
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes an input for a node in the graph
|
/// Computes an input for a node in the graph
|
||||||
pub fn compute_input<T: dyn_any::StaticType>(&mut self, old_network: &NodeNetwork, node_path: &[NodeId], mut input_index: usize, editor_api: Cow<EditorApi<'_>>) -> Result<T, String> {
|
pub fn compute_input<T: dyn_any::StaticType>(&mut self, old_network: &NodeNetwork, node_path: &[NodeId], mut input_index: usize, editor_api: Cow<EditorApi<'_>>) -> Result<T, String> {
|
||||||
let mut network = old_network.clone();
|
let mut network = old_network.clone();
|
||||||
|
|
|
||||||
|
|
@ -697,6 +697,25 @@ impl JsEditorHandle {
|
||||||
let message = DocumentMessage::ToggleLayerExpansion { layer_path };
|
let message = DocumentMessage::ToggleLayerExpansion { layer_path };
|
||||||
self.dispatch(message);
|
self.dispatch(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the string representation of the nodes contents
|
||||||
|
#[wasm_bindgen(js_name = introspectNode)]
|
||||||
|
pub fn introspect_node(&self, node_path: Vec<NodeId>) -> Option<String> {
|
||||||
|
let frontend_messages = EDITOR_INSTANCES.with(|instances| {
|
||||||
|
// Mutably borrow the editors, and if successful, we can access them in the closure
|
||||||
|
instances.try_borrow_mut().map(|mut editors| {
|
||||||
|
// Get the editor instance for this editor ID, then dispatch the message to the backend, and return its response `FrontendMessage` queue
|
||||||
|
editors
|
||||||
|
.get_mut(&self.editor_id)
|
||||||
|
.expect("EDITOR_INSTANCES does not contain the current editor_id")
|
||||||
|
.dispatcher
|
||||||
|
.message_handlers
|
||||||
|
.portfolio_message_handler
|
||||||
|
.introspect_node(&node_path)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
frontend_messages.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed to make JsEditorHandle functions pub to Rust.
|
// Needed to make JsEditorHandle functions pub to Rust.
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ impl ProtoNetwork {
|
||||||
let paths = self.nodes.iter().map(|(_, node)| node.document_node_path.clone()).collect::<Vec<_>>();
|
let paths = self.nodes.iter().map(|(_, node)| node.document_node_path.clone()).collect::<Vec<_>>();
|
||||||
|
|
||||||
let resolved_lookup = resolved.clone();
|
let resolved_lookup = resolved.clone();
|
||||||
if let Some((input_node, id, input, path)) = self.nodes.iter_mut().filter(|(id, _)| !resolved_lookup.contains(id)).find_map(|(id, node)| {
|
if let Some((input_node, id, input, mut path)) = self.nodes.iter_mut().filter(|(id, _)| !resolved_lookup.contains(id)).find_map(|(id, node)| {
|
||||||
if let ProtoNodeInput::Node(input_node, false) = node.input {
|
if let ProtoNodeInput::Node(input_node, false) = node.input {
|
||||||
resolved.insert(*id);
|
resolved.insert(*id);
|
||||||
let pre_node_input = inputs.get(input_node as usize).expect("input node should exist");
|
let pre_node_input = inputs.get(input_node as usize).expect("input node should exist");
|
||||||
|
|
@ -288,6 +288,7 @@ impl ProtoNetwork {
|
||||||
}) {
|
}) {
|
||||||
lookup.insert(id, compose_node_id);
|
lookup.insert(id, compose_node_id);
|
||||||
self.replace_node_references(&lookup, true);
|
self.replace_node_references(&lookup, true);
|
||||||
|
path.push(id);
|
||||||
self.nodes.push((
|
self.nodes.push((
|
||||||
compose_node_id,
|
compose_node_id,
|
||||||
ProtoNode {
|
ProtoNode {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ impl DynamicExecutor {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<String>> {
|
||||||
|
self.tree.introspect(node_path)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn input_type(&self) -> Option<Type> {
|
pub fn input_type(&self) -> Option<Type> {
|
||||||
self.typing_context.type_of(self.output).map(|node_io| node_io.input.clone())
|
self.typing_context.type_of(self.output).map(|node_io| node_io.input.clone())
|
||||||
}
|
}
|
||||||
|
|
@ -99,6 +103,7 @@ impl NodeContainer<'static> {
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct BorrowTree {
|
pub struct BorrowTree {
|
||||||
nodes: HashMap<NodeId, Arc<RwLock<NodeContainer<'static>>>>,
|
nodes: HashMap<NodeId, Arc<RwLock<NodeContainer<'static>>>>,
|
||||||
|
source_map: HashMap<Vec<NodeId>, NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowTree {
|
impl BorrowTree {
|
||||||
|
|
@ -123,6 +128,7 @@ impl BorrowTree {
|
||||||
node.reset();
|
node.reset();
|
||||||
}
|
}
|
||||||
old_nodes.remove(&id);
|
old_nodes.remove(&id);
|
||||||
|
self.source_map.retain(|_, nid| *nid != id);
|
||||||
}
|
}
|
||||||
Ok(old_nodes.into_iter().collect())
|
Ok(old_nodes.into_iter().collect())
|
||||||
}
|
}
|
||||||
|
|
@ -139,6 +145,14 @@ impl BorrowTree {
|
||||||
node
|
node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn introspect(&self, node_path: &[NodeId]) -> Option<Option<String>> {
|
||||||
|
let id = self.source_map.get(node_path)?;
|
||||||
|
let node = self.nodes.get(id)?;
|
||||||
|
let reader = node.read().unwrap();
|
||||||
|
let node = reader.node.as_ref();
|
||||||
|
Some(node.serialize())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get(&self, id: NodeId) -> Option<Arc<RwLock<NodeContainer<'static>>>> {
|
pub fn get(&self, id: NodeId) -> Option<Arc<RwLock<NodeContainer<'static>>>> {
|
||||||
self.nodes.get(&id).cloned()
|
self.nodes.get(&id).cloned()
|
||||||
}
|
}
|
||||||
|
|
@ -163,6 +177,7 @@ impl BorrowTree {
|
||||||
|
|
||||||
pub fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
|
pub fn push_node(&mut self, id: NodeId, proto_node: ProtoNode, typing_context: &TypingContext) -> Result<(), String> {
|
||||||
let ProtoNode { construction_args, identifier, .. } = proto_node;
|
let ProtoNode { construction_args, identifier, .. } = proto_node;
|
||||||
|
self.source_map.insert(proto_node.document_node_path, id);
|
||||||
|
|
||||||
match construction_args {
|
match construction_args {
|
||||||
ConstructionArgs::Value(value) => {
|
ConstructionArgs::Value(value) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue