particle-os-cli/utils/src/syntax_highlighting.rs
Gerald Pinder 92150693d4
feat: Display full recipe with syntax highlighting (#166)
As I was re-arranging my recipe files, I needed a way to ensure that the
order of my recipe is correct without having to read through the
generated `Containerfile`. So I added a `-d`/`--display-full-recipe` arg
to `template` that will print out all of your modules in the order
defined by following the `from-file` property.

```
$> bluebuild template --help
Generate a Containerfile from a recipe

Usage: bluebuild template [OPTIONS] [RECIPE]

Arguments:
  [RECIPE]
          The recipe file to create a template from

Options:
  -o, --output <OUTPUT>
          File to output to instead of STDOUT

      --registry <REGISTRY>
          The registry domain the image will be published to.

          This is used for modules that need to know where the image is being published (i.e. the signing module).

      --registry-namespace <REGISTRY_NAMESPACE>
          The registry namespace the image will be published to.

          This is used for modules that need to know where the image is being published (i.e. the signing module).

  -d, --display-full-recipe
          Instead of creating a Containerfile, display the full recipe after traversing all `from-file` properties.

          This can be used to help debug the order you defined your recipe.

  -t, --syntax-theme <SYNTAX_THEME>
          Choose a theme for the syntax highlighting for the Containerfile or Yaml.

          The default is `mocha-dark`.

          [possible values: mocha-dark, ocean-dark, ocean-light, eighties-dark, inspired-github, solarized-dark, solarized-light]

  -s, --squash
          Puts the build in a `squash-stage` and COPY's the results to the final stage as one layer.

          WARN: This doesn't work with the docker driver as it has been deprecated.

          NOTE: Squash has a performance benefit for the newer versions of podman and buildah.

  -B, --build-driver <BUILD_DRIVER>
          Select which driver to use to build your image

          [possible values: buildah, podman, docker]

  -v, --verbose...
          Increase logging verbosity

  -I, --inspect-driver <INSPECT_DRIVER>
          Select which driver to use to inspect images

          [possible values: skopeo, podman, docker]

  -q, --quiet...
          Decrease logging verbosity

  -h, --help
          Print help (see a summary with '-h')
```

Preview of Containerfile/Dockerfile syntax highlighting:

![image](https://github.com/blue-build/cli/assets/4626052/cf2c452e-94b1-44f3-97ca-162d50a5047f)

Preview of Yaml highlighting:

![image](https://github.com/blue-build/cli/assets/4626052/b7c48b82-3e9e-431c-a55b-679848cd1fa6)
2024-04-27 09:12:04 -04:00

85 lines
2.7 KiB
Rust

use anyhow::{anyhow, Result};
use clap::ValueEnum;
use log::trace;
use serde::ser::Serialize;
use syntect::{dumps, easy::HighlightLines, highlighting::ThemeSet, parsing::SyntaxSet};
#[derive(Debug, Default, Clone, Copy, ValueEnum)]
pub enum DefaultThemes {
#[default]
MochaDark,
OceanDark,
OceanLight,
EightiesDark,
InspiredGithub,
SolarizedDark,
SolarizedLight,
}
impl std::fmt::Display for DefaultThemes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match *self {
Self::MochaDark => "base16-mocha.dark",
Self::OceanDark => "base16-ocean.dark",
Self::OceanLight => "base16-ocean.light",
Self::EightiesDark => "base16-eighties.dark",
Self::InspiredGithub => "InspiredGithub",
Self::SolarizedDark => "Solarized (dark)",
Self::SolarizedLight => "Solarized (light)",
})
}
}
/// Prints the file with syntax highlighting.
///
/// # Errors
/// Will error if the theme doesn't exist, the syntax doesn't exist, or the file
/// failed to serialize.
pub fn print(file: &str, file_type: &str, theme: Option<DefaultThemes>) -> Result<()> {
trace!("syntax_highlighting::print({file}, {file_type}, {theme:?})");
if atty::is(atty::Stream::Stdout) {
let ss: SyntaxSet = if file_type == "dockerfile" || file_type == "Dockerfile" {
dumps::from_uncompressed_data(include_bytes!(concat!(
env!("OUT_DIR"),
"/docker_syntax.bin"
)))?
} else {
SyntaxSet::load_defaults_newlines()
};
let ts = ThemeSet::load_defaults();
let syntax = ss
.find_syntax_by_extension(file_type)
.ok_or_else(|| anyhow!("Failed to get syntax"))?;
let mut h = HighlightLines::new(
syntax,
ts.themes
.get(theme.unwrap_or_default().to_string().as_str())
.ok_or_else(|| anyhow!("Failed to get highlight theme"))?,
);
for line in file.lines() {
let ranges = h.highlight_line(line, &ss)?;
let escaped = syntect::util::as_24_bit_terminal_escaped(&ranges, false);
println!("{escaped}");
}
println!("\x1b[0m");
} else {
println!("{file}");
}
Ok(())
}
/// Takes a serializable struct and prints it out with syntax highlighting.
///
/// # Errors
/// Will error if the theme doesn't exist, the syntax doesn't exist, or the file
/// failed to serialize.
pub fn print_ser<T: Serialize>(
file: &T,
file_type: &str,
theme: Option<DefaultThemes>,
) -> Result<()> {
print(serde_yaml::to_string(file)?.as_str(), file_type, theme)?;
Ok(())
}