Merge pull request #829 from mitchellh/blink

termio: cursor-style-blink being set disables DEC mode 12
This commit is contained in:
Mitchell Hashimoto
2023-11-06 12:09:28 -08:00
committed by GitHub
3 changed files with 61 additions and 9 deletions

View File

@ -195,8 +195,19 @@ palette: Palette = .{},
/// https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.shell_integration /// https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.shell_integration
@"cursor-style": terminal.Cursor.Style = .block, @"cursor-style": terminal.Cursor.Style = .block,
/// Whether the cursor shall blink /// Sets the default blinking state of the cursor. This is just the
@"cursor-style-blink": bool = true, /// default state; running programs may override the cursor style
/// using DECSCUSR (CSI q).
///
/// If this is not set, the cursor blinks by default. Note that
/// this is not the same as a "true" value, as noted below.
///
/// If this is not set at all (null), then Ghostty will respect
/// DEC Mode 12 (AT&T cursor blink) as an alternate approach to
/// turning blinking on/off. If this is set to any value other
/// than null, DEC mode 12 will be ignored but DECSCUSR will still
/// be respected.
@"cursor-style-blink": ?bool = null,
/// The color of the text under the cursor. If this is not set, a default /// The color of the text under the cursor. If this is not set, a default
/// will be chosen. /// will be chosen.

View File

@ -51,5 +51,5 @@ test "Value" {
const testing = std.testing; const testing = std.testing;
try testing.expectEqual(?[:0]const u8, Value(.@"font-family")); try testing.expectEqual(?[:0]const u8, Value(.@"font-family"));
try testing.expectEqual(bool, Value(.@"cursor-style-blink")); try testing.expectEqual(?bool, Value(.@"cursor-style-blink"));
} }

View File

@ -68,7 +68,7 @@ grid_size: renderer.GridSize,
/// The default cursor style. We need to know this so that we can set /// The default cursor style. We need to know this so that we can set
/// it when a CSI q with default is called. /// it when a CSI q with default is called.
default_cursor_style: terminal.Cursor.Style, default_cursor_style: terminal.Cursor.Style,
default_cursor_blink: bool, default_cursor_blink: ?bool,
/// Default foreground color for OSC 10 reporting. /// Default foreground color for OSC 10 reporting.
default_foreground_color: terminal.color.RGB, default_foreground_color: terminal.color.RGB,
@ -89,7 +89,7 @@ pub const DerivedConfig = struct {
palette: terminal.color.Palette, palette: terminal.color.Palette,
image_storage_limit: usize, image_storage_limit: usize,
cursor_style: terminal.Cursor.Style, cursor_style: terminal.Cursor.Style,
cursor_blink: bool, cursor_blink: ?bool,
foreground: configpkg.Config.Color, foreground: configpkg.Config.Color,
background: configpkg.Config.Color, background: configpkg.Config.Color,
osc_color_report_format: configpkg.Config.OSCColorReportFormat, osc_color_report_format: configpkg.Config.OSCColorReportFormat,
@ -139,7 +139,10 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
try term.secondary_screen.kitty_images.setLimit(alloc, opts.config.image_storage_limit); try term.secondary_screen.kitty_images.setLimit(alloc, opts.config.image_storage_limit);
// Set default cursor blink settings // Set default cursor blink settings
term.modes.set(.cursor_blinking, opts.config.cursor_blink); term.modes.set(
.cursor_blinking,
opts.config.cursor_blink orelse true,
);
var subprocess = try Subprocess.init(alloc, opts); var subprocess = try Subprocess.init(alloc, opts);
errdefer subprocess.deinit(); errdefer subprocess.deinit();
@ -1321,7 +1324,7 @@ const StreamHandler = struct {
/// set to true when we're currently in the default cursor state. /// set to true when we're currently in the default cursor state.
default_cursor: bool = true, default_cursor: bool = true,
default_cursor_style: terminal.Cursor.Style, default_cursor_style: terminal.Cursor.Style,
default_cursor_blink: bool, default_cursor_blink: ?bool,
default_foreground_color: terminal.color.RGB, default_foreground_color: terminal.color.RGB,
default_background_color: terminal.color.RGB, default_background_color: terminal.color.RGB,
osc_color_report_format: configpkg.Config.OSCColorReportFormat, osc_color_report_format: configpkg.Config.OSCColorReportFormat,
@ -1343,7 +1346,7 @@ const StreamHandler = struct {
pub fn changeDefaultCursor( pub fn changeDefaultCursor(
self: *StreamHandler, self: *StreamHandler,
style: terminal.Cursor.Style, style: terminal.Cursor.Style,
blink: bool, blink: ?bool,
) void { ) void {
self.default_cursor_style = style; self.default_cursor_style = style;
self.default_cursor_blink = blink; self.default_cursor_blink = blink;
@ -1602,6 +1605,41 @@ const StreamHandler = struct {
// terminal locks because it is only called from process() which // terminal locks because it is only called from process() which
// grabs the lock. // grabs the lock.
// If we are setting cursor blinking, we ignore it if we have
// a default cursor blink setting set. This is a really weird
// behavior so this comment will go deep into trying to explain it.
//
// There are two ways to set cursor blinks: DECSCUSR (CSI _ q)
// and DEC mode 12. DECSCUSR is the modern approach and has a
// way to revert to the "default" (as defined by the terminal)
// cursor style and blink by doing "CSI 0 q". DEC mode 12 controls
// blinking and is either on or off and has no way to set a
// default. DEC mode 12 is also the more antiquated approach.
//
// The problem is that if the user specifies a desired default
// cursor blink with `cursor-style-blink`, the moment a running
// program uses DEC mode 12, the cursor blink can never be reset
// to the default without an explicit DECSCUSR. But if a program
// is using mode 12, it is by definition not using DECSCUSR.
// This makes for somewhat annoying interactions where a poorly
// (or legacy) behaved program will stop blinking, and it simply
// never restarts.
//
// To get around this, we have a special case where if the user
// specifies some explicit default cursor blink desire, we ignore
// DEC mode 12. We allow DECSCUSR to still set the cursor blink
// because programs using DECSCUSR usually are well behaved and
// reset the cursor blink to the default when they exit.
//
// To be extra safe, users can also add a manual `CSI 0 q` to
// their shell config when they render prompts to ensure the
// cursor is exactly as they request.
if (mode == .cursor_blinking and
self.default_cursor_blink != null)
{
return;
}
// We first always set the raw mode on our mode state. // We first always set the raw mode on our mode state.
self.terminal.modes.set(mode, enabled); self.terminal.modes.set(mode, enabled);
@ -1756,7 +1794,10 @@ const StreamHandler = struct {
.default => { .default => {
self.default_cursor = true; self.default_cursor = true;
self.terminal.screen.cursor.style = self.default_cursor_style; self.terminal.screen.cursor.style = self.default_cursor_style;
self.terminal.modes.set(.cursor_blinking, self.default_cursor_blink); self.terminal.modes.set(
.cursor_blinking,
self.default_cursor_blink orelse true,
);
}, },
.blinking_block => { .blinking_block => {