diff --git a/src/terminal/modes.zig b/src/terminal/modes.zig index c92f97b083d..65782e7eb68 100644 --- a/src/terminal/modes.zig +++ b/src/terminal/modes.zig @@ -79,6 +79,19 @@ pub const ModeState = struct { /// Return a DECRPM report for the given mode tag. If the tag does /// not correspond to a known mode, the report state is .not_recognized. pub fn getReport(self: *const ModeState, tag: ModeTag) Report { + // DECECM (Erase Color Mode, DEC private mode 117) controls whether erasing + // and scrolling use the default background or the active background color. + // Ghostty's behavior is fixed equivalent to DECECM reset, and DECRQM has a + // "permanently reset" response for recognized modes that cannot be changed. + // Report that instead of "not recognized" so applications can query and adapt + // to Ghostty's erase-color behavior. + // + // See VT520/VT525 Programmer Information, "Erase Color" and DECRQM/DECRPM: + // https://web.mit.edu/dosathena/doc/www/ek-vt520-rm.pdf + + if (!tag.ansi and tag.value == 117) { + return .{ .tag = tag, .state = .permanently_reset }; + } const mode = modeFromInt(tag.value, tag.ansi) orelse return .{ .tag = tag, .state = .not_recognized, @@ -347,6 +360,13 @@ test "getReport known ANSI mode" { try testing.expectEqual(true, report.tag.ansi); } +test "getReport DECECM permanently reset" { + const state: ModeState = .{}; + const report = state.getReport(.{ .value = 117, .ansi = false }); + try testing.expectEqual(Report.State.permanently_reset, report.state); + try testing.expectEqual(false, report.tag.ansi); +} + test "getReport unknown mode" { const state: ModeState = .{}; const report = state.getReport(.{ .value = 9999 }); diff --git a/src/terminal/stream_terminal.zig b/src/terminal/stream_terminal.zig index f68f088bf83..251105e7208 100644 --- a/src/terminal/stream_terminal.zig +++ b/src/terminal/stream_terminal.zig @@ -1366,6 +1366,10 @@ test "request mode DECRQM with write_pty callback" { // Query an unknown mode s.nextSlice("\x1B[?9999$p"); try testing.expectEqualStrings("\x1B[?9999;0$y", S.last_response.?); + + // Query DECECM, which Ghostty recognizes but does not allow changing + s.nextSlice("\x1B[?117$p"); + try testing.expectEqualStrings("\x1B[?117;4$y", S.last_response.?); } }