terminal: set semantic_prompt.click based on OSC133A options

This commit is contained in:
Mitchell Hashimoto
2026-02-02 09:26:38 -08:00
parent e9b6fea11c
commit b827e587d9

View File

@@ -1087,9 +1087,11 @@ pub fn semanticPrompt(
// "First do a fresh-line."
try self.semanticPromptFreshLine();
const screen: *Screen = self.screens.active;
// "Subsequent text (until a OSC "133;B" or OSC "133;I" command)
// is a prompt string (as if followed by OSC 133;P;k=i\007)."
self.screens.active.cursorSetSemanticContent(.{
screen.cursorSetSemanticContent(.{
.prompt = cmd.readOption(.prompt_kind) orelse .initial,
});
@@ -1100,6 +1102,24 @@ pub fn semanticPrompt(
self.flags.shell_redraws_prompt = v;
}
click: {
// Handle click_events as a priority over cl. click_events
// is another Kitty-specific extension that converts clicks
// within a prompt area to SGR mouse events and defers to the
// shell to handle them.
if (cmd.readOption(.click_events)) |v| {
if (v) {
screen.semantic_prompt.click = .click_events;
break :click;
}
}
// If click_events was not set or disabled, fallback to `cl`.
if (cmd.readOption(.cl)) |v| {
screen.semantic_prompt.click = .{ .cl = v };
}
}
// The "aid" and "cl" options are also valid for this
// command but we don't yet handle these in any meaningful way.
},
@@ -11635,6 +11655,109 @@ test "Terminal: multiple newlines in prompt mode marks all rows" {
}
}
test "Terminal: OSC133A click_events=1 sets click to click_events" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
// Verify default state is none
try testing.expectEqual(.none, t.screens.active.semantic_prompt.click);
// OSC 133;A with click_events=1
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "click_events=1",
});
try testing.expectEqual(.click_events, t.screens.active.semantic_prompt.click);
}
test "Terminal: OSC133A click_events=0 does not set click_events" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
// OSC 133;A with click_events=0
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "click_events=0",
});
// Should remain none since click_events=0 doesn't activate anything
try testing.expectEqual(.none, t.screens.active.semantic_prompt.click);
}
test "Terminal: OSC133A cl option sets click to cl value" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
// OSC 133;A with cl=m (multiple)
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "cl=m",
});
try testing.expectEqual(Screen.SemanticPrompt.SemanticClick{ .cl = .multiple }, t.screens.active.semantic_prompt.click);
}
test "Terminal: OSC133A cl=line sets click to line" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "cl=line",
});
try testing.expectEqual(Screen.SemanticPrompt.SemanticClick{ .cl = .line }, t.screens.active.semantic_prompt.click);
}
test "Terminal: OSC133A click_events=1 takes priority over cl" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
// OSC 133;A with both click_events=1 and cl=m
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "click_events=1;cl=m",
});
// click_events should take priority
try testing.expectEqual(.click_events, t.screens.active.semantic_prompt.click);
}
test "Terminal: OSC133A click_events=0 falls back to cl" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
// OSC 133;A with click_events=0 and cl=v
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "click_events=0;cl=v",
});
// Should fall back to cl since click_events is disabled
try testing.expectEqual(Screen.SemanticPrompt.SemanticClick{ .cl = .conservative_vertical }, t.screens.active.semantic_prompt.click);
}
test "Terminal: OSC133A no click options leaves click as none" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 5 });
defer t.deinit(alloc);
// OSC 133;A with no click-related options
try t.semanticPrompt(.{
.action = .fresh_line_new_prompt,
.options_unvalidated = "aid=123",
});
try testing.expectEqual(.none, t.screens.active.semantic_prompt.click);
}
test "Terminal: cursorIsAtPrompt" {
const alloc = testing.allocator;
var t = try init(alloc, .{ .cols = 10, .rows = 3 });