├── .clang-format ├── .gitignore ├── ClangFormat.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── ClangFormat.xcscheme ├── ClangFormat ├── ClangFormat-Info.plist ├── ClangFormat-Prefix.pch ├── NSDocument+TRVSClangFormat.h ├── NSDocument+TRVSClangFormat.m ├── TRVSClangFormat.h ├── TRVSClangFormat.m ├── TRVSCodeFragment.h ├── TRVSCodeFragment.m ├── TRVSFormatter.h ├── TRVSFormatter.m ├── TRVSPreferences.h ├── TRVSPreferences.m ├── TRVSXcode.h ├── TRVSXcode.m └── en.lproj │ └── InfoPlist.strings ├── LICENSE ├── README.md ├── README ├── assign-keyboard-shortcut.png ├── clangformat-xcode-demo.gif └── usage.png └── bin └── clang-format /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Chromium 3 | PointerBindsToType: false 4 | ObjCSpaceAfterProperty: true 5 | SortIncludes: false 6 | ... 7 | -------------------------------------------------------------------------------- /.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 | project.xcworkspace 22 | 23 | # CocoaPods 24 | Pods -------------------------------------------------------------------------------- /ClangFormat.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 320B996E187C1293003DB7B3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 320B996D187C1293003DB7B3 /* Cocoa.framework */; }; 11 | 3228E445187F200D0037DECF /* TRVSCodeFragment.m in Sources */ = {isa = PBXBuildFile; fileRef = 3228E444187F200D0037DECF /* TRVSCodeFragment.m */; }; 12 | 32A57EE8187C05A4002DEC9D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32A57EE7187C05A4002DEC9D /* Foundation.framework */; }; 13 | 32A57EEE187C05A4002DEC9D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 32A57EEC187C05A4002DEC9D /* InfoPlist.strings */; }; 14 | 32A57EF1187C05A4002DEC9D /* TRVSClangFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 32A57EF0187C05A4002DEC9D /* TRVSClangFormat.m */; }; 15 | 32ABEDCA187EF90500D4E980 /* TRVSXcode.m in Sources */ = {isa = PBXBuildFile; fileRef = 32ABEDC9187EF90500D4E980 /* TRVSXcode.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 16 | 32ABEDD0187EF98400D4E980 /* DVTFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32ABEDCE187EF98400D4E980 /* DVTFoundation.framework */; }; 17 | 32ABEDD1187EF98400D4E980 /* DVTKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32ABEDCF187EF98400D4E980 /* DVTKit.framework */; }; 18 | 32ABEDD4187EF9A600D4E980 /* IDEFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32ABEDD2187EF9A600D4E980 /* IDEFoundation.framework */; }; 19 | 32ABEDD5187EF9A600D4E980 /* IDEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 32ABEDD3187EF9A600D4E980 /* IDEKit.framework */; }; 20 | 32ABEDDC187EFA4F00D4E980 /* TRVSFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 32ABEDD9187EFA4F00D4E980 /* TRVSFormatter.m */; }; 21 | 32ABEDDD187EFA4F00D4E980 /* TRVSPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 32ABEDDB187EFA4F00D4E980 /* TRVSPreferences.m */; }; 22 | 32D2236C187C28E1008D12A3 /* clang-format in Resources */ = {isa = PBXBuildFile; fileRef = 32D2236B187C28E1008D12A3 /* clang-format */; }; 23 | 32F745E418823A57007541E1 /* NSDocument+TRVSClangFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F745E318823A57007541E1 /* NSDocument+TRVSClangFormat.m */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 320B996D187C1293003DB7B3 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 28 | 3228E443187F200D0037DECF /* TRVSCodeFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRVSCodeFragment.h; sourceTree = ""; }; 29 | 3228E444187F200D0037DECF /* TRVSCodeFragment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRVSCodeFragment.m; sourceTree = ""; }; 30 | 32A57EE2187C05A4002DEC9D /* ClangFormat.xcplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ClangFormat.xcplugin; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 32A57EE5187C05A4002DEC9D /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 32 | 32A57EE7187C05A4002DEC9D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 33 | 32A57EEB187C05A4002DEC9D /* ClangFormat-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ClangFormat-Info.plist"; sourceTree = ""; }; 34 | 32A57EED187C05A4002DEC9D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 35 | 32A57EEF187C05A4002DEC9D /* TRVSClangFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TRVSClangFormat.h; sourceTree = ""; }; 36 | 32A57EF0187C05A4002DEC9D /* TRVSClangFormat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TRVSClangFormat.m; sourceTree = ""; }; 37 | 32A57EF2187C05A4002DEC9D /* ClangFormat-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ClangFormat-Prefix.pch"; sourceTree = ""; }; 38 | 32ABEDC8187EF90500D4E980 /* TRVSXcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRVSXcode.h; sourceTree = ""; }; 39 | 32ABEDC9187EF90500D4E980 /* TRVSXcode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRVSXcode.m; sourceTree = ""; }; 40 | 32ABEDCE187EF98400D4E980 /* DVTFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVTFoundation.framework; path = ../../../../../Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework; sourceTree = ""; }; 41 | 32ABEDCF187EF98400D4E980 /* DVTKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVTKit.framework; path = ../../../../../Applications/Xcode.app/Contents/SharedFrameworks/DVTKit.framework; sourceTree = ""; }; 42 | 32ABEDD2187EF9A600D4E980 /* IDEFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IDEFoundation.framework; path = ../../../../../Applications/Xcode.app/Contents/Frameworks/IDEFoundation.framework; sourceTree = ""; }; 43 | 32ABEDD3187EF9A600D4E980 /* IDEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IDEKit.framework; path = ../../../../../Applications/Xcode.app/Contents/Frameworks/IDEKit.framework; sourceTree = ""; }; 44 | 32ABEDD8187EFA4F00D4E980 /* TRVSFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRVSFormatter.h; sourceTree = ""; }; 45 | 32ABEDD9187EFA4F00D4E980 /* TRVSFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRVSFormatter.m; sourceTree = ""; }; 46 | 32ABEDDA187EFA4F00D4E980 /* TRVSPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TRVSPreferences.h; sourceTree = ""; }; 47 | 32ABEDDB187EFA4F00D4E980 /* TRVSPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TRVSPreferences.m; sourceTree = ""; }; 48 | 32D22368187C28DC008D12A3 /* ClangFormat.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = ClangFormat.xcodeproj; sourceTree = SOURCE_ROOT; }; 49 | 32D2236B187C28E1008D12A3 /* clang-format */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = "clang-format"; path = "bin/clang-format"; sourceTree = SOURCE_ROOT; }; 50 | 32F745E218823A57007541E1 /* NSDocument+TRVSClangFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDocument+TRVSClangFormat.h"; sourceTree = ""; }; 51 | 32F745E318823A57007541E1 /* NSDocument+TRVSClangFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDocument+TRVSClangFormat.m"; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 32A57EDF187C05A4002DEC9D /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 320B996E187C1293003DB7B3 /* Cocoa.framework in Frameworks */, 60 | 32A57EE8187C05A4002DEC9D /* Foundation.framework in Frameworks */, 61 | 32ABEDD4187EF9A600D4E980 /* IDEFoundation.framework in Frameworks */, 62 | 32ABEDD5187EF9A600D4E980 /* IDEKit.framework in Frameworks */, 63 | 32ABEDD0187EF98400D4E980 /* DVTFoundation.framework in Frameworks */, 64 | 32ABEDD1187EF98400D4E980 /* DVTKit.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 32A57ED9187C05A4002DEC9D = { 72 | isa = PBXGroup; 73 | children = ( 74 | 32A57EE9187C05A4002DEC9D /* ClangFormat */, 75 | 32A57EE4187C05A4002DEC9D /* Frameworks */, 76 | 32A57EE3187C05A4002DEC9D /* Products */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 32A57EE3187C05A4002DEC9D /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 32A57EE2187C05A4002DEC9D /* ClangFormat.xcplugin */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 32A57EE4187C05A4002DEC9D /* Frameworks */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 32ABEDD2187EF9A600D4E980 /* IDEFoundation.framework */, 92 | 32ABEDD3187EF9A600D4E980 /* IDEKit.framework */, 93 | 32ABEDCE187EF98400D4E980 /* DVTFoundation.framework */, 94 | 32ABEDCF187EF98400D4E980 /* DVTKit.framework */, 95 | 320B996D187C1293003DB7B3 /* Cocoa.framework */, 96 | 32A57EE5187C05A4002DEC9D /* AppKit.framework */, 97 | 32A57EE7187C05A4002DEC9D /* Foundation.framework */, 98 | ); 99 | name = Frameworks; 100 | sourceTree = ""; 101 | }; 102 | 32A57EE9187C05A4002DEC9D /* ClangFormat */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 32A57EEF187C05A4002DEC9D /* TRVSClangFormat.h */, 106 | 32A57EF0187C05A4002DEC9D /* TRVSClangFormat.m */, 107 | 32ABEDD8187EFA4F00D4E980 /* TRVSFormatter.h */, 108 | 32ABEDD9187EFA4F00D4E980 /* TRVSFormatter.m */, 109 | 3228E443187F200D0037DECF /* TRVSCodeFragment.h */, 110 | 3228E444187F200D0037DECF /* TRVSCodeFragment.m */, 111 | 32ABEDDA187EFA4F00D4E980 /* TRVSPreferences.h */, 112 | 32ABEDDB187EFA4F00D4E980 /* TRVSPreferences.m */, 113 | 32ABEDC8187EF90500D4E980 /* TRVSXcode.h */, 114 | 32ABEDC9187EF90500D4E980 /* TRVSXcode.m */, 115 | 32F745E218823A57007541E1 /* NSDocument+TRVSClangFormat.h */, 116 | 32F745E318823A57007541E1 /* NSDocument+TRVSClangFormat.m */, 117 | 32A57EEA187C05A4002DEC9D /* Supporting Files */, 118 | ); 119 | path = ClangFormat; 120 | sourceTree = ""; 121 | }; 122 | 32A57EEA187C05A4002DEC9D /* Supporting Files */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 32D22368187C28DC008D12A3 /* ClangFormat.xcodeproj */, 126 | 32D2236B187C28E1008D12A3 /* clang-format */, 127 | 32A57EEB187C05A4002DEC9D /* ClangFormat-Info.plist */, 128 | 32A57EEC187C05A4002DEC9D /* InfoPlist.strings */, 129 | 32A57EF2187C05A4002DEC9D /* ClangFormat-Prefix.pch */, 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | 32D22369187C28DC008D12A3 /* Products */ = { 135 | isa = PBXGroup; 136 | name = Products; 137 | sourceTree = ""; 138 | }; 139 | /* End PBXGroup section */ 140 | 141 | /* Begin PBXNativeTarget section */ 142 | 32A57EE1187C05A4002DEC9D /* ClangFormat */ = { 143 | isa = PBXNativeTarget; 144 | buildConfigurationList = 32A57EF5187C05A4002DEC9D /* Build configuration list for PBXNativeTarget "ClangFormat" */; 145 | buildPhases = ( 146 | 32A57EDE187C05A4002DEC9D /* Sources */, 147 | 32A57EDF187C05A4002DEC9D /* Frameworks */, 148 | 32A57EE0187C05A4002DEC9D /* Resources */, 149 | ); 150 | buildRules = ( 151 | ); 152 | dependencies = ( 153 | ); 154 | name = ClangFormat; 155 | productName = ClangFormat; 156 | productReference = 32A57EE2187C05A4002DEC9D /* ClangFormat.xcplugin */; 157 | productType = "com.apple.product-type.bundle"; 158 | }; 159 | /* End PBXNativeTarget section */ 160 | 161 | /* Begin PBXProject section */ 162 | 32A57EDA187C05A4002DEC9D /* Project object */ = { 163 | isa = PBXProject; 164 | attributes = { 165 | LastUpgradeCheck = 0510; 166 | ORGANIZATIONNAME = "Travis Jeffery"; 167 | }; 168 | buildConfigurationList = 32A57EDD187C05A4002DEC9D /* Build configuration list for PBXProject "ClangFormat" */; 169 | compatibilityVersion = "Xcode 3.2"; 170 | developmentRegion = English; 171 | hasScannedForEncodings = 0; 172 | knownRegions = ( 173 | en, 174 | ); 175 | mainGroup = 32A57ED9187C05A4002DEC9D; 176 | productRefGroup = 32A57EE3187C05A4002DEC9D /* Products */; 177 | projectDirPath = ""; 178 | projectReferences = ( 179 | { 180 | ProductGroup = 32D22369187C28DC008D12A3 /* Products */; 181 | ProjectRef = 32D22368187C28DC008D12A3 /* ClangFormat.xcodeproj */; 182 | }, 183 | ); 184 | projectRoot = ""; 185 | targets = ( 186 | 32A57EE1187C05A4002DEC9D /* ClangFormat */, 187 | ); 188 | }; 189 | /* End PBXProject section */ 190 | 191 | /* Begin PBXResourcesBuildPhase section */ 192 | 32A57EE0187C05A4002DEC9D /* Resources */ = { 193 | isa = PBXResourcesBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | 32A57EEE187C05A4002DEC9D /* InfoPlist.strings in Resources */, 197 | 32D2236C187C28E1008D12A3 /* clang-format in Resources */, 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXResourcesBuildPhase section */ 202 | 203 | /* Begin PBXSourcesBuildPhase section */ 204 | 32A57EDE187C05A4002DEC9D /* Sources */ = { 205 | isa = PBXSourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 32A57EF1187C05A4002DEC9D /* TRVSClangFormat.m in Sources */, 209 | 3228E445187F200D0037DECF /* TRVSCodeFragment.m in Sources */, 210 | 32ABEDDC187EFA4F00D4E980 /* TRVSFormatter.m in Sources */, 211 | 32F745E418823A57007541E1 /* NSDocument+TRVSClangFormat.m in Sources */, 212 | 32ABEDCA187EF90500D4E980 /* TRVSXcode.m in Sources */, 213 | 32ABEDDD187EFA4F00D4E980 /* TRVSPreferences.m in Sources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXSourcesBuildPhase section */ 218 | 219 | /* Begin PBXVariantGroup section */ 220 | 32A57EEC187C05A4002DEC9D /* InfoPlist.strings */ = { 221 | isa = PBXVariantGroup; 222 | children = ( 223 | 32A57EED187C05A4002DEC9D /* en */, 224 | ); 225 | name = InfoPlist.strings; 226 | sourceTree = ""; 227 | }; 228 | /* End PBXVariantGroup section */ 229 | 230 | /* Begin XCBuildConfiguration section */ 231 | 32A57EF3187C05A4002DEC9D /* Debug */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | ALWAYS_SEARCH_USER_PATHS = NO; 235 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 236 | CLANG_CXX_LIBRARY = "libc++"; 237 | CLANG_ENABLE_OBJC_ARC = YES; 238 | CLANG_WARN_BOOL_CONVERSION = YES; 239 | CLANG_WARN_CONSTANT_CONVERSION = YES; 240 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 241 | CLANG_WARN_EMPTY_BODY = YES; 242 | CLANG_WARN_ENUM_CONVERSION = YES; 243 | CLANG_WARN_INT_CONVERSION = YES; 244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 245 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 246 | COPY_PHASE_STRIP = NO; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 250 | GCC_OPTIMIZATION_LEVEL = 0; 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 256 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 257 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 258 | GCC_WARN_UNDECLARED_SELECTOR = YES; 259 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 260 | GCC_WARN_UNUSED_FUNCTION = YES; 261 | GCC_WARN_UNUSED_VARIABLE = YES; 262 | MACOSX_DEPLOYMENT_TARGET = 10.8; 263 | ONLY_ACTIVE_ARCH = YES; 264 | SDKROOT = macosx; 265 | }; 266 | name = Debug; 267 | }; 268 | 32A57EF4187C05A4002DEC9D /* Release */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ALWAYS_SEARCH_USER_PATHS = NO; 272 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 273 | CLANG_CXX_LIBRARY = "libc++"; 274 | CLANG_ENABLE_OBJC_ARC = YES; 275 | CLANG_WARN_BOOL_CONVERSION = YES; 276 | CLANG_WARN_CONSTANT_CONVERSION = YES; 277 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INT_CONVERSION = YES; 281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | COPY_PHASE_STRIP = YES; 284 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 285 | ENABLE_NS_ASSERTIONS = NO; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | MACOSX_DEPLOYMENT_TARGET = 10.8; 295 | SDKROOT = macosx; 296 | }; 297 | name = Release; 298 | }; 299 | 32A57EF6187C05A4002DEC9D /* Debug */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | COMBINE_HIDPI_IMAGES = YES; 303 | DEPLOYMENT_LOCATION = YES; 304 | DSTROOT = "$(HOME)"; 305 | FRAMEWORK_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "$(DEVELOPER_DIR)/../SharedFrameworks", 308 | "$(DEVELOPER_DIR)/../Frameworks", 309 | ); 310 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 311 | GCC_PREFIX_HEADER = "ClangFormat/ClangFormat-Prefix.pch"; 312 | HEADER_SEARCH_PATHS = ( 313 | "$(inherited)", 314 | "$(DT_TOOLCHAIN_DIR)/usr/include", 315 | ); 316 | INFOPLIST_FILE = "ClangFormat/ClangFormat-Info.plist"; 317 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(DEVELOPER_DIR)"; 319 | PRODUCT_NAME = "$(TARGET_NAME)"; 320 | WRAPPER_EXTENSION = xcplugin; 321 | }; 322 | name = Debug; 323 | }; 324 | 32A57EF7187C05A4002DEC9D /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | COMBINE_HIDPI_IMAGES = YES; 328 | DEPLOYMENT_LOCATION = YES; 329 | DSTROOT = "$(HOME)"; 330 | FRAMEWORK_SEARCH_PATHS = ( 331 | "$(inherited)", 332 | "$(DEVELOPER_DIR)/../SharedFrameworks", 333 | "$(DEVELOPER_DIR)/../Frameworks", 334 | ); 335 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 336 | GCC_PREFIX_HEADER = "ClangFormat/ClangFormat-Prefix.pch"; 337 | HEADER_SEARCH_PATHS = ( 338 | "$(inherited)", 339 | "$(DT_TOOLCHAIN_DIR)/usr/include", 340 | ); 341 | INFOPLIST_FILE = "ClangFormat/ClangFormat-Info.plist"; 342 | INSTALL_PATH = "/Library/Application Support/Developer/Shared/Xcode/Plug-ins"; 343 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(DEVELOPER_DIR)"; 344 | PRODUCT_NAME = "$(TARGET_NAME)"; 345 | WRAPPER_EXTENSION = xcplugin; 346 | }; 347 | name = Release; 348 | }; 349 | /* End XCBuildConfiguration section */ 350 | 351 | /* Begin XCConfigurationList section */ 352 | 32A57EDD187C05A4002DEC9D /* Build configuration list for PBXProject "ClangFormat" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | 32A57EF3187C05A4002DEC9D /* Debug */, 356 | 32A57EF4187C05A4002DEC9D /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | 32A57EF5187C05A4002DEC9D /* Build configuration list for PBXNativeTarget "ClangFormat" */ = { 362 | isa = XCConfigurationList; 363 | buildConfigurations = ( 364 | 32A57EF6187C05A4002DEC9D /* Debug */, 365 | 32A57EF7187C05A4002DEC9D /* Release */, 366 | ); 367 | defaultConfigurationIsVisible = 0; 368 | defaultConfigurationName = Release; 369 | }; 370 | /* End XCConfigurationList section */ 371 | }; 372 | rootObject = 32A57EDA187C05A4002DEC9D /* Project object */; 373 | } 374 | -------------------------------------------------------------------------------- /ClangFormat.xcodeproj/xcshareddata/xcschemes/ClangFormat.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 44 | 47 | 48 | 49 | 55 | 56 | 57 | 58 | 59 | 60 | 66 | 67 | 73 | 74 | 75 | 76 | 78 | 79 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /ClangFormat/ClangFormat-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.travisjeffery.${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 | ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C 28 | F41BD31E-2683-44B8-AE7F-5F09E919790E 29 | 9AFF134A-08DC-4096-8CEE-62A4BB123046 30 | 7265231C-39B4-402C-89E1-16167C4CC990 31 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 32 | CC0D0F4F-05B3-431A-8F33-F84AFCB2C651 33 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 34 | AABB7188-E14E-4433-AD3B-5CD791EAD9A3 35 | E969541F-E6F9-4D25-8158-72DC3545A6C6 36 | 8DC44374-2B35-4C57-A6FE-2AD66A36AAD9 37 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7 38 | A16FF353-8441-459E-A50C-B071F53F51B7 39 | FEC992CC-CA4A-4CFD-8881-77300FCB848A 40 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 41 | 640F884E-CE55-4B40-87C0-8869546CAB7A 42 | 37B30044-3B14-46BA-ABAA-F01000C27B63 43 | AD68E85B-441B-4301-B564-A45E4919A6AD 44 | C4A681B0-4A26-480E-93EC-1218098B9AA0 45 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90 46 | 47 | NSPrincipalClass 48 | TRVSClangFormat 49 | XC4Compatible 50 | 51 | XCGCReady 52 | 53 | XCPluginHasUI 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ClangFormat/ClangFormat-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 | #endif 9 | -------------------------------------------------------------------------------- /ClangFormat/NSDocument+TRVSClangFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDocument+TRVSClangFormat.h 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/11/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSDocument (TRVSClangFormat) 12 | 13 | + (BOOL)trvs_formatOnSave; 14 | + (void)settrvs_formatOnSave:(BOOL)formatOnSave; 15 | 16 | - (BOOL)trvs_shouldFormat; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ClangFormat/NSDocument+TRVSClangFormat.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDocument+TRVSClangFormat.m 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/11/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import "NSDocument+TRVSClangFormat.h" 10 | #import 11 | #import "TRVSFormatter.h" 12 | #import "TRVSXcode.h" 13 | 14 | static BOOL trvs_formatOnSave; 15 | 16 | @implementation NSDocument (TRVSClangFormat) 17 | 18 | - (void)trvs_saveDocumentWithDelegate:(id)delegate 19 | didSaveSelector:(SEL)didSaveSelector 20 | contextInfo:(void *)contextInfo { 21 | if ([self trvs_shouldFormatBeforeSaving]) 22 | [[TRVSFormatter sharedFormatter] 23 | formatDocument:(IDESourceCodeDocument *)self]; 24 | 25 | [self trvs_saveDocumentWithDelegate:delegate 26 | didSaveSelector:didSaveSelector 27 | contextInfo:contextInfo]; 28 | } 29 | 30 | + (void)load { 31 | Method original, swizzle; 32 | 33 | original = class_getInstanceMethod( 34 | self, 35 | NSSelectorFromString( 36 | @"saveDocumentWithDelegate:didSaveSelector:contextInfo:")); 37 | swizzle = class_getInstanceMethod( 38 | self, 39 | NSSelectorFromString( 40 | @"trvs_saveDocumentWithDelegate:didSaveSelector:contextInfo:")); 41 | 42 | method_exchangeImplementations(original, swizzle); 43 | } 44 | 45 | + (void)settrvs_formatOnSave:(BOOL)formatOnSave { 46 | trvs_formatOnSave = formatOnSave; 47 | } 48 | 49 | + (BOOL)trvs_formatOnSave { 50 | return trvs_formatOnSave; 51 | } 52 | 53 | - (BOOL)trvs_shouldFormatBeforeSaving { 54 | return [[self class] trvs_formatOnSave] && 55 | [self trvs_shouldFormat] && 56 | [TRVSXcode sourceCodeDocument] == self; 57 | } 58 | 59 | - (BOOL)trvs_shouldFormat { 60 | return [[NSSet setWithObjects:@"c", @"h", @"cpp", @"cc", @"cxx", @"hh", @"hpp", @"hxx", @"ipp", @"m", @"mm", @"metal", nil] containsObject:[[[self fileURL] pathExtension] lowercaseString]]; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /ClangFormat/TRVSClangFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // ClangFormat.h 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/7/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // the central plug-in interface 12 | 13 | @interface TRVSClangFormat : NSObject 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ClangFormat/TRVSClangFormat.m: -------------------------------------------------------------------------------- 1 | // 2 | // ClangFormat.m 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/7/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import "TRVSClangFormat.h" 10 | #import "TRVSPreferences.h" 11 | #import "TRVSFormatter.h" 12 | #import "NSDocument+TRVSClangFormat.h" 13 | 14 | static TRVSClangFormat *sharedPlugin; 15 | 16 | @interface TRVSClangFormat () 17 | 18 | @property (nonatomic, strong) NSBundle *bundle; 19 | @property (nonatomic, strong) NSMenu *formatMenu; 20 | @property (nonatomic, strong) TRVSPreferences *preferences; 21 | @property (nonatomic, strong) TRVSFormatter *formatter; 22 | 23 | @end 24 | 25 | @implementation TRVSClangFormat 26 | 27 | + (void)pluginDidLoad:(NSBundle *)plugin { 28 | static id sharedPlugin = nil; 29 | static dispatch_once_t onceToken; 30 | NSString *currentApplicationName = 31 | [[NSBundle mainBundle] infoDictionary][@"CFBundleName"]; 32 | if ([currentApplicationName isEqual:@"Xcode"]) { 33 | dispatch_once(&onceToken, ^{ 34 | sharedPlugin = [[self alloc] initWithBundle:plugin]; 35 | }); 36 | } 37 | } 38 | 39 | - (id)initWithBundle:(NSBundle *)plugin { 40 | if (!(self = [super init])) 41 | return nil; 42 | 43 | self.bundle = plugin; 44 | self.preferences = [[TRVSPreferences alloc] 45 | initWithApplicationID:self.bundle.bundleIdentifier]; 46 | NSString *style = [self.preferences objectForKey:[self stylePreferencesKey]] 47 | ?: [[self styles] firstObject]; 48 | self.formatter = [TRVSFormatter sharedFormatter]; 49 | self.formatter.style = style; 50 | 51 | NSNumber *useSystemClangFormat = 52 | [self.preferences objectForKey:[self useSystemClangFormatPreferencesKey]] 53 | ?: [NSNumber numberWithBool:NO]; 54 | self.formatter.useSystemClangFormat = [useSystemClangFormat boolValue]; 55 | 56 | self.formatter.executablePath = 57 | [self.bundle pathForResource:@"clang-format" ofType:@""]; 58 | 59 | [NSDocument settrvs_formatOnSave:[self formatOnSave]]; 60 | 61 | [[NSNotificationCenter defaultCenter] 62 | addObserver:self 63 | selector:@selector(applicationDidFinishLaunching:) 64 | name:NSApplicationDidFinishLaunchingNotification 65 | object:nil]; 66 | 67 | return self; 68 | } 69 | 70 | - (void)applicationDidFinishLaunching:(NSNotification *)notification { 71 | [self addMenuItemsToMenu]; 72 | 73 | [[NSNotificationCenter defaultCenter] 74 | removeObserver:self 75 | name:NSApplicationDidFinishLaunchingNotification 76 | object:nil]; 77 | } 78 | 79 | #pragma mark - Actions 80 | 81 | - (void)setStyleToUseFromMenuItem:(NSMenuItem *)menuItem { 82 | [self.preferences setObject:menuItem.title forKey:[self stylePreferencesKey]]; 83 | [self.preferences synchronize]; 84 | 85 | self.formatter.style = menuItem.title; 86 | 87 | [self prepareFormatMenu]; 88 | } 89 | 90 | #pragma mark - Private 91 | 92 | - (void)prepareFormatMenu { 93 | [self.formatMenu removeAllItems]; 94 | [self addMenuItemsToFormatMenu]; 95 | } 96 | 97 | - (void)addMenuItemsToFormatMenu { 98 | [self addActioningMenuItemsToFormatMenu]; 99 | [self addSeparatorToFormatMenu]; 100 | [self addStyleMenuItemsToFormatMenu]; 101 | [self addSeparatorToFormatMenu]; 102 | [self addFormatOnSaveMenuItem]; 103 | [self addUseSystemClangFormatMenuItem]; 104 | } 105 | 106 | - (void)addActioningMenuItemsToFormatMenu { 107 | NSMenuItem *formatActiveFileItem = [[NSMenuItem alloc] 108 | initWithTitle:NSLocalizedString(@"Format File in Focus", nil) 109 | action:@selector(formatActiveFile) 110 | keyEquivalent:@""]; 111 | [formatActiveFileItem setTarget:self.formatter]; 112 | [self.formatMenu addItem:formatActiveFileItem]; 113 | 114 | NSMenuItem *formatSelectedCharacters = [[NSMenuItem alloc] 115 | initWithTitle:NSLocalizedString(@"Format Selected Text", nil) 116 | action:@selector(formatSelectedCharacters) 117 | keyEquivalent:@""]; 118 | [formatSelectedCharacters setTarget:self.formatter]; 119 | [self.formatMenu addItem:formatSelectedCharacters]; 120 | 121 | NSMenuItem *formatSelectedFilesItem = [[NSMenuItem alloc] 122 | initWithTitle:NSLocalizedString(@"Format Selected Files", nil) 123 | action:@selector(formatSelectedFiles) 124 | keyEquivalent:@""]; 125 | [formatSelectedFilesItem setTarget:self.formatter]; 126 | [self.formatMenu addItem:formatSelectedFilesItem]; 127 | } 128 | 129 | - (void)addSeparatorToFormatMenu { 130 | [self.formatMenu addItem:[NSMenuItem separatorItem]]; 131 | } 132 | 133 | - (void)addStyleMenuItemsToFormatMenu { 134 | [[self styles] enumerateObjectsUsingBlock:^(NSString *format, NSUInteger idx, 135 | BOOL *stop) { 136 | [self addMenuItemWithStyle:format]; 137 | }]; 138 | } 139 | 140 | - (void)addMenuItemWithStyle:(NSString *)style { 141 | NSMenuItem *menuItem = 142 | [[NSMenuItem alloc] initWithTitle:style 143 | action:@selector(setStyleToUseFromMenuItem:) 144 | keyEquivalent:@""]; 145 | [menuItem setTarget:self]; 146 | 147 | if ([style isEqualToString:self.formatter.style]) 148 | menuItem.state = NSOnState; 149 | 150 | [self.formatMenu addItem:menuItem]; 151 | } 152 | 153 | - (void)addFormatOnSaveMenuItem { 154 | NSString *title = NSLocalizedString(@"Enable Format on Save", nil); 155 | if ([self formatOnSave]) 156 | title = NSLocalizedString(@"Disable Format on Save", nil); 157 | 158 | NSMenuItem *toggleFormatOnSaveMenuItem = 159 | [[NSMenuItem alloc] initWithTitle:title 160 | action:@selector(toggleFormatOnSave) 161 | keyEquivalent:@""]; 162 | [toggleFormatOnSaveMenuItem setTarget:self]; 163 | [self.formatMenu addItem:toggleFormatOnSaveMenuItem]; 164 | } 165 | 166 | - (void)addUseSystemClangFormatMenuItem { 167 | NSString *title = [self useSystemClangFormat] 168 | ? NSLocalizedString(@"Use Bundled ClangFormat", nil) 169 | : NSLocalizedString(@"Use System ClangFormat", nil); 170 | NSMenuItem *useSystemClangFormatMenuItem = 171 | [[NSMenuItem alloc] initWithTitle:title 172 | action:@selector(toggleUseSystemClangFormat) 173 | keyEquivalent:@""]; 174 | [useSystemClangFormatMenuItem setTarget:self]; 175 | [self.formatMenu addItem:useSystemClangFormatMenuItem]; 176 | } 177 | 178 | - (void)addMenuItemsToMenu { 179 | NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"Edit"]; 180 | if (!menuItem) 181 | return; 182 | 183 | [[menuItem submenu] addItem:[NSMenuItem separatorItem]]; 184 | 185 | NSMenuItem *actionMenuItem = 186 | [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Clang Format", nil) 187 | action:NULL 188 | keyEquivalent:@""]; 189 | [[menuItem submenu] addItem:actionMenuItem]; 190 | 191 | self.formatMenu = 192 | [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Clang Format", nil)]; 193 | [self addMenuItemsToFormatMenu]; 194 | [actionMenuItem setSubmenu:self.formatMenu]; 195 | } 196 | 197 | - (void)toggleFormatOnSave { 198 | BOOL formatOnSave = ![self formatOnSave]; 199 | 200 | [self.preferences setObject:@(formatOnSave) 201 | forKey:[self formatOnSavePreferencesKey]]; 202 | [self.preferences synchronize]; 203 | 204 | [NSDocument settrvs_formatOnSave:formatOnSave]; 205 | 206 | [self prepareFormatMenu]; 207 | } 208 | 209 | - (BOOL)formatOnSave { 210 | return [[self.preferences 211 | objectForKey:[self formatOnSavePreferencesKey]] boolValue]; 212 | } 213 | 214 | - (void)toggleUseSystemClangFormat { 215 | BOOL useSystemClangFormat = ![self useSystemClangFormat]; 216 | 217 | [self.preferences setObject:@(useSystemClangFormat) 218 | forKey:[self useSystemClangFormatPreferencesKey]]; 219 | [self.preferences synchronize]; 220 | 221 | self.formatter.useSystemClangFormat = useSystemClangFormat; 222 | 223 | [self prepareFormatMenu]; 224 | } 225 | 226 | - (BOOL)useSystemClangFormat { 227 | return [[self.preferences 228 | objectForKey:[self useSystemClangFormatPreferencesKey]] boolValue]; 229 | } 230 | 231 | - (NSString *)formatOnSavePreferencesKey { 232 | return 233 | [self.bundle.bundleIdentifier stringByAppendingString:@".formatOnSave"]; 234 | } 235 | 236 | - (NSString *)stylePreferencesKey { 237 | return [self.bundle.bundleIdentifier stringByAppendingString:@".format"]; 238 | } 239 | 240 | - (NSString *)useSystemClangFormatPreferencesKey { 241 | return [self.bundle.bundleIdentifier 242 | stringByAppendingString:@".useSystemClangFormat"]; 243 | } 244 | 245 | - (NSArray *)styles { 246 | return @[ @"LLVM", @"Google", @"Chromium", @"Mozilla", @"WebKit", @"File" ]; 247 | } 248 | 249 | @end 250 | -------------------------------------------------------------------------------- /ClangFormat/TRVSCodeFragment.h: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSCodeFragment.h 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TRVSCodeFragment; 12 | 13 | @interface TRVSCodeFragmentBuilder : NSObject 14 | 15 | - (TRVSCodeFragment *)build; 16 | 17 | @property (nonatomic, copy) NSString *string; 18 | @property (nonatomic, copy) NSString *formattedString; 19 | @property (nonatomic) NSRange textRange; 20 | @property (nonatomic, strong) NSURL *fileURL; 21 | 22 | @end 23 | 24 | @interface TRVSCodeFragment : NSObject 25 | 26 | + (instancetype)fragmentUsingBlock:(void (^)(TRVSCodeFragmentBuilder *builder))block; 27 | 28 | - (void)formatWithStyle:(NSString *)style 29 | usingClangFormatAtLaunchPath:(NSString *)launchPath 30 | lineRange:(NSRange)lineRange 31 | block:(void (^)(NSString *formattedString, 32 | NSError *error))block; 33 | 34 | @property (nonatomic, copy) NSString *string; 35 | @property (nonatomic, copy) NSString *formattedString; 36 | @property (nonatomic) NSRange textRangePreFormat; 37 | @property (nonatomic) NSRange textRangePostFormat; 38 | @property (nonatomic) NSRange rangeToReplace; 39 | @property (nonatomic, strong) NSURL *fileURL; 40 | @property (nonatomic, strong) NSError *error; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /ClangFormat/TRVSCodeFragment.m: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSCodeFragment.m 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import "TRVSCodeFragment.h" 10 | 11 | @interface TRVSCodeFragment () 12 | 13 | - (instancetype)initWithBuilder:(TRVSCodeFragmentBuilder *)builder; 14 | 15 | @end 16 | 17 | @implementation TRVSCodeFragmentBuilder 18 | 19 | - (TRVSCodeFragment *)build { 20 | return [[TRVSCodeFragment alloc] initWithBuilder:self]; 21 | } 22 | 23 | @end 24 | 25 | @implementation TRVSCodeFragment 26 | 27 | + (instancetype)fragmentUsingBlock: 28 | (void (^)(TRVSCodeFragmentBuilder *builder))block { 29 | TRVSCodeFragmentBuilder *builder = [TRVSCodeFragmentBuilder new]; 30 | block(builder); 31 | return [builder build]; 32 | } 33 | 34 | - (instancetype)initWithBuilder:(TRVSCodeFragmentBuilder *)builder { 35 | if (self = [super init]) { 36 | _string = [builder.string copy]; 37 | _textRangePreFormat = builder.textRange; 38 | _fileURL = builder.fileURL; 39 | } 40 | return self; 41 | } 42 | 43 | // Find the smallest possible part that is different from before formatting, 44 | // so we don't have to replace the entire file. 45 | - (void)updateRangeToReplace:(NSString *)formattedDoc { 46 | NSUInteger originalLen = _string.length; 47 | NSUInteger formattedLen = formattedDoc.length; 48 | NSRange originalSelection = _textRangePreFormat; 49 | 50 | // Find the left boundary. 51 | NSUInteger i; 52 | for (i = 0; i < _textRangePreFormat.location; ++i) { 53 | if ([_string characterAtIndex:i] != [formattedDoc characterAtIndex:i]) { 54 | break; 55 | } 56 | } 57 | NSRange rangeInOriginalDoc = NSMakeRange(i, originalLen - i); 58 | NSRange rangeInFormattedDoc = NSMakeRange(i, formattedLen - i); 59 | 60 | // Find the right boundary. 61 | NSUInteger maxJ = originalLen - NSMaxRange(originalSelection); 62 | NSUInteger j; 63 | for (j = 0; j < maxJ; ++j) { 64 | if ([_string characterAtIndex:originalLen - j - 1] != 65 | [formattedDoc characterAtIndex:formattedLen - j - 1]) { 66 | break; 67 | } 68 | } 69 | rangeInOriginalDoc.length -= j; 70 | rangeInFormattedDoc.length -= j; 71 | 72 | self.rangeToReplace = rangeInOriginalDoc; 73 | self.textRangePostFormat = rangeInFormattedDoc; 74 | self.formattedString = [formattedDoc substringWithRange:rangeInFormattedDoc]; 75 | }; 76 | 77 | - (void)formatWithStyle:(NSString *)style 78 | usingClangFormatAtLaunchPath:(NSString *)launchPath 79 | lineRange:(NSRange)lineRange 80 | block:(void (^)(NSString *formattedString, 81 | NSError *error))block { 82 | NSString *fileName = [self.fileURL lastPathComponent]; 83 | NSURL *tmpDirURL = [[self.fileURL URLByDeletingLastPathComponent] 84 | URLByAppendingPathComponent:@"ClangFormatXcodeTmpDir"]; 85 | [[NSFileManager defaultManager] createDirectoryAtURL:tmpDirURL 86 | withIntermediateDirectories:YES 87 | attributes:nil 88 | error:nil]; 89 | 90 | NSURL *tmpFileURL = [tmpDirURL URLByAppendingPathComponent:fileName]; 91 | [self.string writeToURL:tmpFileURL 92 | atomically:YES 93 | encoding:NSUTF8StringEncoding 94 | error:NULL]; 95 | 96 | NSPipe *outputPipe = [NSPipe pipe]; 97 | NSPipe *errorPipe = [NSPipe pipe]; 98 | 99 | NSTask *task = [[NSTask alloc] init]; 100 | task.standardOutput = outputPipe; 101 | task.standardError = errorPipe; 102 | task.launchPath = launchPath; 103 | task.arguments = @[ 104 | [NSString 105 | stringWithFormat:@"-lines=%tu:%tu", 106 | lineRange.location + 1, // 1-based 107 | lineRange.location + lineRange.length], // 1-based 108 | [NSString stringWithFormat:@"--style=%@", style], 109 | @"-i", 110 | [tmpFileURL path] 111 | ]; 112 | 113 | [outputPipe.fileHandleForReading readToEndOfFileInBackgroundAndNotify]; 114 | 115 | [task launch]; 116 | [task waitUntilExit]; 117 | 118 | NSData *errorData = [errorPipe.fileHandleForReading readDataToEndOfFile]; 119 | 120 | NSString *formattedDoc = [NSString stringWithContentsOfURL:tmpFileURL 121 | encoding:NSUTF8StringEncoding 122 | error:NULL]; 123 | [self updateRangeToReplace:formattedDoc]; 124 | block(self.formattedString, 125 | errorData.length > 0 126 | ? [NSError errorWithDomain:@"com.travisjeffery.error" 127 | code:-99 128 | userInfo:@{ 129 | NSLocalizedDescriptionKey : 130 | [[NSString alloc] 131 | initWithData:errorData 132 | encoding:NSUTF8StringEncoding] 133 | }] 134 | : nil); 135 | 136 | [[NSFileManager defaultManager] removeItemAtURL:tmpDirURL error:NULL]; 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /ClangFormat/TRVSFormatter.h: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSFormatter.h 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class IDESourceCodeDocument; 12 | 13 | @interface TRVSFormatter : NSObject 14 | 15 | @property (nonatomic, copy) NSString *style; 16 | @property (nonatomic, copy) NSString *executablePath; 17 | @property (nonatomic) BOOL useSystemClangFormat; 18 | 19 | + (instancetype)sharedFormatter; 20 | - (instancetype)initWithStyle:(NSString *)style 21 | executablePath:(NSString *)executablePath 22 | useSystemClangFormat:(BOOL)useSystemClangFormat; 23 | - (void)formatActiveFile; 24 | - (void)formatSelectedCharacters; 25 | - (void)formatSelectedFiles; 26 | - (void)formatDocument:(IDESourceCodeDocument *)document; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ClangFormat/TRVSFormatter.m: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSFormatter.m 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import "TRVSFormatter.h" 10 | #import "TRVSXcode.h" 11 | #import "TRVSCodeFragment.h" 12 | #import "NSDocument+TRVSClangFormat.h" 13 | 14 | @interface TRVSFormatter () 15 | 16 | @property (nonatomic, copy) NSSet *supportedFileTypes; 17 | 18 | @end 19 | 20 | @implementation TRVSFormatter 21 | 22 | + (instancetype)sharedFormatter { 23 | static id sharedFormatter = nil; 24 | static dispatch_once_t onceToken; 25 | 26 | dispatch_once(&onceToken, ^{ 27 | sharedFormatter = [[self alloc] initWithStyle:nil 28 | executablePath:nil 29 | useSystemClangFormat:NO]; 30 | }); 31 | 32 | return sharedFormatter; 33 | } 34 | 35 | - (instancetype)initWithStyle:(NSString *)style 36 | executablePath:(NSString *)executablePath 37 | useSystemClangFormat:(BOOL)useSystemClangFormat { 38 | if (self = [self init]) { 39 | self.style = style; 40 | self.executablePath = executablePath; 41 | self.useSystemClangFormat = useSystemClangFormat; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)formatActiveFile { 47 | [self formatRanges: 48 | @[ [NSValue valueWithRange:[TRVSXcode wholeRangeOfTextView]] ] 49 | inDocument:[TRVSXcode sourceCodeDocument]]; 50 | } 51 | 52 | - (void)formatSelectedCharacters { 53 | // Even if there is no selection, go one and perform a format with 0-length 54 | // range. This will format the statement under cursor. 55 | [self formatRanges:[[TRVSXcode textView] selectedRanges] 56 | inDocument:[TRVSXcode sourceCodeDocument]]; 57 | } 58 | 59 | - (void)formatSelectedFiles { 60 | [[TRVSXcode selectedFileNavigableItems] 61 | enumerateObjectsUsingBlock:^(IDEFileNavigableItem *fileNavigableItem, 62 | NSUInteger idx, 63 | BOOL *stop) { 64 | NSDocument *document = [IDEDocumentController 65 | retainedEditorDocumentForNavigableItem:fileNavigableItem 66 | error:NULL]; 67 | 68 | if ([document 69 | isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) { 70 | IDESourceCodeDocument *sourceCodeDocument = 71 | (IDESourceCodeDocument *)document; 72 | 73 | [self 74 | formatRanges: 75 | @[ 76 | [NSValue 77 | valueWithRange: 78 | NSMakeRange( 79 | 0, [[sourceCodeDocument textStorage] length])] 80 | ] 81 | inDocument:sourceCodeDocument]; 82 | 83 | [document saveDocument:nil]; 84 | } 85 | 86 | [IDEDocumentController releaseEditorDocument:document]; 87 | }]; 88 | } 89 | 90 | - (void)formatDocument:(IDESourceCodeDocument *)document { 91 | NSRect rect = [[TRVSXcode textView] visibleRect]; 92 | NSPoint containerOrigin = [[TRVSXcode textView] textContainerOrigin]; 93 | rect = NSOffsetRect(rect, -containerOrigin.x, -containerOrigin.y); 94 | NSRange glyphRange = [[[TRVSXcode textView] layoutManager] 95 | glyphRangeForBoundingRect:rect 96 | inTextContainer:[[TRVSXcode textView] textContainer]]; 97 | NSRange charRange = [[[TRVSXcode textView] layoutManager] 98 | characterRangeForGlyphRange:glyphRange 99 | actualGlyphRange:NULL]; 100 | 101 | 102 | NSUInteger location = [[TRVSXcode textView] selectedRange].location; 103 | NSUInteger length = [[document textStorage] length]; 104 | 105 | [self formatRanges:@[ [NSValue valueWithRange:NSMakeRange(0, length)] ] 106 | inDocument:document]; 107 | 108 | NSUInteger textStorageLength = [[document textStorage] length]; 109 | NSUInteger diff = MAX(length, textStorageLength) - MIN(length, textStorageLength); 110 | 111 | BOOL documentIsLongerAfterFormatting = 112 | length > [[document textStorage] length]; 113 | 114 | if (documentIsLongerAfterFormatting && location > diff) { 115 | location -= diff; 116 | charRange.length -= diff; 117 | } else if (!documentIsLongerAfterFormatting) { 118 | location += diff; 119 | charRange.length += diff; 120 | } 121 | 122 | NSRange range = NSMakeRange(location, 0); 123 | [[TRVSXcode textView] setSelectedRange:range]; 124 | [[TRVSXcode textView] scrollRangeToVisible:charRange]; 125 | } 126 | 127 | #pragma mark - Private 128 | 129 | - (void)formatRanges:(NSArray *)ranges 130 | inDocument:(IDESourceCodeDocument *)document { 131 | if (![document trvs_shouldFormat]) 132 | return; 133 | 134 | DVTSourceTextStorage *textStorage = [document textStorage]; 135 | 136 | NSArray *lineRanges = 137 | [self lineRangesOfCharacterRanges:ranges usingTextStorage:textStorage]; 138 | NSArray *continuousLineRanges = 139 | [self continuousLineRangesOfRanges:lineRanges]; 140 | [self 141 | fragmentsOfContinuousLineRanges:continuousLineRanges 142 | usingTextStorage:textStorage 143 | withDocument:document 144 | block:^(NSArray *fragments, NSArray *errors) { 145 | if (errors.count == 0) { 146 | NSArray *selectionRanges = [self 147 | selectionRangesAfterReplacingFragments: 148 | fragments usingTextStorage: 149 | textStorage 150 | withDocument: 151 | document]; 152 | 153 | if (selectionRanges.count > 0) 154 | [[TRVSXcode textView] 155 | setSelectedRanges:selectionRanges]; 156 | } else { 157 | NSAlert *alert = [NSAlert new]; 158 | alert.messageText = 159 | [(NSError *)errors.firstObject 160 | localizedDescription]; 161 | [alert runModal]; 162 | } 163 | }]; 164 | } 165 | 166 | - (NSArray *) 167 | selectionRangesAfterReplacingFragments:(NSArray *)fragments 168 | usingTextStorage:(DVTSourceTextStorage *)textStorage 169 | withDocument:(IDESourceCodeDocument *)document { 170 | NSMutableArray *selectionRanges = [[NSMutableArray alloc] init]; 171 | 172 | [fragments enumerateObjectsUsingBlock:^(TRVSCodeFragment *fragment, 173 | NSUInteger idx, 174 | BOOL *stop) { 175 | [textStorage beginEditing]; 176 | 177 | [textStorage replaceCharactersInRange:fragment.rangeToReplace 178 | withString:fragment.formattedString 179 | withUndoManager:document.undoManager]; 180 | 181 | [self addSelectedRangeToSelectedRanges:selectionRanges 182 | usingTextStorage:textStorage]; 183 | 184 | [textStorage endEditing]; 185 | }]; 186 | 187 | return selectionRanges; 188 | } 189 | 190 | - (void)addSelectedRangeToSelectedRanges:(NSMutableArray *)selectionRanges 191 | usingTextStorage:(DVTSourceTextStorage *)textStorage { 192 | if (selectionRanges.count > 0) { 193 | NSUInteger i = 0; 194 | 195 | while (i < selectionRanges.count) { 196 | NSRange range = [[selectionRanges objectAtIndex:i] rangeValue]; 197 | range.location += [textStorage changeInLength]; 198 | [selectionRanges replaceObjectAtIndex:i 199 | withObject:[NSValue valueWithRange:range]]; 200 | i++; 201 | } 202 | } 203 | 204 | NSRange editedRange = textStorage.editedRange; 205 | if (editedRange.location != NSNotFound) { 206 | [selectionRanges addObject:[NSValue valueWithRange:editedRange]]; 207 | } 208 | } 209 | 210 | - (void)fragmentsOfContinuousLineRanges:(NSArray *)continuousLineRanges 211 | usingTextStorage:(DVTSourceTextStorage *)textStorage 212 | withDocument:(IDESourceCodeDocument *)document 213 | block:(void (^)(NSArray *fragments, 214 | NSArray *errors))block { 215 | NSMutableArray *fragments = [[NSMutableArray alloc] init]; 216 | NSMutableArray *errors = [[NSMutableArray alloc] init]; 217 | 218 | NSString *executablePath = self.executablePath; 219 | if (self.useSystemClangFormat) { 220 | NSDictionary *environmentDict = [[NSProcessInfo processInfo] environment]; 221 | NSString *shellString = 222 | [environmentDict objectForKey:@"SHELL"] ?: @"/bin/bash"; 223 | 224 | NSPipe *outputPipe = [NSPipe pipe]; 225 | NSPipe *errorPipe = [NSPipe pipe]; 226 | 227 | NSTask *task = [[NSTask alloc] init]; 228 | task.standardOutput = outputPipe; 229 | task.standardError = errorPipe; 230 | task.launchPath = shellString; 231 | task.arguments = @[ @"-c", @"which clang-format" ]; 232 | 233 | [task launch]; 234 | [task waitUntilExit]; 235 | [errorPipe.fileHandleForReading readDataToEndOfFile]; 236 | NSData *outputData = [outputPipe.fileHandleForReading readDataToEndOfFile]; 237 | NSString *outputPath = [[NSString alloc] initWithData:outputData 238 | encoding:NSUTF8StringEncoding]; 239 | outputPath = [outputPath 240 | stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; 241 | 242 | BOOL isDirectory = NO; 243 | if ([[NSFileManager defaultManager] fileExistsAtPath:outputPath isDirectory:&isDirectory] && !isDirectory) { 244 | executablePath = outputPath; 245 | } 246 | } 247 | 248 | [continuousLineRanges enumerateObjectsUsingBlock:^(NSValue *rangeValue, 249 | NSUInteger idx, 250 | BOOL *stop) { 251 | NSRange characterRange = 252 | [textStorage characterRangeForLineRange:[rangeValue rangeValue]]; 253 | 254 | if (characterRange.location == NSNotFound) 255 | return; 256 | 257 | NSString *string = 258 | [[textStorage string] substringWithRange:characterRange]; 259 | 260 | if (!string.length) 261 | return; 262 | 263 | TRVSCodeFragment *fragment = [TRVSCodeFragment 264 | fragmentUsingBlock:^(TRVSCodeFragmentBuilder *builder) { 265 | builder.string = [textStorage string]; 266 | builder.textRange = characterRange; 267 | builder.fileURL = document.fileURL; 268 | }]; 269 | 270 | // clang-format doesn't support descrete ranges, so only the first range 271 | // can be taken. This is fine because in practice, we have only one 272 | // selected range in Xcode. 273 | NSRange lineRange = [continuousLineRanges[0] rangeValue]; 274 | __weak typeof(fragment) weakFragment = fragment; 275 | [fragment formatWithStyle:self.style 276 | usingClangFormatAtLaunchPath:executablePath 277 | lineRange:lineRange 278 | block:^(NSString *formattedString, 279 | NSError *error) { 280 | __strong typeof(weakFragment) 281 | strongFragment = weakFragment; 282 | if (error) { 283 | [errors addObject:error]; 284 | *stop = YES; 285 | } else { 286 | [fragments addObject:strongFragment]; 287 | } 288 | }]; 289 | }]; 290 | 291 | block(fragments, errors); 292 | } 293 | 294 | - (NSArray *)lineRangesOfCharacterRanges:(NSArray *)characterRanges 295 | usingTextStorage:(DVTSourceTextStorage *)textStorage { 296 | NSMutableArray *lineRanges = [[NSMutableArray alloc] init]; 297 | 298 | [characterRanges enumerateObjectsUsingBlock:^(NSValue *rangeValue, 299 | NSUInteger idx, 300 | BOOL *stop) { 301 | [lineRanges 302 | addObject:[NSValue valueWithRange:[textStorage 303 | lineRangeForCharacterRange: 304 | [rangeValue rangeValue]]]]; 305 | }]; 306 | 307 | return lineRanges; 308 | } 309 | 310 | - (NSArray *)continuousLineRangesOfRanges:(NSArray *)ranges { 311 | NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; 312 | 313 | [ranges enumerateObjectsUsingBlock:^(NSValue *rangeValue, 314 | NSUInteger idx, 315 | BOOL *stop) { 316 | [indexSet addIndexesInRange:[rangeValue rangeValue]]; 317 | }]; 318 | 319 | NSMutableArray *continuousRanges = [[NSMutableArray alloc] init]; 320 | 321 | [indexSet enumerateRangesUsingBlock:^(NSRange range, BOOL *stop) { 322 | [continuousRanges addObject:[NSValue valueWithRange:range]]; 323 | }]; 324 | 325 | return continuousRanges; 326 | } 327 | 328 | @end 329 | -------------------------------------------------------------------------------- /ClangFormat/TRVSPreferences.h: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSPreferences.h 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // wrapper for cfpreferences since nsuserdefaults isn't available in plug-ins 12 | 13 | @interface TRVSPreferences : NSObject 14 | 15 | - (instancetype)initWithApplicationID:(NSString *)applicationID; 16 | - (id)objectForKey:(NSString *)key; 17 | - (void)setObject:(id)object forKey:(NSString *)key; 18 | - (BOOL)synchronize; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ClangFormat/TRVSPreferences.m: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSPreferences.m 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import "TRVSPreferences.h" 10 | 11 | @interface TRVSPreferences () 12 | 13 | @property (nonatomic, copy) NSString *applicationID; 14 | 15 | @end 16 | 17 | @implementation TRVSPreferences 18 | 19 | #pragma mark - Designated Initializer 20 | 21 | - (instancetype)initWithApplicationID:(NSString *)applicationID { 22 | self = [super init]; 23 | 24 | if (self) { 25 | self.applicationID = applicationID; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | - (id)objectForKey:(NSString *)key { 32 | CFPropertyListRef value = 33 | CFPreferencesCopyValue((__bridge CFStringRef)key, 34 | (__bridge CFStringRef)self.applicationID, 35 | kCFPreferencesCurrentUser, 36 | kCFPreferencesAnyHost); 37 | 38 | id object = nil; 39 | 40 | if (value != NULL) { 41 | object = (__bridge id)value; 42 | CFRelease(value); 43 | } 44 | 45 | return object; 46 | } 47 | 48 | - (void)setObject:(id)object forKey:(NSString *)key { 49 | CFPreferencesSetValue((__bridge CFStringRef)key, 50 | (__bridge CFPropertyListRef)object, 51 | (__bridge CFStringRef)self.applicationID, 52 | kCFPreferencesCurrentUser, 53 | kCFPreferencesAnyHost); 54 | } 55 | 56 | - (BOOL)synchronize { 57 | return CFPreferencesSynchronize((__bridge CFStringRef)self.applicationID, 58 | kCFPreferencesCurrentUser, 59 | kCFPreferencesAnyHost); 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /ClangFormat/TRVSXcode.h: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSXcode.h 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // here be dragons... have to declare these private apis 12 | 13 | @interface DVTTextDocumentLocation : NSObject 14 | @property (readonly) NSRange characterRange; 15 | @property (readonly) NSRange lineRange; 16 | @end 17 | 18 | @interface DVTTextPreferences : NSObject 19 | + (id)preferences; 20 | @property BOOL trimWhitespaceOnlyLines; 21 | @property BOOL trimTrailingWhitespace; 22 | @property BOOL useSyntaxAwareIndenting; 23 | @end 24 | 25 | @interface DVTSourceTextStorage : NSTextStorage 26 | - (void)replaceCharactersInRange:(NSRange)range 27 | withString:(NSString *)string 28 | withUndoManager:(id)undoManager; 29 | - (NSRange)lineRangeForCharacterRange:(NSRange)range; 30 | - (NSRange)characterRangeForLineRange:(NSRange)range; 31 | - (void)indentCharacterRange:(NSRange)range undoManager:(id)undoManager; 32 | @end 33 | 34 | @interface DVTFileDataType : NSObject 35 | @property (readonly) NSString *identifier; 36 | @end 37 | 38 | @interface DVTFilePath : NSObject 39 | @property (readonly) NSURL *fileURL; 40 | @property (readonly) DVTFileDataType *fileDataTypePresumed; 41 | @end 42 | 43 | @interface IDEContainerItem : NSObject 44 | @property (readonly) DVTFilePath *resolvedFilePath; 45 | @end 46 | 47 | @interface IDEGroup : IDEContainerItem 48 | 49 | @end 50 | 51 | @interface IDEFileReference : IDEContainerItem 52 | 53 | @end 54 | 55 | @interface IDENavigableItem : NSObject 56 | @property (readonly) IDENavigableItem *parentItem; 57 | @property (readonly) id representedObject; 58 | @end 59 | 60 | @interface IDEFileNavigableItem : IDENavigableItem 61 | @property (readonly) DVTFileDataType *documentType; 62 | @property (readonly) NSURL *fileURL; 63 | @end 64 | 65 | @interface IDEStructureNavigator : NSObject 66 | @property (retain) NSArray *selectedObjects; 67 | @end 68 | 69 | @interface IDENavigableItemCoordinator : NSObject 70 | - (id)structureNavigableItemForDocumentURL:(id)arg1 71 | inWorkspace:(id)arg2 72 | error:(id *)arg3; 73 | @end 74 | 75 | @interface IDENavigatorArea : NSObject 76 | - (id)currentNavigator; 77 | @end 78 | 79 | @interface IDEWorkspaceTabController : NSObject 80 | @property (readonly) IDENavigatorArea *navigatorArea; 81 | @end 82 | 83 | @interface IDEDocumentController : NSDocumentController 84 | + (id)editorDocumentForNavigableItem:(id)arg1; 85 | + (id)retainedEditorDocumentForNavigableItem:(id)arg1 error:(id *)arg2; 86 | + (void)releaseEditorDocument:(id)arg1; 87 | @end 88 | 89 | @interface IDESourceCodeDocument : NSDocument 90 | - (DVTSourceTextStorage *)textStorage; 91 | - (NSUndoManager *)undoManager; 92 | @end 93 | 94 | @interface IDESourceCodeComparisonEditor : NSObject 95 | @property (readonly) NSTextView *keyTextView; 96 | @property (retain) NSDocument *primaryDocument; 97 | @end 98 | 99 | @interface IDESourceCodeEditor : NSObject 100 | @property (retain) NSTextView *textView; 101 | - (IDESourceCodeDocument *)sourceCodeDocument; 102 | @end 103 | 104 | @interface IDEEditorContext : NSObject 105 | - (id)editor; // returns the current editor. If the editor is the code editor, 106 | // the class is `IDESourceCodeEditor` 107 | @end 108 | 109 | @interface IDEEditorArea : NSObject 110 | - (IDEEditorContext *)lastActiveEditorContext; 111 | @end 112 | 113 | @interface IDEWorkspaceWindowController : NSObject 114 | @property (readonly) IDEWorkspaceTabController *activeWorkspaceTabController; 115 | - (IDEEditorArea *)editorArea; 116 | @end 117 | 118 | @interface IDEWorkspace : NSObject 119 | @property (readonly) DVTFilePath *representingFilePath; 120 | @end 121 | 122 | @interface IDEWorkspaceDocument : NSDocument 123 | @property (readonly) IDEWorkspace *workspace; 124 | @end 125 | 126 | @interface TRVSXcode : NSObject 127 | 128 | + (IDESourceCodeDocument *)sourceCodeDocument; 129 | + (NSTextView *)textView; 130 | + (BOOL)textViewHasSelection; 131 | + (NSRange)wholeRangeOfTextView; 132 | + (NSArray *)selectedFileNavigableItems; 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /ClangFormat/TRVSXcode.m: -------------------------------------------------------------------------------- 1 | // 2 | // TRVSXcode.m 3 | // ClangFormat 4 | // 5 | // Created by Travis Jeffery on 1/9/14. 6 | // Copyright (c) 2014 Travis Jeffery. All rights reserved. 7 | // 8 | 9 | #import "TRVSXcode.h" 10 | 11 | @implementation TRVSXcode 12 | 13 | + (id)currentEditor { 14 | if ([[self windowController] 15 | isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) { 16 | IDEWorkspaceWindowController *workspaceController = 17 | (IDEWorkspaceWindowController *)[self windowController]; 18 | IDEEditorArea *editorArea = [workspaceController editorArea]; 19 | IDEEditorContext *editorContext = [editorArea lastActiveEditorContext]; 20 | return [editorContext editor]; 21 | } 22 | return nil; 23 | } 24 | 25 | + (IDESourceCodeDocument *)sourceCodeDocument { 26 | if ([[self currentEditor] 27 | isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) { 28 | return [[self currentEditor] sourceCodeDocument]; 29 | } 30 | 31 | if ([[self currentEditor] 32 | isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")] && 33 | [[[self currentEditor] primaryDocument] 34 | isKindOfClass:NSClassFromString(@"IDESourceCodeDocument")]) { 35 | return (IDESourceCodeDocument *)[[self currentEditor] primaryDocument]; 36 | } 37 | 38 | return nil; 39 | } 40 | 41 | + (NSTextView *)textView { 42 | if ([[self currentEditor] 43 | isKindOfClass:NSClassFromString(@"IDESourceCodeEditor")]) { 44 | return [[self currentEditor] textView]; 45 | } 46 | 47 | if ([[self currentEditor] 48 | isKindOfClass:NSClassFromString(@"IDESourceCodeComparisonEditor")]) { 49 | return [[self currentEditor] keyTextView]; 50 | } 51 | 52 | return nil; 53 | } 54 | 55 | + (BOOL)textViewHasSelection { 56 | return [[self textView] selectedRange].length > 0; 57 | } 58 | 59 | + (NSRange)wholeRangeOfTextView { 60 | return NSMakeRange(0, [[[self textView] textStorage] length]); 61 | } 62 | 63 | + (NSArray *)selectedFileNavigableItems { 64 | if (![[self windowController] 65 | isKindOfClass:NSClassFromString(@"IDEWorkspaceWindowController")]) 66 | return nil; 67 | 68 | IDEWorkspaceWindowController *workspaceController = 69 | (IDEWorkspaceWindowController *)[self windowController]; 70 | IDEWorkspaceTabController *workspaceTabController = 71 | [workspaceController activeWorkspaceTabController]; 72 | IDENavigatorArea *navigatorArea = [workspaceTabController navigatorArea]; 73 | id currentNavigator = [navigatorArea currentNavigator]; 74 | 75 | if (![currentNavigator 76 | isKindOfClass:NSClassFromString(@"IDEStructureNavigator")]) 77 | return nil; 78 | 79 | NSMutableArray *array = [NSMutableArray array]; 80 | 81 | [[currentNavigator selectedObjects] 82 | enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 83 | if (![obj isKindOfClass:NSClassFromString(@"IDEFileNavigableItem")]) 84 | return; 85 | 86 | IDEFileNavigableItem *fileNavigableItem = obj; 87 | NSString *uti = fileNavigableItem.documentType.identifier; 88 | if ([[NSWorkspace sharedWorkspace] 89 | type:uti 90 | conformsToType:(NSString *)kUTTypeSourceCode]) { 91 | [array addObject:fileNavigableItem]; 92 | } 93 | }]; 94 | 95 | return array; 96 | } 97 | 98 | + (NSWindowController *)windowController { 99 | return [[NSApp keyWindow] windowController]; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /ClangFormat/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Travis Jeffery 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ClangFormat-Xcode 2 | 3 | An Xcode plug-in to format your code using Clang's format tools, by [@travisjeffery](https://twitter.com/travisjeffery). 4 | 5 | With [clang-format](http://clang.llvm.org/docs/ClangFormat.html) you can use Clang to format your code to styles such as LLVM, Google, Chromium, Mozilla, WebKit, or your own configuration. 6 | 7 | ![usage](https://raw.github.com/travisjeffery/ClangFormat-Xcode/master/README/usage.png) 8 | 9 | ![demo](https://raw.github.com/travisjeffery/ClangFormat-Xcode/master/README/clangformat-xcode-demo.gif) 10 | 11 | 12 | ## Installation: 13 | 14 | :warning: From XCode 8+, unsigning is required in order to use community-made plugins. 15 | Check https://github.com/inket/update_xcode_plugins for more information. 16 | 17 | Install via [Alcatraz](http://alcatraz.io/). 18 | 19 | OR 20 | 21 | Clone this repo, build and run ClangFormat, restart Xcode. 22 | 23 | ## Removing ClangFormat 24 | 25 | To remove ClangFormat, run the following in your terminal: 26 | 27 | `rm -r "~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/ClangFormat.xcplugin"` 28 | 29 | Or just find the same file and move it to the trash. You'll need to restart Xcode after deleting the plugin. 30 | 31 | ## Usage: 32 | 33 | ### Format on save 34 | 35 | I.e., you press `command-s` and the file is formatted and wrote to disk. 36 | 37 | In the menu, open Edit > Clang Format > Click Format on save (a checkmark appears in this menu item indicicating that the feature is active.) 38 | 39 | ### Assign keyboard shortcuts 40 | 41 | You can assign your own keyboard shortcuts like so: 42 | 43 | - Open the System Preferences > Keyboard > Shortcuts > App Shortcuts > Click + 44 | - Set the application to be Xcode 45 | - Set the menu title to an action title, e.g. "Format File in Focus" 46 | - Set your shortcut 47 | 48 | In this example, we'll format the active file when `control-i` is pressed. 49 | 50 | ![assign keyboard shortcut](https://raw.github.com/travisjeffery/ClangFormat-Xcode/master/README/assign-keyboard-shortcut.png) 51 | 52 | ### Using your own style configuration 53 | 54 | By using Clang Format > File in the plug-in menu, Clang will look for the nearest `.clang-format` file from the input file. Most likely, you'll have a .clang-format file at the root of your project. 55 | 56 | [Here are the options for .clang-format and how they're configured](http://clang.llvm.org/docs/ClangFormatStyleOptions.html). Here's a [cool interactive website](http://clangformat.com/) to help you make your .clang-format file. 57 | 58 | If one of the built-in styles is close to what you want, you can bootstrap your own configuration with: 59 | 60 | `./bin/clang-format -style=llvm -dump-config > .clang-format` 61 | 62 | For example, this .clang-format is similar to the [Linux Kernel style](https://www.kernel.org/doc/Documentation/CodingStyle): 63 | 64 | ``` 65 | BasedOnStyle: LLVM 66 | IndentWidth: 8 67 | UseTab: Always 68 | BreakBeforeBraces: Linux 69 | AllowShortIfStatementsOnASingleLine: false 70 | IndentCaseLabels: false 71 | ``` 72 | 73 | And this is similar to Visual Studio's style: 74 | 75 | ``` 76 | UseTab: Never 77 | IndentWidth: 4 78 | BreakBeforeBraces: Allman 79 | AllowShortIfStatementsOnASingleLine: false 80 | IndentCaseLabels: false 81 | ColumnLimit: 0 82 | ``` 83 | -------------------------------------------------------------------------------- /README/assign-keyboard-shortcut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travisjeffery/ClangFormat-Xcode/52205b219251b6db05051fc2bae0243474d27bfe/README/assign-keyboard-shortcut.png -------------------------------------------------------------------------------- /README/clangformat-xcode-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travisjeffery/ClangFormat-Xcode/52205b219251b6db05051fc2bae0243474d27bfe/README/clangformat-xcode-demo.gif -------------------------------------------------------------------------------- /README/usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travisjeffery/ClangFormat-Xcode/52205b219251b6db05051fc2bae0243474d27bfe/README/usage.png -------------------------------------------------------------------------------- /bin/clang-format: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/travisjeffery/ClangFormat-Xcode/52205b219251b6db05051fc2bae0243474d27bfe/bin/clang-format --------------------------------------------------------------------------------