mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-06-03 14:08:40 +03:00

First, this commit modifies libghostty to use a single unified action dispatch system based on a tagged union versus the one-off callback system that was previously in place. This change simplifies the code on both the core and consumer sides of the library. Importantly, as we introduce new actions, we can now maintain ABI compatibility so long as our union size does not change (something I don't promise yet). Second, this moves a lot more of the functions call on a surface into the action system. This affects all apprts and continues the previous work of introducing a more unified API for optional surface features.
266 lines
9.0 KiB
Swift
266 lines
9.0 KiB
Swift
import os
|
|
import SwiftUI
|
|
import GhosttyKit
|
|
|
|
struct Ghostty {
|
|
// The primary logger used by the GhosttyKit libraries.
|
|
static let logger = Logger(
|
|
subsystem: Bundle.main.bundleIdentifier!,
|
|
category: "ghostty"
|
|
)
|
|
|
|
// All the notifications that will be emitted will be put here.
|
|
struct Notification {}
|
|
|
|
// The user notification category identifier
|
|
static let userNotificationCategory = "com.mitchellh.ghostty.userNotification"
|
|
|
|
// The user notification "Show" action
|
|
static let userNotificationActionShow = "com.mitchellh.ghostty.userNotification.Show"
|
|
}
|
|
|
|
// MARK: Build Info
|
|
|
|
extension Ghostty {
|
|
struct Info {
|
|
var mode: ghostty_build_mode_e
|
|
var version: String
|
|
}
|
|
|
|
static var info: Info {
|
|
let raw = ghostty_info()
|
|
let version = NSString(
|
|
bytes: raw.version,
|
|
length: Int(raw.version_len),
|
|
encoding: NSUTF8StringEncoding
|
|
) ?? "unknown"
|
|
|
|
return Info(mode: raw.build_mode, version: String(version))
|
|
}
|
|
}
|
|
|
|
// MARK: Swift Types for C Types
|
|
|
|
extension Ghostty {
|
|
enum SetSecureInput {
|
|
case on
|
|
case off
|
|
case toggle
|
|
|
|
static func from(_ c: ghostty_action_secure_input_e) -> Self? {
|
|
switch (c) {
|
|
case GHOSTTY_SECURE_INPUT_ON:
|
|
return .on
|
|
|
|
case GHOSTTY_SECURE_INPUT_OFF:
|
|
return .off
|
|
|
|
case GHOSTTY_SECURE_INPUT_TOGGLE:
|
|
return .toggle
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An enum that is used for the directions that a split focus event can change.
|
|
enum SplitFocusDirection {
|
|
case previous, next, top, bottom, left, right
|
|
|
|
/// Initialize from a Ghostty API enum.
|
|
static func from(direction: ghostty_action_goto_split_e) -> Self? {
|
|
switch (direction) {
|
|
case GHOSTTY_GOTO_SPLIT_PREVIOUS:
|
|
return .previous
|
|
|
|
case GHOSTTY_GOTO_SPLIT_NEXT:
|
|
return .next
|
|
|
|
case GHOSTTY_GOTO_SPLIT_TOP:
|
|
return .top
|
|
|
|
case GHOSTTY_GOTO_SPLIT_BOTTOM:
|
|
return .bottom
|
|
|
|
case GHOSTTY_GOTO_SPLIT_LEFT:
|
|
return .left
|
|
|
|
case GHOSTTY_GOTO_SPLIT_RIGHT:
|
|
return .right
|
|
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func toNative() -> ghostty_action_goto_split_e {
|
|
switch (self) {
|
|
case .previous:
|
|
return GHOSTTY_GOTO_SPLIT_PREVIOUS
|
|
|
|
case .next:
|
|
return GHOSTTY_GOTO_SPLIT_NEXT
|
|
|
|
case .top:
|
|
return GHOSTTY_GOTO_SPLIT_TOP
|
|
|
|
case .bottom:
|
|
return GHOSTTY_GOTO_SPLIT_BOTTOM
|
|
|
|
case .left:
|
|
return GHOSTTY_GOTO_SPLIT_LEFT
|
|
|
|
case .right:
|
|
return GHOSTTY_GOTO_SPLIT_RIGHT
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Enum used for resizing splits. This is the direction the split divider will move.
|
|
enum SplitResizeDirection {
|
|
case up, down, left, right
|
|
|
|
static func from(direction: ghostty_action_resize_split_direction_e) -> Self? {
|
|
switch (direction) {
|
|
case GHOSTTY_RESIZE_SPLIT_UP:
|
|
return .up;
|
|
case GHOSTTY_RESIZE_SPLIT_DOWN:
|
|
return .down;
|
|
case GHOSTTY_RESIZE_SPLIT_LEFT:
|
|
return .left;
|
|
case GHOSTTY_RESIZE_SPLIT_RIGHT:
|
|
return .right;
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func toNative() -> ghostty_action_resize_split_direction_e {
|
|
switch (self) {
|
|
case .up:
|
|
return GHOSTTY_RESIZE_SPLIT_UP;
|
|
case .down:
|
|
return GHOSTTY_RESIZE_SPLIT_DOWN;
|
|
case .left:
|
|
return GHOSTTY_RESIZE_SPLIT_LEFT;
|
|
case .right:
|
|
return GHOSTTY_RESIZE_SPLIT_RIGHT;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The type of a clipboard request
|
|
enum ClipboardRequest {
|
|
/// A direct paste of clipboard contents
|
|
case paste
|
|
|
|
/// An application is attempting to read from the clipboard using OSC 52
|
|
case osc_52_read
|
|
|
|
/// An application is attempting to write to the clipboard using OSC 52
|
|
case osc_52_write
|
|
|
|
/// The text to show in the clipboard confirmation prompt for a given request type
|
|
func text() -> String {
|
|
switch (self) {
|
|
case .paste:
|
|
return """
|
|
Pasting this text to the terminal may be dangerous as it looks like some commands may be executed.
|
|
"""
|
|
case .osc_52_read:
|
|
return """
|
|
An application is attempting to read from the clipboard.
|
|
The current clipboard contents are shown below.
|
|
"""
|
|
case .osc_52_write:
|
|
return """
|
|
An application is attempting to write to the clipboard.
|
|
The content to write is shown below.
|
|
"""
|
|
}
|
|
}
|
|
|
|
static func from(request: ghostty_clipboard_request_e) -> ClipboardRequest? {
|
|
switch (request) {
|
|
case GHOSTTY_CLIPBOARD_REQUEST_PASTE:
|
|
return .paste
|
|
case GHOSTTY_CLIPBOARD_REQUEST_OSC_52_READ:
|
|
return .osc_52_read
|
|
case GHOSTTY_CLIPBOARD_REQUEST_OSC_52_WRITE:
|
|
return .osc_52_write
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Surface Notifications
|
|
|
|
extension Ghostty.Notification {
|
|
/// Used to pass a configuration along when creating a new tab/window/split.
|
|
static let NewSurfaceConfigKey = "com.mitchellh.ghostty.newSurfaceConfig"
|
|
|
|
/// Posted when a new split is requested. The sending object will be the surface that had focus. The
|
|
/// userdata has one key "direction" with the direction to split to.
|
|
static let ghosttyNewSplit = Notification.Name("com.mitchellh.ghostty.newSplit")
|
|
|
|
/// Close the calling surface.
|
|
static let ghosttyCloseSurface = Notification.Name("com.mitchellh.ghostty.closeSurface")
|
|
|
|
/// Focus previous/next split. Has a SplitFocusDirection in the userinfo.
|
|
static let ghosttyFocusSplit = Notification.Name("com.mitchellh.ghostty.focusSplit")
|
|
static let SplitDirectionKey = ghosttyFocusSplit.rawValue
|
|
|
|
/// Goto tab. Has tab index in the userinfo.
|
|
static let ghosttyGotoTab = Notification.Name("com.mitchellh.ghostty.gotoTab")
|
|
static let GotoTabKey = ghosttyGotoTab.rawValue
|
|
|
|
/// New tab. Has base surface config requested in userinfo.
|
|
static let ghosttyNewTab = Notification.Name("com.mitchellh.ghostty.newTab")
|
|
|
|
/// New window. Has base surface config requested in userinfo.
|
|
static let ghosttyNewWindow = Notification.Name("com.mitchellh.ghostty.newWindow")
|
|
|
|
/// Toggle fullscreen of current window
|
|
static let ghosttyToggleFullscreen = Notification.Name("com.mitchellh.ghostty.toggleFullscreen")
|
|
static let FullscreenModeKey = ghosttyToggleFullscreen.rawValue
|
|
|
|
/// Notification that a surface is becoming focused. This is only sent on macOS 12 to
|
|
/// work around bugs. macOS 13+ should use the ".focused()" attribute.
|
|
static let didBecomeFocusedSurface = Notification.Name("com.mitchellh.ghostty.didBecomeFocusedSurface")
|
|
|
|
/// Notification sent to toggle split maximize/unmaximize.
|
|
static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom")
|
|
|
|
/// Notification
|
|
static let didReceiveInitialWindowFrame = Notification.Name("com.mitchellh.ghostty.didReceiveInitialWindowFrame")
|
|
static let FrameKey = "com.mitchellh.ghostty.frame"
|
|
|
|
/// Notification to render the inspector for a surface
|
|
static let inspectorNeedsDisplay = Notification.Name("com.mitchellh.ghostty.inspectorNeedsDisplay")
|
|
|
|
/// Notification to show/hide the inspector
|
|
static let didControlInspector = Notification.Name("com.mitchellh.ghostty.didControlInspector")
|
|
|
|
static let confirmClipboard = Notification.Name("com.mitchellh.ghostty.confirmClipboard")
|
|
static let ConfirmClipboardStrKey = confirmClipboard.rawValue + ".str"
|
|
static let ConfirmClipboardStateKey = confirmClipboard.rawValue + ".state"
|
|
static let ConfirmClipboardRequestKey = confirmClipboard.rawValue + ".request"
|
|
|
|
/// Notification sent to the active split view to resize the split.
|
|
static let didResizeSplit = Notification.Name("com.mitchellh.ghostty.didResizeSplit")
|
|
static let ResizeSplitDirectionKey = didResizeSplit.rawValue + ".direction"
|
|
static let ResizeSplitAmountKey = didResizeSplit.rawValue + ".amount"
|
|
|
|
/// Notification sent to the split root to equalize split sizes
|
|
static let didEqualizeSplits = Notification.Name("com.mitchellh.ghostty.didEqualizeSplits")
|
|
|
|
/// Notification that renderer health changed
|
|
static let didUpdateRendererHealth = Notification.Name("com.mitchellh.ghostty.didUpdateRendererHealth")
|
|
}
|
|
|
|
// Make the input enum hashable.
|
|
extension ghostty_input_key_e : Hashable {}
|