ColorSenseをカラーコードにも対応させる

NSColorやUIColorの色をエディタ上で確認できるXcodeプラグインに

ColorSense-for-Xcode
https://github.com/omz/ColorSense-for-Xcode

と言うものがあります。お世話になっている方も多いかと思います。

確かにXcode上でピッカーによる色指定がかなり便利になったと思うのですが、#FFFFFF等の色指定は未だに面倒な部分が多いですよね。

多くの人は、多分@"#FFFFFF"等をUIColorに変換するメソッドを書いたり、外部アプリを使ってUIColorに変換したりしてるのではないでしょうか？

ColorSencse一つで解決したらなーと思った私は、
[UIColor #FFFFFF]等を設定した時にもピッカーが出るようにする改造をしてみました。

```objc:OMColorHelper.h
typedef enum OMColorType {
    (略)
    OMColorTypeUICode,              //[UIColor #FFFFFF]
    OMColorTypeNSCode,              //[NSColor #FFFFFF]
}
```

２行を加えます。

```objc:OMColorHelper.h
@interface OMColorHelper : NSObject {
    (略)
    NSRegularExpression *_codeColorRegex;
}
```

_codeColorRegexを加えます。

```objc:OMColorHelper.m
- (id)init
{
(略)
_constantColorRegex = [NSRegularExpression regularExpressionWithPattern:@"\\[\\s*(UI|NS)Color\\s+(black|darkGray|lightGray|white|gray|red|green|blue|cyan|yellow|magenta|orange|purple|brown|clear)Color\\s*\\]" options:0 error:NULL];
_codeColorRegex = [NSRegularExpression regularExpressionWithPattern:@"\\[\\s*(UI|NS)Color\\s+#([A-Fa-f0-9]{6})\\s*\\]" options:0 error:NULL];    // この行を加える
}
```

```objc:OMColorHelper.m
- (NSColor *)colorInText:(NSString *)text selectedRange:(NSRange)selectedRange type:(OMColorType *)type matchedRange:(NSRangePointer)matchedRange
{
（略)

// ここから
    if (!foundColor) {
		[_codeColorRegex enumerateMatchesInString:text options:0 range:NSMakeRange(0, text.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
			NSRange colorRange = [result range];
			if (selectedRange.location >= colorRange.location && NSMaxRange(selectedRange) <= NSMaxRange(colorRange)) {
				NSString *NS_UI = [text substringWithRange:[result rangeAtIndex:1]];
				NSString *colorCode = [text substringWithRange:[result rangeAtIndex:2]];
                
                unsigned int rgb[3];
                for (int i = 0; i < 3; i++) {
                    NSString *component = [colorCode substringWithRange:NSMakeRange(i * 2, 2)];
                    NSScanner *scanner = [NSScanner scannerWithString:component];
                    [scanner scanHexInt:&rgb[i]];
                }
                
				foundColor = [NSColor colorWithCalibratedRed:rgb[0]/255.f green:rgb[1]/255.f blue:rgb[2]/255.f alpha:1.f];
				foundColorRange = colorRange;
				if ([NS_UI isEqualToString:@"UI"]) {
					foundColorType = OMColorTypeUICode;
				} else {
					foundColorType = OMColorTypeNSCode;
				}
				*stop = YES;
			}
		}];
	}
	
// ここまでをif (foundColor) {の前に、加える

	if (foundColor) {
        (略)
}
```

```objc:OMColorHelper.m
- (NSString *)colorStringForColor:(NSColor *)color withType:(OMColorType)colorType
{
(略)
		if (!colorString) {
			if (fabs(red - green) < 0.001 && fabs(green - blue) < 0.001) {
				if (colorType == OMColorTypeUIRGBA || colorType == OMColorTypeUIWhite || colorType == OMColorTypeUIConstant || colorType == OMColorTypeUICode) {
					colorString = [NSString stringWithFormat:@"[UIColor colorWithWhite:%.3f alpha:%.3f]", red, alpha];
				} else if (colorType == OMColorTypeUIRGBAInit || colorType == OMColorTypeUIWhiteInit) {
					colorString = [NSString stringWithFormat:@"[[UIColor alloc] initWithWhite:%.3f alpha:%.3f]", red, alpha];
				}
				else if (colorType == OMColorTypeNSConstant || colorType == OMColorTypeNSRGBACalibrated || colorType == OMColorTypeNSWhiteCalibrated) {
					colorString = [NSString stringWithFormat:@"[NSColor colorWithCalibratedWhite:%.3f alpha:%.3f]", red, alpha];
				} else if (colorType == OMColorTypeNSRGBADevice || colorType == OMColorTypeNSWhiteDevice) {
					colorString = [NSString stringWithFormat:@"[NSColor colorWithDeviceWhite:%.3f alpha:%.3f]", red, alpha];
				}
			} else {
				if (colorType == OMColorTypeUIRGBA || colorType == OMColorTypeUIWhite || colorType == OMColorTypeUIConstant || colorType == OMColorTypeUICode) {
					colorString = [NSString stringWithFormat:@"[UIColor colorWithRed:%.3f green:%.3f blue:%.3f alpha:%.3f]", red, green, blue, alpha];
				} else if (colorType == OMColorTypeUIRGBAInit || colorType == OMColorTypeUIWhiteInit) {
					colorString = [NSString stringWithFormat:@"[[UIColor alloc] initWithRed:%.3f green:%.3f blue:%.3f alpha:%.3f]", red, green, blue, alpha];
				}
				else if (colorType == OMColorTypeNSConstant || colorType == OMColorTypeNSRGBACalibrated || colorType == OMColorTypeNSWhiteCalibrated) {
					colorString = [NSString stringWithFormat:@"[NSColor colorWithCalibratedRed:%.3f green:%.3f blue:%.3f alpha:%.3f]", red, green, blue, alpha];
				} else if (colorType == OMColorTypeNSRGBADevice || colorType == OMColorTypeNSWhiteDevice) {
					colorString = [NSString stringWithFormat:@"[NSColor colorWithDeviceRed:%.3f green:%.3f blue:%.3f alpha:%.3f]", red, green, blue, alpha];
				}
			}
		}
(略)
}
```

if (!colorString) {の中身を上記に置き換える。

後はビルドするだけです。
ColorSenseで[UIColor #FFFFFF]等の記述のときでもピッカーが出るようになります。
ピッカーを出して数値を再定義すれば[UIColor color....];と記述が変更されるので１から入力するよりは楽になるかもしれません。

[UIColor #FFFFFF]等の記述を環境によって変えたいって時は、
_codeColorRegex = [NSRegularExpression regularExpressionWithPattern:@"\\[\\s*(UI|NS)Color\\s+#([A-Fa-f0-9]{6})\\s*\\]" options:0 error:NULL];  

の部分を自分にあわせて変えると良いと思います！

カラーコードを入力したタイミングで[UIColor colorWithRed:0.939 green:1.000 blue:1.000 alpha:1.000];等に変換する改造方法も後日まとめたいですね。

ColorSenseの作者さんから、「改造については自由にしてくれて構わない」とコメントを頂いていると共に、Xcodeプラグインの開発についての勉強目的でも改造方法を掲載しております。ぜひコメントにてアドバイス等を気軽にお願いいたします。