standard-plugin-sdk 0.1.1

Write Standard Code plugins in Rust: wasm components against standard:plugin@2.0.0
Documentation
//! Keys, pastes and the pointer, as typed values. The WIT names keys by
//! string and buttons by number (`wit/plugin.wit`, `event-types`); a
//! plugin matches on these enums instead.

use alloc::string::{String, ToString};

/// Modifier keys held during a key or pointer event.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Modifiers(pub u32);

impl Modifiers {
    pub const NONE: Self = Self(0);
    pub const SHIFT: Self = Self(1);
    pub const CTRL: Self = Self(2);
    /// Alt, or Option on a Mac.
    pub const ALT: Self = Self(4);
    /// Super: Command on a Mac.
    pub const SUPER: Self = Self(8);

    pub const fn contains(self, other: Self) -> bool {
        self.0 & other.0 == other.0 && other.0 != 0
    }

    pub const fn shift(self) -> bool {
        self.contains(Self::SHIFT)
    }

    pub const fn ctrl(self) -> bool {
        self.contains(Self::CTRL)
    }

    pub const fn alt(self) -> bool {
        self.contains(Self::ALT)
    }

    pub const fn super_key(self) -> bool {
        self.contains(Self::SUPER)
    }

    pub const fn is_empty(self) -> bool {
        self.0 == 0
    }
}

impl core::ops::BitOr for Modifiers {
    type Output = Self;

    fn bitor(self, other: Self) -> Self {
        Self(self.0 | other.0)
    }
}

/// Which key. A character key is the character it types; the named keys
/// are the WIT's vocabulary. Escape never arrives: it closes the surface.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum KeyCode {
    /// `a`, `A`, `1`, `?`, `é`: what the key typed, shift applied.
    Char(char),
    Enter,
    Tab,
    /// Shift+Tab, as terminals report it.
    BackTab,
    Backspace,
    Delete,
    Insert,
    Space,
    Left,
    Right,
    Up,
    Down,
    Home,
    End,
    PageUp,
    PageDown,
    /// `F(1)` to `F(12)`.
    F(u8),
    /// A name a newer viewer sends.
    Other(String),
}

impl KeyCode {
    /// Reads the WIT's `key.code`.
    pub fn parse(code: &str) -> Self {
        let mut chars = code.chars();
        if let (Some(character), None) = (chars.next(), chars.next()) {
            return Self::Char(character);
        }
        match code {
            "enter" => Self::Enter,
            "tab" => Self::Tab,
            "backtab" => Self::BackTab,
            "backspace" => Self::Backspace,
            "delete" => Self::Delete,
            "insert" => Self::Insert,
            "space" => Self::Space,
            "left" => Self::Left,
            "right" => Self::Right,
            "up" => Self::Up,
            "down" => Self::Down,
            "home" => Self::Home,
            "end" => Self::End,
            "pageup" => Self::PageUp,
            "pagedown" => Self::PageDown,
            other => match other.strip_prefix('f').and_then(|n| n.parse::<u8>().ok()) {
                Some(n @ 1..=12) => Self::F(n),
                _ => Self::Other(other.to_string()),
            },
        }
    }

    /// The WIT's name for this key.
    pub fn name(&self) -> String {
        match self {
            Self::Char(character) => character.to_string(),
            Self::Enter => "enter".into(),
            Self::Tab => "tab".into(),
            Self::BackTab => "backtab".into(),
            Self::Backspace => "backspace".into(),
            Self::Delete => "delete".into(),
            Self::Insert => "insert".into(),
            Self::Space => "space".into(),
            Self::Left => "left".into(),
            Self::Right => "right".into(),
            Self::Up => "up".into(),
            Self::Down => "down".into(),
            Self::Home => "home".into(),
            Self::End => "end".into(),
            Self::PageUp => "pageup".into(),
            Self::PageDown => "pagedown".into(),
            Self::F(n) => alloc::format!("f{n}"),
            Self::Other(name) => name.clone(),
        }
    }
}

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum KeyPhase {
    #[default]
    Press,
    Repeat,
    /// Only where the viewer's terminal reports releases.
    Release,
}

/// A key on the surface with input focus.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Key {
    pub surface: String,
    pub code: KeyCode,
    /// The text the key types, when it types text.
    pub text: Option<String>,
    pub modifiers: Modifiers,
    pub phase: KeyPhase,
}

impl Key {
    /// A press of `code` with no modifiers (for tests).
    pub fn press(surface: &str, code: KeyCode) -> Self {
        let text = match &code {
            KeyCode::Char(character) => Some(character.to_string()),
            KeyCode::Space => Some(" ".into()),
            _ => None,
        };
        Self {
            surface: surface.into(),
            code,
            text,
            modifiers: Modifiers::NONE,
            phase: KeyPhase::Press,
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PointerKind {
    Down,
    Up,
    /// Motion with no button held.
    Move,
    /// Motion with a button held.
    Drag,
    /// One wheel step; the button says which way.
    Wheel,
    /// The pointer moved onto the surface, before its first `Move`: start
    /// a hover.
    Enter,
    /// The pointer left the surface (or the surface was hidden under it):
    /// end a hover. The position is the last one on the surface.
    Leave,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Button {
    None,
    Left,
    Middle,
    Right,
    WheelUp,
    WheelDown,
    WheelLeft,
    WheelRight,
    /// A number a newer viewer sends.
    Other(u8),
}

impl Button {
    pub fn from_wire(button: u8) -> Self {
        match button {
            0 => Self::None,
            1 => Self::Left,
            2 => Self::Middle,
            3 => Self::Right,
            4 => Self::WheelUp,
            5 => Self::WheelDown,
            6 => Self::WheelLeft,
            7 => Self::WheelRight,
            other => Self::Other(other),
        }
    }

    pub fn wire(self) -> u8 {
        match self {
            Self::None => 0,
            Self::Left => 1,
            Self::Middle => 2,
            Self::Right => 3,
            Self::WheelUp => 4,
            Self::WheelDown => 5,
            Self::WheelLeft => 6,
            Self::WheelRight => 7,
            Self::Other(other) => other,
        }
    }
}

/// The pointer over one of the plugin's surfaces.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pointer {
    pub surface: String,
    /// The position in the surface's units: cells, or surface pixels.
    pub x: u32,
    pub y: u32,
    /// The cell under the pointer.
    pub col: u32,
    pub row: u32,
    pub button: Button,
    pub kind: PointerKind,
    pub modifiers: Modifiers,
}