///|
/// Opaque terminal state snapshot.
///
/// Capture a state with `Tty::get_state`, derive raw mode with
/// `State::make_raw`, and restore it with `Tty::set_state` or
/// `Tty::leave_raw_mode`.
struct State(Bytes)
///|
/// Capture the current terminal state for this handle.
pub fn Tty::get_state(self : Self) -> State raise @os_error.OSError {
let state = State::new()
let rc = tty_get_state(self.input_fd, self.output_fd, state)
if rc < 0 {
@os_error.check_errno("Tty::get_state")
}
state
}
///|
/// Apply a terminal state and return the previous state.
pub fn Tty::set_state(
self : Self,
state : State,
) -> State raise @os_error.OSError {
let old_state = self.get_state()
let rc = tty_set_state(self.input_fd, self.output_fd, state)
if rc < 0 {
ignore(tty_set_state(self.input_fd, self.output_fd, old_state))
@os_error.check_errno("Tty::set_state")
}
old_state
}
///|
/// Derive a raw-mode state from this captured terminal state.
pub fn State::make_raw(self : Self) -> State {
let raw = State::new()
tty_make_raw_state(self, raw)
raw
}
///|
/// Enter raw mode and return the previous terminal state.
pub fn Tty::enter_raw_mode(self : Self) -> State raise @os_error.OSError {
let old_state = self.get_state()
let raw_state = old_state.make_raw()
let rc = tty_set_state(self.input_fd, self.output_fd, raw_state)
if rc < 0 {
ignore(tty_set_state(self.input_fd, self.output_fd, old_state))
@os_error.check_errno("Tty::enter_raw_mode")
}
old_state
}
///|
/// Restore a terminal state captured before or during raw mode.
pub fn Tty::leave_raw_mode(
self : Self,
state : State,
) -> Unit raise @os_error.OSError {
let rc = tty_set_state(self.input_fd, self.output_fd, state)
if rc < 0 {
@os_error.check_errno("Tty::leave_raw_mode")
}
}
///|
/// Run an async callback with raw mode enabled.
///
/// The captured terminal state is restored on success or error.
pub async fn[T] Tty::with_raw_mode(self : Self, f : async () -> T) -> T {
let state = self.enter_raw_mode()
try f() catch {
error => {
self.leave_raw_mode(state)
raise error
}
} noraise {
value => {
self.leave_raw_mode(state)
value
}
}
}
///|
extern "c" fn get_sizeof_state() -> Int = "moonbit_tty_get_sizeof_state"
///|
let sizeof_state : Int = get_sizeof_state()
///|
fn State::new() -> State {
Bytes::make(sizeof_state, 0)
}
///|
#borrow(state)
extern "c" fn tty_get_state(
input_fd : @async/types.Fd,
output_fd : @async/types.Fd,
state : State,
) -> Int = "moonbit_tty_get_state"
///|
#borrow(state)
extern "c" fn tty_set_state(
input_fd : @async/types.Fd,
output_fd : @async/types.Fd,
state : State,
) -> Int = "moonbit_tty_set_state"
///|
#borrow(state, raw)
extern "c" fn tty_make_raw_state(state : State, raw : State) -> Unit = "moonbit_tty_make_raw_state"