diff --git a/TestXcodeColors/AppDelegate.m b/TestXcodeColors/AppDelegate.m index 55ab546..02f950b 100644 --- a/TestXcodeColors/AppDelegate.m +++ b/TestXcodeColors/AppDelegate.m @@ -1,4 +1,5 @@ #import "AppDelegate.h" +#import "XcodeColors.h" // How to apply color formatting to your log statements: // @@ -53,6 +54,57 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification NSLog(XCODE_COLORS_ESCAPE @"fg209,57,168;" @"You can supply your own RGB values!" XCODE_COLORS_RESET); LogBlue(@"Blue text via macro"); + + // [self testANSIColors]; +} + +- (void)testANSIColors { + + NSLog(@"\n=======Testing ANSI colors======="); + + //These correspond to the TRShellColor values + NSArray *colorNames = @[@"Black", @"Red", @"Green", @"Yellow", @"Blue", @"Magenta", @"Cyan", @"White"]; + + TRShellAttribute baseAttributes[] = {TRShellAttributeForegroundRegular, TRShellAttributeForegroundLight, TRShellAttributeBackgroundRegular, TRShellAttributeBackgroundLight}; + + TRShellColor colorCode; + for (NSInteger i = 0; i < 4; i++) { + + TRShellAttribute baseAttribute = baseAttributes[i]; + + // Test without reset + colorCode = TRShellColorBlack; + for (NSString *colorName in colorNames) { + + NSLog(@"%@%lum%@", XCODE_COLORS_ESCAPE, baseAttribute + colorCode++, colorName); + } + + NSLog(@"No Attribute"); + + + //Test with reset + colorCode = TRShellColorBlack; + for (NSString *colorName in colorNames) { + + NSLog(@"%@%lum%@%@", XCODE_COLORS_ESCAPE, baseAttribute + colorCode++, colorName, XCODE_COLORS_RESET); + } + + NSLog(@"No Attribute"); + } + + // Test setting both background and foreground + colorCode = TRShellColorBlack; + NSInteger count = 0; + + for (NSString *colorName in colorNames) { + + TRShellColor bgColorCode = [colorNames count] - (1 + count++); + NSString *bgColorName = colorNames[bgColorCode]; + NSLog(@"%@%lu;%lum%@-bg%@%@", XCODE_COLORS_ESCAPE, TRShellAttributeForegroundRegular + colorCode, TRShellAttributeBackgroundRegular + bgColorCode, colorName, bgColorName,XCODE_COLORS_RESET); + colorCode++; + } + + NSLog(@"No Attribute"); } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication diff --git a/XcodeColors/Info.plist b/XcodeColors/Info.plist index 7a237b5..fbc387f 100644 --- a/XcodeColors/Info.plist +++ b/XcodeColors/Info.plist @@ -12,13 +12,6 @@ ru.DeepIT.${PRODUCT_NAME} CFBundleInfoDictionaryVersion 6.0 - DVTPlugInCompatibilityUUIDs - - 63FC1C47-140D-42B0-BB4D-A10B2D225574 - 37B30044-3B14-46BA-ABAA-F01000C27B63 - 640F884E-CE55-4B40-87C0-8869546CAB7A - A2E4D43F-41F4-4FB9-BB94-7177011C9AED - CFBundleName ${PRODUCT_NAME} CFBundlePackageType @@ -29,6 +22,14 @@ ???? CFBundleVersion 109 + DVTPlugInCompatibilityUUIDs + + 63FC1C47-140D-42B0-BB4D-A10B2D225574 + 37B30044-3B14-46BA-ABAA-F01000C27B63 + 640F884E-CE55-4B40-87C0-8869546CAB7A + A2E4D43F-41F4-4FB9-BB94-7177011C9AED + AD68E85B-441B-4301-B564-A45E4919A6AD + LoadAtLaunch NSPrincipalClass @@ -44,13 +45,13 @@ com.apple.dt.Xcode - XCGCReady - - XCPluginHasUI - XC4Compatible XC5Compatible + XCGCReady + + XCPluginHasUI + diff --git a/XcodeColors/XcodeColors.h b/XcodeColors/XcodeColors.h index 27d4095..da62215 100644 --- a/XcodeColors/XcodeColors.h +++ b/XcodeColors/XcodeColors.h @@ -8,6 +8,81 @@ #import +typedef NS_OPTIONS(NSUInteger, TRShellColor) { + + TRShellColorBlack = 0, + TRShellColorRed, + TRShellColorGreen, + TRShellColorYellow, + TRShellColorBlue, + TRShellColorMagenta, + TRShellColorCyan, + TRShellColorWhite +}; + +typedef NS_ENUM(NSInteger, TRShellAttribute) { + + TRShellAttributeResetAll = 0, + /* TRShellAttributeBold = 1, + TRShellAttributeDim = 2, + TRShellAttributeUnderlined = 4, + TRShellAttributeBlink = 5, + TRShellAttributeInvert = 7, + TRShellAttributeHidden = 8, + + TRShellAttributeResetBold = 21, + TRShellAttributeResetDim = 22, + TRShellAttributeResetUnderlined = 24, + TRShellAttributeResetBlink = 25, + TRShellAttributeResetReverse = 27, + TRShellAttributeResetHidden = 28, + */ + + TRShellAttributeForegroundRegular = 30, + TRShellAttributeForegroundBlack = TRShellAttributeForegroundRegular + TRShellColorBlack, + TRShellAttributeForegroundRed = TRShellAttributeForegroundRegular + TRShellColorRed, + TRShellAttributeForegroundGreen = TRShellAttributeForegroundRegular + TRShellColorGreen, + TRShellAttributeForegroundYellow = TRShellAttributeForegroundRegular + TRShellColorYellow, + TRShellAttributeForegroundBlue = TRShellAttributeForegroundRegular + TRShellColorBlue, + TRShellAttributeForegroundMagenta = TRShellAttributeForegroundRegular + TRShellColorMagenta, + TRShellAttributeForegroundCyan = TRShellAttributeForegroundRegular + TRShellColorCyan, + TRShellAttributeForegroundLightGray = TRShellAttributeForegroundRegular + TRShellColorWhite, + + TRShellAttributeForegroundDefault = 39, + + TRShellAttributeForegroundLight = 90, + TRShellAttributeForegroundDarkGray = TRShellAttributeForegroundLight + TRShellColorBlack, + TRShellAttributeForegroundLightRed = TRShellAttributeForegroundLight + TRShellColorRed, + TRShellAttributeForegroundLightGreen = TRShellAttributeForegroundLight + TRShellColorGreen, + TRShellAttributeForegroundLightYellow = TRShellAttributeForegroundLight + TRShellColorYellow, + TRShellAttributeForegroundLightBlue = TRShellAttributeForegroundLight + TRShellColorBlue, + TRShellAttributeForegroundLightMagenta = TRShellAttributeForegroundLight + TRShellColorMagenta, + TRShellAttributeForegroundLightCyan = TRShellAttributeForegroundLight + TRShellColorCyan, + TRShellAttributeForegroundWhite = TRShellAttributeForegroundLight + TRShellColorWhite, + + TRShellAttributeBackgroundRegular = 40, + TRShellAttributeBackgroundBlack = TRShellAttributeBackgroundRegular + TRShellColorBlack, + TRShellAttributeBackgroundRed = TRShellAttributeBackgroundRegular + TRShellColorRed, + TRShellAttributeBackgroundGreen = TRShellAttributeBackgroundRegular + TRShellColorGreen, + TRShellAttributeBackgroundYellow = TRShellAttributeBackgroundRegular + TRShellColorYellow, + TRShellAttributeBackgroundBlue = TRShellAttributeBackgroundRegular + TRShellColorBlue, + TRShellAttributeBackgroundMagenta = TRShellAttributeBackgroundRegular + TRShellColorMagenta, + TRShellAttributeBackgroundCyan = TRShellAttributeBackgroundRegular + TRShellColorCyan, + TRShellAttributeBackgroundLightGray = TRShellAttributeBackgroundRegular + TRShellColorWhite, + + TRShellAttributeBackgroundDefault = 49, + + TRShellAttributeBackgroundLight = 100, + TRShellAttributeBackgroundDarkGray = TRShellAttributeBackgroundLight + TRShellColorBlack, + TRShellAttributeBackgroundLightRed = TRShellAttributeBackgroundLight + TRShellColorRed, + TRShellAttributeBackgroundLightGreen = TRShellAttributeBackgroundLight + TRShellColorGreen, + TRShellAttributeBackgroundLightYellow = TRShellAttributeBackgroundLight + TRShellColorYellow, + TRShellAttributeBackgroundLightBlue = TRShellAttributeBackgroundLight + TRShellColorBlue, + TRShellAttributeBackgroundLightMagenta = TRShellAttributeBackgroundLight + TRShellColorMagenta, + TRShellAttributeBackgroundLightCyan = TRShellAttributeBackgroundLight + TRShellColorCyan, + TRShellAttributeBackgroundWhite = TRShellAttributeBackgroundLight + TRShellColorWhite, +}; + @interface XcodeColors_NSTextStorage : NSTextStorage - (void)fixAttributesInRange:(NSRange)aRange; diff --git a/XcodeColors/XcodeColors.m b/XcodeColors/XcodeColors.m index 709b48b..de81cb7 100644 --- a/XcodeColors/XcodeColors.m +++ b/XcodeColors/XcodeColors.m @@ -112,37 +112,30 @@ void ApplyANSIColors(NSTextStorage *textStorage, NSRange textStorageRange, NSStr BOOL reset = !stop && (stop = [component hasPrefix:@";"]); BOOL fg = !stop && (stop = [component hasPrefix:@"fg"]); BOOL bg = !stop && (stop = [component hasPrefix:@"bg"]); - + BOOL ansi = !stop; + BOOL resetFg = fg && [component hasPrefix:@"fg;"]; BOOL resetBg = bg && [component hasPrefix:@"bg;"]; - + if (reset) { - // Reset attributes + // reset sequence length (";") + colorCodeSeqLength = 1; + + // Reset attributes [attrs removeObjectForKey:NSForegroundColorAttributeName]; [attrs removeObjectForKey:NSBackgroundColorAttributeName]; - - // Mark the range of the sequence (escape sequence + reset color sequence). - NSRange seqRange = (NSRange){ - .location = componentRange.location - [escapeSeq length], - .length = 1 + [escapeSeq length], - }; - [seqRanges addObject:[NSValue valueWithRange:seqRange]]; } else if (resetFg || resetBg) { + // reset color sequence length (@"xx;") + colorCodeSeqLength = 3; + // Reset attributes if (resetFg) [attrs removeObjectForKey:NSForegroundColorAttributeName]; else [attrs removeObjectForKey:NSBackgroundColorAttributeName]; - - // Mark the range of the sequence (escape sequence + reset color sequence). - NSRange seqRange = (NSRange){ - .location = componentRange.location - [escapeSeq length], - .length = 3 + [escapeSeq length], - }; - [seqRanges addObject:[NSValue valueWithRange:seqRange]]; } else if (fg || bg) { @@ -222,30 +215,152 @@ void ApplyANSIColors(NSTextStorage *textStorage, NSRange textStorageRange, NSStr { [attrs setObject:color forKey:NSBackgroundColorAttributeName]; } - - //NSString *realString = [component substringFromIndex:colorCodeSeqLength]; - - // Mark the range of the entire sequence (escape sequence + color code sequence). - NSRange seqRange = (NSRange){ - .location = componentRange.location - [escapeSeq length], - .length = colorCodeSeqLength + [escapeSeq length], - }; - [seqRanges addObject:[NSValue valueWithRange:seqRange]]; - } + } else { // Wasn't able to parse a color code - - [attrs removeObjectForKey:NSForegroundColorAttributeName]; - [attrs removeObjectForKey:NSBackgroundColorAttributeName]; - - NSRange seqRange = (NSRange){ - .location = componentRange.location - [escapeSeq length], - .length = [escapeSeq length], - }; - [seqRanges addObject:[NSValue valueWithRange:seqRange]]; + colorCodeSeqLength = 0; + + // Reset attributes + [attrs removeObjectForKey:NSForegroundColorAttributeName]; + [attrs removeObjectForKey:NSBackgroundColorAttributeName]; } } + else if (ansi) { + + NSUInteger endIndex = [component rangeOfString:@"m"].location; + + if (endIndex == NSNotFound) { + + // Wasn't able to parse a color code + colorCodeSeqLength = 0; + } + + if (endIndex == 0) { + + // empty color sequence ("m") + colorCodeSeqLength = 1; + } + else { + + colorCodeSeqLength = endIndex + 1; + + NSString *attrString = [component substringWithRange:NSMakeRange(0, endIndex)]; + + NSString * const kTRShellAttributesSeparator = @";"; + + NSArray *attributes = [attrString componentsSeparatedByString:kTRShellAttributesSeparator]; + + NSColor *foregroundColor = nil, *backgroundColor = nil; + BOOL clearForeground = NO, clearBackground = NO; + + for (NSString *attributeStr in attributes) { + + TRShellAttribute attribute = [attributeStr integerValue]; + + switch (attribute) { + + /* reset cases */ + + case TRShellAttributeResetAll: + foregroundColor = backgroundColor = nil; + clearForeground = clearBackground = YES; + break; + + case TRShellAttributeForegroundDefault: + foregroundColor = nil; + clearForeground = YES; + break; + + case TRShellAttributeBackgroundDefault: + backgroundColor = nil; + clearBackground = YES; + break; + + /* foreground color cases */ + + case TRShellAttributeForegroundBlack: + case TRShellAttributeForegroundRed: + case TRShellAttributeForegroundGreen: + case TRShellAttributeForegroundYellow: + case TRShellAttributeForegroundBlue: + case TRShellAttributeForegroundMagenta: + case TRShellAttributeForegroundCyan: + case TRShellAttributeForegroundLightGray: + { + TRShellColor colorCode = attribute - TRShellAttributeForegroundRegular; + foregroundColor = colorForShellColor(colorCode, NO); + break; + } + + case TRShellAttributeForegroundDarkGray: + case TRShellAttributeForegroundLightRed: + case TRShellAttributeForegroundLightGreen: + case TRShellAttributeForegroundLightYellow: + case TRShellAttributeForegroundLightBlue: + case TRShellAttributeForegroundLightMagenta: + case TRShellAttributeForegroundLightCyan: + case TRShellAttributeForegroundWhite: + { + TRShellColor colorCode = attribute - TRShellAttributeForegroundLight; + foregroundColor = colorForShellColor(colorCode, YES); + break; + } + + case TRShellAttributeBackgroundBlack: + case TRShellAttributeBackgroundRed: + case TRShellAttributeBackgroundGreen: + case TRShellAttributeBackgroundYellow: + case TRShellAttributeBackgroundBlue: + case TRShellAttributeBackgroundMagenta: + case TRShellAttributeBackgroundCyan: + case TRShellAttributeBackgroundLightGray: + { + TRShellColor colorCode = attribute - TRShellAttributeBackgroundRegular; + backgroundColor = colorForShellColor(colorCode, NO); + break; + } + + case TRShellAttributeBackgroundDarkGray: + case TRShellAttributeBackgroundLightRed: + case TRShellAttributeBackgroundLightGreen: + case TRShellAttributeBackgroundLightYellow: + case TRShellAttributeBackgroundLightBlue: + case TRShellAttributeBackgroundLightMagenta: + case TRShellAttributeBackgroundLightCyan: + case TRShellAttributeBackgroundWhite: + { + TRShellColor colorCode = attribute - TRShellAttributeBackgroundLight; + backgroundColor = colorForShellColor(colorCode, YES); + break; + } + + default: + break; + } + + } + + if (clearForeground) { + [attrs removeObjectForKey:NSForegroundColorAttributeName]; + } + if (clearBackground) { + [attrs removeObjectForKey:NSBackgroundColorAttributeName]; + } + if (foregroundColor) { + [attrs setObject:foregroundColor forKey:NSForegroundColorAttributeName]; + } + if (backgroundColor) { + [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName]; + } + } + } + + NSRange seqRange = (NSRange){ + .location = componentRange.location - [escapeSeq length], + .length = colorCodeSeqLength + [escapeSeq length], + }; + [seqRanges addObject:[NSValue valueWithRange:seqRange]]; } componentRange.length = [component length]; @@ -275,6 +390,94 @@ void ApplyANSIColors(NSTextStorage *textStorage, NSRange textStorageRange, NSStr } } +NSColor *colorForShellColor(TRShellColor colorCode, BOOL light) { + + // These colors are taken from the Terminal.app default preferences. + + switch (colorCode) { + + case TRShellColorBlack: + + if (!light) { + return [NSColor blackColor]; + } + else { + return [NSColor colorWithCalibratedRed:0.326 green:0.326 blue:0.326 alpha:1.000]; + } + break; + + case TRShellColorRed: + + if (!light) { + return [NSColor colorWithDeviceRed:0.522 green:0.000 blue:0.009 alpha:1.000]; + } + else { + return [NSColor colorWithDeviceRed:0.863 green:0.000 blue:0.021 alpha:1.000]; + } + break; + + case TRShellColorGreen: + + if (!light) { + return [NSColor colorWithCalibratedRed:0.079 green:0.602 blue:0.009 alpha:1.000]; + } + else { + return [NSColor colorWithCalibratedRed:0.110 green:0.839 blue:0.017 alpha:1.000]; + } + break; + + case TRShellColorYellow: + + if (!light) { + return [NSColor colorWithCalibratedRed:0.530 green:0.540 blue:0.017 alpha:1.000]; + } + else { + return [NSColor colorWithCalibratedRed:0.877 green:0.892 blue:0.036 alpha:1.000]; + } + break; + + case TRShellColorBlue: + + if (!light) { + return [NSColor colorWithCalibratedRed:0.000 green:0.000 blue:0.639 alpha:1.000]; + } + else { + return [NSColor colorWithCalibratedRed:0.000 green:0.000 blue:0.998 alpha:1.000]; + } + break; + + case TRShellColorMagenta: + + if (!light) { + return [NSColor colorWithCalibratedRed:0.630 green:0.000 blue:0.640 alpha:1.000]; + } + else { + return [NSColor colorWithCalibratedRed:0.862 green:0.000 blue:0.875 alpha:1.000]; + } + break; + + case TRShellColorCyan: + + if (!light) { + return [NSColor colorWithCalibratedRed:0.075 green:0.589 blue:0.639 alpha:1.000]; + } + else { + return [NSColor colorWithCalibratedRed:0.113 green:0.885 blue:0.875 alpha:1.000]; + } + break; + + case TRShellColorWhite: + + if (!light) { + return [NSColor colorWithCalibratedRed:0.697 green:0.697 blue:0.697 alpha:1.000]; + } + else { + return [NSColor colorWithCalibratedRed:0.876 green:0.876 blue:0.876 alpha:1.000]; + } + break; + } +} + - (void)fixAttributesInRange:(NSRange)aRange { // This method "overrides" the method within NSTextStorage.