2025-06-21 06:39:19 -07:00

115 lines
3.0 KiB
Swift

import AppKit
import AppIntents
import SwiftUI
struct TerminalEntity: AppEntity {
let id: UUID
@Property(title: "Title")
var title: String
@Property(title: "Working Directory")
var workingDirectory: String?
@MainActor
@DeferredProperty(title: "Full Contents")
@available(macOS 26.0, *)
var screenContents: String? {
get async {
guard let surfaceView else { return nil }
return surfaceView.cachedScreenContents.get()
}
}
@MainActor
@DeferredProperty(title: "Visible Contents")
@available(macOS 26.0, *)
var visibleContents: String? {
get async {
guard let surfaceView else { return nil }
return surfaceView.cachedVisibleContents.get()
}
}
var screenshot: Image?
static var typeDisplayRepresentation: TypeDisplayRepresentation {
TypeDisplayRepresentation(name: "Terminal")
}
@MainActor
var displayRepresentation: DisplayRepresentation {
var rep = DisplayRepresentation(title: "\(title)")
if let screenshot,
let nsImage = ImageRenderer(content: screenshot).nsImage,
let data = nsImage.tiffRepresentation {
rep.image = .init(data: data)
}
return rep
}
/// Returns the view associated with this entity. This may no longer exist.
@MainActor
var surfaceView: Ghostty.SurfaceView? {
Self.defaultQuery.all.first { $0.uuid == self.id }
}
@MainActor
var surfaceModel: Ghostty.Surface? {
surfaceView?.surfaceModel
}
static var defaultQuery = TerminalQuery()
init(_ view: Ghostty.SurfaceView) {
self.id = view.uuid
self.title = view.title
self.workingDirectory = view.pwd
self.screenshot = view.screenshot()
}
}
struct TerminalQuery: EntityStringQuery, EnumerableEntityQuery {
@MainActor
func entities(for identifiers: [TerminalEntity.ID]) async throws -> [TerminalEntity] {
return all.filter {
identifiers.contains($0.uuid)
}.map {
TerminalEntity($0)
}
}
@MainActor
func entities(matching string: String) async throws -> [TerminalEntity] {
return all.filter {
$0.title.localizedCaseInsensitiveContains(string)
}.map {
TerminalEntity($0)
}
}
@MainActor
func allEntities() async throws -> [TerminalEntity] {
return all.map { TerminalEntity($0) }
}
@MainActor
func suggestedEntities() async throws -> [TerminalEntity] {
return try await allEntities()
}
@MainActor
var all: [Ghostty.SurfaceView] {
// Find all of our terminal windows (includes quick terminal)
let controllers = NSApp.windows.compactMap {
$0.windowController as? BaseTerminalController
}
// Get all our surfaces
return controllers.reduce([]) { result, c in
result + (c.surfaceTree.root?.leaves() ?? [])
}
}
}