1use crate::terminal::TerminalBuffer;
14use crate::vte::VteParser;
15use portable_pty::{native_pty_system, CommandBuilder, PtySize};
16use std::io::{Read, Write};
17use std::sync::{Arc, Mutex};
18use std::thread;
19
20pub struct Pane {
21 pub id: usize,
22 pub title: String,
23 pub buffer: Arc<Mutex<TerminalBuffer>>,
24 pub x: u16,
25 pub y: u16,
26 pub width: u16,
27 pub height: u16,
28 writer: Option<Box<dyn Write + Send>>,
29 active: bool,
30}
31
32impl Pane {
33 pub fn new(
34 id: usize,
35 shell: &str,
36 x: u16,
37 y: u16,
38 width: u16,
39 height: u16,
40 scrollback: usize,
41 ) -> Self {
42 let buffer = Arc::new(Mutex::new(TerminalBuffer::new(
43 height as usize,
44 width as usize,
45 scrollback,
46 )));
47
48 let pty_system = native_pty_system();
49 let pair = pty_system
50 .openpty(PtySize {
51 rows: height,
52 cols: width,
53 pixel_width: 0,
54 pixel_height: 0,
55 })
56 .expect("failed to open PTY");
57
58 let mut cmd = CommandBuilder::new(shell);
59 cmd.env("TERM", "xterm-256color");
60 cmd.env("KRONOS", "1");
61
62 let _child = pair
63 .slave
64 .spawn_command(cmd)
65 .expect("failed to spawn shell");
66 drop(pair.slave);
67
68 let mut reader = pair
69 .master
70 .try_clone_reader()
71 .expect("failed to clone PTY reader");
72 let writer = pair.master.take_writer().expect("failed to get PTY writer");
73
74 let buf_clone = Arc::clone(&buffer);
75
76 thread::spawn(move || {
82 let mut parser = VteParser::new();
83 let mut byte_buf = [0u8; 4096];
84 loop {
85 match reader.read(&mut byte_buf) {
86 Ok(0) => break,
87 Ok(n) => {
88 let chunk = byte_buf[..n].to_vec();
90
91 if let Ok(mut buf) = buf_clone.lock() {
95 parser.feed_str(&mut buf, &chunk);
96 }
97 }
98 Err(_) => break,
99 }
100 }
101 });
102
103 Self {
104 id,
105 title: format!("pane-{}", id),
106 buffer,
107 x,
108 y,
109 width,
110 height,
111 writer: Some(Box::new(writer)),
112 active: true,
113 }
114 }
115
116 pub fn send_input(&mut self, data: &[u8]) {
118 if let Some(ref mut writer) = self.writer {
119 let _ = writer.write_all(data);
120 let _ = writer.flush();
121 }
122 }
123
124 pub fn resize(&mut self, width: u16, height: u16) {
125 self.width = width;
126 self.height = height;
127 if let Ok(mut buf) = self.buffer.lock() {
128 buf.resize(height as usize, width as usize);
129 }
130 }
131
132 pub fn is_active(&self) -> bool {
133 self.active
134 }
135}