Repository: questbeat/Lin-Xcode5 Branch: master Commit: ca499ac6d375 Files: 78 Total size: 188.7 KB Directory structure: gitextract_srotazw1/ ├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── Lin/ │ ├── DVTDualProxyWindow.h │ ├── DVTFilePath.h │ ├── DVTSourceTextView.h │ ├── IDEEditorDocument.h │ ├── IDEIndex+Lin.h │ ├── IDEIndex+Lin.m │ ├── IDEIndex.h │ ├── IDEIndexCollection.h │ ├── IDEWorkspace.h │ ├── IDEWorkspaceWindow.h │ ├── LNAlertAccessoryView.h │ ├── LNAlertAccessoryView.m │ ├── LNAlertAccessoryView.xib │ ├── LNButtonCell.h │ ├── LNButtonCell.m │ ├── LNDetector.h │ ├── LNDetector.m │ ├── LNEntity.h │ ├── LNEntity.m │ ├── LNHorizontalLine.h │ ├── LNHorizontalLine.m │ ├── LNImageButtonCell.h │ ├── LNImageButtonCell.m │ ├── LNLocalization.h │ ├── LNLocalization.m │ ├── LNLocalizationCollection.h │ ├── LNLocalizationCollection.m │ ├── LNLocalizedStringCollectionOperation.h │ ├── LNLocalizedStringCollectionOperation.m │ ├── LNPopoverContentView.h │ ├── LNPopoverContentView.m │ ├── LNPopoverContentView.xib │ ├── LNPopoverWindow.h │ ├── LNPopoverWindow.m │ ├── LNPopoverWindowController.h │ ├── LNPopoverWindowController.m │ ├── LNRegularExpressionPattern+type.h │ ├── LNRegularExpressionPattern+type.m │ ├── LNRegularExpressionPattern.h │ ├── LNRegularExpressionPattern.m │ ├── LNTableCornerView.h │ ├── LNTableCornerView.m │ ├── LNTableHeaderCell.h │ ├── LNTableHeaderCell.m │ ├── LNTableView.h │ ├── LNTableView.m │ ├── LNUserDefaultsManager.h │ ├── LNUserDefaultsManager.m │ ├── Lin-Info.plist │ ├── Lin-Prefix.pch │ ├── Lin.h │ ├── Lin.m │ ├── MethodSwizzle.h │ ├── MethodSwizzle.m │ ├── NSBundle+versions.h │ ├── NSBundle+versions.m │ ├── NSPopoverFrame+Lin.h │ ├── NSPopoverFrame+Lin.m │ ├── NSPopoverFrame.h │ ├── NSTableView+editedColumnIdentifier.h │ ├── NSTableView+editedColumnIdentifier.m │ └── en.lproj/ │ └── InfoPlist.strings ├── Lin.xcodeproj/ │ ├── project.pbxproj │ └── xcshareddata/ │ └── xcschemes/ │ ├── Lin.xcscheme │ └── LinTests.xcscheme ├── LinTests/ │ ├── LNDetectorTestSet.h │ ├── LNDetectorTestSet.m │ ├── LNDetectorTests.m │ ├── LNLocalizationTests.m │ ├── LinTests-Info.plist │ ├── LinTests-Prefix.pch │ ├── Localizable.strings │ └── en.lproj/ │ └── InfoPlist.strings ├── Makefile └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Generated by http://gitignore.io ### Objective-C ### # Xcode .DS_Store */build/* *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 *.xcworkspace !default.xcworkspace xcuserdata profile *.moved-aside DerivedData .idea/ *.hmap ================================================ FILE: .travis.yml ================================================ language: objective-c script: make clean test ================================================ FILE: LICENSE.txt ================================================ Copyright (c) 2013 Katsuma Tanaka Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Lin/DVTDualProxyWindow.h ================================================ // // DVTDualProxyWindow.h // Lin // // Created by Tanaka Katsuma on 2013/09/26. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface DVTDualProxyWindow : NSWindow @end ================================================ FILE: Lin/DVTFilePath.h ================================================ // // DVTFilePath.h // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface DVTFilePath : NSObject @property (readonly) NSString *fileName; @property (readonly) NSURL *fileURL; @property (readonly) NSArray *pathComponents; @property (readonly) NSString *pathString; @end ================================================ FILE: Lin/DVTSourceTextView.h ================================================ // // DVTSourceTextView.h // Lin // // Created by Tanaka Katsuma on 2013/09/26. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface DVTSourceTextView : NSTextView @end ================================================ FILE: Lin/IDEEditorDocument.h ================================================ // // IDEEditorDocument.h // Lin // // Created by Tanaka Katsuma on 2013/08/24. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class DVTFilePath; @interface IDEEditorDocument : NSDocument @property (retain) DVTFilePath *filePath; @end ================================================ FILE: Lin/IDEIndex+Lin.h ================================================ // // IDEIndex+Lin.h // Lin // // Created by Tanaka Katsuma on 2013/08/24. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "IDEIndex.h" @interface IDEIndex (Lin) @end ================================================ FILE: Lin/IDEIndex+Lin.m ================================================ // // IDEIndex+Lin.m // Lin // // Created by Tanaka Katsuma on 2013/08/24. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "IDEIndex+Lin.h" #import "MethodSwizzle.h" #import "Lin.h" @implementation IDEIndex (Lin) + (void)load { MethodSwizzle(self, @selector(close), @selector(jp_questbeat_lin_close)); } - (void)jp_questbeat_lin_close { [[Lin sharedPlugIn] removeLocalizationsForIndex:self]; [self jp_questbeat_lin_close]; } @end ================================================ FILE: Lin/IDEIndex.h ================================================ // // IDEIndex.h // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class DVTFilePath; @interface IDEIndex : NSObject @property (readonly, nonatomic) DVTFilePath *workspaceFile; @property (readonly, nonatomic) NSString *workspaceName; - (void)close; - (id)filesContaining:(id)arg1 anchorStart:(BOOL)arg2 anchorEnd:(BOOL)arg3 subsequence:(BOOL)arg4 ignoreCase:(BOOL)arg5 cancelWhen:(id)arg6; @end ================================================ FILE: Lin/IDEIndexCollection.h ================================================ // // IDEIndexCollection.h // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface IDEIndexCollection : NSObject @end ================================================ FILE: Lin/IDEWorkspace.h ================================================ // // IDEWorkspace.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class IDEIndex; @class DVTFilePath; @interface IDEWorkspace : NSObject @property (retain) IDEIndex *index; @property (readonly) DVTFilePath *representingFilePath; - (void)_updateIndexableFiles:(id)arg1; @end ================================================ FILE: Lin/IDEWorkspaceWindow.h ================================================ // // IDEWorkspaceWindow.h // Lin // // Created by Tanaka Katsuma on 2013/09/26. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "DVTDualProxyWindow.h" @interface IDEWorkspaceWindow : DVTDualProxyWindow @end ================================================ FILE: Lin/LNAlertAccessoryView.h ================================================ // // LNAlertAccessoryView.h // Lin // // Created by Tanaka Katsuma on 2013/09/22. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class LNLocalizationCollection; @interface LNAlertAccessoryView : NSView @property (nonatomic, copy) NSArray *collections; @property (nonatomic, weak) NSButton *button; @property (nonatomic, copy, readonly) LNLocalizationCollection *selectedCollection; @property (nonatomic, copy, readonly) NSString *inputtedKey; @property (nonatomic, copy, readonly) NSString *inputtedValue; @end ================================================ FILE: Lin/LNAlertAccessoryView.m ================================================ // // LNAlertAccessoryView.m // Lin // // Created by Tanaka Katsuma on 2013/09/22. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNAlertAccessoryView.h" // Models #import "LNLocalizationCollection.h" @interface LNAlertAccessoryView () @property (weak) IBOutlet NSPopUpButton *tableButton; @property (weak) IBOutlet NSPopUpButton *languageButton; @property (weak) IBOutlet NSTextField *keyTextField; @property (weak) IBOutlet NSTextField *valueTextField; @end @implementation LNAlertAccessoryView - (void)awakeFromNib { [super awakeFromNib]; } #pragma mark - Accessors - (void)setCollections:(NSArray *)collections { _collections = collections; // Update [self configureView]; } - (void)setButton:(NSButton *)button { _button = button; // Update [self configureButton]; } - (LNLocalizationCollection *)selectedCollection { NSString *selectedFileName = [self.tableButton titleOfSelectedItem]; NSString *selectedLanguageDesignations = [self.languageButton titleOfSelectedItem]; for (LNLocalizationCollection *collection in self.collections) { if ([collection.fileName isEqualToString:selectedFileName] && [collection.languageDesignation isEqualToString:selectedLanguageDesignations]) { return collection; } } return nil; } - (NSString *)inputtedKey { return self.keyTextField.stringValue; } - (NSString *)inputtedValue { return self.valueTextField.stringValue; } #pragma mark - Actions - (IBAction)tableDidChange:(id)sender { // Update [self updateLanguages]; } #pragma mark - Updating the Views - (void)updateTables { [self.tableButton removeAllItems]; NSMutableSet *tableFileNames = [NSMutableSet set]; for (LNLocalizationCollection *collection in self.collections) { [tableFileNames addObject:collection.fileName]; } [self.tableButton addItemsWithTitles:[tableFileNames allObjects]]; } - (void)updateLanguages { [self.languageButton removeAllItems]; NSString *titleOfSelectedItem = [self.tableButton titleOfSelectedItem]; NSMutableSet *languageDesignations = [NSMutableSet set]; for (LNLocalizationCollection *collection in self.collections) { if ([titleOfSelectedItem isEqualToString:collection.fileName]) { [languageDesignations addObject:collection.languageDesignation]; } } [self.languageButton addItemsWithTitles:[languageDesignations allObjects]]; } - (void)configureView { [self updateTables]; [self updateLanguages]; [self configureButton]; } - (void)configureButton { NSString *key = self.keyTextField.stringValue; NSString *value = self.valueTextField.stringValue; [self.button setEnabled:(self.collections.count > 0 && key.length > 0 && value.length > 0)]; } #pragma mark - NSTextFieldDelegate - (void)controlTextDidChange:(NSNotification *)obj { [self configureButton]; } @end ================================================ FILE: Lin/LNAlertAccessoryView.xib ================================================ ================================================ FILE: Lin/LNButtonCell.h ================================================ // // LNButtonCell.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNButtonCell : NSButtonCell @end ================================================ FILE: Lin/LNButtonCell.m ================================================ // // LNButtonCell.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNButtonCell.h" @implementation LNButtonCell - (void)drawImage:(NSImage *)image withFrame:(NSRect)frame inView:(NSView *)controlView { // Adjustment frame.origin.y += 3; [super drawImage:image withFrame:frame inView:controlView]; } @end ================================================ FILE: Lin/LNDetector.h ================================================ // // LNDetector.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNDetector : NSObject @property (nonatomic, copy, readonly) NSArray *regularExpressionPatterns; + (instancetype)detector; - (NSArray *)entitiesInString:(NSString *)string; @end ================================================ FILE: Lin/LNDetector.m ================================================ // // LNDetector.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNDetector.h" // Models #import "LNEntity.h" #import "LNRegularExpressionPattern.h" #import "LNRegularExpressionPattern+type.h" @interface LNDetector () @property (nonatomic, copy, readwrite) NSArray *regularExpressionPatterns; @end @implementation LNDetector + (instancetype)detector { return [[self alloc] init]; } - (instancetype)init { self = [super init]; if (self) { self.regularExpressionPatterns = @[ [LNRegularExpressionPattern patternWithType:LNEntityTypeLocalizedString], [LNRegularExpressionPattern patternWithType:LNEntityTypeLocalizedStringForKey], [LNRegularExpressionPattern patternWithType:LNEntityTypeLocalizedStringFromTable], [LNRegularExpressionPattern patternWithType:LNEntityTypeLocalizedStringFromTableInBundle], [LNRegularExpressionPattern patternWithType:LNEntityTypeLocalizedStringWithDefaultValue] ]; } return self; } #pragma mark - Finding Entities - (NSArray *)entitiesInString:(NSString *)string { NSMutableArray *entities = [NSMutableArray array]; for (LNRegularExpressionPattern *regularExpressionPattern in self.regularExpressionPatterns) { NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regularExpressionPattern.pattern options:0 error:NULL]; __block NSRange entityRange; __block NSRange keyRange; [regularExpression enumerateMatchesInString:string options:0 range:NSMakeRange(0, string.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { if (result.numberOfRanges == regularExpressionPattern.numberOfRanges) { entityRange = [result rangeAtIndex:regularExpressionPattern.entityRangeIndex]; keyRange = [result rangeAtIndex:regularExpressionPattern.keyRangeIndex]; LNEntity *entity = [LNEntity entityWithType:regularExpressionPattern.type entityRange:entityRange keyRange:keyRange]; [entities addObject:entity]; } }]; } return [entities copy]; } @end ================================================ FILE: Lin/LNEntity.h ================================================ // // LNEntity.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import typedef NS_ENUM(NSUInteger, LNEntityType) { LNEntityTypeLocalizedString = 0, LNEntityTypeLocalizedStringForKey, LNEntityTypeLocalizedStringFromTable, LNEntityTypeLocalizedStringFromTableInBundle, LNEntityTypeLocalizedStringWithDefaultValue }; NS_INLINE NSString * NSStringFromEntityType(LNEntityType type) { NSString *string = nil; switch (type) { case LNEntityTypeLocalizedString: string = @"LNEntityTypeLocalizedString"; break; case LNEntityTypeLocalizedStringForKey: string = @"LNEntityTypeLocalizedStringForKey"; break; case LNEntityTypeLocalizedStringFromTable: string = @"LNEntityTypeLocalizedStringFromTable"; break; case LNEntityTypeLocalizedStringFromTableInBundle: string = @"LNEntityTypeLocalizedStringFromTableInBundle"; break; case LNEntityTypeLocalizedStringWithDefaultValue: string = @"LNEntityTypeLocalizedStringWithDefaultValue"; break; } return string; } @interface LNEntity : NSObject @property (nonatomic, assign, readonly) LNEntityType type; @property (nonatomic, assign, readonly) NSRange entityRange; @property (nonatomic, assign, readonly) NSRange keyRange; + (instancetype)entityWithType:(LNEntityType)type entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange; - (instancetype)initWithType:(LNEntityType)type entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange; @end ================================================ FILE: Lin/LNEntity.m ================================================ // // LNEntity.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNEntity.h" @interface LNEntity () @property (nonatomic, assign, readwrite) LNEntityType type; @property (nonatomic, assign, readwrite) NSRange entityRange; @property (nonatomic, assign, readwrite) NSRange keyRange; @end @implementation LNEntity + (instancetype)entityWithType:(LNEntityType)type entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange { return [[self alloc] initWithType:type entityRange:entityRange keyRange:keyRange]; } - (instancetype)initWithType:(LNEntityType)type entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange { self = [super init]; if (self) { self.type = type; self.entityRange = entityRange; self.keyRange = keyRange; } return self; } - (BOOL)isEqual:(id)object { if (object == self) return YES; if (!object || ![[object class] isEqual:[self class]]) return NO; if (!NSEqualRanges([self entityRange], [object entityRange])) return NO; return YES; } - (NSString *)description { return [NSString stringWithFormat: @"<%@: %p; type = %@; range = %@; key = %@>", NSStringFromClass([self class]), self, NSStringFromEntityType(self.type), NSStringFromRange(self.entityRange), NSStringFromRange(self.keyRange) ]; } @end ================================================ FILE: Lin/LNHorizontalLine.h ================================================ // // LNHorizontalLine.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNHorizontalLine : NSBox @end ================================================ FILE: Lin/LNHorizontalLine.m ================================================ // // LNHorizontalLine.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNHorizontalLine.h" @implementation LNHorizontalLine - (void)drawRect:(NSRect)dirtyRect { [[NSColor colorWithDeviceWhite:204.0/255.0 alpha:1.0] set]; [NSBezierPath strokeLineFromPoint:NSMakePoint(dirtyRect.origin.x, 2.5) toPoint:NSMakePoint(dirtyRect.origin.x + dirtyRect.size.width, 2.5)]; } @end ================================================ FILE: Lin/LNImageButtonCell.h ================================================ // // LNImageButtonCell.h // Lin // // Created by Tanaka Katsuma on 2014/03/04. // Copyright (c) 2014年 Tanaka Katsuma. All rights reserved. // #import @interface LNImageButtonCell : NSButtonCell @end ================================================ FILE: Lin/LNImageButtonCell.m ================================================ // // LNImageButtonCell.m // Lin // // Created by Tanaka Katsuma on 2014/03/04. // Copyright (c) 2014年 Tanaka Katsuma. All rights reserved. // #import "LNImageButtonCell.h" @implementation LNImageButtonCell - (void)drawImage:(NSImage *)image withFrame:(NSRect)frame inView:(NSView *)controlView { // Adjustment frame.origin.y += 2; [super drawImage:image withFrame:frame inView:controlView]; } @end ================================================ FILE: Lin/LNLocalization.h ================================================ // // LNLocalization.h // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class LNLocalizationCollection; @interface LNLocalization : NSObject @property (nonatomic, copy, readonly) NSString *key; @property (nonatomic, copy, readonly) NSString *value; @property (nonatomic, assign, readonly) NSRange entityRange; @property (nonatomic, assign, readonly) NSRange keyRange; @property (nonatomic, assign, readonly) NSRange valueRange; @property (nonatomic, weak, readonly) LNLocalizationCollection *collection; + (instancetype)localizationWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection; - (instancetype)initWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection; @end ================================================ FILE: Lin/LNLocalization.m ================================================ // // LNLocalization.m // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNLocalization.h" @interface LNLocalization () @property (nonatomic, copy, readwrite) NSString *key; @property (nonatomic, copy, readwrite) NSString *value; @property (nonatomic, assign, readwrite) NSRange entityRange; @property (nonatomic, assign, readwrite) NSRange keyRange; @property (nonatomic, assign, readwrite) NSRange valueRange; @property (nonatomic, weak, readwrite) LNLocalizationCollection *collection; @end @implementation LNLocalization + (instancetype)localizationWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection { return [[self alloc] initWithKey:key value:value entityRange:(NSRange)entityRange keyRange:keyRange valueRange:valueRange collection:collection]; } - (instancetype)initWithKey:(NSString *)key value:(NSString *)value entityRange:(NSRange)entityRange keyRange:(NSRange)keyRange valueRange:(NSRange)valueRange collection:(LNLocalizationCollection *)collection { self = [super init]; if (self) { self.key = key; self.value = value; self.entityRange = entityRange; self.keyRange = keyRange; self.valueRange = valueRange; self.collection = collection; } return self; } - (BOOL)isEqual:(id)object { if (object == self) return YES; if (!object || ![[object class] isEqual:[self class]]) return NO; if (![[self key] isEqualToString:[object key]]) return NO; return YES; } - (NSUInteger)hash { return [self.key hash]; } - (NSString *)description { return [NSString stringWithFormat: @"<%@: %p; key = %@; value = %@; entityRange = %@; keyRange = %@; valueRange = %@; collection = %p>", NSStringFromClass([self class]), self, self.key, self.value, NSStringFromRange(self.entityRange), NSStringFromRange(self.keyRange), NSStringFromRange(self.valueRange), self.collection ]; } @end ================================================ FILE: Lin/LNLocalizationCollection.h ================================================ // // LNLocalizationCollection.h // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class LNLocalization; @interface LNLocalizationCollection : NSObject @property (nonatomic, copy, readonly) NSString *filePath; @property (nonatomic, copy, readonly) NSString *languageDesignation; @property (nonatomic, strong, readonly) NSMutableSet *localizations; + (instancetype)localizationCollectionWithContentsOfFile:(NSString *)filePath; - (instancetype)initWithContentsOfFile:(NSString *)filePath; - (NSString *)fileName; - (void)reloadLocalizations; - (void)addLocalization:(LNLocalization *)localization; - (void)deleteLocalization:(LNLocalization *)localization; - (void)replaceLocalization:(LNLocalization *)localization withLocalization:(LNLocalization *)newLocalization; @end ================================================ FILE: Lin/LNLocalizationCollection.m ================================================ // // LNLocalizationCollection.m // Lin // // Created by Tanaka Katsuma on 2013/08/23. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNLocalizationCollection.h" // Models #import "LNLocalization.h" @interface LNLocalizationCollection () @property (nonatomic, copy, readwrite) NSString *filePath; @property (nonatomic, copy, readwrite) NSString *languageDesignation; @property (nonatomic, strong, readwrite) NSMutableSet *localizations; @end @implementation LNLocalizationCollection + (instancetype)localizationCollectionWithContentsOfFile:(NSString *)filePath { return [[self alloc] initWithContentsOfFile:filePath]; } - (instancetype)initWithContentsOfFile:(NSString *)filePath { self = [super init]; if (self) { self.filePath = filePath; // Extract language designation NSArray *pathComponents = [filePath pathComponents]; self.languageDesignation = [[pathComponents objectAtIndex:pathComponents.count - 2] stringByDeletingPathExtension]; // Update [self reloadLocalizations]; } return self; } - (NSString *)description { return [NSString stringWithFormat: @"<%@: %p; filePath = %@; languageDesignation = %@; localizations = %@>", NSStringFromClass([self class]), self, self.filePath, self.languageDesignation, self.localizations ]; } #pragma mark - Accessors - (NSString *)fileName { return [self.filePath lastPathComponent]; } #pragma mark - Managing Localizations - (NSString *)loadContentsOfFile:(NSString *)filePath { NSError *error = nil; NSStringEncoding encoding = NSUTF8StringEncoding; NSString *contents = [NSString stringWithContentsOfURL:[NSURL fileURLWithPath:self.filePath] usedEncoding:&encoding error:&error]; if (error) { NSLog(@"Error: %@", [error localizedDescription]); return nil; } return contents; } - (void)reloadLocalizations { // Load contents NSString *contents = [self loadContentsOfFile:self.filePath]; if (contents) { NSMutableSet *localizations = [NSMutableSet set]; // Parse __block NSInteger lineOffset = 0; __block NSString *key; __block NSString *value; __block NSRange entityRange; __block NSRange keyRange; __block NSRange valueRange; NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:@"(\"(\\S+.*\\S+)\"|(\\S+.*\\S+))\\s*=\\s*\"(.*)\";$" options:0 error:NULL]; [contents enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { key = nil; value = nil; keyRange = NSMakeRange(NSNotFound, 0); valueRange = NSMakeRange(NSNotFound, 0); NSTextCheckingResult *result = [regularExpression firstMatchInString:line options:0 range:NSMakeRange(0, line.length)]; if (result.range.location != NSNotFound && result.numberOfRanges == 5) { entityRange = [result rangeAtIndex:0]; entityRange.location += lineOffset; keyRange = [result rangeAtIndex:2]; if (keyRange.location == NSNotFound) keyRange = [result rangeAtIndex:3]; valueRange = [result rangeAtIndex:4]; key = [line substringWithRange:keyRange]; value = [line substringWithRange:valueRange]; keyRange.location += lineOffset; valueRange.location += lineOffset; } // Create localization if (key != nil && value != nil) { LNLocalization *localization = [LNLocalization localizationWithKey:key value:value entityRange:entityRange keyRange:keyRange valueRange:valueRange collection:self]; [localizations addObject:localization]; } // Move offset NSRange lineRange = [contents lineRangeForRange:NSMakeRange(lineOffset, 0)]; lineOffset += lineRange.length; }]; self.localizations = localizations; } else { self.localizations = nil; } } - (void)addLocalization:(LNLocalization *)localization { // Load contents NSString *contents = [self loadContentsOfFile:self.filePath]; // Add if (![contents hasSuffix:@"\n"]) { contents = [contents stringByAppendingString:@"\n"]; } contents = [contents stringByAppendingFormat:@"\"%@\" = \"%@\";\n", localization.key, localization.value]; // Override NSError *error = nil; [contents writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"Error: %@", [error localizedDescription]); } // Reload [self reloadLocalizations]; } - (void)deleteLocalization:(LNLocalization *)localization { // Load contents NSString *contents = [self loadContentsOfFile:self.filePath]; // Delete line NSRange lineRange = [contents lineRangeForRange:localization.entityRange]; contents = [contents stringByReplacingCharactersInRange:lineRange withString:@""]; // Override NSError *error = nil; [contents writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"Error: %@", [error localizedDescription]); } // Reload [self reloadLocalizations]; } - (void)replaceLocalization:(LNLocalization *)localization withLocalization:(LNLocalization *)newLocalization { // Load contents NSString *contents = [self loadContentsOfFile:self.filePath]; // Replace NSString *newEntity = [NSString stringWithFormat:@"\"%@\" = \"%@\";", newLocalization.key, newLocalization.value]; contents = [contents stringByReplacingCharactersInRange:localization.entityRange withString:newEntity]; // Override NSError *error = nil; [contents writeToFile:self.filePath atomically:NO encoding:NSUTF8StringEncoding error:&error]; if (error) { NSLog(@"Error: %@", [error localizedDescription]); } // Reload [self reloadLocalizations]; } @end ================================================ FILE: Lin/LNLocalizedStringCollectionOperation.h ================================================ // // LNLocalizedStringCollectionOperation.h // Lin // // Created by Wenbin Zhang on 3/7/14. // Copyright (c) 2014 Tanaka Katsuma. All rights reserved. // #import @class IDEIndex; typedef void(^LNLocalizedStringCollectionCompletionBlock)(NSString *workspacePath, NSArray *collections); @interface LNLocalizedStringCollectionOperation : NSOperation @property (nonatomic, strong) IDEIndex *index; @property (nonatomic, copy) LNLocalizedStringCollectionCompletionBlock collectionCompletedBlock; - (instancetype)initWithIndex:(IDEIndex *)index; @end ================================================ FILE: Lin/LNLocalizedStringCollectionOperation.m ================================================ // // LNLocalizedStringCollectionOperation.m // Lin // // Created by Wenbin Zhang on 3/7/14. // Copyright (c) 2014 Tanaka Katsuma. All rights reserved. // #import "LNLocalizedStringCollectionOperation.h" #import "IDEIndex.h" #import "IDEWorkspace.h" #import "IDEIndexCollection.h" #import "DVTFilePath.h" #import "LNLocalizationCollection.h" @interface LNLocalizedStringCollectionOperation () @property (nonatomic, strong) NSArray *collections; @property (nonatomic, strong) NSString *workspaceFilePath; @end @implementation LNLocalizedStringCollectionOperation - (instancetype)initWithIndex:(IDEIndex *)index { self = [super init]; if (self) { self.index = index; } return self; } - (void)main { @autoreleasepool { if (self.isCancelled) { return; } if (!self.index) { return; } [self processLocalizedString]; if (self.isCancelled) { return; } if (self.collectionCompletedBlock) { dispatch_async(dispatch_get_main_queue(), ^{ self.collectionCompletedBlock(self.workspaceFilePath, self.collections); }); } [self cleanup]; } } - (void)processLocalizedString { IDEWorkspace *workspace = [self.index valueForKey:@"_workspace"]; DVTFilePath *representingFilePath = workspace.representingFilePath; self.workspaceFilePath = representingFilePath.pathString; NSMutableArray *mutableCollections = [[NSMutableArray alloc] init]; if (self.workspaceFilePath) { NSString *projectRootPath = [[self.workspaceFilePath stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]; // Find .strings files IDEIndexCollection *indexCollection = [self.index filesContaining:@".strings" anchorStart:NO anchorEnd:NO subsequence:NO ignoreCase:YES cancelWhen:nil]; for (DVTFilePath *filePath in indexCollection) { if (self.isCancelled) { return; } NSString *pathString = filePath.pathString; BOOL parseStringsFilesOutsideWorkspaceProject = YES; if (parseStringsFilesOutsideWorkspaceProject || (!parseStringsFilesOutsideWorkspaceProject && [pathString rangeOfString:projectRootPath].location != NSNotFound)) { // Create localization collection LNLocalizationCollection *collection = [LNLocalizationCollection localizationCollectionWithContentsOfFile:pathString]; [mutableCollections addObject:collection]; } } self.collections = [mutableCollections copy]; } } - (void)cleanup { self.index = nil; } @end ================================================ FILE: Lin/LNPopoverContentView.h ================================================ // // LNPopoverContentView.h // Lin // // Created by Tanaka Katsuma on 2013/09/06. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import extern NSString * const LNPopoverContentViewLocalizationKey; extern NSString * const LNPopoverContentViewLocalizationDidSelectNotification; extern NSString * const LNPopoverContentViewAlertDidDismissNotification; extern NSString * const LNPopoverContentViewDetachButtonDidClickNotification; @interface LNPopoverContentView : NSView @property (nonatomic, weak, readonly) NSTableView *tableView; @property (nonatomic, weak, readonly) NSButton *detachButton; @property (nonatomic, copy) NSArray *collections; @property (nonatomic, copy) NSString *searchString; @end ================================================ FILE: Lin/LNPopoverContentView.m ================================================ // // LNPopoverContentView.m // Lin // // Created by Tanaka Katsuma on 2013/09/06. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNPopoverContentView.h" // Categories #import "NSTableView+editedColumnIdentifier.h" // Models #import "LNLocalizationCollection.h" #import "LNLocalization.h" // Views #import "LNTableHeaderCell.h" #import "LNAlertAccessoryView.h" NSString * const LNPopoverContentViewLocalizationKey = @"LNPopoverContentViewLocalizationKey"; NSString * const LNPopoverContentViewLocalizationDidSelectNotification = @"LNPopoverContentViewRowDidDoubleClickNotification"; NSString * const LNPopoverContentViewAlertDidDismissNotification = @"LNPopoverContentViewAlertDidDismissNotification"; NSString * const LNPopoverContentViewDetachButtonDidClickNotification = @"LNPopoverContentViewDetachButtonDidClickNotification"; @interface LNPopoverContentView () @property (nonatomic, weak, readwrite) IBOutlet NSTableView *tableView; @property (nonatomic, weak, readwrite) IBOutlet NSButton *detachButton; @property (nonatomic, strong) NSMutableArray *localizations; @property (nonatomic, strong) NSMutableArray *sortedLocalizations; - (IBAction)addLocalization:(id)sender; - (IBAction)deleteLocalization:(id)sender; - (IBAction)detachPopover:(id)sender; @end @implementation LNPopoverContentView - (void)awakeFromNib { [super awakeFromNib]; // Set default sort order NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"key" ascending:YES selector:@selector(compare:)]; [self.tableView setSortDescriptors:@[sortDescriptor]]; // Register to notification center [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidEndEditing:) name:NSControlTextDidEndEditingNotification object:nil]; } - (void)dealloc { // Remove from notification center [[NSNotificationCenter defaultCenter] removeObserver:self name:NSControlTextDidEndEditingNotification object:nil]; } #pragma mark - Accessors - (void)setTableView:(NSTableView *)tableView { _tableView = tableView; // Set double click action [_tableView setTarget:self]; [_tableView setDoubleAction:@selector(tableViewDidDoubleClick:)]; } - (void)setCollections:(NSArray *)collections { _collections = collections; // Update [self configureView]; } - (void)setSearchString:(NSString *)searchString { _searchString = searchString; // Update [self configureView]; } #pragma mark - Notifications - (void)textDidEndEditing:(NSNotification *)notification { NSInteger editedRow = [self.tableView editedRow]; NSInteger editedColumn = [self.tableView editedColumn]; if (editedRow >= 0 && editedColumn >= 0) { NSTextView *textView = (NSTextView *)[notification.userInfo objectForKey:@"NSFieldEditor"]; // Create a new localization LNLocalization *localization = [self.sortedLocalizations objectAtIndex:editedRow]; NSString *key = localization.key; NSString *value = localization.value; NSString *columnIdentifier = [self.tableView editedColumnIdentifier]; if ([columnIdentifier isEqualToString:@"key"]) { key = textView.textStorage.string; } else if ([columnIdentifier isEqualToString:@"value"]) { value = textView.textStorage.string; } LNLocalization *newLocalization = [LNLocalization localizationWithKey:key value:value entityRange:localization.entityRange keyRange:localization.keyRange valueRange:localization.valueRange collection:localization.collection]; // Replace in file [localization.collection replaceLocalization:localization withLocalization:newLocalization]; // Update [self configureView]; } } #pragma mark - Actions - (void)tableViewDidDoubleClick:(id)sender { NSInteger clickedRow = [self.tableView clickedRow]; if (clickedRow >= 0) { LNLocalization *localization = [self.sortedLocalizations objectAtIndex:clickedRow]; // Post notification [[NSNotificationCenter defaultCenter] postNotificationName:LNPopoverContentViewLocalizationDidSelectNotification object:self userInfo:@{LNPopoverContentViewLocalizationKey: localization}]; } } - (IBAction)addLocalization:(id)sender { // Create alert NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSViewController *viewController = [[NSViewController alloc] initWithNibName:@"LNAlertAccessoryView" bundle:bundle]; LNAlertAccessoryView *accessoryView = (LNAlertAccessoryView *)viewController.view; accessoryView.collections = self.collections; NSAlert *alert = [NSAlert alertWithMessageText:@"Lin" defaultButton:@"OK" alternateButton:@"Cancel" otherButton:nil informativeTextWithFormat:@"Input a key/value for a new localization."]; alert.accessoryView = accessoryView; NSButton *button = [[alert buttons] objectAtIndex:0]; accessoryView.button = button; // Set icon NSString *filePath = [bundle pathForResource:@"icon120" ofType:@"tiff"]; NSImage *icon = [[NSImage alloc] initWithContentsOfFile:filePath]; [alert setIcon:icon]; // Show alert switch ([alert runModal]) { case NSAlertDefaultReturn: { // Create a new localization LNAlertAccessoryView *accessoryView = (LNAlertAccessoryView *)alert.accessoryView; LNLocalizationCollection *collection = accessoryView.selectedCollection; NSString *key = accessoryView.inputtedKey; NSString *value = accessoryView.inputtedValue; LNLocalization *localization = [LNLocalization localizationWithKey:key value:value entityRange:NSMakeRange(NSNotFound, 0) keyRange:NSMakeRange(NSNotFound, 0) valueRange:NSMakeRange(NSNotFound, 0) collection:collection]; // Add localization to file [collection addLocalization:localization]; // Update [self configureView]; } default: { // Post notification [[NSNotificationCenter defaultCenter] postNotificationName:LNPopoverContentViewAlertDidDismissNotification object:self userInfo:nil]; } break; } } - (IBAction)deleteLocalization:(id)sender { NSInteger selectedRow = [self.tableView selectedRow]; if (selectedRow >= 0) { [self.tableView beginUpdates]; // Delete localization from array LNLocalization *localization = [self.sortedLocalizations objectAtIndex:selectedRow]; NSInteger index = [self.localizations indexOfObject:localization]; [self.localizations removeObjectAtIndex:index]; // Filter localizations [self filterLocalizations]; // Delete localization from file LNLocalizationCollection *collection = localization.collection; [collection deleteLocalization:localization]; // Delete localization from table view [self.tableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:selectedRow] withAnimation:NSTableViewAnimationEffectFade]; [self.tableView endUpdates]; } } - (IBAction)detachPopover:(id)sender { // Post notification [[NSNotificationCenter defaultCenter] postNotificationName:LNPopoverContentViewDetachButtonDidClickNotification object:self userInfo:nil]; } #pragma mark - Updating and Drawing the View - (void)reloadLocalizations { NSMutableArray *localizations = [NSMutableArray array]; for (LNLocalizationCollection *collection in self.collections) { [localizations addObjectsFromArray:[collection.localizations allObjects]]; } self.localizations = localizations; } - (void)filterLocalizations { // Filter localizations NSArray *filteredLocalizations = self.localizations; if (self.searchString.length > 0) { filteredLocalizations = [filteredLocalizations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"key contains[c] %@", self.searchString]]; } // Sort localizations self.sortedLocalizations = [[filteredLocalizations sortedArrayUsingDescriptors:self.tableView.sortDescriptors] mutableCopy]; } - (void)configureView { // Reload localizations [self reloadLocalizations]; // Filter localizations [self filterLocalizations]; // Update table view [self.tableView reloadData]; } #pragma mark - NSTableViewDataSource - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { return self.sortedLocalizations.count; } - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { LNLocalization *localization = [self.sortedLocalizations objectAtIndex:row]; NSString *identifier = tableColumn.identifier; if([identifier isEqualToString:@"table"]) { return [localization.collection.filePath lastPathComponent]; } else if ([identifier isEqualToString:@"language"]) { return localization.collection.languageDesignation; } else if ([identifier isEqualToString:@"key"]) { return localization.key; } else if ([identifier isEqualToString:@"value"]) { return localization.value; } return nil; } - (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors { // Update [self configureView]; } #pragma mark - NSTableViewDelegate - (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)clickedTableColumn { for (NSTableColumn *tableColumn in [tableView tableColumns]) { LNTableHeaderCell *headerCell = (LNTableHeaderCell*)[tableColumn headerCell]; if (tableColumn == clickedTableColumn) { [headerCell setSortAscending:[[[tableView sortDescriptors] objectAtIndex:0] ascending] priority:0]; } else { [headerCell setSortAscending:NO priority:1]; } } } @end ================================================ FILE: Lin/LNPopoverContentView.xib ================================================ ================================================ FILE: Lin/LNPopoverWindow.h ================================================ // // LNPopoverWindow.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNPopoverWindow : NSWindow + (instancetype)popoverWindow; @end ================================================ FILE: Lin/LNPopoverWindow.m ================================================ // // LNPopoverWindow.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNPopoverWindow.h" // Views #import "LNPopoverContentView.h" // Controllers #import "LNPopoverWindowController.h" static NSString * const kLNPopoverWindowToolbarSearchFieldIdentifier = @"Search"; @interface LNPopoverWindow () @property (nonatomic, strong) NSSearchField *searchField; @end @implementation LNPopoverWindow + (instancetype)popoverWindow { LNPopoverWindow *popoverWindow = [[LNPopoverWindow alloc] initWithContentRect:NSZeroRect styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask) backing:NSBackingStoreBuffered defer:NO]; popoverWindow.title = @"Lin"; popoverWindow.level = NSFloatingWindowLevel; popoverWindow.backgroundColor = [NSColor whiteColor]; [popoverWindow.contentView setAutoresizesSubviews:YES]; return popoverWindow; } - (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag]; if (self) { // Create toolbar NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"Toolbar"]; toolbar.delegate = self; toolbar.displayMode = NSToolbarDisplayModeIconOnly; [self setToolbar:toolbar]; } return self; } #pragma mark - Actions - (void)textFieldDidReturn:(id)sender { [self controlTextDidChange:nil]; } #pragma mark - NSToolbarDelegate - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar { return @[NSToolbarFlexibleSpaceItemIdentifier, kLNPopoverWindowToolbarSearchFieldIdentifier]; } - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar { return @[NSToolbarFlexibleSpaceItemIdentifier, kLNPopoverWindowToolbarSearchFieldIdentifier]; } - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag { NSToolbarItem *toolbarItem = nil; if ([itemIdentifier isEqualToString:kLNPopoverWindowToolbarSearchFieldIdentifier]) { toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier]; NSSearchField *searchField = [[NSSearchField alloc] init]; [searchField setDelegate:self]; [searchField setTarget:self]; [searchField setAction:@selector(textFieldDidReturn:)]; [toolbarItem setView:searchField]; self.searchField = searchField; } return toolbarItem; } #pragma mark - NSTextFieldDelegate - (void)controlTextDidChange:(NSNotification *)obj { LNPopoverWindowController *popoverWindowController = (LNPopoverWindowController *)self.windowController; LNPopoverContentView *contentView = (LNPopoverContentView *)popoverWindowController.popoverContentViewController.view; contentView.searchString = self.searchField.stringValue; } @end ================================================ FILE: Lin/LNPopoverWindowController.h ================================================ // // LNPopoverWindowController.h // Lin // // Created by Tanaka Katsuma on 2013/09/20. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class LNPopoverContentViewController; extern NSString * const LNPopoverWindowControllerWindowWillCloseNotification; @interface LNPopoverWindowController : NSWindowController @property (nonatomic, strong) NSViewController *popoverContentViewController; - (instancetype)initWithPopoverContentViewController:(NSViewController *)popoverContentViewController; @end ================================================ FILE: Lin/LNPopoverWindowController.m ================================================ // // LNPopoverWindowController.m // Lin // // Created by Tanaka Katsuma on 2013/09/20. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNPopoverWindowController.h" // Views #import "LNPopoverWindow.h" NSString * const LNPopoverWindowControllerWindowWillCloseNotification = @"LNPopoverWindowControllerWindowWillCloseNotification"; @implementation LNPopoverWindowController - (instancetype)initWithPopoverContentViewController:(NSViewController *)popoverContentViewController { LNPopoverWindow *popoverWindow = [LNPopoverWindow popoverWindow]; popoverWindow.delegate = self; self = [super initWithWindow:popoverWindow]; if (self) { self.popoverContentViewController = popoverContentViewController; } return self; } #pragma mark - Accessors - (void)setPopoverContentViewController:(NSViewController *)popoverContentViewController { // Remove previous content view if (self.popoverContentViewController) { [self.popoverContentViewController.view removeFromSuperview]; } _popoverContentViewController = popoverContentViewController; // Set content view of the window self.popoverContentViewController.view.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; [self.window.contentView setFrame:self.popoverContentViewController.view.bounds]; [self.window.contentView addSubview:self.popoverContentViewController.view]; } #pragma mark - NSWindowDelegate - (void)windowWillClose:(NSNotification *)notification { // Post notification [[NSNotificationCenter defaultCenter] postNotificationName:LNPopoverWindowControllerWindowWillCloseNotification object:self userInfo:nil]; } @end ================================================ FILE: Lin/LNRegularExpressionPattern+type.h ================================================ // // LNRegularExpressionPattern+type.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNRegularExpressionPattern.h" // Models #import "LNEntity.h" @interface LNRegularExpressionPattern (type) @property (nonatomic, assign, readonly) LNEntityType type; + (instancetype)patternWithType:(LNEntityType)type; @end ================================================ FILE: Lin/LNRegularExpressionPattern+type.m ================================================ // // LNRegularExpressionPattern+type.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNRegularExpressionPattern+type.h" #import static NSString * const LNRegularExpressionPatternTypePropertyKey = @"type"; @implementation LNRegularExpressionPattern (type) - (LNEntityType)type { return [objc_getAssociatedObject(self, (__bridge const void *)(LNRegularExpressionPatternTypePropertyKey)) unsignedIntegerValue]; } - (void)setType:(LNEntityType)type { objc_setAssociatedObject(self, (__bridge const void *)(LNRegularExpressionPatternTypePropertyKey), @(type), OBJC_ASSOCIATION_ASSIGN); } + (instancetype)patternWithType:(LNEntityType)type { LNRegularExpressionPattern *regularExpression = nil; NSString *pettern = nil; NSUInteger numberOfRanges = 0; NSUInteger entityRangeIndex = 0; NSUInteger keyRangeIndex = 1; switch (type) { case LNEntityTypeLocalizedString: { pettern = @"NSLocalizedString\\s*\\(\\s*@\"(.*?)\"\\s*,\\s*(.*?)\\s*\\)"; numberOfRanges = 3; } break; case LNEntityTypeLocalizedStringForKey: { pettern = @"localizedStringForKey:\\s*@\"(.*?)\"\\s*value:\\s*(.*?)\\s*table:\\s*(.*?)"; numberOfRanges = 4; } break; case LNEntityTypeLocalizedStringFromTable: { pettern = @"NSLocalizedStringFromTable\\s*\\(\\s*@\"(.*?)\"\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*\\)"; numberOfRanges = 4; } break; case LNEntityTypeLocalizedStringFromTableInBundle: { pettern = @"NSLocalizedStringFromTableInBundle\\s*\\(\\s*@\"(.*?)\"\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*\\)"; numberOfRanges = 5; } break; case LNEntityTypeLocalizedStringWithDefaultValue: { pettern = @"NSLocalizedStringWithDefaultValue\\s*\\(\\s*@\"(.*?)\"\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*,\\s*(.*?)\\s*\\)"; numberOfRanges = 6; } break; } if (pettern) { regularExpression = [LNRegularExpressionPattern patternWithString:pettern numberOfRanges:numberOfRanges entityRangeIndex:entityRangeIndex keyRangeIndex:keyRangeIndex]; regularExpression.type = type; } return regularExpression; } @end ================================================ FILE: Lin/LNRegularExpressionPattern.h ================================================ // // LNRegularExpressionPattern.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNRegularExpressionPattern : NSObject @property (nonatomic, copy, readonly) NSString *pattern; @property (nonatomic, assign, readonly) NSUInteger numberOfRanges; @property (nonatomic, assign, readonly) NSUInteger entityRangeIndex; @property (nonatomic, assign, readonly) NSUInteger keyRangeIndex; + (instancetype)patternWithString:(NSString *)string numberOfRanges:(NSUInteger)numberOfRanges entityRangeIndex:(NSUInteger)entityRangeIndex keyRangeIndex:(NSUInteger)keyRangeIndex; - (instancetype)initWithString:(NSString *)string numberOfRanges:(NSUInteger)numberOfRanges entityRangeIndex:(NSUInteger)entityRangeIndex keyRangeIndex:(NSUInteger)keyRangeIndex; @end ================================================ FILE: Lin/LNRegularExpressionPattern.m ================================================ // // LNRegularExpressionPattern.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNRegularExpressionPattern.h" @interface LNRegularExpressionPattern () @property (nonatomic, copy, readwrite) NSString *pattern; @property (nonatomic, assign, readwrite) NSUInteger numberOfRanges; @property (nonatomic, assign, readwrite) NSUInteger entityRangeIndex; @property (nonatomic, assign, readwrite) NSUInteger keyRangeIndex; @end @implementation LNRegularExpressionPattern + (instancetype)patternWithString:(NSString *)string numberOfRanges:(NSUInteger)numberOfRanges entityRangeIndex:(NSUInteger)entityRangeIndex keyRangeIndex:(NSUInteger)keyRangeIndex { return [[self alloc] initWithString:string numberOfRanges:numberOfRanges entityRangeIndex:entityRangeIndex keyRangeIndex:keyRangeIndex]; } - (instancetype)initWithString:(NSString *)string numberOfRanges:(NSUInteger)numberOfRanges entityRangeIndex:(NSUInteger)entityRangeIndex keyRangeIndex:(NSUInteger)keyRangeIndex { self = [super init]; if (self) { self.pattern = string; self.numberOfRanges = numberOfRanges; self.entityRangeIndex = entityRangeIndex; self.keyRangeIndex = keyRangeIndex; } return self; } @end ================================================ FILE: Lin/LNTableCornerView.h ================================================ // // LNTableCornerView.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNTableCornerView : NSView @end ================================================ FILE: Lin/LNTableCornerView.m ================================================ // // LNTableCornerView.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNTableCornerView.h" @implementation LNTableCornerView - (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; // Background [[NSColor whiteColor] setFill]; NSRectFill(dirtyRect); // Draw separator [[NSColor colorWithDeviceWhite:204.0/255.0 alpha:1.0] setStroke]; [NSBezierPath strokeLineFromPoint:NSMakePoint(dirtyRect.origin.x, 0.5) toPoint:NSMakePoint(dirtyRect.origin.x + dirtyRect.size.width, 0.5)]; } @end ================================================ FILE: Lin/LNTableHeaderCell.h ================================================ // // LNTableHeaderCell.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNTableHeaderCell : NSTableHeaderCell @property (nonatomic, weak) NSTableView *tableView; - (void)setSortAscending:(BOOL)ascending priority:(NSInteger)priority; @end ================================================ FILE: Lin/LNTableHeaderCell.m ================================================ // // LNTableHeaderCell.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNTableHeaderCell.h" static const NSInteger kLNTableHeaderCellSortIndicatorWidth = 8; static const NSInteger kLNTableHeaderCellSortIndicatorHeight = 7; static const NSInteger kLNTableHeaderCellSortIndicatorMarginX = 4; static const NSInteger kLNTableHeaderCellSortIndicatorMarginY = 6; @interface LNTableHeaderCell () @property (nonatomic, assign) BOOL ascending; @property (nonatomic, assign) NSInteger priority; - (void)drawContentInRect:(NSRect)rect highlighted:(BOOL)highlighted; @end @implementation LNTableHeaderCell - (instancetype)init { self = [super init]; if (self) { self.priority = 1; } return self; } #pragma mark - Accessors - (void)setSortAscending:(BOOL)ascending priority:(NSInteger)priority { self.ascending = ascending; self.priority = priority; } #pragma mark - Drawing the View - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { [self drawContentInRect:cellFrame highlighted:NO]; [self drawSortIndicatorWithFrame:cellFrame inView:controlView ascending:self.ascending priority:self.priority]; } - (void)highlight:(BOOL)flag withFrame:(NSRect)cellFrame inView:(NSView *)controlView { [self drawContentInRect:cellFrame highlighted:YES]; [self drawSortIndicatorWithFrame:cellFrame inView:controlView ascending:self.ascending priority:self.priority]; } - (void)drawContentInRect:(NSRect)rect highlighted:(BOOL)highlighted { // Draw background NSRect backgroundRect = rect; backgroundRect.size.width -= 1; if (highlighted) { [[NSColor colorWithDeviceWhite:153.0/255.0 alpha:1.0] set]; } else { [[NSColor whiteColor] set]; } NSRectFill(backgroundRect); // Draw separator [[NSColor colorWithDeviceWhite:204.0/255.0 alpha:1.0] setStroke]; [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x, rect.size.height - 0.5) toPoint:NSMakePoint(rect.origin.x + rect.size.width, rect.size.height - 0.5)]; // Draw title NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedStringValue]]; NSDictionary *attributes; if (highlighted) { attributes = @{ NSForegroundColorAttributeName: [NSColor whiteColor], NSFontAttributeName: [NSFont systemFontOfSize:12.0] }; } else { attributes = @{ NSForegroundColorAttributeName: [NSColor colorWithDeviceWhite:153.0/255.0 alpha:1.0], NSFontAttributeName: [NSFont systemFontOfSize:12.0] }; } [attributedString addAttributes:attributes range:NSMakeRange(0, [attributedString length])]; NSRect titleRect = rect; titleRect.origin.x += 3; titleRect.origin.y += 0; [attributedString drawInRect:titleRect]; } - (void)drawSortIndicatorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView ascending:(BOOL)ascending priority:(NSInteger)priority { NSBezierPath *path = [NSBezierPath bezierPath]; if (ascending) { NSPoint p = NSMakePoint(cellFrame.origin.x + cellFrame.size.width - kLNTableHeaderCellSortIndicatorWidth - kLNTableHeaderCellSortIndicatorMarginX, cellFrame.origin.y + cellFrame.size.height - kLNTableHeaderCellSortIndicatorMarginY); [path moveToPoint:p]; p.x += kLNTableHeaderCellSortIndicatorWidth / 2.0; p.y -= kLNTableHeaderCellSortIndicatorHeight; [path lineToPoint:p]; p.x += kLNTableHeaderCellSortIndicatorWidth / 2.0; p.y += kLNTableHeaderCellSortIndicatorHeight; [path lineToPoint:p]; } else { NSPoint p = NSMakePoint(cellFrame.origin.x + cellFrame.size.width - kLNTableHeaderCellSortIndicatorWidth - kLNTableHeaderCellSortIndicatorMarginX, cellFrame.origin.y + cellFrame.size.height - kLNTableHeaderCellSortIndicatorHeight - kLNTableHeaderCellSortIndicatorMarginY); [path moveToPoint:p]; p.x += kLNTableHeaderCellSortIndicatorWidth / 2.0; p.y += kLNTableHeaderCellSortIndicatorHeight; [path lineToPoint:p]; p.x += kLNTableHeaderCellSortIndicatorWidth / 2.0; p.y -= kLNTableHeaderCellSortIndicatorHeight; [path lineToPoint:p]; } [path closePath]; if (priority == 0) { [[NSColor colorWithDeviceWhite:153.0/255.0 alpha:1.0] set]; } else { [[NSColor clearColor] set]; } [path fill]; } @end ================================================ FILE: Lin/LNTableView.h ================================================ // // LNTableView.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNTableView : NSTableView @end ================================================ FILE: Lin/LNTableView.m ================================================ // // LNTableView.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNTableView.h" // Views #import "LNTableCornerView.h" #import "LNTableHeaderCell.h" @implementation LNTableView - (void)awakeFromNib { [super awakeFromNib]; // Set corner view NSView *cornerView = [self cornerView]; LNTableCornerView *newCornerView = [[LNTableCornerView alloc] initWithFrame:cornerView.frame]; [self setCornerView:newCornerView]; // Change header cell for (NSTableColumn *tableColumn in [self tableColumns]) { NSTableHeaderCell *headerCell = [tableColumn headerCell]; LNTableHeaderCell *newHeaderCell = [[LNTableHeaderCell alloc] init]; newHeaderCell.tableView = self; [newHeaderCell setAttributedStringValue:[headerCell attributedStringValue]]; [tableColumn setHeaderCell:newHeaderCell]; } } @end ================================================ FILE: Lin/LNUserDefaultsManager.h ================================================ // // LNUserDefaultsManager.h // Lin // // Created by Tanaka Katsuma on 2013/09/22. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNUserDefaultsManager : NSObject @property (nonatomic, assign, getter = isEnabled) BOOL enabled; + (instancetype)sharedManager; @end ================================================ FILE: Lin/LNUserDefaultsManager.m ================================================ // // LNUserDefaultsManager.m // Lin // // Created by Tanaka Katsuma on 2013/09/22. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNUserDefaultsManager.h" static NSString * const LNUserDefaultManagerEnabledKey = @"jp.questbeat.Lin.enabled"; @implementation LNUserDefaultsManager + (instancetype)sharedManager { static id _sharedManager; static dispatch_once_t _onceToken; dispatch_once(&_onceToken, ^{ _sharedManager = [[self alloc] init]; }); return _sharedManager; } - (instancetype)init { self = [super init]; if (self) { // Register defaults NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults registerDefaults:@{LNUserDefaultManagerEnabledKey: @(YES)}]; [userDefaults synchronize]; } return self; } #pragma mark - Accessors - (void)setEnabled:(BOOL)enabled { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool:enabled forKey:LNUserDefaultManagerEnabledKey]; [userDefaults synchronize]; } - (BOOL)isEnabled { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; return [userDefaults boolForKey:LNUserDefaultManagerEnabledKey]; } @end ================================================ FILE: Lin/Lin-Info.plist ================================================ CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier jp.questbeat.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 2.0 CFBundleSignature ???? CFBundleVersion 1 DVTPlugInCompatibilityUUIDs 37B30044-3B14-46BA-ABAA-F01000C27B63 640F884E-CE55-4B40-87C0-8869546CAB7A A2E4D43F-41F4-4FB9-BB94-7177011C9AED LSApplicationCategoryType NSHumanReadableCopyright Copyright © 2013年 Tanaka Katsuma. All rights reserved. NSPrincipalClass Lin XC4Compatible XC5Compatible XCGCReady XCPluginHasUI ================================================ FILE: Lin/Lin-Prefix.pch ================================================ // // Prefix header // // The contents of this file are implicitly included at the beginning of every source file. // #ifdef __OBJC__ #import #endif ================================================ FILE: Lin/Lin.h ================================================ // // Lin.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @class IDEIndex; @interface Lin : NSObject + (void)pluginDidLoad:(NSBundle *)bundle; + (instancetype)sharedPlugIn; - (void)indexNeedsUpdate:(IDEIndex *)index; - (void)removeLocalizationsForIndex:(IDEIndex *)index; @end ================================================ FILE: Lin/Lin.m ================================================ // // Lin.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "Lin.h" // Xcode #import "IDEWorkspace.h" #import "DVTFilePath.h" #import "IDEIndex.h" #import "IDEIndexCollection.h" #import "IDEEditorDocument.h" #import "IDEWorkspaceWindow.h" #import "DVTSourceTextView.h" // Categories #import "NSBundle+versions.h" // Shared #import "LNUserDefaultsManager.h" // Models #import "LNDetector.h" #import "LNEntity.h" #import "LNLocalizationCollection.h" #import "LNLocalization.h" // Views #import "LNPopoverContentView.h" // Controllers #import "LNPopoverWindowController.h" #import "LNLocalizedStringCollectionOperation.h" static Lin *_sharedPlugin = nil; @interface NSPopover () - (id)_popoverWindow; @end @interface Lin () @property (nonatomic, strong) NSPopover *popover; @property (nonatomic, strong) LNPopoverWindowController *popoverWindowController; @property (nonatomic, strong) NSTextView *textView; @property (nonatomic, strong) LNDetector *detector; @property (nonatomic, strong) NSMutableDictionary *workspaceLocalizations; @property (nonatomic, copy) NSString *currentWorkspaceFilePath; @property (nonatomic, unsafe_unretained) NSResponder *previousFirstResponder; @property (nonatomic, assign, getter = isActivated) BOOL activated; @property (nonatomic, strong) NSMenuItem *enableMenuItem; @property (nonatomic, strong) NSMenuItem *showWindowMenuItem; @property (nonatomic, strong) NSOperationQueue *collectionProcessQueue; @end @implementation Lin + (void)pluginDidLoad:(NSBundle *)bundle { static dispatch_once_t _onceToken; dispatch_once(&_onceToken, ^{ _sharedPlugin = [[self alloc] init]; }); } + (instancetype)sharedPlugIn { return _sharedPlugin; } - (instancetype)init { self = [super init]; if (self) { // Initialization self.detector = [LNDetector detector]; self.workspaceLocalizations = [NSMutableDictionary dictionary]; // Create menu [self createMenuItem]; // Load views [self instantiatePopover]; [self instantiatePopoverWindowController]; // Register to notification center [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(workspaceWindowDidBecomeMain:) name:NSWindowDidBecomeMainNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(indexDidIndexWorkspace:) name:@"IDEIndexDidIndexWorkspaceNotification" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(editorDocumentDidSave:) name:@"IDEEditorDocumentDidSaveNotification" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(popoverWindowControllerWindowWillClose:) name:LNPopoverWindowControllerWindowWillCloseNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(popoverContentViewLocalizationDidSelect:) name:LNPopoverContentViewLocalizationDidSelectNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(popoverContentViewAlertDidDismiss:) name:LNPopoverContentViewAlertDidDismissNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(popoverContentViewDetachButtonDidClick:) name:LNPopoverContentViewDetachButtonDidClickNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuDidChange:) name:NSMenuDidChangeItemNotification object:nil]; // Activate if enabled if ([[LNUserDefaultsManager sharedManager] isEnabled]) { [self activate]; } self.collectionProcessQueue = [[NSOperationQueue alloc] init]; self.collectionProcessQueue.maxConcurrentOperationCount = 1; } return self; } - (void)instantiatePopover { NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSViewController *contentViewController = [[NSViewController alloc] initWithNibName:@"LNPopoverContentView" bundle:bundle]; NSPopover *popover = [[NSPopover alloc] init]; popover.delegate = self; popover.behavior = NSPopoverBehaviorTransient; popover.appearance = NSPopoverAppearanceMinimal; popover.animates = NO; popover.contentViewController = contentViewController; self.popover = popover; } - (void)instantiatePopoverWindowController { NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSViewController *contentViewController = [[NSViewController alloc] initWithNibName:@"LNPopoverContentView" bundle:bundle]; LNPopoverContentView *contentView = (LNPopoverContentView *)contentViewController.view; [contentView.detachButton setHidden:YES]; LNPopoverWindowController *popoverWindowController = [[LNPopoverWindowController alloc] initWithPopoverContentViewController:contentViewController]; self.popoverWindowController = popoverWindowController; } - (void)dealloc { // Deactivate [self deactivate]; // Remove from notification center [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeMainNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"IDEIndexDidIndexWorkspaceNotification" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:@"IDEEditorDocumentDidSaveNotification" object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:LNPopoverWindowControllerWindowWillCloseNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:LNPopoverContentViewLocalizationDidSelectNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:LNPopoverContentViewAlertDidDismissNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:LNPopoverContentViewDetachButtonDidClickNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMenuDidChangeItemNotification object:nil]; } #pragma mark - Managing Application State - (void)activate { if (!self.activated) { self.activated = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:NSTextDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChangeSelection:) name:NSTextViewDidChangeSelectionNotification object:nil]; } } - (void)deactivate { if (self.activated) { self.activated = NO; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSTextDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSTextViewDidChangeSelectionNotification object:nil]; } } #pragma mark - Notifications - (void)textDidChange:(NSNotification *)notification { if ([[notification object] isKindOfClass:[DVTSourceTextView class]]) { NSTextView *textView = (NSTextView *)[notification object]; self.textView = textView; // Find entity LNEntity *entity = [self selectedEntityInTextView:textView]; if (entity) { [self presentPopoverInTextView:textView entity:entity]; } else { [self dismissPopover]; } } } - (void)textViewDidChangeSelection:(NSNotification *)notification { if ([[notification object] isKindOfClass:[DVTSourceTextView class]]) { NSTextView *textView = (NSTextView *)[notification object]; self.textView = textView; // Find entity LNEntity *entity = [self selectedEntityInTextView:textView]; if (entity) { [self presentPopoverInTextView:textView entity:entity]; } else { [self dismissPopover]; } } } - (void)workspaceWindowDidBecomeMain:(NSNotification *)notification { if ([[notification object] isKindOfClass:[IDEWorkspaceWindow class]]) { NSWindow *workspaceWindow = (NSWindow *)[notification object]; NSWindowController *workspaceWindowController = (NSWindowController *)workspaceWindow.windowController; IDEWorkspace *workspace = (IDEWorkspace *)[workspaceWindowController valueForKey:@"_workspace"]; DVTFilePath *representingFilePath = workspace.representingFilePath; NSString *pathString = representingFilePath.pathString; self.currentWorkspaceFilePath = pathString; } } - (void)indexDidIndexWorkspace:(NSNotification *)notification { IDEIndex *index = (IDEIndex *)[notification object]; [self indexNeedsUpdate:index]; } - (void)editorDocumentDidSave:(NSNotification *)notification { IDEEditorDocument *editorDocument = (IDEEditorDocument *)[notification object]; DVTFilePath *filePath = editorDocument.filePath; NSString *pathString = filePath.pathString; // Check whether there are any changes to .strings NSArray *collections = [self.workspaceLocalizations objectForKey:self.currentWorkspaceFilePath]; for (LNLocalizationCollection *collection in collections) { if ([collection.filePath isEqualToString:pathString]) { [collection reloadLocalizations]; break; } } } - (void)popoverWindowControllerWindowWillClose:(NSNotification *)notification { // Instantiate popover [self instantiatePopover]; } - (void)popoverContentViewLocalizationDidSelect:(NSNotification *)notification { NSTextView *textView = self.textView; LNEntity *entity = [self selectedEntityInTextView:textView]; if (entity) { NSArray *selectedRanges = textView.selectedRanges; if (selectedRanges.count > 0) { NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue]; // Locate the key NSRange lineRange = [textView.textStorage.string lineRangeForRange:selectedRange]; NSRange keyRange = NSMakeRange(lineRange.location + entity.keyRange.location, entity.keyRange.length); // Replace LNLocalization *localization = [[notification userInfo] objectForKey:LNPopoverContentViewLocalizationKey]; [textView insertText:localization.key replacementRange:keyRange]; } } } - (void)popoverContentViewAlertDidDismiss:(NSNotification *)notification { // Show popover again [self presentPopoverInTextView:self.textView entity:[self selectedEntityInTextView:self.textView]]; } - (void)popoverContentViewDetachButtonDidClick:(NSNotification *)notification { [self preparePopoverWindow]; [self detachPopover]; } - (void)menuDidChange:(NSNotification *)notification { // Create menu item [self createMenuItem]; } #pragma mark - Detachig Popover - (void)preparePopoverWindow { // Resize popover window NSWindow *popoverWindow = [self.popover _popoverWindow]; [self.popoverWindowController.window setFrame:NSMakeRect(popoverWindow.frame.origin.x, popoverWindow.frame.origin.y - (80.0 / 2.0), self.popover.contentSize.width, self.popover.contentSize.height + 80.0) display:NO]; // Copy popover content LNPopoverContentView *popoverContentView = (LNPopoverContentView *)self.popover.contentViewController.view; LNPopoverContentView *popoverWindowContentView = (LNPopoverContentView *)self.popoverWindowController.popoverContentViewController.view; popoverWindowContentView.tableView.sortDescriptors = popoverContentView.tableView.sortDescriptors; popoverWindowContentView.collections = popoverContentView.collections; popoverWindowContentView.searchString = popoverContentView.searchString; } - (void)detachPopover { [self dismissPopover]; [self.popoverWindowController showWindow:nil]; } #pragma mark - Entity - (LNEntity *)selectedEntityInTextView:(NSTextView *)textView { NSArray *selectedRanges = textView.selectedRanges; if (selectedRanges.count > 0) { NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue]; // Locate the line containing the caret NSString *string = textView.textStorage.string; NSRange lineRange = [string lineRangeForRange:selectedRange]; NSString *lineString = [string substringWithRange:lineRange]; NSRange selectedRangeInLine = NSMakeRange(selectedRange.location - lineRange.location, selectedRange.length); // Search for the entities NSArray *entities = [self.detector entitiesInString:lineString]; for (LNEntity *entity in entities) { if (NSLocationInRange(selectedRangeInLine.location, entity.entityRange)) { return entity; } } } return nil; } #pragma mark - Menu - (void)createMenuItem { NSMenuItem *editorMenuItem = [[NSApp mainMenu] itemWithTitle:@"Editor"]; if (editorMenuItem && [[editorMenuItem submenu] itemWithTitle:@"Lin"] == nil) { // Load defaults BOOL enabled = [[LNUserDefaultsManager sharedManager] isEnabled]; NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@"Lin" action:NULL keyEquivalent:@""]; NSMenu *submenu = [[NSMenu alloc] initWithTitle:@"Lin"]; menuItem.submenu = submenu; // Enable Lin NSMenuItem *enableMenuItem = [[NSMenuItem alloc] initWithTitle:@"Enable Lin" action:@selector(toggleEnabled:) keyEquivalent:@""]; [enableMenuItem setTarget:self]; enableMenuItem.state = enabled ? NSOnState : NSOffState; [submenu addItem:enableMenuItem]; self.enableMenuItem = enableMenuItem; // Show Window NSMenuItem *showWindowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Show Window" action:@selector(showWindow:) keyEquivalent:@""]; [showWindowMenuItem setTarget:self]; [submenu addItem:showWindowMenuItem]; self.showWindowMenuItem = showWindowMenuItem; // Separator [submenu addItem:[NSMenuItem separatorItem]]; // Version Info NSMenuItem *versionInfoMenuItem = [[NSMenuItem alloc] initWithTitle:@"Version Info" action:@selector(showVersionInfo:) keyEquivalent:@""]; [versionInfoMenuItem setTarget:self]; [submenu addItem:versionInfoMenuItem]; [[editorMenuItem submenu] addItem:[NSMenuItem separatorItem]]; [[editorMenuItem submenu] addItem:menuItem]; } } - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { if (menuItem == self.showWindowMenuItem) { return [[LNUserDefaultsManager sharedManager] isEnabled]; } return YES; } - (void)toggleEnabled:(id)sender { // Save defaults LNUserDefaultsManager *userDefaultManager = [LNUserDefaultsManager sharedManager]; BOOL enabled = ![userDefaultManager isEnabled]; userDefaultManager.enabled = enabled; // Update menu item self.enableMenuItem.state = enabled ? NSOnState : NSOffState; // Activate/Deactivate if (enabled) { [self activate]; } else { [self deactivate]; } } - (void)showWindow:(id)sender { // Prepare window NSArray *collections = [self.workspaceLocalizations objectForKey:self.currentWorkspaceFilePath]; LNPopoverContentView *popoverWindowContentView = (LNPopoverContentView *)self.popoverWindowController.popoverContentViewController.view; popoverWindowContentView.collections = collections; popoverWindowContentView.searchString = @""; // Show window [self.popoverWindowController.window setFrame:NSMakeRect(0, 0, 500, 280) display:NO]; [self.popoverWindowController.window center]; [self.popoverWindowController showWindow:nil]; } - (void)showVersionInfo:(id)sender { // Create alert NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSAlert *alert = [NSAlert alertWithMessageText:@"Lin" defaultButton:@"OK" alternateButton:nil otherButton:@"Open Website" informativeTextWithFormat:@"Version %@\n\nCopyright (c) 2013 Katsuma Tanaka\n\nEmail: questbeat@gmail.com\nTwitter: @questbeat", [bundle shortVersionString]]; // Set icon NSString *filePath = [bundle pathForResource:@"icon120" ofType:@"tiff"]; NSImage *icon = [[NSImage alloc] initWithContentsOfFile:filePath]; [alert setIcon:icon]; // Show alert if ([alert runModal] == NSAlertOtherReturn) { [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://questbe.at/lin"]]; } } #pragma mark - Index - (void)indexNeedsUpdate:(IDEIndex *)index { DVTFilePath *workspaceFile = index.workspaceFile; NSString *workspaceFilePath = workspaceFile.pathString; if (workspaceFilePath) { [self.collectionProcessQueue cancelAllOperations]; [self updateLocalizationsForIndex:index]; } } - (void)updateLocalizationsForIndex:(IDEIndex *)index { LNLocalizedStringCollectionOperation *processOperation = [[LNLocalizedStringCollectionOperation alloc] initWithIndex:index]; processOperation.collectionCompletedBlock = ^(NSString *workspaceFilePath, NSArray *collections) { [self.workspaceLocalizations setObject:collections forKey:workspaceFilePath]; if ([workspaceFilePath isEqualToString:self.currentWorkspaceFilePath]) { if ([self.popover isShown]) { LNPopoverContentView *contentView = (LNPopoverContentView *)self.popover.contentViewController.view; contentView.collections = collections; } else if ([self.popoverWindowController.window isVisible]) { LNPopoverContentView *contentView = (LNPopoverContentView *)self.popoverWindowController.popoverContentViewController.view; contentView.collections = collections; } } }; [self.collectionProcessQueue addOperation:processOperation]; } - (void)removeLocalizationsForIndex:(IDEIndex *)index { DVTFilePath *workspaceFile = index.workspaceFile; NSString *workspaceFilePath = workspaceFile.pathString; if (workspaceFilePath) { [self.workspaceLocalizations removeObjectForKey:workspaceFilePath]; } } #pragma mark - Popover - (void)presentPopoverInTextView:(NSTextView *)textView entity:(LNEntity *)entity { if (![[LNUserDefaultsManager sharedManager] isEnabled]) { return; } NSArray *selectedRanges = textView.selectedRanges; if (selectedRanges.count > 0) { NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue]; // Locate the line containing the caret NSRange lineRange = [textView.textStorage.string lineRangeForRange:selectedRange]; // Stick popover at the beginning of the key NSRange keyRange = NSMakeRange(lineRange.location + entity.keyRange.location, 1); NSRect keyRectOnScreen = [textView firstRectForCharacterRange:keyRange actualRange:NULL]; NSRect keyRectOnWindow = [textView.window convertRectFromScreen:keyRectOnScreen]; NSRect keyRectOnTextView = [textView convertRect:keyRectOnWindow fromView:nil]; // Update or show popover NSArray *collections = [self.workspaceLocalizations objectForKey:self.currentWorkspaceFilePath]; NSString *key = [textView.textStorage.string substringWithRange:NSMakeRange(lineRange.location + entity.keyRange.location, entity.keyRange.length)]; if ([self.popoverWindowController.window isVisible]) { // Update popover content LNPopoverContentView *contentView = (LNPopoverContentView *)self.popoverWindowController.popoverContentViewController.view; contentView.collections = collections; contentView.searchString = key; } else { if ([self.popover isShown]) { // Update the position for popover when the cursor moved self.popover.positioningRect = keyRectOnTextView; // Update popover content LNPopoverContentView *contentView = (LNPopoverContentView *)self.popover.contentViewController.view; contentView.searchString = key; } else { // Show popover [self.popover showRelativeToRect:keyRectOnTextView ofView:textView preferredEdge:NSMinYEdge]; // Update popover content LNPopoverContentView *contentView = (LNPopoverContentView *)self.popover.contentViewController.view; contentView.collections = collections; contentView.searchString = key; } } } } - (void)dismissPopover { if ([self.popoverWindowController.window isVisible]) { // Update popover content NSArray *collections = [self.workspaceLocalizations objectForKey:self.currentWorkspaceFilePath]; LNPopoverContentView *contentView = (LNPopoverContentView *)self.popoverWindowController.popoverContentViewController.view; contentView.collections = collections; contentView.searchString = nil; } else { // Hide popover if (self.popover.shown) { [self.popover performClose:self]; } } } #pragma mark - NSPopoverDelegate - (void)popoverWillShow:(NSNotification *)notification { // Save first responder self.previousFirstResponder = [self.textView.window firstResponder]; } - (void)popoverDidShow:(NSNotification *)notification { // Reclaim key window and first responder [self.textView.window becomeKeyWindow]; [self.textView.window makeFirstResponder:self.previousFirstResponder]; } - (NSWindow *)detachableWindowForPopover:(NSPopover *)popover { // Prepare for detaching [self preparePopoverWindow]; return self.popoverWindowController.window; } @end ================================================ FILE: Lin/MethodSwizzle.h ================================================ // // MethodSwizzle.h // Lin // // Created by Tanaka Katsuma on 2013/08/24. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import void MethodSwizzle(Class cls, SEL org_sel, SEL alt_sel); ================================================ FILE: Lin/MethodSwizzle.m ================================================ // // MethodSwizzle.m // Lin // // Created by Tanaka Katsuma on 2013/08/24. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "MethodSwizzle.h" #import void MethodSwizzle(Class cls, SEL org_sel, SEL alt_sel) { Method org_method = nil, alt_method = nil; org_method = class_getInstanceMethod(cls, org_sel); alt_method = class_getInstanceMethod(cls, alt_sel); if (org_method != nil && alt_method != nil) { method_exchangeImplementations(org_method, alt_method); } } ================================================ FILE: Lin/NSBundle+versions.h ================================================ // // NSBundle+versions.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface NSBundle (versions) - (NSString *)shortVersionString; - (NSNumber *)buildNumber; @end ================================================ FILE: Lin/NSBundle+versions.m ================================================ // // NSBundle+versions.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "NSBundle+versions.h" @implementation NSBundle (versions) - (NSString *)shortVersionString { return [self objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; } - (NSNumber *)buildNumber { return [self objectForInfoDictionaryKey:@"CFBundleVersion"]; } @end ================================================ FILE: Lin/NSPopoverFrame+Lin.h ================================================ // // NSPopoverFrame+Lin.h // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "NSPopoverFrame.h" @interface NSPopoverFrame (Lin) @end ================================================ FILE: Lin/NSPopoverFrame+Lin.m ================================================ // // NSPopoverFrame+Lin.m // Lin // // Created by Tanaka Katsuma on 2013/09/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "NSPopoverFrame+Lin.h" #import #import "MethodSwizzle.h" @implementation NSPopoverFrame (Lin) + (void)load { MethodSwizzle(self, @selector(_drawMinimalPopoverAppearanceInRect:anchorEdge:anchorPoint:), @selector(jp_questbeat_lin_drawMinimalPopoverAppearanceInRect:anchorEdge:anchorPoint:)); } - (void)jp_questbeat_lin_drawMinimalPopoverAppearanceInRect:(struct CGRect)arg1 anchorEdge:(unsigned long long)arg2 anchorPoint:(struct CGPoint)arg3 { [self jp_questbeat_lin_drawMinimalPopoverAppearanceInRect:arg1 anchorEdge:arg2 anchorPoint:arg3]; // Check OS version SInt32 major = 0; SInt32 minor = 0; Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMinor, &minor); if ((major == 10 && minor <= 8) || major <= 9) { // Mac OS X Mountain Lion or older // This code will cause a problem on Max OS X 10.9 Mavericks (or maybe later) [[NSColor whiteColor] setFill]; NSRectFill(arg1); } else { // Mac OS X Mavericks or later CGPathRef path = [self _newMinimalAppearancePathInBounds:arg1 anchorEdge:arg2 anchorPoint:arg3 topCapOnly:NO arrowOffset:0]; CGImageRef maskImage = [self _imageMaskForPath:(struct CGPath *)path anchorEdge:arg2 anchorPoint:arg3]; NSBitmapImageRep *backgroundImageRep = [self backgroundImageRepWithSize:self.bounds.size maskImage:maskImage]; CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; CGImageRef backgroundImageRef = [backgroundImageRep CGImage]; CGContextDrawImage(context, self.bounds, backgroundImageRef); } } - (NSBitmapImageRep *)backgroundImageRepWithSize:(NSSize)size maskImage:(CGImageRef)maskImage { CGContextRef currentContext = [[NSGraphicsContext currentContext] graphicsPort]; CGContextSaveGState(currentContext); CGFloat scale = [self convertSizeToBacking:CGSizeMake(1, 1)].width; size.width *= scale; size.height *= scale; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast); CGContextClipToMask(context, CGRectMake(0, 0, size.width, size.height), maskImage); CGContextSetFillColorWithColor(context, [[NSColor whiteColor] CGColor]); CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height)); CGImageRef backgroundImageRef = CGBitmapContextCreateImage(context); NSBitmapImageRep *backgroundImageRep = [[NSBitmapImageRep alloc] initWithCGImage:backgroundImageRef]; CGImageRelease(backgroundImageRef); CGContextRelease(context); CGColorSpaceRelease(colorSpace); CGContextRestoreGState(currentContext); return backgroundImageRep; } @end ================================================ FILE: Lin/NSPopoverFrame.h ================================================ /* * Generated by class-dump 3.4 (64 bit). * * class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2012 by Steve Nygard. */ #import @class NSImage; @interface NSPopoverFrame : NSView - (void)_drawMinimalPopoverAppearanceInRect:(struct CGRect)arg1 anchorEdge:(unsigned long long)arg2 anchorPoint:(struct CGPoint)arg3; - (struct CGImage *)_imageMaskForPath:(struct CGPath *)arg1 anchorEdge:(unsigned long long)arg2 anchorPoint:(struct CGPoint)arg3; - (struct CGPath *)_newMinimalAppearancePathInBounds:(struct CGRect)arg1 anchorEdge:(unsigned long long)arg2 anchorPoint:(struct CGPoint)arg3 topCapOnly:(BOOL)arg4 arrowOffset:(double)arg5; - (struct CGPath *)_newMinimalAppearancePathInBounds:(struct CGRect)arg1 anchorEdge:(unsigned long long)arg2 arrowPosition:(double)arg3 topCapOnly:(BOOL)arg4 arrowOffset:(double)arg5; @end ================================================ FILE: Lin/NSTableView+editedColumnIdentifier.h ================================================ // // NSTableView+editedColumnIdentifier.h // Lin // // Created by Tanaka Katsuma on 2013/09/22. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface NSTableView (editedColumnIdentifier) - (NSString *)editedColumnIdentifier; @end ================================================ FILE: Lin/NSTableView+editedColumnIdentifier.m ================================================ // // NSTableView+editedColumnIdentifier.m // Lin // // Created by Tanaka Katsuma on 2013/09/22. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "NSTableView+editedColumnIdentifier.h" @implementation NSTableView (editedColumnIdentifier) - (NSString *)editedColumnIdentifier { NSInteger editedColumnIndex = [self editedColumn]; NSArray *tableColumns = [self tableColumns]; for (NSInteger i = 0; i < tableColumns.count; i++) { NSTableColumn *column = [tableColumns objectAtIndex:i]; if (i == editedColumnIndex) { return column.identifier; } } return nil; } @end ================================================ FILE: Lin/en.lproj/InfoPlist.strings ================================================ /* Localized versions of Info.plist keys */ ================================================ FILE: Lin.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ AA02CE8B17EE08240041C2BD /* LNAlertAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA02CE8A17EE08240041C2BD /* LNAlertAccessoryView.xib */; }; AA02CE8E17EE083A0041C2BD /* LNAlertAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = AA02CE8D17EE083A0041C2BD /* LNAlertAccessoryView.m */; }; AA1B7DA717C3C1EC00A3A6D7 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA1B7DA617C3C1EC00A3A6D7 /* Cocoa.framework */; }; AA1B7DB117C3C1EC00A3A6D7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AA1B7DAF17C3C1EC00A3A6D7 /* InfoPlist.strings */; }; AA1B7DBA17C3C20F00A3A6D7 /* Lin.m in Sources */ = {isa = PBXBuildFile; fileRef = AA1B7DB917C3C20F00A3A6D7 /* Lin.m */; }; AA20D87F17ECB12A006B7CA2 /* NSPopoverFrame+Lin.m in Sources */ = {isa = PBXBuildFile; fileRef = AA20D87E17ECB12A006B7CA2 /* NSPopoverFrame+Lin.m */; }; AA2980B417EE2C5300CF46E3 /* LNUserDefaultsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AA2980B317EE2C5300CF46E3 /* LNUserDefaultsManager.m */; }; AA36376617D9EF9E003C5E55 /* LNPopoverContentView.m in Sources */ = {isa = PBXBuildFile; fileRef = AA36376517D9EF9E003C5E55 /* LNPopoverContentView.m */; }; AA3EC36F17EB2A290003A180 /* DVTFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA3EC36D17EB2A290003A180 /* DVTFoundation.framework */; }; AA3EC37017EB2A290003A180 /* DVTKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA3EC36E17EB2A290003A180 /* DVTKit.framework */; }; AA3EC37317EB2A380003A180 /* IDEFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA3EC37117EB2A380003A180 /* IDEFoundation.framework */; }; AA3EC37417EB2A380003A180 /* IDEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA3EC37217EB2A380003A180 /* IDEKit.framework */; }; AA470D5B17C3CFEC005CBB7F /* LNDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = AA470D5A17C3CFEC005CBB7F /* LNDetector.m */; }; AA470D5E17C3D05D005CBB7F /* LNEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = AA470D5D17C3D05D005CBB7F /* LNEntity.m */; }; AA470D6517C3D380005CBB7F /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA470D6417C3D380005CBB7F /* XCTest.framework */; }; AA470D6B17C3D380005CBB7F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AA470D6917C3D380005CBB7F /* InfoPlist.strings */; }; AA470D7D17C3DE31005CBB7F /* LNDetectorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AA470D7C17C3DE31005CBB7F /* LNDetectorTests.m */; }; AA6377CE18C5CCFC005EADC7 /* LNImageButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6377CD18C5CCFC005EADC7 /* LNImageButtonCell.m */; }; AA63897918C6019A0061C2C4 /* icon_plus@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897118C6019A0061C2C4 /* icon_plus@2x.png */; }; AA63897A18C6019A0061C2C4 /* icon_minus.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897218C6019A0061C2C4 /* icon_minus.png */; }; AA63897B18C6019A0061C2C4 /* icon_minus@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897318C6019A0061C2C4 /* icon_minus@2x.png */; }; AA63897C18C6019A0061C2C4 /* icon120.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897418C6019A0061C2C4 /* icon120.png */; }; AA63897D18C6019A0061C2C4 /* icon_plus.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897518C6019A0061C2C4 /* icon_plus.png */; }; AA63897E18C6019A0061C2C4 /* icon_detach@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897618C6019A0061C2C4 /* icon_detach@2x.png */; }; AA63897F18C6019A0061C2C4 /* icon120@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897718C6019A0061C2C4 /* icon120@2x.png */; }; AA63898018C6019A0061C2C4 /* icon_detach.png in Resources */ = {isa = PBXBuildFile; fileRef = AA63897818C6019A0061C2C4 /* icon_detach.png */; }; AA7D4DB117C74CFE0092DF8A /* LNLocalizationCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = AA7D4DB017C74CFE0092DF8A /* LNLocalizationCollection.m */; }; AA7D4DB417C74D0A0092DF8A /* LNLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = AA7D4DB317C74D0A0092DF8A /* LNLocalization.m */; }; AA8F8EF017EDFC68004964FB /* NSTableView+editedColumnIdentifier.m in Sources */ = {isa = PBXBuildFile; fileRef = AA8F8EEF17EDFC68004964FB /* NSTableView+editedColumnIdentifier.m */; }; AA95FDEC17EB48A9007D33D4 /* LNPopoverContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA95FDEB17EB48A9007D33D4 /* LNPopoverContentView.xib */; }; AA95FDEF17EB4E77007D33D4 /* LNPopoverWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = AA95FDEE17EB4E77007D33D4 /* LNPopoverWindowController.m */; }; AAAC873317ED9D4F00BF251D /* LNHorizontalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = AAAC873217ED9D4F00BF251D /* LNHorizontalLine.m */; }; AAAC873B17EDA9CF00BF251D /* LNPopoverWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = AAAC873A17EDA9CF00BF251D /* LNPopoverWindow.m */; }; AAB0CD3117C4382D0085E913 /* LNRegularExpressionPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0CD3017C4382D0085E913 /* LNRegularExpressionPattern.m */; }; AAB0CD3417C448200085E913 /* LNRegularExpressionPattern+type.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0CD3317C448200085E913 /* LNRegularExpressionPattern+type.m */; }; AAB0CD3617C46A730085E913 /* LNDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = AA470D5A17C3CFEC005CBB7F /* LNDetector.m */; }; AAB0CD3717C46B070085E913 /* LNEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = AA470D5D17C3D05D005CBB7F /* LNEntity.m */; }; AAB0CD3817C46B070085E913 /* LNRegularExpressionPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0CD3017C4382D0085E913 /* LNRegularExpressionPattern.m */; }; AAB0CD3917C46B070085E913 /* LNRegularExpressionPattern+type.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0CD3317C448200085E913 /* LNRegularExpressionPattern+type.m */; }; AAB0CD3C17C477030085E913 /* LNDetectorTestSet.m in Sources */ = {isa = PBXBuildFile; fileRef = AAB0CD3B17C477030085E913 /* LNDetectorTestSet.m */; }; AADDDA9417C49D4800BBA67C /* NSBundle+versions.m in Sources */ = {isa = PBXBuildFile; fileRef = AADDDA9317C49D4800BBA67C /* NSBundle+versions.m */; }; AADEADB317C7B6D3001E0C65 /* LNLocalizationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = AADEADB217C7B6D3001E0C65 /* LNLocalizationTests.m */; }; AADEADB417C7B838001E0C65 /* LNLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = AA7D4DB317C74D0A0092DF8A /* LNLocalization.m */; }; AADEADB717C87298001E0C65 /* IDEIndex+Lin.m in Sources */ = {isa = PBXBuildFile; fileRef = AADEADB617C87298001E0C65 /* IDEIndex+Lin.m */; }; AADEADC017C87392001E0C65 /* MethodSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = AADEADBF17C87392001E0C65 /* MethodSwizzle.m */; }; AAF0D6AB17ECB87100B4318B /* LNTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF0D6AA17ECB87100B4318B /* LNTableView.m */; }; AAF0D6AE17ECB89800B4318B /* LNTableHeaderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF0D6AD17ECB89800B4318B /* LNTableHeaderCell.m */; }; AAF0D6B117ECC4AF00B4318B /* LNTableCornerView.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF0D6B017ECC4AF00B4318B /* LNTableCornerView.m */; }; AAF0D6B417ECD8EC00B4318B /* LNButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF0D6B317ECD8EC00B4318B /* LNButtonCell.m */; }; AAFE3C3F17EECF4A0018E478 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = AAFE3C3E17EECF4A0018E478 /* Localizable.strings */; }; AAFE3C4117EED36C0018E478 /* LNLocalizationCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = AA7D4DB017C74CFE0092DF8A /* LNLocalizationCollection.m */; }; F5859DBD18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F5859DBC18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ AA470D6F17C3D380005CBB7F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = AA1B7D9B17C3C1EC00A3A6D7 /* Project object */; proxyType = 1; remoteGlobalIDString = AA1B7DA217C3C1EC00A3A6D7; remoteInfo = Lin; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ AA02CE8A17EE08240041C2BD /* LNAlertAccessoryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LNAlertAccessoryView.xib; sourceTree = ""; }; AA02CE8C17EE083A0041C2BD /* LNAlertAccessoryView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNAlertAccessoryView.h; sourceTree = ""; }; AA02CE8D17EE083A0041C2BD /* LNAlertAccessoryView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNAlertAccessoryView.m; sourceTree = ""; }; AA11AC4017C66F0200889DFB /* DVTFilePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVTFilePath.h; sourceTree = ""; }; AA11AC4317C6746800889DFB /* IDEIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDEIndex.h; sourceTree = ""; }; AA11AC4617C6755400889DFB /* IDEIndexCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDEIndexCollection.h; sourceTree = ""; }; AA1B7DA317C3C1EC00A3A6D7 /* Lin.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Lin.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; AA1B7DA617C3C1EC00A3A6D7 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; AA1B7DA917C3C1EC00A3A6D7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; AA1B7DAA17C3C1EC00A3A6D7 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; AA1B7DAB17C3C1EC00A3A6D7 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; AA1B7DAE17C3C1EC00A3A6D7 /* Lin-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Lin-Info.plist"; sourceTree = ""; }; AA1B7DB017C3C1EC00A3A6D7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; AA1B7DB217C3C1EC00A3A6D7 /* Lin-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Lin-Prefix.pch"; sourceTree = ""; }; AA1B7DB817C3C20F00A3A6D7 /* Lin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lin.h; sourceTree = ""; }; AA1B7DB917C3C20F00A3A6D7 /* Lin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Lin.m; sourceTree = ""; }; AA20D87D17ECB12A006B7CA2 /* NSPopoverFrame+Lin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPopoverFrame+Lin.h"; sourceTree = ""; }; AA20D87E17ECB12A006B7CA2 /* NSPopoverFrame+Lin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSPopoverFrame+Lin.m"; sourceTree = ""; }; AA20D88017ECB1AD006B7CA2 /* NSPopoverFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSPopoverFrame.h; sourceTree = ""; }; AA2980B217EE2C5300CF46E3 /* LNUserDefaultsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNUserDefaultsManager.h; sourceTree = ""; }; AA2980B317EE2C5300CF46E3 /* LNUserDefaultsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNUserDefaultsManager.m; sourceTree = ""; }; AA36376417D9EF9E003C5E55 /* LNPopoverContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopoverContentView.h; sourceTree = ""; }; AA36376517D9EF9E003C5E55 /* LNPopoverContentView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNPopoverContentView.m; sourceTree = ""; }; AA3EC36D17EB2A290003A180 /* DVTFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVTFoundation.framework; path = ../../../../Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework; sourceTree = ""; }; AA3EC36E17EB2A290003A180 /* DVTKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVTKit.framework; path = ../../../../Applications/Xcode.app/Contents/SharedFrameworks/DVTKit.framework; sourceTree = ""; }; AA3EC37117EB2A380003A180 /* IDEFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IDEFoundation.framework; path = ../../../../Applications/Xcode.app/Contents/Frameworks/IDEFoundation.framework; sourceTree = ""; }; AA3EC37217EB2A380003A180 /* IDEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IDEKit.framework; path = ../../../../Applications/Xcode.app/Contents/Frameworks/IDEKit.framework; sourceTree = ""; }; AA470D5917C3CFEC005CBB7F /* LNDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNDetector.h; sourceTree = ""; }; AA470D5A17C3CFEC005CBB7F /* LNDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNDetector.m; sourceTree = ""; }; AA470D5C17C3D05D005CBB7F /* LNEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNEntity.h; sourceTree = ""; }; AA470D5D17C3D05D005CBB7F /* LNEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNEntity.m; sourceTree = ""; }; AA470D6317C3D380005CBB7F /* LinTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; AA470D6417C3D380005CBB7F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; AA470D6817C3D380005CBB7F /* LinTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LinTests-Info.plist"; sourceTree = ""; }; AA470D6A17C3D380005CBB7F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; AA470D6E17C3D380005CBB7F /* LinTests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LinTests-Prefix.pch"; sourceTree = ""; }; AA470D7C17C3DE31005CBB7F /* LNDetectorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNDetectorTests.m; sourceTree = ""; }; AA6377CC18C5CCFC005EADC7 /* LNImageButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNImageButtonCell.h; sourceTree = ""; }; AA6377CD18C5CCFC005EADC7 /* LNImageButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNImageButtonCell.m; sourceTree = ""; }; AA63897118C6019A0061C2C4 /* icon_plus@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_plus@2x.png"; sourceTree = ""; }; AA63897218C6019A0061C2C4 /* icon_minus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_minus.png; sourceTree = ""; }; AA63897318C6019A0061C2C4 /* icon_minus@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_minus@2x.png"; sourceTree = ""; }; AA63897418C6019A0061C2C4 /* icon120.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon120.png; sourceTree = ""; }; AA63897518C6019A0061C2C4 /* icon_plus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_plus.png; sourceTree = ""; }; AA63897618C6019A0061C2C4 /* icon_detach@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_detach@2x.png"; sourceTree = ""; }; AA63897718C6019A0061C2C4 /* icon120@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon120@2x.png"; sourceTree = ""; }; AA63897818C6019A0061C2C4 /* icon_detach.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_detach.png; sourceTree = ""; }; AA7B0CAD17F4228E0004FE3B /* DVTDualProxyWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVTDualProxyWindow.h; sourceTree = ""; }; AA7B0CB017F4229D0004FE3B /* IDEWorkspaceWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDEWorkspaceWindow.h; sourceTree = ""; }; AA7B0CB317F422BB0004FE3B /* DVTSourceTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVTSourceTextView.h; sourceTree = ""; }; AA7D4DAF17C74CFE0092DF8A /* LNLocalizationCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNLocalizationCollection.h; sourceTree = ""; }; AA7D4DB017C74CFE0092DF8A /* LNLocalizationCollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNLocalizationCollection.m; sourceTree = ""; }; AA7D4DB217C74D0A0092DF8A /* LNLocalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNLocalization.h; sourceTree = ""; }; AA7D4DB317C74D0A0092DF8A /* LNLocalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNLocalization.m; sourceTree = ""; }; AA8F8EEE17EDFC68004964FB /* NSTableView+editedColumnIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSTableView+editedColumnIdentifier.h"; sourceTree = ""; }; AA8F8EEF17EDFC68004964FB /* NSTableView+editedColumnIdentifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSTableView+editedColumnIdentifier.m"; sourceTree = ""; }; AA93691517C4E4C000E94318 /* IDEWorkspace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDEWorkspace.h; sourceTree = ""; }; AA95FDEB17EB48A9007D33D4 /* LNPopoverContentView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LNPopoverContentView.xib; sourceTree = ""; }; AA95FDED17EB4E77007D33D4 /* LNPopoverWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopoverWindowController.h; sourceTree = ""; }; AA95FDEE17EB4E77007D33D4 /* LNPopoverWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNPopoverWindowController.m; sourceTree = ""; }; AAAC873117ED9D4F00BF251D /* LNHorizontalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNHorizontalLine.h; sourceTree = ""; }; AAAC873217ED9D4F00BF251D /* LNHorizontalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNHorizontalLine.m; sourceTree = ""; }; AAAC873917EDA9CF00BF251D /* LNPopoverWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNPopoverWindow.h; sourceTree = ""; }; AAAC873A17EDA9CF00BF251D /* LNPopoverWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNPopoverWindow.m; sourceTree = ""; }; AAB0CD2F17C4382D0085E913 /* LNRegularExpressionPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNRegularExpressionPattern.h; sourceTree = ""; }; AAB0CD3017C4382D0085E913 /* LNRegularExpressionPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNRegularExpressionPattern.m; sourceTree = ""; }; AAB0CD3217C448200085E913 /* LNRegularExpressionPattern+type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "LNRegularExpressionPattern+type.h"; sourceTree = ""; }; AAB0CD3317C448200085E913 /* LNRegularExpressionPattern+type.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "LNRegularExpressionPattern+type.m"; sourceTree = ""; }; AAB0CD3A17C477030085E913 /* LNDetectorTestSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNDetectorTestSet.h; sourceTree = ""; }; AAB0CD3B17C477030085E913 /* LNDetectorTestSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNDetectorTestSet.m; sourceTree = ""; }; AADDDA9217C49D4800BBA67C /* NSBundle+versions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+versions.h"; sourceTree = ""; }; AADDDA9317C49D4800BBA67C /* NSBundle+versions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+versions.m"; sourceTree = ""; }; AADEADB217C7B6D3001E0C65 /* LNLocalizationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNLocalizationTests.m; sourceTree = ""; }; AADEADB517C87298001E0C65 /* IDEIndex+Lin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IDEIndex+Lin.h"; sourceTree = ""; }; AADEADB617C87298001E0C65 /* IDEIndex+Lin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IDEIndex+Lin.m"; sourceTree = ""; }; AADEADBB17C872EB001E0C65 /* IDEEditorDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDEEditorDocument.h; sourceTree = ""; }; AADEADBE17C87392001E0C65 /* MethodSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodSwizzle.h; sourceTree = ""; }; AADEADBF17C87392001E0C65 /* MethodSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MethodSwizzle.m; sourceTree = ""; }; AAF0D6A917ECB87100B4318B /* LNTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNTableView.h; sourceTree = ""; }; AAF0D6AA17ECB87100B4318B /* LNTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNTableView.m; sourceTree = ""; }; AAF0D6AC17ECB89800B4318B /* LNTableHeaderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNTableHeaderCell.h; sourceTree = ""; }; AAF0D6AD17ECB89800B4318B /* LNTableHeaderCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNTableHeaderCell.m; sourceTree = ""; }; AAF0D6AF17ECC4AF00B4318B /* LNTableCornerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNTableCornerView.h; sourceTree = ""; }; AAF0D6B017ECC4AF00B4318B /* LNTableCornerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNTableCornerView.m; sourceTree = ""; }; AAF0D6B217ECD8EC00B4318B /* LNButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNButtonCell.h; sourceTree = ""; }; AAF0D6B317ECD8EC00B4318B /* LNButtonCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNButtonCell.m; sourceTree = ""; }; AAFE3C3E17EECF4A0018E478 /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; F5859DBB18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNLocalizedStringCollectionOperation.h; sourceTree = ""; }; F5859DBC18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNLocalizedStringCollectionOperation.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ AA1B7DA017C3C1EC00A3A6D7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( AA3EC37317EB2A380003A180 /* IDEFoundation.framework in Frameworks */, AA3EC37417EB2A380003A180 /* IDEKit.framework in Frameworks */, AA3EC36F17EB2A290003A180 /* DVTFoundation.framework in Frameworks */, AA3EC37017EB2A290003A180 /* DVTKit.framework in Frameworks */, AA1B7DA717C3C1EC00A3A6D7 /* Cocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; AA470D6017C3D380005CBB7F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( AA470D6517C3D380005CBB7F /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ AA1B7D9A17C3C1EC00A3A6D7 = { isa = PBXGroup; children = ( AA1B7DAC17C3C1EC00A3A6D7 /* Lin */, AA470D6617C3D380005CBB7F /* LinTests */, AA1B7DA517C3C1EC00A3A6D7 /* Frameworks */, AA1B7DA417C3C1EC00A3A6D7 /* Products */, ); sourceTree = ""; }; AA1B7DA417C3C1EC00A3A6D7 /* Products */ = { isa = PBXGroup; children = ( AA1B7DA317C3C1EC00A3A6D7 /* Lin.xcplugin */, AA470D6317C3D380005CBB7F /* LinTests.xctest */, ); name = Products; sourceTree = ""; }; AA1B7DA517C3C1EC00A3A6D7 /* Frameworks */ = { isa = PBXGroup; children = ( AA3EC37117EB2A380003A180 /* IDEFoundation.framework */, AA3EC37217EB2A380003A180 /* IDEKit.framework */, AA3EC36D17EB2A290003A180 /* DVTFoundation.framework */, AA3EC36E17EB2A290003A180 /* DVTKit.framework */, AA1B7DA617C3C1EC00A3A6D7 /* Cocoa.framework */, AA470D6417C3D380005CBB7F /* XCTest.framework */, AA1B7DA817C3C1EC00A3A6D7 /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; AA1B7DA817C3C1EC00A3A6D7 /* Other Frameworks */ = { isa = PBXGroup; children = ( AA1B7DA917C3C1EC00A3A6D7 /* Foundation.framework */, AA1B7DAA17C3C1EC00A3A6D7 /* CoreData.framework */, AA1B7DAB17C3C1EC00A3A6D7 /* AppKit.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; AA1B7DAC17C3C1EC00A3A6D7 /* Lin */ = { isa = PBXGroup; children = ( AA93691817C4E4C700E94318 /* Xcode-Private-Classes */, AA20D88117ECB467006B7CA2 /* AppKit-Private-Classes */, AADDDA9517C49D4D00BBA67C /* Categories */, AA2980B517EE2CF600CF46E3 /* Shared */, AA470D7817C3DD42005CBB7F /* Models */, AADDDAA017C4A3BA00BBA67C /* Views */, AADDDA9C17C4A0E200BBA67C /* Controllers */, AA1B7DB817C3C20F00A3A6D7 /* Lin.h */, AA1B7DB917C3C20F00A3A6D7 /* Lin.m */, AADDDA9B17C4A0DA00BBA67C /* Resources */, AA1B7DAD17C3C1EC00A3A6D7 /* Supporting Files */, ); path = Lin; sourceTree = ""; }; AA1B7DAD17C3C1EC00A3A6D7 /* Supporting Files */ = { isa = PBXGroup; children = ( AA1B7DAE17C3C1EC00A3A6D7 /* Lin-Info.plist */, AA1B7DAF17C3C1EC00A3A6D7 /* InfoPlist.strings */, AA1B7DB217C3C1EC00A3A6D7 /* Lin-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; AA20D88117ECB467006B7CA2 /* AppKit-Private-Classes */ = { isa = PBXGroup; children = ( AA20D88017ECB1AD006B7CA2 /* NSPopoverFrame.h */, ); name = "AppKit-Private-Classes"; sourceTree = ""; }; AA2980B517EE2CF600CF46E3 /* Shared */ = { isa = PBXGroup; children = ( AA2980B217EE2C5300CF46E3 /* LNUserDefaultsManager.h */, AA2980B317EE2C5300CF46E3 /* LNUserDefaultsManager.m */, F5859DBB18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.h */, F5859DBC18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.m */, ); name = Shared; sourceTree = ""; }; AA470D6617C3D380005CBB7F /* LinTests */ = { isa = PBXGroup; children = ( AAB0CD3D17C478EF0085E913 /* Models */, AA470D7C17C3DE31005CBB7F /* LNDetectorTests.m */, AADEADB217C7B6D3001E0C65 /* LNLocalizationTests.m */, AAFE3C4017EED0950018E478 /* Resources */, AA470D6717C3D380005CBB7F /* Supporting Files */, ); path = LinTests; sourceTree = ""; }; AA470D6717C3D380005CBB7F /* Supporting Files */ = { isa = PBXGroup; children = ( AA470D6817C3D380005CBB7F /* LinTests-Info.plist */, AA470D6917C3D380005CBB7F /* InfoPlist.strings */, AA470D6E17C3D380005CBB7F /* LinTests-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; AA470D7817C3DD42005CBB7F /* Models */ = { isa = PBXGroup; children = ( AA470D5917C3CFEC005CBB7F /* LNDetector.h */, AA470D5A17C3CFEC005CBB7F /* LNDetector.m */, AA470D5C17C3D05D005CBB7F /* LNEntity.h */, AA470D5D17C3D05D005CBB7F /* LNEntity.m */, AAB0CD2F17C4382D0085E913 /* LNRegularExpressionPattern.h */, AAB0CD3017C4382D0085E913 /* LNRegularExpressionPattern.m */, AAB0CD3217C448200085E913 /* LNRegularExpressionPattern+type.h */, AAB0CD3317C448200085E913 /* LNRegularExpressionPattern+type.m */, AA7D4DAF17C74CFE0092DF8A /* LNLocalizationCollection.h */, AA7D4DB017C74CFE0092DF8A /* LNLocalizationCollection.m */, AA7D4DB217C74D0A0092DF8A /* LNLocalization.h */, AA7D4DB317C74D0A0092DF8A /* LNLocalization.m */, ); name = Models; sourceTree = ""; }; AA63898118C6019F0061C2C4 /* Images */ = { isa = PBXGroup; children = ( AA63897118C6019A0061C2C4 /* icon_plus@2x.png */, AA63897518C6019A0061C2C4 /* icon_plus.png */, AA63897218C6019A0061C2C4 /* icon_minus.png */, AA63897318C6019A0061C2C4 /* icon_minus@2x.png */, AA63897618C6019A0061C2C4 /* icon_detach@2x.png */, AA63897818C6019A0061C2C4 /* icon_detach.png */, AA63897718C6019A0061C2C4 /* icon120@2x.png */, AA63897418C6019A0061C2C4 /* icon120.png */, ); name = Images; sourceTree = ""; }; AA93691817C4E4C700E94318 /* Xcode-Private-Classes */ = { isa = PBXGroup; children = ( AA93691517C4E4C000E94318 /* IDEWorkspace.h */, AA11AC4017C66F0200889DFB /* DVTFilePath.h */, AA11AC4317C6746800889DFB /* IDEIndex.h */, AA11AC4617C6755400889DFB /* IDEIndexCollection.h */, AADEADBB17C872EB001E0C65 /* IDEEditorDocument.h */, AA7B0CAD17F4228E0004FE3B /* DVTDualProxyWindow.h */, AA7B0CB017F4229D0004FE3B /* IDEWorkspaceWindow.h */, AA7B0CB317F422BB0004FE3B /* DVTSourceTextView.h */, ); name = "Xcode-Private-Classes"; sourceTree = ""; }; AAB0CD3D17C478EF0085E913 /* Models */ = { isa = PBXGroup; children = ( AAB0CD3A17C477030085E913 /* LNDetectorTestSet.h */, AAB0CD3B17C477030085E913 /* LNDetectorTestSet.m */, ); name = Models; sourceTree = ""; }; AADDDA9517C49D4D00BBA67C /* Categories */ = { isa = PBXGroup; children = ( AADEADBE17C87392001E0C65 /* MethodSwizzle.h */, AADEADBF17C87392001E0C65 /* MethodSwizzle.m */, AADDDA9217C49D4800BBA67C /* NSBundle+versions.h */, AADDDA9317C49D4800BBA67C /* NSBundle+versions.m */, AADEADB517C87298001E0C65 /* IDEIndex+Lin.h */, AADEADB617C87298001E0C65 /* IDEIndex+Lin.m */, AA20D87D17ECB12A006B7CA2 /* NSPopoverFrame+Lin.h */, AA20D87E17ECB12A006B7CA2 /* NSPopoverFrame+Lin.m */, AA8F8EEE17EDFC68004964FB /* NSTableView+editedColumnIdentifier.h */, AA8F8EEF17EDFC68004964FB /* NSTableView+editedColumnIdentifier.m */, ); name = Categories; sourceTree = ""; }; AADDDA9B17C4A0DA00BBA67C /* Resources */ = { isa = PBXGroup; children = ( AA95FDEB17EB48A9007D33D4 /* LNPopoverContentView.xib */, AA02CE8A17EE08240041C2BD /* LNAlertAccessoryView.xib */, AA63898118C6019F0061C2C4 /* Images */, ); name = Resources; sourceTree = ""; }; AADDDA9C17C4A0E200BBA67C /* Controllers */ = { isa = PBXGroup; children = ( AA95FDED17EB4E77007D33D4 /* LNPopoverWindowController.h */, AA95FDEE17EB4E77007D33D4 /* LNPopoverWindowController.m */, ); name = Controllers; sourceTree = ""; }; AADDDAA017C4A3BA00BBA67C /* Views */ = { isa = PBXGroup; children = ( AAAC873917EDA9CF00BF251D /* LNPopoverWindow.h */, AAAC873A17EDA9CF00BF251D /* LNPopoverWindow.m */, AA36376417D9EF9E003C5E55 /* LNPopoverContentView.h */, AA36376517D9EF9E003C5E55 /* LNPopoverContentView.m */, AAF0D6A917ECB87100B4318B /* LNTableView.h */, AAF0D6AA17ECB87100B4318B /* LNTableView.m */, AAF0D6AF17ECC4AF00B4318B /* LNTableCornerView.h */, AAF0D6B017ECC4AF00B4318B /* LNTableCornerView.m */, AAF0D6AC17ECB89800B4318B /* LNTableHeaderCell.h */, AAF0D6AD17ECB89800B4318B /* LNTableHeaderCell.m */, AAF0D6B217ECD8EC00B4318B /* LNButtonCell.h */, AAF0D6B317ECD8EC00B4318B /* LNButtonCell.m */, AAAC873117ED9D4F00BF251D /* LNHorizontalLine.h */, AAAC873217ED9D4F00BF251D /* LNHorizontalLine.m */, AA02CE8C17EE083A0041C2BD /* LNAlertAccessoryView.h */, AA02CE8D17EE083A0041C2BD /* LNAlertAccessoryView.m */, AA6377CC18C5CCFC005EADC7 /* LNImageButtonCell.h */, AA6377CD18C5CCFC005EADC7 /* LNImageButtonCell.m */, ); name = Views; sourceTree = ""; }; AAFE3C4017EED0950018E478 /* Resources */ = { isa = PBXGroup; children = ( AAFE3C3E17EECF4A0018E478 /* Localizable.strings */, ); name = Resources; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ AA1B7DA217C3C1EC00A3A6D7 /* Lin */ = { isa = PBXNativeTarget; buildConfigurationList = AA1B7DB517C3C1EC00A3A6D7 /* Build configuration list for PBXNativeTarget "Lin" */; buildPhases = ( AA1B7D9F17C3C1EC00A3A6D7 /* Sources */, AA1B7DA017C3C1EC00A3A6D7 /* Frameworks */, AA1B7DA117C3C1EC00A3A6D7 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = Lin; productName = Lin; productReference = AA1B7DA317C3C1EC00A3A6D7 /* Lin.xcplugin */; productType = "com.apple.product-type.bundle"; }; AA470D6217C3D380005CBB7F /* LinTests */ = { isa = PBXNativeTarget; buildConfigurationList = AA470D7117C3D380005CBB7F /* Build configuration list for PBXNativeTarget "LinTests" */; buildPhases = ( AA470D5F17C3D380005CBB7F /* Sources */, AA470D6017C3D380005CBB7F /* Frameworks */, AA470D6117C3D380005CBB7F /* Resources */, ); buildRules = ( ); dependencies = ( AA470D7017C3D380005CBB7F /* PBXTargetDependency */, ); name = LinTests; productName = LinTests; productReference = AA470D6317C3D380005CBB7F /* LinTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ AA1B7D9B17C3C1EC00A3A6D7 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0610; ORGANIZATIONNAME = "Tanaka Katsuma"; TargetAttributes = { AA470D6217C3D380005CBB7F = { TestTargetID = AA1B7DA217C3C1EC00A3A6D7; }; }; }; buildConfigurationList = AA1B7D9E17C3C1EC00A3A6D7 /* Build configuration list for PBXProject "Lin" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = AA1B7D9A17C3C1EC00A3A6D7; productRefGroup = AA1B7DA417C3C1EC00A3A6D7 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( AA1B7DA217C3C1EC00A3A6D7 /* Lin */, AA470D6217C3D380005CBB7F /* LinTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ AA1B7DA117C3C1EC00A3A6D7 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( AA63897B18C6019A0061C2C4 /* icon_minus@2x.png in Resources */, AA63897F18C6019A0061C2C4 /* icon120@2x.png in Resources */, AA63898018C6019A0061C2C4 /* icon_detach.png in Resources */, AA63897A18C6019A0061C2C4 /* icon_minus.png in Resources */, AA95FDEC17EB48A9007D33D4 /* LNPopoverContentView.xib in Resources */, AA63897C18C6019A0061C2C4 /* icon120.png in Resources */, AA63897D18C6019A0061C2C4 /* icon_plus.png in Resources */, AA63897E18C6019A0061C2C4 /* icon_detach@2x.png in Resources */, AA63897918C6019A0061C2C4 /* icon_plus@2x.png in Resources */, AA02CE8B17EE08240041C2BD /* LNAlertAccessoryView.xib in Resources */, AA1B7DB117C3C1EC00A3A6D7 /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; AA470D6117C3D380005CBB7F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( AA470D6B17C3D380005CBB7F /* InfoPlist.strings in Resources */, AAFE3C3F17EECF4A0018E478 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ AA1B7D9F17C3C1EC00A3A6D7 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( AA7D4DB117C74CFE0092DF8A /* LNLocalizationCollection.m in Sources */, AAF0D6B417ECD8EC00B4318B /* LNButtonCell.m in Sources */, AAF0D6B117ECC4AF00B4318B /* LNTableCornerView.m in Sources */, AAB0CD3417C448200085E913 /* LNRegularExpressionPattern+type.m in Sources */, AADDDA9417C49D4800BBA67C /* NSBundle+versions.m in Sources */, AAAC873B17EDA9CF00BF251D /* LNPopoverWindow.m in Sources */, AA8F8EF017EDFC68004964FB /* NSTableView+editedColumnIdentifier.m in Sources */, AA6377CE18C5CCFC005EADC7 /* LNImageButtonCell.m in Sources */, AA20D87F17ECB12A006B7CA2 /* NSPopoverFrame+Lin.m in Sources */, AA02CE8E17EE083A0041C2BD /* LNAlertAccessoryView.m in Sources */, AA36376617D9EF9E003C5E55 /* LNPopoverContentView.m in Sources */, AA470D5E17C3D05D005CBB7F /* LNEntity.m in Sources */, AA7D4DB417C74D0A0092DF8A /* LNLocalization.m in Sources */, AAB0CD3117C4382D0085E913 /* LNRegularExpressionPattern.m in Sources */, AA1B7DBA17C3C20F00A3A6D7 /* Lin.m in Sources */, AAF0D6AE17ECB89800B4318B /* LNTableHeaderCell.m in Sources */, AAAC873317ED9D4F00BF251D /* LNHorizontalLine.m in Sources */, AADEADB717C87298001E0C65 /* IDEIndex+Lin.m in Sources */, AAF0D6AB17ECB87100B4318B /* LNTableView.m in Sources */, AA2980B417EE2C5300CF46E3 /* LNUserDefaultsManager.m in Sources */, AA95FDEF17EB4E77007D33D4 /* LNPopoverWindowController.m in Sources */, AADEADC017C87392001E0C65 /* MethodSwizzle.m in Sources */, F5859DBD18CABC2A009AF108 /* LNLocalizedStringCollectionOperation.m in Sources */, AA470D5B17C3CFEC005CBB7F /* LNDetector.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; AA470D5F17C3D380005CBB7F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( AAFE3C4117EED36C0018E478 /* LNLocalizationCollection.m in Sources */, AADEADB417C7B838001E0C65 /* LNLocalization.m in Sources */, AAB0CD3C17C477030085E913 /* LNDetectorTestSet.m in Sources */, AAB0CD3717C46B070085E913 /* LNEntity.m in Sources */, AAB0CD3817C46B070085E913 /* LNRegularExpressionPattern.m in Sources */, AAB0CD3917C46B070085E913 /* LNRegularExpressionPattern+type.m in Sources */, AAB0CD3617C46A730085E913 /* LNDetector.m in Sources */, AA470D7D17C3DE31005CBB7F /* LNDetectorTests.m in Sources */, AADEADB317C7B6D3001E0C65 /* LNLocalizationTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ AA470D7017C3D380005CBB7F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = AA1B7DA217C3C1EC00A3A6D7 /* Lin */; targetProxy = AA470D6F17C3D380005CBB7F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ AA1B7DAF17C3C1EC00A3A6D7 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( AA1B7DB017C3C1EC00A3A6D7 /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; AA470D6917C3D380005CBB7F /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( AA470D6A17C3D380005CBB7F /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ AA1B7DB317C3C1EC00A3A6D7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; AA1B7DB417C3C1EC00A3A6D7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = macosx; }; name = Release; }; AA1B7DB617C3C1EC00A3A6D7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = "$(HOME)"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SYSTEM_APPS_DIR)/Xcode.app/Contents/SharedFrameworks", "$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Frameworks", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Lin/Lin-Prefix.pch"; INFOPLIST_FILE = "Lin/Lin-Info.plist"; INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = xcplugin; }; name = Debug; }; AA1B7DB717C3C1EC00A3A6D7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DEPLOYMENT_LOCATION = YES; DSTROOT = "$(HOME)"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SYSTEM_APPS_DIR)/Xcode.app/Contents/SharedFrameworks", "$(SYSTEM_APPS_DIR)/Xcode.app/Contents/Frameworks", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Lin/Lin-Prefix.pch"; INFOPLIST_FILE = "Lin/Lin-Info.plist"; INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = xcplugin; }; name = Release; }; AA470D7217C3D380005CBB7F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "LinTests/LinTests-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "LinTests/LinTests-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = xctest; }; name = Debug; }; AA470D7317C3D380005CBB7F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "LinTests/LinTests-Prefix.pch"; INFOPLIST_FILE = "LinTests/LinTests-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = xctest; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ AA1B7D9E17C3C1EC00A3A6D7 /* Build configuration list for PBXProject "Lin" */ = { isa = XCConfigurationList; buildConfigurations = ( AA1B7DB317C3C1EC00A3A6D7 /* Debug */, AA1B7DB417C3C1EC00A3A6D7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; AA1B7DB517C3C1EC00A3A6D7 /* Build configuration list for PBXNativeTarget "Lin" */ = { isa = XCConfigurationList; buildConfigurations = ( AA1B7DB617C3C1EC00A3A6D7 /* Debug */, AA1B7DB717C3C1EC00A3A6D7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; AA470D7117C3D380005CBB7F /* Build configuration list for PBXNativeTarget "LinTests" */ = { isa = XCConfigurationList; buildConfigurations = ( AA470D7217C3D380005CBB7F /* Debug */, AA470D7317C3D380005CBB7F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = AA1B7D9B17C3C1EC00A3A6D7 /* Project object */; } ================================================ FILE: Lin.xcodeproj/xcshareddata/xcschemes/Lin.xcscheme ================================================ ================================================ FILE: Lin.xcodeproj/xcshareddata/xcschemes/LinTests.xcscheme ================================================ ================================================ FILE: LinTests/LNDetectorTestSet.h ================================================ // // LNDetectorTestSet.h // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import @interface LNDetectorTestSet : NSObject @property (nonatomic, copy, readonly) NSString *string; @property (nonatomic, copy, readonly) NSArray *keys; - (instancetype)initWithString:(NSString *)string keys:(NSString *)keyValue, ... NS_REQUIRES_NIL_TERMINATION; @end ================================================ FILE: LinTests/LNDetectorTestSet.m ================================================ // // LNDetectorTestSet.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import "LNDetectorTestSet.h" @interface LNDetectorTestSet () @property (nonatomic, copy, readwrite) NSString *string; @property (nonatomic, copy, readwrite) NSArray *keys; @end @implementation LNDetectorTestSet - (instancetype)initWithString:(NSString *)string keys:(NSString *)keyValue, ... { self = [super init]; if (self) { self.string = string; va_list arguments; va_start(arguments, keyValue); NSString *key = keyValue; NSMutableArray *keys = [NSMutableArray array]; while (key) { [keys addObject:key]; key = va_arg(arguments, typeof(NSString *)); } self.keys = [keys copy]; va_end(arguments); } return self; } @end ================================================ FILE: LinTests/LNDetectorTests.m ================================================ // // LNDetectorTests.m // Lin // // Created by Tanaka Katsuma on 2013/08/21. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import // Models #import "LNDetector.h" #import "LNEntity.h" #import "LNDetectorTestSet.h" @interface LNDetectorTests : XCTestCase @property (nonatomic, strong) LNDetector *detector; - (void)performTests:(LNDetectorTestSet *)testSetValue, ... NS_REQUIRES_NIL_TERMINATION; @end @implementation LNDetectorTests - (void)setUp { [super setUp]; LNDetector *detector = [LNDetector detector]; self.detector = detector; } - (void)tearDown { [super tearDown]; } - (void)testLocalizedString { [self performTests: [[LNDetectorTestSet alloc] initWithString:@"NSLocalizedString(@\"key\", nil);" keys:@"key", nil], [[LNDetectorTestSet alloc] initWithString:@"NSLocalizedString ( @\"key\" , nil );" keys:@"key", nil], [[LNDetectorTestSet alloc] initWithString:@"NSString *value = NSLocalizedString(@\"key\", nil);" keys:@"key", nil], [[LNDetectorTestSet alloc] initWithString:@"NSLog(@\"value1 = %@, value2 = %@\", NSLocalizedString(@\"key1\", nil), NSLocalizedString(@\"key2\", nil));" keys:@"key1", @"key2", nil], nil]; } - (void)testLocalizedStringForKey { [self performTests: [[LNDetectorTestSet alloc] initWithString:@"[[NSBundle mainBundle] localizedStringForKey:@\"key\" value:@\"default_value\" table:@\"table_name\"];" keys:@"key", nil], nil]; } - (void)testLocalizedStringFromTable { [self performTests: [[LNDetectorTestSet alloc] initWithString:@"NSLocalizedStringFromTable(@\"key\", @\"table_name\", @\"comment\");" keys:@"key", nil], nil]; } - (void)testLocalizedStringFromTableInBundle { [self performTests: [[LNDetectorTestSet alloc] initWithString:@"NSLocalizedStringFromTableInBundle(@\"key\", @\"table_name\", [NSBundle mainBundle], @\"comment\");" keys:@"key", nil], nil]; } - (void)testLocalizedStringWithDefaultValue { [self performTests: [[LNDetectorTestSet alloc] initWithString:@"NSLocalizedStringWithDefaultValue(@\"key\", @\"table_name\", [NSBundle mainBundle], @\"default_value\", @\"comment\");" keys:@"key", nil], nil]; } - (void)performTests:(LNDetectorTestSet *)testSetValue, ... { // Parse arguments va_list arguments; va_start(arguments, testSetValue); LNDetectorTestSet *testSet = testSetValue; NSMutableArray *testSets = [NSMutableArray array]; while (testSet) { [testSets addObject:testSet]; testSet = va_arg(arguments, typeof(LNDetectorTestSet *)); } va_end(arguments); // Do tests for (LNDetectorTestSet *testSet in testSets) { NSArray *entities = [self.detector entitiesInString:testSet.string]; XCTAssertTrue(entities.count == testSet.keys.count); // Number of detected entities and expected keys are equal. for (LNEntity *entity in entities) { NSUInteger indexOfEntity = [entities indexOfObject:entity]; NSString *keyString = [testSet.string substringWithRange:entity.keyRange]; XCTAssertEqualObjects(keyString, testSet.keys[indexOfEntity]); // Extracted key is equal to expected key. } } } @end ================================================ FILE: LinTests/LNLocalizationTests.m ================================================ // // LNLocalizationTests.m // Lin // // Created by Tanaka Katsuma on 2013/08/24. // Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. // #import // Models #import "LNLocalizationCollection.h" #import "LNLocalization.h" @interface LNLocalizationTests : XCTestCase @end @implementation LNLocalizationTests - (NSBundle *)testBundle { for (NSBundle *bundle in [NSBundle allBundles]) { if ([[bundle bundleIdentifier] isEqualToString:@"jp.questbeat.LinTests"]) { return bundle; } } return nil; } - (void)testParsingPatterns { NSString *filePath = [[self testBundle] pathForResource:@"Localizable" ofType:@"strings"]; LNLocalizationCollection *collection = [LNLocalizationCollection localizationCollectionWithContentsOfFile:filePath]; struct LNLocalizationTestSet { __unsafe_unretained NSString *key; __unsafe_unretained NSString *value; } testSets[] = { {@"key0", @"value0"}, {@"key1", @"value1"}, {@"key2", @"value2"}, {@"key3", @"value3"}, {@"key4", @"value4"}, {@"key5", @"value5"}, {@"key6", @"value6"}, {@"key7", @"value7"}, {@"key8", @"value8"}, {@"key 9", @"value9"}, {@"key 10", @"value10"}, {@"key 11", @"value11"}, {@"key 12", @"value12"}, {@"key 13", @"value13"}, {@"key 14", @"value14"}, {@"key 15", @"value15"}, {@"key 16", @"value16"}, {@"key.17", @"value17"}, {@"key.18", @"value18"}, {@"key.19", @"value19"}, {@"key.20", @"value20"}, {@"key.21", @"value21"} }; NSInteger numberOfTestSets = sizeof(testSets) / sizeof(struct LNLocalizationTestSet); for (NSInteger i = 0; i < numberOfTestSets; i++) { LNLocalization *localization = [LNLocalization localizationWithKey:testSets[i].key value:testSets[i].value entityRange:NSMakeRange(0, 0) keyRange:NSMakeRange(0, 0) valueRange:NSMakeRange(0, 0) collection:nil]; XCTAssertTrue([collection.localizations containsObject:localization]); } } @end ================================================ FILE: LinTests/LinTests-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier jp.questbeat.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: LinTests/LinTests-Prefix.pch ================================================ // // Prefix header // // The contents of this file are implicitly included at the beginning of every source file. // #ifdef __OBJC__ #import #endif // Fix Xcode 5 confusion about #defines #undef NULL #define NULL ((void*)0) ================================================ FILE: LinTests/Localizable.strings ================================================ /* Localizable.strings Lin Created by Tanaka Katsuma on 2013/09/22. Copyright (c) 2013年 Tanaka Katsuma. All rights reserved. */ key0 = "value0"; key1 = "value1"; key2= "value2"; key3="value3"; "key4" = "value4"; "key5" = "value5"; "key6"= "value6"; "key7"="value7"; key8 = "value8"; "key 9"="value9"; "key 10" ="value10"; "key 11"="value11"; "key 12" ="value12"; "key 13" = "value13"; "key 14" = "value14"; "key 15" ="value15"; "key 16" = "value16"; "key.17" = "value17"; key.18 = "value18"; key.19 = "value19"; key.20="value20"; key.21="value21"; ================================================ FILE: LinTests/en.lproj/InfoPlist.strings ================================================ /* Localized versions of Info.plist keys */ ================================================ FILE: Makefile ================================================ clean: xcodebuild \ -project Lin.xcodeproj \ clean test: xcodebuild \ -project Lin.xcodeproj \ -scheme LinTests \ -configuration Debug \ test ================================================ FILE: README.md ================================================ # Lin Lin is a open source plug-in for **Xcode 5**. It lets you search/manage localizations without opening the .strings files. [![Build Status](https://travis-ci.org/questbeat/Lin-Xcode5.svg?branch=master)](https://travis-ci.org/questbeat/Lin-Xcode5) ![01.png](https://raw.github.com/questbeat/Lin-Xcode5/master/screenshots/01.png) ## Note: Xcode 6 or later This version does not support Xcode 6 or later. Please use the latest version of [questbeat/Lin](https://github.com/questbeat/Lin). ## Features When you are focusing on NSLocalizedString or other functions to get a localized version of a string, Lin shows the list of localizations that contains the inputted key string. ![02.gif](https://raw.github.com/questbeat/Lin-Xcode5/master/screenshots/02.gif) You can add a new localization or remove a localization from the popover. (Click +/- button in the bottom left of the popover.) ![03.gif](https://raw.github.com/questbeat/Lin-Xcode5/master/screenshots/03.png) You can also edit key or value of a localization by clicking the row on the table. ![04.png](https://raw.github.com/questbeat/Lin-Xcode5/master/screenshots/04.png) Lin has not only popover mode, but also window mode. The window will appear when you drag-and-drop the popover. In window mode, the search field can be used to find the localization with a free keyword. ![05.gif](https://raw.github.com/questbeat/Lin-Xcode5/master/screenshots/05.gif) ## Installation Download the project and build it, then relaunch Xcode. Lin will be installed in `~/Library/Application Support/Developer/Shared/Xcode/Plug-ins` automatically. If you want to uninstall Lin, remove Lin.xcplugin in `Plug-ins` directory. ## Settings You can enable/disable Lin or show window manually by opening the Lin menu in the Editor menu in Xcode. ![06.png](https://raw.github.com/questbeat/Lin-Xcode5/master/screenshots/06.png) ## Notes * `.strings` files must be UTF-8 * Supported functions: * NSLocalizedString * NSLocalizedStringFromTable * NSLocalizedStringFromTableInBundle * NSLocalizedStringWithDefaultValue * localizedStringForKey:value:table: * After modifying a `.string` file, don't forget to save otherwise new strings won't appear in completion popup ## License *Lin* is released under the **MIT License**, see *LICENSE.txt*.