mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:01:29 +00:00
M6: a custom stamp's line fills in the template's placeholders only (#1741)
Review on #2345 (gabglus): the line was filled by chained replaces, so a placeholder inside the author's name ("Ada {date}") was filled in too. stamp_line now walks the template once and expands only the {name}, {date} and {time} it finds there; the author's text is kept as written. Trimming and the MAX_STAMP_LINE cut are unchanged. The loop advances by whole characters (strip_prefix, or get() past the next char), so it cannot panic. stamp_lines_fill_in_the_name_date_and_time gains the review's case and a name made only of a placeholder; both fail with the chained replaces. The UI test checks the saved /PCByLine has no placeholder left (from gabglus's commit f6760b37). Co-Authored-By: gabglus <gabglus@hotmail.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
00566d74ea
commit
f5575cf782
3 files changed
+37
-1
No files matched your search
@@ -74,7 +74,25 @@ impl Session {
|
||||
/// stamps' "By" line has them. Cut to [`MAX_STAMP_LINE`](crate::MAX_STAMP_LINE) characters.
|
||||
pub fn stamp_line(&self, template: &str, author: &str) -> String {
|
||||
let (date, time) = self.stamp_date_time();
|
||||
let filled = template.trim().replace("{name}", author.trim()).replace("{date}", &date).replace("{time}", &time);
|
||||
// One pass over the template, so a placeholder the author's name happens to contain
|
||||
// (`Ada {date}`) stays as written rather than being filled in too.
|
||||
let mut filled = String::new();
|
||||
let mut rest = template.trim();
|
||||
while let Some(c) = rest.chars().next() {
|
||||
if let Some(after) = rest.strip_prefix("{name}") {
|
||||
filled.push_str(author.trim());
|
||||
rest = after;
|
||||
} else if let Some(after) = rest.strip_prefix("{date}") {
|
||||
filled.push_str(&date);
|
||||
rest = after;
|
||||
} else if let Some(after) = rest.strip_prefix("{time}") {
|
||||
filled.push_str(&time);
|
||||
rest = after;
|
||||
} else {
|
||||
filled.push(c);
|
||||
rest = rest.get(c.len_utf8()..).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
filled.chars().take(crate::MAX_STAMP_LINE).collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -9420,6 +9420,9 @@ fn repeated_backdrop_artwork_survives_background_undo_redo_and_both_save_modes()
|
||||
fn stamp_lines_fill_in_the_name_date_and_time() {
|
||||
let s = Session::new().with_clock(|| 1_700_000_000);
|
||||
assert_eq!(s.stamp_line("Received {date} {time} by {name}", " Ada "), "Received Nov 14, 2023 10:13 pm by Ada");
|
||||
// Review on #2345 (gabglus): placeholders inside the author's name are kept as written.
|
||||
assert_eq!(s.stamp_line("By {name} — {date} {time}", "Ada {date} {time}"), "By Ada {date} {time} — Nov 14, 2023 10:13 pm");
|
||||
assert_eq!(s.stamp_line("{name}{name}", "{name}"), "{name}{name}");
|
||||
assert_eq!(s.stamp_by_line("Ada"), "By Ada at 10:13 pm, Nov 14, 2023");
|
||||
assert_eq!(s.stamp_by_line(""), "at 10:13 pm, Nov 14, 2023");
|
||||
assert_eq!(s.stamp_line(&"{date}".repeat(100), "Ada").chars().count(), MAX_STAMP_LINE);
|
||||
|
||||
@@ -177,6 +177,21 @@ fn a_dynamic_custom_stamp_keeps_its_line_and_fills_it_in_when_placed() {
|
||||
h.drop_at(p);
|
||||
h.run_steps(4);
|
||||
let s = h.state();
|
||||
let saved = s.session.save_bytes(s.views[0].id).unwrap();
|
||||
let pdf = pdfcraft_cos::Document::open(saved).unwrap();
|
||||
let line = pdf
|
||||
.scan_objects()
|
||||
.find_map(|(_, object)| match object.as_ref() {
|
||||
pdfcraft_cos::Object::Dict(dict) => dict.get(b"PCByLine").and_then(pdfcraft_cos::Object::as_string).map(pdfcraft_cos::PdfString::to_text),
|
||||
_ => None,
|
||||
})
|
||||
.expect("placed custom stamp stores PCByLine in the PDF");
|
||||
assert!(line.starts_with("By Ada at "), "expanded stamp line: {line:?}");
|
||||
assert!(
|
||||
!line.contains("{name}") && !line.contains("{date}") && !line.contains("{time}"),
|
||||
"the saved stamp line must not contain unexpanded placeholders: {line:?}"
|
||||
);
|
||||
|
||||
let doc = s.session.get(s.views[0].id).unwrap();
|
||||
let r = doc.info.annotations.iter().find(|a| a.subtype == "Stamp").expect("placed").rect;
|
||||
let aspect = (r[2] - r[0]) / (r[3] - r[1]);
|
||||
|
||||
Reference in new issue
Block a user