libghostty: C API for SelectionGesture (#12833)
C API side of https://github.com/ghostty-org/ghostty/pull/12830pull/12836/head
commit
6d089a544d
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Example: `ghostty-vt` Selection Gestures
|
||||||
|
|
||||||
|
This contains a simple example of how to use the `ghostty-vt` selection
|
||||||
|
gesture API from C. It creates synthetic press, drag, release, and deep-press
|
||||||
|
events and formats the resulting selection snapshots.
|
||||||
|
|
||||||
|
This uses a `build.zig` and `Zig` to build the C program so that we
|
||||||
|
can reuse a lot of our build logic and depend directly on our source
|
||||||
|
tree, but Ghostty emits a standard C library that can be used with any
|
||||||
|
C tooling.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the program:
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
zig build run
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
|
||||||
|
const exe_mod = b.createModule(.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
exe_mod.addCSourceFiles(.{
|
||||||
|
.root = b.path("src"),
|
||||||
|
.files = &.{"main.c"},
|
||||||
|
});
|
||||||
|
|
||||||
|
// You'll want to use a lazy dependency here so that ghostty is only
|
||||||
|
// downloaded if you actually need it.
|
||||||
|
if (b.lazyDependency("ghostty", .{
|
||||||
|
// Setting simd to false will force a pure static build that
|
||||||
|
// doesn't even require libc, but it has a significant performance
|
||||||
|
// penalty. If your embedding app requires libc anyway, you should
|
||||||
|
// always keep simd enabled.
|
||||||
|
// .simd = false,
|
||||||
|
})) |dep| {
|
||||||
|
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exe
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "c_vt_selection_gesture",
|
||||||
|
.root_module = exe_mod,
|
||||||
|
});
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
// Run
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
if (b.args) |args| run_cmd.addArgs(args);
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
.{
|
||||||
|
.name = .c_vt_selection_gesture,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.fingerprint = 0x5a4e72d27b582404,
|
||||||
|
.minimum_zig_version = "0.15.1",
|
||||||
|
.dependencies = .{
|
||||||
|
// Ghostty dependency. In reality, you'd probably use a URL-based
|
||||||
|
// dependency like the one showed (and commented out) below this one.
|
||||||
|
// We use a path dependency here for simplicity and to ensure our
|
||||||
|
// examples always test against the source they're bundled with.
|
||||||
|
.ghostty = .{ .path = "../../" },
|
||||||
|
|
||||||
|
// Example of what a URL-based dependency looks like:
|
||||||
|
// .ghostty = .{
|
||||||
|
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
|
||||||
|
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ghostty/vt.h>
|
||||||
|
|
||||||
|
//! [selection-gesture-main]
|
||||||
|
static void vt_write(GhosttyTerminal terminal, const char *s) {
|
||||||
|
ghostty_terminal_vt_write(terminal, (const uint8_t *)s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GhosttyGridRef ref_at(GhosttyTerminal terminal, uint16_t x, uint16_t y) {
|
||||||
|
GhosttyGridRef ref = GHOSTTY_INIT_SIZED(GhosttyGridRef);
|
||||||
|
GhosttyPoint point = {
|
||||||
|
.tag = GHOSTTY_POINT_TAG_ACTIVE,
|
||||||
|
.value = { .coordinate = { .x = x, .y = y } },
|
||||||
|
};
|
||||||
|
|
||||||
|
GhosttyResult result = ghostty_terminal_grid_ref(terminal, point, &ref);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_selection(
|
||||||
|
GhosttyTerminal terminal,
|
||||||
|
const char *label,
|
||||||
|
const GhosttySelection *selection) {
|
||||||
|
GhosttyTerminalSelectionFormatOptions opts =
|
||||||
|
GHOSTTY_INIT_SIZED(GhosttyTerminalSelectionFormatOptions);
|
||||||
|
opts.emit = GHOSTTY_FORMATTER_FORMAT_PLAIN;
|
||||||
|
opts.trim = true;
|
||||||
|
opts.selection = selection;
|
||||||
|
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
GhosttyResult result = ghostty_terminal_selection_format_alloc(
|
||||||
|
terminal, NULL, opts, &buf, &len);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
printf("%s: ", label);
|
||||||
|
fwrite(buf, 1, len, stdout);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
ghostty_free(NULL, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GhosttySelectionGestureEvent new_event(
|
||||||
|
GhosttySelectionGestureEventType type) {
|
||||||
|
GhosttySelectionGestureEvent event = NULL;
|
||||||
|
GhosttyResult result = ghostty_selection_gesture_event_new(NULL, &event, type);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
GhosttyTerminal terminal;
|
||||||
|
GhosttyTerminalOptions opts = {
|
||||||
|
.cols = 20,
|
||||||
|
.rows = 4,
|
||||||
|
.max_scrollback = 100,
|
||||||
|
};
|
||||||
|
GhosttyResult result = ghostty_terminal_new(NULL, &terminal, opts);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
vt_write(terminal, "hello world\r\nsecond line");
|
||||||
|
|
||||||
|
GhosttySelectionGesture gesture = NULL;
|
||||||
|
result = ghostty_selection_gesture_new(NULL, &gesture);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
GhosttySelectionGestureEvent press =
|
||||||
|
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_PRESS);
|
||||||
|
GhosttySelectionGestureEvent drag =
|
||||||
|
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DRAG);
|
||||||
|
GhosttySelectionGestureEvent release =
|
||||||
|
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_RELEASE);
|
||||||
|
GhosttySelectionGestureEvent deep_press =
|
||||||
|
new_event(GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DEEP_PRESS);
|
||||||
|
|
||||||
|
GhosttySelectionGestureGeometry geometry = {
|
||||||
|
.columns = 20,
|
||||||
|
.cell_width = 10,
|
||||||
|
.padding_left = 0,
|
||||||
|
.screen_height = 40,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Press in the first cell. A normal single press records the click anchor but
|
||||||
|
// doesn't produce a selection yet, so we discard the optional output.
|
||||||
|
GhosttyGridRef press_ref = ref_at(terminal, 0, 0);
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
press, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &press_ref);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
GhosttySurfacePosition press_pos = { .x = 2, .y = 8 };
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
press, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_POSITION, &press_pos);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
result = ghostty_selection_gesture_event(
|
||||||
|
gesture, terminal, press, NULL);
|
||||||
|
assert(result == GHOSTTY_NO_VALUE);
|
||||||
|
|
||||||
|
// Drag across "hello". The drag event returns a selection snapshot that the
|
||||||
|
// embedder can apply to its UI, copy, or format immediately.
|
||||||
|
GhosttyGridRef drag_ref = ref_at(terminal, 4, 0);
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
drag, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &drag_ref);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
GhosttySurfacePosition drag_pos = { .x = 46, .y = 8 };
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
drag, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_POSITION, &drag_pos);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
drag, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY, &geometry);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
|
||||||
|
GhosttySelection selection = GHOSTTY_INIT_SIZED(GhosttySelection);
|
||||||
|
result = ghostty_selection_gesture_event(
|
||||||
|
gesture, terminal, drag, &selection);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
print_selection(terminal, "drag", &selection);
|
||||||
|
|
||||||
|
// Release updates gesture state but never produces a selection.
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
release, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &drag_ref);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
result = ghostty_selection_gesture_event(
|
||||||
|
gesture, terminal, release, NULL);
|
||||||
|
assert(result == GHOSTTY_NO_VALUE);
|
||||||
|
|
||||||
|
bool dragged = false;
|
||||||
|
result = ghostty_selection_gesture_get(
|
||||||
|
gesture, terminal, GHOSTTY_SELECTION_GESTURE_DATA_DRAGGED, &dragged);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
printf("dragged: %s\n", dragged ? "true" : "false");
|
||||||
|
|
||||||
|
// Deep press uses the active click anchor to select the surrounding word.
|
||||||
|
ghostty_selection_gesture_reset(gesture, terminal);
|
||||||
|
GhosttyGridRef world_ref = ref_at(terminal, 6, 0);
|
||||||
|
result = ghostty_selection_gesture_event_set(
|
||||||
|
press, GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF, &world_ref);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
result = ghostty_selection_gesture_event(
|
||||||
|
gesture, terminal, press, NULL);
|
||||||
|
assert(result == GHOSTTY_NO_VALUE);
|
||||||
|
|
||||||
|
result = ghostty_selection_gesture_event(
|
||||||
|
gesture, terminal, deep_press, &selection);
|
||||||
|
assert(result == GHOSTTY_SUCCESS);
|
||||||
|
print_selection(terminal, "deep press", &selection);
|
||||||
|
|
||||||
|
ghostty_selection_gesture_event_free(deep_press);
|
||||||
|
ghostty_selection_gesture_event_free(release);
|
||||||
|
ghostty_selection_gesture_event_free(drag);
|
||||||
|
ghostty_selection_gesture_event_free(press);
|
||||||
|
ghostty_selection_gesture_free(gesture, terminal);
|
||||||
|
ghostty_terminal_free(terminal);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//! [selection-gesture-main]
|
||||||
|
|
@ -104,6 +104,11 @@
|
||||||
* detect when it loses its value, and move it to a new point.
|
* detect when it loses its value, and move it to a new point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** @example c-vt-selection-gesture/src/main.c
|
||||||
|
* This example demonstrates how to use synthetic selection gesture events to
|
||||||
|
* derive drag and deep-press selection snapshots.
|
||||||
|
*/
|
||||||
|
|
||||||
/** @example c-vt-kitty-graphics/src/main.c
|
/** @example c-vt-kitty-graphics/src/main.c
|
||||||
* This example demonstrates how to use the system interface to install a
|
* This example demonstrates how to use the system interface to install a
|
||||||
* PNG decoder callback and send a Kitty Graphics Protocol image.
|
* PNG decoder callback and send a Kitty Graphics Protocol image.
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,44 @@ extern "C" {
|
||||||
* for the endpoints and reconstruct a GhosttySelection from fresh snapshots
|
* for the endpoints and reconstruct a GhosttySelection from fresh snapshots
|
||||||
* when needed.
|
* when needed.
|
||||||
*
|
*
|
||||||
|
* Selection gestures provide a reusable state machine for turning UI pointer
|
||||||
|
* interactions into selection snapshots. A caller creates one
|
||||||
|
* GhosttySelectionGesture per active gesture stream, reuses typed
|
||||||
|
* GhosttySelectionGestureEvent objects for synthetic press, drag, release,
|
||||||
|
* autoscroll tick, and deep-press events, and applies each event with
|
||||||
|
* ghostty_selection_gesture_event(). The returned GhosttySelection is a
|
||||||
|
* snapshot; the embedder decides whether to render it, format/copy it, or
|
||||||
|
* install it as the terminal's active selection.
|
||||||
|
*
|
||||||
* ## Examples
|
* ## Examples
|
||||||
*
|
*
|
||||||
* @snippet c-vt-selection/src/main.c selection-main
|
* @snippet c-vt-selection/src/main.c selection-main
|
||||||
|
* @snippet c-vt-selection-gesture/src/main.c selection-gesture-main
|
||||||
*
|
*
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque handle to state for interpreting terminal selection gestures.
|
||||||
|
*
|
||||||
|
* The gesture owns only the state required to interpret pointer events. Calls
|
||||||
|
* that use a gesture are not concurrency-safe and must be serialized with
|
||||||
|
* terminal mutations.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef struct GhosttySelectionGestureImpl* GhosttySelectionGesture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque handle to reusable input data for selection gesture operations.
|
||||||
|
*
|
||||||
|
* Event options are set with ghostty_selection_gesture_event_set(). Individual
|
||||||
|
* gesture operations document which options are required or optional.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef struct GhosttySelectionGestureEventImpl* GhosttySelectionGestureEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A snapshot selection range defined by two grid references.
|
* A snapshot selection range defined by two grid references.
|
||||||
*
|
*
|
||||||
|
|
@ -283,6 +314,417 @@ typedef enum GHOSTTY_ENUM_TYPED {
|
||||||
GHOSTTY_SELECTION_ADJUST_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
GHOSTTY_SELECTION_ADJUST_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||||
} GhosttySelectionAdjust;
|
} GhosttySelectionAdjust;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selection behavior chosen for a gesture's click sequence.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef enum GHOSTTY_ENUM_TYPED {
|
||||||
|
/** Cell-granular drag selection. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_BEHAVIOR_CELL = 0,
|
||||||
|
|
||||||
|
/** Word selection on press and word-granular drag selection. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_BEHAVIOR_WORD = 1,
|
||||||
|
|
||||||
|
/** Line selection on press and line-granular drag selection. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_BEHAVIOR_LINE = 2,
|
||||||
|
|
||||||
|
/** Semantic command output selection on press and drag. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_BEHAVIOR_OUTPUT = 3,
|
||||||
|
|
||||||
|
GHOSTTY_SELECTION_GESTURE_BEHAVIOR_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||||
|
} GhosttySelectionGestureBehavior;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selection behaviors for single-, double-, and triple-click gestures.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Behavior for single-click selection gestures. */
|
||||||
|
GhosttySelectionGestureBehavior single_click;
|
||||||
|
|
||||||
|
/** Behavior for double-click selection gestures. */
|
||||||
|
GhosttySelectionGestureBehavior double_click;
|
||||||
|
|
||||||
|
/** Behavior for triple-click selection gestures. */
|
||||||
|
GhosttySelectionGestureBehavior triple_click;
|
||||||
|
} GhosttySelectionGestureBehaviors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display geometry used to interpret selection gesture drag events.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Number of columns in the rendered terminal grid. Must be non-zero. */
|
||||||
|
uint32_t columns;
|
||||||
|
|
||||||
|
/** Width of one terminal cell in surface pixels. Must be non-zero. */
|
||||||
|
uint32_t cell_width;
|
||||||
|
|
||||||
|
/** Left padding before the terminal grid begins in surface pixels. */
|
||||||
|
uint32_t padding_left;
|
||||||
|
|
||||||
|
/** Height of the rendered terminal surface in surface pixels. Must be non-zero. */
|
||||||
|
uint32_t screen_height;
|
||||||
|
} GhosttySelectionGestureGeometry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current autoscroll direction for an active selection drag gesture.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef enum GHOSTTY_ENUM_TYPED {
|
||||||
|
/** No selection autoscroll is requested. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_NONE = 0,
|
||||||
|
|
||||||
|
/** Selection dragging should autoscroll the viewport upward. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_UP = 1,
|
||||||
|
|
||||||
|
/** Selection dragging should autoscroll the viewport downward. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_DOWN = 2,
|
||||||
|
|
||||||
|
GHOSTTY_SELECTION_GESTURE_AUTOSCROLL_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||||
|
} GhosttySelectionGestureAutoscroll;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data fields readable from a selection gesture with
|
||||||
|
* ghostty_selection_gesture_get().
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef enum GHOSTTY_ENUM_TYPED {
|
||||||
|
/** Current click count: uint8_t*. 0 means inactive. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_DATA_CLICK_COUNT = 0,
|
||||||
|
|
||||||
|
/** Whether the current/last left-click gesture has dragged: bool*. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_DATA_DRAGGED = 1,
|
||||||
|
|
||||||
|
/** Current autoscroll request: GhosttySelectionGestureAutoscroll*. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_DATA_AUTOSCROLL = 2,
|
||||||
|
|
||||||
|
/** Current gesture behavior: GhosttySelectionGestureBehavior*. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_DATA_BEHAVIOR = 3,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current left-click anchor: GhosttyGridRef*.
|
||||||
|
*
|
||||||
|
* Returns GHOSTTY_NO_VALUE if there is no valid active anchor. On success,
|
||||||
|
* writes an untracked GhosttyGridRef snapshot with normal GhosttyGridRef
|
||||||
|
* lifetime rules.
|
||||||
|
*/
|
||||||
|
GHOSTTY_SELECTION_GESTURE_DATA_ANCHOR = 4,
|
||||||
|
|
||||||
|
GHOSTTY_SELECTION_GESTURE_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||||
|
} GhosttySelectionGestureData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selection gesture event type.
|
||||||
|
*
|
||||||
|
* The event type is fixed when the event is created. Each event type documents
|
||||||
|
* which options are valid and which options are required by gesture operations.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef enum GHOSTTY_ENUM_TYPED {
|
||||||
|
/** Press event for ghostty_selection_gesture_event(). */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_PRESS = 0,
|
||||||
|
|
||||||
|
/** Release event for ghostty_selection_gesture_event(). */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_RELEASE = 1,
|
||||||
|
|
||||||
|
/** Drag event for ghostty_selection_gesture_event(). */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DRAG = 2,
|
||||||
|
|
||||||
|
/** Autoscroll tick event for ghostty_selection_gesture_event(). */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_AUTOSCROLL_TICK = 3,
|
||||||
|
|
||||||
|
/** Deep press event for ghostty_selection_gesture_event(). */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DEEP_PRESS = 4,
|
||||||
|
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||||
|
} GhosttySelectionGestureEventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options stored on a reusable selection gesture event.
|
||||||
|
*
|
||||||
|
* Passing NULL as the value to ghostty_selection_gesture_event_set() clears the
|
||||||
|
* corresponding option.
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
typedef enum GHOSTTY_ENUM_TYPED {
|
||||||
|
/**
|
||||||
|
* Grid reference under the pointer: GhosttyGridRef*.
|
||||||
|
*
|
||||||
|
* Required for PRESS and DRAG events. Optional for RELEASE events; when unset
|
||||||
|
* or cleared, release records that the pointer did not map to a valid cell.
|
||||||
|
*/
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Surface-space pointer position: GhosttySurfacePosition*.
|
||||||
|
*
|
||||||
|
* Valid for PRESS, DRAG, and AUTOSCROLL_TICK.
|
||||||
|
*/
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_POSITION = 1,
|
||||||
|
|
||||||
|
/** Maximum repeat-click distance in pixels: double*. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REPEAT_DISTANCE = 2,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional monotonic event time in nanoseconds: uint64_t*.
|
||||||
|
*
|
||||||
|
* If unset, press treats the event as untimed and only single-click behavior
|
||||||
|
* is available.
|
||||||
|
*/
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_TIME_NS = 3,
|
||||||
|
|
||||||
|
/** Maximum interval between repeat clicks in nanoseconds: uint64_t*. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REPEAT_INTERVAL_NS = 4,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Word-boundary codepoints: GhosttyCodepoints*.
|
||||||
|
*
|
||||||
|
* The codepoints are copied into event-owned storage when set. If unset,
|
||||||
|
* operations that need word boundaries use Ghostty's defaults.
|
||||||
|
*
|
||||||
|
* Valid for PRESS, DRAG, AUTOSCROLL_TICK, and DEEP_PRESS.
|
||||||
|
*/
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_WORD_BOUNDARY_CODEPOINTS = 5,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selection behavior table: GhosttySelectionGestureBehaviors*.
|
||||||
|
*
|
||||||
|
* If unset, press uses the default behavior table: cell, word, line.
|
||||||
|
*/
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_BEHAVIORS = 6,
|
||||||
|
|
||||||
|
/** Whether a drag or autoscroll tick should produce a rectangular selection: bool*. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_RECTANGLE = 7,
|
||||||
|
|
||||||
|
/** Drag display geometry: GhosttySelectionGestureGeometry*. Required for DRAG and AUTOSCROLL_TICK. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY = 8,
|
||||||
|
|
||||||
|
/** Viewport coordinate for an autoscroll tick: GhosttyPointCoordinate*. Required for AUTOSCROLL_TICK. */
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_VIEWPORT = 9,
|
||||||
|
|
||||||
|
GHOSTTY_SELECTION_GESTURE_EVENT_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
|
||||||
|
} GhosttySelectionGestureEventOption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a reusable selection gesture event object.
|
||||||
|
*
|
||||||
|
* @param allocator Allocator, or NULL for the default allocator
|
||||||
|
* @param out_event Receives the created event handle
|
||||||
|
* @param type Event type. This is fixed for the lifetime of the event.
|
||||||
|
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if out_event is
|
||||||
|
* NULL or type is invalid, or GHOSTTY_OUT_OF_MEMORY if allocation fails
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API GhosttyResult ghostty_selection_gesture_event_new(
|
||||||
|
const GhosttyAllocator* allocator,
|
||||||
|
GhosttySelectionGestureEvent* out_event,
|
||||||
|
GhosttySelectionGestureEventType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a selection gesture event object.
|
||||||
|
*
|
||||||
|
* Passing NULL is allowed and is a no-op.
|
||||||
|
*
|
||||||
|
* @param event Selection gesture event handle to free
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API void ghostty_selection_gesture_event_free(
|
||||||
|
GhosttySelectionGestureEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set or clear an option on a selection gesture event.
|
||||||
|
*
|
||||||
|
* The value type depends on option and is documented by
|
||||||
|
* GhosttySelectionGestureEventOption. Passing NULL for value clears the option.
|
||||||
|
*
|
||||||
|
* @param event Selection gesture event handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||||
|
* @param option Event option to set or clear
|
||||||
|
* @param value Pointer to the input value for option, or NULL to clear
|
||||||
|
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY if copying
|
||||||
|
* event-owned data fails, or GHOSTTY_INVALID_VALUE if event, option, or
|
||||||
|
* value is invalid
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API GhosttyResult ghostty_selection_gesture_event_set(
|
||||||
|
GhosttySelectionGestureEvent event,
|
||||||
|
GhosttySelectionGestureEventOption option,
|
||||||
|
const void* value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a selection gesture event and return the resulting selection snapshot.
|
||||||
|
*
|
||||||
|
* This dispatches to the gesture operation matching the event's fixed type.
|
||||||
|
* For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_PRESS, the event must have
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF set before calling this function.
|
||||||
|
* All other press options use their initialized defaults when unset or cleared.
|
||||||
|
*
|
||||||
|
* For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_RELEASE, only
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF is valid. It is optional; if unset or
|
||||||
|
* cleared, release records that the pointer did not map to a valid cell. Release
|
||||||
|
* events update gesture state but do not produce a selection, so this function
|
||||||
|
* returns GHOSTTY_NO_VALUE after applying them.
|
||||||
|
*
|
||||||
|
* For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DRAG,
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_REF and
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY are required. Position,
|
||||||
|
* rectangle, and word-boundary codepoints are optional and use initialized
|
||||||
|
* defaults when unset or cleared.
|
||||||
|
*
|
||||||
|
* For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_AUTOSCROLL_TICK,
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_VIEWPORT and
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_GEOMETRY are required. Position,
|
||||||
|
* rectangle, and word-boundary codepoints are optional and use initialized
|
||||||
|
* defaults when unset or cleared.
|
||||||
|
*
|
||||||
|
* For GHOSTTY_SELECTION_GESTURE_EVENT_TYPE_DEEP_PRESS, only
|
||||||
|
* GHOSTTY_SELECTION_GESTURE_EVENT_OPT_WORD_BOUNDARY_CODEPOINTS is valid. It is
|
||||||
|
* optional and uses initialized defaults when unset or cleared.
|
||||||
|
*
|
||||||
|
* The returned selection is not installed as the terminal's current selection.
|
||||||
|
* It is a snapshot with the same lifetime rules as GhosttySelection.
|
||||||
|
*
|
||||||
|
* @param gesture Selection gesture handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||||
|
* @param terminal Terminal used to interpret and update gesture state
|
||||||
|
* @param event Selection gesture event handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||||
|
* @param[out] out_selection On success, receives the resulting selection. May
|
||||||
|
* be NULL to apply the event and discard the selection result.
|
||||||
|
* @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the event does not
|
||||||
|
* currently produce a selection, GHOSTTY_OUT_OF_MEMORY if tracking
|
||||||
|
* gesture state fails, or GHOSTTY_INVALID_VALUE if gesture, terminal,
|
||||||
|
* event, or required event data is invalid
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API GhosttyResult ghostty_selection_gesture_event(
|
||||||
|
GhosttySelectionGesture gesture,
|
||||||
|
GhosttyTerminal terminal,
|
||||||
|
GhosttySelectionGestureEvent event,
|
||||||
|
GhosttySelection* out_selection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a selection gesture object.
|
||||||
|
*
|
||||||
|
* The gesture stores mutable state for terminal text selection gestures. The
|
||||||
|
* gesture is not bound to a terminal at creation time; terminal-dependent APIs
|
||||||
|
* take the terminal explicitly.
|
||||||
|
*
|
||||||
|
* @param allocator Allocator, or NULL for the default allocator
|
||||||
|
* @param out_gesture Receives the created gesture handle
|
||||||
|
* @return GHOSTTY_SUCCESS on success, GHOSTTY_INVALID_VALUE if out_gesture is
|
||||||
|
* NULL, or GHOSTTY_OUT_OF_MEMORY if allocation fails
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API GhosttyResult ghostty_selection_gesture_new(
|
||||||
|
const GhosttyAllocator* allocator,
|
||||||
|
GhosttySelectionGesture* out_gesture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a selection gesture object.
|
||||||
|
*
|
||||||
|
* This releases any tracked terminal references owned by the gesture using the
|
||||||
|
* provided terminal, then frees the gesture object. Passing NULL for gesture is
|
||||||
|
* allowed and is a no-op.
|
||||||
|
*
|
||||||
|
* If the terminal is still alive, pass the terminal most recently used with the
|
||||||
|
* gesture so any tracked terminal references can be released correctly. If the
|
||||||
|
* terminal has already been freed, pass NULL for terminal; the terminal's page
|
||||||
|
* storage has already released the underlying tracked references, so the
|
||||||
|
* gesture wrapper can be safely discarded without touching the stale terminal
|
||||||
|
* state.
|
||||||
|
*
|
||||||
|
* @param gesture Selection gesture handle to free
|
||||||
|
* @param terminal Terminal used to release tracked gesture state, or NULL if
|
||||||
|
* the terminal has already been freed
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API void ghostty_selection_gesture_free(
|
||||||
|
GhosttySelectionGesture gesture,
|
||||||
|
GhosttyTerminal terminal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset any active selection gesture state.
|
||||||
|
*
|
||||||
|
* This cancels the active click sequence and releases any tracked terminal
|
||||||
|
* references owned by the gesture without freeing the gesture object.
|
||||||
|
* Passing NULL is allowed and is a no-op.
|
||||||
|
*
|
||||||
|
* @param gesture Selection gesture handle to reset
|
||||||
|
* @param terminal Terminal used to release tracked gesture state
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API void ghostty_selection_gesture_reset(
|
||||||
|
GhosttySelectionGesture gesture,
|
||||||
|
GhosttyTerminal terminal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read data from a selection gesture.
|
||||||
|
*
|
||||||
|
* The type of value depends on data and is documented by
|
||||||
|
* GhosttySelectionGestureData. For GHOSTTY_SELECTION_GESTURE_DATA_ANCHOR,
|
||||||
|
* the returned GhosttyGridRef is an untracked snapshot with normal grid-ref
|
||||||
|
* lifetime rules.
|
||||||
|
*
|
||||||
|
* @param gesture Selection gesture handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||||
|
* @param terminal Terminal used to validate terminal-backed gesture state
|
||||||
|
* @param data Data field to read
|
||||||
|
* @param value Output pointer whose type depends on data
|
||||||
|
* @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if the requested data
|
||||||
|
* has no value, or GHOSTTY_INVALID_VALUE if gesture, terminal, data, or
|
||||||
|
* value is invalid
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API GhosttyResult ghostty_selection_gesture_get(
|
||||||
|
GhosttySelectionGesture gesture,
|
||||||
|
GhosttyTerminal terminal,
|
||||||
|
GhosttySelectionGestureData data,
|
||||||
|
void* value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read multiple data fields from a selection gesture in a single call.
|
||||||
|
*
|
||||||
|
* This is an optimization over calling ghostty_selection_gesture_get() multiple
|
||||||
|
* times. Each entry in values must point to storage of the type documented by
|
||||||
|
* the corresponding GhosttySelectionGestureData key.
|
||||||
|
*
|
||||||
|
* If any individual read fails, the function returns that error and writes the
|
||||||
|
* index of the failing key to out_written when out_written is non-NULL. On
|
||||||
|
* success, out_written receives count when non-NULL.
|
||||||
|
*
|
||||||
|
* @param gesture Selection gesture handle (NULL returns GHOSTTY_INVALID_VALUE)
|
||||||
|
* @param terminal Terminal used to validate terminal-backed gesture state
|
||||||
|
* @param count Number of data fields to read
|
||||||
|
* @param keys Data fields to read (must not be NULL)
|
||||||
|
* @param values Output pointers corresponding to keys (must not be NULL)
|
||||||
|
* @param out_written Optional number of fields read, or failing index on error
|
||||||
|
* @return GHOSTTY_SUCCESS on success, GHOSTTY_NO_VALUE if a requested data
|
||||||
|
* field has no value, or GHOSTTY_INVALID_VALUE if gesture, terminal,
|
||||||
|
* keys, values, or a value pointer is invalid
|
||||||
|
*
|
||||||
|
* @ingroup selection
|
||||||
|
*/
|
||||||
|
GHOSTTY_API GhosttyResult ghostty_selection_gesture_get_multi(
|
||||||
|
GhosttySelectionGesture gesture,
|
||||||
|
GhosttyTerminal terminal,
|
||||||
|
size_t count,
|
||||||
|
const GhosttySelectionGestureData* keys,
|
||||||
|
void** values,
|
||||||
|
size_t* out_written);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derive a word selection snapshot from a terminal grid reference.
|
* Derive a word selection snapshot from a terminal grid reference.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,38 @@ typedef struct {
|
||||||
size_t len;
|
size_t len;
|
||||||
} GhosttyString;
|
} GhosttyString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A surface-space position in pixels.
|
||||||
|
*
|
||||||
|
* This is not a terminal grid coordinate. It represents an x/y position in the
|
||||||
|
* rendered surface coordinate space, with (0, 0) at the top-left of the
|
||||||
|
* surface.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** X position in surface pixels. */
|
||||||
|
double x;
|
||||||
|
|
||||||
|
/** Y position in surface pixels. */
|
||||||
|
double y;
|
||||||
|
} GhosttySurfacePosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A borrowed list of Unicode scalar values.
|
||||||
|
*
|
||||||
|
* Values are encoded as uint32_t scalar values. The memory is not owned by this
|
||||||
|
* struct. The pointer is only valid for the lifetime documented by the API that
|
||||||
|
* consumes or produces it.
|
||||||
|
*
|
||||||
|
* APIs may document special handling for NULL + len 0, such as “use defaults”.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** Pointer to Unicode scalar values. */
|
||||||
|
const uint32_t* ptr;
|
||||||
|
|
||||||
|
/** Number of entries in ptr. */
|
||||||
|
size_t len;
|
||||||
|
} GhosttyCodepoints;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a sized struct to zero and set its size field.
|
* Initialize a sized struct to zero and set its size field.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,15 @@ comptime {
|
||||||
@export(&c.terminal_selection_ordered, .{ .name = "ghostty_terminal_selection_ordered" });
|
@export(&c.terminal_selection_ordered, .{ .name = "ghostty_terminal_selection_ordered" });
|
||||||
@export(&c.terminal_selection_contains, .{ .name = "ghostty_terminal_selection_contains" });
|
@export(&c.terminal_selection_contains, .{ .name = "ghostty_terminal_selection_contains" });
|
||||||
@export(&c.terminal_selection_equal, .{ .name = "ghostty_terminal_selection_equal" });
|
@export(&c.terminal_selection_equal, .{ .name = "ghostty_terminal_selection_equal" });
|
||||||
|
@export(&c.selection_gesture_new, .{ .name = "ghostty_selection_gesture_new" });
|
||||||
|
@export(&c.selection_gesture_free, .{ .name = "ghostty_selection_gesture_free" });
|
||||||
|
@export(&c.selection_gesture_reset, .{ .name = "ghostty_selection_gesture_reset" });
|
||||||
|
@export(&c.selection_gesture_event, .{ .name = "ghostty_selection_gesture_event" });
|
||||||
|
@export(&c.selection_gesture_get, .{ .name = "ghostty_selection_gesture_get" });
|
||||||
|
@export(&c.selection_gesture_get_multi, .{ .name = "ghostty_selection_gesture_get_multi" });
|
||||||
|
@export(&c.selection_gesture_event_new, .{ .name = "ghostty_selection_gesture_event_new" });
|
||||||
|
@export(&c.selection_gesture_event_free, .{ .name = "ghostty_selection_gesture_event_free" });
|
||||||
|
@export(&c.selection_gesture_event_set, .{ .name = "ghostty_selection_gesture_event_set" });
|
||||||
@export(&c.terminal_grid_ref, .{ .name = "ghostty_terminal_grid_ref" });
|
@export(&c.terminal_grid_ref, .{ .name = "ghostty_terminal_grid_ref" });
|
||||||
@export(&c.terminal_grid_ref_track, .{ .name = "ghostty_terminal_grid_ref_track" });
|
@export(&c.terminal_grid_ref_track, .{ .name = "ghostty_terminal_grid_ref_track" });
|
||||||
@export(&c.terminal_point_from_grid_ref, .{ .name = "ghostty_terminal_point_from_grid_ref" });
|
@export(&c.terminal_point_from_grid_ref, .{ .name = "ghostty_terminal_point_from_grid_ref" });
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const lib = @import("lib.zig");
|
||||||
const PageList = @import("PageList.zig");
|
const PageList = @import("PageList.zig");
|
||||||
const Pin = PageList.Pin;
|
const Pin = PageList.Pin;
|
||||||
const Screen = @import("Screen.zig");
|
const Screen = @import("Screen.zig");
|
||||||
|
|
@ -118,22 +119,26 @@ left_drag_autoscroll: Autoscroll,
|
||||||
///
|
///
|
||||||
/// This is used to implement selection above/below the viewport that
|
/// This is used to implement selection above/below the viewport that
|
||||||
/// wants to drag the viewport.
|
/// wants to drag the viewport.
|
||||||
pub const Autoscroll = enum { none, up, down };
|
pub const Autoscroll = lib.Enum(lib.target, &.{
|
||||||
|
"none",
|
||||||
|
"up",
|
||||||
|
"down",
|
||||||
|
});
|
||||||
|
|
||||||
/// The selection behavior for a click and subsequent drag.
|
/// The selection behavior for a click and subsequent drag.
|
||||||
pub const Behavior = enum {
|
pub const Behavior = lib.Enum(lib.target, &.{
|
||||||
/// Cell-granular drag selection. Press returns null to clear selection.
|
// Cell-granular drag selection. Press returns null to clear selection.
|
||||||
cell,
|
"cell",
|
||||||
|
|
||||||
/// Word selection on press and word-granular drag selection.
|
// Word selection on press and word-granular drag selection.
|
||||||
word,
|
"word",
|
||||||
|
|
||||||
/// Line selection on press and line-granular drag selection.
|
// Line selection on press and line-granular drag selection.
|
||||||
line,
|
"line",
|
||||||
|
|
||||||
/// Semantic command output selection on press and drag.
|
// Semantic command output selection on press and drag.
|
||||||
output,
|
"output",
|
||||||
};
|
});
|
||||||
|
|
||||||
/// Standard terminal selection behavior for single-, double-, and triple-clicks.
|
/// Standard terminal selection behavior for single-, double-, and triple-clicks.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ pub const modes = @import("modes.zig");
|
||||||
pub const osc = @import("osc.zig");
|
pub const osc = @import("osc.zig");
|
||||||
pub const render = @import("render.zig");
|
pub const render = @import("render.zig");
|
||||||
pub const selection = @import("selection.zig");
|
pub const selection = @import("selection.zig");
|
||||||
|
pub const selection_gesture = @import("selection_gesture.zig");
|
||||||
pub const key_event = @import("key_event.zig");
|
pub const key_event = @import("key_event.zig");
|
||||||
pub const key_encode = @import("key_encode.zig");
|
pub const key_encode = @import("key_encode.zig");
|
||||||
pub const mouse_event = @import("mouse_event.zig");
|
pub const mouse_event = @import("mouse_event.zig");
|
||||||
|
|
@ -182,6 +183,15 @@ pub const terminal_selection_order = selection.order;
|
||||||
pub const terminal_selection_ordered = selection.ordered;
|
pub const terminal_selection_ordered = selection.ordered;
|
||||||
pub const terminal_selection_contains = selection.contains;
|
pub const terminal_selection_contains = selection.contains;
|
||||||
pub const terminal_selection_equal = selection.equal;
|
pub const terminal_selection_equal = selection.equal;
|
||||||
|
pub const selection_gesture_new = selection_gesture.new;
|
||||||
|
pub const selection_gesture_free = selection_gesture.free;
|
||||||
|
pub const selection_gesture_reset = selection_gesture.reset;
|
||||||
|
pub const selection_gesture_event = selection_gesture.handle_event;
|
||||||
|
pub const selection_gesture_get = selection_gesture.get;
|
||||||
|
pub const selection_gesture_get_multi = selection_gesture.get_multi;
|
||||||
|
pub const selection_gesture_event_new = selection_gesture.event_new;
|
||||||
|
pub const selection_gesture_event_free = selection_gesture.event_free;
|
||||||
|
pub const selection_gesture_event_set = selection_gesture.event_set;
|
||||||
pub const terminal_grid_ref = terminal.grid_ref;
|
pub const terminal_grid_ref = terminal.grid_ref;
|
||||||
pub const terminal_grid_ref_track = terminal.grid_ref_track;
|
pub const terminal_grid_ref_track = terminal.grid_ref_track;
|
||||||
pub const terminal_point_from_grid_ref = terminal.point_from_grid_ref;
|
pub const terminal_point_from_grid_ref = terminal.point_from_grid_ref;
|
||||||
|
|
@ -214,6 +224,7 @@ test {
|
||||||
_ = osc;
|
_ = osc;
|
||||||
_ = render;
|
_ = render;
|
||||||
_ = selection;
|
_ = selection;
|
||||||
|
_ = selection_gesture;
|
||||||
_ = key_event;
|
_ = key_event;
|
||||||
_ = key_encode;
|
_ = key_encode;
|
||||||
_ = mouse_event;
|
_ = mouse_event;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -14,15 +14,29 @@ const size_report = @import("size_report.zig");
|
||||||
const terminal = @import("terminal.zig");
|
const terminal = @import("terminal.zig");
|
||||||
const formatter = @import("formatter.zig");
|
const formatter = @import("formatter.zig");
|
||||||
const selection = @import("selection.zig");
|
const selection = @import("selection.zig");
|
||||||
|
const selection_gesture = @import("selection_gesture.zig");
|
||||||
const render = @import("render.zig");
|
const render = @import("render.zig");
|
||||||
const style_c = @import("style.zig");
|
const style_c = @import("style.zig");
|
||||||
const mouse_encode = @import("mouse_encode.zig");
|
const mouse_encode = @import("mouse_encode.zig");
|
||||||
const grid_ref = @import("grid_ref.zig");
|
const grid_ref = @import("grid_ref.zig");
|
||||||
|
|
||||||
|
/// C: GhosttySurfacePosition
|
||||||
|
pub const SurfacePosition = extern struct {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// C: GhosttyCodepoints
|
||||||
|
pub const Codepoints = extern struct {
|
||||||
|
ptr: ?[*]const u32 = null,
|
||||||
|
len: usize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/// All C API structs and their Ghostty C names.
|
/// All C API structs and their Ghostty C names.
|
||||||
pub const structs: std.StaticStringMap(StructInfo) = structs: {
|
pub const structs: std.StaticStringMap(StructInfo) = structs: {
|
||||||
@setEvalBranchQuota(10_000);
|
@setEvalBranchQuota(10_000);
|
||||||
break :structs .initComptime(.{
|
break :structs .initComptime(.{
|
||||||
|
.{ "GhosttyCodepoints", StructInfo.init(Codepoints) },
|
||||||
.{ "GhosttyColorRgb", StructInfo.init(color.RGB.C) },
|
.{ "GhosttyColorRgb", StructInfo.init(color.RGB.C) },
|
||||||
.{ "GhosttyDeviceAttributes", StructInfo.init(terminal.DeviceAttributes) },
|
.{ "GhosttyDeviceAttributes", StructInfo.init(terminal.DeviceAttributes) },
|
||||||
.{ "GhosttyDeviceAttributesPrimary", StructInfo.init(terminal.DeviceAttributes.Primary) },
|
.{ "GhosttyDeviceAttributesPrimary", StructInfo.init(terminal.DeviceAttributes.Primary) },
|
||||||
|
|
@ -41,8 +55,11 @@ pub const structs: std.StaticStringMap(StructInfo) = structs: {
|
||||||
.{ "GhosttyPoint", StructInfo.init(point.Point.C) },
|
.{ "GhosttyPoint", StructInfo.init(point.Point.C) },
|
||||||
.{ "GhosttyPointCoordinate", StructInfo.init(point.Coordinate) },
|
.{ "GhosttyPointCoordinate", StructInfo.init(point.Coordinate) },
|
||||||
.{ "GhosttyRenderStateColors", StructInfo.init(render.Colors) },
|
.{ "GhosttyRenderStateColors", StructInfo.init(render.Colors) },
|
||||||
|
.{ "GhosttySelectionGestureBehaviors", StructInfo.init(selection_gesture.Behaviors) },
|
||||||
|
.{ "GhosttySelectionGestureGeometry", StructInfo.init(selection_gesture.Geometry) },
|
||||||
.{ "GhosttySizeReportSize", StructInfo.init(size_report.Size) },
|
.{ "GhosttySizeReportSize", StructInfo.init(size_report.Size) },
|
||||||
.{ "GhosttyString", StructInfo.init(lib.String) },
|
.{ "GhosttyString", StructInfo.init(lib.String) },
|
||||||
|
.{ "GhosttySurfacePosition", StructInfo.init(SurfacePosition) },
|
||||||
.{ "GhosttyStyle", StructInfo.init(style_c.Style) },
|
.{ "GhosttyStyle", StructInfo.init(style_c.Style) },
|
||||||
.{ "GhosttyStyleColor", StructInfo.init(style_c.Color) },
|
.{ "GhosttyStyleColor", StructInfo.init(style_c.Color) },
|
||||||
.{ "GhosttyTerminalOptions", StructInfo.init(terminal.Options) },
|
.{ "GhosttyTerminalOptions", StructInfo.init(terminal.Options) },
|
||||||
|
|
@ -150,6 +167,11 @@ fn jsonWriteAll(writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
||||||
fn typeName(comptime T: type) []const u8 {
|
fn typeName(comptime T: type) []const u8 {
|
||||||
return switch (@typeInfo(T)) {
|
return switch (@typeInfo(T)) {
|
||||||
.bool => "bool",
|
.bool => "bool",
|
||||||
|
.float => |info| switch (info.bits) {
|
||||||
|
32 => "f32",
|
||||||
|
64 => "f64",
|
||||||
|
else => @compileError("unsupported float size"),
|
||||||
|
},
|
||||||
.int => |info| switch (info.signedness) {
|
.int => |info| switch (info.signedness) {
|
||||||
.signed => switch (info.bits) {
|
.signed => switch (info.bits) {
|
||||||
8 => "i8",
|
8 => "i8",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue