Skip to content

Commit 2c37530

Browse files
authored
Update main.rs
1 parent 975658f commit 2c37530

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

src/main.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,161 @@
1+
use anyhow::{Context, Result};
2+
use crossterm::{
3+
cursor::{Hide, MoveTo, Show},
4+
event::{self, Event, KeyCode, KeyEvent},
5+
execute,
6+
style::{Color, Print, ResetColor, SetBackgroundColor, SetForegroundColor},
7+
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
8+
ExecutableCommand,
9+
};
10+
use portable_pty::{native_pty_system, CommandBuilder, PtyPair, PtySize};
11+
use std::{
12+
io::{self, BufRead, BufReader, Write},
13+
sync::{
14+
mpsc::{channel, Receiver, Sender},
15+
Arc, Mutex,
16+
},
17+
thread::{self, sleep},
18+
time::Duration,
19+
};
20+
use vte::{Params, Perform, Parser};
121

22+
// Handler for VTE to handle terminal output with "hacker" effects
23+
struct HackerHandler {
24+
tx: Sender<String>,
25+
}
26+
27+
impl Perform for HackerHandler {
28+
fn print(&mut self, c: char) {
29+
// Send char to rendering thread with delay for typing effect
30+
self.tx.send(c.to_string()).unwrap();
31+
}
32+
33+
fn execute(&mut self, byte: u8) {
34+
match byte {
35+
b'\n' => {
36+
// Enter effect: flash or something fancy
37+
self.tx.send("\n".to_string()).unwrap();
38+
// For "flash", we can send a special message, but for simplicity, just newline
39+
}
40+
b'\r' => self.tx.send("\r".to_string()).unwrap(),
41+
b'\t' => self.tx.send("\t".to_string()).unwrap(),
42+
b'\x08' => self.tx.send("\x08".to_string()).unwrap(), // Backspace
43+
_ => {}
44+
}
45+
}
46+
47+
fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _c: char) {}
48+
fn put(&mut self, _byte: u8) {}
49+
fn unhook(&mut self) {}
50+
fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {}
51+
fn csi_dispatch(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, c: char) {
52+
// Handle some CSI for cursor, etc., but simplified
53+
if c == 'J' {
54+
self.tx.send("CLEAR".to_string()).unwrap(); // Special for clear screen
55+
}
56+
}
57+
fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {}
58+
}
59+
60+
fn main() -> Result<()> {
61+
// Setup crossterm
62+
let mut stdout = io::stdout();
63+
enable_raw_mode()?;
64+
execute!(stdout, EnterAlternateScreen, Hide)?;
65+
66+
// Set "hacker" style: green text on black background
67+
execute!(
68+
stdout,
69+
SetForegroundColor(Color::Green),
70+
SetBackgroundColor(Color::Black)
71+
)?;
72+
73+
// Channels for communication
74+
let (tx, rx) = channel::<String>();
75+
76+
// Setup PTY with zsh
77+
let pty_system = native_pty_system();
78+
let pty = pty_system
79+
.openpty(PtySize {
80+
rows: 24,
81+
cols: 80,
82+
pixel_width: 0,
83+
pixel_height: 0,
84+
})
85+
.context("Failed to open PTY")?;
86+
87+
let mut cmd = CommandBuilder::new("zsh");
88+
cmd.cwd(std::env::current_dir()?);
89+
let mut child = cmd.spawn(&pty.pty).context("Failed to spawn zsh")?;
90+
91+
let mut reader = BufReader::new(pty.master.try_clone_reader()?);
92+
let writer = Arc::new(Mutex::new(pty.master.try_clone_writer()?));
93+
94+
// Thread for reading from PTY and parsing with VTE
95+
let writer_clone = writer.clone();
96+
thread::spawn(move || {
97+
let mut parser = Parser::new();
98+
let handler = HackerHandler { tx };
99+
let mut buf = [0; 1024];
100+
loop {
101+
let n = reader.read(&mut buf).unwrap_or(0);
102+
if n == 0 {
103+
break;
104+
}
105+
for &byte in &buf[0..n] {
106+
parser.advance(&mut handler, byte);
107+
}
108+
}
109+
});
110+
111+
// Thread for rendering with effects
112+
thread::spawn(move || {
113+
let mut stdout = io::stdout();
114+
while let Ok(msg) = rx.recv() {
115+
if msg == "CLEAR" {
116+
execute!(stdout, crossterm::terminal::Clear(crossterm::terminal::ClearType::All)).unwrap();
117+
execute!(stdout, MoveTo(0, 0)).unwrap();
118+
} else {
119+
// Typing effect: print char by char with small delay
120+
for c in msg.chars() {
121+
execute!(stdout, Print(c)).unwrap();
122+
stdout.flush().unwrap();
123+
sleep(Duration::from_millis(5)); // Small delay for "hacker typing" effect
124+
}
125+
}
126+
}
127+
});
128+
129+
// Input loop
130+
loop {
131+
if let Ok(Event::Key(KeyEvent { code, .. })) = event::read() {
132+
let mut writer = writer.lock().unwrap();
133+
match code {
134+
KeyCode::Char(c) => {
135+
writer.write_all(c.to_string().as_bytes())?;
136+
}
137+
KeyCode::Enter => {
138+
writer.write_all(b"\n")?;
139+
// Additional enter effect: maybe a "glitch" but simplified
140+
}
141+
KeyCode::Backspace => {
142+
writer.write_all(b"\x7f")?; // Delete
143+
}
144+
KeyCode::Esc => {
145+
break;
146+
}
147+
_ => {}
148+
}
149+
writer.flush()?;
150+
}
151+
152+
if child.try_wait()?.is_some() {
153+
break;
154+
}
155+
}
156+
157+
// Cleanup
158+
disable_raw_mode()?;
159+
execute!(io::stdout(), LeaveAlternateScreen, Show, ResetColor)?;
160+
Ok(())
161+
}

0 commit comments

Comments
 (0)