From ec40f6e3acc7874b82709ab81b254c741529fdff Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 26 Oct 2026 10:52:04 -0400 Subject: Finish engine --- platforms/tortuise-script-compiled/src/buffer.rs | 296 +++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 platforms/tortuise-script-compiled/src/buffer.rs (limited to 'platforms/tortuise-script-compiled/src/buffer.rs') diff --git a/platforms/tortuise-script-compiled/src/buffer.rs b/platforms/tortuise-script-compiled/src/buffer.rs new file mode 100644 index 0000000..c60ee40 --- /dev/null +++ b/platforms/tortuise-script-compiled/src/buffer.rs @@ -0,0 +1,296 @@ +use std::time::Duration; + +use crossterm::style::ContentStyle; +use serde::{Deserialize, Serialize}; +use tortuise::script::Operation; + +use crate::ScriptContext; + +#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct Cell { + pub character: char, + pub foreground_color: Color, + pub background_color: Color, + pub underline_color: Color, + pub attributes: Attributes, + pub x: u16, + pub y: u16, + pub z: u8, +} + +#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Serialize, Deserialize)] +pub struct WindowSize { + pub rows: u16, + pub columns: u16, +} + +#[derive( + Copy, Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize, +)] +pub enum Color { + /// Resets the terminal color. + #[default] + Reset, + + /// Black color. + Black, + + /// Dark grey color. + DarkGrey, + + /// Light red color. + Red, + + /// Dark red color. + DarkRed, + + /// Light green color. + Green, + + /// Dark green color. + DarkGreen, + + /// Light yellow color. + Yellow, + + /// Dark yellow color. + DarkYellow, + + /// Light blue color. + Blue, + + /// Dark blue color. + DarkBlue, + + /// Light magenta color. + Magenta, + + /// Dark magenta color. + DarkMagenta, + + /// Light cyan color. + Cyan, + + /// Dark cyan color. + DarkCyan, + + /// White color. + White, + + /// Grey color. + Grey, + + /// An RGB color. See [RGB color model](https://en.wikipedia.org/wiki/RGB_color_model) for more info. + /// + /// Most UNIX terminals and Windows 10 supported only. + /// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info. + Rgb { r: u8, g: u8, b: u8 }, + + /// An ANSI color. See [256 colors - cheat sheet](https://jonasjacek.github.io/colors/) for more info. + /// + /// Most UNIX terminals and Windows 10 supported only. + /// See [Platform-specific notes](enum.Color.html#platform-specific-notes) for more info. + AnsiValue(u8), +} + +#[derive( + Copy, Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize, +)] +pub struct Attributes(u32); + +pub enum Attribute { + /// Increases the text intensity. + Bold = 1, + /// Decreases the text intensity. + Dim = 2, + /// Emphasises the text. + Italic = 4, + /// Underlines the text. + Underlined = 8, + + // Other types of underlining + /// Double underlines the text. + DoubleUnderlined = 16, + /// Undercurls the text. + Undercurled = 32, + /// Underdots the text. + Underdotted = 64, + /// Underdashes the text. + Underdashed = 128, + + /// Makes the text blinking (< 150 per minute). + SlowBlink = 256, + /// Makes the text blinking (>= 150 per minute). + RapidBlink = 512, + /// Swaps foreground and background colors. + Reverse = 1024, + /// Hides the text (also known as Conceal). + Hidden = 2048, + /// Crosses the text. + CrossedOut = 4096, + /// Sets the [Fraktur](https://en.wikipedia.org/wiki/Fraktur) typeface. + /// + /// Mostly used for [mathematical alphanumeric symbols](https://en.wikipedia.org/wiki/Mathematical_Alphanumeric_Symbols). + Fraktur = 8192, + /// Makes the text framed. + Framed = 16384, + /// Makes the text encircled. + Encircled = 32768, + /// Draws a line at the top of the text. + OverLined = 65536, +} + +impl Attributes { + pub fn none() -> Self { + Self(0) + } + + pub fn with(self, attribute: Attribute) -> Self { + Self(self.0 | attribute as u32) + } + + pub fn without(self, attribute: Attribute) -> Self { + Self(self.0 & !(attribute as u32)) + } + + pub fn set(&mut self, attribute: Attribute) { + self.0 |= attribute as u32; + } + + pub fn unset(&mut self, attribute: Attribute) { + self.0 &= !(attribute as u32) + } + + pub fn has(self, attribute: Attribute) -> bool { + self.0 & (attribute as u32) != 0 + } + + pub fn extend(&mut self, attributes: Attributes) { + self.0 |= attributes.0 + } + + pub fn is_empty(self) -> bool { + self.0 == 0 + } +} + +impl From for crossterm::style::Color { + fn from(value: Color) -> Self { + match value { + Color::Reset => crossterm::style::Color::Reset, + Color::Black => crossterm::style::Color::Black, + Color::DarkGrey => crossterm::style::Color::DarkGrey, + Color::Red => crossterm::style::Color::Red, + Color::DarkRed => crossterm::style::Color::DarkRed, + Color::Green => crossterm::style::Color::Green, + Color::DarkGreen => crossterm::style::Color::DarkGreen, + Color::Yellow => crossterm::style::Color::Yellow, + Color::DarkYellow => crossterm::style::Color::DarkYellow, + Color::Blue => crossterm::style::Color::Blue, + Color::DarkBlue => crossterm::style::Color::DarkBlue, + Color::Magenta => crossterm::style::Color::Magenta, + Color::DarkMagenta => crossterm::style::Color::DarkMagenta, + Color::Cyan => crossterm::style::Color::Cyan, + Color::DarkCyan => crossterm::style::Color::DarkCyan, + Color::White => crossterm::style::Color::White, + Color::Grey => crossterm::style::Color::Grey, + Color::Rgb { r, g, b } => crossterm::style::Color::Rgb { r, g, b }, + Color::AnsiValue(v) => crossterm::style::Color::AnsiValue(v), + } + } +} + +impl From for crossterm::style::Attributes { + fn from(value: Attributes) -> Self { + let mut new = crossterm::style::Attributes::none(); + + if value.has(Attribute::Bold) { + new.set(crossterm::style::Attribute::Bold); + } + if value.has(Attribute::Dim) { + new.set(crossterm::style::Attribute::Dim); + } + if value.has(Attribute::Italic) { + new.set(crossterm::style::Attribute::Italic); + } + if value.has(Attribute::Underlined) { + new.set(crossterm::style::Attribute::Underlined); + } + if value.has(Attribute::DoubleUnderlined) { + new.set(crossterm::style::Attribute::DoubleUnderlined); + } + if value.has(Attribute::Undercurled) { + new.set(crossterm::style::Attribute::Undercurled); + } + if value.has(Attribute::Underdotted) { + new.set(crossterm::style::Attribute::Underdotted); + } + if value.has(Attribute::Underdashed) { + new.set(crossterm::style::Attribute::Underdashed); + } + if value.has(Attribute::SlowBlink) { + new.set(crossterm::style::Attribute::SlowBlink); + } + if value.has(Attribute::RapidBlink) { + new.set(crossterm::style::Attribute::RapidBlink); + } + if value.has(Attribute::Reverse) { + new.set(crossterm::style::Attribute::Reverse); + } + if value.has(Attribute::Hidden) { + new.set(crossterm::style::Attribute::Hidden); + } + if value.has(Attribute::CrossedOut) { + new.set(crossterm::style::Attribute::CrossedOut); + } + if value.has(Attribute::Fraktur) { + new.set(crossterm::style::Attribute::Fraktur); + } + if value.has(Attribute::Framed) { + new.set(crossterm::style::Attribute::Framed); + } + if value.has(Attribute::Encircled) { + new.set(crossterm::style::Attribute::Encircled); + } + if value.has(Attribute::OverLined) { + new.set(crossterm::style::Attribute::OverLined); + } + + new + } +} + +impl ScriptContext<'_> { + pub fn add_cell(&mut self, cell: Cell) { + puffin::profile_function!(); + self.0 + .operation_queue + .push(Operation::AddCell(tortuise::buffer::Cell { + character: cell.character, + style: ContentStyle { + foreground_color: Some(cell.foreground_color.into()), + background_color: Some(cell.background_color.into()), + underline_color: Some(cell.underline_color.into()), + attributes: cell.attributes.into(), + }, + x: cell.x, + y: cell.y, + z: cell.z, + })); + } + + pub fn window_size(&self) -> WindowSize { + puffin::profile_function!(); + let size = &self.0.buffer.window_size; + WindowSize { + rows: size.rows, + columns: size.columns, + } + } + + pub fn set_framerate_limit(&mut self, limit: Option) { + puffin::profile_function!(); + let limit = limit.map(|limit| Duration::from_nanos(1_000_000_000 / limit as u64)); + self.0.operation_queue.push(Operation::SetFrameLimit(limit)); + } +} -- cgit v1.3.1