Skip to content

Commit

Permalink
build_assets.rs: Add code to track dependents of each syntax
Browse files Browse the repository at this point in the history
This information is useful when you want to build several SyntaxSets, but
without having to duplicate SyntaxDefinitions. For example:

"Rust" has no dependencies. But "Markdown" depends on "Rust". With the data
structures this code adds, we know that "Rust" is a dependent syntax for
"Markdown", and can construct a SyntaxSet that takes that into account.

Note that code has a temporary environment flag to ignore any information about
dependents when constructing SyntaxSets. Code that makes use of the new data
structure will be added later.
  • Loading branch information
Enselic committed Sep 22, 2021
1 parent 50e6b06 commit f77ff1c
Showing 1 changed file with 59 additions and 18 deletions.
77 changes: 59 additions & 18 deletions src/assets/build_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ type OtherSyntaxLookup<'a> = HashMap<OtherSyntax, &'a SyntaxDefinition>;
/// Used to look up what dependencies a given [SyntaxDefinition] has
type SyntaxToDependencies = HashMap<SyntaxName, Vec<OtherSyntax>>;

/// Used to look up what other [SyntaxDefinition]s depend on a given [SyntaxDefinition]
type SyntaxToDependents<'a> = HashMap<SyntaxName, Vec<OtherSyntax>>;

/// Represents some other `*.sublime-syntax` file, i.e. another [SyntaxDefinition].
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
enum OtherSyntax {
Expand Down Expand Up @@ -215,7 +218,8 @@ fn build_minimal_syntax_sets(
let syntaxes = syntax_set_builder.syntaxes();

// Build the data structures we need for dependency resolution
let (other_syntax_lookup, syntax_to_dependencies) = generate_maps(syntaxes);
let (other_syntax_lookup, syntax_to_dependencies, syntax_to_dependents) =
generate_maps(syntaxes);

// Create one minimal SyntaxSet from each (non-hidden) SyntaxDefinition
syntaxes.iter().filter_map(move |syntax| {
Expand All @@ -224,7 +228,12 @@ fn build_minimal_syntax_sets(
}

let mut builder = SyntaxSetDependencyBuilder::new();
builder.add_with_dependencies(syntax, &other_syntax_lookup, &syntax_to_dependencies);
builder.add_with_dependencies(
syntax,
&other_syntax_lookup,
&syntax_to_dependencies,
&syntax_to_dependents,
);
let syntax_set = builder.build();

if std::env::var("BAT_PRINT_SYNTAX_DEPENDENCIES").is_ok() {
Expand All @@ -237,22 +246,48 @@ fn build_minimal_syntax_sets(
})
}

/// In order to analyze dependencies, we need two key pieces of data.
/// First, when we have a [OtherSyntax], we need to know what [SyntaxDefinition] that
/// corresponds to. Second, when we have a [SyntaxDefinition], we need to know
/// what dependencies it has. This functions generates that data for each syntax.
fn generate_maps(syntaxes: &[SyntaxDefinition]) -> (OtherSyntaxLookup, SyntaxToDependencies) {
/// In order to analyze dependencies, we need three key pieces of data.
///
/// * When we have a [OtherSyntax], we need to know what [SyntaxDefinition]
/// that corresponds to
/// * When we have a [SyntaxDefinition], we need to know what dependencies it
/// has
/// * When we have a [SyntaxDefinition], we need to know what other syntaxes
/// depend on it
///
/// This functions generates that data for each syntax.
fn generate_maps(
syntaxes: &[SyntaxDefinition],
) -> (OtherSyntaxLookup, SyntaxToDependencies, SyntaxToDependents) {
let mut other_syntax_lookup = HashMap::new();
let mut syntax_to_dependencies = HashMap::new();
let mut syntax_to_dependents = HashMap::new();

for syntax in syntaxes {
syntax_to_dependencies.insert(syntax.name.clone(), dependencies_for_syntax(syntax));

other_syntax_lookup.insert(OtherSyntax::ByName(syntax.name.clone()), syntax);
other_syntax_lookup.insert(OtherSyntax::ByScope(syntax.scope), syntax);
}

(other_syntax_lookup, syntax_to_dependencies)
for syntax in syntaxes {
let dependencies = dependencies_for_syntax(syntax);

for dependency in &dependencies {
if let Some(dependency) = other_syntax_lookup.get(dependency) {
syntax_to_dependents
.entry(dependency.name.clone())
.or_insert_with(Vec::new)
.push(OtherSyntax::ByName(syntax.name.clone()));
}
}

syntax_to_dependencies.insert(syntax.name.clone(), dependencies);
}

(
other_syntax_lookup,
syntax_to_dependencies,
syntax_to_dependents,
)
}

/// Gets what external dependencies a given [SyntaxDefinition] has.
Expand Down Expand Up @@ -322,6 +357,7 @@ impl SyntaxSetDependencyBuilder {
syntax: &SyntaxDefinition,
other_syntax_lookup: &OtherSyntaxLookup,
syntax_to_dependencies: &SyntaxToDependencies,
syntax_to_dependents: &SyntaxToDependents,
) {
let name = &syntax.name;
if self.is_syntax_already_added(name) {
Expand All @@ -330,18 +366,23 @@ impl SyntaxSetDependencyBuilder {

self.syntax_set_builder.add(syntax.clone());

let dependencies = syntax_to_dependencies.get(name);
if dependencies.is_none() {
eprintln!("ERROR: Unknown dependencies for {}", name);
return;
let mut syntaxes_to_add = vec![];
if let Some(dependencies) = syntax_to_dependencies.get(name) {
syntaxes_to_add.extend(dependencies);
}

for dependency in dependencies.unwrap() {
if let Some(syntax_definition_dependency) = other_syntax_lookup.get(dependency) {
if let Some(dependents) = syntax_to_dependents.get(name) {
// This will later be enabled intelligently
if std::env::var("BAT_INCLUDE_SYNTAX_DEPENDENTS").is_ok() {
syntaxes_to_add.extend(dependents);
}
}
for syntax_to_add in syntaxes_to_add {
if let Some(syntax_to_add) = other_syntax_lookup.get(syntax_to_add) {
self.add_with_dependencies(
syntax_definition_dependency,
syntax_to_add,
other_syntax_lookup,
syntax_to_dependencies,
syntax_to_dependents,
)
}
}
Expand Down

0 comments on commit f77ff1c

Please sign in to comment.