Skip to content

Commit

Permalink
Merge pull request #426 from robbertkl/url-fix
Browse files Browse the repository at this point in the history
Fix handling of links containing underscores
  • Loading branch information
tomaz committed Feb 14, 2014
2 parents 7b51b9a + 1760fc2 commit 3fc19dc
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
51 changes: 45 additions & 6 deletions Processing/GBCommentsProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ - (BOOL)isLineMatchingDirectiveStatement:(NSString *)string;
- (GBCommentComponent *)commentComponentByPreprocessingString:(NSString *)string withFlags:(GBProcessingFlag)flags;
- (GBCommentComponent *)commentComponentWithStringValue:(NSString *)string;
- (NSString *)stringByPreprocessingString:(NSString *)string withFlags:(GBProcessingFlag)flags;
- (NSString *)stringByPreprocessingNonLinkString:(NSString *)string withFlags:(GBProcessingFlag)flags;
- (NSString *)stringByConvertingCrossReferencesInString:(NSString *)string withFlags:(GBProcessingFlag)flags;
- (NSString *)stringByConvertingSimpleCrossReferencesInString:(NSString *)string searchRange:(NSRange)searchRange flags:(GBProcessingFlag)flags;
- (NSString *)markdownLinkWithDescription:(NSString *)description address:(NSString *)address flags:(GBProcessingFlag)flags;
Expand Down Expand Up @@ -605,6 +606,49 @@ - (NSString *)stringByPreprocessingString:(NSString *)string withFlags:(GBProces
// Converts all appledoc formatting and cross refs to proper Markdown text suitable for passing to Markdown generator.
if ([string length] == 0) return string;

// Process all links separately, so that they won't be cut off if the contain _'s (which is a formatting marker)
NSString *pattern = @"(\\[.+?\\]\\(.+?\\))";
NSArray *components = [string arrayOfDictionariesByMatchingRegex:pattern withKeysAndCaptures:@"link", 1, nil];
NSRange searchRange = NSMakeRange(0, [string length]);
NSMutableString *result = [NSMutableString stringWithCapacity:[string length]];
for (NSDictionary *component in components) {
NSString *componentLink = [component objectForKey:@"link"];
NSRange componentRange = [string rangeOfString:componentLink options:0 range:searchRange];

if (componentRange.location > searchRange.location) {
NSRange skippedRange = NSMakeRange(searchRange.location, componentRange.location - searchRange.location);
NSString *skippedText = [string substringWithRange:skippedRange];
NSString *preprocessedText = [self stringByPreprocessingNonLinkString:skippedText withFlags:flags];
[result appendString:preprocessedText];
}

// Don't process the link using the formatting markers, might contain formatting markers
NSString *convertedLink = [self stringByConvertingCrossReferencesInString:componentLink withFlags:flags];
[result appendString:convertedLink];

NSUInteger location = componentRange.location + [componentLink length];
searchRange = NSMakeRange(location, [string length] - location);
}

// If there is some remaining text, preprocess it as well.
if ([string length] > searchRange.location) {
NSString *remainingText = [string substringWithRange:searchRange];
NSString *preprocessedText = [self stringByPreprocessingNonLinkString:remainingText withFlags:flags];
[result appendString:preprocessedText];
}

// Finally replace all embedded code span Markdown links to proper ones. Embedded links look like: `[`desc`](address)`.
NSString *regex = [NSString stringWithFormat:@"`((?:%@)?\\[`[^`]*`\\]\\(.+?\\)(?:%@)?)`", self.components.codeSpanStartMarker, self.components.codeSpanEndMarker];
NSString *clean = [result stringByReplacingOccurrencesOfRegex:regex usingBlock:^NSString *(NSInteger captureCount, NSString *const *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
return capturedStrings[1];
}];
return clean;
}

- (NSString *)stringByPreprocessingNonLinkString:(NSString *)string withFlags:(GBProcessingFlag)flags {
// Converts all appledoc formatting and cross refs to proper Markdown text suitable for passing to Markdown generator.
if ([string length] == 0) return string;

// Formatting markers are fine, except *, which should be converted to **. To simplify cross refs detection, we handle all possible formatting markers though so we can search for cross refs within "clean" formatted text, without worrying about markers interfering with search. Note that we also handle "standard" Markdown nested formats and bold markers here, so that we properly handle cross references within.
NSString *pattern = @"(?s:(\\*__|__\\*|\\*\\*_|_\\*\\*|\\*\\*\\*|___|\\*_|_\\*|\\*\\*|__|\\*|_|==!!==|`)(.+?)\\1)";
NSArray *components = [string arrayOfDictionariesByMatchingRegex:pattern withKeysAndCaptures:@"marker", 1, @"value", 2, nil];
Expand Down Expand Up @@ -677,12 +721,7 @@ - (NSString *)stringByPreprocessingString:(NSString *)string withFlags:(GBProces
[result appendString:convertedText];
}

// Finally replace all embedded code span Markdown links to proper ones. Embedded links look like: `[`desc`](address)`.
NSString *regex = [NSString stringWithFormat:@"`((?:%@)?\\[`[^`]*`\\]\\(.+?\\)(?:%@)?)`", self.components.codeSpanStartMarker, self.components.codeSpanEndMarker];
NSString *clean = [result stringByReplacingOccurrencesOfRegex:regex usingBlock:^NSString *(NSInteger captureCount, NSString *const *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
return capturedStrings[1];
}];
return clean;
return result;
}

- (NSString *)stringByConvertingCrossReferencesInString:(NSString *)string withFlags:(GBProcessingFlag)flags {
Expand Down
9 changes: 9 additions & 0 deletions Testing/GBCommentsProcessor-PreprocessingTesting.m
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,15 @@ - (void)testStringByPreprocessingString_shouldLeaveMarkdownBoldItalicsMarkers {
assertThat(result6, is(@"***text1*** *** marked ***"));
}

- (void)testStringByPreprocessingString_shouldKeepReferencesWithMarkersIntact {
// setup
GBCommentsProcessor *processor = [self defaultProcessor];
// execute
NSString *result = [processor stringByPreprocessingString:@"[test_test](http://www.example.com/test_test.html)" withFlags:0];
// verify
assertThat(result, is(@"[test_test](http://www.example.com/test_test.html)"));
}

#pragma mark Class, category and protocol cross references detection

- (void)testStringByConvertingCrossReferencesInString_shouldConvertClass {
Expand Down

0 comments on commit 3fc19dc

Please sign in to comment.