LRC-LIB-KEYWORDS: renaming keeps the levels below whatever the case
Renaming a keyword cut the keywords below it at the byte length of the name as typed. Names match whatever their case, but some letters change length with it (ẞ is three bytes, ß two): `STRAẞE` → `Road` turned `straße|nord` into `Roadnord`, and a cut inside a letter would panic. The levels below are now kept whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
411daefa68
commit
cd8dfa72c2
|
|
@ -30,10 +30,12 @@ pub fn is_under(k: &str, parent: &str) -> bool {
|
|||
k == p || k.strip_prefix(&p).is_some_and(|rest| rest.starts_with(SEP))
|
||||
}
|
||||
|
||||
/// Replace the `from` prefix of `k` (which [`is_under`] `from`) with `to`.
|
||||
/// Replace the `from` prefix of `k` (which [`is_under`] `from`) with `to`. By levels, not bytes:
|
||||
/// `from` may be written in another case, which can change a letter's length (ẞ / ß).
|
||||
fn reparent(k: &str, from: &str, to: &str) -> String {
|
||||
let rest = &k[from.len().min(k.len())..];
|
||||
if to.is_empty() { rest.trim_start_matches(SEP).to_string() } else { format!("{to}{rest}") }
|
||||
let skip = from.split(SEP).filter(|s| !s.trim().is_empty()).count();
|
||||
let rest: Vec<&str> = k.split(SEP).filter(|s| !s.trim().is_empty()).skip(skip).collect();
|
||||
std::iter::once(to).filter(|t| !t.is_empty()).chain(rest).collect::<Vec<_>>().join("|")
|
||||
}
|
||||
|
||||
/// Keep the first of case-insensitively equal keywords.
|
||||
|
|
@ -478,6 +480,19 @@ mod tests {
|
|||
assert_eq!(c.to_snapshot(), before);
|
||||
}
|
||||
|
||||
/// Renaming matches names whatever their case, also where a letter's case changes its length
|
||||
/// (ẞ is three bytes, ß two): the levels below are kept whole, never cut mid-letter.
|
||||
#[test]
|
||||
fn renaming_keeps_the_levels_below_whatever_the_case() {
|
||||
let (mut c, ids) = lib(&[&["straße|nord"], &["ßa|ü"]]);
|
||||
let op = c.rename_keyword_ops("STRAẞE", "Road").unwrap();
|
||||
c.apply(op).unwrap();
|
||||
assert_eq!(kws(&c, ids[0]), ["Road|nord"]);
|
||||
let op = c.rename_keyword_ops("ẞA", "Weg").unwrap();
|
||||
c.apply(op).unwrap();
|
||||
assert_eq!(kws(&c, ids[1]), ["Weg|ü"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suggestions_rank_co_occurrence_and_prefixes() {
|
||||
let (c, _) = lib(&[&["dog", "park"], &["dog", "park", "ball"], &["dog", "beach"], &["cat"], &["cat"], &["cat"], &["parade"], &["eagle"]]);
|
||||
|
|
|
|||
Loading…
Reference in New Issue