core: add support for sign text transformations

Add support for regexp replacement patterns, which can be useful when
the text matched by --sign-filter or --sign-prefix should not be
displayed.
This commit is contained in:
Matthias Schiffer 2024-01-26 22:34:41 +01:00
parent a99a734df8
commit 8a1a26c13c
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
4 changed files with 71 additions and 2 deletions

View file

@ -8,7 +8,7 @@ use std::{
use anyhow::{Context, Result};
use indexmap::IndexSet;
use regex::RegexSet;
use regex::{Regex, RegexSet};
use serde::{Deserialize, Serialize};
use crate::{
@ -130,6 +130,7 @@ pub enum TileKind {
}
/// Common configuration based on command line arguments
#[derive(Debug)]
pub struct Config {
/// Number of threads for parallel processing
pub num_threads: usize,
@ -151,6 +152,8 @@ pub struct Config {
pub viewer_entities_path: PathBuf,
/// Sign text filter patterns
pub sign_patterns: RegexSet,
/// Sign text transformation pattern
pub sign_transforms: Vec<(Regex, String)>,
}
impl Config {
@ -173,6 +176,8 @@ impl Config {
.collect();
let sign_patterns = Self::sign_patterns(args).context("Failed to parse sign patterns")?;
let sign_transforms =
Self::sign_transforms(args).context("Failed to parse sign transforms")?;
Ok(Config {
num_threads,
@ -185,6 +190,7 @@ impl Config {
viewer_info_path,
viewer_entities_path,
sign_patterns,
sign_transforms,
})
}
@ -200,6 +206,28 @@ impl Config {
)?)
}
/// Parses the sign transform argument into a vector of [Regex] and
/// corresponding replacement strings
fn sign_transforms(args: &super::Args) -> Result<Vec<(Regex, String)>> {
let splitter = Regex::new(r"^s/((?:[^\\/]|\\.)*)/((?:[^\\/]|\\.)*)/$").unwrap();
args.sign_transform
.iter()
.map(|t| Self::sign_transform(&splitter, t))
.collect()
}
/// Parses the sign transform argument into a [Regex] and its corresponding
/// replacement string
fn sign_transform(splitter: &Regex, transform: &str) -> Result<(Regex, String)> {
let captures = splitter
.captures(transform)
.with_context(|| format!("Invalid transform pattern '{}'", transform))?;
let regexp = Regex::new(&captures[1])?;
let replacement = captures[2].to_string();
Ok((regexp, replacement))
}
/// Constructs the path to an input region file
pub fn region_path(&self, coords: TileCoords) -> PathBuf {
let filename = coord_filename(coords, "mca");

View file

@ -1,6 +1,7 @@
//! The [MetadataWriter] and related types
use anyhow::{Context, Result};
use regex::Regex;
use serde::Serialize;
use crate::{
@ -8,7 +9,7 @@ use crate::{
io::{fs, storage},
world::{
block_entity::{self, BlockEntity, BlockEntityData},
de,
de, sign,
},
};
@ -145,6 +146,28 @@ impl<'a> MetadataWriter<'a> {
false
}
/// Applies a single transform to a [sign::SignText]
///
/// The regular expression is applied for each line of the sign text
/// separately (actually for each element when JSON text is used)
fn sign_text_transform(sign_text: &mut sign::SignText, transform: &(Regex, String)) {
let (regexp, replacement) = transform;
for line in &mut sign_text.0 {
for text in &mut line.0 {
text.text = regexp.replace_all(&text.text, replacement).into_owned()
}
}
}
/// Applies the configured transforms to the text of a sign
fn sign_transform(&self, sign: &mut block_entity::Sign) {
for transform in &self.config.sign_transforms {
Self::sign_text_transform(&mut sign.front_text, transform);
Self::sign_text_transform(&mut sign.back_text, transform);
}
}
/// Generates [Entities] data from collected entity lists
fn entities(&self) -> Result<Entities> {
let data: ProcessedEntities =
@ -158,6 +181,12 @@ impl<'a> MetadataWriter<'a> {
.filter(|entity| match &entity.data {
BlockEntityData::Sign(sign) => self.sign_filter(sign),
})
.map(|mut entity| {
match &mut entity.data {
BlockEntityData::Sign(sign) => self.sign_transform(sign),
};
entity
})
.collect(),
};

View file

@ -59,6 +59,12 @@ pub struct Args {
/// To make all signs visible, pass an empty string to either option.
#[arg(long)]
pub sign_filter: Vec<String>,
/// Regular expression replacement pattern for sign texts
///
/// Accepts patterns of the form 's/regexp/replacement/'. Transforms
/// are applied to each line of sign texts separately.
#[arg(long)]
pub sign_transform: Vec<String>,
/// Minecraft save directory
pub input_dir: PathBuf,
/// MinedMap data directory