aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/renderer/State.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/renderer/State.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/renderer/State.zig')
-rw-r--r--vendor/libghostty-vt/src/renderer/State.zig123
1 files changed, 123 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/renderer/State.zig b/vendor/libghostty-vt/src/renderer/State.zig
new file mode 100644
index 00000000..e882ddce
--- /dev/null
+++ b/vendor/libghostty-vt/src/renderer/State.zig
@@ -0,0 +1,123 @@
+//! This is the render state that is given to a renderer.
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const Inspector = @import("../inspector/main.zig").Inspector;
+const terminalpkg = @import("../terminal/main.zig");
+const inputpkg = @import("../input.zig");
+const renderer = @import("../renderer.zig");
+
+/// The mutex that must be held while reading any of the data in the
+/// members of this state. Note that the state itself is NOT protected
+/// by the mutex and is NOT thread-safe, only the members values of the
+/// state (i.e. the terminal, devmode, etc. values).
+mutex: *std.Thread.Mutex,
+
+/// The terminal data.
+terminal: *terminalpkg.Terminal,
+
+/// The terminal inspector, if any. This will be null while the inspector
+/// is not active and will be set when it is active.
+inspector: ?*Inspector = null,
+
+/// Dead key state. This will render the current dead key preedit text
+/// over the cursor. This currently only ever renders a single codepoint.
+/// Preedit can in theory be multiple codepoints long but that is left as
+/// a future exercise.
+preedit: ?Preedit = null,
+
+/// Mouse state. This only contains state relevant to what renderers
+/// need about the mouse.
+mouse: Mouse = .{},
+
+pub const Mouse = struct {
+ /// The point on the viewport where the mouse currently is. We use
+ /// viewport points to avoid the complexity of mapping the mouse to
+ /// the renderer state.
+ point: ?terminalpkg.point.Coordinate = null,
+
+ /// The mods that are currently active for the last mouse event.
+ /// This could really just be mods in general and we probably will
+ /// move it out of mouse state at some point.
+ mods: inputpkg.Mods = .{},
+};
+
+/// The pre-edit state. See Surface.preeditCallback for more information.
+pub const Preedit = struct {
+ /// The codepoints to render as preedit text.
+ codepoints: []const Codepoint = &.{},
+
+ /// A single codepoint to render as preedit text.
+ pub const Codepoint = struct {
+ codepoint: u21,
+ wide: bool = false,
+ };
+
+ /// Deinit this preedit that was cre
+ pub fn deinit(self: *const Preedit, alloc: Allocator) void {
+ alloc.free(self.codepoints);
+ }
+
+ /// Allocate a copy of this preedit in the given allocator..
+ pub fn clone(self: *const Preedit, alloc: Allocator) !Preedit {
+ return .{
+ .codepoints = try alloc.dupe(Codepoint, self.codepoints),
+ };
+ }
+
+ /// The width in cells of all codepoints in the preedit.
+ pub fn width(self: *const Preedit) usize {
+ var result: usize = 0;
+ for (self.codepoints) |cp| {
+ result += if (cp.wide) 2 else 1;
+ }
+
+ return result;
+ }
+
+ /// Range returns the start and end x position of the preedit text
+ /// along with any codepoint offset necessary to fit the preedit
+ /// into the available space.
+ pub fn range(
+ self: *const Preedit,
+ start: terminalpkg.size.CellCountInt,
+ max: terminalpkg.size.CellCountInt,
+ ) struct {
+ start: terminalpkg.size.CellCountInt,
+ end: terminalpkg.size.CellCountInt,
+ cp_offset: usize,
+ } {
+ // If our width is greater than the number of cells we have
+ // then we need to adjust our codepoint start to a point where
+ // our width would be less than the number of cells we have.
+ const w, const cp_offset = width: {
+ // max is inclusive, so we need to add 1 to it.
+ const max_width = max - start + 1;
+
+ // Rebuild our width in reverse order. This is because we want
+ // to offset by the end cells, not the start cells (if we have to).
+ var w: terminalpkg.size.CellCountInt = 0;
+ for (0..self.codepoints.len) |i| {
+ const reverse_i = self.codepoints.len - i - 1;
+ const cp = self.codepoints[reverse_i];
+ w += if (cp.wide) 2 else 1;
+ if (w > max_width) {
+ break :width .{ w, reverse_i };
+ }
+ }
+
+ // Width fit in the max width so no offset necessary.
+ break :width .{ w, 0 };
+ };
+
+ // If our preedit goes off the end of the screen, we adjust it so
+ // that it shifts left.
+ const end = start + w;
+ const start_offset = if (end > max) end - max else 0;
+ return .{
+ .start = start -| start_offset,
+ .end = end -| start_offset,
+ .cp_offset = cp_offset,
+ };
+ }
+};