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
This diff is collapsed.
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