1use console::{Key, Term};
27use std::io;
28use std::io::Write;
29
30const MAX_PREFIX_CAPACITY: usize = 32;
31const DEFAULT_TEXT_CAPACITY: usize = 1024;
32
33pub struct Buffer {
36 debug: bool,
38 pub double_line_response: bool,
40 pub terminate_on_up_down: bool,
42 term: Term,
43 index: usize,
45 prefix: String,
47 text: String,
49}
50
51impl ToString for Buffer {
52 fn to_string(&self) -> String {
53 self.text.clone()
54 }
55}
56
57impl Drop for Buffer {
58 fn drop(&mut self) {
59 self.double_line_response = false;
60 self.index = 0;
61 self.text.clear();
62 }
63}
64
65impl std::fmt::Debug for Buffer {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 f.debug_struct("Buffer")
68 .field("debug", &self.debug)
69 .field("double_line_response", &self.double_line_response)
70 .field("terminate_on_up_down", &self.terminate_on_up_down)
71 .field("index", &self.index)
72 .field("text", &self.text);
73 Ok(())
74 }
75}
76
77impl Clone for Buffer {
78 fn clone(&self) -> Self {
79 Self {
80 debug: self.debug,
81 double_line_response: self.double_line_response,
82 terminate_on_up_down: self.terminate_on_up_down,
83 term: self.term.clone(),
84 index: self.index,
85 prefix: self.prefix.clone(),
86 text: self.text.clone(),
87 }
88 }
89}
90
91impl Buffer {
92 pub fn new() -> Self {
95 Buffer {
96 debug: false,
97 double_line_response: false,
98 terminate_on_up_down: false,
99 term: Term::stdout(),
100 index: 0,
101 prefix: String::with_capacity(MAX_PREFIX_CAPACITY),
102 text: String::with_capacity(DEFAULT_TEXT_CAPACITY),
103 }
104 }
105
106 pub fn from(text: &str) -> Self {
109 Buffer {
110 debug: false,
111 double_line_response: false,
112 terminate_on_up_down: false,
113 term: Term::stdout(),
114 index: 0,
115 prefix: String::with_capacity(MAX_PREFIX_CAPACITY),
116 text: String::from(text),
117 }
118 }
119
120 pub fn debug(&mut self) {
123 self.debug = true;
124 }
125
126 fn enter(&mut self) -> io::Result<Key> {
127 if self.double_line_response {
128 self.text.insert(self.index, '\n');
129 }
130 Ok(Key::Enter)
131 }
132 fn home(&mut self) -> io::Result<Key> {
133 self.term.move_cursor_left(self.index)?;
134 self.index = 0;
135 Ok(Key::Home)
136 }
137 fn end(&mut self) -> io::Result<Key> {
138 self.term.move_cursor_right(self.text.len() - self.index)?;
139 self.index = self.text.len();
140 Ok(Key::End)
141 }
142 fn char(&mut self, x: char) -> io::Result<Key> {
143 self.term.move_cursor_right(self.text.len() - self.index)?;
144 self.term.clear_chars(self.text.len() - self.index)?;
145 self.text.insert(self.index, x);
146 write!(&self.term, "{}", &self.text[self.index..self.text.len()])?;
147 self.index += 1;
148 self.term.move_cursor_left(self.text.len() - self.index)?;
149 Ok(Key::Char(x))
150 }
151 fn backspace(&mut self) -> io::Result<Key> {
152 if self.index > 0 {
153 self.term.clear_line()?;
154 self.term
155 .move_cursor_left(self.text.len() + self.prefix.len())?;
156 write!(&self.term, "{}", self.prefix)?;
157 self.text.remove(self.index - 1);
158 self.index -= 1;
159 write!(&self.term, "{}", self.text)?;
160 self.term.move_cursor_left(self.text.len() - self.index)?;
161 }
162 Ok(Key::Backspace)
163 }
164 fn del(&mut self) -> io::Result<Key> {
165 if self.text.len() > 0 && self.text.len() > self.index {
166 self.text.remove(self.index);
167 self.term.clear_line()?;
168 write!(&self.term, "{}", self.text)?;
169 self.term.move_cursor_left(self.text.len() - self.index)?;
170 }
171 Ok(Key::Del)
172 }
173 fn esc(&mut self) -> io::Result<()> {
174 match self.term.read_key()? {
175 Key::Char('f') => {
176 self.word_forward()?;
177 }
178 Key::Char('b') => {
179 self.word_backword()?;
180 }
181 Key::Char('d') => {
182 self.word_delete()?;
183 }
184 Key::Backspace => {
185 self.word_backspace()?;
186 }
187 _ => {}
188 }
189 Ok(())
190 }
191
192 fn word_forward(&mut self) -> io::Result<()> {
193 let mut separater_ids = self
194 .text
195 .match_indices(' ')
196 .map(|t| t.0)
197 .collect::<Vec<usize>>();
198 separater_ids.push(self.text.len());
199 for i in separater_ids {
200 if i > self.index {
201 self.term.move_cursor_right(i - self.index)?;
202 self.index = i;
203 break;
204 }
205 }
206 Ok(())
207 }
208
209 fn word_backword(&mut self) -> io::Result<()> {
210 let mut separater_ids = self
211 .text
212 .match_indices(' ')
213 .map(|t| t.0 + 1)
214 .collect::<Vec<usize>>();
215 separater_ids.insert(0, 0);
216 separater_ids.reverse();
217 for i in separater_ids {
218 if self.index > i {
219 self.term.move_cursor_left(self.index - i)?;
220 self.index = i;
221 break;
222 }
223 }
224 Ok(())
225 }
226
227 fn word_backspace(&mut self) -> io::Result<()> {
228 let mut separater_ids = self
229 .text
230 .match_indices(' ')
231 .map(|t| t.0)
232 .filter(|n| *n < self.index)
233 .collect::<Vec<usize>>();
234 separater_ids.insert(0, 0);
235 separater_ids.reverse();
236
237 if self.text.len() != 0 {
238 let target_id = separater_ids[0];
239 let new_text =
240 self.text[0..target_id].to_string() + &self.text[self.index..self.text.len()];
241 self.text.clear();
242 self.text = new_text;
243 self.index = target_id;
244 self.term.clear_line()?;
245 write!(&self.term, "{}", self.text)?;
246 self.term.move_cursor_left(self.text.len() - target_id)?;
247 }
248
249 Ok(())
250 }
251
252 fn word_delete(&mut self) -> io::Result<()> {
253 let mut separater_ids = self
254 .text
255 .match_indices(' ')
256 .map(|t| t.0)
257 .filter(|n| *n > self.index)
258 .collect::<Vec<usize>>();
259 separater_ids.push(self.text.len());
260 let target_id = separater_ids[0];
261 let new_text =
262 self.text[0..self.index].to_string() + &self.text[target_id..self.text.len()];
263 self.text.clear();
264 self.text = new_text;
265 self.term.clear_line()?;
266 write!(&self.term, "{}", self.text)?;
267 self.term.move_cursor_left(self.text.len() - self.index)?;
268 Ok(())
269 }
270
271 fn left(&mut self) -> io::Result<Key> {
272 if self.index > 0 {
273 self.term.move_cursor_left(1)?;
274 self.index -= 1;
275 }
276 Ok(Key::ArrowLeft)
277 }
278 fn right(&mut self) -> io::Result<Key> {
279 if self.index < self.text.len() {
280 self.term.move_cursor_right(1)?;
281 self.index += 1;
282 }
283 Ok(Key::ArrowRight)
284 }
285
286 pub fn set_prefix(&mut self, prefix: String) {
288 self.prefix.clear();
289 self.prefix = prefix;
290 }
291
292 pub fn read_line(&mut self) -> io::Result<Key> {
301 let k: Key;
302
303 write!(&self.term, "{}", self.prefix)?;
304 loop {
305 match self.term.read_key()? {
306 Key::Enter => {
307 k = self.enter()?;
308 break;
309 }
310 Key::Home => {
311 self.home()?;
312 }
313 Key::End => {
314 self.end()?;
315 }
316 Key::ArrowRight => {
317 self.right()?;
318 }
319 Key::ArrowLeft => {
320 self.left()?;
321 }
322 Key::Backspace => {
323 self.backspace()?;
324 }
325 Key::Del => {
326 self.del()?;
327 }
328 Key::Char(x) => {
329 self.char(x)?;
330 }
331 Key::Escape => {
332 self.esc()?;
333 }
334 Key::ArrowUp => {
335 if self.terminate_on_up_down {
336 k = Key::ArrowUp;
337 break;
338 }
339 }
340 Key::ArrowDown => {
341 if self.terminate_on_up_down {
342 k = Key::ArrowDown;
343 break;
344 }
345 }
346 _ => {}
347 }
348 }
349 Ok(k)
350 }
351}
352
353pub fn read_line() -> io::Result<String> {
363 let mut buf = Buffer::new();
364 buf.read_line()?;
365 Ok(buf.to_string())
366}
367
368pub fn read_line2() -> io::Result<String> {
376 let mut buf = Buffer::new();
377 buf.double_line_response = true;
378 buf.read_line()?;
379 Ok(buf.to_string())
380}
381
382#[cfg(test)]
383mod tests {
384 use crate::readline::*;
385
386 const DUMMY_TEXT: &str = "okachimachi koshigaya inogashira suidobashi ochanomidzu";
387 const DUMMY_INDEX: usize = 19;
388
389 fn init_with_word() -> Buffer {
390 let mut buf = Buffer::new();
391 buf.text = "kabukiza".to_string();
392 buf
393 }
394
395 fn init_modifying_buffer() -> Buffer {
396 let mut buf = Buffer::new();
397 buf.text = DUMMY_TEXT.to_string();
398 buf.index = DUMMY_INDEX;
399 buf
400 }
401
402 #[test]
403 fn test_new() {
404 let b = init_modifying_buffer();
405 assert!(!b.debug);
406 assert!(!b.double_line_response);
407 }
408
409 #[test]
410 fn test_home() {
411 let mut b = init_modifying_buffer();
412 let h = b.home().unwrap();
413 assert_eq!(h, Key::Home);
414 assert_eq!(b.index, 0);
415 }
416
417 #[test]
418 fn test_end() {
419 let mut b = init_modifying_buffer();
420 let k = b.end().unwrap();
421 assert_eq!(k, Key::End);
422 assert_eq!(b.index, b.text.len());
423 }
424
425 #[test]
426 fn test_char_input_at_start_results_a_char() {
427 let mut b = Buffer::new();
428 let k = b.char('g').unwrap();
429 assert_eq!(k, Key::Char('g'));
430 assert_eq!(b.index, 1);
431 assert_eq!(b.text, "g".to_string());
432 }
433
434 #[test]
435 fn test_char_input_before_word_results_inserted_char() {
436 let mut b = init_with_word();
437 let mut text_swap = b.text.clone();
438 let k = b.char('@').unwrap();
439 assert_eq!(k, Key::Char('@'));
440 assert_eq!(b.index, 1);
441 text_swap.insert(0, '@');
442 assert_eq!(b.text, text_swap);
443 }
444
445 #[test]
446 fn test_char_input_between_characters_inserted_char() {
447 let mut b = init_modifying_buffer();
448 let idx_init = b.index;
449 let mut text_swap = b.text.clone();
450 let k = b.char('g').unwrap();
451 assert_eq!(k, Key::Char('g'));
452 assert_eq!(b.index, idx_init + 1);
453 text_swap.insert(idx_init, 'g');
454 assert_eq!(b.text, text_swap);
455 }
456
457 #[test]
458 fn test_string_input_results_modified_word() {
459 let mut b = init_modifying_buffer();
460 let idx_init = b.index;
461 let mut text_swap = b.text.clone();
462 b.char('i').unwrap();
463 b.char('t').unwrap();
464 b.char('a').unwrap();
465 b.char('i').unwrap();
466 assert_eq!(b.index, idx_init + "itai".len());
467 text_swap.insert_str(idx_init, "itai");
468 assert_eq!(
469 b.text,
470 "okachimachi koshigaitaiya inogashira suidobashi ochanomidzu".to_string()
471 );
472 }
473
474 #[test]
475 fn test_backspace_after_characters_removes_char() {
476 let mut b = init_modifying_buffer();
477 let idx_init = b.index;
478 let mut text_swap = b.text.clone();
479 b.backspace().unwrap();
480 assert_eq!(b.index, idx_init - 1);
481 text_swap.remove(idx_init - 1);
482 assert_eq!(b.text, text_swap);
483 }
484
485 #[test]
486 fn test_backspace_before_characters_has_no_effect() {
487 let mut b = init_with_word();
488 let idx_init = b.index;
489 let text_swap = b.text.clone();
490 b.backspace().unwrap();
491 assert_eq!(b.index, idx_init);
492 assert_eq!(b.text, text_swap);
493 }
494
495 #[test]
496 fn test_delete_before_characters_results_shortened_string() {
497 let mut b = init_with_word();
498 let idx_init = b.index;
499 let text_init = b.text.clone();
500 b.del().unwrap();
501 assert_eq!(b.index, idx_init);
502 assert_eq!(b.text, text_init.as_str()[1..text_init.len()]);
503 }
504
505 #[test]
506 fn test_delete_all_characters_results_blank_string() {
507 let mut b = init_with_word();
508 for _ in 0..100 {
509 b.del().unwrap();
510 }
511 assert_eq!(b.index, 0);
512 assert_eq!(b.text, "".to_string());
513 }
514
515 #[test]
516 fn test_delete_many_after_a_character_results_trimmed_string() {
517 let mut b = init_modifying_buffer();
518 let idx_init = b.index;
519 let text_init = b.text.clone();
520 for _ in 0..100 {
521 b.del().unwrap();
522 }
523 assert_eq!(b.index, idx_init);
524 assert_eq!(b.text, text_init.as_str()[0..idx_init]);
525 }
526
527 #[test]
528 fn test_go_word_foward_rearrange_cursor_to_next_word_separator() {
529 let mut b = init_modifying_buffer();
530 b.word_forward().unwrap();
531 assert_eq!(
532 b.index,
533 DUMMY_TEXT.match_indices(' ').map(|t| t.0).nth(1).unwrap()
534 );
535 }
536
537 #[test]
538 fn test_go_word_backward_rearrange_cursor_to_previous_word_head() {
539 let mut b = init_modifying_buffer();
540 b.word_backword().unwrap();
541 assert_eq!(
542 b.index,
543 DUMMY_TEXT.match_indices(' ').map(|t| t.0).nth(0).unwrap() + 1
544 );
545 }
546
547 #[test]
548 fn test_word_backspace_removes_partial_string_from_current_word() {
549 let mut b = init_modifying_buffer();
550 let idx_init = b.index;
551 let text_init = b.text.clone();
552 let idx_prev_space: usize = DUMMY_TEXT
553 .match_indices(' ')
554 .map(|t| t.0)
555 .filter(|n| *n < idx_init)
556 .last()
557 .unwrap();
558 b.word_backspace().unwrap();
559 assert_eq!(b.index, idx_prev_space);
560 assert_eq!(
561 b.text,
562 format!(
563 "{}{}",
564 &text_init[0..idx_prev_space],
565 &text_init[idx_init..text_init.len()]
566 )
567 );
568 }
569
570 #[test]
571 fn test_word_delete_removes_partial_string_from_current_word() {
572 let mut b = init_modifying_buffer();
573 let idx_init = b.index;
574 let text_init = b.text.clone();
575 let idx_next_space: usize = DUMMY_TEXT
576 .match_indices(' ')
577 .map(|t| t.0)
578 .filter(|n| *n >= idx_init)
579 .nth(0)
580 .unwrap();
581 b.word_delete().unwrap();
582 assert_eq!(b.index, idx_init);
583 assert_eq!(
584 b.text,
585 format!(
586 "{}{}",
587 &text_init[0..idx_init],
588 &text_init[idx_next_space..text_init.len()]
589 )
590 );
591 }
592
593 #[test]
594 fn test_left_key_after_characters_results_cursor_shift() {
595 let mut b = init_modifying_buffer();
596 let idx_init = b.index;
597 b.left().unwrap();
598 assert_eq!(b.index, idx_init - 1);
599 }
600
601 #[test]
602 fn test_right_key_after_all_character_results_cursor_shift() {
603 let mut b = init_with_word();
604 b.index = b.text.len();
605 let idx_init = b.text.len();
606 b.right().unwrap();
607 assert_eq!(b.index, idx_init);
608 }
609
610 #[test]
611 fn test_right_key_before_characters_results_cursor_shift() {
612 let mut b = init_with_word();
613 let idx_init = b.index;
614 b.right().unwrap();
615 assert_eq!(b.index, idx_init + 1);
616 }
617
618 #[test]
619 fn test_left_key_before_characters_has_no_effect() {
620 let mut b = init_with_word();
621 let idx_init = b.index;
622 b.left().unwrap();
623 assert_eq!(b.index, idx_init);
624 }
625
626 #[test]
627 fn test_set_prefix() {
628 let mut b = init_with_word();
629 let data = "korekara";
630 assert_eq!(b.prefix.len(), 0);
631 b.set_prefix(data.to_string());
632 assert_eq!(b.prefix.len(), data.len());
633 }
634}