Skip to content

Commit 1ef5c97

Browse files
committed
Add better options for dropped or pasted files.
Dropping into ssh will now offer to upload and paste path, making it easy to send claude code images on remote hosts. You can also copy raw image data and paste it, and it'll give you b64, make file and paste path, or upload options, depending on whether you're sshed.
1 parent eb9c1b1 commit 1ef5c97

23 files changed

+1161
-23
lines changed

CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@
1313
- The deployment target for iTerm2 is macOS 12. You don't need to perform availability checks for older versions.
1414
- Don't replace curly quotes with straight quotes. Same for apostrophes and single quotes.
1515
- In user-visible strings do not use " except as a shorthand for inch. Prefer curly quotes like “ and ”. I know this goes against your nature, but fight hard here.
16+
- Never use auto layout in the terminal window. It virally spreads and breaks autoresizing. It is fine to use it in other windows without a lot of existing autoresizing mask-based code (e.g., the AI chat window)
17+
- The deployment target is macOS 12. Don't add availability checks for 12 and lower.

ThirdParty/UKCrashReporter/UKCrashReporter.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ void UKCrashReporterCheckForCrash(void)
9898
NSTimeInterval lastCrashReportInterval = [[NSUserDefaults standardUserDefaults] floatForKey: @"UKCrashReporterLastCrashReportDate"];
9999
NSDate* lastTimeCrashReported = [NSDate dateWithTimeIntervalSince1970: lastCrashReportInterval];
100100

101-
NSUserDefaults *d = [NSUserDefaults standardUserDefaults];
102-
103101
NSString *errorLog = nil;
104102
@try {
105103
errorLog = UKReadErrorLog();

iTerm2.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
02BBB9199A50961FFEAC2D6D /* iTermFindOnPageHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98E9463133DCF8311E0E5B6E /* iTermFindOnPageHelperTests.swift */; };
1111
052FA2457F95F63A46C30503 /* IntervalTreeCoordinateClampingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6601DD02DFE3C2480DFDC73 /* IntervalTreeCoordinateClampingTests.swift */; };
1212
06E0C88E1DF9695400AA061B /* iTermServiceProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 06E0C88C1DF9695400AA061B /* iTermServiceProvider.h */; };
13+
084F626684E68821BAEC7D9B /* iTermNonTextPasteHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED49EE365D629DAE80503BFD /* iTermNonTextPasteHelper.swift */; };
1314
10AAA7668EA8FBDD64696AB7 /* iTermEventTriggerParameterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE7B0AE10E1598EDE1E01795 /* iTermEventTriggerParameterView.swift */; };
1415
1D027C111CD1867000B0FBFF /* iTermColorPresets.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D027C0F1CD1867000B0FBFF /* iTermColorPresets.h */; };
1516
1D0318281A42563A00932107 /* iTermImageWell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1D0318261A42563A00932107 /* iTermImageWell.h */; };
@@ -944,6 +945,7 @@
944945
874206530564169600CFC3F1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0464AB2F006CD2EC7F000001 /* AppKit.framework */; };
945946
90A1E13B186F9EA4003EC3E8 /* AppleScriptTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 90A1E13A186F9EA4003EC3E8 /* AppleScriptTest.m */; };
946947
98063D9BFF61AB290BEE435C /* iTermCursorSlideAnimator.m in Sources */ = {isa = PBXBuildFile; fileRef = 479FDFE9C0F424FEC10526EC /* iTermCursorSlideAnimator.m */; };
948+
9C2DA778D246D42A1DC362CC /* iTermUploadIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 698B6ED16A3CD11D402C364B /* iTermUploadIndicator.swift */; };
947949
9D737D5F17495B4100B3334D /* PrefsGeneral.png in Resources */ = {isa = PBXBuildFile; fileRef = 9D737D5D17495B4100B3334D /* PrefsGeneral.png */; };
948950
9D737D6017495B4100B3334D /* PrefsGeneral@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9D737D5E17495B4100B3334D /* PrefsGeneral@2x.png */; };
949951
9DB3D6E0176C8F0B0071CCF8 /* PrefsAppearance.png in Resources */ = {isa = PBXBuildFile; fileRef = 9DB3D6DE176C8F0B0071CCF8 /* PrefsAppearance.png */; };
@@ -6201,6 +6203,7 @@
62016203
53FF984A20967805008688D7 /* iTermMetalDeviceProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iTermMetalDeviceProvider.m; sourceTree = "<group>"; };
62026204
5ECE005D1454E59B004861E9 /* PseudoTerminalRestorer.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminalRestorer.h; sourceTree = "<group>"; tabWidth = 4; };
62036205
5ECE005E1454E59B004861E9 /* PseudoTerminalRestorer.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = PseudoTerminalRestorer.m; sourceTree = "<group>"; tabWidth = 4; };
6206+
698B6ED16A3CD11D402C364B /* iTermUploadIndicator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = iTermUploadIndicator.swift; sourceTree = "<group>"; };
62046207
756C32AB2597AC2E0047B3A9 /* iTermImage+Sixel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iTermImage+Sixel.h"; sourceTree = "<group>"; };
62056208
756C32AC2597AC2E0047B3A9 /* iTermImage+Sixel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "iTermImage+Sixel.m"; sourceTree = "<group>"; };
62066209
756C32C12597AC9C0047B3A9 /* libaprutil-1.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libaprutil-1.tbd"; path = "Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libaprutil-1.tbd"; sourceTree = DEVELOPER_DIR; };
@@ -9148,6 +9151,7 @@
91489151
E8CF7563026DDA6303A80106 /* VT100Terminal.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = VT100Terminal.m; sourceTree = "<group>"; tabWidth = 4; };
91499152
E8CF757F026DDAD703A80106 /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; tabWidth = 4; };
91509153
E8E901A202743CA303A80106 /* NSStringITerm.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = NSStringITerm.m; sourceTree = "<group>"; tabWidth = 4; };
9154+
ED49EE365D629DAE80503BFD /* iTermNonTextPasteHelper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = iTermNonTextPasteHelper.swift; sourceTree = "<group>"; };
91519155
F52ED8DD037F0A7D01A8A066 /* PTYSession.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PTYSession.m; sourceTree = "<group>"; tabWidth = 4; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
91529156
F56B230B03A1B36701A8A066 /* PTYWindow.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PTYWindow.m; sourceTree = "<group>"; tabWidth = 4; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
91539157
F5E533B403B2959201A8A066 /* PTYTabView.m */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.objc; path = PTYTabView.m; sourceTree = "<group>"; tabWidth = 4; };
@@ -13396,6 +13400,8 @@
1339613400
76421C2E762130B690D1ADC5 /* RegexAtomIterator.swift */,
1339713401
889A9128E944B618CDE75E18 /* iTermCursorSlideAnimator.h */,
1339813402
479FDFE9C0F424FEC10526EC /* iTermCursorSlideAnimator.m */,
13403+
ED49EE365D629DAE80503BFD /* iTermNonTextPasteHelper.swift */,
13404+
698B6ED16A3CD11D402C364B /* iTermUploadIndicator.swift */,
1339913405
);
1340013406
path = sources;
1340113407
sourceTree = "<group>";
@@ -20005,6 +20011,8 @@
2000520011
A785F516A64BC93AAF1474B8 /* RegexAtomIterator.swift in Sources */,
2000620012
EE293B4DA9D2204FCFDE6784 /* iTermCursorSlideAnimator.h in Sources */,
2000720013
98063D9BFF61AB290BEE435C /* iTermCursorSlideAnimator.m in Sources */,
20014+
084F626684E68821BAEC7D9B /* iTermNonTextPasteHelper.swift in Sources */,
20015+
9C2DA778D246D42A1DC362CC /* iTermUploadIndicator.swift in Sources */,
2000820016
);
2000920017
runOnlyForDeploymentPostprocessing = 0;
2001020018
};

sources/Conductor.swift

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,11 +1528,67 @@ extension Conductor {
15281528
@available(macOS 11, *)
15291529
@objc(uploadFile:to:)
15301530
func upload(file: String, to destinationPath: SCPPath) {
1531-
let file = ConductorFileTransfer(path: destinationPath,
1532-
localPath: file,
1533-
data: nil,
1534-
delegate: self)
1535-
file.upload()
1531+
_ = upload(file: file, to: destinationPath, completion: { _, _ in })
1532+
}
1533+
1534+
@available(macOS 11, *)
1535+
@objc(uploadFile:to:withCompletion:)
1536+
func upload(file: String, to destinationPath: SCPPath, completion: @escaping (Bool, String?) -> Void) -> TransferrableFile? {
1537+
let localPath: String
1538+
let remotePath: SCPPath
1539+
let tempArchivePath: String?
1540+
1541+
// Check if it's a directory - create a tgz archive
1542+
var isDirectory: ObjCBool = false
1543+
if FileManager.default.fileExists(atPath: file, isDirectory: &isDirectory), isDirectory.boolValue {
1544+
do {
1545+
let result = try createArchiveForDirectory(file, destinationPath: destinationPath)
1546+
localPath = result.localPath
1547+
remotePath = result.remotePath
1548+
tempArchivePath = result.tempArchivePath
1549+
} catch {
1550+
DLog("Failed to create tgz archive: \(error)")
1551+
completion(false, error.localizedDescription)
1552+
return nil
1553+
}
1554+
} else {
1555+
localPath = file
1556+
remotePath = destinationPath
1557+
tempArchivePath = nil
1558+
}
1559+
1560+
let transfer = ConductorFileTransfer(path: remotePath,
1561+
localPath: localPath,
1562+
data: nil,
1563+
delegate: self)
1564+
transfer.completionBlock = { success, error in
1565+
// Clean up temp archive if we created one
1566+
if let tempPath = tempArchivePath {
1567+
try? FileManager.default.removeItem(atPath: tempPath)
1568+
}
1569+
completion(success, error)
1570+
}
1571+
transfer.upload()
1572+
return transfer
1573+
}
1574+
1575+
private struct DirectoryArchiveResult {
1576+
let localPath: String
1577+
let remotePath: SCPPath
1578+
let tempArchivePath: String
1579+
}
1580+
1581+
private func createArchiveForDirectory(_ directoryPath: String, destinationPath: SCPPath) throws -> DirectoryArchiveResult {
1582+
DLog("Converting directory to tgz for conductor upload: \(directoryPath)")
1583+
1584+
let tempPath = try NSData.temporaryTGZArchive(ofDirectory: directoryPath)
1585+
1586+
let remotePath = SCPPath()
1587+
remotePath.hostname = destinationPath.hostname
1588+
remotePath.username = destinationPath.username
1589+
remotePath.path = destinationPath.path + ".tgz"
1590+
1591+
return DirectoryArchiveResult(localPath: tempPath, remotePath: remotePath, tempArchivePath: tempPath)
15361592
}
15371593

15381594
private var jumpScript: String {

sources/FileTransferManager.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,14 @@ - (void)transferrableFile:(TransferrableFile *)transferrableFile
343343

344344
TransferrableFileMenuItemViewController *controller = [self viewControllerForTransferrableFile:transferrableFile];
345345
[controller update];
346+
347+
// Call the completion block if set
348+
if (transferrableFile.completionBlock) {
349+
BOOL success = (error == nil);
350+
NSString *errorMessage = error.localizedDescription;
351+
transferrableFile.completionBlock(success, errorMessage);
352+
transferrableFile.completionBlock = nil; // Clear to avoid retain cycles
353+
}
346354
}
347355

348356
- (void)transferrableFileWillStop:(TransferrableFile *)transferrableFile {
@@ -357,6 +365,12 @@ - (void)transferrableFileDidStopTransfer:(TransferrableFile *)transferrableFile
357365
transferrableFile.status = kTransferrableFileStatusCancelled;
358366
TransferrableFileMenuItemViewController *controller = [self viewControllerForTransferrableFile:transferrableFile];
359367
[controller update];
368+
369+
// Call the completion block if set (transfer was cancelled)
370+
if (transferrableFile.completionBlock) {
371+
transferrableFile.completionBlock(NO, @"Transfer cancelled");
372+
transferrableFile.completionBlock = nil;
373+
}
360374
}
361375

362376

sources/NSData+iTerm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ NS_ASSUME_NONNULL_BEGIN
2727
includeExtendedAttrs:(BOOL)includeExtendedAttrs
2828
error:(NSError * _Nullable __autoreleasing * _Nullable)error;
2929

30+
// Creates a .tgz archive of the given directory and writes it to a temp file.
31+
// Returns the path to the temp file on success, or nil on failure.
32+
+ (NSString * _Nullable)temporaryTGZArchiveOfDirectory:(NSString *)directoryPath
33+
error:(NSError * _Nullable __autoreleasing * _Nullable)error;
34+
3035
// returns a string the the data base-64 encoded into 77-column lines divided by lineBreak.
3136
- (NSString *)stringWithBase64EncodingWithLineBreak:(NSString *)lineBreak;
3237

sources/NSData+iTerm.m

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,50 @@ + (NSData *)dataWithTGZContainingFiles:(NSArray<NSString *> *)files
152152
return data;
153153
}
154154

155+
+ (NSString *)temporaryTGZArchiveOfDirectory:(NSString *)directoryPath
156+
error:(NSError **)error {
157+
NSString *folderName = [directoryPath lastPathComponent];
158+
NSString *parentPath = [directoryPath stringByDeletingLastPathComponent];
159+
160+
NSError *archiveError = nil;
161+
NSData *archiveData = [NSData dataWithTGZContainingFiles:@[folderName]
162+
relativeToPath:parentPath
163+
includeExtendedAttrs:NO
164+
error:&archiveError];
165+
// Note: archiveError may be set even on success (e.g., tar warnings to stderr).
166+
// Only fail if we didn't get any data back.
167+
if (!archiveData) {
168+
DLog(@"Failed to create tgz archive: %@", archiveError);
169+
if (error) {
170+
*error = archiveError ?: [NSError errorWithDomain:@"com.googlecode.iterm2"
171+
code:-1
172+
userInfo:@{ NSLocalizedDescriptionKey: @"Failed to create archive of folder." }];
173+
}
174+
return nil;
175+
}
176+
if (archiveError) {
177+
DLog(@"tgz archive created with warning: %@", archiveError);
178+
}
179+
180+
// Write archive to temp file
181+
NSString *tempDir = NSTemporaryDirectory();
182+
NSString *archiveName = [folderName stringByAppendingString:@".tgz"];
183+
NSString *tempPath = [tempDir stringByAppendingPathComponent:archiveName];
184+
185+
if (![archiveData writeToFile:tempPath atomically:YES]) {
186+
DLog(@"Failed to write temp archive to %@", tempPath);
187+
if (error) {
188+
*error = [NSError errorWithDomain:@"com.googlecode.iterm2"
189+
code:-1
190+
userInfo:@{ NSLocalizedDescriptionKey: @"Failed to write temporary archive file." }];
191+
}
192+
return nil;
193+
}
194+
DLog(@"Created temp archive at %@ (%lu bytes)", tempPath, (unsigned long)archiveData.length);
195+
196+
return tempPath;
197+
}
198+
155199
- (BOOL)containsAsciiCharacterInSet:(NSCharacterSet *)asciiSet {
156200
char flags[256];
157201
for (int i = 0; i < 256; i++) {

sources/NSPasteboard+iTerm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,13 @@
1313
- (NSArray *)filenamesOnPasteboardWithShellEscaping:(BOOL)escape forPaste:(BOOL)forPaste;
1414
- (NSData *)dataForFirstFile;
1515

16+
// Check for raw image data (not from a file URL)
17+
- (BOOL)hasRawImageData;
18+
- (NSData *)rawImageData;
19+
- (NSString *)rawImageDataUTType;
20+
21+
// Check for file URLs
22+
- (BOOL)hasFileURLs;
23+
- (NSArray<NSString *> *)filePaths;
24+
1625
@end

sources/NSPasteboard+iTerm.m

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
//
88

99
#import "NSPasteboard+iTerm.h"
10+
#import "DebugLogging.h"
1011
#import "NSStringITerm.h"
1112
#import "iTermPreferences.h"
13+
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
1214

1315
@implementation NSPasteboard (iTerm)
1416

@@ -53,4 +55,68 @@ - (NSData *)dataForFirstFile {
5355
return nil;
5456
}
5557

58+
// Returns the UTType identifier for available image data, or nil if none.
59+
// Only checks type availability - does not fetch or decode any data.
60+
- (NSString *)rawImageDataUTType {
61+
// Don't report image data if we have file URLs - those take precedence
62+
if ([self hasFileURLs]) {
63+
return nil;
64+
}
65+
NSArray<NSString *> *imageTypeIdentifiers = @[
66+
UTTypePNG.identifier,
67+
UTTypeJPEG.identifier,
68+
UTTypeTIFF.identifier,
69+
UTTypeBMP.identifier,
70+
UTTypeGIF.identifier,
71+
UTTypeWebP.identifier,
72+
UTTypeHEIC.identifier
73+
];
74+
return [self availableTypeFromArray:imageTypeIdentifiers];
75+
}
76+
77+
- (BOOL)hasRawImageData {
78+
return [self rawImageDataUTType] != nil;
79+
}
80+
81+
// Fetches the raw bytes for the available image type.
82+
// Only call this when you actually need the data.
83+
- (NSData *)rawImageData {
84+
NSString *type = [self rawImageDataUTType];
85+
if (!type) {
86+
return nil;
87+
}
88+
return [self dataForType:type];
89+
}
90+
91+
- (BOOL)hasFileURLs {
92+
DLog(@"hasFileURLs: pasteboard types=%@", self.types);
93+
NSString *bestType = [self availableTypeFromArray:@[ NSPasteboardTypeFileURL ]];
94+
DLog(@"hasFileURLs: bestType=%@", bestType);
95+
if (![bestType isEqualToString:NSPasteboardTypeFileURL]) {
96+
DLog(@"hasFileURLs: no file URL type available");
97+
return NO;
98+
}
99+
NSArray<NSURL *> *urls = [self readObjectsForClasses:@[ [NSURL class] ] options:0];
100+
DLog(@"hasFileURLs: urls=%@", urls);
101+
for (NSURL *url in urls) {
102+
if (url.isFileURL) {
103+
DLog(@"hasFileURLs: found file URL %@", url);
104+
return YES;
105+
}
106+
}
107+
DLog(@"hasFileURLs: no file URLs found");
108+
return NO;
109+
}
110+
111+
- (NSArray<NSString *> *)filePaths {
112+
NSMutableArray<NSString *> *paths = [NSMutableArray array];
113+
NSArray<NSURL *> *urls = [self readObjectsForClasses:@[ [NSURL class] ] options:0];
114+
for (NSURL *url in urls) {
115+
if (url.isFileURL && url.path) {
116+
[paths addObject:url.path];
117+
}
118+
}
119+
return paths;
120+
}
121+
56122
@end

sources/PTYSession+Private.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,16 @@
3939
@class iTermComposerManager;
4040
@class iTermConductor;
4141
@class AITermControllerObjC;
42+
@class iTermNonTextPasteHelper;
4243

4344
@interface PTYSession () <
4445
iTermAutomaticProfileSwitcherDelegate,
4546
iTermBackgroundDrawingHelperDelegate,
4647
iTermBadgeLabelDelegate,
48+
iTermComposerManagerDelegate,
49+
iTermConductorDelegate,
4750
iTermCoprocessDelegate,
4851
iTermCopyModeHandlerDelegate,
49-
iTermConductorDelegate,
50-
iTermComposerManagerDelegate,
5152
iTermFilterDestination,
5253
iTermHotKeyNavigableSession,
5354
iTermImmutableColorMapDelegate,
@@ -58,20 +59,21 @@ iTermMetalGlueDelegate,
5859
iTermModernKeyMapperDelegate,
5960
iTermModifyOtherKeysMapperDelegate,
6061
iTermNaggingControllerDelegate,
62+
iTermNonTextPasteHelperDelegate,
6163
iTermObject,
6264
iTermPasteHelperDelegate,
6365
iTermPasteboardReporterDelegate,
66+
iTermSessionDirectoryTrackerDelegate,
6467
iTermSessionNameControllerDelegate,
6568
iTermSessionViewDelegate,
6669
iTermShortcutNavigationModeHandlerDelegate,
6770
iTermStandardKeyMapperDelegate,
6871
iTermStatusBarViewControllerDelegate,
6972
iTermTailFindControllerDelegate,
7073
iTermTermkeyKeyMapperDelegate,
71-
iTermTriggersDataSource,
7274
iTermTmuxControllerSession,
75+
iTermTriggersDataSource,
7376
iTermUpdateCadenceControllerDelegate,
74-
iTermSessionDirectoryTrackerDelegate,
7577
TriggerDelegate> {
7678
// Changes are made in the main thread to this and it periodically copied to the mutation thread.
7779
iTermExpect *_expect;
@@ -81,6 +83,8 @@ TriggerDelegate> {
8183
iTermComposerManager *_composerManager;
8284
iTermAppSwitchingPreventionDetector *_appSwitchingPreventionDetector;
8385
AITermControllerObjC *_aiterm;
86+
iTermNonTextPasteHelper *_nonTextPasteHelper;
87+
TransferrableFile *_uploadAndPasteTransfer; // Current upload for "upload and paste path" feature
8488
}
8589

8690
@property(nonatomic, retain) Interval *currentMarkOrNotePosition;

0 commit comments

Comments
 (0)