1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
use crate::{FromInner, HandleTrait, Inner, IntoInner, ToHandle};
use std::convert::{TryFrom, TryInto};
use uv::{
uv_tty_get_vterm_state, uv_tty_get_winsize, uv_tty_init, uv_tty_reset_mode, uv_tty_set_mode,
uv_tty_set_vterm_state, uv_tty_t,
};
/// TTY mode type
#[repr(u32)]
pub enum TtyMode {
/// Initial/normal terminal mode
Normal = uv::uv_tty_mode_t_UV_TTY_MODE_NORMAL as _,
/// Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled)
/// May become equivalent to RawVT in future libuv versions.
Raw = uv::uv_tty_mode_t_UV_TTY_MODE_RAW as _,
/// Binary-safe I/O mode for IPC (Unix-only)
IO = uv::uv_tty_mode_t_UV_TTY_MODE_IO as _,
/// Raw input mode. On Windows ENABLE_WINDOW_TERMINAL_INPUT is also set.
RawVT = uv::uv_tty_mode_t_UV_TTY_MODE_RAW_VT as _,
}
/// Console virtual terminal mode type
#[repr(u32)]
pub enum VTermState {
Supported = uv::uv_tty_vtermstate_t_UV_TTY_SUPPORTED as _,
Unsupported = uv::uv_tty_vtermstate_t_UV_TTY_UNSUPPORTED as _,
}
/// TTY handles represent a stream for the console.
#[derive(Clone, Copy)]
pub struct TtyHandle {
handle: *mut uv_tty_t,
}
impl TtyHandle {
/// Initialize a new TTY stream with the given file descriptor. Usually the file descriptor
/// will be:
///
/// 0 = stdin
/// 1 = stdout
/// 2 = stderr
///
/// On Unix this function will determine the path of the fd of the terminal using ttyname_r(3),
/// open it, and use it if the passed file descriptor refers to a TTY. This lets libuv put the
/// tty in non-blocking mode without affecting other processes that share the tty.
///
/// This function is not thread safe on systems that don’t support ioctl TIOCGPTN or
/// TIOCPTYGNAME, for instance OpenBSD and Solaris.
///
/// Note: If reopening the TTY fails, libuv falls back to blocking writes.
pub fn new(r#loop: &crate::Loop, fd: i32) -> crate::Result<TtyHandle> {
let layout = std::alloc::Layout::new::<uv_tty_t>();
let handle = unsafe { std::alloc::alloc(layout) as *mut uv_tty_t };
if handle.is_null() {
return Err(crate::Error::ENOMEM);
}
let ret = unsafe { uv_tty_init(r#loop.into_inner(), handle, fd, 0) };
if ret < 0 {
unsafe { std::alloc::dealloc(handle as _, layout) };
return Err(crate::Error::from_inner(ret as uv::uv_errno_t));
}
crate::StreamHandle::initialize_data(uv_handle!(handle), super::NoAddlStreamData);
Ok(TtyHandle { handle })
}
/// Set the TTY using the specified terminal mode.
pub fn set_mode(&mut self, mode: TtyMode) -> crate::Result<()> {
crate::uvret(unsafe { uv_tty_set_mode(self.handle, mode as _) })
}
/// To be called when the program exits. Resets TTY settings to default values for the next
/// process to take over.
///
/// This function is async signal-safe on Unix platforms but can fail with error code EBUSY if
/// you call it when execution is inside uv_tty_set_mode().
pub fn reset_mode() -> crate::Result<()> {
crate::uvret(unsafe { uv_tty_reset_mode() })
}
/// Gets the current Window size.
pub fn get_winsize(&self) -> crate::Result<(i32, i32)> {
let mut width: std::os::raw::c_int = 0;
let mut height: std::os::raw::c_int = 0;
crate::uvret(unsafe { uv_tty_get_winsize(self.handle, &mut width as _, &mut height as _) })
.map(|_| (width as _, height as _))
}
/// Controls whether console virtual terminal sequences are processed by libuv or console.
/// Useful in particular for enabling ConEmu support of ANSI X3.64 and Xterm 256 colors.
/// Otherwise Windows10 consoles are usually detected automatically.
///
/// This function is only meaningful on Windows systems. On Unix it is silently ignored.
pub fn set_vterm_state(state: VTermState) {
unsafe { uv_tty_set_vterm_state(state as _) }
}
/// Get the current state of whether console virtual terminal sequences are handled by libuv or
/// the console.
///
/// This function is not implemented on Unix, where it returns UV_ENOTSUP.
pub fn get_vterm_state() -> crate::Result<VTermState> {
let mut state: uv::uv_tty_vtermstate_t = 0;
crate::uvret(unsafe { uv_tty_get_vterm_state(&mut state as _) }).map(|_| match state {
uv::uv_tty_vtermstate_t_UV_TTY_SUPPORTED => VTermState::Supported,
_ => VTermState::Unsupported,
})
}
}
impl FromInner<*mut uv_tty_t> for TtyHandle {
fn from_inner(handle: *mut uv_tty_t) -> TtyHandle {
TtyHandle { handle }
}
}
impl Inner<*mut uv_tty_t> for TtyHandle {
fn inner(&self) -> *mut uv_tty_t {
self.handle
}
}
impl Inner<*mut uv::uv_stream_t> for TtyHandle {
fn inner(&self) -> *mut uv::uv_stream_t {
uv_handle!(self.handle)
}
}
impl Inner<*mut uv::uv_handle_t> for TtyHandle {
fn inner(&self) -> *mut uv::uv_handle_t {
uv_handle!(self.handle)
}
}
impl From<TtyHandle> for crate::StreamHandle {
fn from(tty: TtyHandle) -> crate::StreamHandle {
crate::StreamHandle::from_inner(Inner::<*mut uv::uv_stream_t>::inner(&tty))
}
}
impl From<TtyHandle> for crate::Handle {
fn from(tty: TtyHandle) -> crate::Handle {
crate::Handle::from_inner(Inner::<*mut uv::uv_handle_t>::inner(&tty))
}
}
impl crate::ToStream for TtyHandle {
fn to_stream(&self) -> crate::StreamHandle {
crate::StreamHandle::from_inner(Inner::<*mut uv::uv_stream_t>::inner(self))
}
}
impl ToHandle for TtyHandle {
fn to_handle(&self) -> crate::Handle {
crate::Handle::from_inner(Inner::<*mut uv::uv_handle_t>::inner(self))
}
}
impl TryFrom<crate::Handle> for TtyHandle {
type Error = crate::ConversionError;
fn try_from(handle: crate::Handle) -> Result<Self, Self::Error> {
let t = handle.get_type();
if t != crate::HandleType::TTY {
Err(crate::ConversionError::new(t, crate::HandleType::TTY))
} else {
Ok((handle.inner() as *mut uv_tty_t).into_inner())
}
}
}
impl TryFrom<crate::StreamHandle> for TtyHandle {
type Error = crate::ConversionError;
fn try_from(stream: crate::StreamHandle) -> Result<Self, Self::Error> {
stream.to_handle().try_into()
}
}
impl crate::StreamTrait for TtyHandle {}
impl HandleTrait for TtyHandle {}
impl crate::Loop {
/// Initialize a new TTY stream with the given file descriptor. Usually the file descriptor
/// will be:
///
/// 0 = stdin
/// 1 = stdout
/// 2 = stderr
///
/// On Unix this function will determine the path of the fd of the terminal using ttyname_r(3),
/// open it, and use it if the passed file descriptor refers to a TTY. This lets libuv put the
/// tty in non-blocking mode without affecting other processes that share the tty.
///
/// This function is not thread safe on systems that don’t support ioctl TIOCGPTN or
/// TIOCPTYGNAME, for instance OpenBSD and Solaris.
///
/// Note: If reopening the TTY fails, libuv falls back to blocking writes.
pub fn tty(&self, fd: i32) -> crate::Result<TtyHandle> {
TtyHandle::new(self, fd)
}
}