Expose semantic prompt state through libghostty-vt (#13767)

## Summary

- Add `GHOSTTY_TERMINAL_DATA_CURSOR_AT_PROMPT` to expose semantic prompt
state through `libghostty-vt`.
- Reuse `Terminal.cursorIsAtPrompt()` rather than introducing separate
prompt tracking.

## Motivation

Ghostty already tracks whether the cursor is at a semantic prompt
through `Terminal.cursorIsAtPrompt()`. Exposing this query through
`libghostty-vt` lets downstream terminal consumers use Ghostty's
existing semantic prompt state without introducing separate tracking.

The query returns false when semantic prompt information is unavailable
or the alternate screen is active.

Discussed in https://github.com/ghostty-org/ghostty/discussions/13755.

## Testing

- `zig build test-lib-vt`
- `zig build test-lib-vt -Dtest-filter="get cursor_at_prompt"`
- `zig build -Demit-lib-vt`

## AI disclosure

Codex assisted with adding the `libghostty-vt` query and test,
addressing review feedback, running validation, and drafting this
description. I reviewed and edited the final code and description,
reviewed the validation results, and understand how the change interacts
with Ghostty's semantic prompt state.
This commit is contained in:
Mitchell Hashimoto
2026-08-12 14:11:26 -07:00
committed by GitHub
2 changed files with 39 additions and 0 deletions

View File

@@ -1613,6 +1613,17 @@ typedef enum GHOSTTY_ENUM_TYPED {
* Output type: bool *
*/
GHOSTTY_TERMINAL_DATA_VT_GROUND = 38,
/**
* Whether the cursor is currently at a semantic shell prompt or input area.
*
* This depends on semantic prompt markers such as OSC 133. Returns false
* when semantic prompt information is unavailable or the alternate screen
* is active.
*
* Output type: bool *
*/
GHOSTTY_TERMINAL_DATA_CURSOR_AT_PROMPT = 39,
GHOSTTY_TERMINAL_DATA_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyTerminalData;

View File

@@ -1355,6 +1355,7 @@ pub const TerminalData = enum(c_int) {
continuation_max_bytes = 36,
mode = 37,
vt_ground = 38,
cursor_at_prompt = 39,
/// Output type expected for querying the data of the given kind.
pub fn OutType(comptime self: TerminalData) type {
@@ -1367,6 +1368,7 @@ pub const TerminalData = enum(c_int) {
.viewport_active,
.vt_processing_error,
.vt_ground,
.cursor_at_prompt,
=> bool,
.active_screen => TerminalScreen,
.kitty_keyboard_flags => u8,
@@ -1533,6 +1535,7 @@ fn getTyped(
const mode = out.toMode() orelse return .invalid_value;
out.value = t.modes.get(mode);
},
.cursor_at_prompt => out.* = t.cursorIsAtPrompt(),
}
return .success;
@@ -2864,6 +2867,31 @@ test "get cursor_visible" {
try testing.expect(!visible);
}
test "get cursor_at_prompt" {
var t: Terminal = null;
try testing.expectEqual(Result.success, new(
&lib.alloc.test_allocator,
&t,
80,
24,
));
defer free(t);
var at_prompt: bool = undefined;
try testing.expectEqual(Result.success, get(t, .cursor_at_prompt, @ptrCast(&at_prompt)));
try testing.expect(!at_prompt);
const prompt_start = "\x1b]133;A\x07";
vt_write(t, prompt_start, prompt_start.len);
try testing.expectEqual(Result.success, get(t, .cursor_at_prompt, @ptrCast(&at_prompt)));
try testing.expect(at_prompt);
const alternate_screen = "\x1b[?1049h";
vt_write(t, alternate_screen, alternate_screen.len);
try testing.expectEqual(Result.success, get(t, .cursor_at_prompt, @ptrCast(&at_prompt)));
try testing.expect(!at_prompt);
}
test "get active_screen" {
var t: Terminal = null;
try testing.expectEqual(Result.success, new(