hyprcorrect_core/
replace.rs1use crate::buffer::WordAtCaret;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct Edit {
17 pub backspaces: usize,
19 pub deletes: usize,
21 pub insert: String,
23}
24
25pub fn plan_word_replacement(at: &WordAtCaret, correction: &str) -> Option<Edit> {
32 if correction == at.word {
33 return None;
34 }
35 let trailing_chars = at.trailing.chars().count();
36 Some(Edit {
37 backspaces: at.chars_before_caret + trailing_chars,
40 deletes: at.chars_after_caret,
43 insert: format!("{correction}{}", at.trailing),
46 })
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 fn word_at_end(word: &str, trailing: &str) -> WordAtCaret {
54 WordAtCaret {
55 word: word.to_string(),
56 trailing: trailing.to_string(),
57 chars_before_caret: word.chars().count(),
58 chars_after_caret: 0,
59 }
60 }
61
62 #[test]
63 fn replaces_word_and_keeps_the_trailing_space() {
64 let edit = plan_word_replacement(&word_at_end("vernuer", " "), "veneer").unwrap();
65 assert_eq!(
66 edit,
67 Edit {
68 backspaces: 8,
69 deletes: 0,
70 insert: "veneer ".to_string(),
71 }
72 );
73 }
74
75 #[test]
76 fn replaces_word_with_no_trailing_whitespace() {
77 let edit = plan_word_replacement(&word_at_end("vernuer", ""), "veneer").unwrap();
78 assert_eq!(edit.backspaces, 7);
79 assert_eq!(edit.deletes, 0);
80 assert_eq!(edit.insert, "veneer");
81 }
82
83 #[test]
84 fn no_edit_when_the_word_is_already_correct() {
85 assert_eq!(
86 plan_word_replacement(&word_at_end("veneer", " "), "veneer"),
87 None
88 );
89 }
90
91 #[test]
92 fn backspace_count_covers_all_trailing_whitespace() {
93 let edit = plan_word_replacement(&word_at_end("x", " "), "y").unwrap();
94 assert_eq!(edit.backspaces, 4);
95 assert_eq!(edit.deletes, 0);
96 assert_eq!(edit.insert, "y ");
97 }
98
99 #[test]
100 fn caret_inside_word_splits_into_backspaces_plus_deletes() {
101 let at = WordAtCaret {
103 word: "vernuer".to_string(),
104 trailing: String::new(),
105 chars_before_caret: 3,
106 chars_after_caret: 4,
107 };
108 let edit = plan_word_replacement(&at, "veneer").unwrap();
109 assert_eq!(edit.backspaces, 3);
110 assert_eq!(edit.deletes, 4);
111 assert_eq!(edit.insert, "veneer");
112 }
113
114 #[test]
115 fn count_is_in_characters_not_bytes() {
116 let edit = plan_word_replacement(&word_at_end("café", " "), "coffee").unwrap();
119 assert_eq!(edit.backspaces, 5);
120 assert_eq!(edit.insert, "coffee ");
121 }
122}