diff --git a/src/assets/build_assets.rs b/src/assets/build_assets.rs index fcab4ac4..b09d36dc 100644 --- a/src/assets/build_assets.rs +++ b/src/assets/build_assets.rs @@ -8,6 +8,8 @@ use syntect::parsing::{Scope, SyntaxSet, SyntaxSetBuilder}; use crate::assets::*; +mod graphviz_utils; + type SyntaxName = String; /// Used to look up which [SyntaxDefinition] corresponds to a given [OtherSyntax] @@ -221,6 +223,11 @@ fn build_minimal_syntax_sets( let (other_syntax_lookup, syntax_to_dependencies, syntax_to_dependents) = generate_maps(syntaxes); + maybe_write_syntax_dependencies_to_graphviz_dot_file( + &other_syntax_lookup, + &syntax_to_dependencies, + ); + // Create one minimal SyntaxSet from each (non-hidden) SyntaxDefinition syntaxes.iter().filter_map(move |syntax| { if syntax.hidden { @@ -329,6 +336,26 @@ fn dependencies_from_pattern(pattern: &Pattern) -> Vec { .collect() } +/// To generate a Graphviz dot file of syntax dependencies, do this: +/// ```bash +/// sudo apt install graphviz +/// BAT_SYNTAX_DEPENDENCIES_TO_GRAPHVIZ_DOT_FILE=/tmp/bat-syntax-dependencies.dot cargo run -- cache --build --source assets --blank --target /tmp +/// dot /tmp/bat-syntax-dependencies.dot -Tpng -o /tmp/bat-syntax-dependencies.png +/// open /tmp/bat-syntax-dependencies.png +/// ``` +fn maybe_write_syntax_dependencies_to_graphviz_dot_file( + other_syntax_lookup: &OtherSyntaxLookup, + syntax_to_dependencies: &SyntaxToDependencies, +) { + if let Ok(dot_file_path) = std::env::var("BAT_SYNTAX_DEPENDENCIES_TO_GRAPHVIZ_DOT_FILE") { + graphviz_utils::try_syntax_dependencies_to_graphviz_dot_file( + other_syntax_lookup, + syntax_to_dependencies, + &dot_file_path, + ); + } +} + /// Removes any context name from the syntax reference. /// /// When we track dependencies between syntaxes, we are not interested in diff --git a/src/assets/build_assets/graphviz_utils.rs b/src/assets/build_assets/graphviz_utils.rs new file mode 100644 index 00000000..5c93b37b --- /dev/null +++ b/src/assets/build_assets/graphviz_utils.rs @@ -0,0 +1,41 @@ +use super::*; + +pub(crate) fn try_syntax_dependencies_to_graphviz_dot_file( + other_syntax_lookup: &OtherSyntaxLookup, + syntax_to_dependencies: &SyntaxToDependencies, + dot_file_path: &str, +) { + match syntax_dependencies_to_graphviz_dot_file( + other_syntax_lookup, + syntax_to_dependencies, + dot_file_path, + ) { + Ok(_) => println!("Wrote graphviz dot file to {}", dot_file_path), + Err(e) => eprintln!( + "Failed to write graphviz dot file to {}: {}", + dot_file_path, e + ), + }; +} + +fn syntax_dependencies_to_graphviz_dot_file( + other_syntax_lookup: &OtherSyntaxLookup, + syntax_to_dependencies: &SyntaxToDependencies, + dot_file_path: &str, +) -> Result<()> { + use std::io::Write; + + let mut dot_file = std::fs::File::create(dot_file_path)?; + + writeln!(dot_file, "digraph BatSyntaxDependencies {{")?; + for (key, dependencies) in syntax_to_dependencies { + for dependency in dependencies { + if let Some(dep) = other_syntax_lookup.get(dependency) { + writeln!(dot_file, " \"{}\" -> \"{}\"", key, dep.name)?; + } + } + } + writeln!(dot_file, "}}")?; + + Ok(()) +}