├── .gitignore ├── DebugSearch.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── DebugSearch.xccheckout ├── DebugSearch ├── DebugSearch-Info.plist ├── DebugSearch-Prefix.pch ├── DebugSearch.h ├── DebugSearch.m └── Info.plist ├── README.md └── dbgHighlightConf.plist /.gitignore: -------------------------------------------------------------------------------- 1 | DebugSearch.xcodeproj/project.xcworkspace/xcuserdata* 2 | DebugSearch.xcodeproj/xcuserdata* 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /DebugSearch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 802FE8E91953585F009188E2 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 802FE8E81953585F009188E2 /* AppKit.framework */; }; 11 | 802FE8EB1953585F009188E2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 802FE8EA1953585F009188E2 /* Foundation.framework */; }; 12 | 802FE8F11953585F009188E2 /* DebugSearch.m in Sources */ = {isa = PBXBuildFile; fileRef = 802FE8F01953585F009188E2 /* DebugSearch.m */; }; 13 | 802FE8F31953585F009188E2 /* DebugSearch-Prefix.pch in Resources */ = {isa = PBXBuildFile; fileRef = 802FE8F21953585F009188E2 /* DebugSearch-Prefix.pch */; }; 14 | 802FE8F51953585F009188E2 /* DebugSearch-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 802FE8F41953585F009188E2 /* DebugSearch-Info.plist */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 802FE8E51953585F009188E2 /* DebugSearch.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DebugSearch.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | 802FE8E81953585F009188E2 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 20 | 802FE8EA1953585F009188E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 21 | 802FE8EE1953585F009188E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | 802FE8EF1953585F009188E2 /* DebugSearch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DebugSearch.h; sourceTree = ""; }; 23 | 802FE8F01953585F009188E2 /* DebugSearch.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DebugSearch.m; sourceTree = ""; }; 24 | 802FE8F21953585F009188E2 /* DebugSearch-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DebugSearch-Prefix.pch"; sourceTree = ""; }; 25 | 802FE8F41953585F009188E2 /* DebugSearch-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DebugSearch-Info.plist"; sourceTree = ""; }; 26 | /* End PBXFileReference section */ 27 | 28 | /* Begin PBXFrameworksBuildPhase section */ 29 | 802FE8E21953585F009188E2 /* Frameworks */ = { 30 | isa = PBXFrameworksBuildPhase; 31 | buildActionMask = 2147483647; 32 | files = ( 33 | 802FE8E91953585F009188E2 /* AppKit.framework in Frameworks */, 34 | 802FE8EB1953585F009188E2 /* Foundation.framework in Frameworks */, 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 802FE8DC1953585F009188E2 = { 42 | isa = PBXGroup; 43 | children = ( 44 | 802FE8EC1953585F009188E2 /* DebugSearch */, 45 | 802FE8E71953585F009188E2 /* Frameworks */, 46 | 802FE8E61953585F009188E2 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 802FE8E61953585F009188E2 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 802FE8E51953585F009188E2 /* DebugSearch.xcplugin */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 802FE8E71953585F009188E2 /* Frameworks */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 802FE8E81953585F009188E2 /* AppKit.framework */, 62 | 802FE8EA1953585F009188E2 /* Foundation.framework */, 63 | ); 64 | name = Frameworks; 65 | sourceTree = ""; 66 | }; 67 | 802FE8EC1953585F009188E2 /* DebugSearch */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 802FE8EF1953585F009188E2 /* DebugSearch.h */, 71 | 802FE8F01953585F009188E2 /* DebugSearch.m */, 72 | 802FE8F21953585F009188E2 /* DebugSearch-Prefix.pch */, 73 | 802FE8F41953585F009188E2 /* DebugSearch-Info.plist */, 74 | 802FE8ED1953585F009188E2 /* Supporting Files */, 75 | ); 76 | path = DebugSearch; 77 | sourceTree = ""; 78 | }; 79 | 802FE8ED1953585F009188E2 /* Supporting Files */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 802FE8EE1953585F009188E2 /* Info.plist */, 83 | ); 84 | name = "Supporting Files"; 85 | sourceTree = ""; 86 | }; 87 | /* End PBXGroup section */ 88 | 89 | /* Begin PBXNativeTarget section */ 90 | 802FE8E41953585F009188E2 /* DebugSearch */ = { 91 | isa = PBXNativeTarget; 92 | buildConfigurationList = 802FE8F81953585F009188E2 /* Build configuration list for PBXNativeTarget "DebugSearch" */; 93 | buildPhases = ( 94 | 802FE8E11953585F009188E2 /* Sources */, 95 | 802FE8E21953585F009188E2 /* Frameworks */, 96 | 802FE8E31953585F009188E2 /* Resources */, 97 | ); 98 | buildRules = ( 99 | ); 100 | dependencies = ( 101 | ); 102 | name = DebugSearch; 103 | productName = DebugSearch; 104 | productReference = 802FE8E51953585F009188E2 /* DebugSearch.xcplugin */; 105 | productType = "com.apple.product-type.bundle"; 106 | }; 107 | /* End PBXNativeTarget section */ 108 | 109 | /* Begin PBXProject section */ 110 | 802FE8DD1953585F009188E2 /* Project object */ = { 111 | isa = PBXProject; 112 | attributes = { 113 | LastUpgradeCheck = 0600; 114 | ORGANIZATIONNAME = moises; 115 | TargetAttributes = { 116 | 802FE8E41953585F009188E2 = { 117 | CreatedOnToolsVersion = 6.0; 118 | }; 119 | }; 120 | }; 121 | buildConfigurationList = 802FE8E01953585F009188E2 /* Build configuration list for PBXProject "DebugSearch" */; 122 | compatibilityVersion = "Xcode 3.2"; 123 | developmentRegion = English; 124 | hasScannedForEncodings = 0; 125 | knownRegions = ( 126 | en, 127 | ); 128 | mainGroup = 802FE8DC1953585F009188E2; 129 | productRefGroup = 802FE8E61953585F009188E2 /* Products */; 130 | projectDirPath = ""; 131 | projectRoot = ""; 132 | targets = ( 133 | 802FE8E41953585F009188E2 /* DebugSearch */, 134 | ); 135 | }; 136 | /* End PBXProject section */ 137 | 138 | /* Begin PBXResourcesBuildPhase section */ 139 | 802FE8E31953585F009188E2 /* Resources */ = { 140 | isa = PBXResourcesBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 802FE8F51953585F009188E2 /* DebugSearch-Info.plist in Resources */, 144 | 802FE8F31953585F009188E2 /* DebugSearch-Prefix.pch in Resources */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | /* End PBXResourcesBuildPhase section */ 149 | 150 | /* Begin PBXSourcesBuildPhase section */ 151 | 802FE8E11953585F009188E2 /* Sources */ = { 152 | isa = PBXSourcesBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | 802FE8F11953585F009188E2 /* DebugSearch.m in Sources */, 156 | ); 157 | runOnlyForDeploymentPostprocessing = 0; 158 | }; 159 | /* End PBXSourcesBuildPhase section */ 160 | 161 | /* Begin XCBuildConfiguration section */ 162 | 802FE8F61953585F009188E2 /* Debug */ = { 163 | isa = XCBuildConfiguration; 164 | buildSettings = { 165 | ALWAYS_SEARCH_USER_PATHS = NO; 166 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 167 | CLANG_CXX_LIBRARY = "libc++"; 168 | CLANG_ENABLE_MODULES = YES; 169 | CLANG_ENABLE_OBJC_ARC = YES; 170 | CLANG_WARN_BOOL_CONVERSION = YES; 171 | CLANG_WARN_CONSTANT_CONVERSION = YES; 172 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 173 | CLANG_WARN_EMPTY_BODY = YES; 174 | CLANG_WARN_ENUM_CONVERSION = YES; 175 | CLANG_WARN_INT_CONVERSION = YES; 176 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 177 | CLANG_WARN_UNREACHABLE_CODE = YES; 178 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 179 | COPY_PHASE_STRIP = NO; 180 | ENABLE_STRICT_OBJC_MSGSEND = YES; 181 | GCC_C_LANGUAGE_STANDARD = gnu99; 182 | GCC_DYNAMIC_NO_PIC = NO; 183 | GCC_OPTIMIZATION_LEVEL = 0; 184 | GCC_PREPROCESSOR_DEFINITIONS = ( 185 | "DEBUG=1", 186 | "$(inherited)", 187 | ); 188 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 189 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 190 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 191 | GCC_WARN_UNDECLARED_SELECTOR = YES; 192 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 193 | GCC_WARN_UNUSED_FUNCTION = YES; 194 | GCC_WARN_UNUSED_VARIABLE = YES; 195 | METAL_ENABLE_DEBUG_INFO = YES; 196 | ONLY_ACTIVE_ARCH = YES; 197 | }; 198 | name = Debug; 199 | }; 200 | 802FE8F71953585F009188E2 /* Release */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_UNREACHABLE_CODE = YES; 216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 217 | COPY_PHASE_STRIP = YES; 218 | ENABLE_NS_ASSERTIONS = NO; 219 | ENABLE_STRICT_OBJC_MSGSEND = YES; 220 | GCC_C_LANGUAGE_STANDARD = gnu99; 221 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 222 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 223 | GCC_WARN_UNDECLARED_SELECTOR = YES; 224 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 225 | GCC_WARN_UNUSED_FUNCTION = YES; 226 | GCC_WARN_UNUSED_VARIABLE = YES; 227 | METAL_ENABLE_DEBUG_INFO = NO; 228 | }; 229 | name = Release; 230 | }; 231 | 802FE8F91953585F009188E2 /* Debug */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | COMBINE_HIDPI_IMAGES = YES; 235 | DEPLOYMENT_LOCATION = YES; 236 | DSTROOT = "$(HOME)"; 237 | INFOPLIST_FILE = DebugSearch/Info.plist; 238 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 239 | ONLY_ACTIVE_ARCH = NO; 240 | PRODUCT_NAME = "$(TARGET_NAME)"; 241 | SDKROOT = macosx; 242 | WRAPPER_EXTENSION = xcplugin; 243 | }; 244 | name = Debug; 245 | }; 246 | 802FE8FA1953585F009188E2 /* Release */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | COMBINE_HIDPI_IMAGES = YES; 250 | DEPLOYMENT_LOCATION = YES; 251 | DSTROOT = "$(HOME)"; 252 | INFOPLIST_FILE = DebugSearch/Info.plist; 253 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 254 | PRODUCT_NAME = "$(TARGET_NAME)"; 255 | SDKROOT = macosx; 256 | WRAPPER_EXTENSION = xcplugin; 257 | }; 258 | name = Release; 259 | }; 260 | /* End XCBuildConfiguration section */ 261 | 262 | /* Begin XCConfigurationList section */ 263 | 802FE8E01953585F009188E2 /* Build configuration list for PBXProject "DebugSearch" */ = { 264 | isa = XCConfigurationList; 265 | buildConfigurations = ( 266 | 802FE8F61953585F009188E2 /* Debug */, 267 | 802FE8F71953585F009188E2 /* Release */, 268 | ); 269 | defaultConfigurationIsVisible = 0; 270 | defaultConfigurationName = Release; 271 | }; 272 | 802FE8F81953585F009188E2 /* Build configuration list for PBXNativeTarget "DebugSearch" */ = { 273 | isa = XCConfigurationList; 274 | buildConfigurations = ( 275 | 802FE8F91953585F009188E2 /* Debug */, 276 | 802FE8FA1953585F009188E2 /* Release */, 277 | ); 278 | defaultConfigurationIsVisible = 0; 279 | defaultConfigurationName = Release; 280 | }; 281 | /* End XCConfigurationList section */ 282 | }; 283 | rootObject = 802FE8DD1953585F009188E2 /* Project object */; 284 | } 285 | -------------------------------------------------------------------------------- /DebugSearch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DebugSearch.xcodeproj/project.xcworkspace/xcshareddata/DebugSearch.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 0C79D348-55A2-4EAA-91E3-F3925673DD41 9 | IDESourceControlProjectName 10 | project 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 91306CBAB49FB7D655AC9204E1565DD3D1E490C6 14 | https://github.com/maranas/DebugSearch.git 15 | 16 | IDESourceControlProjectPath 17 | DebugSearch.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 91306CBAB49FB7D655AC9204E1565DD3D1E490C6 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/maranas/DebugSearch.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 91306CBAB49FB7D655AC9204E1565DD3D1E490C6 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 91306CBAB49FB7D655AC9204E1565DD3D1E490C6 36 | IDESourceControlWCCName 37 | DebugSearch 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /DebugSearch/DebugSearch-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | 6 | -------------------------------------------------------------------------------- /DebugSearch/DebugSearch-Prefix.pch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maranas/DebugSearch/48c8177c16fc82b72620e2e05f7c294a0625a197/DebugSearch/DebugSearch-Prefix.pch -------------------------------------------------------------------------------- /DebugSearch/DebugSearch.h: -------------------------------------------------------------------------------- 1 | // 2 | // ___VARIABLE_classPrefix:identifier___DebugSearch.h 3 | // ___VARIABLE_classPrefix:identifier___DebugSearch 4 | // 5 | // Created by Moises Anthony Aranas on 6/19/14. 6 | // Copyright (c) 2014 moises. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DebugSearch : NSObject 12 | 13 | @end -------------------------------------------------------------------------------- /DebugSearch/DebugSearch.m: -------------------------------------------------------------------------------- 1 | // 2 | // DebugSearch.m 3 | // DebugSearch 4 | // 5 | // Created by Moises Anthony Aranas on 6/19/14. 6 | // Copyright (c) 2014 moises. All rights reserved. 7 | // 8 | 9 | #import "DebugSearch.h" 10 | #import 11 | 12 | static DebugSearch *sharedPlugin; 13 | static NSString *myFilter; 14 | static NSString *kFilterForDebugSearchChanged = @"kFilterForDebugSearchChanged"; 15 | 16 | static NSString *plistFilename = @"dbgHighlightConf.plist"; 17 | static NSString *plistConfigFolder = @".dbgSearch"; 18 | 19 | static NSDictionary *highlightsDictionary; 20 | 21 | @interface NSTextStorage (DebugSearch) 22 | - (void)dbgSearch_fixAttributesInRange:(NSRange)aRange; 23 | @end 24 | 25 | @implementation NSTextStorage (DebugSearch) 26 | - (void)dbgSearch_fixAttributesInRange:(NSRange)aRange 27 | { 28 | if ([[self string] rangeOfString:@"(lldb)"].location != NSNotFound) // currently debugging 29 | { 30 | [self dbgSearch_fixAttributesInRange:aRange]; 31 | return; 32 | } 33 | BOOL found = NO; 34 | for (NSLayoutManager* item in [self layoutManagers]) { 35 | if ([[item firstTextView] isKindOfClass:NSClassFromString(@"IDEConsoleTextView")]) 36 | { 37 | found = YES; 38 | break; 39 | } 40 | } 41 | if (found) { 42 | NSString *stringToModify = [[self string] substringWithRange:aRange]; 43 | NSArray *components = [stringToModify componentsSeparatedByString:@"\n"]; 44 | NSDictionary *invisibleAttr = @{ 45 | NSFontAttributeName : [NSFont systemFontOfSize:0.001], 46 | NSForegroundColorAttributeName : [NSColor clearColor] 47 | }; 48 | for (NSString* component in components) { 49 | if (![self hasMatchInString:component]) 50 | { 51 | NSRange rangeToDelete = [[self string] rangeOfString:component options:0 range:aRange]; 52 | if (rangeToDelete.location != NSNotFound) { 53 | [self addAttributes:invisibleAttr range:rangeToDelete]; 54 | } 55 | } else if (highlightsDictionary) { 56 | // highlighting 57 | NSString *wantedKey = nil; 58 | for (NSString* key in [highlightsDictionary allKeys]) { 59 | if ([component rangeOfString:key].location != NSNotFound) { 60 | wantedKey = key; 61 | break; 62 | } 63 | } 64 | if (wantedKey) { 65 | NSArray *params = highlightsDictionary[wantedKey]; 66 | NSColor *textColor = [NSColor colorWithCalibratedRed:[params[0] floatValue] green:[params[1] floatValue] blue:[params[2] floatValue] alpha:[params[3] floatValue]]; 67 | NSRange rangeToColor = [[self string] rangeOfString:component options:0 range:aRange]; 68 | [self addAttribute:NSForegroundColorAttributeName value:textColor range:rangeToColor]; 69 | } 70 | } 71 | } 72 | } 73 | [self dbgSearch_fixAttributesInRange:aRange]; 74 | } 75 | 76 | - (BOOL) hasMatchInString:(NSString*)inputString 77 | { 78 | if (myFilter.length == 0) 79 | { 80 | return YES; 81 | } 82 | NSRange range = NSMakeRange(0, [inputString length]); 83 | NSArray *tokenizedComponents = [inputString componentsSeparatedByString:@"] "]; 84 | if (tokenizedComponents.count > 1) 85 | { 86 | range = [inputString rangeOfString:tokenizedComponents[1]]; 87 | } 88 | NSError *error = nil; 89 | NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:myFilter options:0 error:&error]; 90 | NSArray* matches = [regex matchesInString:inputString options:0 range:range]; 91 | return matches.count > 0; 92 | } 93 | 94 | @end 95 | 96 | @interface NSViewController (DebugSearch) 97 | - (void)dbgSearch_loadView; 98 | // associated object 99 | @property (nonatomic, weak) NSTextField *filterText; 100 | // notification observer 101 | - (void)filterChanged; 102 | @end 103 | 104 | @implementation NSViewController (DebugSearch) 105 | - (void)setFilterText:(NSTextField *)filterText 106 | { 107 | // doesn't need to be strong; we add it to a view anyway, which should retain it 108 | objc_setAssociatedObject(self, @selector(filterText), filterText, OBJC_ASSOCIATION_ASSIGN); 109 | } 110 | 111 | - (NSTextField*)filterText 112 | { 113 | return objc_getAssociatedObject(self, @selector(filterText)); 114 | } 115 | 116 | - (void)dbgSearch_loadView 117 | { 118 | [self dbgSearch_loadView]; 119 | if ([self isKindOfClass:NSClassFromString(@"IDEConsoleArea")]) { 120 | NSTextField *filterText; 121 | filterText = [[NSTextField alloc] initWithFrame:CGRectZero]; 122 | filterText.font = [NSFont systemFontOfSize:10.0]; 123 | filterText.autoresizingMask = NSViewWidthSizable | NSViewMinYMargin; 124 | [filterText setStringValue:myFilter]; 125 | filterText.delegate = sharedPlugin; 126 | if (self.view.subviews.count == 1) { 127 | // DVTViewControllers have only one subview in their main view, which is supposed to be the contentView. 128 | NSView *firstSubview = self.view.subviews[0]; 129 | [firstSubview addSubview:filterText]; 130 | filterText.frame = CGRectMake(0, firstSubview.frame.size.height - 20.0, firstSubview.frame.size.width, 20.0); 131 | for (NSView* sview in [firstSubview subviews]) { 132 | if ([sview isKindOfClass:NSClassFromString(@"DVTScrollView")]) { 133 | // move this down! 134 | sview.frame = CGRectMake(sview.frame.origin.x, sview.frame.origin.y, sview.frame.size.width, sview.frame.size.height - 20.0); 135 | } 136 | } 137 | } 138 | self.filterText = filterText; 139 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(filterChanged) name:kFilterForDebugSearchChanged object:nil]; 140 | } 141 | } 142 | 143 | - (void)filterChanged 144 | { 145 | [self.filterText setStringValue:myFilter]; 146 | } 147 | @end 148 | 149 | @interface DebugSearch() 150 | 151 | @property (nonatomic, strong) NSBundle *bundle; 152 | @end 153 | 154 | @implementation DebugSearch 155 | 156 | + (void)pluginDidLoad:(NSBundle *)plugin 157 | { 158 | static dispatch_once_t onceToken; 159 | NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"]; 160 | if ([currentApplicationName isEqual:@"Xcode"]) { 161 | dispatch_once(&onceToken, ^{ 162 | sharedPlugin = [[self alloc] initWithBundle:plugin]; 163 | // load the plist for highlight definitions 164 | // path to plist 165 | NSString *configPath = [[NSHomeDirectory() stringByAppendingPathComponent:plistConfigFolder] stringByAppendingPathComponent:plistFilename]; 166 | NSLog(@"Loading %@", configPath); 167 | if ([[NSFileManager defaultManager] fileExistsAtPath:configPath isDirectory:NO]) { 168 | highlightsDictionary = [NSDictionary dictionaryWithContentsOfFile:configPath]; 169 | if (!highlightsDictionary) { 170 | NSLog(@"There is something wrong with the config plist; skipping load"); 171 | } else { 172 | NSLog(@"Highlighting definitions loaded."); 173 | } 174 | } else { 175 | NSLog(@"No highlighting definitions."); 176 | } 177 | }); 178 | } 179 | } 180 | 181 | - (id)initWithBundle:(NSBundle *)plugin 182 | { 183 | if (self = [super init]) { 184 | // reference to plugin's bundle, for resource acccess 185 | self.bundle = plugin; 186 | myFilter = @""; // no filter initially 187 | [self replaceMethod]; 188 | } 189 | return self; 190 | } 191 | 192 | - (void)replaceMethod 193 | { 194 | [self swizzleMethod:@selector(fixAttributesInRange:) withMethod:@selector(dbgSearch_fixAttributesInRange:) inClass:[NSTextStorage class]]; 195 | // try to replace the viewDidLoad method for the IDEConsoleArea 196 | [self swizzleMethod:@selector(loadView) withMethod:@selector(dbgSearch_loadView) inClass:NSClassFromString(@"IDEConsoleArea")]; 197 | } 198 | 199 | - (void)dealloc 200 | { 201 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 202 | } 203 | 204 | // text field delegate 205 | - (void)controlTextDidChange:(NSNotification *)obj 206 | { 207 | NSLog(@"Filter changed!"); 208 | myFilter = ((NSTextField*)[obj object]).stringValue; 209 | // post a notification 210 | [[NSNotificationCenter defaultCenter] postNotificationName:kFilterForDebugSearchChanged object:nil]; 211 | } 212 | 213 | // swizzler 214 | - (void)swizzleMethod:(SEL)origSel withMethod:(SEL)overSel inClass:(Class)theClass 215 | { 216 | Method orig = class_getInstanceMethod(theClass, origSel); 217 | Method over = class_getInstanceMethod(theClass, overSel); 218 | if (class_addMethod(theClass, origSel, method_getImplementation(over), method_getTypeEncoding(over))) { 219 | class_replaceMethod(theClass, overSel, method_getImplementation(orig), method_getTypeEncoding(orig)); 220 | } else { 221 | method_exchangeImplementations(orig, over); 222 | } 223 | } 224 | 225 | @end 226 | -------------------------------------------------------------------------------- /DebugSearch/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.puter.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundleShortVersionString 16 | 2.1 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 2.1 21 | DVTPlugInCompatibilityUUIDs 22 | 23 | AD68E85B-441B-4301-B564-A45E4919A6AD 24 | 640F884E-CE55-4B40-87C0-8869546CAB7A 25 | 63FC1C47-140D-42B0-BB4D-A10B2D225574 26 | 37B30044-3B14-46BA-ABAA-F01000C27B63 27 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 28 | C4A681B0-4A26-480E-93EC-1218098B9AA0 29 | E969541F-E6F9-4D25-8158-72DC3545A6C6 30 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 31 | 7265231C-39B4-402C-89E1-16167C4CC990 32 | F41BD31E-2683-44B8-AE7F-5F09E919790E 33 | ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C 34 | 35 | NSPrincipalClass 36 | DebugSearch 37 | XC4Compatible 38 | 39 | XC5Compatible 40 | 41 | XCGCReady 42 | 43 | XCPluginHasUI 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DebugSearch for Xcode 2 | ===================== 3 | 4 | Allows filtering of debug output in Xcode, and also per-line highlighting. 5 | 6 | Installation 7 | ============ 8 | Clone, build, then restart Xcode 9 | 10 | Usage 11 | ===== 12 | There will be a text field added on top of your debug console view in the Xcode IDE. Just enter a string there and the output will be filtered accordingly. 13 | 14 | Highlighting 15 | ============ 16 | The plugin can also highlight lines of output. An example configuration file is included in this project’s root directory (dbgHighlightConf.plist). To setup log highlighting: 17 | - create the directory ~/.dbgSearch/ 18 | - copy the file dbgHighlightConf.plist to that directory 19 | 20 | The file is a simple plist that contains a dictionary with strings as keys, and float values for R, G, B and alpha parameters (will be passed to NSColor). E.g. to color messages containing the string "ERROR" with red, your plist will look like this: 21 | 22 | 23 | 24 | ERROR 25 | 26 | 1.0 # red 27 | 0 # green 28 | 0 # blue 29 | 1.0 # alpha 30 | 31 | 32 | 33 | 34 | 35 | Limitations 36 | =========== 37 | - Once a user starts debugging interactively, filters are ignored. 38 | 39 | This plugin uses the XCode plugin project template Copyright (c) 2013 Delisa Mason and contributors 40 | Get it at https://github.com/kattrali/Xcode5-Plugin-Template 41 | 42 | -------------------------------------------------------------------------------- /dbgHighlightConf.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | ERROR 4 | 5 | 1.0 6 | 0 7 | 0 8 | 1.0 9 | 10 | error 11 | 12 | 1.0 13 | 0 14 | 0 15 | 1.0 16 | 17 | Error 18 | 19 | 1.0 20 | 0 21 | 0 22 | 1.0 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------