1use std::{marker::PhantomData, mem::MaybeUninit};
4
5use crate::{
6 alloc::{Allocator, Object},
7 error::{Result, from_result},
8 ffi,
9};
10
11#[derive(Debug)]
18pub struct Parser<'alloc>(Object<'alloc, ffi::OscParserImpl>);
19
20impl<'alloc> Parser<'alloc> {
21 pub fn new() -> Result<Self> {
23 unsafe { Self::new_inner(std::ptr::null()) }
25 }
26
27 pub fn new_with_alloc<'ctx: 'alloc>(alloc: &'alloc Allocator<'ctx>) -> Result<Self> {
32 unsafe { Self::new_inner(alloc.to_raw()) }
34 }
35
36 unsafe fn new_inner(alloc: *const ffi::Allocator) -> Result<Self> {
37 let mut raw: ffi::OscParser = std::ptr::null_mut();
38 let result = unsafe { ffi::ghostty_osc_new(alloc, &raw mut raw) };
39 from_result(result)?;
40 Ok(Self(Object::new(raw)?))
41 }
42
43 pub fn reset(&mut self) {
49 unsafe { ffi::ghostty_osc_reset(self.0.as_raw()) }
50 }
51
52 pub fn next_byte(&mut self, byte: u8) {
61 unsafe { ffi::ghostty_osc_next(self.0.as_raw(), byte) }
62 }
63
64 #[expect(clippy::missing_panics_doc, reason = "internal invariant")]
80 pub fn end<'p>(&'p mut self, terminator: u8) -> Command<'p, 'alloc> {
81 let raw = unsafe { ffi::ghostty_osc_end(self.0.as_raw(), terminator) };
82 Command {
83 inner: Object::new(raw).expect("command must not be null"),
84 _parser: PhantomData,
85 }
86 }
87}
88
89impl Drop for Parser<'_> {
90 fn drop(&mut self) {
91 unsafe { ffi::ghostty_osc_free(self.0.as_raw()) }
92 }
93}
94
95#[derive(Debug)]
99pub struct Command<'p, 'alloc> {
100 inner: Object<'alloc, ffi::OscCommandImpl>,
101 _parser: PhantomData<&'p Parser<'alloc>>,
102}
103
104impl<'p> Command<'p, '_> {
105 #[must_use]
110 pub fn command_type(self) -> CommandType<'p> {
111 self.command_type_inner().unwrap_or(CommandType::Invalid)
112 }
113
114 fn command_type_inner(&self) -> Option<CommandType<'p>> {
115 use ffi::OscCommandData as Data;
116 use ffi::OscCommandType as Type;
117
118 let raw_type = unsafe { ffi::ghostty_osc_command_type(self.inner.as_raw()) };
119 Some(match raw_type {
120 Type::CHANGE_WINDOW_TITLE => CommandType::ChangeWindowTitle {
121 title: self.get(Data::CHANGE_WINDOW_TITLE_STR)?,
122 },
123 Type::CHANGE_WINDOW_ICON => CommandType::ChangeWindowIcon,
124 Type::SEMANTIC_PROMPT => CommandType::SemanticPrompt,
125 Type::CLIPBOARD_CONTENTS => CommandType::ClipboardContents,
126 Type::REPORT_PWD => CommandType::ReportPwd,
127 Type::MOUSE_SHAPE => CommandType::MouseShape,
128 Type::COLOR_OPERATION => CommandType::ColorOperation,
129 Type::KITTY_COLOR_PROTOCOL => CommandType::KittyColorProtocol,
130 Type::SHOW_DESKTOP_NOTIFICATION => CommandType::ShowDesktopNotification,
131 Type::HYPERLINK_START => CommandType::HyperlinkStart,
132 Type::HYPERLINK_END => CommandType::HyperlinkEnd,
133 Type::CONEMU_SLEEP => CommandType::ConemuSleep,
134 Type::CONEMU_SHOW_MESSAGE_BOX => CommandType::ConemuShowMessageBox,
135 Type::CONEMU_CHANGE_TAB_TITLE => CommandType::ConemuChangeTabTitle,
136 Type::CONEMU_PROGRESS_REPORT => CommandType::ConemuProgressReport,
137 Type::CONEMU_WAIT_INPUT => CommandType::ConemuWaitInput,
138 Type::CONEMU_GUIMACRO => CommandType::ConemuGuiMacro,
139 Type::CONEMU_RUN_PROCESS => CommandType::ConemuRunProcess,
140 Type::CONEMU_OUTPUT_ENVIRONMENT_VARIABLE => {
141 CommandType::ConemuOutputEnvironmentVariable
142 }
143 Type::CONEMU_XTERM_EMULATION => CommandType::ConemuXtermEmulation,
144 Type::CONEMU_COMMENT => CommandType::ConemuComment,
145 Type::KITTY_TEXT_SIZING => CommandType::KittyTextSizing,
146
147 _ => return None,
148 })
149 }
150
151 fn get<T>(&self, tag: ffi::OscCommandData::Type) -> Option<T> {
152 let mut value = MaybeUninit::<T>::zeroed();
153 let result = unsafe {
154 ffi::ghostty_osc_command_data(self.inner.as_raw(), tag, value.as_mut_ptr().cast())
155 };
156
157 if result {
158 Some(unsafe { value.assume_init() })
160 } else {
161 None
162 }
163 }
164}
165
166#[repr(u32)]
168#[derive(Debug, Clone, Default)]
169#[expect(missing_docs, reason = "missing upstream docs")]
170pub enum CommandType<'p> {
171 #[default]
172 Invalid,
173 ChangeWindowTitle {
174 title: &'p str,
176 },
177 ChangeWindowIcon,
178 SemanticPrompt,
179 ClipboardContents,
180 ReportPwd,
181 MouseShape,
182 ColorOperation,
183 KittyColorProtocol,
184 ShowDesktopNotification,
185 HyperlinkStart,
186 HyperlinkEnd,
187 ConemuSleep,
188 ConemuShowMessageBox,
189 ConemuChangeTabTitle,
190 ConemuProgressReport,
191 ConemuWaitInput,
192 ConemuGuiMacro,
193 ConemuRunProcess,
194 ConemuOutputEnvironmentVariable,
195 ConemuXtermEmulation,
196 ConemuComment,
197 KittyTextSizing,
198}