macos: move drop implementation to separate extension

This commit is contained in:
Mitchell Hashimoto
2025-01-11 19:19:49 -08:00
parent a06fc4ff11
commit a2d2cfea59
2 changed files with 63 additions and 80 deletions

View File

@ -92,22 +92,6 @@ extension Ghostty {
windowFocus = false windowFocus = false
} }
} }
.onDrop(of: [.fileURL], isTargeted: nil) { providers in
providers.forEach { provider in
_ = provider.loadObject(ofClass: URL.self) { url, _ in
guard let url = url else { return }
let path = Shell.escape(url.path)
DispatchQueue.main.async {
surfaceView.insertText(
path,
replacementRange: NSMakeRange(0, 0)
)
}
}
}
return true
}
#endif #endif
// If our geo size changed then we show the resize overlay as configured. // If our geo size changed then we show the resize overlay as configured.

View File

@ -1,3 +1,4 @@
import AppKit
import SwiftUI import SwiftUI
import CoreText import CoreText
import UserNotifications import UserNotifications
@ -230,8 +231,9 @@ extension Ghostty {
ghostty_surface_set_color_scheme(surface, scheme) ghostty_surface_set_color_scheme(surface, scheme)
} }
registerForDraggedTypes([.string, .fileURL, .URL]) // The UTTypes that can be dragged onto this view.
registerForDraggedTypes(Array(Self.dropTypes))
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
@ -391,68 +393,6 @@ extension Ghostty {
self?.title = title self?.title = title
} }
} }
// MARK: - Drag and Drop
override func draggingEntered(_ sender: any NSDraggingInfo) -> NSDragOperation {
if let _ = sender.draggingPasteboard.string(forType: .string) {
return .generic
}
if let _ = sender.draggingPasteboard.string(forType: .URL) {
return .generic
}
if let _ = sender.draggingPasteboard.string(forType: .fileURL) {
return .generic
}
return []
}
override func performDragOperation(_ sender: any NSDraggingInfo) -> Bool {
if let droppedText = sender.draggingPasteboard.string(forType: .string) {
let content = Shell.escape(droppedText)
DispatchQueue.main.async {
self.insertText(
content,
replacementRange: NSMakeRange(0, 0)
)
}
return true
}
if let droppedURL = sender.draggingPasteboard.string(forType: .URL) {
let content = Shell.escape(droppedURL)
DispatchQueue.main.async {
self.insertText(
content,
replacementRange: NSMakeRange(0, 0)
)
}
return true
}
if let droppedFileURL = sender.draggingPasteboard.string(forType: .fileURL) {
guard let urlPath = URL(string: droppedFileURL)?.path(percentEncoded: false) else {
return false
}
DispatchQueue.main.async {
self.insertText(
urlPath,
replacementRange: NSMakeRange(0, 0)
)
}
return true
}
return false
}
// MARK: Local Events // MARK: Local Events
@ -1573,3 +1513,62 @@ extension Ghostty.SurfaceView: NSMenuItemValidation {
} }
} }
} }
// MARK: NSDraggingDestination
extension Ghostty.SurfaceView {
static let dropTypes: Set<NSPasteboard.PasteboardType> = [
.string,
.fileURL,
.URL
]
override func draggingEntered(_ sender: any NSDraggingInfo) -> NSDragOperation {
guard let types = sender.draggingPasteboard.types else { return [] }
// If the dragging object contains none of our types then we return none.
// This shouldn't happen because AppKit should guarantee that we only
// receive types we registered for but its good to check.
if Set(types).isDisjoint(with: Self.dropTypes) {
return []
}
// We use copy to get the proper icon
return .copy
}
override func performDragOperation(_ sender: any NSDraggingInfo) -> Bool {
let pb = sender.draggingPasteboard
let content: String?
if let url = pb.string(forType: .URL) {
// URLs first, they get escaped as-is.
content = Ghostty.Shell.escape(url)
} else if let urls = pb.readObjects(forClasses: [NSURL.self]) as? [URL],
urls.count > 0 {
// File URLs next. They get escaped individually and then joined by a
// space if there are multiple.
content = urls
.map { Ghostty.Shell.escape($0.path) }
.joined(separator: " ")
} else if let str = pb.string(forType: .string) {
// Strings are not escaped because they may be copy/pasting a
// command they want to execute.
content = str
} else {
content = nil
}
if let content {
DispatchQueue.main.async {
self.insertText(
content,
replacementRange: NSMakeRange(0, 0)
)
}
return true
}
return false
}
}