1use alloc::boxed::Box;
2use alloc::string::String;
3use core::mem::swap;
4use core::ops::Range;
5use core::sync::atomic::Ordering;
6use core::time::Duration;
7use core::{cmp::min, fmt};
8use pc_keyboard::KeyCode;
9
10use vte::ansi::{Attr, Color as AnsiColor, NamedMode, Rgb};
11use vte::ansi::{CharsetIndex, StandardCharset, TabulationClearMode};
12use vte::ansi::{ClearMode, CursorShape, Processor, Timeout};
13use vte::ansi::{CursorStyle, Hyperlink, KeyboardModes};
14use vte::ansi::{Handler, LineClearMode, Mode, NamedPrivateMode, PrivateMode};
15
16use crate::buffer::TerminalBuffer;
17use crate::cell::{Cell, Flags};
18use crate::color::{Color, ColorScheme};
19use crate::config::CONFIG;
20use crate::font::FontManager;
21use crate::graphic::{DrawTarget, Graphic};
22use crate::keyboard::{KeyboardEvent, KeyboardManager};
23use crate::mouse::{MouseEvent, MouseInput, MouseManager};
24use crate::palette::Palette;
25
26#[derive(Default)]
27pub struct DummySyncHandler;
28
29#[rustfmt::skip]
30impl Timeout for DummySyncHandler {
31 fn set_timeout(&mut self, _duration: Duration) {}
32 fn clear_timeout(&mut self) {}
33 fn pending_timeout(&self) -> bool { false }
34}
35
36bitflags::bitflags! {
37 pub struct TerminalMode: u32 {
38 const SHOW_CURSOR = 1 << 0;
39 const APP_CURSOR = 1 << 1;
40 const APP_KEYPAD = 1 << 2;
41 const MOUSE_REPORT_CLICK = 1 << 3;
42 const BRACKETED_PASTE = 1 << 4;
43 const SGR_MOUSE = 1 << 5;
44 const MOUSE_MOTION = 1 << 6;
45 const LINE_WRAP = 1 << 7;
46 const LINE_FEED_NEW_LINE = 1 << 8;
47 const ORIGIN = 1 << 9;
48 const INSERT = 1 << 10;
49 const FOCUS_IN_OUT = 1 << 11;
50 const ALT_SCREEN = 1 << 12;
51 const MOUSE_DRAG = 1 << 13;
52 const MOUSE_MODE = 1 << 14;
53 const UTF8_MOUSE = 1 << 15;
54 const ALTERNATE_SCROLL = 1 << 16;
55 const VI = 1 << 17;
56 const URGENCY_HINTS = 1 << 18;
57 const ANY = u32::MAX;
58 }
59}
60
61impl Default for TerminalMode {
62 fn default() -> TerminalMode {
63 TerminalMode::SHOW_CURSOR | TerminalMode::LINE_WRAP
64 }
65}
66
67#[derive(Debug, Default, Clone, Copy)]
68struct Cursor {
69 row: usize,
70 column: usize,
71 shape: CursorShape,
72}
73
74pub struct Terminal<D: DrawTarget> {
75 performer: Processor<DummySyncHandler>,
76 inner: TerminalInner<D>,
77}
78
79pub struct TerminalInner<D: DrawTarget> {
80 cursor: Cursor,
81 saved_cursor: Cursor,
82 alt_cursor: Cursor,
83 mode: TerminalMode,
84 attribute_template: Cell,
85 buffer: TerminalBuffer<D>,
86 keyboard: KeyboardManager,
87 mouse: MouseManager,
88 scroll_region: Range<usize>,
89}
90
91impl<D: DrawTarget> Terminal<D> {
92 pub fn new(display: D) -> Self {
93 let mut graphic = Graphic::new(display);
94 graphic.clear(Cell::default());
95
96 Self {
97 performer: Processor::new(),
98 inner: TerminalInner {
99 cursor: Cursor::default(),
100 saved_cursor: Cursor::default(),
101 alt_cursor: Cursor::default(),
102 mode: TerminalMode::default(),
103 attribute_template: Cell::default(),
104 buffer: TerminalBuffer::new(graphic),
105 keyboard: KeyboardManager::default(),
106 mouse: MouseManager::default(),
107 scroll_region: Default::default(),
108 },
109 }
110 }
111
112 pub fn rows(&self) -> usize {
113 self.inner.buffer.height()
114 }
115
116 pub fn columns(&self) -> usize {
117 self.inner.buffer.width()
118 }
119
120 pub fn flush(&mut self) {
121 self.inner.buffer.flush();
122 }
123
124 pub fn process(&mut self, bstr: &[u8]) {
125 self.inner.cursor_handler(false);
126 self.performer.advance(&mut self.inner, bstr);
127 if self.inner.mode.contains(TerminalMode::SHOW_CURSOR) {
128 self.inner.cursor_handler(true);
129 }
130 if CONFIG.auto_flush.load(Ordering::Relaxed) {
131 self.flush();
132 }
133 }
134}
135
136impl<D: DrawTarget> Terminal<D> {
137 pub fn handle_keyboard(&mut self, scancode: u8) -> Option<String> {
138 let event = self.inner.keyboard.handle_keyboard(scancode);
139
140 if let KeyboardEvent::AnsiString(s) = event {
141 if !self.inner.buffer.is_latest() {
142 self.inner.buffer.goto_latest();
143 }
144 return Some(s);
145 }
146
147 match event {
148 KeyboardEvent::SetColorScheme(index) => self.set_color_scheme(index),
149 KeyboardEvent::ScrollUp => self.inner.scroll_history(-1),
150 KeyboardEvent::ScrollDown => self.inner.scroll_history(1),
151 KeyboardEvent::ScrollPageUp => self.inner.scroll_history(-(self.rows() as isize)),
152 KeyboardEvent::ScrollPageDown => self.inner.scroll_history(self.rows() as isize),
153 _ => {}
154 }
155 None
156 }
157
158 pub fn handle_mouse(&mut self, input: MouseInput) -> Option<String> {
159 if !self.inner.mode.contains(TerminalMode::ALT_SCREEN) {
160 match self.inner.mouse.handle_mouse(input) {
161 MouseEvent::Scroll(lines) => self.inner.scroll_history(lines),
162 _ => {}
163 }
164 return None;
165 }
166
167 match self.inner.mouse.handle_mouse(input) {
168 MouseEvent::Scroll(lines) => {
169 let key = if lines > 0 {
170 KeyCode::ArrowUp
171 } else {
172 KeyCode::ArrowDown
173 };
174 (0..lines.unsigned_abs())
175 .flat_map(|_| self.inner.keyboard.simulate_key(key))
176 .collect::<String>()
177 .into()
178 }
179 _ => None,
180 }
181 }
182}
183
184impl<D: DrawTarget> Terminal<D> {
185 pub fn set_auto_flush(&mut self, auto_flush: bool) {
186 CONFIG.auto_flush.store(auto_flush, Ordering::Relaxed);
187 }
188
189 pub fn set_logger(&mut self, logger: Option<fn(fmt::Arguments)>) {
190 *CONFIG.logger.lock() = logger;
191 }
192
193 pub fn set_bell_handler(&mut self, handler: Option<fn()>) {
194 *CONFIG.bell_handler.lock() = handler;
195 }
196
197 pub fn set_history_size(&mut self, size: usize) {
198 self.inner.buffer.resize_history(size);
199 }
200
201 pub fn set_scroll_speed(&mut self, speed: usize) {
202 self.inner.mouse.set_scroll_speed(speed);
203 }
204
205 pub fn set_auto_crnl(&mut self, auto_crnl: bool) {
206 CONFIG.auto_crnl.store(auto_crnl, Ordering::Relaxed);
207 }
208
209 pub fn set_font_manager(&mut self, font_manager: Box<dyn FontManager>) {
210 let (font_width, font_height) = font_manager.size();
211 self.inner.buffer.update_size(font_width, font_height);
212 self.inner.scroll_region = 0..self.inner.buffer.height() - 1;
213 self.inner.reset_state();
214 *CONFIG.font_manager.lock() = Some(font_manager);
215 }
216
217 pub fn set_color_scheme(&mut self, palette_index: usize) {
218 *CONFIG.color_scheme.lock() = ColorScheme::new(palette_index);
219 self.inner.attribute_template = Cell::default();
220 self.inner.buffer.full_flush();
221 }
222
223 pub fn set_custom_color_scheme(&mut self, palette: &Palette) {
224 *CONFIG.color_scheme.lock() = ColorScheme::from(palette);
225 self.inner.attribute_template = Cell::default();
226 self.inner.buffer.full_flush();
227 }
228}
229
230impl<D: DrawTarget> fmt::Write for Terminal<D> {
231 fn write_str(&mut self, s: &str) -> fmt::Result {
232 self.process(s.as_bytes());
233 Ok(())
234 }
235}
236
237impl<D: DrawTarget> TerminalInner<D> {
238 fn cursor_handler(&mut self, enable: bool) {
239 let row = self.cursor.row % self.buffer.height();
240 let column = self.cursor.column % self.buffer.width();
241
242 let mut origin_cell = self.buffer.read(row, column);
243
244 let flag = match self.cursor.shape {
245 CursorShape::Block => Flags::CURSOR_BLOCK,
246 CursorShape::Underline => Flags::CURSOR_UNDERLINE,
247 CursorShape::Beam => Flags::CURSOR_BEAM,
248 CursorShape::HollowBlock => Flags::CURSOR_BLOCK,
249 CursorShape::Hidden => Flags::HIDDEN,
250 };
251
252 if enable {
253 origin_cell.flags.insert(flag);
254 } else {
255 origin_cell.flags.remove(flag);
256 }
257
258 self.buffer.write(row, column, origin_cell);
259 }
260
261 fn scroll_history(&mut self, count: isize) {
262 self.buffer.scroll_history(count);
263 if CONFIG.auto_flush.load(Ordering::Relaxed) {
264 self.buffer.flush();
265 }
266 }
267
268 fn swap_alt_screen(&mut self) {
269 self.mode ^= TerminalMode::ALT_SCREEN;
270 swap(&mut self.cursor, &mut self.alt_cursor);
271 self.buffer.swap_alt_screen(self.attribute_template);
272
273 if !self.mode.contains(TerminalMode::ALT_SCREEN) {
274 self.saved_cursor = self.cursor;
275 self.attribute_template = Cell::default();
276 }
277 }
278}
279
280impl<D: DrawTarget> Handler for TerminalInner<D> {
281 fn set_title(&mut self, title: Option<String>) {
282 log!("Unhandled set_title: {:?}", title);
283 }
284
285 fn set_cursor_style(&mut self, style: Option<CursorStyle>) {
286 log!("Set cursor style: {:?}", style);
287 if let Some(style) = style {
288 self.set_cursor_shape(style.shape);
289 }
290 }
291
292 fn set_cursor_shape(&mut self, shape: CursorShape) {
293 log!("Set cursor shape: {:?}", shape);
294 self.cursor.shape = shape;
295 }
296
297 fn input(&mut self, content: char) {
298 let template = self.attribute_template.set_content(content);
299 let width = if template.wide { 2 } else { 1 };
300
301 if self.cursor.column + width > self.buffer.width() {
302 if !self.mode.contains(TerminalMode::LINE_WRAP) {
303 return;
304 }
305 self.linefeed();
306 self.carriage_return();
307 }
308
309 self.buffer
310 .write(self.cursor.row, self.cursor.column, template);
311 self.cursor.column += 1;
312
313 if template.wide {
314 self.buffer.write(
315 self.cursor.row,
316 self.cursor.column,
317 template.set_placeholder(),
318 );
319 self.cursor.column += 1;
320 }
321 }
322
323 fn goto(&mut self, row: i32, col: usize) {
324 self.cursor.row = min(row as usize, self.buffer.height());
325 self.cursor.column = min(col, self.buffer.width());
326 }
327
328 fn goto_line(&mut self, row: i32) {
329 log!("Goto line: {}", row);
330 self.goto(row, self.cursor.column);
331 }
332
333 fn goto_col(&mut self, col: usize) {
334 log!("Goto column: {}", col);
335 self.goto(self.cursor.row as i32, col);
336 }
337
338 fn insert_blank(&mut self, count: usize) {
339 log!("Insert blank: {}", count);
340 let (row, columns) = (self.cursor.row, self.buffer.width());
341 let count = min(count, columns - self.cursor.column);
342
343 let template = self.attribute_template.clear();
344 for column in (self.cursor.column..columns - count).rev() {
345 self.buffer
346 .write(row, column + count, self.buffer.read(row, column));
347 self.buffer.write(row, column, template);
348 }
349 }
350
351 fn move_up(&mut self, rows: usize) {
352 log!("Move up: {}", rows);
353 self.goto(
354 self.cursor.row.saturating_sub(rows) as i32,
355 self.cursor.column,
356 );
357 }
358
359 fn move_down(&mut self, rows: usize) {
360 log!("Move down: {}", rows);
361 let goto_line = min(self.cursor.row + rows, self.buffer.height() - 1) as i32;
362 self.goto(goto_line, self.cursor.column);
363 }
364
365 fn identify_terminal(&mut self, intermediate: Option<char>) {
366 log!("Unhandled identify terminal: {:?}", intermediate);
367 }
368
369 fn device_status(&mut self, status: usize) {
370 log!("Unhandled device_status: {}", status);
371 }
372
373 fn move_forward(&mut self, cols: usize) {
374 log!("Move forward: {}", cols);
375 self.cursor.column = min(self.cursor.column + cols, self.buffer.width() - 1);
376 }
377
378 fn move_backward(&mut self, cols: usize) {
379 log!("Move backward: {}", cols);
380 self.cursor.column = self.cursor.column.saturating_sub(cols);
381 }
382
383 fn move_up_and_cr(&mut self, rows: usize) {
384 log!("Move up and cr: {}", rows);
385 self.goto(self.cursor.row.saturating_sub(rows) as i32, 0);
386 }
387
388 fn move_down_and_cr(&mut self, rows: usize) {
389 log!("Move down and cr: {}", rows);
390 let goto_line = min(self.cursor.row + rows, self.buffer.height() - 1);
391 self.goto(goto_line as i32, 0);
392 }
393
394 fn put_tab(&mut self, count: u16) {
395 log!("Put tab: {}", count);
396 for _ in 0..count {
397 let tab_stop = self.cursor.column.div_ceil(8) * 8;
398 let end_column = tab_stop.min(self.buffer.width());
399 let template = self.attribute_template.clear();
400
401 while self.cursor.column < end_column {
402 self.buffer
403 .write(self.cursor.row, self.cursor.column, template);
404 self.cursor.column += 1;
405 }
406 }
407 }
408
409 fn backspace(&mut self) {
410 self.cursor.column = self.cursor.column.saturating_sub(1);
411 }
412
413 fn carriage_return(&mut self) {
414 self.cursor.column = 0;
415 }
416
417 fn linefeed(&mut self) {
418 if CONFIG.auto_crnl.load(Ordering::Relaxed) {
419 self.carriage_return();
420 }
421
422 if self.cursor.row == self.scroll_region.end {
423 self.scroll_up(1);
424 } else if self.cursor.row < self.buffer.height() - 1 {
425 self.cursor.row += 1;
426 }
427 }
428
429 fn bell(&mut self) {
430 log!("Bell triggered!");
431 CONFIG.bell_handler.lock().map(|handler| handler());
432 }
433
434 fn substitute(&mut self) {
435 log!("Unhandled substitute!");
436 }
437
438 fn newline(&mut self) {
439 log!("Newline!");
440 self.linefeed();
441
442 if self.mode.contains(TerminalMode::LINE_FEED_NEW_LINE) {
443 self.carriage_return();
444 }
445 }
446
447 fn set_horizontal_tabstop(&mut self) {
448 log!("Unhandled set horizontal tabstop!");
449 }
450
451 fn scroll_up(&mut self, count: usize) {
452 self.buffer.scroll_region(
453 -(count as isize),
454 self.attribute_template,
455 self.scroll_region.clone(),
456 );
457 }
458
459 fn scroll_down(&mut self, count: usize) {
460 self.buffer.scroll_region(
461 count as isize,
462 self.attribute_template,
463 self.scroll_region.clone(),
464 );
465 }
466
467 fn insert_blank_lines(&mut self, count: usize) {
468 log!("Insert blank lines: {}", count);
469 self.scroll_down(count);
470 }
471
472 fn delete_lines(&mut self, count: usize) {
473 log!("Delete lines: {}", count);
474 self.scroll_up(count);
475 }
476
477 fn erase_chars(&mut self, count: usize) {
478 log!("Erase chars: {}", count);
479 let start = self.cursor.column;
480 let end = min(start + count, self.buffer.width());
481
482 let template = self.attribute_template.clear();
483 for column in start..end {
484 self.buffer.write(self.cursor.row, column, template);
485 }
486 }
487
488 fn delete_chars(&mut self, count: usize) {
489 log!("Delete chars: {}", count);
490 let (row, columns) = (self.cursor.row, self.buffer.width());
491 let count = min(count, columns - self.cursor.column - 1);
492
493 let template = self.attribute_template.clear();
494 for column in (self.cursor.column + count)..columns {
495 self.buffer
496 .write(row, column - count, self.buffer.read(row, column));
497 self.buffer.write(row, column, template);
498 }
499 }
500
501 fn move_backward_tabs(&mut self, count: u16) {
502 log!("Unhandled move backward tabs: {}", count);
503 }
504
505 fn move_forward_tabs(&mut self, count: u16) {
506 log!("Unhandled move forward tabs: {}", count);
507 }
508
509 fn save_cursor_position(&mut self) {
510 log!("Save cursor position");
511 self.saved_cursor = self.cursor;
512 }
513
514 fn restore_cursor_position(&mut self) {
515 log!("Restore cursor position");
516 self.cursor = self.saved_cursor;
517 }
518
519 fn clear_line(&mut self, mode: LineClearMode) {
520 log!("Clear line: {:?}", mode);
521 let template = self.attribute_template.clear();
522 match mode {
523 LineClearMode::Right => {
524 for column in self.cursor.column..self.buffer.width() {
525 self.buffer.write(self.cursor.row, column, template);
526 }
527 }
528 LineClearMode::Left => {
529 for column in 0..=self.cursor.column {
530 self.buffer.write(self.cursor.row, column, template);
531 }
532 }
533 LineClearMode::All => {
534 for column in 0..self.buffer.width() {
535 self.buffer.write(self.cursor.row, column, template);
536 }
537 }
538 }
539 }
540
541 fn clear_screen(&mut self, mode: ClearMode) {
542 log!("Clear screen: {:?}", mode);
543 let template = self.attribute_template.clear();
544 match mode {
545 ClearMode::Above => {
546 for row in 0..self.cursor.row {
547 for column in 0..self.buffer.width() {
548 self.buffer.write(row, column, template);
549 }
550 }
551 for column in 0..=self.cursor.column {
552 self.buffer.write(self.cursor.row, column, template);
553 }
554 }
555 ClearMode::Below => {
556 for column in self.cursor.column..self.buffer.width() {
557 self.buffer.write(self.cursor.row, column, template);
558 }
559 for row in self.cursor.row + 1..self.buffer.height() {
560 for column in 0..self.buffer.width() {
561 self.buffer.write(row, column, template);
562 }
563 }
564 }
565 ClearMode::All => {
566 self.buffer.clear(template);
567 self.cursor = Cursor::default();
568 }
569 ClearMode::Saved => {
570 self.buffer.clear(template);
571 self.cursor = Cursor::default();
572 self.buffer.clear_history();
573 }
574 }
575 }
576
577 fn clear_tabs(&mut self, mode: TabulationClearMode) {
578 log!("Unhandled clear tabs: {:?}", mode);
579 }
580
581 fn reset_state(&mut self) {
582 log!("Reset state");
583 if self.mode.contains(TerminalMode::ALT_SCREEN) {
584 self.swap_alt_screen();
585 }
586 self.buffer.clear(Cell::default());
587 self.cursor = Cursor::default();
588 self.saved_cursor = self.cursor;
589 self.buffer.clear_history();
590 self.mode = TerminalMode::default();
591 self.attribute_template = Cell::default();
592 }
593
594 fn reverse_index(&mut self) {
595 log!("Reverse index");
596 if self.cursor.row == self.scroll_region.start {
597 self.scroll_down(1);
598 } else {
599 self.cursor.row -= 1;
600 }
601 }
602
603 fn terminal_attribute(&mut self, attr: Attr) {
604 let handle_color = |color: AnsiColor| match color {
605 AnsiColor::Named(color) => Color::Indexed(color as u16),
606 AnsiColor::Spec(color) => Color::Rgb((color.r, color.g, color.b)),
607 AnsiColor::Indexed(index) => Color::Indexed(index as u16),
608 };
609
610 match attr {
611 Attr::Foreground(color) => self.attribute_template.foreground = handle_color(color),
612 Attr::Background(color) => self.attribute_template.background = handle_color(color),
613 Attr::Reset => self.attribute_template = Cell::default(),
614 Attr::Reverse => self.attribute_template.flags |= Flags::INVERSE,
615 Attr::CancelReverse => self.attribute_template.flags.remove(Flags::INVERSE),
616 Attr::Bold => self.attribute_template.flags.insert(Flags::BOLD),
617 Attr::CancelBold => self.attribute_template.flags.remove(Flags::BOLD),
618 Attr::CancelBoldDim => self.attribute_template.flags.remove(Flags::BOLD),
619 Attr::Italic => self.attribute_template.flags.insert(Flags::ITALIC),
620 Attr::CancelItalic => self.attribute_template.flags.remove(Flags::ITALIC),
621 Attr::Underline => self.attribute_template.flags.insert(Flags::UNDERLINE),
622 Attr::CancelUnderline => self.attribute_template.flags.remove(Flags::UNDERLINE),
623 Attr::Hidden => self.attribute_template.flags.insert(Flags::HIDDEN),
624 Attr::CancelHidden => self.attribute_template.flags.remove(Flags::HIDDEN),
625 _ => log!("Unhandled terminal attribute: {:?}", attr),
626 }
627 }
628
629 fn set_mode(&mut self, mode: Mode) {
630 let mode = match mode {
631 Mode::Named(mode) => mode,
632 Mode::Unknown(mode) => {
633 log!("Ignoring unknown mode {} in set_mode", mode);
634 return;
635 }
636 };
637
638 match mode {
639 NamedMode::Insert => self.mode.insert(TerminalMode::INSERT),
640 NamedMode::LineFeedNewLine => self.mode.insert(TerminalMode::LINE_FEED_NEW_LINE),
641 }
642 }
643
644 fn unset_mode(&mut self, mode: Mode) {
645 let mode = match mode {
646 Mode::Named(mode) => mode,
647 Mode::Unknown(mode) => {
648 log!("Ignoring unknown mode {} in unset_mode", mode);
649 return;
650 }
651 };
652
653 match mode {
654 NamedMode::Insert => self.mode.remove(TerminalMode::INSERT),
655 NamedMode::LineFeedNewLine => self.mode.remove(TerminalMode::LINE_FEED_NEW_LINE),
656 }
657 }
658
659 fn report_mode(&mut self, mode: Mode) {
660 log!("Unhandled report mode: {:?}", mode);
661 }
662
663 fn set_private_mode(&mut self, mode: PrivateMode) {
664 let mode = match mode {
665 PrivateMode::Named(mode) => mode,
666 PrivateMode::Unknown(mode) => {
667 log!("Ignoring unknown mode {} in set_private_mode", mode);
668 return;
669 }
670 };
671
672 match mode {
673 NamedPrivateMode::SwapScreenAndSetRestoreCursor => {
674 if !self.mode.contains(TerminalMode::ALT_SCREEN) {
675 self.swap_alt_screen();
676 }
677 }
678 NamedPrivateMode::ShowCursor => self.mode.insert(TerminalMode::SHOW_CURSOR),
679 NamedPrivateMode::CursorKeys => {
680 self.mode.insert(TerminalMode::APP_CURSOR);
681 self.keyboard.set_app_cursor(true);
682 }
683 NamedPrivateMode::LineWrap => self.mode.insert(TerminalMode::LINE_WRAP),
684 _ => log!("Unhandled set mode: {:?}", mode),
685 }
686 }
687
688 fn unset_private_mode(&mut self, mode: PrivateMode) {
689 let mode = match mode {
690 PrivateMode::Named(mode) => mode,
691 PrivateMode::Unknown(mode) => {
692 log!("Ignoring unknown mode {} in unset_private_mode", mode);
693 return;
694 }
695 };
696
697 match mode {
698 NamedPrivateMode::SwapScreenAndSetRestoreCursor => {
699 if self.mode.contains(TerminalMode::ALT_SCREEN) {
700 self.swap_alt_screen();
701 }
702 }
703 NamedPrivateMode::ShowCursor => self.mode.remove(TerminalMode::SHOW_CURSOR),
704 NamedPrivateMode::CursorKeys => {
705 self.mode.remove(TerminalMode::APP_CURSOR);
706 self.keyboard.set_app_cursor(false);
707 }
708 NamedPrivateMode::LineWrap => self.mode.remove(TerminalMode::LINE_WRAP),
709 _ => log!("Unhandled unset mode: {:?}", mode),
710 }
711 }
712
713 fn report_private_mode(&mut self, mode: PrivateMode) {
714 log!("Unhandled report private mode: {:?}", mode);
715 }
716
717 fn set_scrolling_region(&mut self, top: usize, bottom: Option<usize>) {
718 log!("Set scrolling region: top={}, bottom={:?}", top, bottom);
719 let bottom = bottom.unwrap_or(self.buffer.height());
720
721 if top >= bottom {
722 log!("Invalid scrolling region: ({};{})", top, bottom);
723 return;
724 }
725
726 self.scroll_region.start = min(top, self.buffer.height()) - 1;
727 self.scroll_region.end = min(bottom, self.buffer.height()) - 1;
728 self.goto(0, 0);
729 }
730
731 fn set_keypad_application_mode(&mut self) {
732 log!("Set keypad application mode");
733 self.mode.insert(TerminalMode::APP_KEYPAD);
734 }
735
736 fn unset_keypad_application_mode(&mut self) {
737 log!("Unset keypad application mode");
738 self.mode.remove(TerminalMode::APP_KEYPAD);
739 }
740
741 fn set_active_charset(&mut self, index: CharsetIndex) {
742 log!("Unhandled set active charset: {:?}", index);
743 }
744
745 fn configure_charset(&mut self, index: CharsetIndex, charset: StandardCharset) {
746 log!("Unhandled configure charset: {:?}, {:?}", index, charset);
747 }
748
749 fn set_color(&mut self, index: usize, color: Rgb) {
750 log!("Unhandled set color: {}, {:?}", index, color);
751 }
752
753 fn dynamic_color_sequence(&mut self, prefix: String, index: usize, terminator: &str) {
754 log!(
755 "Unhandled dynamic color sequence: {}, {}, {}",
756 prefix,
757 index,
758 terminator
759 );
760 }
761
762 fn reset_color(&mut self, index: usize) {
763 log!("Unhandled reset color: {}", index);
764 }
765
766 fn clipboard_store(&mut self, clipboard: u8, base64: &[u8]) {
767 log!("Unhandled clipboard store: {}, {:?}", clipboard, base64);
768 }
769
770 fn clipboard_load(&mut self, clipboard: u8, terminator: &str) {
771 log!("Unhandled clipboard load: {}, {}", clipboard, terminator);
772 }
773
774 fn decaln(&mut self) {
775 log!("Unhandled decaln!");
776 }
777
778 fn push_title(&mut self) {
779 log!("Unhandled push title!");
780 }
781
782 fn pop_title(&mut self) {
783 log!("Unhandled pop title!");
784 }
785
786 fn text_area_size_pixels(&mut self) {
787 log!("Unhandled text area size pixels!");
788 }
789
790 fn text_area_size_chars(&mut self) {
791 log!("Unhandled text area size chars!");
792 }
793
794 fn set_hyperlink(&mut self, hyperlink: Option<Hyperlink>) {
795 log!("Unhandled set hyperlink: {:?}", hyperlink);
796 }
797
798 fn report_keyboard_mode(&mut self) {
799 log!("Unhandled report keyboard mode!");
800 }
801
802 fn push_keyboard_mode(&mut self, mode: KeyboardModes) {
803 log!("Unhandled push keyboard mode: {:?}", mode);
804 }
805
806 fn pop_keyboard_modes(&mut self, to_pop: u16) {
807 log!("Unhandled pop keyboard modes: {}", to_pop);
808 }
809}