Skip to content
Snippets Groups Projects
Commit b8ec5e2e authored by George Nachman's avatar George Nachman
Browse files

Half done. I bailed on fixing...

Half done. I bailed on fixing pathOfExistinFileFoundWithPrefix:suffix:workingDirectory:trimWhitespace:completion
parent 23650976
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -39,6 +39,10 @@
- (BOOL)fileExistsAtPathLocally:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkpaths;
 
- (void)asyncFileExistsAtPathLocally:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkPaths
completion:(void (^)(BOOL))completion;
- (BOOL)fileHasForbiddenPrefix:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkpaths;
 
Loading
Loading
Loading
Loading
@@ -226,6 +226,32 @@ NSString * const DirectoryLocationDomain = @"DirectoryLocationDomain";
return NO;
}
 
- (void)asyncFileExistsAtPathLocally:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkPaths
completion:(void (^)(BOOL))completion {
if ([self fileHasForbiddenPrefix:filename additionalNetworkPaths:additionalNetworkPaths]) {
return completion(NO);
}
static dispatch_once_t onceToken;
__block dispatch_queue_t statfsQueue;
dispatch_once(&onceToken, ^{
statfsQueue = dispatch_queue_create("com.iterm2.statfs", DISPATCH_QUEUE_SERIAL);
});
NSString *filenameCopy = [filename copy];
dispatch_async(statfsQueue, ^{
struct statfs buf;
int rc = statfs([filenameCopy UTF8String], &buf);
[filenameCopy release];
dispatch_async(dispatch_get_main_queue(), ^{
if (rc != 0 || (buf.f_flags & MNT_LOCAL)) {
completion([self fileExistsAtPath:filename]);
} else {
completion(NO);
}
});
});
}
- (BOOL)fileExistsAtPathLocally:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkPaths {
if ([self fileHasForbiddenPrefix:filename additionalNetworkPaths:additionalNetworkPaths]) {
Loading
Loading
Loading
Loading
@@ -1757,7 +1757,7 @@ static const int kDragThreshold = 3;
}
 
// Update range of underlined chars indicating cmd-clicakble url.
- (URLAction *)updateUnderlinedURLs:(NSEvent *)event {
- (void)asyncUpdateUnderlinedURLs:(NSEvent *)event completion:(void (^)(URLAction *))completion {
URLAction *action = nil;
if (([event modifierFlags] & NSCommandKeyMask) && (self.window.isKeyWindow ||
[iTermAdvancedSettingsModel cmdClickWhenInactiveInvokesSemanticHistory])) {
Loading
Loading
@@ -1769,45 +1769,50 @@ static const int kDragThreshold = 3;
NSPoint locationInTextView = [self convertPoint:windowRect.origin fromView: nil];
if (!NSPointInRect(locationInTextView, [self bounds])) {
[self removeUnderline];
return action;
completion(action);
return;
}
NSPoint viewPoint = [self windowLocationToRowCol:windowRect.origin allowRightMarginOverflow:NO];
int x = viewPoint.x;
int y = viewPoint.y;
if (![iTermPreferences boolForKey:kPreferenceKeyCmdClickOpensURLs] || y < 0) {
[self removeUnderline];
return action;
completion(action);
return;
} else {
action = [self urlActionForClickAtX:x
y:y
respectingHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]];
if (action) {
_drawingHelper.underlinedRange = VT100GridAbsWindowedRangeFromRelative(action.range, [_dataSource totalScrollbackOverflow]);
if (action.actionType == kURLActionOpenURL) {
NSURL *url = [NSURL URLWithUserSuppliedString:action.string];
if (url && url.host) {
[self setNeedsDisplay:YES];
[self asyncUrlActionForClickAtX:x y:y respectingHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs] completion:^(URLAction *action) {
if (action) {
_drawingHelper.underlinedRange = VT100GridAbsWindowedRangeFromRelative(action.range, [_dataSource totalScrollbackOverflow]);
if (action.actionType == kURLActionOpenURL) {
NSURL *url = [NSURL URLWithUserSuppliedString:action.string];
if (url && url.host) {
[self setNeedsDisplay:YES];
}
}
[self setNeedsDisplay:YES];
completion(action);
} else {
[self removeUnderline];
completion(nil);
}
} else {
[self removeUnderline];
return action;
}
}];
}
} else {
[self removeUnderline];
return action;
completion(action);
return;
}
 
[self setNeedsDisplay:YES]; // It would be better to just display the underlined/formerly underlined area.
return action;
completion(nil);
}
 
- (void)flagsChanged:(NSEvent *)theEvent {
URLAction *action = [self updateUnderlinedURLs:theEvent];
[self updateCursor:theEvent action:action];
[super flagsChanged:theEvent];
[self asyncUpdateUnderlinedURLs:theEvent completion:^(URLAction *action) {
[self updateCursor:theEvent action:action];
}];
}
 
- (void)swipeWithEvent:(NSEvent *)event
Loading
Loading
@@ -1865,7 +1870,8 @@ static const int kDragThreshold = 3;
[self setNeedsDisplay:YES];
}
[self resetMouseLocationToRefuseFirstResponderAt];
[self updateUnderlinedURLs:event];
[self asyncUpdateUnderlinedURLs:event
completion:^(URLAction *action) { }];
[_delegate textViewShowHoverURL:nil];
}
 
Loading
Loading
@@ -1879,7 +1885,9 @@ static const int kDragThreshold = 3;
[self setNeedsDisplay:YES];
}
}
[self updateCursor:event action:[self updateUnderlinedURLs:event]];
[self asyncUpdateUnderlinedURLs:event completion:^(URLAction *action) {
[self updateCursor:event action:action];
}];
if ([iTermPreferences boolForKey:kPreferenceKeyFocusFollowsMouse] &&
[[self window] alphaValue] > 0 &&
![NSApp modalWindow]) {
Loading
Loading
@@ -2386,9 +2394,10 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
 
- (void)mouseMoved:(NSEvent *)event {
[self resetMouseLocationToRefuseFirstResponderAt];
URLAction *action = [self updateUnderlinedURLs:event];
[self asyncUpdateUnderlinedURLs:event completion:^(URLAction *action) {
[self updateCursor:event action:action];
}];
[self reportMouseEvent:event];
[self updateCursor:event action:action];
}
 
- (void)mouseDragged:(NSEvent *)event
Loading
Loading
@@ -2479,40 +2488,39 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
_semanticHistoryDragged = YES;
 
// Drag a file handle (only possible when there is no selection).
URLAction *action = [self urlActionForClickAtX:x y:y];
NSString *path = action.fullPath;
if (path == nil) {
DLog(@"path is nil");
return;
}
NSPoint dragPosition;
NSImage *dragImage;
[self asyncUrlActionForClickAtX:x y:y completion:^(URLAction *action) {
NSString *path = action.fullPath;
if (path == nil) {
DLog(@"path is nil");
return;
}
 
dragImage = [[NSWorkspace sharedWorkspace] iconForFile:path];
dragPosition = [self convertPoint:[event locationInWindow] fromView:nil];
dragPosition.x -= [dragImage size].width / 2;
NSPoint dragPosition;
NSImage *dragImage;
 
NSURL *url = [[[NSURL alloc] initWithScheme:@"file" host:nil path:path] autorelease];
dragImage = [[NSWorkspace sharedWorkspace] iconForFile:path];
dragPosition = [self convertPoint:[event locationInWindow] fromView:nil];
dragPosition.x -= [dragImage size].width / 2;
 
NSPasteboardItem *pbItem = [[[NSPasteboardItem alloc] init] autorelease];
[pbItem setString:[url absoluteString] forType:(NSString *)kUTTypeFileURL];
NSDraggingItem *dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease];
[dragItem setDraggingFrame:NSMakeRect(dragPosition.x, dragPosition.y, dragImage.size.width, dragImage.size.height)
contents:dragImage];
NSDraggingSession *draggingSession = [self beginDraggingSessionWithItems:@[ dragItem ]
event:event
source:self];
NSURL *url = [[[NSURL alloc] initWithScheme:@"file" host:nil path:path] autorelease];
 
draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
draggingSession.draggingFormation = NSDraggingFormationNone;
NSPasteboardItem *pbItem = [[[NSPasteboardItem alloc] init] autorelease];
[pbItem setString:[url absoluteString] forType:(NSString *)kUTTypeFileURL];
NSDraggingItem *dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease];
[dragItem setDraggingFrame:NSMakeRect(dragPosition.x, dragPosition.y, dragImage.size.width, dragImage.size.height)
contents:dragImage];
NSDraggingSession *draggingSession = [self beginDraggingSessionWithItems:@[ dragItem ]
event:event
source:self];
 
// Valid drag, so we reset the flag because mouseUp doesn't get called when a drag is done
_semanticHistoryDragged = NO;
DLog(@"did semantic history drag");
draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
draggingSession.draggingFormation = NSDraggingFormationNone;
 
// Valid drag, so we reset the flag because mouseUp doesn't get called when a drag is done
_semanticHistoryDragged = NO;
DLog(@"did semantic history drag");
}];
return;
}
 
[_selectionScrollHelper mouseDraggedTo:locationInTextView coord:VT100GridCoordMake(x, y)];
Loading
Loading
@@ -2540,71 +2548,72 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
iTermTextExtractor *extractor = [iTermTextExtractor textExtractorWithDataSource:_dataSource];
VT100GridCoord coord = VT100GridCoordMake(x, y);
 
URLAction *action = [self urlActionForClickAtX:x y:y];
DLog(@"openTargetWithEvent has action=%@", action);
if (action) {
switch (action.actionType) {
case kURLActionOpenExistingFile: {
NSString *extendedPrefix = [extractor wrappedStringAt:coord
forward:NO
respectHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]
maxChars:[iTermAdvancedSettingsModel maxSemanticHistoryPrefixOrSuffix]
continuationChars:nil
convertNullsToSpace:YES
coords:nil];
NSString *extendedSuffix = [extractor wrappedStringAt:coord
forward:YES
respectHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]
maxChars:[iTermAdvancedSettingsModel maxSemanticHistoryPrefixOrSuffix]
continuationChars:nil
convertNullsToSpace:YES
coords:nil];
if (![self openSemanticHistoryPath:action.string
workingDirectory:action.workingDirectory
prefix:extendedPrefix
suffix:extendedSuffix]) {
[self findUrlInString:action.string andOpenInBackground:openInBackground];
[self asyncUrlActionForClickAtX:x y:y completion:^(URLAction *action) {
DLog(@"openTargetWithEvent has action=%@", action);
if (action) {
switch (action.actionType) {
case kURLActionOpenExistingFile: {
NSString *extendedPrefix = [extractor wrappedStringAt:coord
forward:NO
respectHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]
maxChars:[iTermAdvancedSettingsModel maxSemanticHistoryPrefixOrSuffix]
continuationChars:nil
convertNullsToSpace:YES
coords:nil];
NSString *extendedSuffix = [extractor wrappedStringAt:coord
forward:YES
respectHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]
maxChars:[iTermAdvancedSettingsModel maxSemanticHistoryPrefixOrSuffix]
continuationChars:nil
convertNullsToSpace:YES
coords:nil];
if (![self openSemanticHistoryPath:action.string
workingDirectory:action.workingDirectory
prefix:extendedPrefix
suffix:extendedSuffix]) {
[self findUrlInString:action.string andOpenInBackground:openInBackground];
}
break;
}
break;
}
case kURLActionOpenURL: {
NSURL *url = [NSURL URLWithUserSuppliedString:action.string];
if ([url.scheme isEqualToString:@"file"] && url.host.length > 0 && ![url.host isEqualToString:[VT100RemoteHost localHostName]]) {
SCPPath *path = [[[SCPPath alloc] init] autorelease];
path.path = url.path;
path.hostname = url.host;
path.username = [PTYTextView usernameToDownloadFileOnHost:url.host];
if (path.username == nil) {
return;
case kURLActionOpenURL: {
NSURL *url = [NSURL URLWithUserSuppliedString:action.string];
if ([url.scheme isEqualToString:@"file"] && url.host.length > 0 && ![url.host isEqualToString:[VT100RemoteHost localHostName]]) {
SCPPath *path = [[[SCPPath alloc] init] autorelease];
path.path = url.path;
path.hostname = url.host;
path.username = [PTYTextView usernameToDownloadFileOnHost:url.host];
if (path.username == nil) {
return;
}
[self downloadFileAtSecureCopyPath:path
displayName:url.path.lastPathComponent
locationInView:action.range.coordRange];
} else {
[self openURL:url inBackground:openInBackground];
}
[self downloadFileAtSecureCopyPath:path
displayName:url.path.lastPathComponent
locationInView:action.range.coordRange];
} else {
[self openURL:url inBackground:openInBackground];
break;
}
break;
}
 
case kURLActionSmartSelectionAction: {
DLog(@"Run smart selection selector %@", NSStringFromSelector(action.selector));
[self performSelector:action.selector withObject:action];
break;
}
case kURLActionSmartSelectionAction: {
DLog(@"Run smart selection selector %@", NSStringFromSelector(action.selector));
[self performSelector:action.selector withObject:action];
break;
}
 
case kURLActionOpenImage:
DLog(@"Open image");
[[NSWorkspace sharedWorkspace] openFile:[(iTermImageInfo *)action.identifier nameForNewSavedTempFile]];
break;
case kURLActionOpenImage:
DLog(@"Open image");
[[NSWorkspace sharedWorkspace] openFile:[(iTermImageInfo *)action.identifier nameForNewSavedTempFile]];
break;
 
case kURLActionSecureCopyFile:
DLog(@"Secure copy file.");
[self downloadFileAtSecureCopyPath:action.identifier
displayName:action.string
locationInView:action.range.coordRange];
break;
case kURLActionSecureCopyFile:
DLog(@"Secure copy file.");
[self downloadFileAtSecureCopyPath:action.identifier
displayName:action.string
locationInView:action.range.coordRange];
break;
}
}
}
}];
}
 
- (BOOL)openSemanticHistoryPath:(NSString *)path
Loading
Loading
@@ -6107,20 +6116,23 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
}
 
 
- (URLAction *)urlActionForClickAtX:(int)x
y:(int)y
respectingHardNewlines:(BOOL)respectHardNewlines {
- (void)asyncUrlActionForClickAtX:(int)x
y:(int)y
respectingHardNewlines:(BOOL)respectHardNewlines
completion:(void (^)(URLAction *))completion {
DLog(@"urlActionForClickAt:%@,%@ respectingHardNewlines:%@",
@(x), @(y), @(respectHardNewlines));
 
const VT100GridCoord coord = VT100GridCoordMake(x, y);
iTermImageInfo *imageInfo = [self imageInfoAtCoord:coord];
if (imageInfo) {
return [URLAction urlActionToOpenImage:imageInfo];
completion([URLAction urlActionToOpenImage:imageInfo]);
return;
}
iTermTextExtractor *extractor = [iTermTextExtractor textExtractorWithDataSource:_dataSource];
if ([extractor characterAt:coord].code == 0) {
return nil;
completion(nil);
return;
}
[extractor restrictToLogicalWindowIncludingCoord:coord];
 
Loading
Loading
@@ -6133,17 +6145,18 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
DLog(@"It is %@", workingDirectory);
}
 
return [iTermURLActionFactory urlActionAtCoord:VT100GridCoordMake(x, y)
respectHardNewlines:respectHardNewlines
workingDirectory:workingDirectory ?: @""
remoteHost:[_dataSource remoteHostOnLine:y]
selectors:[self smartSelectionActionSelectorDictionary]
rules:_smartSelectionRules
extractor:extractor
semanticHistoryController:self.semanticHistoryController
pathFactory:^SCPPath *(NSString *path, int line) {
return [_dataSource scpPathForFile:path onLine:line];
}];
[iTermURLActionFactory asyncUrlActionAtCoord:VT100GridCoordMake(x, y)
respectHardNewlines:respectHardNewlines
workingDirectory:workingDirectory ?: @""
remoteHost:[_dataSource remoteHostOnLine:y]
selectors:[self smartSelectionActionSelectorDictionary]
rules:_smartSelectionRules
extractor:extractor
semanticHistoryController:self.semanticHistoryController
pathFactory:^SCPPath *(NSString *path, int line) {
return [_dataSource scpPathForFile:path onLine:line];
}
completion:completion];
}
 
- (void)imageDidLoad:(NSNotification *)notification {
Loading
Loading
@@ -6170,12 +6183,13 @@ static double EuclideanDistance(NSPoint p1, NSPoint p2) {
return NO;
}
 
- (URLAction *)urlActionForClickAtX:(int)x y:(int)y {
- (void)asyncUrlActionForClickAtX:(int)x y:(int)y completion:(void (^)(URLAction *action))completion {
// I tried respecting hard newlines if that is a legal URL, but that's such a broad definition
// that it doesn't work well. Hard EOLs mid-url are very common. Let's try always ignoring them.
return [self urlActionForClickAtX:x
y:y
respectingHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]];
return [self asyncUrlActionForClickAtX:x
y:y
respectingHardNewlines:![iTermAdvancedSettingsModel ignoreHardNewlinesInURLs]
completion:completion];
}
 
- (NSDragOperation)dragOperationForSender:(id<NSDraggingInfo>)sender {
Loading
Loading
Loading
Loading
@@ -42,13 +42,11 @@ extern NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey;
@property (nonatomic, assign) id<iTermSemanticHistoryControllerDelegate> delegate;
@property (nonatomic, readonly) BOOL activatesOnAnyString; // Doesn't have to be a real file?
 
// Given a possibly relative |path| and |workingDirectory|, returns the absolute path. If |path|
// includes a line number then *lineNumber will be filled in with it. Files on network shares are
// rejected.
- (NSString *)getFullPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
lineNumber:(NSString **)lineNumber
columnNumber:(NSString **)columnNumber;
// Given a possibly relative |path| and |workingDirectory|, returns the absolute path.
// Files on network shares are rejected.
- (void)asyncGetFullPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
completion:(void (^)(NSString *path, NSString *lineNumber, NSString *columnNumber))completion;
 
// Opens the file at the relative |path| (which may include :lineNumber) in |workingDirectory|.
// The |substitutions| dictionary is used to expand \references in the command to run (gotten from
Loading
Loading
Loading
Loading
@@ -53,16 +53,15 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
additionalNetworkPaths:[[iTermAdvancedSettingsModel pathsToIgnore] componentsSeparatedByString:@","]];
}
 
- (NSString *)getFullPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
lineNumber:(NSString **)lineNumber
columnNumber:(NSString **)columnNumber {
- (void)asyncGetFullPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
completion:(void (^)(NSString *path, NSString *lineNumber, NSString *columnNumber))completion {
DLog(@"Check if %@ is a valid path in %@", path, workingDirectory);
NSString *origPath = path;
// TODO(chendo): Move regex, define capture semantics in config file/prefs
if (!path || [path length] == 0) {
DLog(@" no: it is empty");
return nil;
completion(nil, nil, nil);
}
 
// If it's in any form of bracketed delimiters, strip them
Loading
Loading
@@ -73,19 +72,15 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
withString:@""];
DLog(@" Strip trailing chars, leaving %@", path);
 
if (lineNumber != nil) {
*lineNumber = [path stringByMatching:@":(\\d+)" capture:1];
}
if (columnNumber != nil) {
*columnNumber = [path stringByMatching:@":(\\d+):(\\d+)" capture:2];
}
NSString *lineNumberResult = [path stringByMatching:@":(\\d+)" capture:1];
NSString *columnNumberResult = [path stringByMatching:@":(\\d+):(\\d+)" capture:2];
path = [[path stringByReplacingOccurrencesOfRegex:@":\\d*(?::.*)?$"
withString:@""]
stringByExpandingTildeInPath];
DLog(@" Strip line number suffix leaving %@", path);
if ([path length] == 0) {
// Everything was stripped out, meaning we'd try to open the working directory.
return nil;
return completion(nil, lineNumberResult, columnNumberResult);
}
if ([path rangeOfRegex:@"^/"].location == NSNotFound) {
path = [workingDirectory stringByAppendingPathComponent:path];
Loading
Loading
@@ -103,38 +98,39 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
// and respect for explicitly excluded paths. The latter category will now
// be stat()ed, although they were always stat()ed because of unintentional
// disk access in the old code.
if ([self fileExistsAtPathLocally:path]) {
DLog(@" YES: A file exists at %@", path);
NSURL *url = [NSURL fileURLWithPath:path];
// Resolve path by removing ./ and ../ etc
path = [[url standardizedURL] path];
DLog(@" Check standardized path for forbidden prefix %@", path);
if ([self fileHasForbiddenPrefix:path]) {
DLog(@" NO: Standardized path has forbidden prefix.");
return nil;
}
return path;
}
// If path doesn't exist and it starts with "a/" or "b/" (from `diff`).
if ([origPath isMatchedByRegex:@"^[ab]/"]) {
DLog(@" Treating as diff path");
// strip the prefix off ...
origPath = [origPath stringByReplacingOccurrencesOfRegex:@"^[ab]/"
withString:@""];
// ... and calculate the full path again
return [self getFullPath:origPath
workingDirectory:workingDirectory
lineNumber:lineNumber
columnNumber:columnNumber];
}
DLog(@" NO: no valid path found");
return nil;
[self.fileManager asyncFileExistsAtPathLocally:path
additionalNetworkPaths:[[iTermAdvancedSettingsModel pathsToIgnore] componentsSeparatedByString:@","]
completion:^(BOOL existsLocally) {
if (existsLocally) {
DLog(@" YES: A file exists at %@", path);
NSURL *url = [NSURL fileURLWithPath:path];
// Resolve path by removing ./ and ../ etc
NSString *path = [[url standardizedURL] path];
DLog(@" Check standardized path for forbidden prefix %@", path);
if ([self fileHasForbiddenPrefix:path]) {
DLog(@" NO: Standardized path has forbidden prefix.");
completion(nil, lineNumberResult, columnNumberResult);
}
completion(path, lineNumberResult, columnNumberResult);
} else if ([origPath isMatchedByRegex:@"^[ab]/"]) {
// If path doesn't exist and it starts with "a/" or "b/" (from `diff`).
DLog(@" Treating as diff path");
// strip the prefix off ...
NSString *pathWithoutDiffPrefix =
[origPath stringByReplacingOccurrencesOfRegex:@"^[ab]/"
withString:@""];
// ... and calculate the full path again
[self asyncGetFullPath:pathWithoutDiffPrefix
workingDirectory:workingDirectory
completion:completion];
} else {
DLog(@" NO: no valid path found");
completion(nil, nil, nil);
}
}];
}
 
- (NSString *)preferredEditorIdentifier {
Loading
Loading
@@ -325,16 +321,25 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
workingDirectory:(NSString *)workingDirectory
substitutions:(NSDictionary *)substitutions {
DLog(@"openPath:%@ workingDirectory:%@ substitutions:%@", path, workingDirectory, substitutions);
BOOL isDirectory;
NSString *lineNumber = @"";
NSString *columnNumber = @"";
 
BOOL isRawAction = [prefs_[kSemanticHistoryActionKey] isEqualToString:kSemanticHistoryRawCommandAction];
if (!isRawAction) {
path = [self getFullPath:path workingDirectory:workingDirectory lineNumber:&lineNumber columnNumber:&columnNumber];
[self asyncGetFullPath:path workingDirectory:workingDirectory completion:^(NSString *fullPath, NSString *lineNumber, NSString *columnNumber) {
[self reallyOpenPath:fullPath workingDirectory:workingDirectory substitutions:substitutions];
}];
DLog(@"Not a raw action. New path is %@, line number is %@", path, lineNumber);
}
 
[self reallyOpenPath:path workingDirectory:workingDirectory substitutions:substitutions];
}
- (void)reallyOpenPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
substitutions:(NSDictionary *)substitutions {
BOOL isDirectory;
NSString *lineNumber = @"";
NSString *columnNumber = @"";
NSString *script = [prefs_ objectForKey:kSemanticHistoryTextKey];
NSMutableDictionary *augmentedSubs = [[substitutions mutableCopy] autorelease];
augmentedSubs[@"1"] = path ? [path stringWithEscapedShellCharactersIncludingNewlines:YES] : @"";
Loading
Loading
@@ -438,12 +443,11 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
return [iTermSemanticHistoryPrefsController bundleIdIsEditor:[self bundleIdForDefaultAppForFile:file]];
}
 
- (NSString *)pathOfExistingFileFoundWithPrefix:(NSString *)beforeStringIn
suffix:(NSString *)afterStringIn
workingDirectory:(NSString *)workingDirectory
charsTakenFromPrefix:(int *)charsTakenFromPrefixPtr
charsTakenFromSuffix:(int *)suffixChars
trimWhitespace:(BOOL)trimWhitespace {
- (void)asyncPathOfExistingFileFoundWithPrefix:(NSString *)beforeStringIn
suffix:(NSString *)afterStringIn
workingDirectory:(NSString *)workingDirectory
trimWhitespace:(BOOL)trimWhitespace
completion:(void (^)(NSString *path, int charsTakenFromPrefix, int suffixChars))completion {
BOOL workingDirectoryIsOk = [self fileExistsAtPathLocally:workingDirectory];
if (!workingDirectoryIsOk) {
DLog(@"Working directory %@ is a network share or doesn't exist. Not using it for context.",
Loading
Loading
@@ -504,41 +508,57 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
dispatch_once(&onceToken, ^{
questionableSuffixes = [@[ @"!", @"?", @".", @",", @";", @":", @"...", @"…" ] retain];
});
for (NSString *modifiedPossiblePath in [self pathsFromPath:trimmedPath byRemovingBadSuffixes:questionableSuffixes]) {
BOOL exists = NO;
if (workingDirectoryIsOk || [modifiedPossiblePath hasPrefix:@"/"]) {
exists = ([self getFullPath:modifiedPossiblePath workingDirectory:workingDirectory lineNumber:NULL columnNumber:NULL] != nil);
}
if (exists) {
if (charsTakenFromPrefixPtr) {
if (trimWhitespace &&
[[right stringByTrimmingTrailingCharactersFromCharacterSet:whitespaceCharset] length] == 0) {
// trimmedPath is trim(left + right). If trim(right) is empty
// then we don't want to count trailing whitespace from left in the chars
// taken from prefix.
*charsTakenFromPrefixPtr = [[left stringByTrimmingTrailingCharactersFromCharacterSet:whitespaceCharset] length];
} else {
*charsTakenFromPrefixPtr = left.length;
}
}
if (suffixChars) {
NSInteger lengthOfBadSuffix = trimmedPath.length - modifiedPossiblePath.length;
if (trimWhitespace) {
*suffixChars = [[right stringByTrimmingTrailingCharactersFromCharacterSet:whitespaceCharset] length] - lengthOfBadSuffix;
} else {
*suffixChars = right.length - lengthOfBadSuffix;
}
NSArray *possiblePaths = [self pathsFromPath:trimmedPath byRemovingBadSuffixes:questionableSuffixes];
if (possiblePath.count) {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self checkPaths:possiblePaths workingDirectoryIsOk:(BOOL)workingDirectoryIsOk completion:^(NSString *path, int charsTakenFromPrefix, int suffixChars) {
if (path) {
completion(path, charsTakenFromPrefix, suffixChars);
}
DLog(@"Using path %@", modifiedPossiblePath);
return modifiedPossiblePath;
}
dispatch_group_leave(group);
}];
}
if (--iterationsBeforeQuitting == 0) {
return nil;
completion(nil);
return;
}
}
}
return nil;
completion(nil);
}
- (void)checkPaths:(NSArray *)paths workingDirectoryIsOk:(BOOL)workingDirectoryIsOk completion:(void (^)(NSString *, int, int))completion {
NSString *modifiedPossiblePath = [paths firstObject];
paths = [paths subarrayWithRange:NSMakeRange(1, paths.count - 1)];
BOOL exists = NO;
if (workingDirectoryIsOk || [modifiedPossiblePath hasPrefix:@"/"]) {
[self asyncGetFullPath:modifiedPossiblePath workingDirectory:workingDirectory completion:^(NSString *path, NSString *lineNumber, NSString *columnNumber) {
BOOL exists = (path != nil);
if (exists) {
int charsTakenFromPrefixPtr;
if (trimWhitespace &&
[[right stringByTrimmingTrailingCharactersFromCharacterSet:whitespaceCharset] length] == 0) {
// trimmedPath is trim(left + right). If trim(right) is empty
// then we don't want to count trailing whitespace from left in the chars
// taken from prefix.
charsTakenFromPrefixPtr = [[left stringByTrimmingTrailingCharactersFromCharacterSet:whitespaceCharset] length];
} else {
charsTakenFromPrefixPtr = left.length;
}
int suffixChars;
NSInteger lengthOfBadSuffix = trimmedPath.length - modifiedPossiblePath.length;
if (trimWhitespace) {
suffixChars = [[right stringByTrimmingTrailingCharactersFromCharacterSet:whitespaceCharset] length] - lengthOfBadSuffix;
} else {
suffixChars = right.length - lengthOfBadSuffix;
}
DLog(@"Using path %@", modifiedPossiblePath);
completion(modifiedPossiblePath, charsTakenFromPrefixPtr, suffixChars);
}
}];
}
completion(nil, 0, 0);
}
 
- (NSArray *)pathsFromPath:(NSString *)source byRemovingBadSuffixes:(NSArray *)badSuffixes {
Loading
Loading
Loading
Loading
@@ -18,14 +18,15 @@
 
@interface iTermURLActionFactory : NSUserDefaults
 
+ (URLAction *)urlActionAtCoord:(VT100GridCoord)coord
respectHardNewlines:(BOOL)respectHardNewlines
workingDirectory:(NSString *)workingDirectory
remoteHost:(VT100RemoteHost *)remoteHost
selectors:(NSDictionary<NSNumber *, NSString *> *)selectors
rules:(NSArray *)rules
extractor:(iTermTextExtractor *)extractor
semanticHistoryController:(iTermSemanticHistoryController *)semanticHistoryController
pathFactory:(SCPPath *(^)(NSString *, int))pathFactory;
+ (void)asyncUrlActionAtCoord:(VT100GridCoord)coord
respectHardNewlines:(BOOL)respectHardNewlines
workingDirectory:(NSString *)workingDirectory
remoteHost:(VT100RemoteHost *)remoteHost
selectors:(NSDictionary<NSNumber *, NSString *> *)selectors
rules:(NSArray *)rules
extractor:(iTermTextExtractor *)extractor
semanticHistoryController:(iTermSemanticHistoryController *)semanticHistoryController
pathFactory:(SCPPath *(^)(NSString *, int))pathFactory
completion:(void (^)(URLAction *))completion;
 
@end
Loading
Loading
@@ -25,19 +25,21 @@
 
@implementation iTermURLActionFactory
 
+ (URLAction *)urlActionAtCoord:(VT100GridCoord)coord
respectHardNewlines:(BOOL)respectHardNewlines
workingDirectory:(NSString *)workingDirectory
remoteHost:(VT100RemoteHost *)remoteHost
selectors:(NSDictionary<NSNumber *, NSString *> *)selectors
rules:(NSArray *)rules
extractor:(iTermTextExtractor *)extractor
semanticHistoryController:(iTermSemanticHistoryController *)semanticHistoryController
pathFactory:(SCPPath *(^)(NSString *, int))pathFactory {
+ (void)asyncUrlActionAtCoord:(VT100GridCoord)coord
respectHardNewlines:(BOOL)respectHardNewlines
workingDirectory:(NSString *)workingDirectory
remoteHost:(VT100RemoteHost *)remoteHost
selectors:(NSDictionary<NSNumber *, NSString *> *)selectors
rules:(NSArray *)rules
extractor:(iTermTextExtractor *)extractor
semanticHistoryController:(iTermSemanticHistoryController *)semanticHistoryController
pathFactory:(SCPPath *(^)(NSString *, int))pathFactory
completion:(void (^)(URLAction *))completion {
URLAction *action;
action = [self urlActionForHypertextLinkAt:coord extractor:extractor];
if (action) {
return action;
completion(action);
return;
}
 
NSMutableIndexSet *continuationCharsCoords = [NSMutableIndexSet indexSet];
Loading
Loading
@@ -59,56 +61,63 @@
convertNullsToSpace:NO
coords:suffixCoords];
 
action = [self urlActionForExistingFileAt:coord
prefix:prefix
prefixCoords:prefixCoords
suffix:suffix
suffixCoords:suffixCoords
workingDirectory:workingDirectory
extractor:extractor
semanticHistoryController:semanticHistoryController];
if (action) {
return action;
}
action = [self urlActionForSmartSelectionAt:coord
respectHardNewlines:respectHardNewlines
workingDirectory:workingDirectory
remoteHost:remoteHost
rules:rules
selectors:selectors
textExtractor:extractor];
if (action) {
return action;
}
action = [self urlActionForAnyStringSemanticHistoryAt:coord
workingDirectory:workingDirectory
rules:rules
textExtractor:extractor
semanticHistoryController:semanticHistoryController];
if (action) {
return action;
}
// No luck. Look for something vaguely URL-like.
action = [self urlActionForURLAt:coord
prefix:prefix
prefixCoords:prefixCoords
suffix:suffix
suffixCoords:suffixCoords
extractor:extractor];
if (action) {
return action;
}
// TODO: We usually don't get here because "foo.txt" looks enough like a URL that we do a DNS
// lookup and fail. It'd be nice to fallback to an SCP file path.
// See if we can conjure up a secure copy path.
return [self urlActionWithSecureCopyAt:coord
rules:rules
textExtractor:extractor
pathFactory:pathFactory];
[self asyncUrlActionForExistingFileAt:coord
prefix:prefix
prefixCoords:prefixCoords
suffix:suffix
suffixCoords:suffixCoords
workingDirectory:workingDirectory
extractor:extractor
semanticHistoryController:semanticHistoryController
completion:^(URLAction *action) {
if (action) {
completion(action);
return;
} else {
action = [self urlActionForSmartSelectionAt:coord
respectHardNewlines:respectHardNewlines
workingDirectory:workingDirectory
remoteHost:remoteHost
rules:rules
selectors:selectors
textExtractor:extractor];
if (action) {
completion(action);
return;
}
action = [self urlActionForAnyStringSemanticHistoryAt:coord
workingDirectory:workingDirectory
rules:rules
textExtractor:extractor
semanticHistoryController:semanticHistoryController];
if (action) {
completion(action);
return;
}
// No luck. Look for something vaguely URL-like.
action = [self urlActionForURLAt:coord
prefix:prefix
prefixCoords:prefixCoords
suffix:suffix
suffixCoords:suffixCoords
extractor:extractor];
if (action) {
completion(action);
return;
}
// TODO: We usually don't get here because "foo.txt" looks enough like a URL that we do a DNS
// lookup and fail. It'd be nice to fallback to an SCP file path.
// See if we can conjure up a secure copy path.
action = [self urlActionWithSecureCopyAt:coord
rules:rules
textExtractor:extractor
pathFactory:pathFactory];
completion(action);
}
}];
}
 
#pragma mark - Sub-factories
Loading
Loading
@@ -138,14 +147,15 @@
}
}
 
+ (URLAction *)urlActionForExistingFileAt:(VT100GridCoord)coord
prefix:(NSString *)prefix
prefixCoords:(NSArray *)prefixCoords
suffix:(NSString *)suffix
suffixCoords:(NSArray *)suffixCoords
workingDirectory:(NSString *)workingDirectory
extractor:(iTermTextExtractor *)extractor
semanticHistoryController:(iTermSemanticHistoryController *)semanticHistoryController {
+ (void)asyncUrlActionForExistingFileAt:(VT100GridCoord)coord
prefix:(NSString *)prefix
prefixCoords:(NSArray *)prefixCoords
suffix:(NSString *)suffix
suffixCoords:(NSArray *)suffixCoords
workingDirectory:(NSString *)workingDirectory
extractor:(iTermTextExtractor *)extractor
semanticHistoryController:(iTermSemanticHistoryController *)semanticHistoryController
completion:(void (^)(URLAction *))completion {
NSString *possibleFilePart1 =
[prefix substringIncludingOffset:[prefix length] - 1
fromCharacterSet:[NSCharacterSet filenameCharacterSet]
Loading
Loading
@@ -195,16 +205,17 @@
range.coordRange.end = [extractor successorOfCoord:lastCoord];
range.columnWindow = extractor.logicalWindow;
action.range = range;
action.fullPath = [semanticHistoryController getFullPath:filename
workingDirectory:workingDirectory
lineNumber:NULL
columnNumber:NULL];
action.workingDirectory = workingDirectory;
return action;
action.workingDirectory = workingDirectory
[semanticHistoryController asyncGetFullPath:filename
workingDirectory:workingDirectory
completion:^(NSString *path, NSString *lineNumber, NSString *columnNumber) {
action.fullPath = path;
completion(action);
}];
}
 
return nil;
completion(nil);
}
 
+ (URLAction *)urlActionForSmartSelectionAt:(VT100GridCoord)coord
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment