sudachi/input_text/buffer/
edit.rs

1/*
2 *  Copyright (c) 2021 Works Applications Co., Ltd.
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *   Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16
17use crate::input_text::buffer::REALLY_MAX_LENGTH;
18use std::ops::Range;
19
20#[derive(Clone)]
21pub struct ReplaceOp<'a> {
22    what: Range<usize>,
23    with: ReplaceTgt<'a>,
24}
25
26#[derive(Clone)]
27enum ReplaceTgt<'a> {
28    Ref(&'a str),
29    Char(char),
30    Str(String),
31}
32
33pub struct InputEditor<'a> {
34    replaces: &'a mut Vec<ReplaceOp<'a>>,
35}
36
37impl<'a> InputEditor<'a> {
38    pub(super) fn new(replaces: &'a mut Vec<ReplaceOp<'a>>) -> InputEditor {
39        InputEditor { replaces }
40    }
41
42    /// Replace range with a &str
43    pub fn replace_ref(&mut self, range: Range<usize>, result: &'a str) {
44        let op = ReplaceOp {
45            what: range,
46            with: ReplaceTgt::Ref(result),
47        };
48        self.replaces.push(op);
49    }
50
51    /// Replace range with char
52    pub fn replace_char(&mut self, range: Range<usize>, result: char) {
53        let op = ReplaceOp {
54            what: range,
55            with: ReplaceTgt::Char(result),
56        };
57        self.replaces.push(op);
58    }
59
60    /// Replace range with owned String
61    pub fn replace_own(&mut self, range: Range<usize>, result: String) {
62        let op = ReplaceOp {
63            what: range,
64            with: ReplaceTgt::Str(result),
65        };
66        self.replaces.push(op);
67    }
68
69    /// Replace range with char, followed by chars from iterator
70    pub fn replace_char_iter<It>(&mut self, range: Range<usize>, ch: char, mut rest: It)
71    where
72        It: Iterator<Item = char>,
73    {
74        match rest.next() {
75            None => self.replace_char(range, ch),
76            Some(ch2) => {
77                let mut s = String::with_capacity(12); //4 japanese chars
78                s.push(ch);
79                s.push(ch2);
80                s.extend(rest);
81                self.replace_own(range, s)
82            }
83        }
84    }
85}
86
87// Edits are assumed to be sorted (from start to end) and non-overlapping.
88// This is not checked right now (may be we should check this in debug mode)
89// Current plugin implementations satisfy this criteria.
90pub fn resolve_edits(
91    source: &str,
92    source_mapping: &Vec<usize>,
93    target: &mut String,
94    target_mapping: &mut Vec<usize>,
95    edits: &mut Vec<ReplaceOp>,
96) -> usize {
97    let mut start: usize = 0;
98    let mut cur_len: isize = source.len() as isize;
99    for edit in edits.drain(..) {
100        target.push_str(&source[start..edit.what.start]);
101        target_mapping.extend(source_mapping[start..edit.what.start].iter());
102        start = edit.what.end;
103        cur_len += match edit.with {
104            ReplaceTgt::Str(s) => {
105                add_replace(source_mapping, target, target_mapping, edit.what, &s)
106            }
107            ReplaceTgt::Ref(s) => add_replace(source_mapping, target, target_mapping, edit.what, s),
108            ReplaceTgt::Char(c) => add_replace(
109                source_mapping,
110                target,
111                target_mapping,
112                edit.what,
113                c.encode_utf8(&mut [0; 4]),
114            ),
115        };
116        if cur_len > REALLY_MAX_LENGTH as isize {
117            return cur_len as usize;
118        }
119    }
120    target.push_str(&source[start..]);
121    target_mapping.extend(source_mapping[start..].iter());
122    // first byte of mapping MUST be 0
123    if let Some(v) = target_mapping.first_mut() {
124        *v = 0;
125    }
126    cur_len as usize
127}
128
129fn add_replace(
130    source_mapping: &Vec<usize>,
131    target: &mut String,
132    target_mapping: &mut Vec<usize>,
133    what: Range<usize>,
134    with: &str,
135) -> isize {
136    if with.is_empty() {
137        return -(what.len() as isize);
138    }
139    target.push_str(with);
140
141    // the first char of replacing string will correspond with whole replaced string
142    target_mapping.push(source_mapping[what.start]);
143    let pos = source_mapping[what.end];
144    for _ in 1..with.len() {
145        target_mapping.push(pos);
146    }
147    with.len() as isize - what.len() as isize
148}
149
150#[cfg(test)]
151mod test {
152    use super::super::InputBuffer;
153    use crate::input_text::InputTextIndex;
154
155    #[test]
156    fn edit_ref_1() {
157        let mut buffer = InputBuffer::from("宇宙人");
158        buffer
159            .with_editor(|_, mut r| {
160                r.replace_ref(3..6, "銀");
161                Ok(r)
162            })
163            .expect("should not break");
164        assert_eq!(0, buffer.replaces.len());
165        assert_eq!(buffer.current(), "宇銀人");
166        assert_eq!(buffer.orig_slice(3..6), "宙");
167    }
168
169    #[test]
170    fn edit_char_1() {
171        let mut buffer = InputBuffer::from("宇宙人");
172        buffer
173            .with_editor(|_, mut r| {
174                r.replace_char(3..6, '銀');
175                Ok(r)
176            })
177            .expect("should not break");
178        assert_eq!(0, buffer.replaces.len());
179        assert_eq!(buffer.current(), "宇銀人");
180        assert_eq!(buffer.orig_slice(3..6), "宙");
181    }
182
183    #[test]
184    fn edit_ref_2_borrow() {
185        let s = String::from("銀");
186        let mut buffer = InputBuffer::from("宇宙人");
187        buffer
188            .with_editor(|_, mut r| {
189                r.replace_ref(3..6, &s);
190                Ok(r)
191            })
192            .expect("should not break");
193        assert_eq!(0, buffer.replaces.len());
194        assert_eq!(buffer.current(), "宇銀人");
195    }
196
197    #[test]
198    fn edit_str_1() {
199        let mut buffer = InputBuffer::from("宇宙人");
200        buffer
201            .with_editor(|_, mut r| {
202                r.replace_own(3..6, String::from("銀"));
203                Ok(r)
204            })
205            .expect("should not break");
206        assert_eq!(0, buffer.replaces.len());
207        assert_eq!(buffer.current(), "宇銀人");
208        assert_eq!(buffer.orig_slice(3..6), "宙");
209    }
210
211    #[test]
212    fn replace_start_w_longer() {
213        let mut buffer = InputBuffer::from("宇宙人");
214        buffer
215            .with_editor(|_, mut r| {
216                r.replace_ref(0..3, "銀河");
217                Ok(r)
218            })
219            .expect("should not break");
220        assert_eq!(0, buffer.replaces.len());
221        assert_eq!(buffer.m2o, &[0, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9]);
222        assert_eq!(buffer.current(), "銀河宙人");
223        assert_eq!(buffer.orig_slice(0..6), "宇");
224        assert_eq!(buffer.orig_slice(0..3), "宇");
225        assert_eq!(buffer.orig_slice(3..6), "");
226    }
227
228    #[test]
229    fn replace_mid_w_longer() {
230        let mut buffer = InputBuffer::from("宇宙人");
231        buffer
232            .with_editor(|_, mut r| {
233                r.replace_ref(3..6, "銀河");
234                Ok(r)
235            })
236            .expect("should not break");
237        assert_eq!(0, buffer.replaces.len());
238        assert_eq!(buffer.m2o, &[0, 1, 2, 3, 6, 6, 6, 6, 6, 6, 7, 8, 9]);
239        assert_eq!(buffer.current(), "宇銀河人");
240        assert_eq!(buffer.orig_slice(3..9), "宙");
241        assert_eq!(buffer.orig_slice(3..6), "宙");
242        assert_eq!(buffer.orig_slice(6..9), "");
243    }
244
245    #[test]
246    fn replace_end_w_longer() {
247        let mut buffer = InputBuffer::from("宇宙人");
248        buffer
249            .with_editor(|_, mut r| {
250                r.replace_ref(6..9, "銀河");
251                Ok(r)
252            })
253            .expect("should not break");
254        assert_eq!(0, buffer.replaces.len());
255        assert_eq!(buffer.m2o, &[0, 1, 2, 3, 4, 5, 6, 9, 9, 9, 9, 9, 9]);
256        assert_eq!(buffer.current(), "宇宙銀河");
257        assert_eq!(buffer.orig_slice(6..12), "人");
258        assert_eq!(buffer.orig_slice(6..9), "人");
259        assert_eq!(buffer.orig_slice(9..12), "");
260    }
261
262    #[test]
263    fn replace_start_w_shorter() {
264        let mut buffer = InputBuffer::from("宇宙人");
265        buffer
266            .with_editor(|_, mut r| {
267                r.replace_ref(0..6, "河");
268                Ok(r)
269            })
270            .expect("should not break");
271        assert_eq!(0, buffer.replaces.len());
272        assert_eq!(buffer.current(), "河人");
273        assert_eq!(buffer.m2o, &[0, 6, 6, 6, 7, 8, 9]);
274        assert_eq!(buffer.orig_slice(0..3), "宇宙");
275        assert_eq!(buffer.orig_slice(3..6), "人");
276    }
277
278    #[test]
279    fn replace_end_w_shorter() {
280        let mut buffer = InputBuffer::from("宇宙人");
281        buffer
282            .with_editor(|_, mut r| {
283                r.replace_ref(3..9, "河");
284                Ok(r)
285            })
286            .expect("should not break");
287        assert_eq!(0, buffer.replaces.len());
288        assert_eq!(buffer.current(), "宇河");
289        assert_eq!(buffer.m2o, &[0, 1, 2, 3, 9, 9, 9]);
290        assert_eq!(buffer.orig_slice(0..3), "宇");
291        assert_eq!(buffer.orig_slice(3..6), "宙人");
292    }
293
294    #[test]
295    fn replace_start_w_none() {
296        let mut buffer = InputBuffer::from("宇宙人");
297        buffer
298            .with_editor(|_, mut r| {
299                r.replace_ref(0..6, "");
300                Ok(r)
301            })
302            .expect("should not break");
303        assert_eq!(0, buffer.replaces.len());
304        assert_eq!(buffer.current(), "人");
305        assert_eq!(buffer.m2o, &[0, 7, 8, 9]);
306        assert_eq!(buffer.orig_slice(0..3), "宇宙人");
307    }
308
309    #[test]
310    fn replace_start_w_none_2() {
311        let mut buffer = InputBuffer::from("宇宙人");
312        buffer
313            .with_editor(|_, mut r| {
314                r.replace_ref(0..3, "");
315                Ok(r)
316            })
317            .expect("should not break");
318        assert_eq!(0, buffer.replaces.len());
319        assert_eq!(buffer.current(), "宙人");
320        assert_eq!(buffer.m2o, &[0, 4, 5, 6, 7, 8, 9]);
321        assert_eq!(buffer.orig_slice(0..3), "宇宙");
322        assert_eq!(buffer.orig_slice(3..6), "人");
323    }
324
325    #[test]
326    fn replace_end_w_none() {
327        let mut buffer = InputBuffer::from("宇宙人");
328        buffer
329            .with_editor(|_, mut r| {
330                r.replace_ref(3..9, "");
331                Ok(r)
332            })
333            .expect("should not break");
334        assert_eq!(0, buffer.replaces.len());
335        assert_eq!(buffer.current(), "宇");
336        assert_eq!(buffer.m2o, &[0, 1, 2, 9]);
337        assert_eq!(buffer.orig_slice(0..3), "宇宙人");
338    }
339
340    #[test]
341    fn replace_diff_width() {
342        let mut buffer = InputBuffer::from("âbC1あ");
343        buffer
344            .with_editor(|_, mut r| {
345                r.replace_ref(0..2, "a");
346                r.replace_ref(2..5, "b");
347                r.replace_ref(5..6, "c");
348                Ok(r)
349            })
350            .expect("should not break");
351        assert_eq!(0, buffer.replaces.len());
352        assert_eq!(buffer.current(), "abc1あ");
353        assert_eq!(buffer.m2o, &[0, 2, 5, 6, 7, 8, 9, 10]);
354        assert_eq!(buffer.orig_slice(0..3), "âbC");
355        assert_eq!(buffer.orig_slice(0..1), "â");
356        assert_eq!(buffer.orig_slice(1..2), "b");
357        assert_eq!(buffer.orig_slice(2..3), "C");
358    }
359
360    #[test]
361    fn replace_with_more_cnt() {
362        let mut buffer = InputBuffer::from("あ");
363        buffer
364            .with_editor(|_, mut r| {
365                r.replace_ref(0..3, "abc");
366                Ok(r)
367            })
368            .expect("should not break");
369        assert_eq!(0, buffer.replaces.len());
370        assert_eq!(buffer.current(), "abc");
371        assert_eq!(buffer.m2o, &[0, 3, 3, 3]);
372        assert_eq!(buffer.orig_slice(0..3), "あ");
373        assert_eq!(buffer.orig_slice(0..1), "あ");
374        assert_eq!(buffer.orig_slice(1..2), "");
375        assert_eq!(buffer.orig_slice(2..3), "");
376    }
377}