1use std::cell::RefCell;
4use std::fmt;
5use std::rc::Rc;
6use unicode_segmentation::UnicodeSegmentation;
7use unicode_width::UnicodeWidthChar;
8
9use super::Result;
10use highlight::Highlighter;
11use hint::Hinter;
12use history::{Direction, History};
13use keymap::{Anchor, At, CharSearch, Cmd, Movement, RepeatCount, Word};
14use keymap::{InputState, Refresher};
15use line_buffer::{LineBuffer, WordAction, MAX_LINE};
16use tty::{Position, RawReader, Renderer};
17use undo::Changeset;
18
19pub struct State<'out, 'prompt> {
22 pub out: &'out mut dyn Renderer,
23 prompt: &'prompt str, prompt_size: Position, pub line: LineBuffer, pub cursor: Position, pub old_rows: usize, history_index: usize, saved_line_for_history: LineBuffer, byte_buffer: [u8; 4],
32 pub changes: Rc<RefCell<Changeset>>, pub hinter: Option<&'out dyn Hinter>,
34 pub highlighter: Option<&'out dyn Highlighter>,
35 no_hint: bool, }
37
38impl<'out, 'prompt> State<'out, 'prompt> {
39 pub fn new(
40 out: &'out mut dyn Renderer,
41 prompt: &'prompt str,
42 history_index: usize,
43 hinter: Option<&'out dyn Hinter>,
44 highlighter: Option<&'out dyn Highlighter>,
45 ) -> State<'out, 'prompt> {
46 let capacity = MAX_LINE;
47 let prompt_size = out.calculate_position(prompt, Position::default());
48 State {
49 out,
50 prompt,
51 prompt_size,
52 line: LineBuffer::with_capacity(capacity),
53 cursor: prompt_size,
54 old_rows: 0,
55 history_index,
56 saved_line_for_history: LineBuffer::with_capacity(capacity),
57 byte_buffer: [0; 4],
58 changes: Rc::new(RefCell::new(Changeset::new())),
59 hinter,
60 highlighter,
61 no_hint: true,
62 }
63 }
64
65 pub fn next_cmd<R: RawReader>(
66 &mut self,
67 input_state: &mut InputState,
68 rdr: &mut R,
69 single_esc_abort: bool,
70 ) -> Result<Cmd> {
71 loop {
72 let rc = input_state.next_cmd(rdr, self, single_esc_abort);
73 if rc.is_err() && self.out.sigwinch() {
74 self.out.update_size();
75 try!(self.refresh_line());
76 continue;
77 }
78 if let Ok(Cmd::Replace(_, _)) = rc {
79 self.changes.borrow_mut().begin();
80 }
81 return rc;
82 }
83 }
84
85 pub fn backup(&mut self) {
86 self.saved_line_for_history
87 .update(self.line.as_str(), self.line.pos());
88 }
89
90 pub fn restore(&mut self) {
91 self.line.update(
92 self.saved_line_for_history.as_str(),
93 self.saved_line_for_history.pos(),
94 );
95 }
96
97 pub fn move_cursor(&mut self) -> Result<()> {
98 let cursor = self
100 .out
101 .calculate_position(&self.line[..self.line.pos()], self.prompt_size);
102 if self.cursor == cursor {
103 return Ok(());
104 }
105 if self.highlighter.map_or(false, |h| {
106 self.line
107 .grapheme_at_cursor()
108 .map_or(false, |s| h.highlight_char(s))
109 }) {
110 let prompt_size = self.prompt_size;
111 try!(self.refresh(self.prompt, prompt_size, None));
112 } else {
113 try!(self.out.move_cursor(self.cursor, cursor));
114 }
115 self.cursor = cursor;
116 Ok(())
117 }
118
119 fn refresh(&mut self, prompt: &str, prompt_size: Position, hint: Option<String>) -> Result<()> {
120 let (cursor, end_pos) = try!(self.out.refresh_line(
121 prompt,
122 prompt_size,
123 &self.line,
124 hint,
125 self.cursor.row,
126 self.old_rows,
127 self.highlighter,
128 ));
129
130 self.cursor = cursor;
131 self.old_rows = end_pos.row;
132 Ok(())
133 }
134
135 fn hint(&mut self) -> Option<String> {
136 if let Some(hinter) = self.hinter {
137 self.no_hint = false;
138 hinter.hint(self.line.as_str(), self.line.pos())
139 } else {
140 self.no_hint = true;
141 None
142 }
143 }
144}
145
146impl<'out, 'prompt> Refresher for State<'out, 'prompt> {
147 fn refresh_line(&mut self) -> Result<()> {
148 let prompt_size = self.prompt_size;
149 let hint = self.hint();
150 self.refresh(self.prompt, prompt_size, hint)
151 }
152
153 fn refresh_prompt_and_line(&mut self, prompt: &str) -> Result<()> {
154 let prompt_size = self.out.calculate_position(prompt, Position::default());
155 let hint = self.hint();
156 self.refresh(prompt, prompt_size, hint)
157 }
158
159 fn doing_insert(&mut self) {
160 self.changes.borrow_mut().begin();
161 }
162
163 fn done_inserting(&mut self) {
164 self.changes.borrow_mut().end();
165 }
166
167 fn last_insert(&self) -> Option<String> {
168 self.changes.borrow().last_insert()
169 }
170}
171
172impl<'out, 'prompt> fmt::Debug for State<'out, 'prompt> {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 f.debug_struct("State")
175 .field("prompt", &self.prompt)
176 .field("prompt_size", &self.prompt_size)
177 .field("buf", &self.line)
178 .field("cursor", &self.cursor)
179 .field("cols", &self.out.get_columns())
180 .field("old_rows", &self.old_rows)
181 .field("history_index", &self.history_index)
182 .field("saved_line_for_history", &self.saved_line_for_history)
183 .finish()
184 }
185}
186
187impl<'out, 'prompt> State<'out, 'prompt> {
188 pub fn edit_insert(&mut self, ch: char, n: RepeatCount) -> Result<()> {
190 if let Some(push) = self.line.insert(ch, n) {
191 if push {
192 let prompt_size = self.prompt_size;
193 let no_previous_hint = self.no_hint;
194 let hint = self.hint();
195 if n == 1
196 && self.cursor.col + ch.width().unwrap_or(0) < self.out.get_columns()
197 && (hint.is_none() && no_previous_hint) && !self.highlighter.map_or(true, |h| h.highlight_char(ch.encode_utf8(&mut self.byte_buffer)))
199 {
200 let cursor = self
202 .out
203 .calculate_position(&self.line[..self.line.pos()], self.prompt_size);
204 self.cursor = cursor;
205 let bits = ch.encode_utf8(&mut self.byte_buffer);
206 let bits = bits.as_bytes();
207 self.out.write_and_flush(bits)
208 } else {
209 self.refresh(self.prompt, prompt_size, hint)
210 }
211 } else {
212 self.refresh_line()
213 }
214 } else {
215 Ok(())
216 }
217 }
218
219 pub fn edit_replace_char(&mut self, ch: char, n: RepeatCount) -> Result<()> {
221 self.changes.borrow_mut().begin();
222 let succeed = if let Some(chars) = self.line.delete(n) {
223 let count = chars.graphemes(true).count();
224 self.line.insert(ch, count);
225 self.line.move_backward(1);
226 true
227 } else {
228 false
229 };
230 self.changes.borrow_mut().end();
231 if succeed {
232 self.refresh_line()
233 } else {
234 Ok(())
235 }
236 }
237
238 pub fn edit_overwrite_char(&mut self, ch: char) -> Result<()> {
240 if let Some(end) = self.line.next_pos(1) {
241 {
242 let text = ch.encode_utf8(&mut self.byte_buffer);
243 let start = self.line.pos();
244 self.line.replace(start..end, text);
245 }
246 self.refresh_line()
247 } else {
248 Ok(())
249 }
250 }
251
252 pub fn edit_yank(
254 &mut self,
255 input_state: &InputState,
256 text: &str,
257 anchor: Anchor,
258 n: RepeatCount,
259 ) -> Result<()> {
260 if let Anchor::After = anchor {
261 self.line.move_forward(1);
262 }
263 if self.line.yank(text, n).is_some() {
264 if !input_state.is_emacs_mode() {
265 self.line.move_backward(1);
266 }
267 self.refresh_line()
268 } else {
269 Ok(())
270 }
271 }
272
273 pub fn edit_yank_pop(&mut self, yank_size: usize, text: &str) -> Result<()> {
275 self.changes.borrow_mut().begin();
276 let result = if self.line.yank_pop(yank_size, text).is_some() {
277 self.refresh_line()
278 } else {
279 Ok(())
280 };
281 self.changes.borrow_mut().end();
282 result
283 }
284
285 pub fn edit_move_backward(&mut self, n: RepeatCount) -> Result<()> {
287 if self.line.move_backward(n) {
288 self.move_cursor()
289 } else {
290 Ok(())
291 }
292 }
293
294 pub fn edit_move_forward(&mut self, n: RepeatCount) -> Result<()> {
296 if self.line.move_forward(n) {
297 self.move_cursor()
298 } else {
299 Ok(())
300 }
301 }
302
303 pub fn edit_move_home(&mut self) -> Result<()> {
305 if self.line.move_home() {
306 self.move_cursor()
307 } else {
308 Ok(())
309 }
310 }
311
312 pub fn edit_move_end(&mut self) -> Result<()> {
314 if self.line.move_end() {
315 self.move_cursor()
316 } else {
317 Ok(())
318 }
319 }
320
321 pub fn edit_kill(&mut self, mvt: &Movement) -> Result<()> {
322 if self.line.kill(mvt) {
323 self.refresh_line()
324 } else {
325 Ok(())
326 }
327 }
328
329 pub fn edit_insert_text(&mut self, text: &str) -> Result<()> {
330 if text.is_empty() {
331 return Ok(());
332 }
333 let cursor = self.line.pos();
334 self.line.insert_str(cursor, text);
335 self.refresh_line()
336 }
337
338 pub fn edit_delete(&mut self, n: RepeatCount) -> Result<()> {
339 if self.line.delete(n).is_some() {
340 self.refresh_line()
341 } else {
342 Ok(())
343 }
344 }
345
346 pub fn edit_transpose_chars(&mut self) -> Result<()> {
348 self.changes.borrow_mut().begin();
349 let succeed = self.line.transpose_chars();
350 self.changes.borrow_mut().end();
351 if succeed {
352 self.refresh_line()
353 } else {
354 Ok(())
355 }
356 }
357
358 pub fn edit_move_to_prev_word(&mut self, word_def: Word, n: RepeatCount) -> Result<()> {
359 if self.line.move_to_prev_word(word_def, n) {
360 self.move_cursor()
361 } else {
362 Ok(())
363 }
364 }
365
366 pub fn edit_move_to_next_word(&mut self, at: At, word_def: Word, n: RepeatCount) -> Result<()> {
367 if self.line.move_to_next_word(at, word_def, n) {
368 self.move_cursor()
369 } else {
370 Ok(())
371 }
372 }
373
374 pub fn edit_move_to(&mut self, cs: CharSearch, n: RepeatCount) -> Result<()> {
375 if self.line.move_to(cs, n) {
376 self.move_cursor()
377 } else {
378 Ok(())
379 }
380 }
381
382 pub fn edit_word(&mut self, a: WordAction) -> Result<()> {
383 self.changes.borrow_mut().begin();
384 let succeed = self.line.edit_word(a);
385 self.changes.borrow_mut().end();
386 if succeed {
387 self.refresh_line()
388 } else {
389 Ok(())
390 }
391 }
392
393 pub fn edit_transpose_words(&mut self, n: RepeatCount) -> Result<()> {
394 self.changes.borrow_mut().begin();
395 let succeed = self.line.transpose_words(n);
396 self.changes.borrow_mut().end();
397 if succeed {
398 self.refresh_line()
399 } else {
400 Ok(())
401 }
402 }
403
404 pub fn edit_history_next(&mut self, history: &History, prev: bool) -> Result<()> {
407 if history.is_empty() {
408 return Ok(());
409 }
410 if self.history_index == history.len() {
411 if prev {
412 self.backup();
414 } else {
415 return Ok(());
416 }
417 } else if self.history_index == 0 && prev {
418 return Ok(());
419 }
420 if prev {
421 self.history_index -= 1;
422 } else {
423 self.history_index += 1;
424 }
425 if self.history_index < history.len() {
426 let buf = history.get(self.history_index).unwrap();
427 self.changes.borrow_mut().begin();
428 self.line.update(buf, buf.len());
429 self.changes.borrow_mut().end();
430 } else {
431 self.restore();
433 }
434 self.refresh_line()
435 }
436
437 pub fn edit_history_search(&mut self, history: &History, dir: Direction) -> Result<()> {
439 if history.is_empty() {
440 return self.out.beep();
441 }
442 if self.history_index == history.len() && dir == Direction::Forward
443 || self.history_index == 0 && dir == Direction::Reverse
444 {
445 return self.out.beep();
446 }
447 if dir == Direction::Reverse {
448 self.history_index -= 1;
449 } else {
450 self.history_index += 1;
451 }
452 if let Some(history_index) = history.starts_with(
453 &self.line.as_str()[..self.line.pos()],
454 self.history_index,
455 dir,
456 ) {
457 self.history_index = history_index;
458 let buf = history.get(history_index).unwrap();
459 self.changes.borrow_mut().begin();
460 self.line.update(buf, buf.len());
461 self.changes.borrow_mut().end();
462 self.refresh_line()
463 } else {
464 self.out.beep()
465 }
466 }
467
468 pub fn edit_history(&mut self, history: &History, first: bool) -> Result<()> {
470 if history.is_empty() {
471 return Ok(());
472 }
473 if self.history_index == history.len() {
474 if first {
475 self.backup();
477 } else {
478 return Ok(());
479 }
480 } else if self.history_index == 0 && first {
481 return Ok(());
482 }
483 if first {
484 self.history_index = 0;
485 let buf = history.get(self.history_index).unwrap();
486 self.changes.borrow_mut().begin();
487 self.line.update(buf, buf.len());
488 self.changes.borrow_mut().end();
489 } else {
490 self.history_index = history.len();
491 self.restore();
493 }
494 self.refresh_line()
495 }
496}
497
498#[cfg(test)]
499pub fn init_state<'out>(out: &'out mut Renderer, line: &str, pos: usize) -> State<'out, 'static> {
500 State {
501 out,
502 prompt: "",
503 prompt_size: Position::default(),
504 line: LineBuffer::init(line, pos, None),
505 cursor: Position::default(),
506 old_rows: 0,
507 history_index: 0,
508 saved_line_for_history: LineBuffer::with_capacity(100),
509 byte_buffer: [0; 4],
510 changes: Rc::new(RefCell::new(Changeset::new())),
511 hinter: None,
512 highlighter: None,
513 no_hint: true,
514 }
515}
516
517#[cfg(test)]
518mod test {
519 use super::init_state;
520 use history::History;
521 use tty::Sink;
522
523 #[test]
524 fn edit_history_next() {
525 let mut out = Sink::new();
526 let line = "current edited line";
527 let mut s = init_state(&mut out, line, 6);
528 let mut history = History::new();
529 history.add("line0");
530 history.add("line1");
531 s.history_index = history.len();
532
533 for _ in 0..2 {
534 s.edit_history_next(&history, false).unwrap();
535 assert_eq!(line, s.line.as_str());
536 }
537
538 s.edit_history_next(&history, true).unwrap();
539 assert_eq!(line, s.saved_line_for_history.as_str());
540 assert_eq!(1, s.history_index);
541 assert_eq!("line1", s.line.as_str());
542
543 for _ in 0..2 {
544 s.edit_history_next(&history, true).unwrap();
545 assert_eq!(line, s.saved_line_for_history.as_str());
546 assert_eq!(0, s.history_index);
547 assert_eq!("line0", s.line.as_str());
548 }
549
550 s.edit_history_next(&history, false).unwrap();
551 assert_eq!(line, s.saved_line_for_history.as_str());
552 assert_eq!(1, s.history_index);
553 assert_eq!("line1", s.line.as_str());
554
555 s.edit_history_next(&history, false).unwrap();
556 assert_eq!(2, s.history_index);
558 assert_eq!(line, s.line.as_str());
559 }
560}