support select text for replacing

This commit is contained in:
Zitao Xiong
2015-11-19 03:04:40 -05:00
parent 62ce9584da
commit a92c86075c
12 changed files with 738 additions and 122 deletions

View File

@@ -7,9 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
0966970B1B5A20C200D29654 /* AMMenuGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0966970A1B5A20C200D29654 /* AMMenuGenerator.m */; };
0966970B1B5A20C200D29654 /* QLMenuGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 0966970A1B5A20C200D29654 /* QLMenuGenerator.m */; };
0966970D1B5A20C900D29654 /* MenuItemData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0966970C1B5A20C900D29654 /* MenuItemData.plist */; };
096697101B5A214400D29654 /* AMConstString.m in Sources */ = {isa = PBXBuildFile; fileRef = 0966970F1B5A214400D29654 /* AMConstString.m */; };
096697101B5A214400D29654 /* QLConstString.m in Sources */ = {isa = PBXBuildFile; fileRef = 0966970F1B5A214400D29654 /* QLConstString.m */; };
098C633B1BFDB38E00A6398E /* QLIDEHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 098C633A1BFDB38E00A6398E /* QLIDEHelper.m */; };
098C633E1BFDB43100A6398E /* QLXcodeHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 098C633D1BFDB43100A6398E /* QLXcodeHelper.m */; };
099474BA1B5A1F3000E39E3C /* OLSettingController.m in Sources */ = {isa = PBXBuildFile; fileRef = 099474B81B5A1F3000E39E3C /* OLSettingController.m */; };
099474BB1B5A1F3000E39E3C /* OLSettingController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 099474B91B5A1F3000E39E3C /* OLSettingController.xib */; };
09A343C6174068E600A713EE /* RCXcode.m in Sources */ = {isa = PBXBuildFile; fileRef = 09A343C5174068E200A713EE /* RCXcode.m */; };
@@ -21,11 +23,15 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
096697091B5A20C200D29654 /* AMMenuGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AMMenuGenerator.h; sourceTree = "<group>"; };
0966970A1B5A20C200D29654 /* AMMenuGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AMMenuGenerator.m; sourceTree = "<group>"; };
096697091B5A20C200D29654 /* QLMenuGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QLMenuGenerator.h; sourceTree = "<group>"; };
0966970A1B5A20C200D29654 /* QLMenuGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QLMenuGenerator.m; sourceTree = "<group>"; };
0966970C1B5A20C900D29654 /* MenuItemData.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = MenuItemData.plist; sourceTree = "<group>"; };
0966970E1B5A214400D29654 /* AMConstString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AMConstString.h; sourceTree = "<group>"; };
0966970F1B5A214400D29654 /* AMConstString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AMConstString.m; sourceTree = "<group>"; };
0966970E1B5A214400D29654 /* QLConstString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QLConstString.h; sourceTree = "<group>"; };
0966970F1B5A214400D29654 /* QLConstString.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QLConstString.m; sourceTree = "<group>"; };
098C63391BFDB38E00A6398E /* QLIDEHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QLIDEHelper.h; sourceTree = "<group>"; };
098C633A1BFDB38E00A6398E /* QLIDEHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QLIDEHelper.m; sourceTree = "<group>"; };
098C633C1BFDB43100A6398E /* QLXcodeHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QLXcodeHelper.h; sourceTree = "<group>"; };
098C633D1BFDB43100A6398E /* QLXcodeHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QLXcodeHelper.m; sourceTree = "<group>"; };
099474B71B5A1F3000E39E3C /* OLSettingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OLSettingController.h; sourceTree = "<group>"; };
099474B81B5A1F3000E39E3C /* OLSettingController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OLSettingController.m; sourceTree = "<group>"; };
099474B91B5A1F3000E39E3C /* OLSettingController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OLSettingController.xib; sourceTree = "<group>"; };
@@ -89,10 +95,14 @@
09A343C4174068E200A713EE /* RCXcode.h */,
09A343C5174068E200A713EE /* RCXcode.m */,
0966970C1B5A20C900D29654 /* MenuItemData.plist */,
0966970E1B5A214400D29654 /* AMConstString.h */,
0966970F1B5A214400D29654 /* AMConstString.m */,
096697091B5A20C200D29654 /* AMMenuGenerator.h */,
0966970A1B5A20C200D29654 /* AMMenuGenerator.m */,
0966970E1B5A214400D29654 /* QLConstString.h */,
0966970F1B5A214400D29654 /* QLConstString.m */,
098C633C1BFDB43100A6398E /* QLXcodeHelper.h */,
098C633D1BFDB43100A6398E /* QLXcodeHelper.m */,
098C63391BFDB38E00A6398E /* QLIDEHelper.h */,
098C633A1BFDB38E00A6398E /* QLIDEHelper.m */,
096697091B5A20C200D29654 /* QLMenuGenerator.h */,
0966970A1B5A20C200D29654 /* QLMenuGenerator.m */,
09F6563A174041010000486B /* Supporting Files */,
099474B71B5A1F3000E39E3C /* OLSettingController.h */,
099474B81B5A1F3000E39E3C /* OLSettingController.m */,
@@ -178,9 +188,11 @@
buildActionMask = 2147483647;
files = (
09F65641174041010000486B /* QuickLocalization.m in Sources */,
096697101B5A214400D29654 /* AMConstString.m in Sources */,
096697101B5A214400D29654 /* QLConstString.m in Sources */,
098C633B1BFDB38E00A6398E /* QLIDEHelper.m in Sources */,
099474BA1B5A1F3000E39E3C /* OLSettingController.m in Sources */,
0966970B1B5A20C200D29654 /* AMMenuGenerator.m in Sources */,
098C633E1BFDB43100A6398E /* QLXcodeHelper.m in Sources */,
0966970B1B5A20C200D29654 /* QLMenuGenerator.m in Sources */,
09A343C6174068E600A713EE /* RCXcode.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -44,20 +44,46 @@ NSUInteger QL_CountOccurentOfStringWithSubString(NSString *str, NSString *subStr
[super windowDidLoad];
[self.comboBox selectItemAtIndex:0];
[self updatePreviewText];
}
- (IBAction)onSaveButton:(id)sender {
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
kQLFormatStringCommentValueKey: @"<# comment #>",
kQLFormatStringTableNameValueKey: @"nil",
kQLFormatStringBundleValueKey: @"nil",
kQLFormatStringValueValueKey: @"<# value #>",
kQLFormatStringCommentSameKey: @YES,
kQLFormatStringSwiftSyntax: @NO,
}];
self.commentTextField.stringValue = [[NSUserDefaults standardUserDefaults] objectForKey:kQLFormatStringCommentValueKey];
self.tableNameTextField.stringValue = [[NSUserDefaults standardUserDefaults] objectForKey:kQLFormatStringTableNameValueKey];
self.bunldeTextField.stringValue = [[NSUserDefaults standardUserDefaults] objectForKey:kQLFormatStringBundleValueKey];
self.valueTextField.stringValue = [[NSUserDefaults standardUserDefaults] objectForKey:kQLFormatStringValueValueKey];
if ([[NSUserDefaults standardUserDefaults] boolForKey:kQLFormatStringSwiftSyntax]) {
self.swiftLocalizationPreviewButton.state = NSOnState;
}
else {
self.swiftLocalizationPreviewButton.state = NSOffState;
}
if ([[NSUserDefaults standardUserDefaults] boolForKey:kQLFormatStringCommentSameKey]) {
self.commentSameAsKeyCheckButton.state = NSOnState;
}
else {
self.commentSameAsKeyCheckButton.state = NSOffState;
}
}
- (IBAction)commentDidChange:(id)sender {
[[NSUserDefaults standardUserDefaults] setObject:self.commentTextField.stringValue forKey:kQLFormatStringCommentValueKey];
[self updatePreviewText];
}
- (IBAction)onTableNameChanged:(id)sender {
[[NSUserDefaults standardUserDefaults] setObject:self.tableNameTextField.stringValue forKey:kQLFormatStringTableNameValueKey];
[self updatePreviewText];
}
- (IBAction)onBunldeNameChanged:(id)sender {
[[NSUserDefaults standardUserDefaults] setObject:self.bunldeTextField.stringValue forKey:kQLFormatStringBundleValueKey];
[self updatePreviewText];
}
@@ -72,6 +98,7 @@ NSUInteger QL_CountOccurentOfStringWithSubString(NSString *str, NSString *subStr
}
- (IBAction)onValueTextField:(id)sender {
[[NSUserDefaults standardUserDefaults] setObject:self.valueTextField.stringValue forKey:kQLFormatStringValueValueKey];
[self updatePreviewText];
}

View File

@@ -9,13 +9,6 @@
#import <Foundation/Foundation.h>
extern NSString * const kDeclareMap;
extern NSString * const kImplementMap;
extern NSString * const kImplementContent;
extern NSString * const kSelectTextType;
extern NSString * const kSelectTextFirstSelectMethod;
extern NSString * const kMenuRootMenuTitle;
extern NSString * const kMenuPluginTitle;
extern NSString * const kMenuSubMenuItems;
@@ -29,4 +22,10 @@ extern NSString * const kMenuActionTitle;
extern NSString * const kQLFormatStringKey;
extern NSString * const kQLFormatStringCommentSameKey;
extern NSString * const kQLFormatStringSwiftSyntax;
extern NSString * const kQLFormatStringSwiftSyntax;
extern NSString * const kQLFormatStringCommentValueKey;
extern NSString * const kQLFormatStringTableNameValueKey;
extern NSString * const kQLFormatStringBundleValueKey;
extern NSString * const kQLFormatStringValueValueKey;

View File

@@ -6,16 +6,9 @@
// Copyright (c) 2015 Tendencystudio. All rights reserved.
//
#import "AMConstString.h"
#import "QLConstString.h"
NSString * const kDeclareMap = @"declareMap";
NSString * const kImplementMap = @"implementMap";
NSString * const kImplementContent = @"implementContent";
NSString * const kSelectTextType = @"type";
NSString * const kSelectTextFirstSelectMethod = @"firstSelectMethod";
NSString * const kMenuRootMenuTitle = @"rootMenuTitle";
NSString * const kMenuPluginTitle = @"pluginTitle";
NSString * const kMenuSubMenuItems = @"subMenuItems";
@@ -29,4 +22,11 @@ NSString * const kMenuActionTitle = @"Implement Mehod";
NSString * const kQLFormatStringKey = @"KQLFormatStringKey";
NSString * const kQLFormatStringCommentSameKey = @"KQLFormatStringKey";
NSString * const kQLFormatStringSwiftSyntax = @"kQLFormatStringSwiftSyntax";
NSString * const kQLFormatStringSwiftSyntax = @"kQLFormatStringSwiftSyntax";
NSString * const kQLFormatStringCommentValueKey = @"kQLFormatStringCommentValueKey";
NSString * const kQLFormatStringTableNameValueKey = @"kQLFormatStringTableNameValueKey";
NSString * const kQLFormatStringBundleValueKey = @"kQLFormatStringBundleValueKey";
NSString * const kQLFormatStringValueValueKey = @"kQLFormatStringValueValueKey";

View File

@@ -0,0 +1,132 @@
//
// QLIDEHelper.h
// QLMethod2Implement
//
// Created by Long on 14-4-15.
// Copyright (c) 2014年 Tendencystudio. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef enum {
QLIDEFileTypeMFile = 0,
QLIDEFileTypeHFile
}QLIDEFileType;
typedef enum {
QLImplementTypeMethod = 0,
QLImplementTypeConstString,
QLImplementTypeSelector,
QLImplementTypeInvocation,
QLImplementTypeGetter
}QLImplementType;
@interface QLIDEHelper : NSObject
/**
* Open file in Xcode editor.
*
* @param filePath file path.
*
* @return return YES if open file success.
*/
+ (BOOL)openFile:(NSString *)filePath;
/**
* Get current edit file path.
*
* @return current edit file path
*/
+ (NSString *)getCurrentEditFilePath;
/**
* Get .m file of current edit file.
*
* @return .m file path.
*/
+ (NSString *)getMFilePathOfCurrentEditFile;
/**
* Get current class name by "Current Edit File Path"
*
* @return class name.
*/
+ (NSString *)getCurrentClassName;
/**
* Check current opened file is .h file.
*
* @return return YES if current fils is .h file.
*/
+ (BOOL)isHeaderFile;
/**
* Get .h file of current edit file.
*
* @return .h file path.
*/
+ (NSString *)getHFilePathOfCurrentEditFile;
/**
* Highlight text and scroll to visible in current edit file.
*
* @param target text.
*/
+ (void)selectText:(NSString *)text;
/**
* Search regex string and scroll to visible in current edit file.
*
* @param regex regex string.
* @param text highlight text.
*/
+ (void)selectTextWithRegex:(NSString *)regex highlightText:(NSString *)text;
/**
* Replace text in current editor.
*
* @param text text to be replace.
* @param newText new text.
*/
+ (void)replaceText:(NSString *)text withNewText:(NSString *)newText;
/**
* Get current selected range string.
*
* @return selected range string.
*/
+ (NSString *)getCurrentSelectMethod;
/**
* Get all class name by @interface or @implementation of .h file or .m file of the current edit file.
*
* @param fileType QLIDEFileTypeMFile or QLIDEFileTypeHFile
*
* @return class name.
*/
+ (NSArray *)getCurrentClassNameByCurrentSelectedRangeWithFileType:(QLIDEFileType)fileType;
/**
* Get target insert position for code generation.
*
* @param range content range: contentRange = [QLIDEHelper getClassImplementContentRangeWithClassNameItemList:currentClassName fileText:textView.textStorage.string fileType:QLIDEFileTypeMFile];
*
* @return target insert range.
*/
+ (NSRange)getInsertRangeWithClassImplementContentRange:(NSRange)range;
/**
* Get class @interface or @implementation code range(before @end) in .h or .m file.
*
* @param classNameItemList all class name by: NSArray *currentClassName = [QLIDEHelper getCurrentClassNameByCurrentSelectedRangeWithFileType:QLIDEFileTypeHFile];
* @param fileText target string for match, should be .m (fileType should be QLIDEFileTypeMFile) or .h (fileType should be QLIDEFileTypeHFile) file content string.
* @param fileType QLIDEFileTypeMFile or QLIDEFileTypeHFile
*
* @return range from @interface/@implementation to @end, not include @end.
*/
+ (NSRange)getClassImplementContentRangeWithClassNameItemList:(NSArray *)classNameItemList
fileText:(NSString *)fileText
fileType:(QLIDEFileType)fileType;
@end

View File

@@ -0,0 +1,220 @@
//
// QLIDEHelper.m
// QLMethod2Implement
//
// Created by Long on 14-4-15.
// Copyright (c) 2014 Tendencystudio. All rights reserved.
//
#import "QLIDEHelper.h"
#import "QLXcodeHelper.h"
#import <AppKit/AppKit.h>
@implementation QLIDEHelper
+ (BOOL)openFile:(NSString *)filePath
{
NSWindowController *currentWindowController = [[NSApp mainWindow] windowController];
NSLog(@"currentWindowController %@",[currentWindowController description]);
if ([currentWindowController isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) {
NSLog(@"Open in current Xocde");
id<NSApplicationDelegate> appDelegate = (id<NSApplicationDelegate>)[NSApp delegate];
if ([appDelegate application:NSApp openFile:filePath]) {
return YES;
}
}
return NO;
}
+ (NSString *)getCurrentEditFilePath
{
IDESourceCodeDocument *currentSourceCodeDocument = [QLXcodeHelper currentSourceCodeDocument];
NSString *filePath = [[currentSourceCodeDocument fileURL] path];
return filePath;
}
+ (BOOL)isHeaderFile
{
NSString *filePath = [QLIDEHelper getCurrentEditFilePath];
if ([filePath rangeOfString:@".h"].length > 0) {
return YES;
}
return NO;
}
+ (NSString *)getHFilePathOfCurrentEditFile
{
NSString *filePath = [QLIDEHelper getCurrentEditFilePath];
filePath = [filePath stringByDeletingPathExtension];
filePath = [filePath stringByAppendingPathExtension:@"h"];
return filePath;
}
+ (NSString *)getMFilePathOfCurrentEditFile
{
NSString *filePath = [QLIDEHelper getCurrentEditFilePath];
if ([filePath rangeOfString:@".h"].length > 0) {
NSString *mFilePath = [filePath stringByReplacingOccurrencesOfString:@".h" withString:@".m"];
if ([[NSFileManager defaultManager] fileExistsAtPath:mFilePath]) {
return mFilePath;
}
mFilePath = [filePath stringByReplacingOccurrencesOfString:@".h" withString:@".mm"];
if ([[NSFileManager defaultManager] fileExistsAtPath:mFilePath]) {
return mFilePath;
}
}
return filePath;
}
+ (NSString *)getCurrentClassName
{
NSString *fileName = [[QLIDEHelper getCurrentEditFilePath] lastPathComponent];
return [fileName stringByDeletingPathExtension];
}
+ (void)selectText:(NSString *)text
{
NSTextView *textView = [QLXcodeHelper currentSourceCodeTextView];
NSRange textRange = [textView.textStorage.string rangeOfString:text options:NSCaseInsensitiveSearch];
if (textRange.location != NSNotFound)
{
[textView setSelectedRange:textRange];
[textView scrollRangeToVisible:textRange];
}
}
+ (void)selectTextWithRegex:(NSString *)regex highlightText:(NSString *)text
{
NSTextView *textView = [QLXcodeHelper currentSourceCodeTextView];
NSRegularExpression *regularExpression = [NSRegularExpression
regularExpressionWithPattern:regex
options:NSRegularExpressionAnchorsMatchLines
error:NULL];
NSRange range = [regularExpression rangeOfFirstMatchInString:textView.textStorage.string
options:0
range:NSMakeRange(0, [textView.textStorage.string length])];
if (range.location == NSNotFound) {
return;
}
NSString *string = [textView.textStorage.string substringWithRange:range];
NSLog(@"selectTextWithRegex: %@", string);
NSRange textRange = [string rangeOfString:text options:NSCaseInsensitiveSearch];
if (textRange.location != NSNotFound) {
range = NSMakeRange(range.location+textRange.location, textRange.length);
}
[textView setSelectedRange:range];
[textView scrollRangeToVisible:range];
}
+ (void)replaceText:(NSString *)text withNewText:(NSString *)newText
{
NSTextView *textView = [QLXcodeHelper currentSourceCodeTextView];
NSRange textRange = [textView.textStorage.string rangeOfString:text options:NSCaseInsensitiveSearch];
[textView scrollRangeToVisible:textRange];
[textView insertText:newText replacementRange:textRange];
}
+ (NSString *)getCurrentSelectMethod
{
NSTextView *textView = [QLXcodeHelper currentSourceCodeTextView];
NSArray* selectedRanges = [textView selectedRanges];
if (selectedRanges.count >= 1) {
NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue];
NSString *text = textView.textStorage.string;
NSRange lineRange = [text lineRangeForRange:selectedRange];
NSString *line = [text substringWithRange:lineRange];
return line;
}
return nil;
}
+ (NSArray *)getCurrentClassNameByCurrentSelectedRangeWithFileType:(QLIDEFileType)fileType
{
NSTextView *textView = [QLXcodeHelper currentSourceCodeTextView];
NSArray* selectedRanges = [textView selectedRanges];
if (selectedRanges.count >= 1) {
NSRange selectedRange = [[selectedRanges objectAtIndex:0] rangeValue];
NSString *text = textView.textStorage.string;
NSRange lineRange = [text lineRangeForRange:selectedRange];
NSString *regexString = nil;
if (fileType == QLIDEFileTypeHFile) {
regexString = @"(?<=@interface)\\s+(\\w+)\\s*\\(?(\\w*)\\)?";
}else if (fileType == QLIDEFileTypeMFile) {
regexString = @"(?<=@implementation)\\s+(\\w+)\\s*\\(?(\\w*)\\)?";
}
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:regexString
options:0
error:NULL];
NSArray *results = [regex matchesInString:textView.textStorage.string options:0 range:NSMakeRange(0, lineRange.location)];
if (results.count > 0) {
NSTextCheckingResult *textCheckingResult = results[results.count - 1];
NSRange classNameRange = textCheckingResult.range;
if (classNameRange.location != NSNotFound) {
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < textCheckingResult.numberOfRanges; i++) {
NSString *item = [text substringWithRange:[textCheckingResult rangeAtIndex:i]];
if (item.length > 0) {
[array addObject:item];
NSLog(@"%@", item);
}
}
return array;
}
}
}
return nil;
}
+ (NSRange)getClassImplementContentRangeWithClassNameItemList:(NSArray *)classNameItemList fileText:(NSString *)fileText fileType:(QLIDEFileType)fileType
{
if (classNameItemList.count > 1) {
NSString *normalImplementationFormatString = @"@implementation\\s+%@.+?(?=\\s{0,3000}@end)";
if (fileType == QLIDEFileTypeHFile) {
normalImplementationFormatString = @"@interface\\s+%@.+?(?=\\s{0,3000}@end)";
}
NSString *regexPattern = [NSString stringWithFormat:normalImplementationFormatString, classNameItemList[1]];
if (classNameItemList.count == 3) {
NSString *categoryImplementationFormatString = @"@implementation\\s+%@\\s+\\(%@\\).+?(?=\\s{0,3000}@end)";
if (fileType == QLIDEFileTypeHFile) {
categoryImplementationFormatString = @"@interface\\s+%@\\s+\\(%@\\).+?(?=\\s{0,3000}@end)";
}
regexPattern = [NSString stringWithFormat:categoryImplementationFormatString, classNameItemList[1], classNameItemList[2]];
}
NSLog(@"#%@",regexPattern);
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:regexPattern
options:NSRegularExpressionDotMatchesLineSeparators
error:NULL];
NSTextCheckingResult *textCheckingResult = [regex firstMatchInString:fileText
options:0
range:NSMakeRange(0, fileText.length)];
// NSLog(@"#%@", [fileText substringWithRange:textCheckingResult.range]);
if (textCheckingResult.range.location != NSNotFound) {
return textCheckingResult.range;
}
}
return NSMakeRange(NSNotFound, 0);
}
+ (NSRange)getInsertRangeWithClassImplementContentRange:(NSRange)range
{
if (range.location != NSNotFound) {
return NSMakeRange(range.location+range.length, 1);
}
return NSMakeRange(NSNotFound, 0);
}
@end

View File

@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h>
@interface AMMenuGenerator : NSObject
@interface QLMenuGenerator : NSObject
+ (void)generateMenuItems:(NSBundle *)bundle version:(NSString *)version target:(id)target;
+ (NSUInteger)getKeyEquivalentModifierMaskWithKey:(NSString *)key;

View File

@@ -6,10 +6,10 @@
// Copyright (c) 2015 Tendencystudio. All rights reserved.
//
#import "AMMenuGenerator.h"
#import "QLMenuGenerator.h"
#import "RCXcode.h"
@implementation AMMenuGenerator
@implementation QLMenuGenerator
+ (void)generateMenuItems:(NSBundle *)bundle version:(NSString *)version target:(id)target
{
@@ -51,10 +51,10 @@
NSMenuItem *subMenuItem = [[NSMenuItem alloc] initWithTitle:subMenuTitle action:selector keyEquivalent:keyEquivalent];
if (maskArray.count == 1) {
subMenuItem.keyEquivalentModifierMask = [AMMenuGenerator getKeyEquivalentModifierMaskWithKey:maskArray[0]];
subMenuItem.keyEquivalentModifierMask = [QLMenuGenerator getKeyEquivalentModifierMaskWithKey:maskArray[0]];
}else if(maskArray.count == 2) {
subMenuItem.keyEquivalentModifierMask = [AMMenuGenerator getKeyEquivalentModifierMaskWithKey:maskArray[0]] |
[AMMenuGenerator getKeyEquivalentModifierMaskWithKey:maskArray[1]];
subMenuItem.keyEquivalentModifierMask = [QLMenuGenerator getKeyEquivalentModifierMaskWithKey:maskArray[0]] |
[QLMenuGenerator getKeyEquivalentModifierMaskWithKey:maskArray[1]];
}
subMenuItem.target = target;
[submenu addItem:subMenuItem];

View File

@@ -0,0 +1,125 @@
//
// QLXcodeHelper.h
//
//
// Created by Mellong on 14-4-13.
// Copyright (c) 2014年 Tendencystudio. All rights reserved.
//
#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 QLXcodeHelper : NSObject
+ (IDEWorkspaceDocument *)currentWorkspaceDocument;
+ (IDESourceCodeDocument *)currentSourceCodeDocument;
+ (NSTextView *)currentSourceCodeTextView;
+ (NSArray *)selectedObjCFileNavigableItems;
@end

View File

@@ -0,0 +1,123 @@
//
// QLXcodeHelper.m
//
//
// Created by Mellong on 14-4-13.
// Copyright (c) 2014 Tendencystudio. All rights reserved.
//
#import "QLXcodeHelper.h"
@implementation QLXcodeHelper
#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 ([[QLXcodeHelper currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) {
IDESourceCodeEditor *editor = [QLXcodeHelper currentEditor];
return editor.sourceCodeDocument;
}
if ([[QLXcodeHelper currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) {
IDESourceCodeComparisonEditor *editor = [QLXcodeHelper currentEditor];
if ([[editor primaryDocument] isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) {
IDESourceCodeDocument *document = (IDESourceCodeDocument *)editor.primaryDocument;
return document;
}
}
return nil;
}
+ (NSTextView *)currentSourceCodeTextView {
if ([[QLXcodeHelper currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) {
IDESourceCodeEditor *editor = [QLXcodeHelper currentEditor];
return editor.textView;
}
if ([[QLXcodeHelper currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) {
IDESourceCodeComparisonEditor *editor = [QLXcodeHelper 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

View File

@@ -4,5 +4,5 @@
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import "AMConstString.h"
#import "QLConstString.h"
#endif

View File

@@ -9,7 +9,8 @@
#import "QuickLocalization.h"
#import "RCXcode.h"
#import "OLSettingController.h"
#import "AMMenuGenerator.h"
#import "QLMenuGenerator.h"
#import "QLIDEHelper.h"
static NSString *localizeRegexs[] = {
@"NSLocalizedString\\s*\\(\\s*@\"(.*)\"\\s*,\\s*(.*)\\s*\\)",
@@ -74,42 +75,7 @@ static id sharedPlugin = nil;
}
- (void)createMenuItem {
[AMMenuGenerator generateMenuItems:self.bundle version:[self getBundleVersion] target:self];
// return;
// [[NSOperationQueue mainQueue] addOperationWithBlock:^{
// NSMenuItem *viewMenuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"];
// if (viewMenuItem) {
// [[viewMenuItem submenu] addItem:[NSMenuItem separatorItem]];
//
// NSMenuItem *localization = [[NSMenuItem alloc] initWithTitle:@"Quick Localization" action:@selector(quickLocalization:) keyEquivalent:@"d"];
// [localization setKeyEquivalentModifierMask:NSShiftKeyMask | NSAlternateKeyMask];
// [localization setTarget:self];
// [localization setTag:0];
//
// NSMenuItem *shouldUseStringFromTableInBundleToggle = [[NSMenuItem alloc] initWithTitle:@"NSLocalizedStringFromTableInBundle" action:@selector(toggleStringFromTableInBundle) keyEquivalent:@""];
// [shouldUseStringFromTableInBundleToggle setTarget:self];
//
// NSMenuItem *nilToggle = [[NSMenuItem alloc] initWithTitle:@"Use nil for NSLocalizedString comment" action:@selector(toggleNilOption) keyEquivalent:@""];
// [nilToggle setTarget:self];
//
// NSMenuItem *snippetToggle = [[NSMenuItem alloc] initWithTitle:@"Use <# comments #> for NSLocalizedString comment" action:@selector(toggleSnippetOption) keyEquivalent:@""];
// [snippetToggle setTarget:self];
//
// NSMenuItem *swiftSyntax = [[NSMenuItem alloc] initWithTitle:@"Swift Localization" action:@selector(toggleSwiftOption) keyEquivalent:@""];
// [swiftSyntax setTarget:self];
//
// NSMenu *groupMenu = [[NSMenu alloc] initWithTitle:@"Quick Localization"];
// [groupMenu addItem:localization];
// [groupMenu addItem:nilToggle];
// [groupMenu addItem:snippetToggle];
// [groupMenu addItem:swiftSyntax];
// [groupMenu addItem:shouldUseStringFromTableInBundleToggle];
//
// NSMenuItem *groupMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quick Localization" action:NULL keyEquivalent:@""];
// [[viewMenuItem submenu] addItem:groupMenuItem];
// [[viewMenuItem submenu] setSubmenu:groupMenu forItem:groupMenuItem];
// }
// }];
[QLMenuGenerator generateMenuItems:self.bundle version:[self getBundleVersion] target:self];
}
// Sample Action, for menu item:
@@ -120,59 +86,71 @@ static id sharedPlugin = nil;
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];
NSArray *localizedMatches = [localizedRex matchesInString:line options:0 range:NSMakeRange(0, [line length])];
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:[self currentStringRegexs] options:NSRegularExpressionCaseInsensitive error:nil];
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];
// NSLog(@"string index:%d, %@", i, string);
NSString *outputString;
NSString *savedFormatString = [[NSUserDefaults standardUserDefaults] objectForKey:kQLFormatStringKey];
NSUInteger placeHolderCount = QL_CountOccurentOfStringWithSubString(savedFormatString, @"%@");
if (placeHolderCount == 2) {
outputString = [NSString stringWithFormat:savedFormatString, string, string];
}
else if (placeHolderCount == 1) {
outputString = [NSString stringWithFormat:savedFormatString, string];
}
else {
outputString = [NSString stringWithFormat:@"placeholder incorrect, it is %@", savedFormatString];
}
addedLength = addedLength + outputString.length - string.length;
if ([textView shouldChangeTextInRange:matchedRangeInDocument replacementString:outputString]) {
[textView.textStorage replaceCharactersInRange:matchedRangeInDocument
withAttributedString:[[NSAttributedString alloc] initWithString:outputString]];
[textView didChangeText];
}
// [textView replaceCharactersInRange:matchedRangeInDocument withString:outputString];
// NSAlert *alert = [NSAlert alertWithMessageText:outputString defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@""];
// [alert runModal];
BOOL replaced = [self replaceTextInRange:range textView:textView];
//if user selected text is not being replaced, try using line replacing
if (!replaced) {
NSRange lineRange = [textView.textStorage.string lineRangeForRange:range];
[self replaceTextInRange:lineRange textView:textView];
}
}
}
- (BOOL)replaceTextInRange:(NSRange)range textView:(NSTextView *)textView {
NSString *line = [textView.textStorage.string substringWithRange:range];
NSRegularExpression *localizedRex = [[NSRegularExpression alloc] initWithPattern:localizeRegexs[0] options:NSRegularExpressionCaseInsensitive error:nil];
NSArray *localizedMatches = [localizedRex matchesInString:line options:0 range:NSMakeRange(0, [line length])];
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:[self currentStringRegexs] options:NSRegularExpressionCaseInsensitive error:nil];
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(range.location + matchedRangeInLine.location + addedLength, matchedRangeInLine.length);
if ([self isRange:matchedRangeInLine inSkipedRanges:localizedMatches]) {
continue;
}
NSString *string = [line substringWithRange:matchedRangeInLine];
// NSLog(@"string index:%d, %@", i, string);
NSString *outputString;
NSString *savedFormatString = [[NSUserDefaults standardUserDefaults] objectForKey:kQLFormatStringKey];
NSUInteger placeHolderCount = QL_CountOccurentOfStringWithSubString(savedFormatString, @"%@");
if (placeHolderCount == 2) {
outputString = [NSString stringWithFormat:savedFormatString, string, string];
}
else if (placeHolderCount == 1) {
outputString = [NSString stringWithFormat:savedFormatString, string];
}
else {
outputString = [NSString stringWithFormat:@"placeholder incorrect, format string is %@", savedFormatString];
}
addedLength = addedLength + outputString.length - string.length;
if ([textView shouldChangeTextInRange:matchedRangeInDocument replacementString:outputString]) {
[textView.textStorage replaceCharactersInRange:matchedRangeInDocument
withAttributedString:[[NSAttributedString alloc] initWithString:outputString]];
[textView didChangeText];
}
// [textView replaceCharactersInRange:matchedRangeInDocument withString:outputString];
// NSAlert *alert = [NSAlert alertWithMessageText:outputString defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@""];
// [alert runModal];
}
if (matches.count) {
return YES;
}
else {
return NO;
}
}
- (NSString *)currentStringRegexs {
BOOL isSwiftSyntax = [[NSUserDefaults standardUserDefaults] boolForKey:kQLFormatStringSwiftSyntax];
if (isSwiftSyntax) {