Files
galaxy/crates/galaxy_terminal/src/model/mode.rs
T

141 lines
5.8 KiB
Rust

use bitflags::bitflags;
bitflags! {
#[derive(Copy, Clone)]
pub struct TermMode: u32 {
const NONE = 0;
const SHOW_CURSOR = 0b0000_0000_0000_0000_0001;
const APP_CURSOR = 0b0000_0000_0000_0000_0010;
const APP_KEYPAD = 0b0000_0000_0000_0000_0100;
const MOUSE_REPORT_CLICK = 0b0000_0000_0000_0000_1000;
const BRACKETED_PASTE = 0b0000_0000_0000_0001_0000;
const SGR_MOUSE = 0b0000_0000_0000_0010_0000;
const MOUSE_MOTION = 0b0000_0000_0000_0100_0000;
const LINE_WRAP = 0b0000_0000_0000_1000_0000;
const LINE_FEED_NEW_LINE = 0b0000_0000_0001_0000_0000;
const ORIGIN = 0b0000_0000_0010_0000_0000;
const INSERT = 0b0000_0000_0100_0000_0000;
const FOCUS_IN_OUT = 0b0000_0000_1000_0000_0000;
const MOUSE_DRAG = 0b0000_0010_0000_0000_0000;
const MOUSE_MODE = 0b0000_0010_0000_0100_1000;
const UTF8_MOUSE = 0b0000_0100_0000_0000_0000;
const ALTERNATE_SCROLL = 0b0000_1000_0000_0000_0000;
const VI = 0b0001_0000_0000_0000_0000;
const URGENCY_HINTS = 0b0010_0000_0000_0000_0000;
// Kitty keyboard protocol enhancement flags
// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
/// Flag 1: Disambiguate escape codes.
/// Encodes ambiguous keys using CSI u sequences instead of legacy encodings:
/// - Esc key → CSI 27 u (distinguishes standalone Esc from escape sequence starts)
/// - Modified keys (Alt+key, Ctrl+key, Ctrl+Alt+key, Shift+Alt+key) → CSI u format
const KEYBOARD_DISAMBIGUATE_ESCAPE = 0b0100_0000_0000_0000_0000;
/// Flag 2: Report event types.
/// Enables reporting of key press, repeat, and release events, not just key presses.
/// Format includes event type in the CSI u sequence.
const KEYBOARD_REPORT_EVENT_TYPES = 0b1000_0000_0000_0000_0000;
/// Flag 4: Report alternate keys.
/// Reports the unshifted key alongside the shifted key. For example, when Shift+2 is
/// pressed, reports both "@" (shifted) and "2" (unshifted) for layout-independent
/// keybinding support.
const KEYBOARD_REPORT_ALTERNATE_KEYS = 0b0001_0000_0000_0000_0000_0000;
/// Flag 8: Report all keys as escape codes.
/// Forces all keys, including printable characters, to be encoded as CSI u sequences.
/// Provides a uniform encoding format. For example, plain 'a' becomes ESC[97;1u instead
/// of just 0x61. Often combined with flag 1 for "full CSI u" mode (flags = 9).
const KEYBOARD_REPORT_ALL_AS_ESCAPE = 0b0010_0000_0000_0000_0000_0000;
/// Flag 16: Report associated text.
/// Includes the text that would be generated by the key event, useful for applications
/// that want both the semantic key information and the resulting text.
const KEYBOARD_REPORT_ASSOCIATED_TEXT = 0b0100_0000_0000_0000_0000_0000;
const KEYBOARD_PROTOCOL = Self::KEYBOARD_DISAMBIGUATE_ESCAPE.bits()
| Self::KEYBOARD_REPORT_EVENT_TYPES.bits()
| Self::KEYBOARD_REPORT_ALTERNATE_KEYS.bits()
| Self::KEYBOARD_REPORT_ALL_AS_ESCAPE.bits()
| Self::KEYBOARD_REPORT_ASSOCIATED_TEXT.bits();
const ANY = u32::MAX;
}
}
impl Default for TermMode {
fn default() -> TermMode {
TermMode::SHOW_CURSOR
| TermMode::LINE_WRAP
| TermMode::ALTERNATE_SCROLL
| TermMode::URGENCY_HINTS
}
}
bitflags! {
/// Kitty keyboard protocol modes.
/// These map to the flags sent via CSI > flags u, CSI = flags u, etc.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct KeyboardModes: u32 {
const NO_MODE = 0;
const DISAMBIGUATE_ESC_CODES = 0b0000_0001;
const REPORT_EVENT_TYPES = 0b0000_0010;
const REPORT_ALTERNATE_KEYS = 0b0000_0100;
const REPORT_ALL_KEYS_AS_ESC = 0b0000_1000;
const REPORT_ASSOCIATED_TEXT = 0b0001_0000;
}
}
/// Convert KeyboardModes to TermMode flags
impl From<KeyboardModes> for TermMode {
fn from(modes: KeyboardModes) -> Self {
let mut term_mode = TermMode::NONE;
if modes.contains(KeyboardModes::DISAMBIGUATE_ESC_CODES) {
term_mode |= TermMode::KEYBOARD_DISAMBIGUATE_ESCAPE;
}
if modes.contains(KeyboardModes::REPORT_EVENT_TYPES) {
term_mode |= TermMode::KEYBOARD_REPORT_EVENT_TYPES;
}
if modes.contains(KeyboardModes::REPORT_ALTERNATE_KEYS) {
term_mode |= TermMode::KEYBOARD_REPORT_ALTERNATE_KEYS;
}
if modes.contains(KeyboardModes::REPORT_ALL_KEYS_AS_ESC) {
term_mode |= TermMode::KEYBOARD_REPORT_ALL_AS_ESCAPE;
}
if modes.contains(KeyboardModes::REPORT_ASSOCIATED_TEXT) {
term_mode |= TermMode::KEYBOARD_REPORT_ASSOCIATED_TEXT;
}
term_mode
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum KeyboardModesApplyBehavior {
/// Replace all current modes with new ones
Replace,
/// Union (add) new modes to existing ones
Union,
/// Difference (remove) modes from existing ones
Difference,
}
impl KeyboardModesApplyBehavior {
/// Maps kitty keyboard protocol apply-mode values to behavior.
///
/// From kitty's `CSI = flags ; mode u` command:
/// - `1` (or omitted) = replace current flags
/// - `2` = union/add flags
/// - `3` = difference/remove flags
pub fn from_kitty_apply_mode(mode: u16) -> Option<Self> {
match mode {
1 => Some(Self::Replace),
2 => Some(Self::Union),
3 => Some(Self::Difference),
_ => None,
}
}
}