mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-03 04:38:39 +03:00
140 lines
3.7 KiB
Swift
140 lines
3.7 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?
|
|
|
|
@Property(title: "Kind")
|
|
var kind: Kind
|
|
|
|
@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()
|
|
|
|
// Determine the kind based on the window controller type
|
|
if view.window?.windowController is QuickTerminalController {
|
|
self.kind = .quick
|
|
} else {
|
|
self.kind = .normal
|
|
}
|
|
}
|
|
}
|
|
|
|
extension TerminalEntity {
|
|
enum Kind: String, AppEnum {
|
|
case normal
|
|
case quick
|
|
|
|
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Terminal Kind")
|
|
|
|
static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [
|
|
.normal: .init(title: "Normal"),
|
|
.quick: .init(title: "Quick")
|
|
]
|
|
}
|
|
}
|
|
|
|
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. This will include the quick terminal
|
|
// but only if it was previously opened.
|
|
let controllers = NSApp.windows.compactMap {
|
|
$0.windowController as? BaseTerminalController
|
|
}
|
|
|
|
// Get all our surfaces
|
|
return controllers.flatMap {
|
|
$0.surfaceTree.root?.leaves() ?? []
|
|
}
|
|
}
|
|
}
|