mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-25 16:41:44 +00:00
Expose semantic prompt state through C APIs
This commit is contained in:
@@ -1134,6 +1134,7 @@ GHOSTTY_API ghostty_app_t ghostty_surface_app(ghostty_surface_t);
|
||||
GHOSTTY_API ghostty_surface_config_s ghostty_surface_inherited_config(ghostty_surface_t, ghostty_surface_context_e);
|
||||
GHOSTTY_API void ghostty_surface_update_config(ghostty_surface_t, ghostty_config_t);
|
||||
GHOSTTY_API bool ghostty_surface_needs_confirm_quit(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_is_at_prompt(ghostty_surface_t);
|
||||
GHOSTTY_API bool ghostty_surface_process_exited(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_refresh(ghostty_surface_t);
|
||||
GHOSTTY_API void ghostty_surface_draw(ghostty_surface_t);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -967,6 +967,17 @@ pub fn needsConfirmQuit(self: *Surface) bool {
|
||||
};
|
||||
}
|
||||
|
||||
/// True if the surface cursor is currently at a shell prompt according to
|
||||
/// semantic prompt integration. If shell integration is unavailable, this
|
||||
/// conservatively returns false.
|
||||
pub fn isAtPrompt(self: *Surface) bool {
|
||||
if (self.child_exited) return false;
|
||||
|
||||
self.renderer_state.mutex.lockUncancelable(global.io());
|
||||
defer self.renderer_state.mutex.unlock(global.io());
|
||||
return self.io.terminal.cursorIsAtPrompt();
|
||||
}
|
||||
|
||||
/// Called from the app thread to handle mailbox messages to our specific
|
||||
/// surface.
|
||||
pub fn handleMessage(self: *Surface, msg: Message) !void {
|
||||
|
||||
@@ -1606,6 +1606,11 @@ pub const CAPI = struct {
|
||||
return surface.core_surface.needsConfirmQuit();
|
||||
}
|
||||
|
||||
/// Returns true if the surface cursor is currently at a semantic prompt.
|
||||
export fn ghostty_surface_is_at_prompt(surface: *Surface) bool {
|
||||
return surface.core_surface.isAtPrompt();
|
||||
}
|
||||
|
||||
/// Returns true if the surface process has exited.
|
||||
export fn ghostty_surface_process_exited(surface: *Surface) bool {
|
||||
return surface.core_surface.child_exited;
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user