1use std::cmp::min;
17use std::ops::{Index, IndexMut, Range};
18use std::time::{Duration, Instant};
19use std::{io, ptr};
20
21use arraydeque::ArrayDeque;
22use unicode_width::UnicodeWidthChar;
23
24use crate::ansi::{
25 self, Attr, CharsetIndex, Color, CursorStyle, Handler, MouseCursor, NamedColor, StandardCharset,
26};
27use crate::grid::{
28 BidirectionalIterator, DisplayIter, Grid, IndexRegion, Indexed, Scroll, ViewportPosition,
29};
30use crate::index;
31use crate::selection::{self, Locations, Selection};
32use crate::term::cell::{Cell, LineLength};
33
34pub mod cell;
35
36pub trait Search {
41 fn semantic_search_left(&self, _: index::Point<usize>) -> index::Point<usize>;
43 fn semantic_search_right(&self, _: index::Point<usize>) -> index::Point<usize>;
45 fn url_search(&self, _: index::Point<usize>) -> Option<String>;
47}
48
49impl Search for Term {
50 fn semantic_search_left(&self, mut point: index::Point<usize>) -> index::Point<usize> {
51 point.line = min(point.line, self.grid.len() - 1);
53
54 let mut iter = self.grid.iter_from(point);
55 let last_col = self.grid.num_cols() - index::Column(1);
56
57 while let Some(cell) = iter.prev() {
58 if self.semantic_escape_chars.contains(cell.c) {
59 break;
60 }
61
62 if iter.cur.col == last_col && !cell.flags.contains(cell::Flags::WRAPLINE) {
63 break; }
65
66 point = iter.cur;
67 }
68
69 point
70 }
71
72 fn semantic_search_right(&self, mut point: index::Point<usize>) -> index::Point<usize> {
73 point.line = min(point.line, self.grid.len() - 1);
75
76 let mut iter = self.grid.iter_from(point);
77 let last_col = self.grid.num_cols() - index::Column(1);
78
79 while let Some(cell) = iter.next() {
80 if self.semantic_escape_chars.contains(cell.c) {
81 break;
82 }
83
84 point = iter.cur;
85
86 if iter.cur.col == last_col && !cell.flags.contains(cell::Flags::WRAPLINE) {
87 break; }
89 }
90
91 point
92 }
93
94 fn url_search(&self, _: index::Point<usize>) -> Option<String> {
95 None }
97}
98
99impl selection::Dimensions for Term {
100 fn dimensions(&self) -> index::Point {
101 index::Point {
102 col: self.grid.num_cols(),
103 line: self.grid.num_lines(),
104 }
105 }
106}
107
108pub struct RenderableCellsIter<'a> {
117 inner: DisplayIter<'a, Cell>,
118 grid: &'a Grid<Cell>,
119 cursor: &'a index::Point,
120 cursor_offset: usize,
121 mode: TermMode,
122 selection: Option<index::RangeInclusive<index::Linear>>,
123 cursor_cells: ArrayDeque<[Indexed<Cell>; 3]>,
124}
125
126impl<'a> RenderableCellsIter<'a> {
127 fn new<'b>(
132 grid: &'b Grid<Cell>,
133 cursor: &'b index::Point,
134 mode: TermMode,
135 selection: Option<Locations>,
136 cursor_style: CursorStyle,
137 ) -> RenderableCellsIter<'b> {
138 let cursor_offset = grid.line_to_offset(cursor.line);
139 let inner = grid.display_iter();
140
141 let mut selection_range = None;
142 if let Some(loc) = selection {
143 let start_line = grid.buffer_line_to_visible(loc.start.line);
145 let end_line = grid.buffer_line_to_visible(loc.end.line);
146
147 let locations = match (start_line, end_line) {
149 (ViewportPosition::Visible(start_line), ViewportPosition::Visible(end_line)) => {
150 Some((start_line, loc.start.col, end_line, loc.end.col))
151 }
152 (ViewportPosition::Visible(start_line), ViewportPosition::Above) => {
153 Some((start_line, loc.start.col, index::Line(0), index::Column(0)))
154 }
155 (ViewportPosition::Below, ViewportPosition::Visible(end_line)) => {
156 Some((grid.num_lines(), index::Column(0), end_line, loc.end.col))
157 }
158 (ViewportPosition::Below, ViewportPosition::Above) => Some((
159 grid.num_lines(),
160 index::Column(0),
161 index::Line(0),
162 index::Column(0),
163 )),
164 _ => None,
165 };
166
167 if let Some((start_line, start_col, end_line, end_col)) = locations {
168 let mut end = index::Point {
171 line: start_line,
172 col: start_col,
173 };
174 let mut start = index::Point {
175 line: end_line,
176 col: end_col,
177 };
178
179 if start > end {
180 ::std::mem::swap(&mut start, &mut end);
181 }
182
183 let cols = grid.num_cols();
184 let start = index::Linear(start.line.0 * cols.0 + start.col.0);
185 let end = index::Linear(end.line.0 * cols.0 + end.col.0);
186
187 selection_range = Some(index::RangeInclusive::new(start, end));
189 }
190 }
191
192 RenderableCellsIter {
193 cursor,
194 cursor_offset,
195 grid,
196 inner,
197 mode,
198 selection: selection_range,
199 cursor_cells: ArrayDeque::new(),
200 }
201 .initialize(cursor_style)
202 }
203
204 fn push_cursor_cells(&mut self, original: Cell, cursor: Cell, wide: Cell) {
205 self.cursor_cells
207 .push_back(Indexed {
208 line: self.cursor.line,
209 column: self.cursor.col,
210 inner: original,
211 })
212 .expect("won't exceed capacity");
213
214 self.cursor_cells
216 .push_back(Indexed {
217 line: self.cursor.line,
218 column: self.cursor.col,
219 inner: cursor,
220 })
221 .expect("won't exceed capacity");
222
223 if self.is_wide_cursor(&cursor) {
226 self.cursor_cells
227 .push_back(Indexed {
228 line: self.cursor.line,
229 column: self.cursor.col + 1,
230 inner: wide,
231 })
232 .expect("won't exceed capacity");
233 }
234 }
235
236 fn populate_block_cursor(&mut self) {
237 let text_color = Color::Named(NamedColor::CursorText);
238 let cursor_color = Color::Named(NamedColor::Cursor);
239
240 let original_cell = self.grid[self.cursor];
241
242 let mut cursor_cell = self.grid[self.cursor];
243 cursor_cell.fg = text_color;
244 cursor_cell.bg = cursor_color;
245
246 let mut wide_cell = cursor_cell;
247 wide_cell.c = ' ';
248
249 self.push_cursor_cells(original_cell, cursor_cell, wide_cell);
250 }
251
252 fn populate_char_cursor(&mut self, cursor_cell_char: char, wide_cell_char: char) {
253 let original_cell = self.grid[self.cursor];
254
255 let mut cursor_cell = self.grid[self.cursor];
256 let cursor_color = Color::Named(NamedColor::Cursor);
257 cursor_cell.c = cursor_cell_char;
258 cursor_cell.fg = cursor_color;
259
260 let mut wide_cell = cursor_cell;
261 wide_cell.c = wide_cell_char;
262
263 self.push_cursor_cells(original_cell, cursor_cell, wide_cell);
264 }
265
266 fn populate_underline_cursor(&mut self) {
267 self.populate_char_cursor('_', '_');
268 }
269
270 fn populate_beam_cursor(&mut self) {
271 self.populate_char_cursor('|', ' ');
272 }
273
274 fn populate_box_cursor(&mut self) {
275 self.populate_char_cursor('█', ' ');
276 }
277
278 #[inline]
279 fn is_wide_cursor(&self, cell: &Cell) -> bool {
280 cell.flags.contains(cell::Flags::WIDE_CHAR) && (self.cursor.col + 1) < self.grid.num_cols()
281 }
282
283 fn populate_no_cursor(&mut self) {
285 self.cursor_cells
286 .push_back(Indexed {
287 line: self.cursor.line,
288 column: self.cursor.col,
289 inner: self.grid[self.cursor],
290 })
291 .expect("won't exceed capacity");
292 }
293
294 fn initialize(mut self, cursor_style: CursorStyle) -> Self {
295 if self.cursor_is_visible() {
296 match cursor_style {
297 CursorStyle::HollowBlock => {
298 self.populate_box_cursor();
299 }
300 CursorStyle::Block => {
301 self.populate_block_cursor();
302 }
303 CursorStyle::Beam => {
304 self.populate_beam_cursor();
305 }
306 CursorStyle::Underline => {
307 self.populate_underline_cursor();
308 }
309 }
310 } else {
311 self.populate_no_cursor();
312 }
313 self
314 }
315
316 #[inline]
318 fn cursor_is_visible(&self) -> bool {
319 self.mode.contains(mode::TermMode::SHOW_CURSOR) && self.grid.contains(self.cursor)
320 }
321
322 fn compute_fg(&self, fg: Color, cell: &Cell) -> Color {
323 use self::cell::Flags;
324 match fg {
325 Color::Spec(rgb) => Color::Spec(rgb),
326 Color::Named(ansi) => {
327 match cell.flags & Flags::DIM_BOLD {
328 self::cell::Flags::DIM_BOLD if ansi == NamedColor::Foreground => {
330 Color::Named(NamedColor::DimForeground)
331 }
332 self::cell::Flags::DIM | self::cell::Flags::DIM_BOLD => {
333 Color::Named(ansi.to_dim())
334 }
335 _ => Color::Named(ansi),
337 }
338 }
339 Color::Indexed(idx) => {
340 let idx = match (cell.flags & Flags::DIM_BOLD, idx) {
341 (self::cell::Flags::BOLD, 0..=7) => idx + 8,
342 (self::cell::Flags::DIM, 8..=15) => idx - 8,
343 _ => idx,
346 };
347
348 Color::Indexed(idx)
349 }
350 }
351 }
352}
353
354#[derive(Copy, Clone, Debug)]
355pub struct RenderableCell {
356 pub line: index::Line,
358 pub column: index::Column,
359 pub chars: [char; cell::MAX_ZEROWIDTH_CHARS + 1],
360 pub fg: Color,
361 pub bg: Color,
362 pub flags: cell::Flags,
363}
364
365impl<'a> Iterator for RenderableCellsIter<'a> {
366 type Item = RenderableCell;
367
368 #[inline]
373 fn next(&mut self) -> Option<Self::Item> {
374 loop {
375 let cell = if self.cursor_offset == self.inner.offset()
377 && self.inner.column() == self.cursor.col
378 {
379 let mut cell = self.cursor_cells.pop_front().unwrap();
381 cell.line = self.inner.line();
382
383 if self.cursor_cells.is_empty() {
387 self.inner.next();
388 }
389 cell
390 } else {
391 use crate::index::Contains;
392
393 let cell = self.inner.next()?;
394
395 let index = index::Linear(cell.line.0 * self.grid.num_cols().0 + cell.column.0);
396
397 let selected = self
398 .selection
399 .as_ref()
400 .map(|range| range.contains_(index))
401 .unwrap_or(false);
402
403 if cell.is_empty() && !selected {
405 continue;
406 }
407
408 cell
409 };
410
411 let fg = self.compute_fg(cell.fg, &cell);
413 let bg = cell.bg;
414
415 return Some(RenderableCell {
416 line: cell.line,
417 column: cell.column,
418 flags: cell.flags,
419 chars: cell.chars(),
420 fg,
421 bg,
422 });
423 }
424 }
425}
426
427pub mod mode {
428 use bitflags::bitflags;
429
430 bitflags! {
431 pub struct TermMode: u16 {
432 const SHOW_CURSOR = 0b00_0000_0000_0001;
433 const APP_CURSOR = 0b00_0000_0000_0010;
434 const APP_KEYPAD = 0b00_0000_0000_0100;
435 const MOUSE_REPORT_CLICK = 0b00_0000_0000_1000;
436 const BRACKETED_PASTE = 0b00_0000_0001_0000;
437 const SGR_MOUSE = 0b00_0000_0010_0000;
438 const MOUSE_MOTION = 0b00_0000_0100_0000;
439 const LINE_WRAP = 0b00_0000_1000_0000;
440 const LINE_FEED_NEW_LINE = 0b00_0001_0000_0000;
441 const ORIGIN = 0b00_0010_0000_0000;
442 const INSERT = 0b00_0100_0000_0000;
443 const FOCUS_IN_OUT = 0b00_1000_0000_0000;
444 const ALT_SCREEN = 0b01_0000_0000_0000;
445 const MOUSE_DRAG = 0b10_0000_0000_0000;
446 const ANY = 0b11_1111_1111_1111;
447 const NONE = 0;
448 }
449 }
450
451 impl Default for TermMode {
452 fn default() -> TermMode {
453 TermMode::SHOW_CURSOR | TermMode::LINE_WRAP
454 }
455 }
456}
457
458pub use self::mode::TermMode;
459
460trait CharsetMapping {
461 fn map(&self, c: char) -> char {
462 c
463 }
464}
465
466impl CharsetMapping for StandardCharset {
467 #[inline]
470 fn map(&self, c: char) -> char {
471 match *self {
472 StandardCharset::Ascii => c,
473 StandardCharset::SpecialCharacterAndLineDrawing => match c {
474 '`' => '◆',
475 'a' => '▒',
476 'b' => '\t',
477 'c' => '\u{000c}',
478 'd' => '\r',
479 'e' => '\n',
480 'f' => '°',
481 'g' => '±',
482 'h' => '\u{2424}',
483 'i' => '\u{000b}',
484 'j' => '┘',
485 'k' => '┐',
486 'l' => '┌',
487 'm' => '└',
488 'n' => '┼',
489 'o' => '⎺',
490 'p' => '⎻',
491 'q' => '─',
492 'r' => '⎼',
493 's' => '⎽',
494 't' => '├',
495 'u' => '┤',
496 'v' => '┴',
497 'w' => '┬',
498 'x' => '│',
499 'y' => '≤',
500 'z' => '≥',
501 '{' => 'π',
502 '|' => '≠',
503 '}' => '£',
504 '~' => '·',
505 _ => c,
506 },
507 }
508 }
509}
510
511#[derive(Default, Copy, Clone)]
512struct Charsets([StandardCharset; 4]);
513
514impl Index<CharsetIndex> for Charsets {
515 type Output = StandardCharset;
516 fn index(&self, index: CharsetIndex) -> &StandardCharset {
517 &self.0[index as usize]
518 }
519}
520
521impl IndexMut<CharsetIndex> for Charsets {
522 fn index_mut(&mut self, index: CharsetIndex) -> &mut StandardCharset {
523 &mut self.0[index as usize]
524 }
525}
526
527#[derive(Default, Copy, Clone)]
528pub struct Cursor {
529 pub point: index::Point,
531
532 template: Cell,
534
535 charsets: Charsets,
537}
538
539pub struct VisualBell {
540 duration: Duration,
542
543 start_time: Option<Instant>,
545}
546
547impl VisualBell {
548 pub fn new() -> VisualBell {
549 VisualBell {
550 duration: Duration::from_secs(1),
551 start_time: None,
552 }
553 }
554
555 pub fn ring(&mut self) -> f64 {
557 let now = Instant::now();
558 self.start_time = Some(now);
559 0.0
560 }
561
562 pub fn intensity(&self) -> f64 {
565 0.0
566 }
567
568 pub fn completed(&mut self) -> bool {
570 match self.start_time {
571 Some(earlier) => {
572 if Instant::now().duration_since(earlier) >= self.duration {
573 self.start_time = None;
574 }
575 false
576 }
577 None => true,
578 }
579 }
580}
581
582pub struct Term {
583 grid: Grid<Cell>,
585
586 input_needs_wrap: bool,
592
593 next_title: Option<String>,
597
598 next_mouse_cursor: Option<MouseCursor>,
600
601 alt_grid: Grid<Cell>,
603
604 alt: bool,
606
607 cursor: Cursor,
609
610 active_charset: CharsetIndex,
613
614 tabs: TabStops,
616
617 mode: TermMode,
619
620 scroll_region: Range<index::Line>,
622
623 size_info: SizeInfo,
625
626 pub dirty: bool,
627
628 pub visual_bell: VisualBell,
629 pub next_is_urgent: Option<bool>,
630
631 cursor_save: Cursor,
633
634 cursor_save_alt: Cursor,
636
637 semantic_escape_chars: String,
638
639 cursor_style: Option<CursorStyle>,
641
642 default_cursor_style: CursorStyle,
644
645 dynamic_title: bool,
646
647 tabspaces: usize,
649
650 auto_scroll: bool,
652
653 should_exit: bool,
655}
656
657#[derive(Debug, Copy, Clone)]
659pub struct SizeInfo {
660 pub width: f32,
662
663 pub height: f32,
665
666 pub cell_width: f32,
668
669 pub cell_height: f32,
671
672 pub padding_x: f32,
674
675 pub padding_y: f32,
677
678 pub dpr: f64,
680}
681
682impl SizeInfo {
683 #[inline]
684 pub fn lines(&self) -> index::Line {
685 index::Line(((self.height - 2. * self.padding_y) / self.cell_height) as usize)
686 }
687
688 #[inline]
689 pub fn cols(&self) -> index::Column {
690 index::Column(((self.width - 2. * self.padding_x) / self.cell_width) as usize)
691 }
692
693 pub fn contains_point(&self, x: usize, y: usize) -> bool {
694 x < (self.width - self.padding_x) as usize
695 && x >= self.padding_x as usize
696 && y < (self.height - self.padding_y) as usize
697 && y >= self.padding_y as usize
698 }
699
700 pub fn pixels_to_coords(&self, x: usize, y: usize) -> index::Point {
701 let col =
702 index::Column(x.saturating_sub(self.padding_x as usize) / (self.cell_width as usize));
703 let line =
704 index::Line(y.saturating_sub(self.padding_y as usize) / (self.cell_height as usize));
705
706 index::Point {
707 line: min(line, index::Line(self.lines().saturating_sub(1))),
708 col: min(col, index::Column(self.cols().saturating_sub(1))),
709 }
710 }
711}
712
713impl Term {
714 pub fn selection(&self) -> &Option<Selection> {
715 &self.grid.selection
716 }
717
718 pub fn selection_mut(&mut self) -> &mut Option<Selection> {
719 &mut self.grid.selection
720 }
721
722 #[inline]
723 pub fn get_next_title(&mut self) -> Option<String> {
724 self.next_title.take()
725 }
726
727 pub fn scroll_display(&mut self, scroll: Scroll) {
728 self.grid.scroll_display(scroll);
729 self.dirty = true;
730 }
731
732 #[inline]
733 pub fn get_next_mouse_cursor(&mut self) -> Option<MouseCursor> {
734 self.next_mouse_cursor.take()
735 }
736
737 pub fn new(size: SizeInfo) -> Term {
738 let num_cols = size.cols();
739 let num_lines = size.lines();
740
741 let semantic_escape_chars = "".to_owned();
742 let history_size = 1024; let default_cursor_style = ansi::CursorStyle::Block;
744 let dynamic_title = true;
745 let auto_scroll = true;
746 let grid = Grid::new(num_lines, num_cols, history_size, Cell::default());
747 let alt = Grid::new(
748 num_lines,
749 num_cols,
750 0, Cell::default(),
752 );
753
754 let tabspaces = 4;
755 let tabs = TabStops::new(grid.num_cols(), tabspaces);
756
757 let scroll_region = index::Line(0)..grid.num_lines();
758
759 Term {
760 next_title: None,
761 next_mouse_cursor: None,
762 dirty: false,
763 visual_bell: VisualBell::new(),
764 next_is_urgent: None,
765 input_needs_wrap: false,
766 grid,
767 alt_grid: alt,
768 alt: false,
769 active_charset: Default::default(),
770 cursor: Default::default(),
771 cursor_save: Default::default(),
772 cursor_save_alt: Default::default(),
773 tabs,
774 mode: Default::default(),
775 scroll_region,
776 size_info: size,
777 semantic_escape_chars,
778 cursor_style: None,
779 default_cursor_style,
780 dynamic_title,
781 tabspaces,
782 auto_scroll,
783 should_exit: false,
784 }
785 }
786
787 #[inline]
788 pub fn needs_draw(&self) -> bool {
789 self.dirty
790 }
791
792 pub fn selection_to_string(&self) -> Option<String> {
793 trait PushChar {
795 fn push_char(&mut self, c: char);
796 fn maybe_newline(&mut self, grid: &Grid<Cell>, line: usize, ending: index::Column) {
797 if ending != index::Column(0)
798 && !grid[line][ending - 1].flags.contains(cell::Flags::WRAPLINE)
799 {
800 self.push_char('\n');
801 }
802 }
803 }
804
805 impl PushChar for String {
806 #[inline]
807 fn push_char(&mut self, c: char) {
808 self.push(c);
809 }
810 }
811
812 use std::ops::Range;
813
814 trait Append: PushChar {
815 fn append(
816 &mut self,
817 grid: &Grid<Cell>,
818 tabs: &TabStops,
819 line: usize,
820 cols: Range<index::Column>,
821 );
822 }
823
824 impl Append for String {
825 fn append(
826 &mut self,
827 grid: &Grid<Cell>,
828 tabs: &TabStops,
829 mut line: usize,
830 cols: Range<index::Column>,
831 ) {
832 line = min(line, grid.len() - 1);
834
835 let grid_line = &grid[line];
836 let line_length = grid_line.line_length();
837 let line_end = min(line_length, cols.end + 1);
838
839 if line_end.0 == 0 && cols.end >= grid.num_cols() - 1 {
840 self.push('\n');
841 } else if cols.start < line_end {
842 let mut tab_mode = false;
843
844 for col in index::Range::from(cols.start..line_end) {
845 let cell = grid_line[col];
846
847 if tab_mode {
848 if tabs[col] {
850 tab_mode = false;
851 } else if cell.c == ' ' {
852 continue;
853 }
854 }
855
856 if !cell.flags.contains(cell::Flags::WIDE_CHAR_SPACER) {
857 self.push(cell.c);
858 for c in (&cell.chars()[1..]).iter().filter(|c| **c != ' ') {
859 self.push(*c);
860 }
861 }
862
863 if cell.c == '\t' {
864 tab_mode = true;
865 }
866 }
867
868 if cols.end >= grid.num_cols() - 1 {
869 self.maybe_newline(grid, line, line_end);
870 }
871 }
872 }
873 }
874
875 let alt_screen = self.mode.contains(TermMode::ALT_SCREEN);
876 let selection = self.grid.selection.clone()?;
877 let span = selection.to_span(self, alt_screen)?;
878
879 let mut res = String::new();
880
881 let Locations { mut start, mut end } = span.to_locations();
882
883 if start > end {
884 ::std::mem::swap(&mut start, &mut end);
885 }
886
887 let line_count = end.line - start.line;
888 let max_col = index::Column(usize::max_value() - 1);
889
890 match line_count {
891 0 => {
893 res.append(&self.grid, &self.tabs, start.line, start.col..end.col);
894 }
895
896 1 => {
898 res.append(&self.grid, &self.tabs, end.line, end.col..max_col);
900
901 res.append(
903 &self.grid,
904 &self.tabs,
905 start.line,
906 index::Column(0)..start.col,
907 );
908 }
909
910 _ => {
912 res.append(&self.grid, &self.tabs, end.line, end.col..max_col);
914
915 let middle_range = (start.line + 1)..(end.line);
916 for line in middle_range.rev() {
917 res.append(&self.grid, &self.tabs, line, index::Column(0)..max_col);
918 }
919
920 res.append(
922 &self.grid,
923 &self.tabs,
924 start.line,
925 index::Column(0)..start.col,
926 );
927 }
928 }
929
930 Some(res)
931 }
932
933 pub fn pixels_to_coords(&self, x: usize, y: usize) -> Option<index::Point> {
940 if self.size_info.contains_point(x, y) {
941 Some(self.size_info.pixels_to_coords(x, y))
942 } else {
943 None
944 }
945 }
946
947 pub fn grid(&self) -> &Grid<Cell> {
952 &self.grid
953 }
954
955 #[cfg(test)]
957 pub fn grid_mut(&mut self) -> &mut Grid<Cell> {
958 &mut self.grid
959 }
960
961 pub fn renderable_cells(&self) -> RenderableCellsIter {
967 let alt_screen = self.mode.contains(TermMode::ALT_SCREEN);
968 let selection = self
969 .grid
970 .selection
971 .as_ref()
972 .and_then(|s| s.to_span(self, alt_screen))
973 .map(|span| span.to_locations());
974
975 let cursor = self.cursor_style.unwrap_or(self.default_cursor_style);
976
977 RenderableCellsIter::new(&self.grid, &self.cursor.point, self.mode, selection, cursor)
978 }
979
980 pub fn resize(&mut self, size: &SizeInfo) {
982 debug!("Resizing terminal");
983
984 if size.width as usize <= 2 * self.size_info.padding_x as usize
986 || size.height as usize <= 2 * self.size_info.padding_y as usize
987 {
988 return;
989 }
990
991 let old_cols = self.grid.num_cols();
992 let old_lines = self.grid.num_lines();
993 let mut num_cols = size.cols();
994 let mut num_lines = size.lines();
995
996 self.size_info = *size;
997
998 if old_cols == num_cols && old_lines == num_lines {
999 debug!("Term::resize dimensions unchanged");
1000 return;
1001 }
1002
1003 self.grid.selection = None;
1004 self.alt_grid.selection = None;
1005
1006 if num_cols <= index::Column(1) {
1008 num_cols = index::Column(2);
1009 }
1010
1011 if num_lines <= index::Line(1) {
1013 num_lines = index::Line(2);
1014 }
1015
1016 if self.cursor.point.line >= num_lines {
1018 let lines = self.cursor.point.line - num_lines + 1;
1019 self.grid
1020 .scroll_up(&(index::Line(0)..old_lines), lines, &self.cursor.template);
1021 }
1022
1023 if self.cursor_save_alt.point.line >= num_lines {
1025 let lines = self.cursor_save_alt.point.line - num_lines + 1;
1026 self.alt_grid.scroll_up(
1027 &(index::Line(0)..old_lines),
1028 lines,
1029 &self.cursor_save_alt.template,
1030 );
1031 }
1032
1033 if num_lines > old_lines {
1035 if self.mode.contains(TermMode::ALT_SCREEN) {
1036 let growage = min(
1037 num_lines - old_lines,
1038 index::Line(self.alt_grid.scroll_limit()),
1039 );
1040 self.cursor_save.point.line += growage;
1041 } else {
1042 let growage = min(num_lines - old_lines, index::Line(self.grid.scroll_limit()));
1043 self.cursor.point.line += growage;
1044 }
1045 }
1046
1047 debug!(
1048 "New num_cols is {} and num_lines is {}",
1049 num_cols, num_lines
1050 );
1051
1052 self.grid.resize(num_lines, num_cols, &Cell::default());
1054 self.alt_grid.resize(num_lines, num_cols, &Cell::default());
1055
1056 self.scroll_region = index::Line(0)..self.grid.num_lines();
1058
1059 self.cursor.point.col = min(self.cursor.point.col, num_cols - 1);
1061 self.cursor.point.line = min(self.cursor.point.line, num_lines - 1);
1062 self.cursor_save.point.col = min(self.cursor_save.point.col, num_cols - 1);
1063 self.cursor_save.point.line = min(self.cursor_save.point.line, num_lines - 1);
1064 self.cursor_save_alt.point.col = min(self.cursor_save_alt.point.col, num_cols - 1);
1065 self.cursor_save_alt.point.line = min(self.cursor_save_alt.point.line, num_lines - 1);
1066
1067 self.tabs = TabStops::new(self.grid.num_cols(), self.tabspaces);
1069 }
1070
1071 #[inline]
1072 pub fn size_info(&self) -> &SizeInfo {
1073 &self.size_info
1074 }
1075
1076 #[inline]
1077 pub fn mode(&self) -> &TermMode {
1078 &self.mode
1079 }
1080
1081 #[inline]
1082 pub fn cursor(&self) -> &Cursor {
1083 &self.cursor
1084 }
1085
1086 pub fn swap_alt(&mut self) {
1087 if self.alt {
1088 let template = &self.cursor.template;
1089 self.grid.region_mut(..).each(|c| c.reset(template));
1090 }
1091
1092 self.alt = !self.alt;
1093 ::std::mem::swap(&mut self.grid, &mut self.alt_grid);
1094 }
1095
1096 #[inline]
1101 fn scroll_down_relative(&mut self, origin: index::Line, mut lines: index::Line) {
1102 trace!(
1103 "Scrolling down relative: origin={}, lines={}",
1104 origin,
1105 lines
1106 );
1107 lines = min(lines, self.scroll_region.end - self.scroll_region.start);
1108 lines = min(lines, self.scroll_region.end - origin);
1109
1110 self.grid.scroll_down(
1112 &(origin..self.scroll_region.end),
1113 lines,
1114 &self.cursor.template,
1115 );
1116 }
1117
1118 #[inline]
1123 fn scroll_up_relative(&mut self, origin: index::Line, lines: index::Line) {
1124 trace!("Scrolling up relative: origin={}, lines={}", origin, lines);
1125 let lines = min(lines, self.scroll_region.end - self.scroll_region.start);
1126
1127 self.grid.scroll_up(
1129 &(origin..self.scroll_region.end),
1130 lines,
1131 &self.cursor.template,
1132 );
1133 }
1134
1135 fn deccolm(&mut self) {
1136 let scroll_region = index::Line(0)..self.grid.num_lines();
1139 self.set_scrolling_region(scroll_region);
1140
1141 let template = self.cursor.template;
1143 self.grid.region_mut(..).each(|c| c.reset(&template));
1144 }
1145
1146 #[inline]
1147 pub fn exit(&mut self) {
1148 self.should_exit = true;
1149 }
1150
1151 #[inline]
1152 pub fn should_exit(&self) -> bool {
1153 self.should_exit
1154 }
1155}
1156
1157impl ansi::TermInfo for Term {
1158 #[inline]
1159 fn lines(&self) -> index::Line {
1160 self.grid.num_lines()
1161 }
1162
1163 #[inline]
1164 fn cols(&self) -> index::Column {
1165 self.grid.num_cols()
1166 }
1167}
1168
1169impl ansi::Handler for Term {
1170 #[inline]
1172 fn set_title(&mut self, title: &str) {
1173 if self.dynamic_title {
1174 self.next_title = Some(title.to_owned());
1175 }
1176 }
1177
1178 #[inline]
1180 fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
1181 self.next_mouse_cursor = Some(cursor);
1182 }
1183
1184 #[inline]
1185 fn set_cursor_style(&mut self, style: Option<CursorStyle>) {
1186 trace!("Setting cursor style {:?}", style);
1187 self.cursor_style = style;
1188 }
1189
1190 #[inline]
1192 fn input(&mut self, c: char) {
1193 if self.auto_scroll {
1195 self.scroll_display(Scroll::Bottom);
1196 }
1197
1198 if self.input_needs_wrap {
1199 if !self.mode.contains(mode::TermMode::LINE_WRAP) {
1200 return;
1201 }
1202
1203 trace!("Wrapping input");
1204
1205 {
1206 let location = index::Point {
1207 line: self.cursor.point.line,
1208 col: self.cursor.point.col,
1209 };
1210
1211 let cell = &mut self.grid[&location];
1212 cell.flags.insert(cell::Flags::WRAPLINE);
1213 }
1214
1215 if (self.cursor.point.line + 1) >= self.scroll_region.end {
1216 self.linefeed();
1217 } else {
1218 self.cursor.point.line += 1;
1219 }
1220
1221 self.cursor.point.col = index::Column(0);
1222 self.input_needs_wrap = false;
1223 }
1224
1225 if let Some(width) = c.width() {
1227 let num_cols = self.grid.num_cols();
1228
1229 if self.mode.contains(mode::TermMode::INSERT)
1231 && self.cursor.point.col + width < num_cols
1232 {
1233 let line = self.cursor.point.line;
1234 let col = self.cursor.point.col;
1235 let line = &mut self.grid[line];
1236
1237 let src = line[col..].as_ptr();
1238 let dst = line[(col + width)..].as_mut_ptr();
1239 unsafe {
1240 ptr::copy(src, dst, (num_cols - col - width).0);
1242 }
1243 }
1244
1245 if width == 0 {
1247 let col = self.cursor.point.col.0.saturating_sub(1);
1248 let line = self.cursor.point.line;
1249 if self.grid[line][index::Column(col)]
1250 .flags
1251 .contains(cell::Flags::WIDE_CHAR_SPACER)
1252 {
1253 col.saturating_sub(1);
1254 }
1255 self.grid[line][index::Column(col)].push_extra(c);
1256 return;
1257 }
1258
1259 let cell = &mut self.grid[&self.cursor.point];
1260 *cell = self.cursor.template;
1261 cell.c = self.cursor.charsets[self.active_charset].map(c);
1262
1263 if width == 2 {
1265 cell.flags.insert(cell::Flags::WIDE_CHAR);
1266
1267 if self.cursor.point.col + 1 < num_cols {
1268 self.cursor.point.col += 1;
1269 let spacer = &mut self.grid[&self.cursor.point];
1270 *spacer = self.cursor.template;
1271 spacer.flags.insert(cell::Flags::WIDE_CHAR_SPACER);
1272 }
1273 }
1274 }
1275
1276 if (self.cursor.point.col + 1) < self.grid.num_cols() {
1277 self.cursor.point.col += 1;
1278 } else {
1279 self.input_needs_wrap = true;
1280 }
1281 }
1282
1283 #[inline]
1284 fn goto(&mut self, line: index::Line, col: index::Column) {
1285 trace!("Going to: line={}, col={}", line, col);
1286 let (y_offset, max_y) = if self.mode.contains(mode::TermMode::ORIGIN) {
1287 (self.scroll_region.start, self.scroll_region.end - 1)
1288 } else {
1289 (index::Line(0), self.grid.num_lines() - 1)
1290 };
1291
1292 self.cursor.point.line = min(line + y_offset, max_y);
1293 self.cursor.point.col = min(col, self.grid.num_cols() - 1);
1294 self.input_needs_wrap = false;
1295 }
1296
1297 #[inline]
1298 fn goto_line(&mut self, line: index::Line) {
1299 trace!("Going to line: {}", line);
1300 self.goto(line, self.cursor.point.col)
1301 }
1302
1303 #[inline]
1304 fn goto_col(&mut self, col: index::Column) {
1305 trace!("Going to column: {}", col);
1306 self.goto(self.cursor.point.line, col)
1307 }
1308
1309 #[inline]
1310 fn insert_blank(&mut self, count: index::Column) {
1311 let count = min(count, self.size_info.cols() - self.cursor.point.col);
1314
1315 let source = self.cursor.point.col;
1316 let destination = self.cursor.point.col + count;
1317 let num_cells = (self.size_info.cols() - destination).0;
1318
1319 let line = &mut self.grid[self.cursor.point.line];
1320
1321 unsafe {
1322 let src = line[source..].as_ptr();
1323 let dst = line[destination..].as_mut_ptr();
1324
1325 ptr::copy(src, dst, num_cells);
1326 }
1327
1328 let template = self.cursor.template;
1331 for c in &mut line[source..destination] {
1332 c.reset(&template);
1333 }
1334 }
1335
1336 #[inline]
1337 fn move_up(&mut self, lines: index::Line) {
1338 trace!("Moving up: {}", lines);
1339 let move_to = index::Line(self.cursor.point.line.0.saturating_sub(lines.0));
1340 self.goto(move_to, self.cursor.point.col)
1341 }
1342
1343 #[inline]
1344 fn move_down(&mut self, lines: index::Line) {
1345 trace!("Moving down: {}", lines);
1346 let move_to = self.cursor.point.line + lines;
1347 self.goto(move_to, self.cursor.point.col)
1348 }
1349
1350 #[inline]
1351 fn identify_terminal<W: io::Write>(&mut self, writer: &mut W) {
1352 let _ = writer.write_all(b"\x1b[?6c");
1353 }
1354
1355 #[inline]
1356 fn device_status<W: io::Write>(&mut self, writer: &mut W, arg: usize) {
1357 trace!("Reporting device status: {}", arg);
1358 match arg {
1359 5 => {
1360 let _ = writer.write_all(b"\x1b[0n");
1361 }
1362 6 => {
1363 let pos = self.cursor.point;
1364 let _ = write!(writer, "\x1b[{};{}R", pos.line + 1, pos.col + 1);
1365 }
1366 _ => debug!("unknown device status query: {}", arg),
1367 };
1368 }
1369
1370 #[inline]
1371 fn move_forward(&mut self, cols: index::Column) {
1372 trace!("Moving forward: {}", cols);
1373 self.cursor.point.col = min(self.cursor.point.col + cols, self.grid.num_cols() - 1);
1374 self.input_needs_wrap = false;
1375 }
1376
1377 #[inline]
1378 fn move_backward(&mut self, cols: index::Column) {
1379 trace!("Moving backward: {}", cols);
1380 self.cursor.point.col -= min(self.cursor.point.col, cols);
1381 self.input_needs_wrap = false;
1382 }
1383
1384 #[inline]
1385 fn move_down_and_cr(&mut self, lines: index::Line) {
1386 trace!("Moving down and cr: {}", lines);
1387 let move_to = self.cursor.point.line + lines;
1388 self.goto(move_to, index::Column(0))
1389 }
1390
1391 #[inline]
1392 fn move_up_and_cr(&mut self, lines: index::Line) {
1393 trace!("Moving up and cr: {}", lines);
1394 let move_to = index::Line(self.cursor.point.line.0.saturating_sub(lines.0));
1395 self.goto(move_to, index::Column(0))
1396 }
1397
1398 #[inline]
1399 fn put_tab(&mut self, mut count: i64) {
1400 trace!("Putting tab: {}", count);
1401
1402 while self.cursor.point.col < self.grid.num_cols() && count != 0 {
1403 count -= 1;
1404
1405 let cell = &mut self.grid[&self.cursor.point];
1406 if cell.c == ' ' {
1407 cell.c = self.cursor.charsets[self.active_charset].map('\t');
1408 }
1409
1410 loop {
1411 if (self.cursor.point.col + 1) == self.grid.num_cols() {
1412 break;
1413 }
1414
1415 self.cursor.point.col += 1;
1416
1417 if self.tabs[self.cursor.point.col] {
1418 break;
1419 }
1420 }
1421 }
1422
1423 self.input_needs_wrap = false;
1424 }
1425
1426 #[inline]
1428 fn backspace(&mut self) {
1429 trace!("Backspace");
1430 if self.cursor.point.col > index::Column(0) {
1431 self.cursor.point.col -= 1;
1432 self.input_needs_wrap = false;
1433 }
1434 }
1435
1436 #[inline]
1438 fn carriage_return(&mut self) {
1439 trace!("Carriage return");
1440 self.cursor.point.col = index::Column(0);
1441 self.input_needs_wrap = false;
1442 }
1443
1444 #[inline]
1446 fn linefeed(&mut self) {
1447 trace!("Linefeed");
1448 let next = self.cursor.point.line + 1;
1449 if next == self.scroll_region.end {
1450 self.scroll_up(index::Line(1));
1451 } else if next < self.grid.num_lines() {
1452 self.cursor.point.line += 1;
1453 }
1454 }
1455
1456 #[inline]
1458 fn bell(&mut self) {
1459 trace!("Bell");
1460 self.visual_bell.ring();
1461 self.next_is_urgent = Some(true);
1462 }
1463
1464 #[inline]
1465 fn substitute(&mut self) {
1466 trace!("[unimplemented] Substitute");
1467 }
1468
1469 #[inline]
1492 fn newline(&mut self) {
1493 self.linefeed();
1494
1495 if self.mode.contains(mode::TermMode::LINE_FEED_NEW_LINE) {
1496 self.carriage_return();
1497 }
1498 }
1499
1500 #[inline]
1501 fn set_horizontal_tabstop(&mut self) {
1502 trace!("Setting horizontal tabstop");
1503 let column = self.cursor.point.col;
1504 self.tabs[column] = true;
1505 }
1506
1507 #[inline]
1508 fn scroll_up(&mut self, lines: index::Line) {
1509 let origin = self.scroll_region.start;
1510 self.scroll_up_relative(origin, lines);
1511 }
1512
1513 #[inline]
1514 fn scroll_down(&mut self, lines: index::Line) {
1515 let origin = self.scroll_region.start;
1516 self.scroll_down_relative(origin, lines);
1517 }
1518
1519 #[inline]
1520 fn insert_blank_lines(&mut self, lines: index::Line) {
1521 use crate::index::Contains;
1522 trace!("Inserting blank {} lines", lines);
1523 if self.scroll_region.contains_(self.cursor.point.line) {
1524 let origin = self.cursor.point.line;
1525 self.scroll_down_relative(origin, lines);
1526 }
1527 }
1528
1529 #[inline]
1530 fn delete_lines(&mut self, lines: index::Line) {
1531 use crate::index::Contains;
1532 trace!("Deleting {} lines", lines);
1533 if self.scroll_region.contains_(self.cursor.point.line) {
1534 let origin = self.cursor.point.line;
1535 self.scroll_up_relative(origin, lines);
1536 }
1537 }
1538
1539 #[inline]
1540 fn erase_chars(&mut self, count: index::Column) {
1541 trace!(
1542 "Erasing chars: count={}, col={}",
1543 count,
1544 self.cursor.point.col
1545 );
1546 let start = self.cursor.point.col;
1547 let end = min(start + count, self.grid.num_cols());
1548
1549 let row = &mut self.grid[self.cursor.point.line];
1550 let template = self.cursor.template; for c in &mut row[start..end] {
1552 c.reset(&template);
1553 }
1554 }
1555
1556 #[inline]
1557 fn delete_chars(&mut self, count: index::Column) {
1558 let count = min(count, self.size_info.cols());
1560
1561 let start = self.cursor.point.col;
1562 let end = min(start + count, self.grid.num_cols() - 1);
1563 let n = (self.size_info.cols() - end).0;
1564
1565 let line = &mut self.grid[self.cursor.point.line];
1566
1567 unsafe {
1568 let src = line[end..].as_ptr();
1569 let dst = line[start..].as_mut_ptr();
1570
1571 ptr::copy(src, dst, n);
1572 }
1573
1574 let template = self.cursor.template;
1577 let end = self.size_info.cols() - count;
1578 for c in &mut line[end..] {
1579 c.reset(&template);
1580 }
1581 }
1582
1583 #[inline]
1584 fn move_backward_tabs(&mut self, count: i64) {
1585 trace!("Moving backward {} tabs", count);
1586
1587 for _ in 0..count {
1588 let mut col = self.cursor.point.col;
1589 for i in (0..(col.0)).rev() {
1590 if self.tabs[index::Column(i)] {
1591 col = index::Column(i);
1592 break;
1593 }
1594 }
1595 self.cursor.point.col = col;
1596 }
1597 }
1598
1599 #[inline]
1600 fn move_forward_tabs(&mut self, count: i64) {
1601 trace!("[unimplemented] Moving forward {} tabs", count);
1602 }
1603
1604 #[inline]
1605 fn save_cursor_position(&mut self) {
1606 trace!("Saving cursor position");
1607 let cursor = if self.alt {
1608 &mut self.cursor_save_alt
1609 } else {
1610 &mut self.cursor_save
1611 };
1612
1613 *cursor = self.cursor;
1614 }
1615
1616 #[inline]
1617 fn restore_cursor_position(&mut self) {
1618 trace!("Restoring cursor position");
1619 let source = if self.alt {
1620 &self.cursor_save_alt
1621 } else {
1622 &self.cursor_save
1623 };
1624
1625 self.cursor = *source;
1626 self.cursor.point.line = min(self.cursor.point.line, self.grid.num_lines() - 1);
1627 self.cursor.point.col = min(self.cursor.point.col, self.grid.num_cols() - 1);
1628 }
1629
1630 #[inline]
1631 fn clear_line(&mut self, mode: ansi::LineClearMode) {
1632 trace!("Clearing line: {:?}", mode);
1633 let mut template = self.cursor.template;
1634 template.flags ^= template.flags;
1635
1636 let col = self.cursor.point.col;
1637
1638 match mode {
1639 ansi::LineClearMode::Right => {
1640 let row = &mut self.grid[self.cursor.point.line];
1641 for cell in &mut row[col..] {
1642 cell.reset(&template);
1643 }
1644 }
1645 ansi::LineClearMode::Left => {
1646 let row = &mut self.grid[self.cursor.point.line];
1647 for cell in &mut row[..=col] {
1648 cell.reset(&template);
1649 }
1650 }
1651 ansi::LineClearMode::All => {
1652 let row = &mut self.grid[self.cursor.point.line];
1653 for cell in &mut row[..] {
1654 cell.reset(&template);
1655 }
1656 }
1657 }
1658 }
1659
1660 #[inline]
1661 fn clear_screen(&mut self, mode: ansi::ClearMode) {
1662 trace!("Clearing screen: {:?}", mode);
1663 let mut template = self.cursor.template;
1664 template.flags ^= template.flags;
1665
1666 self.grid.selection = None;
1668
1669 match mode {
1670 ansi::ClearMode::Below => {
1671 for cell in &mut self.grid[self.cursor.point.line][self.cursor.point.col..] {
1672 cell.reset(&template);
1673 }
1674 if self.cursor.point.line < self.grid.num_lines() - 1 {
1675 self.grid
1676 .region_mut((self.cursor.point.line + 1)..)
1677 .each(|cell| cell.reset(&template));
1678 }
1679 }
1680 ansi::ClearMode::All => self.grid.region_mut(..).each(|c| c.reset(&template)),
1681 ansi::ClearMode::Above => {
1682 if self.cursor.point.line > index::Line(1) {
1684 self.grid
1686 .region_mut(..self.cursor.point.line)
1687 .each(|cell| cell.reset(&template));
1688 }
1689 let end = min(self.cursor.point.col + 1, self.grid.num_cols());
1691 for cell in &mut self.grid[self.cursor.point.line][..end] {
1692 cell.reset(&template);
1693 }
1694 }
1695 ansi::ClearMode::Saved => self.grid.clear_history(),
1697 }
1698 }
1699
1700 #[inline]
1701 fn clear_tabs(&mut self, mode: ansi::TabulationClearMode) {
1702 trace!("Clearing tabs: {:?}", mode);
1703 match mode {
1704 ansi::TabulationClearMode::Current => {
1705 let column = self.cursor.point.col;
1706 self.tabs[column] = false;
1707 }
1708 ansi::TabulationClearMode::All => {
1709 self.tabs.clear_all();
1710 }
1711 }
1712 }
1713
1714 #[inline]
1716 fn reset_state(&mut self) {
1717 self.input_needs_wrap = false;
1718 self.next_title = None;
1719 self.next_mouse_cursor = None;
1720 self.alt = false;
1721 self.cursor = Default::default();
1722 self.active_charset = Default::default();
1723 self.mode = Default::default();
1724 self.next_is_urgent = None;
1725 self.cursor_save = Default::default();
1726 self.cursor_save_alt = Default::default();
1727 self.cursor_style = None;
1728 self.grid.clear_history();
1729 self.grid.region_mut(..).each(|c| c.reset(&Cell::default()));
1730 }
1731
1732 #[inline]
1733 fn reverse_index(&mut self) {
1734 trace!("Reversing index");
1735 if self.cursor.point.line == self.scroll_region.start {
1737 self.scroll_down(index::Line(1));
1738 } else {
1739 self.cursor.point.line -= min(self.cursor.point.line, index::Line(1));
1740 }
1741 }
1742
1743 #[inline]
1745 fn terminal_attribute(&mut self, attr: Attr) {
1746 trace!("Setting attribute: {:?}", attr);
1747 match attr {
1748 Attr::Foreground(color) => self.cursor.template.fg = color,
1749 Attr::Background(color) => self.cursor.template.bg = color,
1750 Attr::Reset => {
1751 self.cursor.template.fg = Color::Named(NamedColor::Foreground);
1752 self.cursor.template.bg = Color::Named(NamedColor::Background);
1753 self.cursor.template.flags = cell::Flags::empty();
1754 }
1755 Attr::Reverse => self.cursor.template.flags.insert(cell::Flags::INVERSE),
1756 Attr::CancelReverse => self.cursor.template.flags.remove(cell::Flags::INVERSE),
1757 Attr::Bold => self.cursor.template.flags.insert(cell::Flags::BOLD),
1758 Attr::CancelBold => self.cursor.template.flags.remove(cell::Flags::BOLD),
1759 Attr::Dim => self.cursor.template.flags.insert(cell::Flags::DIM),
1760 Attr::CancelBoldDim => self
1761 .cursor
1762 .template
1763 .flags
1764 .remove(cell::Flags::BOLD | cell::Flags::DIM),
1765 Attr::Italic => self.cursor.template.flags.insert(cell::Flags::ITALIC),
1766 Attr::CancelItalic => self.cursor.template.flags.remove(cell::Flags::ITALIC),
1767 Attr::Underscore => self.cursor.template.flags.insert(cell::Flags::UNDERLINE),
1768 Attr::CancelUnderline => self.cursor.template.flags.remove(cell::Flags::UNDERLINE),
1769 Attr::Hidden => self.cursor.template.flags.insert(cell::Flags::HIDDEN),
1770 Attr::CancelHidden => self.cursor.template.flags.remove(cell::Flags::HIDDEN),
1771 Attr::Strike => self.cursor.template.flags.insert(cell::Flags::STRIKEOUT),
1772 Attr::CancelStrike => self.cursor.template.flags.remove(cell::Flags::STRIKEOUT),
1773 _ => {
1774 debug!("Term got unhandled attr: {:?}", attr);
1775 }
1776 }
1777 }
1778
1779 #[inline]
1780 fn set_mode(&mut self, mode: ansi::Mode) {
1781 trace!("Setting mode: {:?}", mode);
1782 match mode {
1783 ansi::Mode::SwapScreenAndSetRestoreCursor => {
1784 self.mode.insert(mode::TermMode::ALT_SCREEN);
1785 self.save_cursor_position();
1786 if !self.alt {
1787 self.swap_alt();
1788 }
1789 self.save_cursor_position();
1790 }
1791 ansi::Mode::ShowCursor => self.mode.insert(mode::TermMode::SHOW_CURSOR),
1792 ansi::Mode::CursorKeys => self.mode.insert(mode::TermMode::APP_CURSOR),
1793 ansi::Mode::ReportMouseClicks => {
1794 self.mode.insert(mode::TermMode::MOUSE_REPORT_CLICK);
1795 self.set_mouse_cursor(MouseCursor::Arrow);
1796 }
1797 ansi::Mode::ReportCellMouseMotion => {
1798 self.mode.insert(mode::TermMode::MOUSE_DRAG);
1799 self.set_mouse_cursor(MouseCursor::Arrow);
1800 }
1801 ansi::Mode::ReportAllMouseMotion => {
1802 self.mode.insert(mode::TermMode::MOUSE_MOTION);
1803 self.set_mouse_cursor(MouseCursor::Arrow);
1804 }
1805 ansi::Mode::ReportFocusInOut => self.mode.insert(mode::TermMode::FOCUS_IN_OUT),
1806 ansi::Mode::BracketedPaste => self.mode.insert(mode::TermMode::BRACKETED_PASTE),
1807 ansi::Mode::SgrMouse => self.mode.insert(mode::TermMode::SGR_MOUSE),
1808 ansi::Mode::LineWrap => self.mode.insert(mode::TermMode::LINE_WRAP),
1809 ansi::Mode::LineFeedNewLine => self.mode.insert(mode::TermMode::LINE_FEED_NEW_LINE),
1810 ansi::Mode::Origin => self.mode.insert(mode::TermMode::ORIGIN),
1811 ansi::Mode::DECCOLM => self.deccolm(),
1812 ansi::Mode::Insert => self.mode.insert(mode::TermMode::INSERT), ansi::Mode::BlinkingCursor => {
1814 trace!("... unimplemented mode");
1815 }
1816 }
1817 }
1818
1819 #[inline]
1820 fn unset_mode(&mut self, mode: ansi::Mode) {
1821 trace!("Unsetting mode: {:?}", mode);
1822 match mode {
1823 ansi::Mode::SwapScreenAndSetRestoreCursor => {
1824 self.mode.remove(mode::TermMode::ALT_SCREEN);
1825 self.restore_cursor_position();
1826 if self.alt {
1827 self.swap_alt();
1828 }
1829 self.restore_cursor_position();
1830 }
1831 ansi::Mode::ShowCursor => self.mode.remove(mode::TermMode::SHOW_CURSOR),
1832 ansi::Mode::CursorKeys => self.mode.remove(mode::TermMode::APP_CURSOR),
1833 ansi::Mode::ReportMouseClicks => {
1834 self.mode.remove(mode::TermMode::MOUSE_REPORT_CLICK);
1835 self.set_mouse_cursor(MouseCursor::Text);
1836 }
1837 ansi::Mode::ReportCellMouseMotion => {
1838 self.mode.remove(mode::TermMode::MOUSE_DRAG);
1839 self.set_mouse_cursor(MouseCursor::Text);
1840 }
1841 ansi::Mode::ReportAllMouseMotion => {
1842 self.mode.remove(mode::TermMode::MOUSE_MOTION);
1843 self.set_mouse_cursor(MouseCursor::Text);
1844 }
1845 ansi::Mode::ReportFocusInOut => self.mode.remove(mode::TermMode::FOCUS_IN_OUT),
1846 ansi::Mode::BracketedPaste => self.mode.remove(mode::TermMode::BRACKETED_PASTE),
1847 ansi::Mode::SgrMouse => self.mode.remove(mode::TermMode::SGR_MOUSE),
1848 ansi::Mode::LineWrap => self.mode.remove(mode::TermMode::LINE_WRAP),
1849 ansi::Mode::LineFeedNewLine => self.mode.remove(mode::TermMode::LINE_FEED_NEW_LINE),
1850 ansi::Mode::Origin => self.mode.remove(mode::TermMode::ORIGIN),
1851 ansi::Mode::DECCOLM => self.deccolm(),
1852 ansi::Mode::Insert => self.mode.remove(mode::TermMode::INSERT),
1853 ansi::Mode::BlinkingCursor => {
1854 trace!("... unimplemented mode");
1855 }
1856 }
1857 }
1858
1859 #[inline]
1860 fn set_scrolling_region(&mut self, region: Range<index::Line>) {
1861 trace!("Setting scrolling region: {:?}", region);
1862 self.scroll_region.start = min(region.start, self.grid.num_lines());
1863 self.scroll_region.end = min(region.end, self.grid.num_lines());
1864 self.goto(index::Line(0), index::Column(0));
1865 }
1866
1867 #[inline]
1868 fn set_keypad_application_mode(&mut self) {
1869 trace!("Setting keypad application mode");
1870 self.mode.insert(mode::TermMode::APP_KEYPAD);
1871 }
1872
1873 #[inline]
1874 fn unset_keypad_application_mode(&mut self) {
1875 trace!("Unsetting keypad application mode");
1876 self.mode.remove(mode::TermMode::APP_KEYPAD);
1877 }
1878
1879 #[inline]
1880 fn set_active_charset(&mut self, index: CharsetIndex) {
1881 trace!("Setting active charset {:?}", index);
1882 self.active_charset = index;
1883 }
1884
1885 #[inline]
1886 fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
1887 trace!("Configuring charset {:?} as {:?}", index, charset);
1888 self.cursor.charsets[index] = charset;
1889 }
1890
1891 #[inline]
1893 fn set_clipboard(&mut self, _string: &str) {
1894 }
1896
1897 #[inline]
1898 fn dectest(&mut self) {
1899 trace!("Dectesting");
1900 let mut template = self.cursor.template;
1901 template.c = 'E';
1902
1903 self.grid.region_mut(..).each(|c| c.reset(&template));
1904 }
1905}
1906
1907struct TabStops {
1908 tabs: Vec<bool>,
1909}
1910
1911impl TabStops {
1912 fn new(num_cols: index::Column, tabspaces: usize) -> TabStops {
1913 TabStops {
1914 tabs: index::Range::from(index::Column(0)..num_cols)
1915 .map(|i| (*i as usize) % tabspaces == 0)
1916 .collect::<Vec<bool>>(),
1917 }
1918 }
1919
1920 fn clear_all(&mut self) {
1921 unsafe {
1922 ptr::write_bytes(self.tabs.as_mut_ptr(), 0, self.tabs.len());
1923 }
1924 }
1925}
1926
1927impl Index<index::Column> for TabStops {
1928 type Output = bool;
1929
1930 fn index(&self, index: index::Column) -> &bool {
1931 &self.tabs[index.0]
1932 }
1933}
1934
1935impl IndexMut<index::Column> for TabStops {
1936 fn index_mut(&mut self, index: index::Column) -> &mut bool {
1937 self.tabs.index_mut(index.0)
1938 }
1939}
1940
1941#[cfg(test)]
1942mod tests {
1943 use super::{Cell, SizeInfo, Term};
1944 use crate::term::cell;
1945
1946 use crate::ansi::{self, CharsetIndex, Handler, StandardCharset};
1947 use crate::grid::{Grid, Scroll};
1948 use crate::index;
1949 use crate::selection::Selection;
1950 use std::mem;
1951
1952 #[test]
1953 fn semantic_selection_works() {
1954 let size = SizeInfo {
1955 width: 21.0,
1956 height: 51.0,
1957 cell_width: 3.0,
1958 cell_height: 3.0,
1959 padding_x: 0.0,
1960 padding_y: 0.0,
1961 dpr: 1.0,
1962 };
1963 let mut term = Term::new(size);
1964 let mut grid: Grid<Cell> = Grid::new(index::Line(3), index::Column(5), 0, Cell::default());
1965 for i in 0..5 {
1966 for j in 0..2 {
1967 grid[index::Line(j)][index::Column(i)].c = 'a';
1968 }
1969 }
1970 grid[index::Line(0)][index::Column(0)].c = '"';
1971 grid[index::Line(0)][index::Column(3)].c = '"';
1972 grid[index::Line(1)][index::Column(2)].c = '"';
1973 grid[index::Line(0)][index::Column(4)]
1974 .flags
1975 .insert(cell::Flags::WRAPLINE);
1976
1977 let mut escape_chars = String::from("\"");
1978
1979 mem::swap(&mut term.grid, &mut grid);
1980 mem::swap(&mut term.semantic_escape_chars, &mut escape_chars);
1981
1982 {
1983 *term.selection_mut() = Some(Selection::semantic(index::Point {
1984 line: 2,
1985 col: index::Column(1),
1986 }));
1987 assert_eq!(term.selection_to_string(), Some(String::from("aa")));
1988 }
1989
1990 {
1991 *term.selection_mut() = Some(Selection::semantic(index::Point {
1992 line: 2,
1993 col: index::Column(4),
1994 }));
1995 assert_eq!(term.selection_to_string(), Some(String::from("aaa")));
1996 }
1997
1998 {
1999 *term.selection_mut() = Some(Selection::semantic(index::Point {
2000 line: 1,
2001 col: index::Column(1),
2002 }));
2003 assert_eq!(term.selection_to_string(), Some(String::from("aaa")));
2004 }
2005 }
2006
2007 #[test]
2008 fn line_selection_works() {
2009 let size = SizeInfo {
2010 width: 21.0,
2011 height: 51.0,
2012 cell_width: 3.0,
2013 cell_height: 3.0,
2014 padding_x: 0.0,
2015 padding_y: 0.0,
2016 dpr: 1.0,
2017 };
2018 let mut term = Term::new(size);
2019 let mut grid: Grid<Cell> = Grid::new(index::Line(1), index::Column(5), 0, Cell::default());
2020 for i in 0..5 {
2021 grid[index::Line(0)][index::Column(i)].c = 'a';
2022 }
2023 grid[index::Line(0)][index::Column(0)].c = '"';
2024 grid[index::Line(0)][index::Column(3)].c = '"';
2025
2026 mem::swap(&mut term.grid, &mut grid);
2027
2028 *term.selection_mut() = Some(Selection::lines(index::Point {
2029 line: 0,
2030 col: index::Column(3),
2031 }));
2032 assert_eq!(term.selection_to_string(), Some(String::from("\"aa\"a\n")));
2033 }
2034
2035 #[test]
2036 fn selecting_empty_line() {
2037 let size = SizeInfo {
2038 width: 21.0,
2039 height: 51.0,
2040 cell_width: 3.0,
2041 cell_height: 3.0,
2042 padding_x: 0.0,
2043 padding_y: 0.0,
2044 dpr: 1.0,
2045 };
2046 let mut term = Term::new(size);
2047 let mut grid: Grid<Cell> = Grid::new(index::Line(3), index::Column(3), 0, Cell::default());
2048 for l in 0..3 {
2049 if l != 1 {
2050 for c in 0..3 {
2051 grid[index::Line(l)][index::Column(c)].c = 'a';
2052 }
2053 }
2054 }
2055
2056 mem::swap(&mut term.grid, &mut grid);
2057
2058 let mut selection = Selection::simple(
2059 index::Point {
2060 line: 2,
2061 col: index::Column(0),
2062 },
2063 index::Side::Left,
2064 );
2065 selection.update(
2066 index::Point {
2067 line: 0,
2068 col: index::Column(2),
2069 },
2070 index::Side::Right,
2071 );
2072 *term.selection_mut() = Some(selection);
2073 assert_eq!(term.selection_to_string(), Some("aaa\n\naaa\n".into()));
2074 }
2075
2076 #[test]
2077 fn input_line_drawing_character() {
2078 let size = SizeInfo {
2079 width: 21.0,
2080 height: 51.0,
2081 cell_width: 3.0,
2082 cell_height: 3.0,
2083 padding_x: 0.0,
2084 padding_y: 0.0,
2085 dpr: 1.0,
2086 };
2087 let mut term = Term::new(size);
2088 let cursor = index::Point::new(index::Line(0), index::Column(0));
2089 term.configure_charset(
2090 CharsetIndex::G0,
2091 StandardCharset::SpecialCharacterAndLineDrawing,
2092 );
2093 term.input('a');
2094
2095 assert_eq!(term.grid()[&cursor].c, '▒');
2096 }
2097
2098 #[test]
2099 fn clear_saved_lines() {
2100 let size = SizeInfo {
2101 width: 21.0,
2102 height: 51.0,
2103 cell_width: 3.0,
2104 cell_height: 3.0,
2105 padding_x: 0.0,
2106 padding_y: 0.0,
2107 dpr: 1.0,
2108 };
2109 let mut term: Term = Term::new(size);
2110
2111 term.grid.scroll_up(
2113 &(index::Line(0)..index::Line(1)),
2114 index::Line(1),
2115 &Cell::default(),
2116 );
2117
2118 term.clear_screen(ansi::ClearMode::Saved);
2120
2121 let mut scrolled_grid = term.grid.clone();
2123 scrolled_grid.scroll_display(Scroll::Top);
2124 assert_eq!(term.grid, scrolled_grid);
2125 }
2126}
2127
2128#[cfg(all(test, feature = "bench"))]
2129mod benches {
2130 extern crate test;
2131
2132 use std::fs::File;
2133 use std::io::Read;
2134 use std::mem;
2135 use std::path::Path;
2136
2137 use crate::config::Config;
2138 use crate::grid::Grid;
2139 use crate::message_bar::MessageBuffer;
2140
2141 use super::cell::Cell;
2142 use super::{SizeInfo, Term};
2143
2144 fn read_string<P>(path: P) -> String
2145 where
2146 P: AsRef<Path>,
2147 {
2148 let mut res = String::new();
2149 File::open(path.as_ref())
2150 .unwrap()
2151 .read_to_string(&mut res)
2152 .unwrap();
2153
2154 res
2155 }
2156
2157 #[bench]
2167 fn render_iter(b: &mut test::Bencher) {
2168 let serialized_grid = read_string(concat!(
2170 env!("CARGO_MANIFEST_DIR"),
2171 "/tests/ref/vim_large_window_scroll/grid.json"
2172 ));
2173 let serialized_size = read_string(concat!(
2174 env!("CARGO_MANIFEST_DIR"),
2175 "/tests/ref/vim_large_window_scroll/size.json"
2176 ));
2177
2178 let mut grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
2179 let size: SizeInfo = json::from_str(&serialized_size).unwrap();
2180
2181 let config = Config::default();
2182
2183 let mut terminal = Term::new(size);
2184 mem::swap(&mut terminal.grid, &mut grid);
2185
2186 b.iter(|| {
2187 let iter = terminal.renderable_cells(&config, false);
2188 for cell in iter {
2189 test::black_box(cell);
2190 }
2191 })
2192 }
2193}