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

@ -75,6 +75,12 @@ All prefixes and filters are applied to the front and back text separately, but
both the front and the back text will be shown in the popup when one of them both the front and the back text will be shown in the popup when one of them
matches. matches.
Finally, `--sign-transform` allows to specify sed-style replacement patterns to
modify the text displayed on the map. This can be used if the text matched by
`--sign-prefix` or `--sign-filter` should not be displayed:
`--sign-filter 's/\[Map\]//'` would replace each occurence of "\[Map\]" with
the empty string.
## Installation ## Installation
Binary builds of the map generator for Linux and Windows, as well as an archive Binary builds of the map generator for Linux and Windows, as well as an archive

View file

@ -8,7 +8,7 @@ use std::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use indexmap::IndexSet; use indexmap::IndexSet;
use regex::RegexSet; use regex::{Regex, RegexSet};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -130,6 +130,7 @@ pub enum TileKind {
} }
/// Common configuration based on command line arguments /// Common configuration based on command line arguments
#[derive(Debug)]
pub struct Config { pub struct Config {
/// Number of threads for parallel processing /// Number of threads for parallel processing
pub num_threads: usize, pub num_threads: usize,
@ -151,6 +152,8 @@ pub struct Config {
pub viewer_entities_path: PathBuf, pub viewer_entities_path: PathBuf,
/// Sign text filter patterns /// Sign text filter patterns
pub sign_patterns: RegexSet, pub sign_patterns: RegexSet,
/// Sign text transformation pattern
pub sign_transforms: Vec<(Regex, String)>,
} }
impl Config { impl Config {
@ -173,6 +176,8 @@ impl Config {
.collect(); .collect();
let sign_patterns = Self::sign_patterns(args).context("Failed to parse sign patterns")?; 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 { Ok(Config {
num_threads, num_threads,
@ -185,6 +190,7 @@ impl Config {
viewer_info_path, viewer_info_path,
viewer_entities_path, viewer_entities_path,
sign_patterns, 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 /// Constructs the path to an input region file
pub fn region_path(&self, coords: TileCoords) -> PathBuf { pub fn region_path(&self, coords: TileCoords) -> PathBuf {
let filename = coord_filename(coords, "mca"); let filename = coord_filename(coords, "mca");

View file

@ -1,6 +1,7 @@
//! The [MetadataWriter] and related types //! The [MetadataWriter] and related types
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use regex::Regex;
use serde::Serialize; use serde::Serialize;
use crate::{ use crate::{
@ -8,7 +9,7 @@ use crate::{
io::{fs, storage}, io::{fs, storage},
world::{ world::{
block_entity::{self, BlockEntity, BlockEntityData}, block_entity::{self, BlockEntity, BlockEntityData},
de, de, sign,
}, },
}; };
@ -145,6 +146,28 @@ impl<'a> MetadataWriter<'a> {
false 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 /// Generates [Entities] data from collected entity lists
fn entities(&self) -> Result<Entities> { fn entities(&self) -> Result<Entities> {
let data: ProcessedEntities = let data: ProcessedEntities =
@ -158,6 +181,12 @@ impl<'a> MetadataWriter<'a> {
.filter(|entity| match &entity.data { .filter(|entity| match &entity.data {
BlockEntityData::Sign(sign) => self.sign_filter(sign), BlockEntityData::Sign(sign) => self.sign_filter(sign),
}) })
.map(|mut entity| {
match &mut entity.data {
BlockEntityData::Sign(sign) => self.sign_transform(sign),
};
entity
})
.collect(), .collect(),
}; };

View file

@ -59,6 +59,12 @@ pub struct Args {
/// To make all signs visible, pass an empty string to either option. /// To make all signs visible, pass an empty string to either option.
#[arg(long)] #[arg(long)]
pub sign_filter: Vec<String>, 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 /// Minecraft save directory
pub input_dir: PathBuf, pub input_dir: PathBuf,
/// MinedMap data directory /// MinedMap data directory