use std::{marker::PhantomData, mem::MaybeUninit};
use crate::{
error::{Error, Result, from_result, from_result_with_len},
ffi,
style::{self, PaletteIndex, RgbColor, Style},
};
#[derive(Clone, Debug)]
pub struct GridRef<'t> {
pub(crate) inner: ffi::GhosttyGridRef,
pub(crate) _phan: PhantomData<&'t ffi::GhosttyTerminal>,
}
impl GridRef<'_> {
pub fn row(&self) -> Result<Row> {
let mut v = ffi::GhosttyRow::default();
let result = unsafe { ffi::ghostty_grid_ref_row(std::ptr::from_ref(&self.inner), &raw mut v) };
from_result(result)?;
Ok(Row(v))
}
pub fn cell(&self) -> Result<Cell> {
let mut v = ffi::GhosttyCell::default();
let result = unsafe { ffi::ghostty_grid_ref_cell(std::ptr::from_ref(&self.inner), &raw mut v) };
from_result(result)?;
Ok(Cell(v))
}
pub fn style(&self) -> Result<Style> {
let mut v = ffi::GhosttyStyle::default();
let result =
unsafe { ffi::ghostty_grid_ref_style(std::ptr::from_ref(&self.inner), &raw mut v) };
from_result(result)?;
Style::try_from(v)
}
pub fn graphemes(&self, buf: &mut [char]) -> Result<usize> {
let mut len = 0;
let result = unsafe {
ffi::ghostty_grid_ref_graphemes(
std::ptr::from_ref(&self.inner),
std::ptr::from_mut(buf).cast(),
buf.len(),
&raw mut len,
)
};
from_result_with_len(result, len)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Row(pub(crate) ffi::GhosttyRow);
impl Row {
fn get<T>(&self, tag: ffi::GhosttyRowData) -> Result<T> {
let mut value = MaybeUninit::<T>::zeroed();
let result = unsafe { ffi::ghostty_row_get(self.0, tag, value.as_mut_ptr().cast()) };
from_result(result)?;
Ok(unsafe { value.assume_init() })
}
pub fn is_wrapped(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_WRAP)
}
pub fn is_wrap_continuation(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_WRAP_CONTINUATION)
}
pub fn has_grapheme_cluster(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_GRAPHEME)
}
pub fn is_styled(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_STYLED)
}
pub fn has_hyperlink(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_HYPERLINK)
}
pub fn semantic_prompt(self) -> Result<RowSemanticPrompt> {
self.get::<ffi::GhosttyRowSemanticPrompt>(
ffi::GhosttyRowData_GHOSTTY_ROW_DATA_SEMANTIC_PROMPT,
)
.and_then(|v| v.try_into().map_err(|_| Error::InvalidValue))
}
pub fn has_kitty_virtual_placeholder(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_KITTY_VIRTUAL_PLACEHOLDER)
}
pub fn is_dirty(self) -> Result<bool> {
self.get(ffi::GhosttyRowData_GHOSTTY_ROW_DATA_DIRTY)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Cell(pub(crate) ffi::GhosttyCell);
impl Cell {
fn get<T>(&self, tag: ffi::GhosttyCellData) -> Result<T> {
let mut value = MaybeUninit::<T>::zeroed();
let result = unsafe { ffi::ghostty_cell_get(self.0, tag, value.as_mut_ptr().cast()) };
from_result(result)?;
Ok(unsafe { value.assume_init() })
}
pub fn codepoint(self) -> Result<u32> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_CODEPOINT)
}
pub fn content_tag(self) -> Result<CellContentTag> {
self.get::<ffi::GhosttyCellContentTag>(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_CONTENT_TAG)
.and_then(|v| v.try_into().map_err(|_| Error::InvalidValue))
}
pub fn wide(self) -> Result<CellWide> {
self.get::<ffi::GhosttyCellWide>(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_WIDE)
.and_then(|v| v.try_into().map_err(|_| Error::InvalidValue))
}
pub fn has_text(self) -> Result<bool> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_HAS_TEXT)
}
pub fn has_styling(self) -> Result<bool> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_HAS_STYLING)
}
pub fn style_id(self) -> Result<style::Id> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_STYLE_ID)
.map(style::Id)
}
pub fn has_hyperlink(self) -> Result<bool> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_HAS_HYPERLINK)
}
pub fn is_protected(self) -> Result<bool> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_PROTECTED)
}
pub fn semantic_content(self) -> Result<CellSemanticContent> {
self.get::<ffi::GhosttyCellSemanticContent>(
ffi::GhosttyCellData_GHOSTTY_CELL_DATA_SEMANTIC_CONTENT,
)
.and_then(|v| v.try_into().map_err(|_| Error::InvalidValue))
}
pub fn bg_color_palette(self) -> Result<PaletteIndex> {
self.get(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_COLOR_PALETTE)
.map(PaletteIndex)
}
pub fn bg_color_rgb(self) -> Result<RgbColor> {
Ok(self
.get::<ffi::GhosttyColorRgb>(ffi::GhosttyCellData_GHOSTTY_CELL_DATA_COLOR_RGB)?
.into())
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
pub enum RowSemanticPrompt {
None = ffi::GhosttyRowSemanticPrompt_GHOSTTY_ROW_SEMANTIC_NONE,
Prompt = ffi::GhosttyRowSemanticPrompt_GHOSTTY_ROW_SEMANTIC_PROMPT,
Continuation = ffi::GhosttyRowSemanticPrompt_GHOSTTY_ROW_SEMANTIC_PROMPT_CONTINUATION,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
pub enum CellContentTag {
Codepoint = ffi::GhosttyCellContentTag_GHOSTTY_CELL_CONTENT_CODEPOINT,
CodepointGrapheme = ffi::GhosttyCellContentTag_GHOSTTY_CELL_CONTENT_CODEPOINT_GRAPHEME,
BgColorPalette = ffi::GhosttyCellContentTag_GHOSTTY_CELL_CONTENT_BG_COLOR_PALETTE,
BgColorRgb = ffi::GhosttyCellContentTag_GHOSTTY_CELL_CONTENT_BG_COLOR_RGB,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
pub enum CellWide {
Narrow = ffi::GhosttyCellWide_GHOSTTY_CELL_WIDE_NARROW,
Wide = ffi::GhosttyCellWide_GHOSTTY_CELL_WIDE_WIDE,
SpacerTail = ffi::GhosttyCellWide_GHOSTTY_CELL_WIDE_SPACER_TAIL,
SpacerHead = ffi::GhosttyCellWide_GHOSTTY_CELL_WIDE_SPACER_HEAD,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, int_enum::IntEnum)]
pub enum CellSemanticContent {
Output = ffi::GhosttyCellSemanticContent_GHOSTTY_CELL_SEMANTIC_OUTPUT,
Input = ffi::GhosttyCellSemanticContent_GHOSTTY_CELL_SEMANTIC_INPUT,
Prompt = ffi::GhosttyCellSemanticContent_GHOSTTY_CELL_SEMANTIC_PROMPT,
}