├── .gitignore ├── Icon.png ├── Icon.sketch ├── LICENSE ├── README.md ├── SwiftTools.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── dom.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── SwiftTools ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon_1024.jpg │ │ ├── icon_128.jpg │ │ ├── icon_16.jpg │ │ ├── icon_256 1.jpg │ │ ├── icon_256.jpg │ │ ├── icon_32 1.jpg │ │ ├── icon_32.jpg │ │ ├── icon_512 1.jpg │ │ ├── icon_512.jpg │ │ └── icon_64.jpg │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── ContentView.swift ├── Info.plist ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json └── SwiftTools.entitlements ├── SwiftToolsHelper ├── .gitignore ├── .swiftpm │ └── xcode │ │ └── xcshareddata │ │ └── xcschemes │ │ └── SwiftToolsHelper.xcscheme ├── Package.swift ├── README.md ├── Sources │ └── SwiftToolsHelper │ │ ├── Function.swift │ │ ├── LineType.swift │ │ ├── StringExtension.swift │ │ ├── SwiftToolsHelper.swift │ │ └── TypedLine.swift └── Tests │ ├── LinuxMain.swift │ └── SwiftToolsHelperTests │ ├── AlignEqualTests.swift │ ├── ColorLiteralToUIColorTests.swift │ ├── HexToUIColorTests.swift │ ├── ProtocolFromSelectedMethodsTests.swift │ ├── SortImportTests.swift │ ├── TypedLineTests.swift │ ├── UIColorToColorLiteralTests.swift │ └── XCTestManifests.swift └── SwiftToolsXcodeExtension ├── Info.plist ├── SourceEditorCommand.swift ├── SourceEditorExtension.swift └── SwiftToolsXcodeExtension.entitlements /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/xcode,swift,swiftpm 3 | # Edit at https://www.gitignore.io/?templates=xcode,swift,swiftpm 4 | 5 | ### Swift ### 6 | # Xcode 7 | # 8 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 9 | 10 | ## Build generated 11 | build/ 12 | DerivedData/ 13 | 14 | ## Various settings 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata/ 24 | 25 | ## Other 26 | *.moved-aside 27 | *.xccheckout 28 | *.xcscmblueprint 29 | 30 | ## Obj-C/Swift specific 31 | *.hmap 32 | *.ipa 33 | *.dSYM.zip 34 | *.dSYM 35 | 36 | ## Playgrounds 37 | timeline.xctimeline 38 | playground.xcworkspace 39 | 40 | # Swift Package Manager 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | .build/ 46 | # Add this line if you want to avoid checking in Xcode SPM integration. 47 | # .swiftpm/xcode 48 | 49 | # CocoaPods 50 | # We recommend against adding the Pods directory to your .gitignore. However 51 | # you should judge for yourself, the pros and cons are mentioned at: 52 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 53 | # Pods/ 54 | # Add this line if you want to avoid checking in source code from the Xcode workspace 55 | # *.xcworkspace 56 | 57 | # Carthage 58 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 59 | # Carthage/Checkouts 60 | 61 | Carthage/Build 62 | 63 | # Accio dependency management 64 | Dependencies/ 65 | .accio/ 66 | 67 | # fastlane 68 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 69 | # screenshots whenever they are needed. 70 | # For more information about the recommended setup visit: 71 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 72 | 73 | fastlane/report.xml 74 | fastlane/Preview.html 75 | fastlane/screenshots/**/*.png 76 | fastlane/test_output 77 | 78 | # Code Injection 79 | # After new code Injection tools there's a generated folder /iOSInjectionProject 80 | # https://github.com/johnno1962/injectionforxcode 81 | 82 | iOSInjectionProject/ 83 | 84 | ### SwiftPM ### 85 | Packages 86 | xcuserdata 87 | *.xcodeproj 88 | 89 | 90 | ### Xcode ### 91 | # Xcode 92 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 93 | 94 | ## User settings 95 | 96 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 97 | 98 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 99 | 100 | ## Xcode Patch 101 | *.xcodeproj/* 102 | !*.xcodeproj/project.pbxproj 103 | !*.xcodeproj/xcshareddata/ 104 | !*.xcworkspace/contents.xcworkspacedata 105 | /*.gcno 106 | 107 | ### Xcode Patch ### 108 | **/xcshareddata/WorkspaceSettings.xcsettings 109 | 110 | # End of https://www.gitignore.io/api/xcode,swift,swiftpm 111 | -------------------------------------------------------------------------------- /Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/Icon.png -------------------------------------------------------------------------------- /Icon.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/Icon.sketch -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dominik Hauser 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftTools 2 | Xcode extension for Swift code 3 | 4 | Included tools: 5 | 6 | ## Align Equals 7 | 8 | Before 9 | 10 | ``` 11 | enum Constants { 12 | static let github = "dasdom" 13 | static let twitterHandle = "dasdom" 14 | static let answerToEverything = 42 15 | } 16 | ``` 17 | 18 | After 19 | 20 | ``` 21 | enum Constants { 22 | static let github = "dasdom" 23 | static let twitterHandle = "dasdom" 24 | static let answerToEverything = 42 25 | } 26 | ``` 27 | 28 | ## Copy Protocol Declarations For Selected Methods To Clipboard 29 | 30 | Select these two methods 31 | 32 | ``` 33 | func foo(a: String, b: Int) { 34 | // foobar 35 | } 36 | 37 | func bar(map: MKMapView) -> Int { 38 | return 0 39 | } 40 | ``` 41 | 42 | and use this tool. The following code is copied to the clipboard: 43 | 44 | ``` 45 | protocol <#Protocol Name#> { 46 | func foo(a: String, b: Int) 47 | func bar(map: MKMapView) -> Int 48 | } 49 | ``` 50 | 51 | ## Hex To UIColor 52 | 53 | Select the following line in Xcode 54 | 55 | ``` 56 | // #af33d1 57 | ``` 58 | 59 | and select the tool. The following line is added below the selected line: 60 | 61 | ``` 62 | let <#name#> = UIColor(red: 0.686, green: 0.200, blue: 0.820, alpha: 1.000) 63 | ``` 64 | 65 | ## Sort Imports 66 | 67 | Before 68 | 69 | ``` 70 | import MapKit 71 | import Foo 72 | import UIKit 73 | import Bar 74 | import Foundation 75 | ``` 76 | 77 | After 78 | 79 | ``` 80 | import Foundation 81 | import MapKit 82 | import UIKit 83 | 84 | import Bar 85 | import Foo 86 | ``` 87 | 88 | # Author 89 | 90 | Dominik Hauser 91 | 92 | [@dasdom](https://twitter.com/dasdom) 93 | 94 | # Licence 95 | 96 | MIT 97 | -------------------------------------------------------------------------------- /SwiftTools.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F22D92B62405D2C80042B1F1 /* SwiftToolsHelper in Frameworks */ = {isa = PBXBuildFile; productRef = F22D92B52405D2C80042B1F1 /* SwiftToolsHelper */; }; 11 | F2A524C724018B0B009481D2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A524C624018B0B009481D2 /* AppDelegate.swift */; }; 12 | F2A524C924018B0B009481D2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A524C824018B0B009481D2 /* ContentView.swift */; }; 13 | F2A524CE24018B0E009481D2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F2A524CD24018B0E009481D2 /* Preview Assets.xcassets */; }; 14 | F2A524D124018B0E009481D2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F2A524CF24018B0E009481D2 /* Main.storyboard */; }; 15 | F2A524E024018B6E009481D2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2A524DF24018B6E009481D2 /* Cocoa.framework */; }; 16 | F2A524E324018B6E009481D2 /* SourceEditorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A524E224018B6E009481D2 /* SourceEditorExtension.swift */; }; 17 | F2A524E524018B6E009481D2 /* SourceEditorCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2A524E424018B6E009481D2 /* SourceEditorCommand.swift */; }; 18 | F2A524EA24018B6E009481D2 /* CodeTools.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = F2A524DD24018B6E009481D2 /* CodeTools.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 19 | F2D4B6CE2437D040002139BD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F2A524CA24018B0E009481D2 /* Assets.xcassets */; }; 20 | F2E1047825CE90EB0043B391 /* XcodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2E1047725CE90EB0043B391 /* XcodeKit.framework */; }; 21 | F2E1047925CE90EB0043B391 /* XcodeKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F2E1047725CE90EB0043B391 /* XcodeKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | F2A524E824018B6E009481D2 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = F2A524BB24018B0A009481D2 /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = F2A524DC24018B6E009481D2; 30 | remoteInfo = SwiftToolsXcodeExtension; 31 | }; 32 | /* End PBXContainerItemProxy section */ 33 | 34 | /* Begin PBXCopyFilesBuildPhase section */ 35 | F2A524EE24018B6E009481D2 /* Embed App Extensions */ = { 36 | isa = PBXCopyFilesBuildPhase; 37 | buildActionMask = 2147483647; 38 | dstPath = ""; 39 | dstSubfolderSpec = 13; 40 | files = ( 41 | F2A524EA24018B6E009481D2 /* CodeTools.appex in Embed App Extensions */, 42 | ); 43 | name = "Embed App Extensions"; 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | F2E1047A25CE90EB0043B391 /* Embed Frameworks */ = { 47 | isa = PBXCopyFilesBuildPhase; 48 | buildActionMask = 2147483647; 49 | dstPath = ""; 50 | dstSubfolderSpec = 10; 51 | files = ( 52 | F2E1047925CE90EB0043B391 /* XcodeKit.framework in Embed Frameworks */, 53 | ); 54 | name = "Embed Frameworks"; 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXCopyFilesBuildPhase section */ 58 | 59 | /* Begin PBXFileReference section */ 60 | F2A524C324018B0B009481D2 /* CodeTools!.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CodeTools!.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | F2A524C624018B0B009481D2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 62 | F2A524C824018B0B009481D2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 63 | F2A524CA24018B0E009481D2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 64 | F2A524CD24018B0E009481D2 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 65 | F2A524D024018B0E009481D2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 66 | F2A524D224018B0E009481D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | F2A524D324018B0E009481D2 /* SwiftTools.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftTools.entitlements; sourceTree = ""; }; 68 | F2A524DD24018B6E009481D2 /* CodeTools.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = CodeTools.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 69 | F2A524DF24018B6E009481D2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 70 | F2A524E224018B6E009481D2 /* SourceEditorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorExtension.swift; sourceTree = ""; }; 71 | F2A524E424018B6E009481D2 /* SourceEditorCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceEditorCommand.swift; sourceTree = ""; }; 72 | F2A524E624018B6E009481D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | F2A524E724018B6E009481D2 /* SwiftToolsXcodeExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftToolsXcodeExtension.entitlements; sourceTree = ""; }; 74 | F2A524EF24018DA2009481D2 /* SwiftToolsHelper */ = {isa = PBXFileReference; lastKnownFileType = folder; path = SwiftToolsHelper; sourceTree = ""; }; 75 | F2E1047725CE90EB0043B391 /* XcodeKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XcodeKit.framework; path = Library/Frameworks/XcodeKit.framework; sourceTree = DEVELOPER_DIR; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | F2A524C024018B0B009481D2 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | F2A524DA24018B6E009481D2 /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | F2E1047825CE90EB0043B391 /* XcodeKit.framework in Frameworks */, 91 | F22D92B62405D2C80042B1F1 /* SwiftToolsHelper in Frameworks */, 92 | F2A524E024018B6E009481D2 /* Cocoa.framework in Frameworks */, 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | /* End PBXFrameworksBuildPhase section */ 97 | 98 | /* Begin PBXGroup section */ 99 | F2A524BA24018B0A009481D2 = { 100 | isa = PBXGroup; 101 | children = ( 102 | F2A524EF24018DA2009481D2 /* SwiftToolsHelper */, 103 | F2A524C524018B0B009481D2 /* SwiftTools */, 104 | F2A524E124018B6E009481D2 /* SwiftToolsXcodeExtension */, 105 | F2A524DE24018B6E009481D2 /* Frameworks */, 106 | F2A524C424018B0B009481D2 /* Products */, 107 | ); 108 | sourceTree = ""; 109 | }; 110 | F2A524C424018B0B009481D2 /* Products */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | F2A524C324018B0B009481D2 /* CodeTools!.app */, 114 | F2A524DD24018B6E009481D2 /* CodeTools.appex */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | F2A524C524018B0B009481D2 /* SwiftTools */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | F2A524C624018B0B009481D2 /* AppDelegate.swift */, 123 | F2A524C824018B0B009481D2 /* ContentView.swift */, 124 | F2A524CA24018B0E009481D2 /* Assets.xcassets */, 125 | F2A524CF24018B0E009481D2 /* Main.storyboard */, 126 | F2A524D224018B0E009481D2 /* Info.plist */, 127 | F2A524D324018B0E009481D2 /* SwiftTools.entitlements */, 128 | F2A524CC24018B0E009481D2 /* Preview Content */, 129 | ); 130 | path = SwiftTools; 131 | sourceTree = ""; 132 | }; 133 | F2A524CC24018B0E009481D2 /* Preview Content */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | F2A524CD24018B0E009481D2 /* Preview Assets.xcassets */, 137 | ); 138 | path = "Preview Content"; 139 | sourceTree = ""; 140 | }; 141 | F2A524DE24018B6E009481D2 /* Frameworks */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | F2E1047725CE90EB0043B391 /* XcodeKit.framework */, 145 | F2A524DF24018B6E009481D2 /* Cocoa.framework */, 146 | ); 147 | name = Frameworks; 148 | sourceTree = ""; 149 | }; 150 | F2A524E124018B6E009481D2 /* SwiftToolsXcodeExtension */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | F2A524E224018B6E009481D2 /* SourceEditorExtension.swift */, 154 | F2A524E424018B6E009481D2 /* SourceEditorCommand.swift */, 155 | F2A524E624018B6E009481D2 /* Info.plist */, 156 | F2A524E724018B6E009481D2 /* SwiftToolsXcodeExtension.entitlements */, 157 | ); 158 | path = SwiftToolsXcodeExtension; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | F2A524C224018B0B009481D2 /* SwiftTools */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = F2A524D624018B0E009481D2 /* Build configuration list for PBXNativeTarget "SwiftTools" */; 167 | buildPhases = ( 168 | F2A524BF24018B0B009481D2 /* Sources */, 169 | F2A524C024018B0B009481D2 /* Frameworks */, 170 | F2A524C124018B0B009481D2 /* Resources */, 171 | F2A524EE24018B6E009481D2 /* Embed App Extensions */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | F2A524E924018B6E009481D2 /* PBXTargetDependency */, 177 | ); 178 | name = SwiftTools; 179 | packageProductDependencies = ( 180 | ); 181 | productName = SwiftTools; 182 | productReference = F2A524C324018B0B009481D2 /* CodeTools!.app */; 183 | productType = "com.apple.product-type.application"; 184 | }; 185 | F2A524DC24018B6E009481D2 /* SwiftToolsXcodeExtension */ = { 186 | isa = PBXNativeTarget; 187 | buildConfigurationList = F2A524EB24018B6E009481D2 /* Build configuration list for PBXNativeTarget "SwiftToolsXcodeExtension" */; 188 | buildPhases = ( 189 | F2A524D924018B6E009481D2 /* Sources */, 190 | F2A524DA24018B6E009481D2 /* Frameworks */, 191 | F2A524DB24018B6E009481D2 /* Resources */, 192 | F2E1047A25CE90EB0043B391 /* Embed Frameworks */, 193 | ); 194 | buildRules = ( 195 | ); 196 | dependencies = ( 197 | ); 198 | name = SwiftToolsXcodeExtension; 199 | packageProductDependencies = ( 200 | F22D92B52405D2C80042B1F1 /* SwiftToolsHelper */, 201 | ); 202 | productName = SwiftToolsXcodeExtension; 203 | productReference = F2A524DD24018B6E009481D2 /* CodeTools.appex */; 204 | productType = "com.apple.product-type.xcode-extension"; 205 | }; 206 | /* End PBXNativeTarget section */ 207 | 208 | /* Begin PBXProject section */ 209 | F2A524BB24018B0A009481D2 /* Project object */ = { 210 | isa = PBXProject; 211 | attributes = { 212 | LastSwiftUpdateCheck = 1140; 213 | LastUpgradeCheck = 1140; 214 | ORGANIZATIONNAME = dasdom; 215 | TargetAttributes = { 216 | F2A524C224018B0B009481D2 = { 217 | CreatedOnToolsVersion = 11.4; 218 | }; 219 | F2A524DC24018B6E009481D2 = { 220 | CreatedOnToolsVersion = 11.4; 221 | }; 222 | }; 223 | }; 224 | buildConfigurationList = F2A524BE24018B0A009481D2 /* Build configuration list for PBXProject "SwiftTools" */; 225 | compatibilityVersion = "Xcode 9.3"; 226 | developmentRegion = en; 227 | hasScannedForEncodings = 0; 228 | knownRegions = ( 229 | en, 230 | Base, 231 | ); 232 | mainGroup = F2A524BA24018B0A009481D2; 233 | productRefGroup = F2A524C424018B0B009481D2 /* Products */; 234 | projectDirPath = ""; 235 | projectRoot = ""; 236 | targets = ( 237 | F2A524C224018B0B009481D2 /* SwiftTools */, 238 | F2A524DC24018B6E009481D2 /* SwiftToolsXcodeExtension */, 239 | ); 240 | }; 241 | /* End PBXProject section */ 242 | 243 | /* Begin PBXResourcesBuildPhase section */ 244 | F2A524C124018B0B009481D2 /* Resources */ = { 245 | isa = PBXResourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | F2A524D124018B0E009481D2 /* Main.storyboard in Resources */, 249 | F2D4B6CE2437D040002139BD /* Assets.xcassets in Resources */, 250 | F2A524CE24018B0E009481D2 /* Preview Assets.xcassets in Resources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | F2A524DB24018B6E009481D2 /* Resources */ = { 255 | isa = PBXResourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | /* End PBXResourcesBuildPhase section */ 262 | 263 | /* Begin PBXSourcesBuildPhase section */ 264 | F2A524BF24018B0B009481D2 /* Sources */ = { 265 | isa = PBXSourcesBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | F2A524C924018B0B009481D2 /* ContentView.swift in Sources */, 269 | F2A524C724018B0B009481D2 /* AppDelegate.swift in Sources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | F2A524D924018B6E009481D2 /* Sources */ = { 274 | isa = PBXSourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | F2A524E324018B6E009481D2 /* SourceEditorExtension.swift in Sources */, 278 | F2A524E524018B6E009481D2 /* SourceEditorCommand.swift in Sources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXSourcesBuildPhase section */ 283 | 284 | /* Begin PBXTargetDependency section */ 285 | F2A524E924018B6E009481D2 /* PBXTargetDependency */ = { 286 | isa = PBXTargetDependency; 287 | target = F2A524DC24018B6E009481D2 /* SwiftToolsXcodeExtension */; 288 | targetProxy = F2A524E824018B6E009481D2 /* PBXContainerItemProxy */; 289 | }; 290 | /* End PBXTargetDependency section */ 291 | 292 | /* Begin PBXVariantGroup section */ 293 | F2A524CF24018B0E009481D2 /* Main.storyboard */ = { 294 | isa = PBXVariantGroup; 295 | children = ( 296 | F2A524D024018B0E009481D2 /* Base */, 297 | ); 298 | name = Main.storyboard; 299 | sourceTree = ""; 300 | }; 301 | /* End PBXVariantGroup section */ 302 | 303 | /* Begin XCBuildConfiguration section */ 304 | F2A524D424018B0E009481D2 /* Debug */ = { 305 | isa = XCBuildConfiguration; 306 | buildSettings = { 307 | ALWAYS_SEARCH_USER_PATHS = NO; 308 | CLANG_ANALYZER_NONNULL = YES; 309 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 310 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 311 | CLANG_CXX_LIBRARY = "libc++"; 312 | CLANG_ENABLE_MODULES = YES; 313 | CLANG_ENABLE_OBJC_ARC = YES; 314 | CLANG_ENABLE_OBJC_WEAK = YES; 315 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 316 | CLANG_WARN_BOOL_CONVERSION = YES; 317 | CLANG_WARN_COMMA = YES; 318 | CLANG_WARN_CONSTANT_CONVERSION = YES; 319 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 320 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 321 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 322 | CLANG_WARN_EMPTY_BODY = YES; 323 | CLANG_WARN_ENUM_CONVERSION = YES; 324 | CLANG_WARN_INFINITE_RECURSION = YES; 325 | CLANG_WARN_INT_CONVERSION = YES; 326 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 327 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 331 | CLANG_WARN_STRICT_PROTOTYPES = YES; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 334 | CLANG_WARN_UNREACHABLE_CODE = YES; 335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = dwarf; 338 | ENABLE_STRICT_OBJC_MSGSEND = YES; 339 | ENABLE_TESTABILITY = YES; 340 | GCC_C_LANGUAGE_STANDARD = gnu11; 341 | GCC_DYNAMIC_NO_PIC = NO; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_OPTIMIZATION_LEVEL = 0; 344 | GCC_PREPROCESSOR_DEFINITIONS = ( 345 | "DEBUG=1", 346 | "$(inherited)", 347 | ); 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | MACOSX_DEPLOYMENT_TARGET = 10.15; 355 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 356 | MTL_FAST_MATH = YES; 357 | ONLY_ACTIVE_ARCH = YES; 358 | SDKROOT = macosx; 359 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 360 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 361 | }; 362 | name = Debug; 363 | }; 364 | F2A524D524018B0E009481D2 /* Release */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ALWAYS_SEARCH_USER_PATHS = NO; 368 | CLANG_ANALYZER_NONNULL = YES; 369 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 371 | CLANG_CXX_LIBRARY = "libc++"; 372 | CLANG_ENABLE_MODULES = YES; 373 | CLANG_ENABLE_OBJC_ARC = YES; 374 | CLANG_ENABLE_OBJC_WEAK = YES; 375 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_COMMA = YES; 378 | CLANG_WARN_CONSTANT_CONVERSION = YES; 379 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 380 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 381 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 382 | CLANG_WARN_EMPTY_BODY = YES; 383 | CLANG_WARN_ENUM_CONVERSION = YES; 384 | CLANG_WARN_INFINITE_RECURSION = YES; 385 | CLANG_WARN_INT_CONVERSION = YES; 386 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 387 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 388 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 389 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 390 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 391 | CLANG_WARN_STRICT_PROTOTYPES = YES; 392 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 393 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 394 | CLANG_WARN_UNREACHABLE_CODE = YES; 395 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 396 | COPY_PHASE_STRIP = NO; 397 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 398 | ENABLE_NS_ASSERTIONS = NO; 399 | ENABLE_STRICT_OBJC_MSGSEND = YES; 400 | GCC_C_LANGUAGE_STANDARD = gnu11; 401 | GCC_NO_COMMON_BLOCKS = YES; 402 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 404 | GCC_WARN_UNDECLARED_SELECTOR = YES; 405 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 406 | GCC_WARN_UNUSED_FUNCTION = YES; 407 | GCC_WARN_UNUSED_VARIABLE = YES; 408 | MACOSX_DEPLOYMENT_TARGET = 10.15; 409 | MTL_ENABLE_DEBUG_INFO = NO; 410 | MTL_FAST_MATH = YES; 411 | SDKROOT = macosx; 412 | SWIFT_COMPILATION_MODE = wholemodule; 413 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 414 | }; 415 | name = Release; 416 | }; 417 | F2A524D724018B0E009481D2 /* Debug */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 421 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 422 | CODE_SIGN_ENTITLEMENTS = SwiftTools/SwiftTools.entitlements; 423 | CODE_SIGN_IDENTITY = "Apple Development"; 424 | CODE_SIGN_STYLE = Automatic; 425 | COMBINE_HIDPI_IMAGES = YES; 426 | CURRENT_PROJECT_VERSION = 14; 427 | DEVELOPMENT_ASSET_PATHS = "\"SwiftTools/Preview Content\""; 428 | DEVELOPMENT_TEAM = Q6PD97MRX4; 429 | ENABLE_HARDENED_RUNTIME = YES; 430 | ENABLE_PREVIEWS = YES; 431 | INFOPLIST_FILE = SwiftTools/Info.plist; 432 | LD_RUNPATH_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "@executable_path/../Frameworks", 435 | ); 436 | MACOSX_DEPLOYMENT_TARGET = 13.0; 437 | MARKETING_VERSION = 1.4.1; 438 | PRODUCT_BUNDLE_IDENTIFIER = de.dasdom.Bazinga; 439 | PRODUCT_NAME = "CodeTools!"; 440 | PROVISIONING_PROFILE_SPECIFIER = ""; 441 | SWIFT_VERSION = 5.0; 442 | }; 443 | name = Debug; 444 | }; 445 | F2A524D824018B0E009481D2 /* Release */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 450 | CODE_SIGN_ENTITLEMENTS = SwiftTools/SwiftTools.entitlements; 451 | CODE_SIGN_IDENTITY = "Apple Development"; 452 | CODE_SIGN_STYLE = Automatic; 453 | COMBINE_HIDPI_IMAGES = YES; 454 | CURRENT_PROJECT_VERSION = 14; 455 | DEVELOPMENT_ASSET_PATHS = "\"SwiftTools/Preview Content\""; 456 | DEVELOPMENT_TEAM = Q6PD97MRX4; 457 | ENABLE_HARDENED_RUNTIME = YES; 458 | ENABLE_PREVIEWS = YES; 459 | INFOPLIST_FILE = SwiftTools/Info.plist; 460 | LD_RUNPATH_SEARCH_PATHS = ( 461 | "$(inherited)", 462 | "@executable_path/../Frameworks", 463 | ); 464 | MACOSX_DEPLOYMENT_TARGET = 13.0; 465 | MARKETING_VERSION = 1.4.1; 466 | PRODUCT_BUNDLE_IDENTIFIER = de.dasdom.Bazinga; 467 | PRODUCT_NAME = "CodeTools!"; 468 | PROVISIONING_PROFILE_SPECIFIER = ""; 469 | SWIFT_VERSION = 5.0; 470 | }; 471 | name = Release; 472 | }; 473 | F2A524EC24018B6E009481D2 /* Debug */ = { 474 | isa = XCBuildConfiguration; 475 | buildSettings = { 476 | CODE_SIGN_ENTITLEMENTS = SwiftToolsXcodeExtension/SwiftToolsXcodeExtension.entitlements; 477 | CODE_SIGN_IDENTITY = "Apple Development"; 478 | CODE_SIGN_STYLE = Automatic; 479 | COMBINE_HIDPI_IMAGES = YES; 480 | CURRENT_PROJECT_VERSION = 14; 481 | DEVELOPMENT_TEAM = Q6PD97MRX4; 482 | ENABLE_HARDENED_RUNTIME = YES; 483 | INFOPLIST_FILE = SwiftToolsXcodeExtension/Info.plist; 484 | LD_RUNPATH_SEARCH_PATHS = ( 485 | "$(inherited)", 486 | "@executable_path/../Frameworks", 487 | "@executable_path/../../../../Frameworks", 488 | ); 489 | MACOSX_DEPLOYMENT_TARGET = 13.0; 490 | MARKETING_VERSION = 1.4.1; 491 | PRODUCT_BUNDLE_IDENTIFIER = de.dasdom.Bazinga.SwiftToolsXcodeExtension; 492 | PRODUCT_NAME = CodeTools; 493 | PROVISIONING_PROFILE_SPECIFIER = ""; 494 | SKIP_INSTALL = YES; 495 | SWIFT_VERSION = 5.0; 496 | }; 497 | name = Debug; 498 | }; 499 | F2A524ED24018B6E009481D2 /* Release */ = { 500 | isa = XCBuildConfiguration; 501 | buildSettings = { 502 | CODE_SIGN_ENTITLEMENTS = SwiftToolsXcodeExtension/SwiftToolsXcodeExtension.entitlements; 503 | CODE_SIGN_IDENTITY = "Apple Development"; 504 | CODE_SIGN_STYLE = Automatic; 505 | COMBINE_HIDPI_IMAGES = YES; 506 | CURRENT_PROJECT_VERSION = 14; 507 | DEVELOPMENT_TEAM = Q6PD97MRX4; 508 | ENABLE_HARDENED_RUNTIME = YES; 509 | INFOPLIST_FILE = SwiftToolsXcodeExtension/Info.plist; 510 | LD_RUNPATH_SEARCH_PATHS = ( 511 | "$(inherited)", 512 | "@executable_path/../Frameworks", 513 | "@executable_path/../../../../Frameworks", 514 | ); 515 | MACOSX_DEPLOYMENT_TARGET = 13.0; 516 | MARKETING_VERSION = 1.4.1; 517 | PRODUCT_BUNDLE_IDENTIFIER = de.dasdom.Bazinga.SwiftToolsXcodeExtension; 518 | PRODUCT_NAME = CodeTools; 519 | PROVISIONING_PROFILE_SPECIFIER = ""; 520 | SKIP_INSTALL = YES; 521 | SWIFT_VERSION = 5.0; 522 | }; 523 | name = Release; 524 | }; 525 | /* End XCBuildConfiguration section */ 526 | 527 | /* Begin XCConfigurationList section */ 528 | F2A524BE24018B0A009481D2 /* Build configuration list for PBXProject "SwiftTools" */ = { 529 | isa = XCConfigurationList; 530 | buildConfigurations = ( 531 | F2A524D424018B0E009481D2 /* Debug */, 532 | F2A524D524018B0E009481D2 /* Release */, 533 | ); 534 | defaultConfigurationIsVisible = 0; 535 | defaultConfigurationName = Release; 536 | }; 537 | F2A524D624018B0E009481D2 /* Build configuration list for PBXNativeTarget "SwiftTools" */ = { 538 | isa = XCConfigurationList; 539 | buildConfigurations = ( 540 | F2A524D724018B0E009481D2 /* Debug */, 541 | F2A524D824018B0E009481D2 /* Release */, 542 | ); 543 | defaultConfigurationIsVisible = 0; 544 | defaultConfigurationName = Release; 545 | }; 546 | F2A524EB24018B6E009481D2 /* Build configuration list for PBXNativeTarget "SwiftToolsXcodeExtension" */ = { 547 | isa = XCConfigurationList; 548 | buildConfigurations = ( 549 | F2A524EC24018B6E009481D2 /* Debug */, 550 | F2A524ED24018B6E009481D2 /* Release */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | /* End XCConfigurationList section */ 556 | 557 | /* Begin XCSwiftPackageProductDependency section */ 558 | F22D92B52405D2C80042B1F1 /* SwiftToolsHelper */ = { 559 | isa = XCSwiftPackageProductDependency; 560 | productName = SwiftToolsHelper; 561 | }; 562 | /* End XCSwiftPackageProductDependency section */ 563 | }; 564 | rootObject = F2A524BB24018B0A009481D2 /* Project object */; 565 | } 566 | -------------------------------------------------------------------------------- /SwiftTools.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftTools.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftTools.xcodeproj/xcuserdata/dom.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftTools.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | SwiftToolsXcodeExtension.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | F2A524C224018B0B009481D2 21 | 22 | primary 23 | 24 | 25 | F2A524DC24018B6E009481D2 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SwiftTools/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // Copyright © 2020 dasdom. All rights reserved. 3 | // 4 | 5 | import Cocoa 6 | import SwiftUI 7 | 8 | @NSApplicationMain 9 | class AppDelegate: NSObject, NSApplicationDelegate { 10 | 11 | var window: NSWindow! 12 | 13 | func applicationDidFinishLaunching(_ aNotification: Notification) { 14 | // Create the SwiftUI view that provides the window contents. 15 | let contentView = ContentView() 16 | 17 | // Create the window and set the content view. 18 | window = NSWindow( 19 | contentRect: NSRect(x: 0, y: 0, width: 800, height: 900), 20 | styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], 21 | backing: .buffered, defer: false) 22 | window.center() 23 | window.setFrameAutosaveName("Main Window") 24 | window.contentView = NSHostingView(rootView: contentView) 25 | window.makeKeyAndOrderFront(nil) 26 | } 27 | 28 | func applicationWillTerminate(_ aNotification: Notification) { 29 | // Insert code here to tear down your application 30 | } 31 | 32 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 33 | return true 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_16.jpg", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon_32 1.jpg", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon_32.jpg", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon_64.jpg", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon_128.jpg", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon_256 1.jpg", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon_256.jpg", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon_512 1.jpg", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon_512.jpg", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon_1024.jpg", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_1024.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_128.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_16.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_256 1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_256 1.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_256.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_256.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_32 1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_32 1.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_32.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_512 1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_512 1.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_512.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_512.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dasdom/SwiftTools/745b809da306ea326e8883119a6d80e9421bbffb/SwiftTools/Assets.xcassets/AppIcon.appiconset/icon_64.jpg -------------------------------------------------------------------------------- /SwiftTools/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftTools/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /SwiftTools/ContentView.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // Copyright © 2020 dasdom. All rights reserved. 3 | // 4 | 5 | import SwiftUI 6 | 7 | struct ContentView: View { 8 | var body: some View { 9 | VStack(alignment: .leading) { 10 | Text("A selection of Xcode tools for Swift code.") 11 | .font(.headline) 12 | .padding([.top, .bottom]) 13 | Text(""" 14 | The following tools are included: 15 | 16 | - Align equals 17 | - Color Literal to UIColor 18 | - Copy Protocol Declarations For Selected Methods To Clipboard 19 | - Hex to UIColor 20 | - UIColor to Color Literal 21 | - Sort Imports 22 | """) 23 | Text("\nTo activate the tools, open System Preferences > Extensions > Xcode Source Editor and check the check box at CodeTools.") 24 | Spacer() 25 | Text("You can find the code for this Xcode extension at: https://github.com/dasdom/SwiftTools") 26 | Text("dominik.hauser@dasdom.de") 27 | } 28 | .padding() 29 | .frame(maxWidth: .infinity, maxHeight: .infinity) 30 | } 31 | } 32 | 33 | 34 | struct ContentView_Previews: PreviewProvider { 35 | static var previews: some View { 36 | ContentView() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SwiftTools/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | CodeTools 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSApplicationCategoryType 24 | public.app-category.developer-tools 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2020 dasdom. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | NSSupportsAutomaticTermination 34 | 35 | NSSupportsSuddenTermination 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /SwiftTools/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftTools/SwiftTools.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SwiftToolsHelper/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /SwiftToolsHelper/.swiftpm/xcode/xcshareddata/xcschemes/SwiftToolsHelper.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftToolsHelper", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "SwiftToolsHelper", 12 | targets: ["SwiftToolsHelper"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 21 | .target( 22 | name: "SwiftToolsHelper", 23 | dependencies: []), 24 | .testTarget( 25 | name: "SwiftToolsHelperTests", 26 | dependencies: ["SwiftToolsHelper"]), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /SwiftToolsHelper/README.md: -------------------------------------------------------------------------------- 1 | # SwiftToolsHelper 2 | 3 | A description of this package. 4 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Sources/SwiftToolsHelper/Function.swift: -------------------------------------------------------------------------------- 1 | // Created by Dominik Hauser on 07.06.24. 2 | // 3 | // 4 | 5 | 6 | import Foundation 7 | 8 | class Function { 9 | let name: String 10 | let comments: [TypedLine] 11 | var typedLines: [TypedLine] = [] 12 | 13 | init(name: String, comments: [TypedLine]) { 14 | self.name = name 15 | self.comments = comments 16 | } 17 | 18 | func lines() -> [String] { 19 | return comments.map({ $0.text }) + typedLines.map({ $0.text }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Sources/SwiftToolsHelper/LineType.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // 3 | // 4 | 5 | import Foundation 6 | 7 | enum LineType : String, Equatable { 8 | case startOfMultilineComment 9 | case endOfMultilineComment 10 | case withinMultilineComment 11 | case inlineComment 12 | case inlineFuncDeclaration 13 | case startOfMultilineFuncDeclaration 14 | case endOfMultilineFuncDeclaration 15 | case withinMultilineFuncDeclaration 16 | case endOfFunc 17 | case otherCode 18 | case codeWithEquals 19 | case `import` 20 | case testableImport 21 | case uiColorDefinitionRedGreenBlue 22 | case colorLiteralDefinition 23 | case placeHolder 24 | } 25 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Sources/SwiftToolsHelper/StringExtension.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // 3 | // 4 | 5 | import Foundation 6 | 7 | extension String { 8 | 9 | func rangeOfFirstMatchOf(regex: String) -> NSRange { 10 | 11 | let range = NSRange(location: 0, length: self.utf16.count) 12 | let regex = try! NSRegularExpression(pattern: regex) 13 | return regex.rangeOfFirstMatch(in: self, options: [], range: range) 14 | } 15 | 16 | func isMatching(regex: String) -> Bool { 17 | return rangeOfFirstMatchOf(regex: regex).location != NSNotFound 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Sources/SwiftToolsHelper/SwiftToolsHelper.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import Cocoa 4 | 5 | public struct SwiftToolsHelper { 6 | 7 | public static func alignEquals(in lines: [String]) -> [String] { 8 | 9 | let typed = typedLines(from: lines) 10 | return alignEquals(in: typed) 11 | } 12 | 13 | public static func sort(in lines: [String]) -> [String] { 14 | let typed = typedLines(from: lines) 15 | return sort(in: typed) 16 | } 17 | 18 | public static func protocolFromMethods(in lines: [String]) { 19 | 20 | let typed = typedLines(from: lines) 21 | let protocolString = protocolFromMethods(in: typed) 22 | 23 | NSPasteboard.general.clearContents() 24 | NSPasteboard.general.setString(protocolString, forType: NSPasteboard.PasteboardType.string) 25 | } 26 | 27 | public static func hexToUIColor(for text: String) -> String { 28 | 29 | let range = text.range(of: "//") 30 | 31 | let scanner = Scanner(string: text) 32 | scanner.charactersToBeSkipped = NSCharacterSet.alphanumerics.inverted 33 | 34 | var rgbValue: UInt64 = 0 35 | scanner.scanHexInt64(&rgbValue) 36 | var r = CGFloat(0) 37 | var g = CGFloat(0) 38 | var b = CGFloat(0) 39 | var a = CGFloat(0) 40 | if rgbValue > 0xffffff { 41 | r = CGFloat((rgbValue & 0xFF000000) >> 24) / 255.0 42 | g = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0 43 | b = CGFloat((rgbValue & 0xFF00) >> 8) / 255.0 44 | a = CGFloat((rgbValue & 0xFF)) / 255.0 45 | } else { 46 | r = CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0 47 | g = CGFloat((rgbValue & 0xFF00) >> 8) / 255.0 48 | b = CGFloat((rgbValue & 0xFF)) / 255.0 49 | a = 1.0 50 | } 51 | 52 | var indentString = "" 53 | if range?.lowerBound != range?.upperBound { 54 | if let location = range?.lowerBound.utf16Offset(in: text) { 55 | for _ in 0.. = UIColor(red: %.3f, green: %.3f, blue: %.3f, alpha: %.3f)", indentString, r, g, b, a) 62 | } 63 | 64 | public static func uiColorToColorLiteral(for lines: [String]) -> [String] { 65 | 66 | let typed = typedLines(from: lines) 67 | return uiColorToColorLiteral(in: typed) 68 | } 69 | 70 | public static func colorLiteralToUIColor(for lines: [String]) -> [String] { 71 | 72 | let typed = typedLines(from: lines) 73 | return colorLiteralToUIColor(for: typed) 74 | } 75 | 76 | public static func sortImport(in lines: [String]) -> [String] { 77 | 78 | let typed = typedLines(from: lines) 79 | return sortImport(in: typed) 80 | } 81 | 82 | public static func sortFunctions(in lines: [String]) -> [String] { 83 | _ = typedLines(from: lines) 84 | var newLines = aboveFunctions.map({ $0.text }) 85 | 86 | newLines += nonEmptyOutsideOfFunction.map({ $0.text }) 87 | if nonEmptyOutsideOfFunction.count > 0 { 88 | newLines += ["\n"] 89 | } 90 | for function in functions.sorted(by: { $0.name < $1.name }) { 91 | newLines += function.lines() 92 | newLines += ["\n"] 93 | } 94 | if functions.count > 0 { 95 | newLines.removeLast() 96 | } 97 | 98 | newLines += afterFunctions.map({ $0.text }) 99 | return newLines 100 | } 101 | } 102 | 103 | extension SwiftToolsHelper { 104 | 105 | static var functions: [Function] = [] 106 | static var aboveFunctions: [TypedLine] = [] 107 | static var nonEmptyOutsideOfFunction: [TypedLine] = [] 108 | static var afterFunctions: [TypedLine] = [] 109 | 110 | static func typedLines(from lines: [String]) -> [TypedLine] { 111 | 112 | var typedLines: [TypedLine] = [] 113 | var inMultilineComment = false 114 | var inMultilineFuncDeclaration = false 115 | var scopeCount = 0 116 | // var inFunction = false 117 | var functionComment: [TypedLine] = [] 118 | var currentFunction: Function? 119 | var endOfFunction = false 120 | 121 | functions = [] 122 | aboveFunctions = [] 123 | nonEmptyOutsideOfFunction = [] 124 | afterFunctions = [] 125 | 126 | // var nonEmptyOutsideOfFunction: [TypedLine] = [] 127 | 128 | for line in lines { 129 | endOfFunction = false 130 | 131 | if line.isMatching(regex: "\\*/") { 132 | if inMultilineComment { 133 | inMultilineComment = false 134 | // } else { 135 | // var tempTypedLines: [TypedLine] = [] 136 | // let indexOfStart = typedLines.lastIndex(where: { $0.type == .startOfMultilineComment }) ?? -1 137 | // for (index, typedLine) in typedLines.enumerated() { 138 | // if indexOfStart < index { 139 | // tempTypedLines.append(TypedLine(type: .withinMultilineComment, text: typedLine.text)) 140 | // } else { 141 | // tempTypedLines.append(typedLine) 142 | // } 143 | // } 144 | // typedLines = tempTypedLines 145 | } 146 | let typedLine = TypedLine(type: .endOfMultilineComment, text: line) 147 | typedLines.append(typedLine) 148 | functionComment.append(typedLine) 149 | 150 | } else if line.isMatching(regex: "/\\*") { 151 | inMultilineComment = true 152 | let typedLine = TypedLine(type: .startOfMultilineComment, text: line) 153 | typedLines.append(typedLine) 154 | functionComment.append(typedLine) 155 | 156 | } else if inMultilineComment { 157 | let typedLine = TypedLine(type: .withinMultilineComment, text: line) 158 | typedLines.append(typedLine) 159 | functionComment.append(typedLine) 160 | 161 | } else if line.isMatching(regex: "$.*/{2,}") { 162 | let typedLine = TypedLine(type: .inlineComment, text: line) 163 | typedLines.append(typedLine) 164 | functionComment.append(typedLine) 165 | 166 | } else if line.isMatching(regex: "(func).+\\{") { 167 | let typedLine = TypedLine(type: .inlineFuncDeclaration, text: line) 168 | typedLines.append(typedLine) 169 | currentFunction = Function(name: line, comments: functionComment) 170 | 171 | functionComment = [] 172 | 173 | } else if line.isMatching(regex: "(func).+\\(") { 174 | inMultilineFuncDeclaration = true 175 | let typedLine = TypedLine(type: .startOfMultilineFuncDeclaration, text: line) 176 | typedLines.append(typedLine) 177 | currentFunction = Function(name: line, comments: functionComment) 178 | 179 | functionComment = [] 180 | 181 | } else if false == line.isMatching(regex: "\\{") && inMultilineFuncDeclaration { 182 | let typedLine = TypedLine(type: .withinMultilineFuncDeclaration, text: line) 183 | typedLines.append(typedLine) 184 | 185 | functionComment = [] 186 | 187 | } else if line.isMatching(regex: "=.*UIColor\\(red:.+green:.+blue:.+alpha:.+\\)") { 188 | let typedLine = TypedLine(type: .uiColorDefinitionRedGreenBlue, text: line) 189 | typedLines.append(typedLine) 190 | 191 | functionComment = [] 192 | 193 | } else if line.isMatching(regex: "=.*#colorLiteral\\(red.+green:.+blue:.+alpha:.+\\)") { 194 | let typedLine = TypedLine(type: .colorLiteralDefinition, text: line) 195 | typedLines.append(typedLine) 196 | 197 | functionComment = [] 198 | 199 | } else if line.isMatching(regex: " \\{") && inMultilineFuncDeclaration { 200 | inMultilineFuncDeclaration = false 201 | let typedLine = TypedLine(type: .endOfMultilineFuncDeclaration, text: line) 202 | typedLines.append(typedLine) 203 | 204 | functionComment = [] 205 | 206 | } else if line.isMatching(regex: "#>") && line.isMatching(regex: "<#") { 207 | let typedLine = TypedLine(type: .placeHolder, text: line) 208 | typedLines.append(typedLine) 209 | 210 | functionComment = [] 211 | 212 | } else if line.isMatching(regex: "\\s+=\\s+") && false == line.isMatching(regex: ".if.") { 213 | let typedLine = TypedLine(type: .codeWithEquals, text: line) 214 | typedLines.append(typedLine) 215 | 216 | functionComment = [] 217 | 218 | } else if line.isMatching(regex: "^import") { 219 | let typedLine = TypedLine(type: .import, text: line) 220 | typedLines.append(typedLine) 221 | 222 | functionComment = [] 223 | 224 | } else if line.isMatching(regex: "^@testable import") { 225 | let typedLine = TypedLine(type: .testableImport, text: line) 226 | typedLines.append(typedLine) 227 | 228 | functionComment = [] 229 | 230 | } else if line.isMatching(regex: "\\}.*if.*\\{") { 231 | let typedLine = TypedLine(type: .otherCode, text: line) 232 | typedLines.append(typedLine) 233 | 234 | functionComment = [] 235 | 236 | } else if line.isMatching(regex: " \\{") && false == line.isMatching(regex: "\\}") && nil != currentFunction { 237 | scopeCount += 1 238 | let typedLine = TypedLine(type: .otherCode, text: line) 239 | typedLines.append(typedLine) 240 | 241 | } else if line.isMatching(regex: "\\}") && nil != currentFunction { 242 | if scopeCount == 0 { 243 | let typedLine = TypedLine(type: .endOfFunc, text: line) 244 | typedLines.append(typedLine) 245 | if let currentFunction { 246 | currentFunction.typedLines.append(typedLine) 247 | functions.append(currentFunction) 248 | let nonEmptyLines = afterFunctions.filter({ $0.text.isMatching(regex: "^.*\\S+.*$") }) 249 | nonEmptyOutsideOfFunction.append(contentsOf: nonEmptyLines) 250 | afterFunctions = [] 251 | } 252 | currentFunction = nil 253 | endOfFunction = true 254 | } else { 255 | let typedLine = TypedLine(type: .otherCode, text: line) 256 | typedLines.append(typedLine) 257 | scopeCount -= 1 258 | } 259 | 260 | } else { 261 | let typedLine = TypedLine(type: .otherCode, text: line) 262 | typedLines.append(typedLine) 263 | 264 | functionComment = [] 265 | 266 | } 267 | 268 | if functions.isEmpty && nil == currentFunction { 269 | let typedLine = TypedLine(type: .otherCode, text: line) 270 | aboveFunctions.append(typedLine) 271 | // } else if line.isMatching(regex: "^.*\\S+.*$") && line != "\n" && nil == currentFunction && false == endOfFunction { 272 | // let typedLine = TypedLine(type: .otherCode, text: line) 273 | // nonEmptyOutsideOfFunction.append(typedLine) 274 | } 275 | if false == functions.isEmpty && nil == currentFunction && false == endOfFunction { 276 | let typedLine = TypedLine(type: .otherCode, text: line) 277 | afterFunctions.append(typedLine) 278 | } 279 | 280 | if let currentFunction, 281 | let typedLine = typedLines.last { 282 | currentFunction.typedLines.append(typedLine) 283 | } 284 | } 285 | return typedLines 286 | } 287 | 288 | static func alignEquals(in typedLines: [TypedLine]) -> [String] { 289 | 290 | let normalizedLines = typedLines.map { typedLine -> TypedLine in 291 | 292 | if typedLine.type != .codeWithEquals && typedLine.type != .uiColorDefinitionRedGreenBlue { 293 | return typedLine 294 | } 295 | 296 | return replace(pattern: "\\s+=\\s+", with: " = ", in: typedLine) 297 | } 298 | 299 | let maxEqualPosition = maxOffsetOfFirst(character: "=", in: normalizedLines) 300 | 301 | let resultLinesText = normalizedLines.map { line -> String in 302 | 303 | let text = line.text 304 | if line.type != .codeWithEquals && line.type != .uiColorDefinitionRedGreenBlue { 305 | return text 306 | } 307 | 308 | if let index = text.firstIndex(of: "="), index.utf16Offset(in: text) < maxEqualPosition { 309 | var spaces = "" 310 | for _ in 0.. {\n\(rawlines)\n}\n" 338 | } 339 | 340 | static func sortImport(in lines: [TypedLine]) -> [String] { 341 | 342 | let sortedImportLines = lines.filter({ $0.type == .import }).sorted(by: { $0.text < $1.text }) 343 | let sortedTestableImportLines = lines.filter({ $0.type == .testableImport }).sorted(by: { $0.text < $1.text }) 344 | 345 | let firstParty = appleFrameworks() 346 | 347 | var sortedFirstPartyImportLines: [TypedLine] = [] 348 | var sortedThirdPartyImportLines: [TypedLine] = [] 349 | for importLine in sortedImportLines { 350 | if let framework = importLine.text.components(separatedBy: " ").last?.trimmingCharacters(in: .whitespacesAndNewlines) { 351 | // print("framework: \(framework)") 352 | if firstParty.contains(framework) { 353 | sortedFirstPartyImportLines.append(importLine) 354 | } else { 355 | sortedThirdPartyImportLines.append(importLine) 356 | } 357 | } 358 | } 359 | 360 | guard let indexOfFirstImport = lines.firstIndex(where: { $0.type == .import || $0.type == .testableImport }) else { 361 | return lines.map({ $0.text }) 362 | } 363 | 364 | guard let indexOfLastImport = lines.lastIndex(where: { $0.type == .import || $0.type == .testableImport }) else { 365 | return lines.map({ $0.text }) 366 | } 367 | 368 | 369 | var typedWithSortedImport = lines.filter({ $0.type != .import && $0.type != .testableImport }) 370 | 371 | let numberOfNonImportLinesInGroupOfImports = indexOfLastImport - indexOfFirstImport - (sortedFirstPartyImportLines.count + sortedThirdPartyImportLines.count + sortedTestableImportLines.count) 372 | 373 | if numberOfNonImportLinesInGroupOfImports == 0 { 374 | if typedWithSortedImport[indexOfFirstImport].text == "\n" { 375 | typedWithSortedImport.remove(at: indexOfFirstImport) 376 | } 377 | } 378 | 379 | if numberOfNonImportLinesInGroupOfImports == 2 { 380 | if typedWithSortedImport[indexOfFirstImport].text == "\n" { 381 | typedWithSortedImport.remove(at: indexOfFirstImport) 382 | } 383 | if typedWithSortedImport[indexOfFirstImport+1].text == "\n" { 384 | typedWithSortedImport.remove(at: indexOfFirstImport+1) 385 | } 386 | } 387 | 388 | var imports: [TypedLine] = [] 389 | if sortedFirstPartyImportLines.count > 0 { 390 | imports.append(contentsOf: sortedFirstPartyImportLines) 391 | } 392 | if sortedTestableImportLines.count > 0 { 393 | if imports.count > 0 { 394 | imports.append(TypedLine(type: .otherCode, text: "")) 395 | } 396 | imports.append(contentsOf: sortedTestableImportLines) 397 | } 398 | if sortedThirdPartyImportLines.count > 0 { 399 | if imports.count > 0 { 400 | imports.append(TypedLine(type: .otherCode, text: "")) 401 | } 402 | imports.append(contentsOf: sortedThirdPartyImportLines) 403 | } 404 | 405 | typedWithSortedImport.insert(contentsOf: imports, at: indexOfFirstImport) 406 | return typedWithSortedImport.map({ $0.text }) 407 | } 408 | 409 | static func sort(in lines: [TypedLine]) -> [String] { 410 | return lines.sorted(by: { $0.text < $1.text }).map({ $0.text }) 411 | } 412 | 413 | static func uiColorToColorLiteral(in lines: [TypedLine]) -> [String] { 414 | 415 | var result: [String] = [] 416 | for line in lines { 417 | if line.type == .uiColorDefinitionRedGreenBlue { 418 | result.append(line.text.replacingOccurrences(of: "UIColor", with: "#colorLiteral")) 419 | } else { 420 | result.append(line.text) 421 | } 422 | } 423 | return result 424 | } 425 | 426 | static func colorLiteralToUIColor(for lines: [TypedLine]) -> [String] { 427 | 428 | var result: [String] = [] 429 | for line in lines { 430 | if line.type == .colorLiteralDefinition { 431 | result.append(line.text.replacingOccurrences(of: "#colorLiteral", with: "UIColor")) 432 | } else { 433 | result.append(line.text) 434 | } 435 | } 436 | return result 437 | } 438 | } 439 | 440 | // MARK: - Helper Methods 441 | extension SwiftToolsHelper { 442 | static func replace(pattern: String, with replacement: String, in typedLine: TypedLine) -> TypedLine { 443 | let text = typedLine.text 444 | let equalRange = text.rangeOfFirstMatchOf(regex: pattern) 445 | let normalizedLine = text.replacingCharacters(in: Range(equalRange, in: text)!, with: " = ") 446 | return TypedLine(type: typedLine.type, text: normalizedLine) 447 | } 448 | 449 | static func maxOffsetOfFirst(character: Character, in typedLines: [TypedLine]) -> Int { 450 | 451 | let maxOffset = typedLines.reduce(0) { result, nextLine in 452 | 453 | let text = nextLine.text 454 | if let index = text.firstIndex(of: character) { 455 | return max(result, index.utf16Offset(in: text)) 456 | } else { 457 | return result 458 | } 459 | } 460 | return maxOffset 461 | } 462 | 463 | static func appleFrameworks() -> [String] { 464 | return ["Cocoa", 465 | "Foundation", 466 | "Swift", 467 | "SwiftUI", 468 | "TVML", 469 | "TVMLKit", 470 | "TVUIKit", 471 | "UIKit", 472 | "WatchKit", 473 | 474 | "AGL", 475 | "ARKit", 476 | "ColorSync", 477 | "CoreAnimation", 478 | "CoreGraphics", 479 | "CoreImage", 480 | "GameController", 481 | "GameKit", 482 | "GameplayKit", 483 | "GLKit", 484 | "ImageIO", 485 | "Metal", 486 | "MetalPerformanceShaders", 487 | "MetalKit", 488 | "ModelIO", 489 | "OpenGL", 490 | "PDFKit", 491 | "PencilKit", 492 | "Quartz", 493 | "RealityKit", 494 | "ReplayKit", 495 | "SceneKit", 496 | "SpriteKit", 497 | "Vision", 498 | 499 | "Accounts", 500 | "AddressBook", 501 | "AddressBookUI", 502 | "ApplicationServices", 503 | "AutomaticAssessmentConfiguration", 504 | "BackgroundTasks", 505 | "BusinessChat", 506 | "CallKit", 507 | "CareKit", 508 | "CarPlay", 509 | "ClassKit", 510 | "ClockKit", 511 | "CloudKit", 512 | "Combine", 513 | "Contacts", 514 | "ContactsUI", 515 | "CoreData", 516 | "CoreFoundation", 517 | "CoreLocation", 518 | "CoreML", 519 | "CoreMotion", 520 | "CoreSpotlight", 521 | "CoreText", 522 | "CreateML", 523 | "DeviceCheck", 524 | "EventKit", 525 | "EventKitUI", 526 | "FileProvider", 527 | "FileProviderUI", 528 | "HealthKit", 529 | "HomeKit", 530 | "iAd", 531 | "JavaScriptCore", 532 | "MapKit", 533 | "Messages", 534 | "MessageUI", 535 | "MultipeerConnectivity", 536 | "NaturalLanguage", 537 | "NewsstandKit", 538 | "NotificationCenter", 539 | "PassKit", 540 | "PreferencePanes", 541 | "PushKit", 542 | "QuickLook", 543 | "QuickLookThumbnailing", 544 | "SafariServices", 545 | "SiriKit", 546 | "Social", 547 | "Speech", 548 | "StoreKit", 549 | "TVServices", 550 | "UserNotifications", 551 | "UserNotificationsUI", 552 | "WatchConnectivity", 553 | "WebKit", 554 | 555 | "AssetsLibrary", 556 | "AudioToolbox", 557 | "AudioUnit", 558 | "AVFoundation", 559 | "AVKit", 560 | "CoreAudio", 561 | "CoreAudioKit", 562 | "CoreAudioTypes", 563 | "CoreHaptics", 564 | "CoreMedia", 565 | "CoreMIDI", 566 | "CoreVideo", 567 | "ImageCaptureCore", 568 | "iTunesLibrary", 569 | "MediaPlayer", 570 | "MediaAccessibility", 571 | "MediaLibrary", 572 | "PhotoKit", 573 | "QTKit", 574 | "ScreenSaver", 575 | "SoundAnalysis", 576 | "VideoToolbox", 577 | "VisionKit", 578 | 579 | "Accelerate", 580 | "CryptoKit", 581 | "AuthenticationServices", 582 | "CFNetwork", 583 | "Collaboration", 584 | "Compression", 585 | "CoreBluetooth", 586 | "CoreNFC", 587 | "CoreServices", 588 | "CoreTelephony", 589 | "CoreWLAN", 590 | "CryptoTokenKit", 591 | "DarwinNotify", 592 | "Device Management", 593 | "DiskArbitration", 594 | "Dispatch", 595 | "dnssd", 596 | "DriverKit", 597 | "EndpointSecurity", 598 | "ExceptionHandling", 599 | "ExecutionPolicy", 600 | "ExternalAccessory", 601 | "FinderSync", 602 | "ForceFeedback", 603 | "FWAUserLib", 604 | "GSS", 605 | "HIDDriverKit", 606 | "Hypervisor", 607 | "InputMethodKit", 608 | "IOBluetooth", 609 | "IOBluetoothUI", 610 | "IOKit", 611 | "IOSurface", 612 | "IOUSBHost", 613 | "libkern", 614 | "LatentSemanticMapping", 615 | "LocalAuthentication", 616 | "MetricKit", 617 | "MobileCoreServices", 618 | "Network", 619 | "NetworkExtension", 620 | "NetworkingDriverKit", 621 | "ObjectiveC", 622 | "OpenDirectory", 623 | "os", 624 | "OSLog", 625 | "PCIDriverKit", 626 | "Security", 627 | "SecurityFoundation", 628 | "SecurityInterface", 629 | "SerialDriverKit", 630 | "ServiceManagement", 631 | "simd", 632 | "SystemConfiguration", 633 | "SystemExtensions", 634 | "USBDriverKit", 635 | "USBSerialDriverKit", 636 | "vmnet", 637 | "XPC", 638 | 639 | "XCTest", 640 | ] 641 | } 642 | 643 | } 644 | 645 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Sources/SwiftToolsHelper/TypedLine.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // 3 | // 4 | 5 | import Foundation 6 | 7 | struct TypedLine : Equatable { 8 | let type: LineType 9 | let text: String 10 | } 11 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import SwiftToolsHelperTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += SwiftToolsHelperTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/AlignEqualTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class AlignEqualTests: XCTestCase { 9 | 10 | func test_alignEquals_twoLinesWithEquals() { 11 | let input = [ 12 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 13 | TypedLine(type: .codeWithEquals, text: "let foobar = getFoobar()"), 14 | ] 15 | 16 | let result = SwiftToolsHelper.alignEquals(in: input) 17 | 18 | let expectedResult = [ 19 | "let a = getA()", 20 | "let foobar = getFoobar()" 21 | ] 22 | XCTAssertEqual(expectedResult, result) 23 | } 24 | 25 | func test_alignEquals_2Lines_spaceBeforeEqual() { 26 | let input = [ 27 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 28 | TypedLine(type: .codeWithEquals, text: "let foobar = getFoobar()") 29 | ] 30 | 31 | let result = SwiftToolsHelper.alignEquals(in: input) 32 | 33 | let expectedResult = [ 34 | "let a = getA()", 35 | "let foobar = getFoobar()" 36 | ] 37 | XCTAssertEqual(expectedResult, result) 38 | } 39 | 40 | func test_alignEquals_5Lines() { 41 | let input = [ 42 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 43 | TypedLine(type: .codeWithEquals, text: "let foobar = getFoobar()"), 44 | TypedLine(type: .codeWithEquals, text: "let b = getA()"), 45 | TypedLine(type: .codeWithEquals, text: "let baz = getFoobar()"), 46 | TypedLine(type: .codeWithEquals, text: "let c = getA()") 47 | ] 48 | 49 | let result = SwiftToolsHelper.alignEquals(in: input) 50 | 51 | let expectedResult = [ 52 | "let a = getA()", 53 | "let foobar = getFoobar()", 54 | "let b = getA()", 55 | "let baz = getFoobar()", 56 | "let c = getA()" 57 | ] 58 | XCTAssertEqual(expectedResult, result) 59 | } 60 | 61 | func test_alignEquals_interceptedLine() { 62 | let input = [ 63 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 64 | TypedLine(type: .otherCode, text: "foobar()"), 65 | TypedLine(type: .codeWithEquals, text: "let blabla = getA()") 66 | ] 67 | 68 | let result = SwiftToolsHelper.alignEquals(in: input) 69 | 70 | let expectedResult = [ 71 | "let a = getA()", 72 | "foobar()", 73 | "let blabla = getA()" 74 | ] 75 | XCTAssertEqual(expectedResult, result) 76 | } 77 | 78 | func test_alignEquals_ignoresComments() { 79 | let input = [ 80 | TypedLine(type: .inlineComment, text: "// let a = getA()"), 81 | TypedLine(type: .codeWithEquals, text: "let b = getA()"), 82 | TypedLine(type: .codeWithEquals, text: "let blabla = getA()") 83 | ] 84 | 85 | let result = SwiftToolsHelper.alignEquals(in: input) 86 | 87 | let expectedResult = [ 88 | "// let a = getA()", 89 | "let b = getA()", 90 | "let blabla = getA()" 91 | ] 92 | XCTAssertEqual(expectedResult, result) 93 | } 94 | 95 | func test_alignEquals_worksWithColor() { 96 | let input = [ 97 | TypedLine(type: .uiColorDefinitionRedGreenBlue, text: "let foobarColor = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)"), 98 | TypedLine(type: .codeWithEquals, text: "let blabla = getA()"), 99 | ] 100 | 101 | let result = SwiftToolsHelper.alignEquals(in: input) 102 | 103 | let expectedResult = [ 104 | "let foobarColor = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)", 105 | "let blabla = getA()" 106 | ] 107 | XCTAssertEqual(expectedResult, result) 108 | } 109 | 110 | func test_alignEquals_worksWithColorLiteral() { 111 | let input = [ 112 | TypedLine(type: .colorLiteralDefinition, text: "let foobarColor = #colorLiteral(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)"), 113 | TypedLine(type: .codeWithEquals, text: "let blabla = getA()"), 114 | ] 115 | 116 | let result = SwiftToolsHelper.alignEquals(in: input) 117 | 118 | let expectedResult = [ 119 | "let foobarColor = #colorLiteral(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)", 120 | "let blabla = getA()" 121 | ] 122 | XCTAssertEqual(expectedResult, result) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/ColorLiteralToUIColorTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 03.04.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class ColorLiteralToUIColorTests : XCTestCase { 9 | 10 | func test_colorLiteralToUIColor() { 11 | let input = " let foobarColor = #colorLiteral(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)" 12 | 13 | let result = SwiftToolsHelper.colorLiteralToUIColor(for: [input]) 14 | 15 | let expectedResult = [" let foobarColor = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)"] 16 | XCTAssertEqual(expectedResult, result) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/HexToUIColorTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 23.02.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class HexToUIColorTests : XCTestCase { 9 | 10 | func test_hexToUIColor_withHashtagSign() { 11 | let input = "#FFa004ce" 12 | 13 | let result = SwiftToolsHelper.hexToUIColor(for: input) 14 | 15 | let expectedResult = "let <#name#> = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)" 16 | XCTAssertEqual(expectedResult, result) 17 | } 18 | 19 | func test_hexToUIColor_withoutHashtagSign() { 20 | let input = "FFa004ce" 21 | 22 | let result = SwiftToolsHelper.hexToUIColor(for: input) 23 | 24 | let expectedResult = "let <#name#> = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)" 25 | XCTAssertEqual(expectedResult, result) 26 | } 27 | 28 | func test_hexToUIColor_withHashtagSignAndBeginningOfLine() { 29 | let input = " // #FFa004ce" 30 | 31 | let result = SwiftToolsHelper.hexToUIColor(for: input) 32 | 33 | let expectedResult = " let <#name#> = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)" 34 | XCTAssertEqual(expectedResult, result) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/ProtocolFromSelectedMethodsTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 23.02.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class ProtocolFromSelectedMethodsTests : XCTestCase { 9 | 10 | func test_protocolFromSelectedMethods_oneMethod() { 11 | 12 | let input = [ 13 | TypedLine(type: .startOfMultilineFuncDeclaration, text: "func foo() {"), 14 | TypedLine(type: .otherCode, text: " return"), 15 | TypedLine(type: .otherCode, text: "}"), 16 | ] 17 | 18 | let result = SwiftToolsHelper.protocolFromMethods(in: input) 19 | 20 | let expectedResult = "protocol <#Protocol Name#> {\nfunc foo()\n}\n" 21 | XCTAssertEqual(expectedResult, result) 22 | } 23 | 24 | func test_protocolFromSelectedMethods_twoMethods() { 25 | 26 | let input = [ 27 | TypedLine(type: .startOfMultilineFuncDeclaration, text: "func foo() {"), 28 | TypedLine(type: .otherCode, text: " return"), 29 | TypedLine(type: .otherCode, text: "}"), 30 | TypedLine(type: .otherCode, text: ""), 31 | TypedLine(type: .startOfMultilineFuncDeclaration, text: "func a(a: A,"), 32 | TypedLine(type: .withinMultilineFuncDeclaration, text: " b: B,"), 33 | TypedLine(type: .endOfMultilineFuncDeclaration, text: " c: C) {"), 34 | TypedLine(type: .otherCode, text: " foo()"), 35 | ] 36 | 37 | let result = SwiftToolsHelper.protocolFromMethods(in: input) 38 | 39 | let expectedResult = "protocol <#Protocol Name#> {\nfunc foo()\nfunc a(a: A,\nb: B,\nc: C)\n}\n" 40 | XCTAssertEqual(expectedResult, result) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/SortImportTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 14.03.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class SortImportTests : XCTestCase { 9 | 10 | func test_sortImport_treeLines() { 11 | let input = [ 12 | TypedLine(type: .inlineComment, text: "//"), 13 | TypedLine(type: .otherCode, text: ""), 14 | TypedLine(type: .import, text: "import UIKit\n"), 15 | TypedLine(type: .import, text: "import Foo\n"), 16 | TypedLine(type: .import, text: "import Foundation\n"), 17 | TypedLine(type: .import, text: "import Bar\n"), 18 | TypedLine(type: .otherCode, text: ""), 19 | TypedLine(type: .otherCode, text: "class Foo {"), 20 | TypedLine(type: .otherCode, text: "}"), 21 | ] 22 | 23 | let result = SwiftToolsHelper.sortImport(in: input) 24 | 25 | let expectedResult = [ 26 | "//", 27 | "", 28 | "import Foundation\n", 29 | "import UIKit\n", 30 | "", 31 | "import Bar\n", 32 | "import Foo\n", 33 | "", 34 | "class Foo {", 35 | "}" 36 | ] 37 | XCTAssertEqual(expectedResult, result) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/TypedLineTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class TypedLineTests: XCTestCase { 9 | 10 | func test_type_inlineComment() { 11 | 12 | let input = [ 13 | "// let a = getA()", 14 | ] 15 | 16 | let result = SwiftToolsHelper.typedLines(from: input) 17 | 18 | let expectedResult = [ 19 | TypedLine(type: .inlineComment, text: "// let a = getA()"), 20 | ] 21 | XCTAssertEqual(expectedResult, result) 22 | } 23 | 24 | func test_type_code() { 25 | 26 | let input = [ 27 | "let a = getA()", 28 | ] 29 | 30 | let result = SwiftToolsHelper.typedLines(from: input) 31 | 32 | let expectedResult = [ 33 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 34 | ] 35 | XCTAssertEqual(expectedResult, result) 36 | } 37 | 38 | func test_type_inlineCommentAndCode() { 39 | 40 | let input = [ 41 | "// let a = getA()", 42 | "let a = getA()", 43 | ] 44 | 45 | let result = SwiftToolsHelper.typedLines(from: input) 46 | 47 | let expectedResult = [ 48 | TypedLine(type: .inlineComment, text: "// let a = getA()"), 49 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 50 | ] 51 | XCTAssertEqual(expectedResult, result) 52 | } 53 | 54 | func test_type_multilineCommentAndCode_within() { 55 | 56 | let input = [ 57 | "let a = getA()", 58 | "/* let a = getA()", 59 | "let a = getA()", 60 | "let a = getA() */", 61 | "let a = getA()", 62 | ] 63 | 64 | let result = SwiftToolsHelper.typedLines(from: input) 65 | 66 | let expectedResult = [ 67 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 68 | TypedLine(type: .startOfMultilineComment, text: "/* let a = getA()"), 69 | TypedLine(type: .withinMultilineComment, text: "let a = getA()"), 70 | TypedLine(type: .endOfMultilineComment, text: "let a = getA() */"), 71 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 72 | ] 73 | XCTAssertEqual(expectedResult, result) 74 | } 75 | 76 | func test_type_multilineCommentAndCode_end() { 77 | 78 | let input = [ 79 | "let a = getA()", 80 | "/* let a = getA()", 81 | "let a = getA()", 82 | ] 83 | 84 | let result = SwiftToolsHelper.typedLines(from: input) 85 | 86 | let expectedResult = [ 87 | TypedLine(type: .codeWithEquals, text: "let a = getA()"), 88 | TypedLine(type: .startOfMultilineComment, text: "/* let a = getA()"), 89 | TypedLine(type: .withinMultilineComment, text: "let a = getA()"), 90 | ] 91 | XCTAssertEqual(expectedResult, result) 92 | } 93 | 94 | func test_type_inlineFuncDeclaration() { 95 | let input = [ 96 | "func a() {" 97 | ] 98 | 99 | let result = SwiftToolsHelper.typedLines(from: input) 100 | 101 | let expectedResult = [ 102 | TypedLine(type: .inlineFuncDeclaration, text: "func a() {") 103 | ] 104 | XCTAssertEqual(expectedResult, result) 105 | } 106 | 107 | func test_type_multilineFuncDeclaration() { 108 | let input = [ 109 | "func a(a: A", 110 | " b: B", 111 | " c: C) {" 112 | ] 113 | 114 | let result = SwiftToolsHelper.typedLines(from: input) 115 | 116 | let expectedResult = [ 117 | TypedLine(type: .startOfMultilineFuncDeclaration, text: "func a(a: A"), 118 | TypedLine(type: .withinMultilineFuncDeclaration, text: " b: B"), 119 | TypedLine(type: .endOfMultilineFuncDeclaration, text: " c: C) {") 120 | ] 121 | XCTAssertEqual(expectedResult, result) 122 | } 123 | 124 | func test_type_multilineFuncDeclaration_andOtherCode() { 125 | let input = [ 126 | "func a(a: A", 127 | " b: B) {", 128 | " foo()" 129 | ] 130 | 131 | let result = SwiftToolsHelper.typedLines(from: input) 132 | 133 | let expectedResult = [ 134 | TypedLine(type: .startOfMultilineFuncDeclaration, text: "func a(a: A"), 135 | TypedLine(type: .endOfMultilineFuncDeclaration, text: " b: B) {"), 136 | TypedLine(type: .otherCode, text: " foo()") 137 | ] 138 | XCTAssertEqual(expectedResult, result) 139 | } 140 | 141 | func test_type_import() { 142 | let input = [ 143 | "import UIKit", 144 | "import Foundation", 145 | "import MapKit" 146 | ] 147 | 148 | let result = SwiftToolsHelper.typedLines(from: input) 149 | 150 | let expectedResult = [ 151 | TypedLine(type: .import, text: "import UIKit"), 152 | TypedLine(type: .import, text: "import Foundation"), 153 | TypedLine(type: .import, text: "import MapKit"), 154 | ] 155 | XCTAssertEqual(expectedResult, result) 156 | } 157 | 158 | func test_type_uiColorDefinition() { 159 | let input = [ 160 | "let foobarColor = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)" 161 | ] 162 | 163 | let result = SwiftToolsHelper.typedLines(from: input) 164 | 165 | let expectedResult = [ 166 | TypedLine(type: .uiColorDefinitionRedGreenBlue, text: input[0]) 167 | ] 168 | XCTAssertEqual(expectedResult, result) 169 | } 170 | 171 | func test_type_placeholder() { 172 | let input = [ 173 | "let foobar = <#name#>" 174 | ] 175 | 176 | let result = SwiftToolsHelper.typedLines(from: input) 177 | 178 | let expectedResult = [ 179 | TypedLine(type: .placeHolder, text: input[0]) 180 | ] 181 | XCTAssertEqual(expectedResult, result) 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/UIColorToColorLiteralTests.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 30.03.20. 2 | // 3 | // 4 | 5 | import XCTest 6 | @testable import SwiftToolsHelper 7 | 8 | final class UIColorToColorLiteralTests : XCTestCase { 9 | 10 | func test_uiColorToColorLiteral() { 11 | let input = " let foobarColor = UIColor(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)" 12 | 13 | let result = SwiftToolsHelper.uiColorToColorLiteral(for: [input]) 14 | 15 | let expectedResult = [" let foobarColor = #colorLiteral(red: 1.000, green: 0.627, blue: 0.016, alpha: 0.808)"] 16 | XCTAssertEqual(expectedResult, result) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SwiftToolsHelper/Tests/SwiftToolsHelperTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(SwiftToolsHelperTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /SwiftToolsXcodeExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | CodeTools 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | XCSourceEditorCommandDefinitions 30 | 31 | 32 | XCSourceEditorCommandClassName 33 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 34 | XCSourceEditorCommandIdentifier 35 | $(PRODUCT_BUNDLE_IDENTIFIER).AlignEquals 36 | XCSourceEditorCommandName 37 | Align equals 38 | 39 | 40 | XCSourceEditorCommandClassName 41 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 42 | XCSourceEditorCommandIdentifier 43 | $(PRODUCT_BUNDLE_IDENTIFIER).ColorLiteralToUIColor 44 | XCSourceEditorCommandName 45 | Color Literal to UIColor 46 | 47 | 48 | XCSourceEditorCommandClassName 49 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 50 | XCSourceEditorCommandIdentifier 51 | $(PRODUCT_BUNDLE_IDENTIFIER).CopyProtocolDeclarationToClipboard 52 | XCSourceEditorCommandName 53 | Copy Protocol Declarations For Selected Methods To Clipboard 54 | 55 | 56 | XCSourceEditorCommandClassName 57 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 58 | XCSourceEditorCommandIdentifier 59 | $(PRODUCT_BUNDLE_IDENTIFIER).HexToUIColor 60 | XCSourceEditorCommandName 61 | Hex to UIColor 62 | 63 | 64 | XCSourceEditorCommandClassName 65 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 66 | XCSourceEditorCommandIdentifier 67 | $(PRODUCT_BUNDLE_IDENTIFIER).UIColorToColorLiteral 68 | XCSourceEditorCommandName 69 | UIColor to Color Literal 70 | 71 | 72 | XCSourceEditorCommandClassName 73 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 74 | XCSourceEditorCommandIdentifier 75 | $(PRODUCT_BUNDLE_IDENTIFIER).SortImports 76 | XCSourceEditorCommandName 77 | Sort Imports 78 | 79 | 80 | XCSourceEditorCommandClassName 81 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 82 | XCSourceEditorCommandIdentifier 83 | $(PRODUCT_BUNDLE_IDENTIFIER).SortSelected 84 | XCSourceEditorCommandName 85 | Sort Selected 86 | 87 | 88 | XCSourceEditorCommandClassName 89 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 90 | XCSourceEditorCommandIdentifier 91 | $(PRODUCT_BUNDLE_IDENTIFIER).SortSelectedFunctions 92 | XCSourceEditorCommandName 93 | Sort Selected Functions 94 | 95 | 96 | XCSourceEditorCommandClassName 97 | $(PRODUCT_MODULE_NAME).SourceEditorCommand 98 | XCSourceEditorCommandIdentifier 99 | $(PRODUCT_BUNDLE_IDENTIFIER).SelectPlaceholder 100 | XCSourceEditorCommandName 101 | Select Matching Placeholder 102 | 103 | 104 | XCSourceEditorExtensionPrincipalClass 105 | $(PRODUCT_MODULE_NAME).SourceEditorExtension 106 | 107 | NSExtensionPointIdentifier 108 | com.apple.dt.Xcode.extension.source-editor 109 | 110 | NSHumanReadableCopyright 111 | Copyright © 2020 dasdom. All rights reserved. 112 | 113 | 114 | -------------------------------------------------------------------------------- /SwiftToolsXcodeExtension/SourceEditorCommand.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // Copyright © 2020 dasdom. All rights reserved. 3 | // 4 | 5 | import Foundation 6 | import XcodeKit 7 | import SwiftToolsHelper 8 | import UserNotifications 9 | 10 | class SourceEditorCommand: NSObject, XCSourceEditorCommand { 11 | 12 | func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void { 13 | // Implement your command here, invoking the completion handler when done. Pass it nil on success, and an NSError on failure. 14 | 15 | let identifier = invocation.commandIdentifier 16 | 17 | let buffer = invocation.buffer 18 | let selections = buffer.selections 19 | let lines = buffer.lines 20 | 21 | defer { 22 | completionHandler(nil) 23 | } 24 | 25 | if identifier.hasSuffix(".AlignEquals") { 26 | 27 | if let range = firstSelectedRange(from: selections) { 28 | if let lines = Array(lines.subarray(with: range)) as? [String] { 29 | 30 | let changedLines = SwiftToolsHelper.alignEquals(in: lines) 31 | 32 | buffer.lines.replaceObjects(in: range, withObjectsFrom: changedLines) 33 | } 34 | } 35 | } else if identifier.hasSuffix(".ColorLiteralToUIColor") { 36 | 37 | if let lines = lines as? [String] { 38 | let result = SwiftToolsHelper.colorLiteralToUIColor(for: lines) 39 | buffer.lines.removeAllObjects() 40 | buffer.lines.addObjects(from: result) 41 | } 42 | 43 | } else if identifier.hasSuffix(".CopyProtocolDeclarationToClipboard") { 44 | 45 | if let range = firstSelectedRange(from: selections) { 46 | if let lines = Array(lines.subarray(with: range)) as? [String] { 47 | 48 | SwiftToolsHelper.protocolFromMethods(in: lines) 49 | 50 | let center = UNUserNotificationCenter.current() 51 | center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in 52 | 53 | if let error = error { 54 | print("error: \(error)") 55 | } 56 | 57 | // Enable or disable features based on the authorization. 58 | let content = UNMutableNotificationContent() 59 | content.title = "Protocol definition copied" 60 | content.body = "Protocol definition for selected methods copied to clipboard." 61 | 62 | // Configure the recurring date. 63 | var dateComponents = DateComponents() 64 | dateComponents.calendar = Calendar.current 65 | 66 | dateComponents.weekday = 3 // Tuesday 67 | dateComponents.hour = 14 // 14:00 hours 68 | 69 | // Create the trigger as a repeating event. 70 | let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false) 71 | 72 | // Create the request 73 | let uuidString = UUID().uuidString 74 | let request = UNNotificationRequest(identifier: uuidString, 75 | content: content, trigger: trigger) 76 | 77 | // Schedule the request with the system. 78 | let notificationCenter = UNUserNotificationCenter.current() 79 | notificationCenter.add(request) { (error) in 80 | if let error = error { 81 | print("error \(error)") 82 | } 83 | } 84 | } 85 | 86 | } 87 | } 88 | } else if identifier.hasSuffix(".HexToUIColor") { 89 | 90 | if let firstSelection = selections.firstObject as? XCSourceTextRange { 91 | 92 | let start = firstSelection.start.column 93 | let end = firstSelection.end.column 94 | let startLine = firstSelection.start.line 95 | let endLine = firstSelection.end.line 96 | 97 | if endLine - startLine > 1 { 98 | return 99 | } 100 | 101 | let line: String = lines[startLine] as! String 102 | let input: String 103 | if startLine == endLine, start < end { 104 | let range = NSRange(location: start, length: end-start) 105 | input = (line as NSString).substring(with: range) 106 | } else { 107 | input = line 108 | } 109 | 110 | let result = SwiftToolsHelper.hexToUIColor(for: input) 111 | lines.insert(result, at: startLine+1) 112 | } 113 | 114 | } else if identifier.hasSuffix(".UIColorToColorLiteral") { 115 | 116 | if let lines = lines as? [String] { 117 | let result = SwiftToolsHelper.uiColorToColorLiteral(for: lines) 118 | buffer.lines.removeAllObjects() 119 | buffer.lines.addObjects(from: result) 120 | } 121 | 122 | } else if identifier.hasSuffix(".SortImports") { 123 | 124 | if let lines = lines as? [String] { 125 | let result = SwiftToolsHelper.sortImport(in: lines) 126 | buffer.lines.removeAllObjects() 127 | buffer.lines.addObjects(from: result) 128 | } 129 | } else if identifier.hasSuffix(".SortSelected") { 130 | 131 | if let range = firstSelectedRange(from: selections) { 132 | if let lines = Array(lines.subarray(with: range)) as? [String] { 133 | 134 | let changedLines = SwiftToolsHelper.sort(in: lines) 135 | 136 | buffer.lines.replaceObjects(in: range, withObjectsFrom: changedLines) 137 | } 138 | } 139 | } else if identifier.hasSuffix(".SortSelectedFunctions") { 140 | 141 | if let range = firstSelectedRange(from: selections) { 142 | if let lines = Array(lines.subarray(with: range)) as? [String] { 143 | 144 | let changedLines = SwiftToolsHelper.sortFunctions(in: lines) 145 | 146 | buffer.lines.replaceObjects(in: range, withObjectsFrom: changedLines) 147 | } 148 | } 149 | 150 | } else if identifier.hasSuffix(".SelectPlaceholder") { 151 | 152 | guard let selectedText = firstSelectedText(from: selections, in: lines) else { 153 | return 154 | } 155 | 156 | guard let stringLines = lines as? [NSString] else { 157 | return 158 | } 159 | 160 | for (index, line) in stringLines.enumerated() { 161 | 162 | var range = NSRange(location: 0, length: 0) 163 | var rangeToCompare = NSRange(location: 0, length: line.length) 164 | 165 | repeat { 166 | 167 | range = line.range(of: selectedText, options: .backwards, range: rangeToCompare) 168 | 169 | if range.length > 0 { 170 | let start = XCSourceTextPosition(line: index, column: range.location) 171 | let end = XCSourceTextPosition(line: index, column: range.location + range.length) 172 | let selection = XCSourceTextRange(start: start, end: end) 173 | 174 | selections.add(selection) 175 | 176 | rangeToCompare = NSRange(location: 0, length: range.location) 177 | } 178 | 179 | } while range.length > 0 180 | 181 | } 182 | } 183 | } 184 | 185 | func firstSelectedRange(from selections: NSArray) -> NSRange? { 186 | if let firstSelection = selections.firstObject as? XCSourceTextRange { 187 | 188 | let start = firstSelection.start 189 | let end = firstSelection.end 190 | return NSRange(location: start.line, length: end.line - start.line+1) 191 | } 192 | return nil 193 | } 194 | 195 | 196 | func firstSelectedText(from selections: NSArray, in lines: NSArray) -> String? { 197 | 198 | guard let firstSelection = selections.firstObject as? XCSourceTextRange else { 199 | return nil 200 | } 201 | 202 | 203 | guard let line = lines[firstSelection.start.line] as? NSString else { 204 | return nil 205 | } 206 | 207 | let start = firstSelection.start 208 | let end = firstSelection.end 209 | let range = NSRange(location: start.column, length: end.column - start.column) 210 | 211 | return line.substring(with: range) 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /SwiftToolsXcodeExtension/SourceEditorExtension.swift: -------------------------------------------------------------------------------- 1 | // Created by dasdom on 22.02.20. 2 | // Copyright © 2020 dasdom. All rights reserved. 3 | // 4 | 5 | import Foundation 6 | import XcodeKit 7 | 8 | class SourceEditorExtension: NSObject, XCSourceEditorExtension { 9 | 10 | /* 11 | func extensionDidFinishLaunching() { 12 | // If your extension needs to do any work at launch, implement this optional method. 13 | } 14 | */ 15 | 16 | /* 17 | var commandDefinitions: [[XCSourceEditorCommandDefinitionKey: Any]] { 18 | // If your extension needs to return a collection of command definitions that differs from those in its Info.plist, implement this optional property getter. 19 | return [] 20 | } 21 | */ 22 | 23 | } 24 | -------------------------------------------------------------------------------- /SwiftToolsXcodeExtension/SwiftToolsXcodeExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | --------------------------------------------------------------------------------