use std::io;
mod platform;
pub use platform::CapabilityProfile;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PointerShape {
Default,
Pointer,
Text,
NotAllowed,
}
impl PointerShape {
pub fn as_kitty_name(self) -> &'static str {
match self {
PointerShape::Default => "default",
PointerShape::Pointer => "pointer",
PointerShape::Text => "text",
PointerShape::NotAllowed => "not-allowed",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum KeyboardProtocol {
#[default]
Off,
Auto,
On,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Size {
pub width: u16,
pub height: u16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DriverOptions {
pub enable_mouse: bool,
pub enable_pointer_shapes: bool,
pub enable_focus_change: bool,
pub keyboard_protocol: KeyboardProtocol,
}
impl Default for DriverOptions {
fn default() -> Self {
Self {
enable_mouse: false,
enable_pointer_shapes: detect_pointer_shapes_enabled(),
enable_focus_change: false,
keyboard_protocol: KeyboardProtocol::Off,
}
}
}
pub struct TerminalDriver {
size: Size,
started: bool,
options: DriverOptions,
keyboard_enhanced: bool,
capabilities: CapabilityProfile,
platform: Box<dyn platform::PlatformDriver>,
}
impl TerminalDriver {
pub fn new(options: DriverOptions) -> io::Result<Self> {
let mut platform = platform::make_platform_driver();
let size = platform.refresh_size()?;
Ok(Self {
size,
started: false,
options,
keyboard_enhanced: false,
capabilities: platform::capability_profile(),
platform,
})
}
pub fn size(&self) -> Size {
self.size
}
pub fn started(&self) -> bool {
self.started
}
pub fn options(&self) -> DriverOptions {
self.options
}
pub fn capabilities(&self) -> CapabilityProfile {
self.capabilities
}
pub fn keyboard_enhanced(&self) -> bool {
self.keyboard_enhanced
}
pub fn start(&mut self) -> io::Result<()> {
if self.started {
return Ok(());
}
self.keyboard_enhanced = self
.platform
.start(self.options, self.options.keyboard_protocol)?;
self.started = true;
Ok(())
}
pub fn stop(&mut self) -> io::Result<()> {
if !self.started {
return Ok(());
}
let result = self.platform.stop(self.options, self.keyboard_enhanced);
self.keyboard_enhanced = false;
self.started = false;
result
}
pub fn refresh_size(&mut self) -> io::Result<Size> {
self.size = self.platform.refresh_size()?;
Ok(self.size)
}
pub fn reassert_runtime_modes(&mut self) -> io::Result<()> {
self.platform.reassert_runtime_modes(self.started)
}
pub fn set_pointer_shape(&mut self, shape: PointerShape) -> io::Result<()> {
if !self.capabilities.supports_pointer_shapes {
return Ok(());
}
self.platform
.set_pointer_shape(self.started, self.options, shape)
}
}
impl Drop for TerminalDriver {
fn drop(&mut self) {
let _ = self.stop();
}
}
fn detect_pointer_shapes_enabled() -> bool {
platform::detect_pointer_shapes_enabled()
}
#[cfg(test)]
mod tests {
use super::platform;
#[test]
fn capability_profile_has_required_flags() {
let profile = platform::capability_profile();
assert!(profile.requires_mode_reassert_on_resize);
assert!(profile.supports_focus_change);
#[cfg(not(target_os = "windows"))]
{
assert!(profile.supports_dim_reliably);
assert!(profile.supports_reverse_reliably);
}
}
}