termina 0.3.1

A cross-platform VT manipulation library
Documentation
use std::{
    io::{self, Write as _},
    time::Duration,
};

use termina::{
    escape::{
        csi::{self, Csi},
        dcs::{self, Dcs},
    },
    style::RgbColor,
    Event, PlatformTerminal, Terminal,
};

const TEST_COLOR: RgbColor = RgbColor::new(150, 150, 150);

#[derive(Debug, Default, Clone, Copy)]
struct Features {
    kitty_keyboard: bool,
    sychronized_output: bool,
    true_color: bool,
    extended_underlines: bool,
}

fn main() -> io::Result<()> {
    let mut terminal = PlatformTerminal::new()?;
    terminal.enter_raw_mode()?;

    write!(
        terminal,
        "{}{}{}{}{}{}{}",
        // Kitty keyboard
        Csi::Keyboard(csi::Keyboard::QueryFlags),
        // Synchronized output
        Csi::Mode(csi::Mode::QueryDecPrivateMode(csi::DecPrivateMode::Code(
            csi::DecPrivateModeCode::SynchronizedOutput
        ))),
        // True color and while we're at it, extended underlines:
        // <https://github.com/termstandard/colors?tab=readme-ov-file#querying-the-terminal>
        Csi::Sgr(csi::Sgr::Background(TEST_COLOR.into())),
        Csi::Sgr(csi::Sgr::UnderlineColor(TEST_COLOR.into())),
        Dcs::Request(dcs::DcsRequest::GraphicRendition),
        Csi::Sgr(csi::Sgr::Reset),
        // Finally request the primary device attributes
        Csi::Device(csi::Device::RequestPrimaryDeviceAttributes),
    )?;
    terminal.flush()?;

    let mut features = Features::default();
    loop {
        if !terminal.poll(Event::is_escape, Some(Duration::from_millis(100)))? {
            eprintln!("Did not receive any responses to queries in 100ms\r");
            break;
        }

        match terminal.read(Event::is_escape)? {
            Event::Csi(Csi::Keyboard(csi::Keyboard::ReportFlags(_))) => {
                features.kitty_keyboard = true
            }
            Event::Csi(Csi::Mode(csi::Mode::ReportDecPrivateMode {
                mode: csi::DecPrivateMode::Code(csi::DecPrivateModeCode::SynchronizedOutput),
                setting,
            })) => {
                features.sychronized_output = matches!(
                    setting,
                    csi::DecModeSetting::Set | csi::DecModeSetting::Reset
                );
            }
            Event::Dcs(Dcs::Response {
                value: dcs::DcsResponse::GraphicRendition(sgrs),
                ..
            }) => {
                features.true_color = sgrs.contains(&csi::Sgr::Background(TEST_COLOR.into()));
                features.extended_underlines =
                    sgrs.contains(&csi::Sgr::UnderlineColor(TEST_COLOR.into()));
            }
            Event::Csi(Csi::Device(csi::Device::DeviceAttributes(_))) => break,
            other => eprintln!("unexpected event: {other:?}\r"),
        }
    }
    println!("Detected features: {features:?}");

    Ok(())
}