Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/build-dev-and-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,11 @@ jobs:
- name: 📃 Generate code documentation info for website
if: github.ref == 'refs/heads/master'
run: |
cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
cd tools/editor-message-tree
cargo run
cd ../..
mkdir -p artifacts-generated
mv hierarchical_message_system_tree.txt artifacts-generated/hierarchical_message_system_tree.txt
mv website/generated/hierarchical_message_system_tree.txt artifacts-generated/hierarchical_message_system_tree.txt
- name: 💿 Obtain cache of auto-generated code docs artifacts, to check if they've changed
if: github.ref == 'refs/heads/master'
Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,23 @@ jobs:
rustup update stable
echo "🦀 Latest updated version of Rust:"
rustc --version
cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
cd tools/editor-message-tree
cargo run
cd ../..
mkdir artifacts
mv hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt
mv website/generated/hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt

- name: 🚚 Move `artifacts` contents to the project root
- name: 🚚 Move `artifacts` contents to website/generated
run: |
mv artifacts/* .
mkdir -p website/generated
mv artifacts/* website/generated/

- name: 🔧 Build auto-generated code docs artifacts into HTML
run: |
cd website
npm run generate-editor-structure

- name: Generate node catalog documentation
- name: 📃 Generate node catalog documentation
run: |
cd tools/node-docs
cargo run
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,3 @@ flamegraph.svg
.idea/
.direnv
.DS_Store
hierarchical_message_system_tree.txt
hierarchical_message_system_tree.html
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ members = [
"node-graph/preprocessor",
"proc-macros",
"tools/crate-hierarchy-viz",
"tools/node-docs"
"tools/editor-message-tree",
"tools/node-docs",
]
default-members = [
"editor",
Expand Down
95 changes: 3 additions & 92 deletions editor/src/messages/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,97 +53,8 @@ impl specta::Type for MessageDiscriminant {
}
}

#[cfg(test)]
mod test {
use super::*;
use std::io::Write;

#[test]
fn generate_message_tree() {
let result = Message::build_message_tree();
let mut file = std::fs::File::create("../hierarchical_message_system_tree.txt").unwrap();
file.write_all(format!("{} `{}`\n", result.name(), result.path()).as_bytes()).unwrap();
if let Some(variants) = result.variants() {
for (i, variant) in variants.iter().enumerate() {
let is_last = i == variants.len() - 1;
print_tree_node(variant, "", is_last, &mut file);
}
}
}

fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &mut std::fs::File) {
// Print the current node
let (branch, child_prefix) = if tree.message_handler_data_fields().is_some() || tree.message_handler_fields().is_some() {
("├── ", format!("{prefix}│ "))
} else if is_last {
("└── ", format!("{prefix} "))
} else {
("├── ", format!("{prefix}│ "))
};

if tree.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, branch, tree.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, tree.name(), tree.path()).as_bytes()).unwrap();
}

// Print children if any
if let Some(variants) = tree.variants() {
let len = variants.len();
for (i, variant) in variants.iter().enumerate() {
let is_last_child = i == len - 1;
print_tree_node(variant, &child_prefix, is_last_child, file);
}
}

// Print message field if any
if let Some(fields) = tree.fields() {
let len = fields.len();
for (i, field) in fields.iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };

file.write_all(format!("{child_prefix}{branch}{field}\n").as_bytes()).unwrap();
}
}

// Print handler field if any
if let Some(data) = tree.message_handler_fields() {
let len = data.fields().len();
let (branch, child_prefix) = if tree.message_handler_data_fields().is_some() {
("├── ", format!("{prefix}│ "))
} else {
("└── ", format!("{prefix} "))
};

const FRONTEND_MESSAGE_STR: &str = "FrontendMessage";
if data.name().is_empty() && tree.name() != FRONTEND_MESSAGE_STR {
panic!("{}'s MessageHandler is missing #[message_handler_data]", tree.name());
} else if tree.name() != FRONTEND_MESSAGE_STR {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap();

for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };

file.write_all(format!("{}{}{}\n", child_prefix, branch, field.0).as_bytes()).unwrap();
}
}
}

// Print data field if any
if let Some(data) = tree.message_handler_data_fields() {
let len = data.fields().len();
if data.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, "└── ", data.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, "└── ", data.name(), data.path()).as_bytes()).unwrap();
}
for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };
file.write_all(format!("{}{}{}\n", format!("{} ", prefix), branch, field.0).as_bytes()).unwrap();
}
}
impl Message {
pub fn message_tree() -> DebugMessageTree {
Self::build_message_tree()
}
}
11 changes: 11 additions & 0 deletions tools/editor-message-tree/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "editor-message-tree"
description = "Tool to generate developer documentation for the editor message system structure"
edition.workspace = true
version.workspace = true
license.workspace = true
authors.workspace = true

[dependencies]
# Local dependencies
editor = { path = "../../editor", package = "graphite-editor" }
93 changes: 93 additions & 0 deletions tools/editor-message-tree/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use editor::messages::message::Message;
use editor::utility_types::DebugMessageTree;
use std::io::Write;

fn main() {
let result = Message::message_tree();
std::fs::create_dir_all("../../website/generated").unwrap();
let mut file = std::fs::File::create("../../website/generated/hierarchical_message_system_tree.txt").unwrap();
file.write_all(format!("{} `{}`\n", result.name(), result.path()).as_bytes()).unwrap();
if let Some(variants) = result.variants() {
for (i, variant) in variants.iter().enumerate() {
let is_last = i == variants.len() - 1;
print_tree_node(variant, "", is_last, &mut file);
}
}
}

fn print_tree_node(tree: &DebugMessageTree, prefix: &str, is_last: bool, file: &mut std::fs::File) {
// Print the current node
let (branch, child_prefix) = if tree.message_handler_data_fields().is_some() || tree.message_handler_fields().is_some() {
("├── ", format!("{prefix}│ "))
} else if is_last {
("└── ", format!("{prefix} "))
} else {
("├── ", format!("{prefix}│ "))
};

if tree.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, branch, tree.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, tree.name(), tree.path()).as_bytes()).unwrap();
}

// Print children if any
if let Some(variants) = tree.variants() {
let len = variants.len();
for (i, variant) in variants.iter().enumerate() {
let is_last_child = i == len - 1;
print_tree_node(variant, &child_prefix, is_last_child, file);
}
}

// Print message field if any
if let Some(fields) = tree.fields() {
let len = fields.len();
for (i, field) in fields.iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };

file.write_all(format!("{child_prefix}{branch}{field}\n").as_bytes()).unwrap();
}
}

// Print handler field if any
if let Some(data) = tree.message_handler_fields() {
let len = data.fields().len();
let (branch, child_prefix) = if tree.message_handler_data_fields().is_some() {
("├── ", format!("{prefix}│ "))
} else {
("└── ", format!("{prefix} "))
};

const FRONTEND_MESSAGE_STR: &str = "FrontendMessage";
if data.name().is_empty() && tree.name() != FRONTEND_MESSAGE_STR {
panic!("{}'s MessageHandler is missing #[message_handler_data]", tree.name());
} else if tree.name() != FRONTEND_MESSAGE_STR {
file.write_all(format!("{}{}{} `{}`\n", prefix, branch, data.name(), data.path()).as_bytes()).unwrap();

for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };

file.write_all(format!("{}{}{}\n", child_prefix, branch, field.0).as_bytes()).unwrap();
}
}
}

// Print data field if any
if let Some(data) = tree.message_handler_data_fields() {
let len = data.fields().len();
if data.path().is_empty() {
file.write_all(format!("{}{}{}\n", prefix, "└── ", data.name()).as_bytes()).unwrap();
} else {
file.write_all(format!("{}{}{} `{}`\n", prefix, "└── ", data.name(), data.path()).as_bytes()).unwrap();
}
for (i, field) in data.fields().iter().enumerate() {
let is_last_field = i == len - 1;
let branch = if is_last_field { "└── " } else { "├── " };
let field = &field.0;
file.write_all(format!("{prefix} {branch}{field}\n").as_bytes()).unwrap();
}
}
}
2 changes: 2 additions & 0 deletions website/.build-scripts/generate-editor-structure.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: Port this script to Rust as part of `tools/editor-message-tree/src/main.rs`

/* eslint-disable no-console */

import fs from "fs";
Expand Down
1 change: 1 addition & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules/
public/
generated/
static/*
!static/js/
content/learn/node-catalog
8 changes: 4 additions & 4 deletions website/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"type": "module",
"scripts": {
"postinstall": "node .build-scripts/install.ts",
"generate-editor-structure": "node .build-scripts/generate-editor-structure.ts ../hierarchical_message_system_tree.txt ../hierarchical_message_system_tree.html",
"generate-editor-structure": "node .build-scripts/generate-editor-structure.ts generated/hierarchical_message_system_tree.txt generated/hierarchical_message_system_tree.html",
"lint": "eslint . && tsc --noEmit",
"lint-fix": "eslint . --fix && tsc --noEmit"
},
Expand All @@ -28,7 +28,7 @@
"eslint": "^9.39.2",
"prettier": "^3.8.0",
"sass": "1.97.2",
"tar": "^7.5.4",
"tar": "^7.5.6",
"typescript-eslint": "^8.53.1"
},
"dependencies": {
Expand Down
8 changes: 5 additions & 3 deletions website/templates/macros/replacements.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ <h2 class="headline"><a href="{{ article.permalink | safe }}">{{ article.title }
{% endmacro text_balancer %}

{% macro hierarchical_message_system_tree() %}
{%- set content = load_data(path = "../../hierarchical_message_system_tree.html", format = "plain", required = false) -%}
{%- set content = load_data(path = "../generated/hierarchical_message_system_tree.html", format = "plain", required = false) -%}
{%- set fallback = "<pre>THIS CONTENT IS FILLED IN WHEN CI BUILDS THE WEBSITE.

TO TEST IT LOCALLY, FROM THE `website` DIRECTORY, RUN:
TO TEST IT LOCALLY, FROM THE ROOT OF THE PROJECT, RUN:

cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
cd tools/editor-message-tree
cargo run
cd ../../website
npm run generate-editor-structure</pre>" -%}
{{ content | default(value = fallback) | safe }}
{% endmacro hierarchical_message_system_tree %}