Merge #358: Replace every occurrence in edit.findReplace when replacement contains find (@Silvertree2010)

This commit is contained in:
bflatastic
2026-10-15 17:53:06 +07:00
2 changed files with 33 additions and 4 deletions
+11 -4
View File
@@ -1012,13 +1012,20 @@ fn find_replace(s: &mut Session, p: &Value) -> Result<Value> {
}
if let NodeKind::Text(t) = &mut n.kind {
// Replace occurrence by occurrence so styles shift correctly.
// The search resumes after each inserted replacement, so a replacement that
// contains `find` neither loops forever nor stops the other occurrences.
let mut guard = 0;
while let Some(pos) = t.characters.find(find.as_str()) {
let start = t.characters.get(..pos).map(|x| x.chars().count()).unwrap_or(0);
let len = find.chars().count();
let mut cursor = 0;
let len = find.chars().count();
let r_len = r.chars().count();
loop {
let from = t.characters.char_indices().nth(cursor).map_or(t.characters.len(), |(b, _)| b);
let Some(pos) = t.characters.get(from..).and_then(|tail| tail.find(find.as_str())) else { break };
let start = cursor + t.characters.get(from..from + pos).map_or(0, |x| x.chars().count());
t.replace_range(start, start + len, r);
cursor = start + r_len;
guard += 1;
if guard > 10_000 || r.contains(find.as_str()) {
if guard > 10_000 {
break;
}
}
+22
View File
@@ -161,6 +161,28 @@ fn text_create_autosize_and_edit() {
assert_eq!(s.doc().unwrap().node(t).unwrap().kind.text().unwrap().characters, "Hello");
}
#[test]
fn find_replace_replaces_every_occurrence_when_replacement_contains_find() {
for (text, find, replace, want) in [
("cat and cat", "cat", "cats", "cats and cats"),
("cat and cat", "cat", "category", "category and category"),
("banana", "a", "aa", "baanaanaa"),
] {
let mut s = sess();
let t = id(&s.execute("text.create", &json!({"text": text, "x": 0, "y": 0})).unwrap());
s.execute("edit.findReplace", &json!({"find": find, "replace": replace})).unwrap();
assert_eq!(s.doc().unwrap().node(t).unwrap().kind.text().unwrap().characters, want, "{text}: {find} -> {replace}");
}
}
#[test]
fn find_replace_rejects_empty_find() {
let mut s = sess();
let t = id(&s.execute("text.create", &json!({"text": "cat", "x": 0, "y": 0})).unwrap());
assert!(s.execute("edit.findReplace", &json!({"find": "", "replace": "x"})).is_err());
assert_eq!(s.doc().unwrap().node(t).unwrap().kind.text().unwrap().characters, "cat");
}
#[test]
fn components_and_instances_sync() {
let mut s = sess();