mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
feat: ensure text, files and URLs can be drag and dropped to terminal (#4962)
This PR ensures one can drag and drop the following things to the terminal window: - File (Inserts the file path into the terminal) - URL - Text This resolves #4932
This commit is contained in:
@ -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.
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import AppKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import CoreText
|
import CoreText
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
@ -230,6 +231,9 @@ extension Ghostty {
|
|||||||
|
|
||||||
ghostty_surface_set_color_scheme(surface, scheme)
|
ghostty_surface_set_color_scheme(surface, scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The UTTypes that can be dragged onto this view.
|
||||||
|
registerForDraggedTypes(Array(Self.dropTypes))
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -1509,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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user