Permalink
Browse files

Fix handling of links containing underscores

  • Loading branch information...
1 parent 7b51b9a commit 1760fc2a3e3db9c0b05afd01d02fa1b54876028f @robbertkl robbertkl committed Feb 13, 2014
Showing with 54 additions and 6 deletions.
  1. +45 −6 Processing/GBCommentsProcessor.m
  2. +9 −0 Testing/GBCommentsProcessor-PreprocessingTesting.m
@@ -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;
@@ -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];
@@ -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 {
@@ -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 {

0 comments on commit 1760fc2

Please sign in to comment.