simple change text

This commit is contained in:
Zitao Xiong
2013-05-12 20:53:07 -05:00
parent f33a15691d
commit 420ad480e9
6 changed files with 356 additions and 24 deletions

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
*.mkm
# Xcode
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
!default.xcworkspace
xcuserdata
*.moved-aside
DerivedData
.idea/

View File

@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
09A343C6174068E600A713EE /* RCXcode.m in Sources */ = {isa = PBXBuildFile; fileRef = 09A343C5174068E200A713EE /* RCXcode.m */; };
09F65636174041010000486B /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09F65635174041010000486B /* AppKit.framework */; };
09F65638174041010000486B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09F65637174041010000486B /* Foundation.framework */; };
09F6563E174041010000486B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 09F6563C174041010000486B /* InfoPlist.strings */; };
@@ -14,6 +15,8 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
09A343C4174068E200A713EE /* RCXcode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCXcode.h; sourceTree = "<group>"; };
09A343C5174068E200A713EE /* RCXcode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCXcode.m; sourceTree = "<group>"; };
09F65632174041010000486B /* QuickLocalization.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QuickLocalization.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; };
09F65635174041010000486B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
09F65637174041010000486B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -68,6 +71,8 @@
children = (
09F6563F174041010000486B /* QuickLocalization.h */,
09F65640174041010000486B /* QuickLocalization.m */,
09A343C4174068E200A713EE /* RCXcode.h */,
09A343C5174068E200A713EE /* RCXcode.m */,
09F6563A174041010000486B /* Supporting Files */,
);
path = QuickLocalization;
@@ -146,6 +151,7 @@
buildActionMask = 2147483647;
files = (
09F65641174041010000486B /* QuickLocalization.m in Sources */,
09A343C6174068E600A713EE /* RCXcode.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -271,6 +277,7 @@
09F65647174041010000486B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:QuickLocalization.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -7,12 +7,19 @@
//
#import "QuickLocalization.h"
#import "RCXcode.h"
static NSString *localizeRegexs[] = {
@"NSLocalizedString\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*\\)",
@"localizedStringForKey:\\s*@\"(.*)\"\\s*value:\\s*(.*)\\s*table:\\s*(.*)",
@"NSLocalizedStringFromTable\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*\\)",
@"NSLocalizedStringFromTableInBundle\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*\\)",
@"NSLocalizedStringWithDefaultValue\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*,\\s*(.*)\\s*\\)"
};
static NSString *stringRegexs = @"@\"[^\"]*\"";
@implementation QuickLocalization
+ (void)pluginDidLoad:(NSBundle *)plugin
{
+ (void)pluginDidLoad:(NSBundle *)plugin {
static id sharedPlugin = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@@ -20,35 +27,87 @@
});
}
- (id)init
{
- (id)init {
if (self = [super init]) {
// Create menu items, initialize UI, etc.
// Sample Menu Item:
NSMenuItem *viewMenuItem = [[NSApp mainMenu] itemWithTitle:@"File"];
if (viewMenuItem) {
[[viewMenuItem submenu] addItem:[NSMenuItem separatorItem]];
NSMenuItem *sample = [[NSMenuItem alloc] initWithTitle:@"Do Action" action:@selector(doMenuAction) keyEquivalent:@""];
[sample setTarget:self];
[[viewMenuItem submenu] addItem:sample];
[sample release];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidFinishLaunching:)
name:NSApplicationDidFinishLaunchingNotification
object:nil];
}
return self;
}
// Sample Action, for menu item:
- (void)doMenuAction
{
NSAlert *alert = [NSAlert alertWithMessageText:@"Hello, World" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@""];
[alert runModal];
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSMenuItem *viewMenuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
if (viewMenuItem) {
[[viewMenuItem submenu] addItem:[NSMenuItem separatorItem]];
NSMenuItem *sample = [[NSMenuItem alloc] initWithTitle:@"Quick Localization" action:@selector(quickLocalization) keyEquivalent:@"c"];
[sample setKeyEquivalentModifierMask:NSCommandKeyMask | NSShiftKeyMask];
[sample setTarget:self];
[[viewMenuItem submenu] addItem:sample];
[sample release];
}
}
- (void)dealloc
{
// Sample Action, for menu item:
- (void)quickLocalization {
IDESourceCodeDocument *document = [RCXcode currentSourceCodeDocument];
NSTextView *textView = [RCXcode currentSourceCodeTextView];
if (!document || !textView) {
return;
}
// NSLog(@"file: %@", [RCXcode currentWorkspaceDocument].workspace.representingFilePath.fileURL.absoluteString);
NSArray *selectedRanges = [textView selectedRanges];
if ([selectedRanges count] > 0) {
NSRange range = [[selectedRanges objectAtIndex:0] rangeValue];
NSRange lineRange = [textView.textStorage.string lineRangeForRange:range];
NSString *line = [textView.textStorage.string substringWithRange:lineRange];
NSRegularExpression *localizedRex = [[[NSRegularExpression alloc] initWithPattern:localizeRegexs[0] options:NSRegularExpressionCaseInsensitive error:nil] autorelease];
NSArray *localizedMatches = [localizedRex matchesInString:line options:0 range:NSMakeRange(0, [line length])];
NSRegularExpression *regex = [[[NSRegularExpression alloc] initWithPattern:stringRegexs options:NSRegularExpressionCaseInsensitive error:nil] autorelease];
NSArray *matches = [regex matchesInString:line options:0 range:NSMakeRange(0, [line length])];
NSUInteger addedLength = 0;
for (int i = 0; i < [matches count]; i++) {
NSTextCheckingResult *result = [matches objectAtIndex:i];
NSRange matchedRangeInLine = result.range;
NSRange matchedRangeInDocument = NSMakeRange(lineRange.location + matchedRangeInLine.location + addedLength, matchedRangeInLine.length);
if ([self isRange:matchedRangeInLine inSkipedRanges:localizedMatches]) {
continue;
}
NSString *string = [line substringWithRange:matchedRangeInLine];
NSString *outputString = [NSString stringWithFormat:@"NSLocalizedString(%@, %@)", string, string];
addedLength = outputString.length - string.length;
if ([textView shouldChangeTextInRange:matchedRangeInDocument replacementString:outputString]) {
[textView.textStorage replaceCharactersInRange:matchedRangeInDocument
withAttributedString:[[[NSAttributedString alloc] initWithString:outputString] autorelease]];
[textView didChangeText];
}
// [textView replaceCharactersInRange:matchedRangeInDocument withString:outputString];
// NSAlert *alert = [NSAlert alertWithMessageText:outputString defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@""];
// [alert runModal];
}
}
}
- (BOOL)isRange:(NSRange)range inSkipedRanges:(NSArray *)ranges {
for (int i = 0; i < [ranges count]; i++) {
NSTextCheckingResult *result = [ranges objectAtIndex:i];
NSRange skippedRange = result.range;
if (skippedRange.location <= range.location && skippedRange.location + skippedRange.length > range.location + range.length) {
return YES;
}
}
return NO;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
@end
@end

122
QuickLocalization/RCXcode.h Normal file
View File

@@ -0,0 +1,122 @@
//
//
// Created by Zitao on 12/05/13.
//
//
#import <Cocoa/Cocoa.h>
@interface DVTTextDocumentLocation : NSObject
@property (readonly) NSRange characterRange;
@property (readonly) NSRange lineRange;
@end
@interface DVTTextPreferences : NSObject
+ (id)preferences;
@property BOOL trimWhitespaceOnlyLines;
@property BOOL trimTrailingWhitespace;
@property BOOL useSyntaxAwareIndenting;
@end
@interface DVTSourceTextStorage : NSTextStorage
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string withUndoManager:(id)undoManager;
- (NSRange)lineRangeForCharacterRange:(NSRange)range;
- (NSRange)characterRangeForLineRange:(NSRange)range;
- (void)indentCharacterRange:(NSRange)range undoManager:(id)undoManager;
@end
@interface DVTFileDataType : NSObject
@property (readonly) NSString *identifier;
@end
@interface DVTFilePath : NSObject
@property (readonly) NSURL *fileURL;
@property (readonly) DVTFileDataType *fileDataTypePresumed;
@end
@interface IDEContainerItem : NSObject
@property (readonly) DVTFilePath *resolvedFilePath;
@end
@interface IDEGroup : IDEContainerItem
@end
@interface IDEFileReference : IDEContainerItem
@end
@interface IDENavigableItem : NSObject
@property (readonly) IDENavigableItem *parentItem;
@property (readonly) id representedObject;
@end
@interface IDEFileNavigableItem : IDENavigableItem
@property (readonly) DVTFileDataType *documentType;
@property (readonly) NSURL *fileURL;
@end
@interface IDEStructureNavigator : NSObject
@property (retain) NSArray *selectedObjects;
@end
@interface IDENavigableItemCoordinator : NSObject
- (id)structureNavigableItemForDocumentURL:(id)arg1 inWorkspace:(id)arg2 error:(id *)arg3;
@end
@interface IDENavigatorArea : NSObject
- (id)currentNavigator;
@end
@interface IDEWorkspaceTabController : NSObject
@property (readonly) IDENavigatorArea *navigatorArea;
@end
@interface IDEDocumentController : NSDocumentController
+ (id)editorDocumentForNavigableItem:(id)arg1;
+ (id)retainedEditorDocumentForNavigableItem:(id)arg1 error:(id *)arg2;
+ (void)releaseEditorDocument:(id)arg1;
@end
@interface IDESourceCodeDocument : NSDocument
- (DVTSourceTextStorage *)textStorage;
- (NSUndoManager *)undoManager;
@end
@interface IDESourceCodeComparisonEditor : NSObject
@property (readonly) NSTextView *keyTextView;
@property (retain) NSDocument *primaryDocument;
@end
@interface IDESourceCodeEditor : NSObject
@property (retain) NSTextView *textView;
- (IDESourceCodeDocument *)sourceCodeDocument;
@end
@interface IDEEditorContext : NSObject
- (id)editor; // returns the current editor. If the editor is the code editor, the class is `IDESourceCodeEditor`
@end
@interface IDEEditorArea : NSObject
- (IDEEditorContext *)lastActiveEditorContext;
@end
@interface IDEWorkspaceWindowController : NSObject
@property (readonly) IDEWorkspaceTabController *activeWorkspaceTabController;
- (IDEEditorArea *)editorArea;
@end
@interface IDEWorkspace : NSObject
@property (readonly) DVTFilePath *representingFilePath;
@end
@interface IDEWorkspaceDocument : NSDocument
@property (readonly) IDEWorkspace *workspace;
@end
@interface RCXcode : NSObject
+ (IDEWorkspaceDocument *)currentWorkspaceDocument;
+ (IDESourceCodeDocument *)currentSourceCodeDocument;
+ (NSTextView *)currentSourceCodeTextView;
+ (NSArray *)selectedObjCFileNavigableItems;
@end

120
QuickLocalization/RCXcode.m Normal file
View File

@@ -0,0 +1,120 @@
//
//
// Created by Zitao on 12/05/13.
//
//
#import "RCXcode.h"
@implementation RCXcode {}
#pragma mark - Helpers
+ (id)currentEditor {
NSWindowController *currentWindowController = [[NSApp keyWindow] windowController];
if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) {
IDEWorkspaceWindowController *workspaceController = (IDEWorkspaceWindowController *)currentWindowController;
IDEEditorArea *editorArea = [workspaceController editorArea];
IDEEditorContext *editorContext = [editorArea lastActiveEditorContext];
return [editorContext editor];
}
return nil;
}
+ (IDEWorkspaceDocument *)currentWorkspaceDocument {
NSWindowController *currentWindowController = [[NSApp keyWindow] windowController];
id document = [currentWindowController document];
if (currentWindowController && [document isKindOfClass:NSClassFromString(@"IDEWorkspaceDocument")]) {
return (IDEWorkspaceDocument *)document;
}
return nil;
}
+ (IDESourceCodeDocument *)currentSourceCodeDocument {
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) {
IDESourceCodeEditor *editor = [RCXcode currentEditor];
return editor.sourceCodeDocument;
}
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) {
IDESourceCodeComparisonEditor *editor = [RCXcode currentEditor];
if ([[editor primaryDocument] isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) {
IDESourceCodeDocument *document = (IDESourceCodeDocument *)editor.primaryDocument;
return document;
}
}
return nil;
}
+ (NSTextView *)currentSourceCodeTextView {
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) {
IDESourceCodeEditor *editor = [RCXcode currentEditor];
return editor.textView;
}
if ([[RCXcode currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) {
IDESourceCodeComparisonEditor *editor = [RCXcode currentEditor];
return editor.keyTextView;
}
return nil;
}
+ (NSArray *)selectedObjCFileNavigableItems {
NSMutableArray *mutableArray = [NSMutableArray array];
id currentWindowController = [[NSApp keyWindow] windowController];
if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) {
IDEWorkspaceWindowController *workspaceController = currentWindowController;
IDEWorkspaceTabController *workspaceTabController = [workspaceController activeWorkspaceTabController];
IDENavigatorArea *navigatorArea = [workspaceTabController navigatorArea];
id currentNavigator = [navigatorArea currentNavigator];
if ([currentNavigator isKindOfClass:NSClassFromString(@"IDEStructureNavigator")]) {
IDEStructureNavigator *structureNavigator = currentNavigator;
for (id selectedObject in structureNavigator.selectedObjects) {
if ([selectedObject isKindOfClass:NSClassFromString(@"IDEFileNavigableItem")]) {
IDEFileNavigableItem *fileNavigableItem = selectedObject;
NSString *uti = fileNavigableItem.documentType.identifier;
if ([uti isEqualToString:(NSString *)kUTTypeObjectiveCSource] || [uti isEqualToString:(NSString *)kUTTypeCHeader]) {
[mutableArray addObject:fileNavigableItem];
}
}
}
}
}
if (mutableArray.count) {
return [NSArray arrayWithArray:mutableArray];
}
return nil;
}
+ (NSArray *)containerFolderURLsForNavigableItem:(IDENavigableItem *)navigableItem {
NSMutableArray *mArray = [NSMutableArray array];
do {
NSURL *folderURL = nil;
id representedObject = navigableItem.representedObject;
if ([navigableItem isKindOfClass:NSClassFromString(@"IDEGroupNavigableItem")]) {
// IDE-GROUP (a folder in the navigator)
IDEGroup *group = (IDEGroup *)representedObject;
folderURL = group.resolvedFilePath.fileURL;
} else if ([navigableItem isKindOfClass:NSClassFromString(@"IDEContainerFileReferenceNavigableItem")]) {
// CONTAINER (an Xcode project)
IDEFileReference *fileReference = representedObject;
folderURL = [fileReference.resolvedFilePath.fileURL URLByDeletingLastPathComponent];
} else if ([navigableItem isKindOfClass:NSClassFromString(@"IDEKeyDrivenNavigableItem")]) {
// WORKSPACE (root: Xcode project or workspace)
IDEWorkspace *workspace = representedObject;
folderURL = [workspace.representingFilePath.fileURL URLByDeletingLastPathComponent];
}
if (folderURL && ![mArray containsObject:folderURL]) [mArray addObject:folderURL];
navigableItem = [navigableItem parentItem];
} while (navigableItem != nil);
if (mArray.count > 0) return [NSArray arrayWithArray:mArray];
return nil;
}
@end