Skip to main content

terminal/
terminal_callbacks.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::fs::File;
6use std::io::Write;
7use std::sync::{Arc, Mutex};
8use vt100::Screen;
9
10/// A standard vt100 callback implementation that writes responses
11/// back to a provided PTY file descriptor (such as Device Attributes
12/// and Device Status Report).
13pub struct TerminalCallbacks {
14    pty_fd: Arc<Mutex<Option<File>>>,
15}
16
17impl TerminalCallbacks {
18    pub fn new(pty_fd: Option<File>) -> Self {
19        Self { pty_fd: Arc::new(Mutex::new(pty_fd)) }
20    }
21
22    pub fn new_with_shared(pty_fd: Arc<Mutex<Option<File>>>) -> Self {
23        Self { pty_fd }
24    }
25}
26
27impl vt100::Callbacks for TerminalCallbacks {
28    fn unhandled_csi(
29        &mut self,
30        screen: &mut Screen,
31        i1: Option<u8>,
32        _i2: Option<u8>,
33        params: &[&[u16]],
34        c: char,
35    ) {
36        if let Some(fd) = self.pty_fd.lock().unwrap().as_mut() {
37            if i1 == None && c == 'c' {
38                // Primary Device Attributes (DA1)
39                let _ = fd.write_all(b"\x1b[?6c");
40            } else if i1 == Some(b'>') && c == 'c' {
41                // Secondary Device Attributes (DA2)
42                let _ = fd.write_all(b"\x1b[>0;278;0c");
43            } else if i1 == None && c == 'n' {
44                // Device Status Report (DSR)
45                let param = params.iter().next().and_then(|p| p.first()).copied().unwrap_or(0);
46                if param == 5 {
47                    let _ = fd.write_all(b"\x1b[0n");
48                } else if param == 6 {
49                    let (row, col) = screen.cursor_position();
50                    let response = format!("\x1b[{};{}R", row + 1, col + 1);
51                    let _ = fd.write_all(response.as_bytes());
52                }
53            }
54        }
55    }
56}