Skip to content

Commit

Permalink
refactor(xtask): Internally detect regex implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
CosmicHorrorDev committed Jan 14, 2025
1 parent 3201fb3 commit ff14d6a
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 60 deletions.
149 changes: 99 additions & 50 deletions xtask/src/gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,62 @@ use syntect::{
use tempfile::TempDir;
use xshell::{cmd, Shell};

use self::acknowledgements::{Acknowledgements, NORM_LICENSE_STEMS};
use self::acknowledgements::{Acknowledgements, License, NORM_LICENSE_STEMS};

mod acknowledgements;
mod themes;
mod utils;

const NORM_RELEVANT_EXTS: &[&str] = &["patch", "sublime-syntax", "tmtheme"];

#[derive(Clone, Copy, PartialEq, Eq)]
enum RegexImpl {
Onig,
Fancy,
}

impl RegexImpl {
/// Detects `syntect`'s currently active regex implementation
///
/// # Panics
///
/// Panics when zero or multiple implementations are active
fn detect() -> Self {
let onig = cfg!(feature = "syntect-onig");
let fancy = cfg!(feature = "syntect-fancy");
match (onig, fancy) {
(true, false) => Self::Onig,
(false, true) => Self::Fancy,
(false, false) => panic!("No regex impl feature detected"),
(true, true) => panic!("Both onig and fancy impls detected"),
}
}

fn newlines_asset_name(self) -> &'static str {
match self {
RegexImpl::Fancy => "syntaxes-fancy-newlines.bin",
RegexImpl::Onig => "syntaxes-onig-newlines.bin",
}
}

fn no_newlines_asset_name(self) -> &'static str {
match self {
RegexImpl::Fancy => "syntaxes-fancy-no-newlines.bin",
RegexImpl::Onig => "syntaxes-onig-no-newlines.bin",
}
}
}

struct AssetsDir {
tempdir: TempDir,
regex_impl: RegexImpl,
}

impl AssetsDir {
/// Move desired assets to a tempdir and apply patches
fn new(input: &Path) -> anyhow::Result<Self> {
let regex_impl = RegexImpl::detect();

log::info!("Setting up assets dir");
let tempdir = tempfile::Builder::new()
.prefix("two-face-assets-")
Expand Down Expand Up @@ -52,27 +93,30 @@ impl AssetsDir {
}
}

// Apply bat's patches
let apply_patches_from = |patch_shell: &Shell, from| -> anyhow::Result<()> {
for patch in utils::walk_files(from)? {
let patch_contents = fs::read(&patch)?;
let output = cmd!(patch_shell, "patch --strip=0")
.stdin(&patch_contents)
.quiet()
.read()?;
log::debug!("Patch output:\n{output}");
}

Ok(())
};
let patch_shell = Shell::new()?;
patch_shell.change_dir(temp_path);
for patch in utils::walk_files(&temp_path.join("patches"))? {
let patch_contents = fs::read(&patch)?;
let output = cmd!(patch_shell, "patch --strip=0")
.stdin(&patch_contents)
.quiet()
.read()?;
log::debug!("Patch output:\n{output}");
}
for patch in utils::walk_files(Path::new("patches")).unwrap_or_default() {
let patch_contents = fs::read(&patch)?;
let output = cmd!(patch_shell, "patch --strip=0")
.stdin(&patch_contents)
.quiet()
.read()?;
log::debug!("Patch output:\n{output}");
}

Ok(Self { tempdir })
// Apply bat's patches
let bat_patches = temp_path.join("patches");
apply_patches_from(&patch_shell, &bat_patches)?;
// And now our own
apply_patches_from(&patch_shell, Path::new("patches"))?;

Ok(Self {
tempdir,
regex_impl,
})
}

fn path(&self) -> &Path {
Expand All @@ -81,7 +125,7 @@ impl AssetsDir {

fn load_syntax_set(&self, newlines: utils::IncludeNewlines) -> anyhow::Result<SyntaxSet> {
log::debug!("Loading syntax set");
let syn_dir = self.tempdir.path().join("syntaxes");
let syn_dir = self.path().join("syntaxes");
let mut builder = SyntaxSetBuilder::new();
builder.add_plain_text_syntax();
for file in utils::walk_files(&syn_dir)? {
Expand Down Expand Up @@ -116,29 +160,27 @@ impl AssetsDir {
}
}

pub fn gen(only_fancy_syntaxes: bool) -> anyhow::Result<()> {
pub fn gen() -> anyhow::Result<()> {
let assets_dir = AssetsDir::new(Path::new("bat/assets"))?;
let output_dir = assets_dir.path().join("out");
fs::create_dir_all(&output_dir)?;

log::info!("Generating dumps for syntaxes with newlines");
let syn_set_newlines = assets_dir.load_syntax_set(utils::IncludeNewlines::Yes)?;
let syn_name = if only_fancy_syntaxes {
"syntaxes-fancy-newlines.bin"
} else {
"syntaxes-onig-newlines.bin"
};
let syn_name = assets_dir.regex_impl.newlines_asset_name();
syntect::dumps::dump_to_uncompressed_file(&syn_set_newlines, output_dir.join(syn_name))?;
log::info!("Again now with no newlines");
let syn_set_no_newlines = assets_dir.load_syntax_set(utils::IncludeNewlines::No)?;
let syn_name = if only_fancy_syntaxes {
"syntaxes-fancy-no-newlines.bin"
} else {
"syntaxes-onig-no-newlines.bin"
};
let syn_name = assets_dir.regex_impl.no_newlines_asset_name();
// Syntax set has each syntax internally compressed, so no point re-compressing everything
syntect::dumps::dump_to_uncompressed_file(&syn_set_no_newlines, output_dir.join(syn_name))?;

if !only_fancy_syntaxes {
let generated_dir = Path::new("generated");
fs::create_dir_all(generated_dir)?;

// Onig contains all syntaxes that are present with fancy, and more, so generate any one-off
// embedded assets when it's the active implementation
if assets_dir.regex_impl == RegexImpl::Onig {
log::info!("Generating dumps for all other assets");
let theme_set = assets_dir.load_theme_set()?;
let acks = assets_dir.load_acknowledgements()?;
Expand All @@ -147,33 +189,40 @@ pub fn gen(only_fancy_syntaxes: bool) -> anyhow::Result<()> {
let ack_full_bin_name = "acknowledgements_full.bin";
syntect::dumps::dump_to_uncompressed_file(&theme_set, output_dir.join(theme_name))?;
fs::write(output_dir.join(ack_name), acks.to_md())?;

// The static markdown file will have _all_ the acknowledgements while the embedded data
// will only keep ones that require acknowledgement
let needs_ack = Acknowledgements {
for_themes: acks
.for_themes
.into_iter()
.filter(|ack| ack.needs_acknowledgement())
.collect(),
for_syntaxes: acks
.for_syntaxes
let filter_needs_ack = |licenses: Vec<License>| {
licenses
.into_iter()
.filter(|ack| ack.needs_acknowledgement())
.collect(),
.filter(|license| license.needs_acknowledgement())
.collect()
};
let needs_ack = Acknowledgements {
for_themes: filter_needs_ack(acks.for_themes),
for_syntaxes: filter_needs_ack(acks.for_syntaxes),
};
syntect::dumps::dump_to_file(&needs_ack, output_dir.join(ack_full_bin_name))?;

let assets_dir = Path::new("assets");
log::info!(
"Copying from `{}` to `{}`",
assets_dir.display(),
generated_dir.display()
);
for file in utils::walk_files(assets_dir)? {
fs::copy(&file, generated_dir.join(file.file_name().unwrap()))?;
}
}

log::info!("Copying from {}", output_dir.display());
let generated_dir = Path::new("generated");
fs::create_dir_all(generated_dir)?;
log::info!(
"Copying from `{}` to `{}`",
output_dir.display(),
generated_dir.display()
);
for file in utils::walk_files(&output_dir)? {
fs::copy(&file, generated_dir.join(file.file_name().unwrap()))?;
}
log::info!("Copying from `assets/`");
for file in utils::walk_files(Path::new("assets"))? {
fs::copy(&file, generated_dir.join(file.file_name().unwrap()))?;
}

Ok(())
}
7 changes: 5 additions & 2 deletions xtask/src/gen/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::path::{Path, PathBuf};
use std::{
fs,
path::{Path, PathBuf},
};

use anyhow::Context;
use syntect::parsing::SyntaxDefinition;
Expand All @@ -12,7 +15,7 @@ pub enum IncludeNewlines {

// Helper function copied from syntect internals
pub fn load_syntax_file(p: &Path, newlines: IncludeNewlines) -> anyhow::Result<SyntaxDefinition> {
let s = std::fs::read_to_string(p)?;
let s = fs::read_to_string(p)?;

let include_newlines = newlines == IncludeNewlines::Yes;
SyntaxDefinition::load_from_str(&s, include_newlines, p.file_stem().and_then(|x| x.to_str()))
Expand Down
10 changes: 2 additions & 8 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ enum Commands {
yes_update_submodules: bool,
/// Should only be set by `cargo xtask gen` running. Never set manually
///
/// Only generate the syntax dumps for fancy-regex
#[arg(long)]
only_fancy_syntaxes: bool,
/// Should only be set by `cargo xtask gen` running. Never set manually
///
/// Weird hack because `cargo xtask gen` calls back into itself to run. This is done, so
/// that we can have a single "run" that sets different features for `syntect`
#[arg(long)]
Expand All @@ -49,11 +44,10 @@ fn main() -> anyhow::Result<()> {
match cli.command {
Commands::Gen {
yes_update_submodules,
only_fancy_syntaxes,
calling_self,
} => {
if calling_self {
gen::gen(only_fancy_syntaxes)?;
gen::gen()?;
} else {
anyhow::ensure!(
yes_update_submodules,
Expand All @@ -73,7 +67,7 @@ fn main() -> anyhow::Result<()> {
cmd!(shell, "cargo {xtask_args...} -- {args...}").run()?;
cmd!(
shell,
"cargo {xtask_args...} {fancy_feature...} -- {args...} --only-fancy-syntaxes"
"cargo {xtask_args...} {fancy_feature...} -- {args...}"
)
.run()?;
}
Expand Down

0 comments on commit ff14d6a

Please sign in to comment.