├── .gitignore ├── DTXcodeUtils.podspec ├── Example ├── .gitignore ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Example.xcworkspace │ └── contents.xcworkspacedata ├── Example │ ├── DTExample.h │ ├── DTExample.m │ ├── Example-Info.plist │ ├── Example-Prefix.pch │ └── en.lproj │ │ └── InfoPlist.strings └── Podfile ├── LICENSE ├── Pod ├── Classes │ ├── .gitkeep │ ├── DTXcodeUtils.h │ └── DTXcodeUtils.m └── XcodeHeaders │ └── DTXcodeHeaders.h ├── README.md └── XcodeHeaders.h /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # We recommend against adding the Pods directory to your .gitignore. However 26 | # you should judge for yourself, the pros and cons are mentioned at: 27 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 28 | # 29 | # Note: if you ignore the Pods directory, make sure to uncomment 30 | # `pod install` in .travis.yml 31 | # 32 | # Pods/ 33 | -------------------------------------------------------------------------------- /DTXcodeUtils.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "DTXcodeUtils" 3 | s.deprecated = true 4 | s.version = "0.1.1" 5 | s.summary = "Useful helper functions for writing Xcode plugins" 6 | s.homepage = "https://github.com/thurn/DTXcodeUtils" 7 | s.license = 'Creative Commons Zero' 8 | s.author = { "Derek Thurn" => "derek@fake.email" } 9 | s.source = { :git => "https://github.com/thurn/DTXcodeUtils.git", :tag => s.version.to_s } 10 | 11 | s.platform = :osx 12 | s.requires_arc = true 13 | 14 | s.source_files = 'Pod/Classes/**/*.{h,m}', 'Pod/XcodeHeaders/**/*.h' 15 | end 16 | -------------------------------------------------------------------------------- /Example/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | .Trashes 4 | *.swp 5 | *.lock 6 | *~.nib 7 | DerivedData/ 8 | build/ 9 | *.pbxuser 10 | *.mode1v3 11 | *.mode2v3 12 | *.perspectivev3 13 | !default.pbxuser 14 | !default.mode1v3 15 | !default.mode2v3 16 | !default.perspectivev3 17 | xcuserdata 18 | *.moved-aside 19 | Pods/ 20 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | archiveVersion 6 | 1 7 | classes 8 | 9 | objectVersion 10 | 46 11 | objects 12 | 13 | 17A62964667C4A58A53684F8 14 | 15 | buildActionMask 16 | 2147483647 17 | files 18 | 19 | inputPaths 20 | 21 | isa 22 | PBXShellScriptBuildPhase 23 | name 24 | Check Pods Manifest.lock 25 | outputPaths 26 | 27 | runOnlyForDeploymentPostprocessing 28 | 0 29 | shellPath 30 | /bin/sh 31 | shellScript 32 | diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null 33 | if [[ $? != 0 ]] ; then 34 | cat << EOM 35 | error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. 36 | EOM 37 | exit 1 38 | fi 39 | 40 | showEnvVarsInLog 41 | 0 42 | 43 | 61BDFE5F61124E5F8218F0EF 44 | 45 | fileRef 46 | F8C7CFACE9CB4A1E842D5907 47 | isa 48 | PBXBuildFile 49 | 50 | 7CD9185919A7B46F00B814F8 51 | 52 | children 53 | 54 | 7CD9186919A7B46F00B814F8 55 | 7CD9186419A7B46F00B814F8 56 | 7CD9186319A7B46F00B814F8 57 | 8137908705E64CAA935259DF 58 | 59 | isa 60 | PBXGroup 61 | sourceTree 62 | <group> 63 | 64 | 7CD9185A19A7B46F00B814F8 65 | 66 | attributes 67 | 68 | CLASSPREFIX 69 | DT 70 | LastUpgradeCheck 71 | 0510 72 | 73 | buildConfigurationList 74 | 7CD9185D19A7B46F00B814F8 75 | compatibilityVersion 76 | Xcode 3.2 77 | developmentRegion 78 | English 79 | hasScannedForEncodings 80 | 0 81 | isa 82 | PBXProject 83 | knownRegions 84 | 85 | en 86 | 87 | mainGroup 88 | 7CD9185919A7B46F00B814F8 89 | productRefGroup 90 | 7CD9186319A7B46F00B814F8 91 | projectDirPath 92 | 93 | projectReferences 94 | 95 | projectRoot 96 | 97 | targets 98 | 99 | 7CD9186119A7B46F00B814F8 100 | 101 | 102 | 7CD9185D19A7B46F00B814F8 103 | 104 | buildConfigurations 105 | 106 | 7CD9187319A7B46F00B814F8 107 | 7CD9187419A7B46F00B814F8 108 | 109 | defaultConfigurationIsVisible 110 | 0 111 | defaultConfigurationName 112 | Release 113 | isa 114 | XCConfigurationList 115 | 116 | 7CD9185E19A7B46F00B814F8 117 | 118 | buildActionMask 119 | 2147483647 120 | files 121 | 122 | 7CD9187119A7B46F00B814F8 123 | 124 | isa 125 | PBXSourcesBuildPhase 126 | runOnlyForDeploymentPostprocessing 127 | 0 128 | 129 | 7CD9185F19A7B46F00B814F8 130 | 131 | buildActionMask 132 | 2147483647 133 | files 134 | 135 | 7CD9186619A7B46F00B814F8 136 | 7CD9186819A7B46F00B814F8 137 | 61BDFE5F61124E5F8218F0EF 138 | 139 | isa 140 | PBXFrameworksBuildPhase 141 | runOnlyForDeploymentPostprocessing 142 | 0 143 | 144 | 7CD9186019A7B46F00B814F8 145 | 146 | buildActionMask 147 | 2147483647 148 | files 149 | 150 | 7CD9186E19A7B46F00B814F8 151 | 152 | isa 153 | PBXResourcesBuildPhase 154 | runOnlyForDeploymentPostprocessing 155 | 0 156 | 157 | 7CD9186119A7B46F00B814F8 158 | 159 | buildConfigurationList 160 | 7CD9187519A7B46F00B814F8 161 | buildPhases 162 | 163 | 17A62964667C4A58A53684F8 164 | 7CD9185E19A7B46F00B814F8 165 | 7CD9185F19A7B46F00B814F8 166 | 7CD9186019A7B46F00B814F8 167 | B5CB82C51FF641CE9A74FAFC 168 | 169 | buildRules 170 | 171 | dependencies 172 | 173 | isa 174 | PBXNativeTarget 175 | name 176 | Example 177 | productName 178 | Example 179 | productReference 180 | 7CD9186219A7B46F00B814F8 181 | productType 182 | com.apple.product-type.bundle 183 | 184 | 7CD9186219A7B46F00B814F8 185 | 186 | explicitFileType 187 | wrapper.cfbundle 188 | includeInIndex 189 | 0 190 | isa 191 | PBXFileReference 192 | path 193 | Example.xcplugin 194 | sourceTree 195 | BUILT_PRODUCTS_DIR 196 | 197 | 7CD9186319A7B46F00B814F8 198 | 199 | children 200 | 201 | 7CD9186219A7B46F00B814F8 202 | 203 | isa 204 | PBXGroup 205 | name 206 | Products 207 | sourceTree 208 | <group> 209 | 210 | 7CD9186419A7B46F00B814F8 211 | 212 | children 213 | 214 | 7CD9186519A7B46F00B814F8 215 | 7CD9186719A7B46F00B814F8 216 | F8C7CFACE9CB4A1E842D5907 217 | 218 | isa 219 | PBXGroup 220 | name 221 | Frameworks 222 | sourceTree 223 | <group> 224 | 225 | 7CD9186519A7B46F00B814F8 226 | 227 | isa 228 | PBXFileReference 229 | lastKnownFileType 230 | wrapper.framework 231 | name 232 | AppKit.framework 233 | path 234 | System/Library/Frameworks/AppKit.framework 235 | sourceTree 236 | SDKROOT 237 | 238 | 7CD9186619A7B46F00B814F8 239 | 240 | fileRef 241 | 7CD9186519A7B46F00B814F8 242 | isa 243 | PBXBuildFile 244 | 245 | 7CD9186719A7B46F00B814F8 246 | 247 | isa 248 | PBXFileReference 249 | lastKnownFileType 250 | wrapper.framework 251 | name 252 | Foundation.framework 253 | path 254 | System/Library/Frameworks/Foundation.framework 255 | sourceTree 256 | SDKROOT 257 | 258 | 7CD9186819A7B46F00B814F8 259 | 260 | fileRef 261 | 7CD9186719A7B46F00B814F8 262 | isa 263 | PBXBuildFile 264 | 265 | 7CD9186919A7B46F00B814F8 266 | 267 | children 268 | 269 | 7CD9186F19A7B46F00B814F8 270 | 7CD9187019A7B46F00B814F8 271 | 7CD9186A19A7B46F00B814F8 272 | 273 | isa 274 | PBXGroup 275 | path 276 | Example 277 | sourceTree 278 | <group> 279 | 280 | 7CD9186A19A7B46F00B814F8 281 | 282 | children 283 | 284 | 7CD9186B19A7B46F00B814F8 285 | 7CD9186C19A7B46F00B814F8 286 | 7CD9187219A7B46F00B814F8 287 | 288 | isa 289 | PBXGroup 290 | name 291 | Supporting Files 292 | sourceTree 293 | <group> 294 | 295 | 7CD9186B19A7B46F00B814F8 296 | 297 | isa 298 | PBXFileReference 299 | lastKnownFileType 300 | text.plist.xml 301 | path 302 | Example-Info.plist 303 | sourceTree 304 | <group> 305 | 306 | 7CD9186C19A7B46F00B814F8 307 | 308 | children 309 | 310 | 7CD9186D19A7B46F00B814F8 311 | 312 | isa 313 | PBXVariantGroup 314 | name 315 | InfoPlist.strings 316 | sourceTree 317 | <group> 318 | 319 | 7CD9186D19A7B46F00B814F8 320 | 321 | isa 322 | PBXFileReference 323 | lastKnownFileType 324 | text.plist.strings 325 | name 326 | en 327 | path 328 | en.lproj/InfoPlist.strings 329 | sourceTree 330 | <group> 331 | 332 | 7CD9186E19A7B46F00B814F8 333 | 334 | fileRef 335 | 7CD9186C19A7B46F00B814F8 336 | isa 337 | PBXBuildFile 338 | 339 | 7CD9186F19A7B46F00B814F8 340 | 341 | isa 342 | PBXFileReference 343 | lastKnownFileType 344 | sourcecode.c.h 345 | path 346 | DTExample.h 347 | sourceTree 348 | <group> 349 | 350 | 7CD9187019A7B46F00B814F8 351 | 352 | isa 353 | PBXFileReference 354 | lastKnownFileType 355 | sourcecode.c.objc 356 | path 357 | DTExample.m 358 | sourceTree 359 | <group> 360 | 361 | 7CD9187119A7B46F00B814F8 362 | 363 | fileRef 364 | 7CD9187019A7B46F00B814F8 365 | isa 366 | PBXBuildFile 367 | 368 | 7CD9187219A7B46F00B814F8 369 | 370 | isa 371 | PBXFileReference 372 | lastKnownFileType 373 | sourcecode.c.h 374 | path 375 | Example-Prefix.pch 376 | sourceTree 377 | <group> 378 | 379 | 7CD9187319A7B46F00B814F8 380 | 381 | buildSettings 382 | 383 | ALWAYS_SEARCH_USER_PATHS 384 | NO 385 | CLANG_CXX_LANGUAGE_STANDARD 386 | gnu++0x 387 | CLANG_CXX_LIBRARY 388 | libc++ 389 | CLANG_ENABLE_MODULES 390 | YES 391 | CLANG_ENABLE_OBJC_ARC 392 | YES 393 | CLANG_WARN_BOOL_CONVERSION 394 | YES 395 | CLANG_WARN_CONSTANT_CONVERSION 396 | YES 397 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE 398 | YES_ERROR 399 | CLANG_WARN_EMPTY_BODY 400 | YES 401 | CLANG_WARN_ENUM_CONVERSION 402 | YES 403 | CLANG_WARN_INT_CONVERSION 404 | YES 405 | CLANG_WARN_OBJC_ROOT_CLASS 406 | YES_ERROR 407 | CLANG_WARN__DUPLICATE_METHOD_MATCH 408 | YES 409 | COPY_PHASE_STRIP 410 | NO 411 | GCC_C_LANGUAGE_STANDARD 412 | gnu99 413 | GCC_DYNAMIC_NO_PIC 414 | NO 415 | GCC_ENABLE_OBJC_EXCEPTIONS 416 | YES 417 | GCC_OPTIMIZATION_LEVEL 418 | 0 419 | GCC_PREPROCESSOR_DEFINITIONS 420 | 421 | DEBUG=1 422 | $(inherited) 423 | 424 | GCC_SYMBOLS_PRIVATE_EXTERN 425 | NO 426 | GCC_WARN_64_TO_32_BIT_CONVERSION 427 | YES 428 | GCC_WARN_ABOUT_RETURN_TYPE 429 | YES_ERROR 430 | GCC_WARN_UNDECLARED_SELECTOR 431 | YES 432 | GCC_WARN_UNINITIALIZED_AUTOS 433 | YES_AGGRESSIVE 434 | GCC_WARN_UNUSED_FUNCTION 435 | YES 436 | GCC_WARN_UNUSED_VARIABLE 437 | YES 438 | MACOSX_DEPLOYMENT_TARGET 439 | 10.9 440 | ONLY_ACTIVE_ARCH 441 | YES 442 | SDKROOT 443 | macosx 444 | 445 | isa 446 | XCBuildConfiguration 447 | name 448 | Debug 449 | 450 | 7CD9187419A7B46F00B814F8 451 | 452 | buildSettings 453 | 454 | ALWAYS_SEARCH_USER_PATHS 455 | NO 456 | CLANG_CXX_LANGUAGE_STANDARD 457 | gnu++0x 458 | CLANG_CXX_LIBRARY 459 | libc++ 460 | CLANG_ENABLE_MODULES 461 | YES 462 | CLANG_ENABLE_OBJC_ARC 463 | YES 464 | CLANG_WARN_BOOL_CONVERSION 465 | YES 466 | CLANG_WARN_CONSTANT_CONVERSION 467 | YES 468 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE 469 | YES_ERROR 470 | CLANG_WARN_EMPTY_BODY 471 | YES 472 | CLANG_WARN_ENUM_CONVERSION 473 | YES 474 | CLANG_WARN_INT_CONVERSION 475 | YES 476 | CLANG_WARN_OBJC_ROOT_CLASS 477 | YES_ERROR 478 | CLANG_WARN__DUPLICATE_METHOD_MATCH 479 | YES 480 | COPY_PHASE_STRIP 481 | YES 482 | DEBUG_INFORMATION_FORMAT 483 | dwarf-with-dsym 484 | ENABLE_NS_ASSERTIONS 485 | NO 486 | GCC_C_LANGUAGE_STANDARD 487 | gnu99 488 | GCC_ENABLE_OBJC_EXCEPTIONS 489 | YES 490 | GCC_WARN_64_TO_32_BIT_CONVERSION 491 | YES 492 | GCC_WARN_ABOUT_RETURN_TYPE 493 | YES_ERROR 494 | GCC_WARN_UNDECLARED_SELECTOR 495 | YES 496 | GCC_WARN_UNINITIALIZED_AUTOS 497 | YES_AGGRESSIVE 498 | GCC_WARN_UNUSED_FUNCTION 499 | YES 500 | GCC_WARN_UNUSED_VARIABLE 501 | YES 502 | MACOSX_DEPLOYMENT_TARGET 503 | 10.9 504 | SDKROOT 505 | macosx 506 | 507 | isa 508 | XCBuildConfiguration 509 | name 510 | Release 511 | 512 | 7CD9187519A7B46F00B814F8 513 | 514 | buildConfigurations 515 | 516 | 7CD9187619A7B46F00B814F8 517 | 7CD9187719A7B46F00B814F8 518 | 519 | defaultConfigurationIsVisible 520 | 0 521 | isa 522 | XCConfigurationList 523 | 524 | 7CD9187619A7B46F00B814F8 525 | 526 | baseConfigurationReference 527 | 8137908705E64CAA935259DF 528 | buildSettings 529 | 530 | COMBINE_HIDPI_IMAGES 531 | YES 532 | DEPLOYMENT_LOCATION 533 | YES 534 | DSTROOT 535 | $(HOME) 536 | GCC_PRECOMPILE_PREFIX_HEADER 537 | YES 538 | GCC_PREFIX_HEADER 539 | Example/Example-Prefix.pch 540 | INFOPLIST_FILE 541 | Example/Example-Info.plist 542 | INSTALL_PATH 543 | /Library/Application Support/Developer/Shared/Xcode/Plug-ins 544 | PRODUCT_NAME 545 | $(TARGET_NAME) 546 | WRAPPER_EXTENSION 547 | xcplugin 548 | 549 | isa 550 | XCBuildConfiguration 551 | name 552 | Debug 553 | 554 | 7CD9187719A7B46F00B814F8 555 | 556 | baseConfigurationReference 557 | 8137908705E64CAA935259DF 558 | buildSettings 559 | 560 | COMBINE_HIDPI_IMAGES 561 | YES 562 | DEPLOYMENT_LOCATION 563 | YES 564 | DSTROOT 565 | $(HOME) 566 | GCC_PRECOMPILE_PREFIX_HEADER 567 | YES 568 | GCC_PREFIX_HEADER 569 | Example/Example-Prefix.pch 570 | INFOPLIST_FILE 571 | Example/Example-Info.plist 572 | INSTALL_PATH 573 | /Library/Application Support/Developer/Shared/Xcode/Plug-ins 574 | PRODUCT_NAME 575 | $(TARGET_NAME) 576 | WRAPPER_EXTENSION 577 | xcplugin 578 | 579 | isa 580 | XCBuildConfiguration 581 | name 582 | Release 583 | 584 | 8137908705E64CAA935259DF 585 | 586 | includeInIndex 587 | 1 588 | isa 589 | PBXFileReference 590 | lastKnownFileType 591 | text.xcconfig 592 | name 593 | Pods-Example.xcconfig 594 | path 595 | Pods/Pods-Example.xcconfig 596 | sourceTree 597 | <group> 598 | 599 | B5CB82C51FF641CE9A74FAFC 600 | 601 | buildActionMask 602 | 2147483647 603 | files 604 | 605 | inputPaths 606 | 607 | isa 608 | PBXShellScriptBuildPhase 609 | name 610 | Copy Pods Resources 611 | outputPaths 612 | 613 | runOnlyForDeploymentPostprocessing 614 | 0 615 | shellPath 616 | /bin/sh 617 | shellScript 618 | "${SRCROOT}/Pods/Pods-Example-resources.sh" 619 | 620 | showEnvVarsInLog 621 | 0 622 | 623 | F8C7CFACE9CB4A1E842D5907 624 | 625 | explicitFileType 626 | archive.ar 627 | includeInIndex 628 | 0 629 | isa 630 | PBXFileReference 631 | path 632 | libPods-Example.a 633 | sourceTree 634 | BUILT_PRODUCTS_DIR 635 | 636 | 637 | rootObject 638 | 7CD9185A19A7B46F00B814F8 639 | 640 | 641 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Example/DTExample.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface DTExample : NSObject 4 | 5 | @end -------------------------------------------------------------------------------- /Example/Example/DTExample.m: -------------------------------------------------------------------------------- 1 | #import "DTExample.h" 2 | 3 | #import "DTXcodeHeaders.h" 4 | #import "DTXcodeUtils.h" 5 | 6 | static DTExample *sharedPlugin; 7 | 8 | @interface DTExample() 9 | @property (nonatomic) BOOL highlightingEnabled; 10 | @property (nonatomic, strong) NSBundle *bundle; 11 | @end 12 | 13 | @implementation DTExample 14 | 15 | + (void)pluginDidLoad:(NSBundle *)plugin { 16 | static dispatch_once_t onceToken; 17 | NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"]; 18 | if ([currentApplicationName isEqual:@"Xcode"]) { 19 | dispatch_once(&onceToken, ^{ sharedPlugin = [[self alloc] initWithBundle:plugin]; }); 20 | } 21 | } 22 | 23 | - (id)initWithBundle:(NSBundle *)plugin { 24 | if (self = [super init]) { 25 | _bundle = plugin; 26 | _highlightingEnabled = YES; 27 | NSMenuItem *menuItem = [DTXcodeUtils getMainMenuItemWithTitle:@"Edit"]; 28 | if (menuItem) { 29 | [[menuItem submenu] addItem:[NSMenuItem separatorItem]]; 30 | NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"Toggle Highlighting" 31 | action:@selector(doMenuAction) 32 | keyEquivalent:@""]; 33 | [actionMenuItem setTarget:self]; 34 | [[menuItem submenu] addItem:actionMenuItem]; 35 | } 36 | } 37 | return self; 38 | } 39 | 40 | - (void)doMenuAction { 41 | DVTTextStorage *storage = [DTXcodeUtils currentTextStorage]; 42 | _highlightingEnabled = !_highlightingEnabled; 43 | storage.syntaxColoringEnabled = _highlightingEnabled; 44 | DVTSourceTextView *textView = [DTXcodeUtils currentSourceTextView]; 45 | [textView setNeedsDisplay:YES]; 46 | } 47 | 48 | - (void)dealloc { 49 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Example/Example/Example-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.example.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | DVTPlugInCompatibilityUUIDs 26 | 27 | 640F884E-CE55-4B40-87C0-8869546CAB7A 28 | 37B30044-3B14-46BA-ABAA-F01000C27B63 29 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 30 | 31 | NSPrincipalClass 32 | DTExample 33 | XC4Compatible 34 | 35 | XC5Compatible 36 | 37 | XCGCReady 38 | 39 | XCPluginHasUI 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/Example/Example-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /Example/Example/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx 2 | 3 | target "Example" do 4 | pod "DTXcodeUtils", :path => "../" 5 | end 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Except where otherwise noted, all files are released under the 2 | Creative Commons Zero license: 3 | 4 | CC0 1.0 Universal 5 | 6 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 7 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 8 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 9 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 10 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 11 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 12 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 13 | HEREUNDER. 14 | 15 | Statement of Purpose 16 | 17 | The laws of most jurisdictions throughout the world automatically confer 18 | exclusive Copyright and Related Rights (defined below) upon the creator 19 | and subsequent owner(s) (each and all, an "owner") of an original work of 20 | authorship and/or a database (each, a "Work"). 21 | 22 | Certain owners wish to permanently relinquish those rights to a Work for 23 | the purpose of contributing to a commons of creative, cultural and 24 | scientific works ("Commons") that the public can reliably and without fear 25 | of later claims of infringement build upon, modify, incorporate in other 26 | works, reuse and redistribute as freely as possible in any form whatsoever 27 | and for any purposes, including without limitation commercial purposes. 28 | These owners may contribute to the Commons to promote the ideal of a free 29 | culture and the further production of creative, cultural and scientific 30 | works, or to gain reputation or greater distribution for their Work in 31 | part through the use and efforts of others. 32 | 33 | For these and/or other purposes and motivations, and without any 34 | expectation of additional consideration or compensation, the person 35 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 36 | is an owner of Copyright and Related Rights in the Work, voluntarily 37 | elects to apply CC0 to the Work and publicly distribute the Work under its 38 | terms, with knowledge of his or her Copyright and Related Rights in the 39 | Work and the meaning and intended legal effect of CC0 on those rights. 40 | 41 | 1. Copyright and Related Rights. A Work made available under CC0 may be 42 | protected by copyright and related or neighboring rights ("Copyright and 43 | Related Rights"). Copyright and Related Rights include, but are not 44 | limited to, the following: 45 | 46 | i. the right to reproduce, adapt, distribute, perform, display, 47 | communicate, and translate a Work; 48 | ii. moral rights retained by the original author(s) and/or performer(s); 49 | iii. publicity and privacy rights pertaining to a person's image or 50 | likeness depicted in a Work; 51 | iv. rights protecting against unfair competition in regards to a Work, 52 | subject to the limitations in paragraph 4(a), below; 53 | v. rights protecting the extraction, dissemination, use and reuse of data 54 | in a Work; 55 | vi. database rights (such as those arising under Directive 96/9/EC of the 56 | European Parliament and of the Council of 11 March 1996 on the legal 57 | protection of databases, and under any national implementation 58 | thereof, including any amended or successor version of such 59 | directive); and 60 | vii. other similar, equivalent or corresponding rights throughout the 61 | world based on applicable law or treaty, and any national 62 | implementations thereof. 63 | 64 | 2. Waiver. To the greatest extent permitted by, but not in contravention 65 | of, applicable law, Affirmer hereby overtly, fully, permanently, 66 | irrevocably and unconditionally waives, abandons, and surrenders all of 67 | Affirmer's Copyright and Related Rights and associated claims and causes 68 | of action, whether now known or unknown (including existing as well as 69 | future claims and causes of action), in the Work (i) in all territories 70 | worldwide, (ii) for the maximum duration provided by applicable law or 71 | treaty (including future time extensions), (iii) in any current or future 72 | medium and for any number of copies, and (iv) for any purpose whatsoever, 73 | including without limitation commercial, advertising or promotional 74 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 75 | member of the public at large and to the detriment of Affirmer's heirs and 76 | successors, fully intending that such Waiver shall not be subject to 77 | revocation, rescission, cancellation, termination, or any other legal or 78 | equitable action to disrupt the quiet enjoyment of the Work by the public 79 | as contemplated by Affirmer's express Statement of Purpose. 80 | 81 | 3. Public License Fallback. Should any part of the Waiver for any reason 82 | be judged legally invalid or ineffective under applicable law, then the 83 | Waiver shall be preserved to the maximum extent permitted taking into 84 | account Affirmer's express Statement of Purpose. In addition, to the 85 | extent the Waiver is so judged Affirmer hereby grants to each affected 86 | person a royalty-free, non transferable, non sublicensable, non exclusive, 87 | irrevocable and unconditional license to exercise Affirmer's Copyright and 88 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 89 | maximum duration provided by applicable law or treaty (including future 90 | time extensions), (iii) in any current or future medium and for any number 91 | of copies, and (iv) for any purpose whatsoever, including without 92 | limitation commercial, advertising or promotional purposes (the 93 | "License"). The License shall be deemed effective as of the date CC0 was 94 | applied by Affirmer to the Work. Should any part of the License for any 95 | reason be judged legally invalid or ineffective under applicable law, such 96 | partial invalidity or ineffectiveness shall not invalidate the remainder 97 | of the License, and in such case Affirmer hereby affirms that he or she 98 | will not (i) exercise any of his or her remaining Copyright and Related 99 | Rights in the Work or (ii) assert any associated claims and causes of 100 | action with respect to the Work, in either case contrary to Affirmer's 101 | express Statement of Purpose. 102 | 103 | 4. Limitations and Disclaimers. 104 | 105 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 106 | surrendered, licensed or otherwise affected by this document. 107 | b. Affirmer offers the Work as-is and makes no representations or 108 | warranties of any kind concerning the Work, express, implied, 109 | statutory or otherwise, including without limitation warranties of 110 | title, merchantability, fitness for a particular purpose, non 111 | infringement, or the absence of latent or other defects, accuracy, or 112 | the present or absence of errors, whether or not discoverable, all to 113 | the greatest extent permissible under applicable law. 114 | c. Affirmer disclaims responsibility for clearing rights of other persons 115 | that may apply to the Work or any use thereof, including without 116 | limitation any person's Copyright and Related Rights in the Work. 117 | Further, Affirmer disclaims responsibility for obtaining any necessary 118 | consents, permissions or other rights required for any use of the 119 | Work. 120 | d. Affirmer understands and acknowledges that Creative Commons is not a 121 | party to this document and has no duty or obligation with respect to 122 | this CC0 or use of the Work. 123 | -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thurn/DTXcodeUtils/4082cfa5a6f985424904aef416d3a871b9da04b5/Pod/Classes/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/DTXcodeUtils.h: -------------------------------------------------------------------------------- 1 | @class DVTSourceTextView; 2 | @class DVTTextStorage; 3 | @class IDEEditor; 4 | @class IDEEditorArea; 5 | @class IDESourceCodeDocument; 6 | @class IDEEditorContext; 7 | @class IDEWorkspaceWindowController; 8 | 9 | @interface DTXcodeUtils : NSObject 10 | + (NSWindow *)currentWindow; 11 | + (NSResponder *)currentWindowResponder; 12 | + (NSMenu *)mainMenu; 13 | + (IDEWorkspaceWindowController *)currentWorkspaceWindowController; 14 | + (IDEEditorArea *)currentEditorArea; 15 | + (IDEEditorContext *)currentEditorContext; 16 | + (IDEEditor *)currentEditor; 17 | + (IDESourceCodeDocument *)currentSourceCodeDocument; 18 | + (DVTSourceTextView *)currentSourceTextView; 19 | + (DVTTextStorage *)currentTextStorage; 20 | + (NSScrollView *)currentScrollView; 21 | 22 | + (NSMenuItem *)getMainMenuItemWithTitle:(NSString *)title; 23 | @end 24 | -------------------------------------------------------------------------------- /Pod/Classes/DTXcodeUtils.m: -------------------------------------------------------------------------------- 1 | #import "DTXcodeUtils.h" 2 | 3 | #import "DTXcodeHeaders.h" 4 | 5 | @implementation DTXcodeUtils 6 | 7 | + (NSWindow *)currentWindow { 8 | return [[NSApplication sharedApplication] keyWindow]; 9 | } 10 | 11 | + (NSResponder *)currentWindowResponder { 12 | return [[self currentWindow] firstResponder]; 13 | } 14 | 15 | + (NSMenu *)mainMenu { 16 | return [NSApp mainMenu]; 17 | } 18 | 19 | + (NSMenuItem *)getMainMenuItemWithTitle:(NSString *)title { 20 | return [[self mainMenu] itemWithTitle:title]; 21 | } 22 | 23 | + (IDEWorkspaceWindowController *)currentWorkspaceWindowController { 24 | NSLog(@"getting window controller"); 25 | NSWindowController *result = [self currentWindow].windowController; 26 | if ([result isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) { 27 | return (IDEWorkspaceWindowController *)result; 28 | } 29 | return nil; 30 | } 31 | 32 | + (IDEEditorArea *)currentEditorArea { 33 | return [self currentWorkspaceWindowController].editorArea; 34 | } 35 | 36 | + (IDEEditorContext *)currentEditorContext { 37 | return [self currentEditorArea].lastActiveEditorContext; 38 | } 39 | 40 | + (IDEEditor *)currentEditor { 41 | return [self currentEditorContext].editor; 42 | } 43 | 44 | + (IDESourceCodeDocument *)currentSourceCodeDocument { 45 | if ([[self currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) { 46 | return ((IDESourceCodeEditor *)[self currentEditor]).sourceCodeDocument; 47 | } else if ([[self currentEditor] isKindOfClass: 48 | NSClassFromString(@"IDESourceCodeComparisonEditor")]) { 49 | IDEEditorDocument *document = 50 | ((IDESourceCodeComparisonEditor *)[self currentEditor]).primaryDocument; 51 | if ([document isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) { 52 | return (IDESourceCodeDocument *)document; 53 | } 54 | } 55 | return nil; 56 | } 57 | 58 | + (DVTSourceTextView *)currentSourceTextView { 59 | if ([[self currentEditor] isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) { 60 | return ((IDESourceCodeEditor *)[self currentEditor]).textView; 61 | } else if ([[self currentEditor] isKindOfClass: 62 | NSClassFromString(@"IDESourceCodeComparisonEditor")]) { 63 | return ((IDESourceCodeComparisonEditor *)[self currentEditor]).keyTextView; 64 | } 65 | return nil; 66 | } 67 | 68 | + (DVTTextStorage *)currentTextStorage { 69 | NSTextView *textView = [self currentSourceTextView]; 70 | if ([textView.textStorage isKindOfClass:NSClassFromString(@"DVTTextStorage")]) { 71 | return (DVTTextStorage *)textView.textStorage; 72 | } 73 | return nil; 74 | } 75 | 76 | + (NSScrollView *)currentScrollView { 77 | NSView *view = [self currentSourceTextView]; 78 | return [view enclosingScrollView]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Pod/XcodeHeaders/DTXcodeHeaders.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | @interface DVTTextStorage : NSTextStorage 4 | /** Whether to syntax highlight the current editor */ 5 | @property(getter=isSyntaxColoringEnabled) BOOL syntaxColoringEnabled; 6 | 7 | /** Converts from a character number in the text to a line number */ 8 | - (NSRange)lineRangeForCharacterRange:(NSRange)characterRange; 9 | 10 | /** Converts from a line number in the text to a character number */ 11 | - (NSRange)characterRangeForLineRange:(NSRange)lineRange; 12 | @end 13 | 14 | @interface DVTCompletingTextView : NSTextView 15 | @end 16 | 17 | @interface DVTSourceTextView : DVTCompletingTextView 18 | @end 19 | 20 | @interface DVTViewController : NSViewController 21 | @end 22 | 23 | @interface IDEViewController : DVTViewController 24 | @end 25 | 26 | @class IDEEditorContext; 27 | @interface IDEEditorArea : IDEViewController 28 | @property(retain, nonatomic) IDEEditorContext *lastActiveEditorContext; 29 | @end 30 | 31 | @interface IDEEditor : IDEViewController 32 | @end 33 | 34 | @interface IDEEditorContext : IDEViewController 35 | @property(retain, nonatomic) IDEEditor *editor; 36 | @property(retain, nonatomic) IDEEditorArea *editorArea; 37 | @end 38 | 39 | @interface IDEEditorDocument : NSDocument 40 | @end 41 | 42 | @interface IDESourceCodeDocument : IDEEditorDocument 43 | @end 44 | 45 | @interface IDESourceCodeEditor : IDEEditor 46 | @property(readonly) IDESourceCodeDocument *sourceCodeDocument; 47 | @property(retain) DVTSourceTextView *textView; 48 | @end 49 | 50 | @interface IDEComparisonEditor : IDEEditor 51 | @property(retain) IDEEditorDocument *secondaryDocument; 52 | @property(retain) IDEEditorDocument *primaryDocument; 53 | @end 54 | 55 | @interface IDESourceCodeComparisonEditor : IDEComparisonEditor 56 | @property(readonly) DVTSourceTextView *keyTextView; 57 | @end 58 | 59 | @interface IDEWorkspaceWindowController : NSWindowController 60 | @property(readonly) IDEEditorArea *editorArea; 61 | @end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DTXcodeUtils 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/DTXcodeUtils.svg?style=flat)](http://cocoadocs.org/docsets/DTXcodeUtils) 4 | [![License](https://img.shields.io/cocoapods/l/DTXcodeUtils.svg?style=flat)](http://cocoadocs.org/docsets/DTXcodeUtils) 5 | [![Platform](https://img.shields.io/cocoapods/p/DTXcodeUtils.svg?style=flat)](http://cocoadocs.org/docsets/DTXcodeUtils) 6 | 7 | ## Usage 8 | 9 | This is a collection of useful helper functions I am developing to make writing Xcode plugins easier. They 10 | provide access to various parts of Xcode internals by calling into Xcode's private APIs. 11 | 12 | An example of how to use the library is included in the Example directory. This shows how to make a simple 13 | plugin which toggles Xcode's syntax highlighting on or off. 14 | 15 | To run the example project, clone the repo, and run `pod install` from the Example directory. Open the resulting 16 | xcworkspace in Xcode and run the Example target. This should install the example plugin in the IDE. After 17 | restarting Xcode, you should get a "Toggle Highlighting" option in the Xcode Edit menu. 18 | 19 | ## Installation 20 | 21 | DTXcodeUtils is available through [CocoaPods](http://cocoapods.org). To install 22 | it, simply add the following line to your Podfile: 23 | 24 | pod "DTXcodeUtils" 25 | 26 | ## License 27 | 28 | DTXcodeUtils is available under the Creative Commons Zero license. See the LICENSE file for more info. 29 | -------------------------------------------------------------------------------- /XcodeHeaders.h: -------------------------------------------------------------------------------- 1 | // 2 | // XcodeHeaders.h 3 | // Pods 4 | // 5 | // Created by Derek Thurn on 8/25/14. 6 | // 7 | // 8 | 9 | #ifndef Pods_XcodeHeaders_h 10 | #define Pods_XcodeHeaders_h 11 | 12 | 13 | 14 | #endif 15 | --------------------------------------------------------------------------------