mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal: parse and handle set modify key format (ESC[>{a};{b}m)
This commit is contained in:
@ -1115,6 +1115,7 @@ pub fn keyCallback(
|
||||
self.renderer_state.mutex.lock();
|
||||
const cursor_key_application = self.io.terminal.modes.cursor_keys;
|
||||
const keypad_key_application = self.io.terminal.modes.keypad_keys;
|
||||
const modify_other_keys = self.io.terminal.modes.modify_other_keys;
|
||||
self.renderer_state.mutex.unlock();
|
||||
|
||||
// Check if we're processing a function key.
|
||||
@ -1133,10 +1134,8 @@ pub fn keyCallback(
|
||||
|
||||
switch (entry.modify_other_keys) {
|
||||
.any => {},
|
||||
|
||||
// TODO
|
||||
.set => {},
|
||||
.set_other => continue,
|
||||
.set => if (modify_other_keys) continue,
|
||||
.set_other => if (!modify_other_keys) continue,
|
||||
}
|
||||
|
||||
const mods_int: u8 = @bitCast(binding_mods);
|
||||
|
@ -99,6 +99,10 @@ modes: packed struct {
|
||||
|
||||
bracketed_paste: bool = false, // 2004
|
||||
|
||||
// This is set via ESC[4;2m. Any other modify key mode just sets
|
||||
// this to false.
|
||||
modify_other_keys: bool = false,
|
||||
|
||||
// This isn't a mode, this is set by OSC 133 using the "A" event.
|
||||
// If this is true, it tells us that the shell supports redrawing
|
||||
// the prompt and that when we resize, if the cursor is at a prompt,
|
||||
|
@ -192,3 +192,12 @@ pub const StatusDisplay = enum(u16) {
|
||||
// Non-exhaustive so that @intToEnum never fails for unsupported values.
|
||||
_,
|
||||
};
|
||||
|
||||
/// The possible modify key formats to ESC[>{a};{b}m
|
||||
/// Note: this is not complete, we should add more as we support more
|
||||
pub const ModifyKeyFormat = union(enum) {
|
||||
legacy: void,
|
||||
cursor_keys: void,
|
||||
function_keys: void,
|
||||
other_keys: enum { none, numeric_except, numeric },
|
||||
};
|
||||
|
@ -21,6 +21,7 @@ pub const CursorStyle = ansi.CursorStyle;
|
||||
pub const DeviceAttributeReq = ansi.DeviceAttributeReq;
|
||||
pub const DeviceStatusReq = ansi.DeviceStatusReq;
|
||||
pub const Mode = ansi.Mode;
|
||||
pub const ModifyKeyFormat = ansi.ModifyKeyFormat;
|
||||
pub const StatusLineType = ansi.StatusLineType;
|
||||
pub const StatusDisplay = ansi.StatusDisplay;
|
||||
pub const EraseDisplay = csi.EraseDisplay;
|
||||
|
@ -437,25 +437,75 @@ pub fn Stream(comptime Handler: type) type {
|
||||
} else log.warn("unimplemented CSI callback: {}", .{action}),
|
||||
|
||||
// SGR - Select Graphic Rendition
|
||||
'm' => if (action.intermediates.len == 0) {
|
||||
if (@hasDecl(T, "setAttribute")) {
|
||||
'm' => switch (action.intermediates.len) {
|
||||
0 => if (@hasDecl(T, "setAttribute")) {
|
||||
var p: sgr.Parser = .{ .params = action.params, .colon = action.sep == .colon };
|
||||
while (p.next()) |attr| {
|
||||
// log.info("SGR attribute: {}", .{attr});
|
||||
try self.handler.setAttribute(attr);
|
||||
}
|
||||
} else log.warn("unimplemented CSI callback: {}", .{action});
|
||||
} else {
|
||||
// Nothing, but I wanted a place to put this comment:
|
||||
// there are others forms of CSI m that have intermediates.
|
||||
// `vim --clean` uses `CSI ? 4 m` and I don't know what
|
||||
// that means. And there is also `CSI > m` which is used
|
||||
// to control modifier key reporting formats that we don't
|
||||
// support yet.
|
||||
log.debug(
|
||||
"ignoring unimplemented CSI m with intermediates: {s}",
|
||||
.{action.intermediates},
|
||||
);
|
||||
} else log.warn("unimplemented CSI callback: {}", .{action}),
|
||||
|
||||
1 => switch (action.intermediates[0]) {
|
||||
'>' => if (@hasDecl(T, "setModifyKeyFormat")) blk: {
|
||||
if (action.params.len == 0) {
|
||||
// Reset
|
||||
try self.handler.setModifyKeyFormat(.{ .legacy = {} });
|
||||
break :blk;
|
||||
}
|
||||
|
||||
var format: ansi.ModifyKeyFormat = switch (action.params[0]) {
|
||||
0 => .{ .legacy = {} },
|
||||
1 => .{ .cursor_keys = {} },
|
||||
2 => .{ .function_keys = {} },
|
||||
4 => .{ .other_keys = .none },
|
||||
else => {
|
||||
log.warn("invalid setModifyKeyFormat: {}", .{action});
|
||||
break :blk;
|
||||
},
|
||||
};
|
||||
|
||||
if (action.params.len > 2) {
|
||||
log.warn("invalid setModifyKeyFormat: {}", .{action});
|
||||
break :blk;
|
||||
}
|
||||
|
||||
if (action.params.len == 2) {
|
||||
switch (format) {
|
||||
// We don't support any of the subparams yet for these.
|
||||
.legacy => {},
|
||||
.cursor_keys => {},
|
||||
.function_keys => {},
|
||||
|
||||
// We only support the numeric form.
|
||||
.other_keys => |*v| switch (action.params[1]) {
|
||||
2 => v.* = .numeric,
|
||||
else => v.* = .none,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
try self.handler.setModifyKeyFormat(format);
|
||||
} else log.warn("unimplemented setModifyKeyFormat: {}", .{action}),
|
||||
|
||||
else => log.warn(
|
||||
"unknown CSI m with intermediate: {}",
|
||||
.{action.intermediates[0]},
|
||||
),
|
||||
},
|
||||
|
||||
else => {
|
||||
// Nothing, but I wanted a place to put this comment:
|
||||
// there are others forms of CSI m that have intermediates.
|
||||
// `vim --clean` uses `CSI ? 4 m` and I don't know what
|
||||
// that means. And there is also `CSI > m` which is used
|
||||
// to control modifier key reporting formats that we don't
|
||||
// support yet.
|
||||
log.warn(
|
||||
"ignoring unimplemented CSI m with intermediates: {s}",
|
||||
.{action.intermediates},
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
// CPR - Request Cursor Position Report
|
||||
|
@ -1183,6 +1183,17 @@ const StreamHandler = struct {
|
||||
self.terminal.setScrollingRegion(top, bot);
|
||||
}
|
||||
|
||||
pub fn setModifyKeyFormat(self: *StreamHandler, format: terminal.ModifyKeyFormat) !void {
|
||||
self.terminal.modes.modify_other_keys = false;
|
||||
switch (format) {
|
||||
.other_keys => |v| switch (v) {
|
||||
.numeric => self.terminal.modes.modify_other_keys = true,
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setMode(self: *StreamHandler, mode: terminal.Mode, enabled: bool) !void {
|
||||
// Note: this function doesn't need to grab the render state or
|
||||
// terminal locks because it is only called from process() which
|
||||
|
Reference in New Issue
Block a user