Skip to content

Commit

Permalink
feat: 添加 rename 方法
Browse files Browse the repository at this point in the history
  • Loading branch information
KonghaYao committed Jan 12, 2025
1 parent ba78f8c commit 0ed3832
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 95 deletions.
160 changes: 81 additions & 79 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "cn-font-split"
description = "划时代的字体切割工具,CJK与任何字符!支持 otf、ttf、woff2 字体多线程切割,完美地细颗粒度地进行包大小控制。A revolutionary font subetter that supports CJK and any characters! It enables multi-threaded subset of otf, ttf, and woff2 fonts, allowing for precise control over package size."
version = "7.1.0"
version = "7.2.0"
edition = "2021"
authors = ["KonghaYao<[email protected]>"]
homepage = "https://chinese-font.netlify.app/"
Expand All @@ -22,6 +22,7 @@ unicode-range = { version = "0.1.0", path = "crates/unicode_range" }
woff = "0.3.4"
current_platform = "0.2.0"
chrono = "0.4.38"
regex = "1.11.1"

[dev-dependencies]
env_logger = "0.11.6"
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn main_test() {
// auto_subset: Some(false),
// font_feature: Some(false),
// reduce_mins: Some(false),

// rename_output_font: Some("font_[hash:6].[ext]".to_string()),
..Default::default()
};

Expand Down
12 changes: 8 additions & 4 deletions src/link_subset/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
pub(crate) mod name_template;
mod output_css;
use crate::{message::EventFactory, runner::Context};
use cn_font_proto::{api_interface::EventMessage, INDEX_PROTO};

const HTML_TEMPLATE: &[u8] = include_bytes!("./index.html");
pub fn link_subset(ctx: &mut Context) {
let css = ctx.input.css.clone().unwrap_or_default();
Expand All @@ -12,10 +14,12 @@ pub fn link_subset(ctx: &mut Context) {
&file_name,
css_code.as_bytes().to_vec(),
));
(ctx.callback)(EventMessage::output_data(
"index.html",
HTML_TEMPLATE.to_vec(),
));
if ctx.input.test_html.unwrap_or(true) {
(ctx.callback)(EventMessage::output_data(
"index.html",
HTML_TEMPLATE.to_vec(),
));
}
(ctx.callback)(EventMessage::output_data(
"index.proto",
INDEX_PROTO.to_vec(),
Expand Down
134 changes: 134 additions & 0 deletions src/link_subset/name_template.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use cn_font_utils::slice_string;
use regex::Regex;
use std::collections::HashMap;

type Replacer = Box<dyn Fn(Option<&str>) -> String>;

fn create_replacer(value: impl Into<String>) -> Replacer {
let value_str = value.into();
Box::new(move |_| value_str.clone())
}

fn create_length_replacer(replacer: Replacer) -> Replacer {
Box::new(move |arg| {
if let Some(length_arg) = arg {
if let Ok(length) = length_arg.parse::<usize>() {
return replacer(None).chars().take(length).collect();
}
}
replacer(None)
})
}

pub fn name_template(
template: &str,
hash: &str,
ext: &str,
index: &usize,
) -> String {
let mut replacements: HashMap<String, Replacer> = HashMap::new();
// 添加索引占位符的替换函数。
replacements
.insert("index".to_string(), create_replacer(index.to_string()));
replacements.insert("ext".to_string(), create_replacer(ext));

// 添加哈希占位符的替换函数,这里同时使用'md5'作为别名。
replacements.insert(
"hash".to_string(),
create_length_replacer(create_replacer(hash)),
);
replacements.insert(
"md5".to_string(),
create_length_replacer(create_replacer(hash)),
);

// 编译正则表达式
let re = Regex::new(r"\[\\*([\w:]+)\\*\]").unwrap();

re.replace_all(template, |caps: &regex::Captures| {
let text = caps.get(0).map_or("", |m| m.as_str());
// 判断是否为简单的占位符(无参数)。
if text.len() > 2 {
let inner_tag = slice_string(text, 1, -1);
// 尝试解析占位符的类型和参数。
if let Some(captures) =
Regex::new(r"^(\w+)(?::(\w+))?$").unwrap().captures(&inner_tag)
{
let kind = captures.get(1).map_or("", |m| m.as_str());
let arg = captures.get(2).map_or("", |m| m.as_str());

// 获取对应的替换函数,并应用参数进行替换。
if let Some(replacer) = replacements.get(kind) {
return replacer(Some(arg)).to_owned();
}
}
} else if caps.get(1).map_or(false, |m| !m.as_str().is_empty()) {
let inner_tag = slice_string(text, 2, -2);
// 处理转义的字符。
return format!("[{}]", inner_tag);
}
// 对无法识别的匹配项,原样返回。
caps[0].to_string()
})
.to_string()
}

#[test]
fn test_simple_placeholder() {
let template = "file_[hash].[ext]";
let hash = "d41d8cd98f00b204e9800998ecf8427e";
let ext = "txt";
let index = 1;
let result = name_template(template, hash, ext, &index);
assert_eq!(result, format!("file_{}.{}", hash, ext));
}

#[test]
fn test_parameterized_placeholder() {
let template = "short_hash_[hash:8]";
let hash = "d41d8cd98f00b204e9800998ecf8427e";
let ext = "txt";
let index = 1;
let result = name_template(template, hash, ext, &index);
assert_eq!(result, format!("short_hash_{}", &hash[..8]));
}

#[test]
fn test_escaped_placeholder() {
let template = r"file_[\ext\]";
let hash = "d41d8cd98f00b204e9800998ecf8427e";
let ext = "txt";
let index = 1;
let result = name_template(template, hash, ext, &index);
assert_eq!(result, "file_[ext]");
}

#[test]
fn test_alias_placeholder() {
let template = "alias_$(md5)";
let hash = "d41d8cd98f00b204e9800998ecf8427e";
let ext = "txt";
let index = 1;
let result = name_template(template, hash, ext, &index);
assert_eq!(result, format!("alias_{}", hash));
}

#[test]
fn test_nonexistent_placeholder() {
let template = "prefix_$(nonexistent)_suffix";
let hash = "d41d8cd98f00b204e9800998ecf8427e";
let ext = "txt";
let index = 1;
let result = name_template(template, hash, ext, &index);
assert_eq!(result, template); // Should remain unchanged
}

#[test]
fn test_index_placeholder() {
let template = "item_[index]";
let hash = "d41d8cd98f00b204e9800998ecf8427e";
let ext = "txt";
let index = 42;
let result = name_template(template, hash, ext, &index);
assert_eq!(result, "item_42");
}
5 changes: 1 addition & 4 deletions src/link_subset/output_css.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ pub fn output_css(ctx: &mut Context, css: &CssProperties) -> String {
.map(|res| {
let src_str: String = [
locals.join(","),
format!(
r#"url("./{}")format("woff2")"#,
res.hash.clone() + ".woff2"
),
format!(r#"url("./{}")format("woff2")"#, res.file_name.clone()),
]
.join(",")
+ polyfill_str.as_str();
Expand Down
16 changes: 11 additions & 5 deletions src/run_subset.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::link_subset::name_template::name_template;
use crate::message::EventFactory;
use crate::runner::Context;
use cn_font_proto::api_interface::output_report::{
Expand Down Expand Up @@ -40,7 +41,7 @@ pub fn run_subset(ctx: &mut Context) {
ctx.face.collect_unicodes().iter().map(|x| x.clone()),
);
let origin_size: u32 = all_chars.len().try_into().unwrap();

let file_name_template = ctx.input.rename_output_font.clone();
info!("font subset result log");
let thread_result: Vec<ThreadResult> = ctx
.pre_subset_result
Expand All @@ -63,22 +64,26 @@ pub fn run_subset(ctx: &mut Context) {
result_bytes,
hash_string.to_string()
);
let file_name = if let Some(name) = &file_name_template {
name_template(&name, &hash_string, "woff2", &index)
} else {
hash_string.to_string() + ".woff2"
};
ThreadResult {
subset_result: RunSubsetResult {
hash: hash_string.to_string(),
unicodes: r.clone(),
file_name: file_name.clone(),
},
log: SubsetDetail {
id: (index as u32) + 1_u32,
file_name: file_name.clone(),
hash: hash_string.to_string(),
chars: r.clone(),
bytes: result.len() as u32,
duration: duration.as_millis() as u32,
},
message: EventMessage::output_data(
(hash_string.to_string() + ".woff2").as_str(),
result,
),
message: EventMessage::output_data(&file_name, result),
}
})
.collect::<Vec<ThreadResult>>();
Expand Down Expand Up @@ -124,4 +129,5 @@ pub fn run_subset(ctx: &mut Context) {
pub struct RunSubsetResult {
pub hash: String,
pub unicodes: Vec<u32>,
pub file_name: String,
}
4 changes: 3 additions & 1 deletion src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ pub fn font_split<F: Fn(EventMessage)>(config: InputTemplate, callback: F) {
let mut reporter_buffer = Vec::new();
ctx.reporter.encode(&mut reporter_buffer).unwrap();

callback(EventMessage::output_data("reporter.bin", reporter_buffer));
if ctx.input.reporter.unwrap_or(true) {
callback(EventMessage::output_data("reporter.bin", reporter_buffer));
}

// 发送一个结束信息
callback(EventMessage::create_end_message());
Expand Down

0 comments on commit 0ed3832

Please sign in to comment.