mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
macos: configurable undo timeout
This commit is contained in:
@@ -77,7 +77,7 @@ class BaseTerminalController: NSWindowController,
|
||||
|
||||
/// The time that undo/redo operations that contain running ptys are valid for.
|
||||
var undoExpiration: Duration {
|
||||
.seconds(5)
|
||||
ghostty.config.undoTimeout
|
||||
}
|
||||
|
||||
/// The undo manager for this controller is the undo manager of the window,
|
||||
|
@@ -506,6 +506,14 @@ extension Ghostty {
|
||||
return v;
|
||||
}
|
||||
|
||||
var undoTimeout: Duration {
|
||||
guard let config = self.config else { return .seconds(5) }
|
||||
var v: UInt = 0
|
||||
let key = "undo-timeout"
|
||||
_ = ghostty_config_get(config, &v, key, UInt(key.count))
|
||||
return .milliseconds(v)
|
||||
}
|
||||
|
||||
var autoUpdate: AutoUpdate? {
|
||||
guard let config = self.config else { return nil }
|
||||
var v: UnsafePointer<Int8>? = nil
|
||||
|
@@ -29,6 +29,9 @@ class ExpiringUndoManager: UndoManager {
|
||||
expiresAfter duration: Duration,
|
||||
handler: @escaping (TargetType) -> Void
|
||||
) {
|
||||
// Ignore instantly expiring undos
|
||||
guard duration.timeInterval > 0 else { return }
|
||||
|
||||
let expiringTarget = ExpiringTarget(
|
||||
target,
|
||||
expiresAfter: duration,
|
||||
|
@@ -1705,6 +1705,52 @@ keybind: Keybinds = .{},
|
||||
/// window is ever created. Only implemented on Linux and macOS.
|
||||
@"initial-window": bool = true,
|
||||
|
||||
/// The duration that undo operations remain available. After this
|
||||
/// time, the operation will be removed from the undo stack and
|
||||
/// cannot be undone.
|
||||
///
|
||||
/// The default value is 5 seconds.
|
||||
///
|
||||
/// This timeout applies per operation, meaning that if you perform
|
||||
/// multiple operations, each operation will have its own timeout.
|
||||
/// New operations do not reset the timeout of previous operations.
|
||||
///
|
||||
/// A timeout of zero will effectively disable undo operations. It is
|
||||
/// not possible to set an infinite timeout, but you can set a very
|
||||
/// large timeout to effectively disable the timeout (on the order of years).
|
||||
/// This is highly discouraged, as it will cause the undo stack to grow
|
||||
/// indefinitely, memory usage to grow unbounded, and terminal sessions
|
||||
/// to never actually quit.
|
||||
///
|
||||
/// The duration is specified as a series of numbers followed by time units.
|
||||
/// Whitespace is allowed between numbers and units. Each number and unit will
|
||||
/// be added together to form the total duration.
|
||||
///
|
||||
/// The allowed time units are as follows:
|
||||
///
|
||||
/// * `y` - 365 SI days, or 8760 hours, or 31536000 seconds. No adjustments
|
||||
/// are made for leap years or leap seconds.
|
||||
/// * `d` - one SI day, or 86400 seconds.
|
||||
/// * `h` - one hour, or 3600 seconds.
|
||||
/// * `m` - one minute, or 60 seconds.
|
||||
/// * `s` - one second.
|
||||
/// * `ms` - one millisecond, or 0.001 second.
|
||||
/// * `us` or `µs` - one microsecond, or 0.000001 second.
|
||||
/// * `ns` - one nanosecond, or 0.000000001 second.
|
||||
///
|
||||
/// Examples:
|
||||
/// * `1h30m`
|
||||
/// * `45s`
|
||||
///
|
||||
/// Units can be repeated and will be added together. This means that
|
||||
/// `1h1h` is equivalent to `2h`. This is confusing and should be avoided.
|
||||
/// A future update may disallow this.
|
||||
///
|
||||
/// This configuration is only supported on macOS. Linux doesn't
|
||||
/// support undo operations at all so this configuration has no
|
||||
/// effect.
|
||||
@"undo-timeout": Duration = .{ .duration = 5 * std.time.ns_per_s },
|
||||
|
||||
/// The position of the "quick" terminal window. To learn more about the
|
||||
/// quick terminal, see the documentation for the `toggle_quick_terminal`
|
||||
/// binding action.
|
||||
@@ -6583,7 +6629,7 @@ pub const Duration = struct {
|
||||
if (remaining.len == 0) break;
|
||||
|
||||
// Find the longest number
|
||||
const number = number: {
|
||||
const number: u64 = number: {
|
||||
var prev_number: ?u64 = null;
|
||||
var prev_remaining: ?[]const u8 = null;
|
||||
for (1..remaining.len + 1) |index| {
|
||||
@@ -6597,8 +6643,17 @@ pub const Duration = struct {
|
||||
break :number prev_number;
|
||||
} orelse return error.InvalidValue;
|
||||
|
||||
// A number without a unit is invalid
|
||||
if (remaining.len == 0) return error.InvalidValue;
|
||||
// A number without a unit is invalid unless the number is
|
||||
// exactly zero. In that case, the unit is unambiguous since
|
||||
// its all the same.
|
||||
if (remaining.len == 0) {
|
||||
if (number == 0) {
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return error.InvalidValue;
|
||||
}
|
||||
|
||||
// Find the longest matching unit. Needs to be the longest matching
|
||||
// to distinguish 'm' from 'ms'.
|
||||
@@ -6808,6 +6863,11 @@ test "parse duration" {
|
||||
try std.testing.expectEqual(unit.factor, d.duration);
|
||||
}
|
||||
|
||||
{
|
||||
const d = try Duration.parseCLI("0");
|
||||
try std.testing.expectEqual(@as(u64, 0), d.duration);
|
||||
}
|
||||
|
||||
{
|
||||
const d = try Duration.parseCLI("100ns");
|
||||
try std.testing.expectEqual(@as(u64, 100), d.duration);
|
||||
|
Reference in New Issue
Block a user