1mod ncurses_bridge;
2mod shell_bridge;
3
4use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
5pub use ncurses_bridge::*;
6pub use shell_bridge::*;
7use std::io;
8use thiserror::Error;
9
10use crate::io::pipe;
11use tokio::io::{AsyncRead, AsyncWrite};
12use tokio::sync::mpsc;
13
14pub trait TerminalBridge {
15 async fn bridge<R: AsyncRead + Send + Unpin, W: AsyncWrite + Send + Unpin>(
17 reader: &mut R,
18 writer: &mut W,
19 );
20}
21
22#[derive(Error, Debug)]
23pub enum TerminalError {
24 #[error("IO error: {0}")]
25 Io(#[from] io::Error),
26
27 #[error("String Send error: {0}")]
28 StringSend(#[from] mpsc::error::SendError<String>),
29
30 #[error("Bytes Send error: {0}")]
31 BytesSend(#[from] mpsc::error::SendError<Vec<u8>>),
32
33 #[error("Recv error: {0}")]
34 Recv(#[from] mpsc::error::TryRecvError),
35
36 #[error("Pipe error: {0}")]
37 Pipe(#[from] pipe::PipeError),
38
39 #[error("format error {0}")]
40 FmtError(#[from] std::fmt::Error),
41
42 #[error("Stop signal")]
43 Terminate,
44}
45
46type TerminalResult<T> = Result<T, TerminalError>;
47
48fn is_ctr_key(key_event: KeyEvent) -> bool {
49 key_event.kind == KeyEventKind::Press && key_event.modifiers == KeyModifiers::CONTROL
50}
51
52pub(crate) fn is_terminate_process(key_event: KeyEvent) -> bool {
53 return is_ctr_key(key_event) && key_event.code == KeyCode::Char('c');
54}
55
56pub(crate) fn is_stop_terminal(key_event: KeyEvent) -> bool {
57 return is_ctr_key(key_event) && key_event.code == KeyCode::Char('d');
58}