├── .DS_Store ├── ExampleImage ├── StarConsoleLink.gif ├── example_image_objc.png └── example_image_swift.png ├── README.md ├── Scripts ├── install.sh └── uninstall.sh ├── StarConsoleLink.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── StarConsoleLink.xcscmblueprint │ └── xcuserdata │ │ └── Star.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── StarConsoleLink.xcscheme └── xcuserdata │ └── Star.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── StarConsoleLink ├── .DS_Store ├── Business │ └── Settings │ │ ├── ConsoleLinkConfig.swift │ │ ├── SettingsWindowController.swift │ │ └── SettingsWindowController.xib ├── Extensions │ ├── Dispatch-Extension.swift │ ├── NSColor-Extension.swift │ ├── Operator-Extension.swift │ └── String-Extension.swift ├── Info.plist ├── Library │ ├── JRSwizzle │ │ ├── JRSwizzle.h │ │ └── JRSwizzle.m │ ├── LogColor │ │ ├── LogColorKit.h │ │ └── LogColorKit.m │ ├── PluginHelper.swift │ ├── StarFunctions.h │ └── StarFunctions.m ├── Logger │ ├── Logger.h │ └── Logger.swift ├── NSObject-Extension.swift ├── NSTextStorage-Extension.swift ├── NSTextView-Extension.swift ├── StarConsoleLink-Bridging-Header.h └── StarConsoleLink.swift ├── StarConsoleLinkExample ├── .DS_Store ├── StarConsoleLinkExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── StarConsoleLinkExample.xcscmblueprint │ │ └── xcuserdata │ │ │ └── Star.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── Star.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── StarConsoleLinkExample.xcscheme │ │ └── xcschememanagement.plist └── StarConsoleLinkExample │ ├── OCLogger.h │ ├── OCLogger.m │ ├── StarConsoleLinkExample-Bridging-Header.h │ ├── SwiftLogger.swift │ └── main.swift └── StarConsoleLinkForXcode6-7 ├── ExampleImage ├── StarConsoleLink.gif ├── example_image_objc.png └── example_image_swift.png ├── README.md ├── Scripts ├── install.sh └── uninstall.sh ├── StarConsoleLink.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── StarConsoleLink.xcscmblueprint │ └── xcuserdata │ │ └── Star.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── StarConsoleLink.xcscheme └── xcuserdata │ └── Star.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── StarConsoleLink ├── Business │ └── Settings │ │ ├── ConsoleLinkConfig.swift │ │ ├── SettingsWindowController.swift │ │ └── SettingsWindowController.xib ├── Extensions │ ├── Dispatch-Extension.swift │ ├── NSColor-Extension.swift │ ├── Operator-Extension.swift │ └── String-Extension.swift ├── Info.plist ├── Library │ ├── JRSwizzle │ │ ├── JRSwizzle.h │ │ └── JRSwizzle.m │ ├── LogColor │ │ ├── LogColorKit.h │ │ └── LogColorKit.m │ ├── PluginHelper.swift │ ├── StarFunctions.h │ └── StarFunctions.m ├── Logger │ ├── Logger.h │ └── Logger.swift ├── NSObject-Extension.swift ├── NSTextStorage-Extension.swift ├── NSTextView-Extension.swift ├── StarConsoleLink-Bridging-Header.h └── StarConsoleLink.swift └── StarConsoleLinkExample ├── StarConsoleLinkExample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── StarConsoleLinkExample.xcscmblueprint │ └── xcuserdata │ │ └── Star.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Star.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── StarConsoleLinkExample.xcscheme │ └── xcschememanagement.plist └── StarConsoleLinkExample ├── OCLogger.h ├── OCLogger.m ├── StarConsoleLinkExample-Bridging-Header.h ├── SwiftLogger.swift └── main.swift /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/.DS_Store -------------------------------------------------------------------------------- /ExampleImage/StarConsoleLink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/ExampleImage/StarConsoleLink.gif -------------------------------------------------------------------------------- /ExampleImage/example_image_objc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/ExampleImage/example_image_objc.png -------------------------------------------------------------------------------- /ExampleImage/example_image_swift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/ExampleImage/example_image_swift.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Introduction 【简介】 3 | 4 | StarConsoleLink inject the link to your Xcode console, which allows you to click on the link area rapid positioning to the log line. 5 | 6 | StarConsoleLink给你的Xcode控制台注入了超链接,它能让你点击链接时,快速跳转到日志输出语句位置。 7 | 8 | ![Smaller icon](https://github.com/iStarEternal/StarConsoleLink/blob/master/ExampleImage/StarConsoleLink.gif "Case Diagram") 9 | 10 | 11 | 12 | # How to use in Xcode8 13 | 14 | 15 | 自Xcode8之后,Xcode增加了签名,默认不再支持自定义插件,但可以通过重新签名Xcode安装插件 16 | 17 | 步骤: 18 | 19 | 0、你可以先备份自己的未签名的Xcode,但是我没有备份,目前没发现什么影响,推荐你们备份。 20 | 21 | 1、打开钥匙串,点击钥匙串访问->证书助理->创建证书 22 | 23 | 2、名称输入"XcodeSigner",身份类型选择"自签名证书",证书类型选择"代码签名",点击创建,创建出来的证书保存起来,以后或许还用得着。 24 | 25 | 3、打开终端,执行下面代码,等待几分钟,Xcode8就重新被签名了。 26 | ``` 27 | sudo codesign -f -s XcodeSigner /Applications/Xcode.app 28 | ``` 29 | 30 | 4、可能你之前安装过的其他插件已经失效,一些插件不兼容Xcode8甚至会导致Xcode崩溃,我们只能让引起崩溃的插件删除,可以执行这句命令解决。 31 | ``` 32 | find ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins -name Info.plist -maxdepth 3 | xargs -I{} defaults write {} DVTPlugInCompatibilityUUIDs -array-add `defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID` 33 | ``` 34 | 或者你也能自己进入:```~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins```目录中,手动删除所有插件。 35 | 36 | 37 | 5、执行下面代码,安装StarConsoleLink 38 | ```install 39 | curl -fsSL https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/master/Scripts/install.sh | sh 40 | ``` 41 | 42 | 6、重启Xcode,运行的时候就会出现Load Bundle,点击Load Bundle,这时你就会发现插件已经可以使用了。如果插件未生效,下文中还有其他解决方案可以帮助你。 43 | 44 | 45 | # How to use? 【使用说明】 46 | 47 | 48 | 1. If you are using Swift, Copy Logger.swift to you project. 49 | 50 | 2. If you are using Objective-C, Copy Logger.h to you project and #import "Logger.h" to you PrefixHeader.pch. 51 | 52 | 3. If you want to custom you logs, please follow the rules: [FileName.extension:LineNumber], Just like [main.swift:15]. 53 | 54 | 55 | 56 | 1. 如果你使用的是Swift,请拷贝 Logger.swift 到你的项目中去。 57 | 58 | 2. 如果你使用的是Objective-C,请拷贝 Logger.h 到你的项目中,并在你的.pch文件中添加 #import "Logger.h"。 59 | 60 | 3. 如果你想要自定义你的日志,请遵照[FileName.extension:LineNumber]的书写规范,例:[main.swift:15]。 61 | 62 | 63 | # Install 【安装】 64 | 65 | ```install 66 | curl -fsSL https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/master/Scripts/install.sh | sh 67 | ``` 68 | 69 | 70 | 71 | # Uninstall 【卸载】 72 | 73 | ```uninstall 74 | curl -fsSL https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/master/Scripts/uninstall.sh | sh 75 | ``` 76 | 77 | 78 | # The New Feature 【新功能】 79 | 80 | ####v1.4.1 81 | 82 | 重构Logger.h并删除了Logger.m 83 | 现已加入alcatraz-packages(Package Manager) 84 | 85 | 86 | ####v1.4 87 | 88 | 修复了1.3在控制台输入文字会发生闪退的BUG 89 | 90 | 91 | ####v1.3 92 | 93 | 添加了NSDictionary和NSArray的日志显示,Unicode转中文 94 | 95 | 您现在可以在菜单栏 Plugins -> Star Console Link -> Chinese Unicode Enabled 选择是否关闭中文转换了。 96 | ```objective-c 97 | LogWarning(@"%@", @{@"name": @"星星", @"age": @"18岁"}); 98 | ``` 99 | ``` 100 | 以前: 101 | <2016-07-14 14:07:03> [Warning][OCLogger.m:45] { 102 | age = "18\U5c81"; 103 | name = "\U661f\U661f"; 104 | } 105 | 现在: 106 | <2016-07-14 14:07:41> [Warning][OCLogger.m:45] { 107 | age = "18岁"; 108 | name = "星星"; 109 | } 110 | ``` 111 | 112 | 113 | ####v1.2 114 | 115 | 添加了LogBackTrace,并对LogBackTrace的日志加入了超链接,您现在也可以更快的定位到日志的方法调用堆栈了。 116 | 117 | 您现在可以在菜单栏 Plugins -> Star Console Link -> Enabled 选择是否关闭StarConsoleLink 118 | 119 | 您现在可以在菜单栏 Plugins -> Star Console Link -> Setting 进行Link的颜色配置 120 | 121 | 122 | ####v1.1 123 | 124 | 将OC的NSLog替换成了printf,并添加了日志输出时间 125 | 126 | 127 | 128 | ####v1.0 129 | 130 | StarConsoleLink集成了XcodeColors,他可以让你自定义你Log的颜色。感谢@robbiehanson提供的支持:https://github.com/robbiehanson/XcodeColors 131 | 132 | 给您的日志加入了超链接,让您可以更快的定位到打印输出的位置。 133 | 134 | 给您的日志加入了色彩元素,让您可以更好的区分日志的类型。 135 | 136 | 增强您的日志语句,您可以使用下面的语句来输出更多类型的日志。 137 | 138 | ```objective-c 139 | LogInfo(@"你好"); 140 | // 黑色 [Info][ViewController.m:35]你好 141 | LogSuccess(@"Hello"); 142 | // 绿色 [Success][ViewController.m:35]Hello 143 | LogWarning(@"Bonjour"); 144 | // 黄色 [Warning][ViewController.m:35]Bonjour 145 | LogError(@"¡Hola"); 146 | // 红色 [Error][ViewController.m:35]¡Hola 147 | ``` 148 | 149 | # If Ineffective【如果插件未生效】 150 | 151 | 第一步:请先检查你是否启用了该插件 152 | ``` 153 | defaults read com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-{Current Xcode Version} 154 | ``` 155 | 156 | 第二步:如果发现插件在skipped中,请执行下列代码,然后重启Xcode,并点击Load Bundles 157 | ``` 158 | defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-{Current Xcode Version} 159 | ``` 160 | 161 | # Example 【案例】 162 | 163 | * Objective-C 164 | 165 | ```objective-c 166 | 167 | #define StarDebug DEBUG 168 | #define StarXCodeColors 1 169 | 170 | #define XCODE_COLORS_ESCAPE @"\033[" 171 | #define XCODE_COLORS_ESCAPE_FG XCODE_COLORS_ESCAPE @"fg" 172 | #define XCODE_COLORS_ESCAPE_BG XCODE_COLORS_ESCAPE @"bg" 173 | 174 | #define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE @"fg;" // Clear any foreground color 175 | #define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE @"bg;" // Clear any background color 176 | #define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE @";" // Clear any foreground or background color 177 | 178 | #define NSLogColor @"22,22,22" // 黑色 179 | #define NSLogTitle @"Info" 180 | 181 | #define InfoColor @"22,22,22" // 黑色 182 | #define InfoTitle @"Info" 183 | 184 | #if StarDebug /* Debug Begin */ 185 | 186 | #if StarXCodeColors != 0 /* Color Begin */ 187 | 188 | #define PrivateLog(color, title, format, ...)\ 189 | printf("%s%s;[%s][%s:%d] %s %s\n",\ 190 | [XCODE_COLORS_ESCAPE_FG UTF8String],\ 191 | [color UTF8String],\ 192 | [title UTF8String],\ 193 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 194 | __LINE__,\ 195 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String],\ 196 | [XCODE_COLORS_RESET_FG UTF8String]\ 197 | );\ 198 | 199 | // NSLog 200 | #define NSLog(format, ...) \ 201 | PrivateLog(NSLogColor, NSLogTitle, format, ##__VA_ARGS__) 202 | 203 | // Information 204 | #define LogInfo(format, ...) \ 205 | PrivateLog(InfoColor, InfoTitle, format, ##__VA_ARGS__) 206 | 207 | #else /* Color Else */ 208 | 209 | #define PrivateLog(color, title, format, ...)\ 210 | printf("[%s][%s:%d] %s\n",\ 211 | [title UTF8String],\ 212 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 213 | __LINE__,\ 214 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String]\ 215 | );\ 216 | 217 | // NSLog 218 | #define NSLog(format, ...) \ 219 | PrivateLog(0, NSLogTitle, format, ##__VA_ARGS__) 220 | 221 | // Information 222 | #define LogInfo(format, ...) \ 223 | PrivateLog(0, InfoTitle, format, ##__VA_ARGS__) 224 | 225 | #endif /* Color End */ 226 | 227 | #else /* Debug Else */ 228 | 229 | #define PrivateLog(color, title, format, ...) while(0){} 230 | #define NSLog(...) while(0){} 231 | #define LogInfo(...) while(0){} 232 | 233 | #endif /* Debug End */ 234 | 235 | 236 | ``` 237 | And then you can log within a Objective-C method like so: 238 | 239 | ```Objective-C 240 | LogInfo("StarConsoleLink"); 241 | ``` 242 | 243 | * Swift 244 | ```swift 245 | 246 | let StarDebug = true 247 | 248 | struct LogColor { 249 | 250 | static let XcodeColors = true 251 | 252 | static let ESCAPE = "\u{001b}[" 253 | static let ESCAPE_FG = "\u{001b}[fg" 254 | static let ESCAPE_BG = "\u{001b}[bg" 255 | 256 | static let RESET = ESCAPE + ";" // Clear any foreground or background color 257 | static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color 258 | static let RESET_BG = ESCAPE + "bg;" // Clear any background color 259 | } 260 | 261 | let InfoColor = "22,22,22" // 黑色 262 | let InfoTitle = "Info" 263 | 264 | let DebugColor = "28,0,207" // 蓝色 265 | let DebugTitle = "Debug" 266 | 267 | let WarningColor = "218,130,53" // 黄色 268 | let WarningTitle = "Warning" 269 | 270 | let ErrorColor = "196,26,22" // 红色 271 | let ErrorTitle = "Error" 272 | 273 | let ImportantColor = "196,26,22" // 红色 274 | let ImportantTitle = "Important - 如果发现该行日志,应该及时处理" 275 | 276 | 277 | class Logger: NSObject { 278 | 279 | class func print(value: T, title: String, color: String, functionName: String, fileName: String, lineNumber: Int) { 280 | guard StarDebug else { 281 | return 282 | } 283 | if LogColor.XcodeColors { 284 | Swift.print("\(LogColor.ESCAPE_FG)\(color);[\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)\(LogColor.RESET_FG)") 285 | } 286 | else { 287 | Swift.print("[\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)") 288 | } 289 | } 290 | class func info(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 291 | print(value, title: InfoTitle, color: InfoColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 292 | } 293 | class func debug(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 294 | print(value, title: DebugTitle, color: DebugColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 295 | } 296 | class func warning(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 297 | print(value, title: WarningTitle, color: WarningColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 298 | } 299 | class func error(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 300 | print(value, title: ErrorTitle, color: ErrorColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 301 | } 302 | class func important(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 303 | print(value, title: ImportantTitle, color: ImportantColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 304 | } 305 | } 306 | 307 | ``` 308 | And then you can log within a Swift method like so: 309 | 310 | ```Swift 311 | Logger.info("StarConsoleLink") 312 | ``` 313 | -------------------------------------------------------------------------------- /Scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Set up the environment. 4 | 5 | PLUGIN_DIR="$HOME/Library/Application Support/Developer/Shared/Xcode/Plug-ins" 6 | STARCONSOLELINK_PATH="$PLUGIN_DIR/StarConsoleLink.xcplugin" 7 | 8 | # Check path, Remove if exist 9 | 10 | if [ -d "$PLUGIN_DIR" ]; then 11 | if [ -d "$STARCONSOLELINK_PATH" ]; then 12 | echo "" 13 | echo "Remove $STARCONSOLELINK_PATH" 14 | rm -rf "$STARCONSOLELINK_PATH" 15 | fi 16 | fi 17 | 18 | echo "" 19 | echo "Downloading StarConsoleLink..." 20 | 21 | # Prepare 22 | mkdir -p /var/tmp/StarConsoleLink.tmp && cd /var/tmp/StarConsoleLink.tmp 23 | 24 | echo "" 25 | # Clone from git 26 | git clone https://github.com/iStarEternal/StarConsoleLink.git --depth 1 /var/tmp/StarConsoleLink.tmp > /dev/null 27 | 28 | echo "" 29 | echo "Installing StarConsoleLink..." 30 | 31 | # Then build 32 | xcodebuild clean > /dev/null 33 | xcodebuild > /dev/null 34 | 35 | # Remove tmp files 36 | cd ~ 37 | rm -rf /var/tmp/StarConsoleLink.tmp 38 | 39 | # Done 40 | echo "" 41 | if [ -d "$PLUGIN_DIR" ]; then 42 | if [ -d "$STARCONSOLELINK_PATH" ]; then 43 | echo "StarConsoleLink successfully installed! 🍻 Please restart your Xcode." 44 | else 45 | echo "StarConsoleLink installation failed! I'm sorry 😭😭😭." 46 | fi 47 | fi 48 | echo "" -------------------------------------------------------------------------------- /Scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Set up the environment. 4 | 5 | PLUGIN_DIR="$HOME/Library/Application Support/Developer/Shared/Xcode/Plug-ins" 6 | STARCONSOLELINK_PATH="$PLUGIN_DIR/StarConsoleLink.xcplugin" 7 | 8 | # Remove 9 | 10 | echo "" 11 | echo "Remove StarConsoleLink..." 12 | 13 | if [ -d "$PLUGIN_DIR" ]; then 14 | if [ -d "$STARCONSOLELINK_PATH" ]; then 15 | echo "" 16 | echo "Remove $STARCONSOLELINK_PATH" 17 | rm -rf "$STARCONSOLELINK_PATH" 18 | fi 19 | fi 20 | 21 | # Done 22 | echo "" 23 | echo "StarConsoleLink successfully uninstalled. Loved. Agoni.😢 Please restart your Xcode." 24 | echo "" -------------------------------------------------------------------------------- /StarConsoleLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StarConsoleLink.xcodeproj/project.xcworkspace/xcshareddata/StarConsoleLink.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : { 5 | 6 | } 7 | }, 8 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 9 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : 0 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "D2FA363F-FEE5-49FD-AA34-F2535129D2CD", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : "StarProject_XcodePlugins\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "StarConsoleLink", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "OwnPlugins\/StarConsoleLink\/StarConsoleLink.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "http:\/\/code.taobao.org\/svn\/StarProject_XcodePlugins", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /StarConsoleLink.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLink.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StarConsoleLink.xcodeproj/xcshareddata/xcschemes/StarConsoleLink.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 58 | 60 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /StarConsoleLink.xcodeproj/xcuserdata/Star.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /StarConsoleLink.xcodeproj/xcuserdata/Star.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SuppressBuildableAutocreation 6 | 7 | F8FC45E71C59E7570037FEE5 8 | 9 | primary 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /StarConsoleLink/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLink/.DS_Store -------------------------------------------------------------------------------- /StarConsoleLink/Business/Settings/ConsoleLinkConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConsoleLinkConfig.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ConsoleLinkConfig: NSObject { 12 | 13 | 14 | private static var __once: () = { () -> Void in 15 | ConsoleLinkConfigSingleton.instance = ConsoleLinkConfig() 16 | }() 17 | 18 | 19 | fileprivate struct ConsoleLinkConfigSingleton { 20 | static var predicate: Int = 0 21 | static var instance: ConsoleLinkConfig! = nil 22 | } 23 | 24 | static var shared: ConsoleLinkConfig { 25 | _ = ConsoleLinkConfig.__once 26 | return ConsoleLinkConfigSingleton.instance 27 | } 28 | 29 | 30 | static func setConfig(_ config: AnyObject, forKey key: String) { 31 | UserDefaults.standard.set(config, forKey: key) 32 | UserDefaults.standard.synchronize() 33 | } 34 | 35 | static func configForKey(_ key: String, defaultValue: T) -> T { 36 | if let obj = UserDefaults.standard.object(forKey: key) { 37 | return obj as? T ?? defaultValue 38 | } 39 | else { 40 | return defaultValue 41 | } 42 | } 43 | 44 | static func configForKey(_ key: String) -> T? { 45 | if let obj = UserDefaults.standard.object(forKey: key) { 46 | return obj as? T 47 | } 48 | else { 49 | return nil 50 | } 51 | } 52 | 53 | 54 | // MARK: - 是否打开StarConsoleLink 55 | 56 | fileprivate static var consoleLinkEnabledKey = "iStar.StarConsoleLink.IsOpenConsoleLink" 57 | fileprivate var consoleLinkEnabled: Bool? 58 | static var consoleLinkEnabled: Bool { 59 | get { 60 | if shared.consoleLinkEnabled == nil { 61 | let enabled: Bool? = configForKey(consoleLinkEnabledKey) 62 | return enabled ?? true 63 | } 64 | return shared.consoleLinkEnabled! 65 | } 66 | set { 67 | setConfig(newValue as AnyObject, forKey: consoleLinkEnabledKey) 68 | shared.consoleLinkEnabled = newValue 69 | } 70 | } 71 | 72 | 73 | // MARK: - 中文Unicode 74 | 75 | fileprivate static var ChineseUnicodeEnabledKey = "iStar.StarConsoleLink.ChineseUnicodeEnabledKey" 76 | fileprivate var ChineseUnicodeEnabled: Bool? 77 | static var ChineseUnicodeEnabled: Bool { 78 | get { 79 | if shared.ChineseUnicodeEnabled == nil { 80 | let enabled: Bool? = configForKey(ChineseUnicodeEnabledKey) 81 | return enabled ?? true 82 | } 83 | return shared.ChineseUnicodeEnabled! 84 | } 85 | set { 86 | setConfig(newValue as AnyObject, forKey: ChineseUnicodeEnabledKey) 87 | shared.ChineseUnicodeEnabled = newValue 88 | } 89 | } 90 | 91 | 92 | fileprivate static let linkColorKeywordKey = "iStar.StarConsoleLink.LinkColorKey" 93 | fileprivate static let linkColorDefaultValue = 0x0000ff 94 | fileprivate var linkColor: NSColor? 95 | static var linkColor: NSColor { 96 | get { 97 | if shared.linkColor == nil { 98 | let intRGB: Int = configForKey(linkColorKeywordKey, defaultValue: linkColorDefaultValue) 99 | shared.linkColor = NSColor(rgb: intRGB) 100 | } 101 | return shared.linkColor! 102 | } 103 | set { 104 | setConfig(newValue.rgb as AnyObject, forKey: linkColorKeywordKey) 105 | shared.linkColor = newValue 106 | } 107 | } 108 | } 109 | 110 | // MARK: - Log config: Base 111 | extension ConsoleLinkConfig { 112 | 113 | 114 | fileprivate static let debugLogKeywordKey = "iStar.StarConsoleLink.DebugLogColorKey" 115 | fileprivate static let infoLogKeywordKey = "iStar.StarConsoleLink.InfoLogKeywordKey" 116 | fileprivate static let warningLogKeywordKey = "iStar.StarConsoleLink.WarningLogKeywordKey" 117 | fileprivate static let errorLogKeywordKey = "iStar.StarConsoleLink.ErrorLogKeywordKey" 118 | 119 | fileprivate static let debugLogColorKey = "iStar.StarConsoleLink.DebugLogColorKey" 120 | fileprivate static let infoLogColorKey = "iStar.StarConsoleLink.InfoLogColorKey" 121 | fileprivate static let warningLogColorKey = "iStar.StarConsoleLink.WarningLogColorKey" 122 | fileprivate static let errorLogColorKey = "iStar.StarConsoleLink.ErrorLogColorKey" 123 | 124 | 125 | static var debugLogKeyword: String { 126 | get { 127 | return configForKey(debugLogKeywordKey, defaultValue: "[Debug]") 128 | } 129 | set { 130 | setConfig(newValue as AnyObject, forKey: debugLogKeywordKey) 131 | } 132 | } 133 | 134 | static var infoLogKeyword: String { 135 | get { 136 | return configForKey(infoLogKeywordKey, defaultValue: "[Info]") 137 | } 138 | set { 139 | setConfig(newValue as AnyObject, forKey: infoLogKeywordKey) 140 | } 141 | } 142 | 143 | static var warningLogKeyword: String { 144 | get { 145 | return configForKey(warningLogKeywordKey, defaultValue: "[Warning]") 146 | } 147 | set { 148 | setConfig(newValue as AnyObject, forKey: warningLogKeywordKey) 149 | } 150 | } 151 | 152 | static var errorLogKeyword: String { 153 | get { 154 | return configForKey(errorLogKeywordKey, defaultValue: "[Error]") 155 | } 156 | set { 157 | setConfig(newValue as AnyObject, forKey: errorLogKeywordKey) 158 | } 159 | } 160 | 161 | 162 | 163 | 164 | static var debugLogColor: NSColor { 165 | get { 166 | let intRGB: Int = configForKey(debugLogColorKey, defaultValue: 0xFFFF00) 167 | return NSColor(rgb: intRGB) 168 | } 169 | set { 170 | setConfig(newValue.rgb as AnyObject, forKey: debugLogColorKey) 171 | } 172 | } 173 | 174 | static var infoLogColor: NSColor { 175 | get { 176 | let intRGB: Int = configForKey(infoLogColorKey, defaultValue: 0x000000) 177 | return NSColor(rgb: intRGB) 178 | } 179 | set { 180 | setConfig(newValue.rgb as AnyObject, forKey: infoLogColorKey) 181 | } 182 | } 183 | 184 | static var warningLogColor: NSColor { 185 | get { 186 | let intRGB: Int = configForKey(warningLogColorKey, defaultValue: 0xFFFF00) 187 | return NSColor(rgb: intRGB) 188 | } 189 | set { 190 | setConfig(newValue.rgb as AnyObject, forKey: warningLogColorKey) 191 | } 192 | } 193 | 194 | static var errorLogColor: NSColor { 195 | get { 196 | let intRGB: Int = configForKey(errorLogColorKey, defaultValue: 0x00FFFF) 197 | return NSColor(rgb: intRGB) 198 | } 199 | set { 200 | setConfig(newValue.rgb as AnyObject, forKey: errorLogColorKey) 201 | } 202 | } 203 | } 204 | 205 | // MARK: - Log color config: HttpRequest 206 | extension ConsoleLinkConfig { 207 | 208 | fileprivate static var successLogColorKey = "iStar.StarConsoleLink.SuccessLogColorKey" 209 | fileprivate static var failureLogColorKey = "iStar.StarConsoleLink.FailureLogColorKey" 210 | 211 | 212 | static var successLogColor: NSColor { 213 | get { 214 | let intRGB: Int = configForKey(successLogColorKey, defaultValue: 0x000000) 215 | return NSColor(rgb: intRGB) 216 | } 217 | set { 218 | setConfig(newValue.rgb as AnyObject, forKey: successLogColorKey) 219 | } 220 | } 221 | 222 | static var failureLogColor: NSColor { 223 | get { 224 | let intRGB: Int = configForKey(failureLogColorKey, defaultValue: 0x000000) 225 | return NSColor(rgb: intRGB) 226 | } 227 | set { 228 | setConfig(newValue.rgb as AnyObject, forKey: failureLogColorKey) 229 | } 230 | } 231 | } 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /StarConsoleLink/Business/Settings/SettingsWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsWindowController.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/19. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | /// 开发中 未完成 以后颜色由Xcode配置,不再由代码配 11 | class SettingsWindowController: NSWindowController { 12 | 13 | 14 | var bundle: Bundle! 15 | 16 | @IBOutlet weak var linkColorWell: NSColorWell! 17 | 18 | @IBOutlet weak var debugLogKeywordTextField: NSTextField! 19 | @IBOutlet weak var infoLogKeywordTextField: NSTextField! 20 | @IBOutlet weak var warningLogKeywordTextField: NSTextField! 21 | @IBOutlet weak var errorLogKeywordTextField: NSTextField! 22 | 23 | @IBOutlet weak var successLogKeywordTextField: NSTextField! 24 | @IBOutlet weak var failureLogKeywordTextField: NSTextField! 25 | 26 | @IBOutlet weak var assertLogKeywordTextField: NSTextField! 27 | @IBOutlet weak var fatalLogKeywordTextField: NSTextField! 28 | 29 | 30 | @IBOutlet weak var debugLogColorWell: NSColorWell! 31 | @IBOutlet weak var infoLogColorWell: NSColorWell! 32 | @IBOutlet weak var warningLogColorWell: NSColorWell! 33 | @IBOutlet weak var errorLogColorWell: NSColorWell! 34 | 35 | @IBOutlet weak var successLogColorWell: NSColorWell! 36 | @IBOutlet weak var failureLogColorWell: NSColorWell! 37 | 38 | @IBOutlet weak var assertLogColorWell: NSColorWell! 39 | @IBOutlet weak var fatalLogColorWell: NSColorWell! 40 | 41 | 42 | override func windowDidLoad() { 43 | super.windowDidLoad() 44 | loadConfig() 45 | } 46 | 47 | func loadConfig() { 48 | 49 | linkColorWell.color = ConsoleLinkConfig.linkColor 50 | 51 | debugLogKeywordTextField.stringValue = ConsoleLinkConfig.debugLogKeyword 52 | infoLogKeywordTextField.stringValue = ConsoleLinkConfig.infoLogKeyword 53 | warningLogKeywordTextField.stringValue = ConsoleLinkConfig.warningLogKeyword 54 | errorLogKeywordTextField.stringValue = ConsoleLinkConfig.errorLogKeyword 55 | 56 | debugLogColorWell.color = ConsoleLinkConfig.debugLogColor 57 | infoLogColorWell.color = ConsoleLinkConfig.infoLogColor 58 | warningLogColorWell.color = ConsoleLinkConfig.warningLogColor 59 | errorLogColorWell.color = ConsoleLinkConfig.errorLogColor 60 | } 61 | 62 | @IBAction func handleKeywordChanged(_ sender: NSTextField) { 63 | Logger.info(sender.stringValue) 64 | 65 | if sender == debugLogKeywordTextField { 66 | ConsoleLinkConfig.debugLogKeyword = sender.stringValue 67 | } 68 | else if sender == infoLogKeywordTextField { 69 | ConsoleLinkConfig.infoLogKeyword = sender.stringValue 70 | } 71 | else if sender == warningLogKeywordTextField { 72 | ConsoleLinkConfig.warningLogKeyword = sender.stringValue 73 | } 74 | else if sender == errorLogKeywordTextField { 75 | ConsoleLinkConfig.errorLogKeyword = sender.stringValue 76 | } 77 | 78 | } 79 | 80 | 81 | @IBAction func handleColorChanged(_ sender: NSColorWell) { 82 | if sender == linkColorWell { 83 | ConsoleLinkConfig.linkColor = sender.color 84 | } 85 | else if sender == debugLogColorWell { 86 | ConsoleLinkConfig.debugLogColor = sender.color 87 | } 88 | else if sender == infoLogColorWell { 89 | ConsoleLinkConfig.infoLogColor = sender.color 90 | } 91 | else if sender == warningLogColorWell { 92 | ConsoleLinkConfig.warningLogColor = sender.color 93 | } 94 | else if sender == errorLogColorWell { 95 | ConsoleLinkConfig.errorLogColor = sender.color 96 | } 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /StarConsoleLink/Extensions/Dispatch-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // dispatch_queue_t-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/17. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension DispatchQueue { 12 | 13 | // func async(_ closure: @escaping ()->()) { 14 | // self.async(execute: closure) 15 | // } 16 | // 17 | // func sync(_ closure: ()->()) { 18 | // self.sync(execute: closure) 19 | // } 20 | // 21 | // func delay(_ delay: Double, _ block: @escaping ()->()) { 22 | // dispatch_delay(delay, self, block) 23 | // } 24 | } 25 | 26 | func dispatch_delay(_ delay: Double, _ block: @escaping ()->()) { 27 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double((Int64)(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: { () -> Void in 28 | block() 29 | }) 30 | } 31 | 32 | func dispatch_delay(_ delay: Double, _ queue: DispatchQueue, _ block: @escaping ()->()) { 33 | queue.asyncAfter(deadline: DispatchTime.now() + Double((Int64)(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: { () -> Void in 34 | block() 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /StarConsoleLink/Extensions/NSColor-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor-Extension.swift 3 | // AviationLogin 4 | // 5 | // Created by 星星 on 15/7/28. 6 | // Copyright (c) 2015年 chinaaviationconsulting. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //#if swift(>=2.0) 12 | 13 | //#endif 14 | 15 | #if os(iOS) || os(tvOS) 16 | import UIKit 17 | public typealias Color = UIColor 18 | #else 19 | import AppKit 20 | public typealias Color = NSColor 21 | #endif 22 | 23 | 24 | extension Color { 25 | 26 | convenience init(r:Int, g:Int, b:Int, a:CGFloat) { 27 | self.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: a) 28 | } 29 | 30 | convenience init(rgb:Int) { 31 | let red = Double((rgb >> 16) & 0xff) / 255.0 32 | let green = Double((rgb >> 8) & 0xff) / 255.0 33 | let blue = Double(rgb & 0xff) / 255.0 34 | self.init(red:CGFloat(red), green:CGFloat(green), blue:CGFloat(blue), alpha:CGFloat(1)) 35 | } 36 | 37 | /// alpha range: 0 - 1.0 38 | convenience init(rgb: Int, alpha: CGFloat) { 39 | let red = Double((rgb >> 16) & 0xff) / 255.0 40 | let green = Double((rgb >> 8) & 0xff) / 255.0 41 | let blue = Double(rgb & 0xff) / 255.0 42 | self.init(red:CGFloat(red), green:CGFloat(green), blue:CGFloat(blue), alpha:alpha) 43 | } 44 | 45 | convenience init(rgba:Int) { 46 | let red = Double((rgba >> 32) & 0xff) / 255.0 47 | let green = Double((rgba >> 16) & 0xff) / 255.0 48 | let blue = Double((rgba >> 8) & 0xff) / 255.0 49 | let alpha = Double(rgba & 0xff) / 255.0 50 | self.init(red:CGFloat(red), green:CGFloat(green), blue:CGFloat(blue), alpha:CGFloat(alpha)) 51 | } 52 | 53 | 54 | static func rgb(_ rgb: Int) -> Color { 55 | return Color(rgb: rgb) 56 | } 57 | 58 | var rgb: Int { 59 | 60 | #if os(iOS) || os(tvOS) 61 | var red: CGFloat = 0 62 | var green: CGFloat = 0 63 | var blue: CGFloat = 0 64 | var alpha: CGFloat = 0 65 | self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) 66 | 67 | let intRed = Int(red * 255.0) 68 | let intGreen = Int(red * 255.0) 69 | let intBlue = Int(red * 255.0) 70 | return (intRed << 16) + (intGreen << 8) + intBlue 71 | #else 72 | let red = Int(self.redComponent * 255.0) 73 | let green = Int(self.greenComponent * 255.0) 74 | let blue = Int(self.blueComponent * 255.0) 75 | // let alpha = self.alphaComponent 76 | return (red << 16) + (green << 8) + blue 77 | #endif 78 | } 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /StarConsoleLink/Extensions/Operator-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Operator-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | // MARK: - Int 和 CGfloat 加法 13 | public func +(lhs: Int, rhs: CGFloat) -> CGFloat { 14 | return CGFloat(lhs) + rhs 15 | } 16 | 17 | public func +(lhs: CGFloat, rhs: Int) -> CGFloat { 18 | return lhs + CGFloat(rhs) 19 | } 20 | 21 | 22 | // MARK: - Int 和 CGfloat 减法 23 | public func -(lhs: Int, rhs: CGFloat) -> CGFloat { 24 | return CGFloat(lhs) - rhs 25 | } 26 | 27 | public func -(lhs: CGFloat, rhs: Int) -> CGFloat { 28 | return lhs - CGFloat(rhs) 29 | } 30 | 31 | 32 | // MARK: - Int 和 CGfloat 乘法 33 | public func *(lhs: Int, rhs: CGFloat) -> CGFloat { 34 | return CGFloat(lhs) * rhs 35 | } 36 | 37 | public func *(lhs: CGFloat, rhs: Int) -> CGFloat { 38 | return lhs * CGFloat(rhs) 39 | } 40 | 41 | 42 | // MARK: - Int 和 CGfloat 除法 43 | public func /(lhs: Int, rhs: CGFloat) -> CGFloat { 44 | return CGFloat(lhs) / rhs 45 | } 46 | 47 | public func /(lhs: CGFloat, rhs: Int) -> CGFloat { 48 | return lhs / CGFloat(rhs) 49 | } -------------------------------------------------------------------------------- /StarConsoleLink/Extensions/String-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | #if os(iOS) || os(tvOS) 13 | import UIKit 14 | public typealias Font = UIFont 15 | #else 16 | import AppKit 17 | public typealias Font = NSFont 18 | #endif 19 | 20 | extension NSString { 21 | 22 | var swiftString: String { 23 | get { 24 | return self as String 25 | } 26 | } 27 | 28 | func sizeWithFont(_ font: Font,maxSize:CGSize) -> CGSize { 29 | return self.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName : font], context: nil).size 30 | } 31 | } 32 | 33 | 34 | 35 | 36 | extension String { 37 | 38 | var OCString: NSString { 39 | get { 40 | return self as NSString 41 | } 42 | } 43 | 44 | // subscript (r: Range) -> String { 45 | // get { 46 | // let startIndex = self.characters.index(self.startIndex, offsetBy: r.lowerBound) 47 | // let endIndex = <#T##String.CharacterView corresponding to `startIndex`##String.CharacterView#>.index(startIndex, offsetBy: r.upperBound - r.lowerBound) 48 | // return self[startIndex ..< endIndex] 49 | // // return self[Range(start: startIndex, end: endIndex)] 50 | // } 51 | // } 52 | 53 | // func rangeFromNSRange(_ nsRange : NSRange) -> Range? { 54 | // 55 | // let from16 = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex) 56 | // let to16 = from16.advancedBy(nsRange.length, limit: utf16.endIndex) 57 | // if let from = String.Index(from16, within: self), 58 | // let to = String.Index(to16, within: self) { 59 | // return from ..< to 60 | // } 61 | // return nil 62 | // } 63 | 64 | // func NSRangeFromRange(_ range : Range) -> NSRange { 65 | // let utf16view = self.utf16 66 | // let from = String.UTF16View.Index(range.lowerBound, within: utf16view) 67 | // let to = String.UTF16View.Index(range.upperBound, within: utf16view) 68 | // return NSMakeRange(utf16view.startIndex.distanceTo(from), from.distanceTo(to)) 69 | // } 70 | // 71 | var length:Int{ 72 | get { 73 | // return self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) 74 | return self.characters.count 75 | } 76 | } 77 | 78 | var lastPathComponent: String { 79 | get { 80 | return self.OCString.lastPathComponent 81 | } 82 | } 83 | 84 | func isAllDigit() -> Bool { 85 | for uni in unicodeScalars{ 86 | if CharacterSet.decimalDigits.contains(UnicodeScalar(uni.value)!){ 87 | continue 88 | } 89 | return false 90 | } 91 | return true 92 | } 93 | 94 | var isEmptyOrWhiteSpace: Bool { 95 | if self.trimmingCharacters(in: CharacterSet.whitespaces).isEmpty { 96 | return true 97 | } 98 | return false 99 | } 100 | 101 | func sizeWithFont(_ font: Font, maxSize:CGSize) -> CGSize { 102 | return self.OCString.sizeWithFont(font, maxSize: maxSize) 103 | } 104 | 105 | static func isNullOrEmpty(_ str: String?) -> Bool { 106 | if str == nil { 107 | return true 108 | } 109 | if str!.isEmpty { 110 | return true 111 | } 112 | return false 113 | } 114 | 115 | static func isNullOrWhiteSpace(_ str: String?) -> Bool { 116 | if str == nil { 117 | return true 118 | } 119 | if str!.trimmingCharacters(in: CharacterSet.whitespaces).isEmpty { 120 | return true 121 | } 122 | return false 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /StarConsoleLink/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.4 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.4.1 25 | DVTPlugInCompatibilityUUIDs 26 | 27 | D7881182-AD00-4C36-A94D-F45FC9B0CF85 28 | EE23884D-A5C0-4163-94CF-DBBF3A5ED8D6 29 | B395D63E-9166-4CD6-9287-6889D507AD6A 30 | C3998872-68CC-42C2-847C-B44D96AB2691 31 | DF11C142-1584-4A99-87AC-1925D5F5652A 32 | DFFB3951-EB0A-4C09-9DAC-5F2D28CC839C 33 | FEC992CC-CA4A-4CFD-8881-77300FCB848A 34 | C4A681B0-4A26-480E-93EC-1218098B9AA0 35 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 36 | AD68E85B-441B-4301-B564-A45E4919A6AD 37 | 63FC1C47-140D-42B0-BB4D-A10B2D225574 38 | 37B30044-3B14-46BA-ABAA-F01000C27B63 39 | 640F884E-CE55-4B40-87C0-8869546CAB7A 40 | 992275C1-432A-4CF7-B659-D84ED6D42D3F 41 | A16FF353-8441-459E-A50C-B071F53F51B7 42 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7 43 | E969541F-E6F9-4D25-8158-72DC3545A6C6 44 | 8DC44374-2B35-4C57-A6FE-2AD66A36AAD9 45 | AABB7188-E14E-4433-AD3B-5CD791EAD9A3 46 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90 47 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 48 | CC0D0F4F-05B3-431A-8F33-F84AFCB2C651 49 | 7265231C-39B4-402C-89E1-16167C4CC990 50 | 9AFF134A-08DC-4096-8CEE-62A4BB123046 51 | F41BD31E-2683-44B8-AE7F-5F09E919790E 52 | E71C2CFE-BFD8-4044-8F06-00AE685A406C 53 | ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C 54 | 55 | LSMinimumSystemVersion 56 | $(MACOSX_DEPLOYMENT_TARGET) 57 | NSPrincipalClass 58 | StarConsoleLink 59 | XC4Compatible 60 | 61 | XCPluginHasUI 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /StarConsoleLink/Library/JRSwizzle/JRSwizzle.h: -------------------------------------------------------------------------------- 1 | // JRSwizzle.h semver:1.0 2 | // Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com 3 | // Some rights reserved: http://opensource.org/licenses/MIT 4 | // https://github.com/rentzsch/jrswizzle 5 | 6 | #import 7 | 8 | @interface NSObject (JRSwizzle) 9 | 10 | + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_; 11 | + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_; 12 | 13 | @end -------------------------------------------------------------------------------- /StarConsoleLink/Library/JRSwizzle/JRSwizzle.m: -------------------------------------------------------------------------------- 1 | // JRSwizzle.m semver:1.0 2 | // Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com 3 | // Some rights reserved: http://opensource.org/licenses/MIT 4 | // https://github.com/rentzsch/jrswizzle 5 | 6 | #import "JRSwizzle.h" 7 | 8 | #if TARGET_OS_IPHONE 9 | #import 10 | #import 11 | #else 12 | #import 13 | #endif 14 | 15 | #define SetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \ 16 | if (ERROR_VAR) { \ 17 | NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \ 18 | *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \ 19 | code:-1 \ 20 | userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \ 21 | } 22 | #define SetNSError(ERROR_VAR, FORMAT,...) SetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__) 23 | 24 | #if OBJC_API_VERSION >= 2 25 | #define GetClass(obj) object_getClass(obj) 26 | #else 27 | #define GetClass(obj) (obj ? obj->isa : Nil) 28 | #endif 29 | 30 | @implementation NSObject (JRSwizzle) 31 | 32 | + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ { 33 | #if OBJC_API_VERSION >= 2 34 | Method origMethod = class_getInstanceMethod(self, origSel_); 35 | if (!origMethod) { 36 | #if TARGET_OS_IPHONE 37 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]); 38 | #else 39 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); 40 | #endif 41 | return NO; 42 | } 43 | 44 | Method altMethod = class_getInstanceMethod(self, altSel_); 45 | if (!altMethod) { 46 | #if TARGET_OS_IPHONE 47 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self class]); 48 | #else 49 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); 50 | #endif 51 | return NO; 52 | } 53 | 54 | class_addMethod(self, 55 | origSel_, 56 | class_getMethodImplementation(self, origSel_), 57 | method_getTypeEncoding(origMethod)); 58 | class_addMethod(self, 59 | altSel_, 60 | class_getMethodImplementation(self, altSel_), 61 | method_getTypeEncoding(altMethod)); 62 | 63 | method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_)); 64 | return YES; 65 | #else 66 | // Scan for non-inherited methods. 67 | Method directOriginalMethod = NULL, directAlternateMethod = NULL; 68 | 69 | void *iterator = NULL; 70 | struct objc_method_list *mlist = class_nextMethodList(self, &iterator); 71 | while (mlist) { 72 | int method_index = 0; 73 | for (; method_index < mlist->method_count; method_index++) { 74 | if (mlist->method_list[method_index].method_name == origSel_) { 75 | assert(!directOriginalMethod); 76 | directOriginalMethod = &mlist->method_list[method_index]; 77 | } 78 | if (mlist->method_list[method_index].method_name == altSel_) { 79 | assert(!directAlternateMethod); 80 | directAlternateMethod = &mlist->method_list[method_index]; 81 | } 82 | } 83 | mlist = class_nextMethodList(self, &iterator); 84 | } 85 | 86 | // If either method is inherited, copy it up to the target class to make it non-inherited. 87 | if (!directOriginalMethod || !directAlternateMethod) { 88 | Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL; 89 | if (!directOriginalMethod) { 90 | inheritedOriginalMethod = class_getInstanceMethod(self, origSel_); 91 | if (!inheritedOriginalMethod) { 92 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); 93 | return NO; 94 | } 95 | } 96 | if (!directAlternateMethod) { 97 | inheritedAlternateMethod = class_getInstanceMethod(self, altSel_); 98 | if (!inheritedAlternateMethod) { 99 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); 100 | return NO; 101 | } 102 | } 103 | 104 | int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1; 105 | struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1))); 106 | hoisted_method_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind 107 | hoisted_method_list->method_count = hoisted_method_count; 108 | Method hoisted_method = hoisted_method_list->method_list; 109 | 110 | if (!directOriginalMethod) { 111 | bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method)); 112 | directOriginalMethod = hoisted_method++; 113 | } 114 | if (!directAlternateMethod) { 115 | bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method)); 116 | directAlternateMethod = hoisted_method; 117 | } 118 | class_addMethods(self, hoisted_method_list); 119 | } 120 | 121 | // Swizzle. 122 | IMP temp = directOriginalMethod->method_imp; 123 | directOriginalMethod->method_imp = directAlternateMethod->method_imp; 124 | directAlternateMethod->method_imp = temp; 125 | 126 | return YES; 127 | #endif 128 | } 129 | 130 | + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ { 131 | return [GetClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_]; 132 | } 133 | 134 | @end -------------------------------------------------------------------------------- /StarConsoleLink/Library/LogColor/LogColorKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // LogColorKit.h 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/19. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface LogColorKit : NSObject 13 | 14 | + (void)applyANSIColors:(NSTextStorage *)textStorage 15 | textStorageRange:(NSRange)textStorageRange 16 | escapeSeq:(NSString *)escapeSeq; 17 | void ApplyANSIColors(NSTextStorage *textStorage, NSRange textStorageRange, NSString *escapeSeq); 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /StarConsoleLink/Library/LogColor/LogColorKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // LogColorKit.m 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/19. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import "LogColorKit.h" 10 | 11 | @implementation LogColorKit 12 | 13 | + (void)applyANSIColors:(NSTextStorage *)textStorage textStorageRange:(NSRange)textStorageRange escapeSeq:(NSString *)escapeSeq { 14 | ApplyANSIColors(textStorage, textStorageRange, escapeSeq); 15 | } 16 | 17 | // https://github.com/robbiehanson/XcodeColors 18 | void ApplyANSIColors(NSTextStorage *textStorage, NSRange textStorageRange, NSString *escapeSeq) { 19 | NSRange range = [[textStorage string] rangeOfString:escapeSeq options:0 range:textStorageRange]; 20 | if (range.location == NSNotFound) 21 | { 22 | // No escape sequence(s) in the string. 23 | return; 24 | } 25 | 26 | // Architecture: 27 | // 28 | // We're going to split the string into components separated by the given escape sequence. 29 | // Then we're going to loop over the components, looking for color codes at the beginning of each component. 30 | // 31 | // For example, if the input string is "Hello__fg124,12,12;World" (with __ representing the escape sequence), 32 | // then our components would be: ( 33 | // "Hello" 34 | // "fg124,12,12;World" 35 | // ) 36 | // 37 | // We would find a color code (rgb 124, 12, 12) for the foreground color in the second component. 38 | // At that point, the parsed foreground color goes into an attributes dictionary (attrs), 39 | // and the foreground color stays in effect (for the current component & future components) 40 | // until it gets cleared via a different foreground color, or a clear sequence. 41 | // 42 | // The attributes are applied to the entire range of the component, and then we move onto the next component. 43 | // 44 | // At the very end, we go back and apply "invisible" attributes (zero font, and clear text) 45 | // to the escape and color sequences. 46 | 47 | 48 | NSString *affectedString = [[textStorage string] substringWithRange:textStorageRange]; 49 | 50 | // Split the string into components separated by the given escape sequence. 51 | 52 | NSArray *components = [affectedString componentsSeparatedByString:escapeSeq]; 53 | 54 | NSRange componentRange = textStorageRange; 55 | componentRange.length = 0; 56 | 57 | BOOL firstPass = YES; 58 | 59 | NSMutableArray *seqRanges = [NSMutableArray arrayWithCapacity:[components count]]; 60 | NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithCapacity:2]; 61 | 62 | for (NSString *component in components) 63 | { 64 | if (firstPass) 65 | { 66 | // The first component in the array won't need processing. 67 | // If there was an escape sequence at the very beginning of the string, 68 | // then the first component in the array will be an empty string. 69 | // Otherwise the first component is everything before the first escape sequence. 70 | } 71 | else 72 | { 73 | // componentSeqRange : Range of escape sequence within component, e.g. "fg124,12,12;" 74 | 75 | NSColor *color = nil; 76 | NSUInteger colorCodeSeqLength = 0; 77 | 78 | BOOL stop = NO; 79 | 80 | BOOL reset = !stop && (stop = [component hasPrefix:@";"]); 81 | BOOL fg = !stop && (stop = [component hasPrefix:@"fg"]); 82 | BOOL bg = !stop && (stop = [component hasPrefix:@"bg"]); 83 | 84 | BOOL resetFg = fg && [component hasPrefix:@"fg;"]; 85 | BOOL resetBg = bg && [component hasPrefix:@"bg;"]; 86 | 87 | if (reset) 88 | { 89 | // Reset attributes 90 | [attrs removeObjectForKey:NSForegroundColorAttributeName]; 91 | [attrs removeObjectForKey:NSBackgroundColorAttributeName]; 92 | 93 | // Mark the range of the sequence (escape sequence + reset color sequence). 94 | NSRange seqRange = (NSRange){ 95 | .location = componentRange.location - [escapeSeq length], 96 | .length = 1 + [escapeSeq length], 97 | }; 98 | [seqRanges addObject:[NSValue valueWithRange:seqRange]]; 99 | } 100 | else if (resetFg || resetBg) 101 | { 102 | // Reset attributes 103 | if (resetFg) 104 | [attrs removeObjectForKey:NSForegroundColorAttributeName]; 105 | else 106 | [attrs removeObjectForKey:NSBackgroundColorAttributeName]; 107 | 108 | // Mark the range of the sequence (escape sequence + reset color sequence). 109 | NSRange seqRange = (NSRange){ 110 | .location = componentRange.location - [escapeSeq length], 111 | .length = 3 + [escapeSeq length], 112 | }; 113 | [seqRanges addObject:[NSValue valueWithRange:seqRange]]; 114 | } 115 | else if (fg || bg) 116 | { 117 | // Looking for something like this: "fg124,22,12;" or "bg17,24,210;". 118 | // These are the rgb values for the foreground or background. 119 | 120 | NSString *str_r = nil; 121 | NSString *str_g = nil; 122 | NSString *str_b = nil; 123 | 124 | NSRange range_search = NSMakeRange(2, MIN(4, [component length] - 2)); 125 | NSRange range_separator; 126 | NSRange range_value; 127 | 128 | // Search for red separator 129 | range_separator = [component rangeOfString:@"," options:0 range:range_search]; 130 | if (range_separator.location != NSNotFound) 131 | { 132 | // Extract red substring 133 | range_value.location = range_search.location; 134 | range_value.length = range_separator.location - range_search.location; 135 | 136 | str_r = [component substringWithRange:range_value]; 137 | 138 | // Update search range 139 | range_search.location = range_separator.location + range_separator.length; 140 | range_search.length = MIN(4, [component length] - range_search.location); 141 | 142 | // Search for green separator 143 | range_separator = [component rangeOfString:@"," options:0 range:range_search]; 144 | if (range_separator.location != NSNotFound) 145 | { 146 | // Extract green substring 147 | range_value.location = range_search.location; 148 | range_value.length = range_separator.location - range_search.location; 149 | 150 | str_g = [component substringWithRange:range_value]; 151 | 152 | // Update search range 153 | range_search.location = range_separator.location + range_separator.length; 154 | range_search.length = MIN(4, [component length] - range_search.location); 155 | 156 | // Search for blue separator 157 | range_separator = [component rangeOfString:@";" options:0 range:range_search]; 158 | if (range_separator.location != NSNotFound) 159 | { 160 | // Extract blue substring 161 | range_value.location = range_search.location; 162 | range_value.length = range_separator.location - range_search.location; 163 | 164 | str_b = [component substringWithRange:range_value]; 165 | 166 | // Mark the length of the entire color code sequence. 167 | colorCodeSeqLength = range_separator.location + range_separator.length; 168 | } 169 | } 170 | } 171 | 172 | if (str_r && str_g && str_b) 173 | { 174 | // Parse rgb values and create color 175 | 176 | int r = MAX(0, MIN(255, [str_r intValue])); 177 | int g = MAX(0, MIN(255, [str_g intValue])); 178 | int b = MAX(0, MIN(255, [str_b intValue])); 179 | 180 | color = [NSColor colorWithCalibratedRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0]; 181 | 182 | if (fg) { 183 | [attrs setObject:color forKey:NSForegroundColorAttributeName]; 184 | } 185 | else { 186 | [attrs setObject:color forKey:NSBackgroundColorAttributeName]; 187 | } 188 | 189 | //NSString *realString = [component substringFromIndex:colorCodeSeqLength]; 190 | 191 | // Mark the range of the entire sequence (escape sequence + color code sequence). 192 | NSRange seqRange = (NSRange){ 193 | .location = componentRange.location - [escapeSeq length], 194 | .length = colorCodeSeqLength + [escapeSeq length], 195 | }; 196 | [seqRanges addObject:[NSValue valueWithRange:seqRange]]; 197 | } 198 | else 199 | { 200 | // Wasn't able to parse a color code 201 | 202 | [attrs removeObjectForKey:NSForegroundColorAttributeName]; 203 | [attrs removeObjectForKey:NSBackgroundColorAttributeName]; 204 | 205 | NSRange seqRange = (NSRange){ 206 | .location = componentRange.location - [escapeSeq length], 207 | .length = [escapeSeq length], 208 | }; 209 | [seqRanges addObject:[NSValue valueWithRange:seqRange]]; 210 | } 211 | } 212 | } 213 | 214 | componentRange.length = [component length]; 215 | 216 | [textStorage addAttributes:attrs range:componentRange]; 217 | 218 | componentRange.location += componentRange.length + [escapeSeq length]; 219 | firstPass = NO; 220 | 221 | } // END: for (NSString *component in components) 222 | 223 | 224 | // Now loop over all the discovered sequences, and apply "invisible" attributes to them. 225 | 226 | if ([seqRanges count] > 0) 227 | { 228 | NSDictionary *clearAttrs = 229 | [NSDictionary dictionaryWithObjectsAndKeys: 230 | [NSFont systemFontOfSize:0.001], NSFontAttributeName, 231 | [NSColor clearColor], NSForegroundColorAttributeName, nil]; 232 | 233 | for (NSValue *seqRangeValue in seqRanges) 234 | { 235 | NSRange seqRange = [seqRangeValue rangeValue]; 236 | [textStorage addAttributes:clearAttrs range:seqRange]; 237 | } 238 | } 239 | } 240 | 241 | @end 242 | -------------------------------------------------------------------------------- /StarConsoleLink/Library/PluginHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PluginHelper.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AppKit 11 | //import XcodeKit 12 | 13 | 14 | // MARK: - File Cache & Find File 15 | 16 | // [workspacePath : [fileName : filePath]] 17 | var filePathCache = [String : [String : String]]() 18 | 19 | func findFile(_ workspacePath : String, _ fileName : String) -> String? { 20 | var thisWorkspaceCache = filePathCache[workspacePath] ?? [:] 21 | if let result = thisWorkspaceCache[fileName] { 22 | if FileManager.default.fileExists(atPath: result) { 23 | return result 24 | } 25 | } 26 | 27 | var searchPath = workspacePath 28 | var prevSearchPath : String? = nil 29 | var searchCount = 0 30 | while true { 31 | if let result = findFile(fileName, searchPath, prevSearchPath) , !result.isEmpty { 32 | thisWorkspaceCache[fileName] = result 33 | filePathCache[workspacePath] = thisWorkspaceCache 34 | return result 35 | } 36 | 37 | prevSearchPath = searchPath 38 | searchPath = searchPath.OCString.deletingLastPathComponent 39 | searchCount += 1 40 | let searchPathCount = searchPath.components(separatedBy: "/").count 41 | if searchPathCount <= 3 || searchCount >= 2 { 42 | return nil 43 | } 44 | } 45 | } 46 | 47 | func findFile(_ fileName : String, _ searchPath : String, _ prevSearchPath : String?) -> String? { 48 | let args = (prevSearchPath == nil ? 49 | ["-L", searchPath, "-name", fileName, "-print", "-quit"] : 50 | ["-L", searchPath, "-name", prevSearchPath!, "-prune", "-o", "-name", fileName, "-print", "-quit"]) 51 | return PluginHelper.runShellCommand("/usr/bin/find", arguments: args) 52 | } 53 | 54 | 55 | // MARK: - PluginHelper 56 | 57 | class PluginHelper: NSObject { 58 | 59 | static func runShellCommand(_ launchPath: String, arguments: [String]) -> String? { 60 | let pipe = Pipe() 61 | let task = Process() 62 | task.launchPath = launchPath 63 | task.arguments = arguments 64 | task.standardOutput = pipe 65 | let file = pipe.fileHandleForReading 66 | task.launch() 67 | guard let result = NSString(data: file.readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue)?.trimmingCharacters(in: CharacterSet.newlines) else { 68 | return nil 69 | } 70 | return result as String 71 | } 72 | 73 | static func getViewByClassName(_ name: String, inContainer container: NSView) -> NSView? { 74 | 75 | guard let targetClass = NSClassFromString(name) else { 76 | return nil 77 | } 78 | for subview in container.subviews { 79 | if subview.isKind(of: targetClass) { 80 | return subview 81 | } 82 | if let view = getViewByClassName(name, inContainer: subview) { 83 | return view 84 | } 85 | } 86 | return nil 87 | } 88 | } 89 | 90 | extension PluginHelper { 91 | 92 | static func workspacePath() -> String? { 93 | 94 | if let workspacePath = StarFunctions.workspacePath() { 95 | return workspacePath 96 | } 97 | 98 | guard let anyClass = NSClassFromString("IDEWorkspaceWindowController") as? NSObject.Type, 99 | let windowControllers = anyClass.value(forKey: "workspaceWindowControllers") as? [NSObject], 100 | let window = NSApp.keyWindow ?? NSApp.windows.first else { 101 | Logger.info("Failed to establish workspace path") 102 | return nil 103 | } 104 | var workspace: NSObject? 105 | for controller in windowControllers { 106 | if (controller.value(forKey: "window") as AnyObject).isEqual(window) == true { 107 | workspace = controller.value(forKey: "_workspace") as? NSObject 108 | } 109 | } 110 | 111 | guard let workspacePath = workspace?.value(forKeyPath: "representingFilePath._pathString") as? NSString else { 112 | Logger.info("Failed to establish workspace path") 113 | return nil 114 | } 115 | 116 | return workspacePath.deletingLastPathComponent as String 117 | } 118 | 119 | // 代码台 120 | static func editorTextView(inWindow window: NSWindow? = NSApp.mainWindow) -> NSTextView? { 121 | guard let window = window, 122 | let windowController = window.windowController, 123 | let editor = windowController.value(forKeyPath: "editorArea.lastActiveEditorContext.editor"), 124 | let textView = (editor as AnyObject).value(forKey: "textView") as? NSTextView else { 125 | return nil 126 | } 127 | return textView 128 | // let window = window! 129 | // let windowController = window.windowController! 130 | // let editor = windowController.value(forKeyPath: "editorArea.lastActiveEditorContext.editor")! 131 | // let textView = (editor as AnyObject).value(forKey: "textView") as! NSView 132 | 133 | // SourceCodeEditorView 134 | } 135 | 136 | // DVTSourceTextView 控制台 137 | static func consoleTextView(inWindow window: NSWindow? = NSApp.mainWindow) -> NSTextView? { 138 | guard let contentView = window?.contentView, 139 | let consoleTextView = PluginHelper.getViewByClassName("IDEConsoleTextView", inContainer: contentView) as? NSTextView else { 140 | return nil 141 | } 142 | return consoleTextView 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /StarConsoleLink/Library/StarFunctions.h: -------------------------------------------------------------------------------- 1 | // 2 | // StarFunctions.h 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/25. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StarFunctions: NSObject 12 | + (NSString*)workspacePath; 13 | + (void)printMothList:(Class)class; 14 | + (NSArray *)getAllProperties:(Class)class; 15 | + (NSDictionary *)properties_aps:(Class)class; 16 | @end -------------------------------------------------------------------------------- /StarConsoleLink/Library/StarFunctions.m: -------------------------------------------------------------------------------- 1 | // 2 | // StarFunctions.m 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/25. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import "StarFunctions.h" 10 | #import 11 | #import "JRSwizzle.h" 12 | 13 | @implementation StarFunctions 14 | 15 | + (NSString*)workspacePath { 16 | @try { 17 | NSDocument *document = [NSApp orderedDocuments].firstObject; 18 | return [[document valueForKeyPath:@"_workspace.representingFilePath.fileURL"] URLByDeletingLastPathComponent].path; 19 | } 20 | @catch (NSException *exception) { 21 | return nil; 22 | } 23 | return nil; 24 | } 25 | 26 | + (void)printMothList:(Class)class { 27 | unsigned int mothCout_f =0; 28 | Method* mothList_f = class_copyMethodList(class, &mothCout_f); 29 | for(int i=0;i [%s][%s:%d] %s %s %s\n",\ 62 | STAR_CONSOLE_COLOR_ESCAPE_FG,\ 63 | color,\ 64 | star_current_time(),\ 65 | title,\ 66 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 67 | __LINE__,\ 68 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String],\ 69 | STAR_CONSOLE_COLOR_RESET_FG,\ 70 | star_back_trace(stack, StarBackTraceDepth)\ 71 | )\ 72 | 73 | // NSLog 74 | #define NSLog(format, ...) \ 75 | PrivateLog(NSLogColor, NSLogTitle, StarBackTrace, format, ##__VA_ARGS__) 76 | 77 | // Information 78 | #define LogInfo(format, ...) \ 79 | PrivateLog(InfoColor, InfoTitle, StarBackTrace, format, ##__VA_ARGS__) 80 | 81 | // Debug 82 | #define LogDebug(format, ...) \ 83 | PrivateLog(DebugColor, DebugTitle, StarBackTrace, format, ##__VA_ARGS__) 84 | 85 | // Warning 86 | #define LogWarning(format, ...) \ 87 | PrivateLog(WarningColor, WarningTitle, StarBackTrace, format, ##__VA_ARGS__) 88 | 89 | // Error 90 | #define LogError(format, ...) \ 91 | PrivateLog(ErrorColor, ErrorTitle, StarBackTrace, format, ##__VA_ARGS__) 92 | 93 | // Success 94 | #define LogSuccess(format, ...) \ 95 | PrivateLog(SuccessColor, SuccessTitle, StarBackTrace, format, ##__VA_ARGS__) 96 | 97 | // Failure 98 | #define LogFailure(format, ...) \ 99 | PrivateLog(FailureColor, FailureTitle, StarBackTrace, format, ##__VA_ARGS__) 100 | 101 | // Assert 102 | #define LogAssert(condition, format, ...)\ 103 | PrivateLog(AssertColor, AssertTitle, StarBackTrace, format, ##__VA_ARGS__);\ 104 | NSAssert(condition, format, ##__VA_ARGS__) 105 | 106 | // LogBackTrace 107 | #define LogBackTrace(format, ...) \ 108 | PrivateLog(BackTraceColor, BackTraceTitle, 1, format, ##__VA_ARGS__)\ 109 | 110 | #else /* Color Else */ 111 | 112 | #define PrivateLog(color, title, stack, format, ...)\ 113 | printf("<%s> [%s][%s:%d] %s %s\n",\ 114 | star_current_time(),\ 115 | title,\ 116 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 117 | __LINE__,\ 118 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String],\ 119 | star_back_trace(stack, StarBackTraceDepth)\ 120 | );\ 121 | 122 | // NSLog 123 | #define NSLog(format, ...) \ 124 | PrivateLog(0, NSLogTitle, StarBackTrace, format, ##__VA_ARGS__) 125 | 126 | // Information 127 | #define LogInfo(format, ...) \ 128 | PrivateLog(0, InfoTitle, StarBackTrace, format, ##__VA_ARGS__) 129 | 130 | // Debug 131 | #define LogDebug(format, ...) \ 132 | PrivateLog(0, DebugTitle, StarBackTrace, format, ##__VA_ARGS__) 133 | 134 | // Warning 135 | #define LogWarning(format, ...) \ 136 | PrivateLog(0, WarningTitle, StarBackTrace, format, ##__VA_ARGS__) 137 | 138 | // Error 139 | #define LogError(format, ...) \ 140 | PrivateLog(0, ErrorTitle, StarBackTrace, format, ##__VA_ARGS__) 141 | 142 | // Success 143 | #define LogSuccess(format, ...) \ 144 | PrivateLog(0, SuccessTitle, StarBackTrace, format, ##__VA_ARGS__) 145 | 146 | // Failure 147 | #define LogFailure(format, ...) \ 148 | PrivateLog(0, FailureTitle, StarBackTrace, format, ##__VA_ARGS__) 149 | 150 | // Assert 151 | #define LogAssert(condition, format, ...)\ 152 | PrivateLog(0, FailureTitle, StarBackTrace, format, ##__VA_ARGS__);\ 153 | NSAssert(condition, format, ##__VA_ARGS__) 154 | 155 | // Stack 156 | #define LogBackTrace(format, ...) \ 157 | PrivateLog(0, BackTraceTitle, 1, format, ##__VA_ARGS__)\ 158 | 159 | #endif /* Color End */ 160 | 161 | #else /* Debug Else */ 162 | 163 | #define PrivateLog(color, title, format, ...) while(0){} 164 | #define NSLog(...) while(0){} 165 | #define LogInfo(...) while(0){} 166 | #define LogDebug(...) while(0){} 167 | #define LogError(...) while(0){} 168 | #define LogWarning(...) while(0){} 169 | #define LogSuccess(...) while(0){} 170 | #define LogFailure(...) while(0){} 171 | #define LogAssert(condition, format, ...) while(0){} 172 | #define LogBackTrace(...) while(0){} 173 | 174 | #endif /* Debug End */ 175 | 176 | 177 | 178 | 179 | /* Function Begin */ 180 | 181 | #include 182 | #include 183 | #include 184 | #include 185 | #include 186 | #include 187 | 188 | #define STAR_BACK_TRACE_BUFFER 4096 189 | #define STAR_TIME_BUFFER 255 190 | 191 | 192 | static inline const char * star_back_trace(int open, int depth) { 193 | 194 | if (!open) { 195 | return ""; 196 | } 197 | 198 | static char star_back_trace_str[STAR_BACK_TRACE_BUFFER]; 199 | 200 | void *callstack[128]; 201 | int frames = backtrace(callstack, 128); 202 | char **strs = backtrace_symbols(callstack, frames); 203 | 204 | memset(star_back_trace_str, 0, STAR_BACK_TRACE_BUFFER * sizeof(char)); 205 | strcat(star_back_trace_str, "\n"); 206 | for (int i = 1; i < frames; i++) { 207 | // if (strlen(star_back_trace_str) + strlen(strs[i]) + 16 > STAR_BACK_TRACE_BUFFER) 208 | // break; 209 | strcat(star_back_trace_str, "\n\t"); 210 | strcat(star_back_trace_str, strs[i]); 211 | if (i == depth) 212 | break; 213 | } 214 | strcat(star_back_trace_str, "\n"); 215 | 216 | free(strs); 217 | strs = NULL; 218 | 219 | return star_back_trace_str; 220 | } 221 | 222 | static inline const char * star_current_time() { 223 | 224 | static char star_time_str[STAR_TIME_BUFFER]; 225 | 226 | time_t rawtime; 227 | struct tm * timeinfo; 228 | time(&rawtime); 229 | timeinfo = localtime(&rawtime); 230 | memset(star_time_str, 0, STAR_TIME_BUFFER * sizeof(char)); 231 | strftime(star_time_str, STAR_TIME_BUFFER, "%Y-%m-%d %H:%M:%S", timeinfo); 232 | return star_time_str; 233 | } 234 | 235 | /** 236 | * 如果需要用到毫秒,那就替换成下列函数好了 237 | */ 238 | static inline const char * star_current_time_milli() { 239 | 240 | static char star_time_str[STAR_TIME_BUFFER]; 241 | 242 | struct timeb timeinfo; 243 | ftime(&timeinfo); 244 | 245 | struct tm * second_timeinfo; 246 | second_timeinfo = localtime(&timeinfo.time); 247 | 248 | memset(star_time_str, 0, STAR_TIME_BUFFER * sizeof(char)); 249 | strftime(star_time_str, STAR_TIME_BUFFER, "%Y-%m-%d %H:%M:%S", second_timeinfo); 250 | 251 | //#if using_millitm 252 | char millitm[16]; 253 | sprintf(millitm, ".%03d", timeinfo.millitm); 254 | strcat(star_time_str, millitm); 255 | //#endif 256 | 257 | return star_time_str; 258 | } 259 | 260 | /* Function End */ 261 | 262 | 263 | 264 | #endif /* Logger_h */ 265 | -------------------------------------------------------------------------------- /StarConsoleLink/Logger/Logger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // 控制是否启用日志打印 12 | // 此处的DEBUG应该在target下 Build Settings 搜索 Other Swift Flags 13 | // 设置Debug 添加 -D DEBUG,注意不要好Release一起添加 14 | #if DEBUG 15 | let StarDebug = true 16 | #else 17 | let StarDebug = false 18 | #endif 19 | 20 | 21 | struct LogColor { 22 | 23 | static let XcodeColors = true 24 | 25 | static let ESCAPE = "\u{001b}[" 26 | static let ESCAPE_FG = "\u{001b}[fg" 27 | static let ESCAPE_BG = "\u{001b}[bg" 28 | 29 | static let RESET = ESCAPE + ";" // Clear any foreground or background color 30 | static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color 31 | static let RESET_BG = ESCAPE + "bg;" // Clear any background color 32 | } 33 | 34 | let InfoColor = "22,22,22" // 黑色 35 | let InfoTitle = "Info" 36 | 37 | let DebugColor = "28,0,207" // 蓝色 38 | let DebugTitle = "Debug" 39 | 40 | let WarningColor = "218,130,53" // 黄色 41 | let WarningTitle = "Warning" 42 | 43 | let ErrorColor = "196,26,22" // 红色 44 | let ErrorTitle = "Error" 45 | 46 | let ImportantColor = "196,26,22" // 红色 47 | let ImportantTitle = "Important - 如果发现该行日志,应该及时处理" 48 | 49 | let SuccessColor = "0,116,0" // 绿色 50 | let SuccessTitle = "Success" 51 | 52 | let FailureColor = "196,26,22" // 红色 53 | let FailureTitle = "Failure" 54 | 55 | let AssertColor = "196,26,22" // 红色 56 | let AssertTitle = "Assert" 57 | 58 | let FatalErrorColor = "196,26,22" // 红色 59 | let FatalErrorTitle = "FatalError" 60 | 61 | //#if swift(>=2.2) 62 | // let functionName = #function 63 | //#else 64 | // let functionName = __FUNCTION__ 65 | //#endif 66 | 67 | struct Logger { 68 | 69 | static func print(_ value: T, title: String, color: String, functionName: String, fileName: String, lineNumber: Int) { 70 | 71 | guard StarDebug else { 72 | return 73 | } 74 | if LogColor.XcodeColors { 75 | Swift.print("\(LogColor.ESCAPE_FG)\(color);<\(current_time())> [\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)\(LogColor.RESET_FG)") 76 | } 77 | else { 78 | Swift.print("<\(current_time())> [\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)") 79 | } 80 | } 81 | 82 | static func info(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 83 | print(value, title: InfoTitle, color: InfoColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 84 | } 85 | 86 | static func debug(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 87 | print(value, title: DebugTitle, color: DebugColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 88 | } 89 | 90 | static func warning(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 91 | print(value, title: WarningTitle, color: WarningColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 92 | } 93 | 94 | static func error(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 95 | print(value, title: ErrorTitle, color: ErrorColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 96 | } 97 | 98 | static func important(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 99 | print(value, title: ImportantTitle, color: ImportantColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 100 | } 101 | 102 | fileprivate static func current_time() -> String { 103 | let bufferSize = 255 104 | var buffer = [Int8](repeating: 0, count: bufferSize) 105 | var rawtime = time(nil) 106 | let timeinfo = localtime(&rawtime) 107 | strftime(&buffer, 32, "%Y-%m-%d %H:%M:%S", timeinfo) // %B 108 | // String 109 | let datetime = String(cString: buffer, encoding: String.Encoding.utf8)! 110 | // free(buffer) 111 | return datetime 112 | } 113 | 114 | static func star_back_trace(_ depth: UInt) -> String { 115 | 116 | 117 | Swift.print(Thread.callStackSymbols); 118 | 119 | 120 | // void *callstack[128]; 121 | // int frames = backtrace(callstack, 128); 122 | // char **strs = backtrace_symbols(callstack, frames); 123 | // 124 | // memset(star_back_trace_str, 0, STAR_BACK_TRACE_BUFFER * sizeof(char)); 125 | // strcat(star_back_trace_str, "\n"); 126 | // for (int i = 1; i < frames; i++) { 127 | // // if (strlen(star_back_trace_str) + strlen(strs[i]) + 16 > STAR_BACK_TRACE_BUFFER) 128 | // // break; 129 | // strcat(star_back_trace_str, "\n\t"); 130 | // strcat(star_back_trace_str, strs[i]); 131 | // if (i == depth) 132 | // break; 133 | // } 134 | // strcat(star_back_trace_str, "\n"); 135 | // 136 | // free(strs); 137 | // strs = NULL; 138 | // 139 | // return star_back_trace_str; 140 | return ""; 141 | } 142 | 143 | } 144 | 145 | // MARK: - Resoponse 146 | extension Logger { 147 | 148 | static func success(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 149 | print(value, title: SuccessTitle, color: SuccessColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 150 | } 151 | 152 | static func failure(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 153 | print(value, title: FailureTitle, color: FailureColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 154 | } 155 | } 156 | 157 | // MARK: - Assert 158 | extension Logger { 159 | 160 | static func assertionFailure(_ value: String, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 161 | print(value, title: AssertTitle, color: AssertColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 162 | Swift.assertionFailure(value) 163 | 164 | } 165 | 166 | static func assert(_ flag: Bool, value:String, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 167 | print(value, title: AssertTitle, color: AssertColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 168 | Swift.assert(flag) 169 | } 170 | 171 | static func fatalError(_ value: String, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 172 | print(value, title: FatalErrorTitle, color: FatalErrorColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 173 | Swift.fatalError(value) 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /StarConsoleLink/NSObject-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension NSObject { 12 | class func pluginDidLoad(_ bundle: Bundle) { 13 | let appName = Bundle.main.infoDictionary?["CFBundleName"] as? NSString 14 | if appName == "Xcode" { 15 | if sharedPlugin == nil { 16 | sharedPlugin = StarConsoleLink(bundle: bundle) 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /StarConsoleLink/NSTextStorage-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSTextStorage-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | 13 | // used 14 | var UsedInConsoleKey = "Mark.By.Star.isUsedInXcodeConsole" 15 | 16 | // XcodeColors escape 17 | let XCODE_COLORS_ESCAPE = "\u{001b}[" 18 | 19 | // \[ 匹配[开头的 20 | // ([\w\+\-]+) 匹配文件名,包含+号-号 21 | // \. 匹配文件名中的点 22 | // (\w+) 匹配后缀 23 | // : 匹配冒号 24 | // (\d+) 匹配行号 25 | // \] 匹配]结尾的 26 | let RegularFileNameLineExpr = try! NSRegularExpression(pattern: "\\[(([\\w\\+\\-]+)\\.(\\w+):(\\d+))\\]", options: .caseInsensitive) 27 | 28 | // ([\+\-]) 匹配OC方法的类型 29 | // \[ 匹配[开头的 30 | // ([\w\+\-]+) 匹配文件名,包含+号-号 31 | // \ 匹配文件名中的空格 32 | // ([\w\:]+) 匹配后缀 33 | // \] 匹配]结尾的 34 | let RegularFileNameMethodExpr = try! NSRegularExpression(pattern: "([\\+\\-])\\[(([\\w\\+\\-]+) ([\\w\\:]+))\\]", options: .caseInsensitive) 35 | 36 | struct StarConsoleLinkFieldName { 37 | static let flag = "Star.StarConsoleLink.Flag" 38 | static let fileName = "Star.StarConsoleLink.FileName" 39 | static let line = "Star.StarConsoleLink.Line" 40 | static let methodName = "Star.StarConsoleLink.MethodName" 41 | static let methodType = "Star.StarConsoleLink.MethodType" 42 | } 43 | 44 | 45 | extension NSTextStorage { 46 | 47 | 48 | var usedInConsole: Bool { 49 | get { 50 | return (objc_getAssociatedObject(self, &UsedInConsoleKey) as? NSNumber)?.boolValue ?? false 51 | } 52 | set { 53 | objc_setAssociatedObject(self, &UsedInConsoleKey, NSNumber(value: newValue as Bool), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 54 | } 55 | } 56 | 57 | func star_fixAttributesInRange(_ range: NSRange) { 58 | star_fixAttributesInRange(range) 59 | if usedInConsole && ConsoleLinkConfig.consoleLinkEnabled { 60 | LogColorKit.applyANSIColors(self, textStorageRange: range, escapeSeq: XCODE_COLORS_ESCAPE) 61 | self.injectNormalLinks() 62 | self.injectBackTraceLinks() 63 | } 64 | } 65 | 66 | 67 | fileprivate func injectNormalLinks() { 68 | 69 | let matches = RegularFileNameLineExpr.matches(in: self.string, options: .reportProgress, range: self.editedRange) 70 | for result in matches where result.numberOfRanges == 5 { 71 | 72 | let ocText = self.string.OCString 73 | 74 | // let fullRange = result.rangeAtIndex(0) 75 | let linkRange = result.rangeAt(1) 76 | let link = ocText.substring(with: linkRange) 77 | 78 | let fileNameRange = result.rangeAt(2) 79 | let fileName = ocText.substring(with: fileNameRange) 80 | 81 | let fileExtensionRange = result.rangeAt(3) 82 | let fileExtension = ocText.substring(with: fileExtensionRange) 83 | 84 | let lineRange = result.rangeAt(4) 85 | let line = ocText.substring(with: lineRange) 86 | 87 | self.addAttribute(StarConsoleLinkFieldName.flag, value: "1", range: linkRange) 88 | self.addAttribute(StarConsoleLinkFieldName.fileName, value: "\(fileName).\(fileExtension)", range: linkRange) 89 | self.addAttribute(StarConsoleLinkFieldName.line, value: line, range: linkRange) 90 | 91 | self.addAttribute(NSLinkAttributeName, value: link, range: linkRange) 92 | self.addAttribute(NSForegroundColorAttributeName, value: ConsoleLinkConfig.linkColor, range: linkRange) 93 | } 94 | 95 | } 96 | 97 | fileprivate func injectBackTraceLinks() { 98 | 99 | let matches = RegularFileNameMethodExpr.matches(in: self.string, options: .reportProgress, range: self.editedRange) 100 | for result in matches where result.numberOfRanges == 5 { 101 | 102 | let ocText = self.string.OCString 103 | 104 | let fullRange = result.rangeAt(0) 105 | let fullText = ocText.substring(with: fullRange) 106 | Logger.error(fullText) 107 | 108 | let methodTypeRange = result.rangeAt(1) 109 | let methodType = ocText.substring(with: methodTypeRange) 110 | 111 | let linkRange = result.rangeAt(2) 112 | let link = ocText.substring(with: linkRange) 113 | 114 | let fileNameRange = result.rangeAt(3) 115 | let fileName = ocText.substring(with: fileNameRange) 116 | 117 | let methodNameRange = result.rangeAt(4) 118 | let methodName = ocText.substring(with: methodNameRange) 119 | 120 | self.addAttribute(StarConsoleLinkFieldName.flag, value: "2", range: linkRange) 121 | self.addAttribute(StarConsoleLinkFieldName.methodType, value:methodType, range: linkRange) 122 | self.addAttribute(StarConsoleLinkFieldName.fileName, value:fileName, range: linkRange) 123 | self.addAttribute(StarConsoleLinkFieldName.methodName, value:methodName, range: linkRange) 124 | 125 | self.addAttribute(NSLinkAttributeName, value: link, range: linkRange) 126 | self.addAttribute(NSForegroundColorAttributeName, value: ConsoleLinkConfig.linkColor, range: linkRange) 127 | } 128 | 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /StarConsoleLink/NSTextView-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSTextView-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | extension NSTextView { 13 | 14 | 15 | func star_mouseDown(_ theEvent: NSEvent) { 16 | 17 | 18 | // 当前点击的TextView是否是Xcode的Console 19 | guard let expectedClass = NSClassFromString("IDEConsoleTextView") , self.isKind(of: expectedClass) else { 20 | star_mouseDown(theEvent) 21 | return 22 | } 23 | 24 | // 点击区域是否是rich text 25 | let pos = self.convert(theEvent.locationInWindow, from:nil) 26 | let index = self.characterIndexForInsertion(at: pos) 27 | guard self.attributedString().length > 1 && index < self.attributedString().length else { 28 | star_mouseDown(theEvent) 29 | return 30 | } 31 | 32 | let attr = self.attributedString().attributes(at: index, effectiveRange: nil) 33 | 34 | // 验证标志 35 | guard attr[StarConsoleLinkFieldName.flag] != nil else { 36 | star_mouseDown(theEvent) 37 | return 38 | } 39 | 40 | // 访问[filename.extension:line]的超链接 41 | if let fileName = attr[StarConsoleLinkFieldName.fileName] as? String, 42 | let lineNumber = attr[StarConsoleLinkFieldName.line] as? String { 43 | 44 | guard let workspacePath = PluginHelper.workspacePath(), let filePath = findFile(workspacePath, fileName) else { 45 | // 如果是按规则定义的链接,但是没有找到对应的文件,那么此次点击应该使其失效 46 | return 47 | } 48 | 49 | // 用编辑器打开文件 50 | if let open = NSApplication.shared().delegate?.application?(NSApplication.shared(), openFile: filePath) , open { 51 | // 主线程异步调用,防止闪退 52 | DispatchQueue.main.async { () -> Void in 53 | if let textView = PluginHelper.editorTextView(inWindow: self.window), 54 | let line = Int(lineNumber) 55 | , line >= 1 { 56 | textView.scrollToLine(line) 57 | } 58 | } 59 | } 60 | } 61 | 62 | // 访问[filename methodName:]的超链接 63 | if var fileName = attr[StarConsoleLinkFieldName.fileName] as? String, 64 | let methodType = attr[StarConsoleLinkFieldName.methodType] as? String, 65 | let methodName = attr[StarConsoleLinkFieldName.methodName] as? String { 66 | 67 | // 暂时只支持查找.m结尾的文件 68 | fileName.append(".m") 69 | guard let workspacePath = PluginHelper.workspacePath(), let filePath = findFile(workspacePath, fileName) else { 70 | return 71 | } 72 | if let open = NSApplication.shared().delegate?.application?(NSApplication.shared(), openFile: filePath) , open { 73 | 74 | DispatchQueue.main.async { 75 | if let textView = PluginHelper.editorTextView(inWindow: self.window) { 76 | textView.scrollToMethod(methodType, methodName) 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | fileprivate func scrollToLine(_ line: Int) { 84 | 85 | guard let text = self.string?.OCString else { 86 | return 87 | } 88 | 89 | var currentLine:Int = 0 90 | text.enumerateLines { (lineText: String, stop: UnsafeMutablePointer) in 91 | currentLine += 1 92 | if line == currentLine { 93 | let lineRange = text.range(of: lineText) 94 | if lineRange.location != NSNotFound { 95 | self.scrollRangeToVisible(lineRange) 96 | self.setSelectedRange(lineRange) 97 | } 98 | stop.pointee = ObjCBool(true) 99 | } 100 | } 101 | } 102 | 103 | fileprivate func scrollToMethod(_ methodType: String, _ methodName: String) { 104 | 105 | guard let text = self.string?.OCString else { 106 | return 107 | } 108 | 109 | var passTotalCount = 0 110 | var passIndex = 0 111 | 112 | text.enumerateLines { (lineText, stop) in 113 | 114 | var methodComponents = methodName.components(separatedBy: ":") 115 | 116 | // 无参函数直接处理 117 | if methodComponents.count == 1 { 118 | if lineText.range(of: methodType) != nil 119 | && lineText.range(of: methodName) != nil { 120 | 121 | let lineRange = text.range(of: lineText) 122 | if lineRange.location != NSNotFound { 123 | self.scrollRangeToVisible(lineRange) 124 | self.setSelectedRange(lineRange) 125 | stop.pointee = ObjCBool(true) 126 | } 127 | } 128 | } 129 | 130 | // 有参方法已经完成,但是没有考虑换行的情况,任性,不想做,想让我做给钱。。。。 131 | if methodComponents.count > 1 { 132 | methodComponents.removeLast() 133 | methodComponents = methodComponents.map { $0 + ":" } 134 | 135 | if lineText.range(of: methodType) == nil { 136 | } 137 | 138 | if lineText.range(of: methodType) != nil { 139 | passTotalCount = methodComponents.count 140 | 141 | for methodElement in methodComponents { 142 | if lineText.range(of: methodElement) != nil { 143 | passIndex += 1 144 | } 145 | } 146 | if (passIndex == passTotalCount) { 147 | let lineRange = text.range(of: lineText) 148 | if lineRange.location != NSNotFound { 149 | self.scrollRangeToVisible(lineRange) 150 | self.setSelectedRange(lineRange) 151 | stop.pointee = ObjCBool(true) 152 | } 153 | } 154 | } 155 | } 156 | } 157 | } 158 | 159 | 160 | func star_insertNewline(_ arg1: AnyObject) { 161 | self.star_checkTextView() 162 | self.star_insertNewline(arg1) 163 | } 164 | 165 | func star_clearConsoleItems() { 166 | self.star_checkTextView() 167 | self.star_clearConsoleItems() 168 | } 169 | 170 | func star_shouldChangeTextInRanges(_ ranges: AnyObject, replacementStrings strings: AnyObject) -> Bool { 171 | self.star_checkTextView() 172 | return self.star_shouldChangeTextInRanges(ranges, replacementStrings: strings) 173 | } 174 | 175 | 176 | func star_checkTextView() { 177 | 178 | guard let expectedClass = NSClassFromString("IDEConsoleTextView") 179 | , self.isKind(of: expectedClass) else { 180 | return 181 | } 182 | guard let textStorage = self.textStorage else { 183 | return 184 | } 185 | if let startLocationOfLastLine = self.value(forKeyPath: "_startLocationOfLastLine") as? Int 186 | , textStorage.length < startLocationOfLastLine { 187 | self.setValue(textStorage.length, forKeyPath: "_startLocationOfLastLine") 188 | } 189 | 190 | if let lastRemovableTextLocation = self.value(forKeyPath: "_lastRemovableTextLocation") as? Int 191 | , textStorage.length < lastRemovableTextLocation { 192 | self.setValue(textStorage.length, forKeyPath: "_lastRemovableTextLocation") 193 | } 194 | } 195 | } 196 | 197 | -------------------------------------------------------------------------------- /StarConsoleLink/StarConsoleLink-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | 6 | 7 | #import "JRSwizzle.h" 8 | #import "LogColorKit.h" 9 | #import "StarFunctions.h" 10 | //#import "IDEConsoleTextView.h" -------------------------------------------------------------------------------- /StarConsoleLinkExample/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkExample/.DS_Store -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/xcshareddata/StarConsoleLinkExample.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : { 5 | 6 | } 7 | }, 8 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 9 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : 0 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "ED8A9B23-49E3-454B-8058-94C4502E2310", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : "StarProject_XcodePlugins\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "StarConsoleLinkExample", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "OwnPlugins\/StarConsoleLink\/StarConsoleLinkExample\/StarConsoleLinkExample.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "http:\/\/code.taobao.org\/svn\/StarProject_XcodePlugins", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/xcuserdata/Star.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/xcuserdata/Star.xcuserdatad/xcschemes/StarConsoleLinkExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/xcuserdata/Star.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | StarConsoleLinkExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | F8F23EFF1CD0EFE0002623E4 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample/OCLogger.h: -------------------------------------------------------------------------------- 1 | // 2 | // OCLogger.h 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OCLogger : NSObject 12 | 13 | - (void)runLog; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample/OCLogger.m: -------------------------------------------------------------------------------- 1 | // 2 | // OCLogger.m 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | 10 | 11 | #import "OCLogger.h" 12 | #import "Logger.h" 13 | 14 | 15 | 16 | @interface OCLogger () 17 | 18 | @end 19 | 20 | @implementation OCLogger 21 | 22 | + (void)backTrace:(NSString *)bt arg1:(NSString *)arg1 arg2:(NSString *)agr2{ 23 | LogBackTrace(@"%@", bt); 24 | } 25 | 26 | 27 | - (void)POST:(NSString *)paramModal success:(NSInteger)success failure:(NSString *)failure { 28 | 29 | LogBackTrace(@"%@", @"你好"); 30 | } 31 | - (void)runLog { 32 | 33 | LogWarning(@"------------------ ObjectiveC Logger Test ------------------"); 34 | PrivateLog("0,0,0", "Hello", 0, @"你好:星星,%@", @"请不要使用PrivateLog"); 35 | NSLog(@"NSLog"); 36 | LogDebug(@"调试"); 37 | LogInfo(@"消息"); 38 | LogWarning(@"警告"); 39 | LogError(@"错误"); 40 | LogSuccess(@"成功"); 41 | LogFailure(@"失败"); 42 | LogBackTrace(@"堆栈信息"); 43 | 44 | 45 | LogWarning(@"%@", @{@"name": @"星星", @"age": @"18岁"}); 46 | 47 | [OCLogger backTrace:@"啦啦啦" arg1: @"" arg2: @""]; 48 | [self POST:@"" success:0 failure:@""]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample/StarConsoleLinkExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | //#import Logger.h 6 | #import "OCLogger.h" -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample/SwiftLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftLogger.swift 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/5/12. 6 | // Copyright © 2016年 星星. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class SwiftLogger: NSObject { 12 | 13 | func runLog() { 14 | Logger.info("当前在Swift中测试打印") 15 | Logger.info("测试打印不存在的文件链接:[viewController-abc.swift:25] ") 16 | Logger.info("测试打印URL链接:[192.168.8.250:8080]") 17 | Logger.info("测试打印不带方括号的链接:SwiftLogger.swift:19") 18 | Logger.info("测试打印行号超出的链接:[SwiftLogger.swift:100]") 19 | 20 | Logger.warning("------------------ Swift Logger Test ------------------") 21 | Logger.info("测试颜色打印") 22 | Logger.debug("测试颜色打印") 23 | Logger.warning("测试颜色打印") 24 | Logger.error("测试颜色打印") 25 | Logger.important("测试颜色打印") 26 | Logger.success("测试颜色打印") 27 | Logger.failure("测试颜色打印") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /StarConsoleLinkExample/StarConsoleLinkExample/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/4/27. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | SwiftLogger().runLog() 13 | OCLogger().runLog() -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/ExampleImage/StarConsoleLink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkForXcode6-7/ExampleImage/StarConsoleLink.gif -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/ExampleImage/example_image_objc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkForXcode6-7/ExampleImage/example_image_objc.png -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/ExampleImage/example_image_swift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkForXcode6-7/ExampleImage/example_image_swift.png -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Introduction 【简介】 3 | 4 | StarConsoleLink inject the link to your Xcode console, which allows you to click on the link area rapid positioning to the log line. 5 | 6 | StarConsoleLink给你的Xcode控制台注入了超链接,它能让你点击链接时,快速跳转到日志输出语句位置。 7 | 8 | ![Smaller icon](https://github.com/iStarEternal/StarConsoleLink/blob/master/ExampleImage/StarConsoleLink.gif "Case Diagram") 9 | 10 | 11 | # How to use? 【使用说明】 12 | 13 | Please note that plugins are not supported by Xcode 8. See https://github.com/alcatraz/Alcatraz/issues/475 for more information. 14 | 15 | 16 | 1. If you are using Swift, Copy Logger.swift to you project. 17 | 18 | 2. If you are using Objective-C, Copy Logger.h to you project and #import "Logger.h" to you PrefixHeader.pch. 19 | 20 | 3. If you want to custom you logs, please follow the rules: [FileName.extension:LineNumber], Just like [main.swift:15]. 21 | 22 | 23 | 1. 如果你使用的是Swift,请拷贝 Logger.swift 到你的项目中去。 24 | 25 | 2. 如果你使用的是Objective-C,请拷贝 Logger.h 到你的项目中,并在你的.pch文件中添加 #import "Logger.h"。 26 | 27 | 3. 如果你想要自定义你的日志,请遵照[FileName.extension:LineNumber]的书写规范,例:[main.swift:15]。 28 | 29 | 30 | # Install 【安装】 31 | 32 | ```install 33 | curl -fsSL https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/master/Scripts/install.sh | sh 34 | ``` 35 | 36 | 37 | 38 | # Uninstall 【卸载】 39 | 40 | ```uninstall 41 | curl -fsSL https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/master/Scripts/uninstall.sh | sh 42 | ``` 43 | 44 | 45 | # The New Feature 【新功能】 46 | 47 | ####v1.4.1 48 | 49 | 重构Logger.h并删除了Logger.m 50 | 现已加入alcatraz-packages(Package Manager) 51 | 52 | 53 | ####v1.4 54 | 55 | 修复了1.3在控制台输入文字会发生闪退的BUG 56 | 57 | 58 | ####v1.3 59 | 60 | 添加了NSDictionary和NSArray的日志显示,Unicode转中文 61 | 62 | 您现在可以在菜单栏 Plugins -> Star Console Link -> Chinese Unicode Enabled 选择是否关闭中文转换了。 63 | ```objective-c 64 | LogWarning(@"%@", @{@"name": @"星星", @"age": @"18岁"}); 65 | ``` 66 | ``` 67 | 以前: 68 | <2016-07-14 14:07:03> [Warning][OCLogger.m:45] { 69 | age = "18\U5c81"; 70 | name = "\U661f\U661f"; 71 | } 72 | 现在: 73 | <2016-07-14 14:07:41> [Warning][OCLogger.m:45] { 74 | age = "18岁"; 75 | name = "星星"; 76 | } 77 | ``` 78 | 79 | 80 | ####v1.2 81 | 82 | 添加了LogBackTrace,并对LogBackTrace的日志加入了超链接,您现在也可以更快的定位到日志的方法调用堆栈了。 83 | 84 | 您现在可以在菜单栏 Plugins -> Star Console Link -> Enabled 选择是否关闭StarConsoleLink 85 | 86 | 您现在可以在菜单栏 Plugins -> Star Console Link -> Setting 进行Link的颜色配置 87 | 88 | 89 | ####v1.1 90 | 91 | 将OC的NSLog替换成了printf,并添加了日志输出时间 92 | 93 | 94 | 95 | ####v1.0 96 | 97 | StarConsoleLink集成了XcodeColors,他可以让你自定义你Log的颜色。感谢@robbiehanson提供的支持:https://github.com/robbiehanson/XcodeColors 98 | 99 | 给您的日志加入了超链接,让您可以更快的定位到打印输出的位置。 100 | 101 | 给您的日志加入了色彩元素,让您可以更好的区分日志的类型。 102 | 103 | 增强您的日志语句,您可以使用下面的语句来输出更多类型的日志。 104 | 105 | ```objective-c 106 | LogInfo(@"你好"); 107 | // 黑色 [Info][ViewController.m:35]你好 108 | LogSuccess(@"Hello"); 109 | // 绿色 [Success][ViewController.m:35]Hello 110 | LogWarning(@"Bonjour"); 111 | // 黄色 [Warning][ViewController.m:35]Bonjour 112 | LogError(@"¡Hola"); 113 | // 红色 [Error][ViewController.m:35]¡Hola 114 | ``` 115 | 116 | # If Ineffective【如果插件未生效】 117 | 118 | 第一步:请先检查你是否启用了该插件 119 | ``` 120 | defaults read com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-{Current Xcode Version} 121 | ``` 122 | 123 | 第二步:如果发现插件在skipped中,请执行下列代码,然后重启Xcode,并点击Load Bundles 124 | ``` 125 | defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-{Current Xcode Version} 126 | ``` 127 | 128 | # Example 【案例】 129 | 130 | * Objective-C 131 | 132 | ```objective-c 133 | 134 | #define StarDebug DEBUG 135 | #define StarXCodeColors 1 136 | 137 | #define XCODE_COLORS_ESCAPE @"\033[" 138 | #define XCODE_COLORS_ESCAPE_FG XCODE_COLORS_ESCAPE @"fg" 139 | #define XCODE_COLORS_ESCAPE_BG XCODE_COLORS_ESCAPE @"bg" 140 | 141 | #define XCODE_COLORS_RESET_FG XCODE_COLORS_ESCAPE @"fg;" // Clear any foreground color 142 | #define XCODE_COLORS_RESET_BG XCODE_COLORS_ESCAPE @"bg;" // Clear any background color 143 | #define XCODE_COLORS_RESET XCODE_COLORS_ESCAPE @";" // Clear any foreground or background color 144 | 145 | #define NSLogColor @"22,22,22" // 黑色 146 | #define NSLogTitle @"Info" 147 | 148 | #define InfoColor @"22,22,22" // 黑色 149 | #define InfoTitle @"Info" 150 | 151 | #if StarDebug /* Debug Begin */ 152 | 153 | #if StarXCodeColors != 0 /* Color Begin */ 154 | 155 | #define PrivateLog(color, title, format, ...)\ 156 | printf("%s%s;[%s][%s:%d] %s %s\n",\ 157 | [XCODE_COLORS_ESCAPE_FG UTF8String],\ 158 | [color UTF8String],\ 159 | [title UTF8String],\ 160 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 161 | __LINE__,\ 162 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String],\ 163 | [XCODE_COLORS_RESET_FG UTF8String]\ 164 | );\ 165 | 166 | // NSLog 167 | #define NSLog(format, ...) \ 168 | PrivateLog(NSLogColor, NSLogTitle, format, ##__VA_ARGS__) 169 | 170 | // Information 171 | #define LogInfo(format, ...) \ 172 | PrivateLog(InfoColor, InfoTitle, format, ##__VA_ARGS__) 173 | 174 | #else /* Color Else */ 175 | 176 | #define PrivateLog(color, title, format, ...)\ 177 | printf("[%s][%s:%d] %s\n",\ 178 | [title UTF8String],\ 179 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 180 | __LINE__,\ 181 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String]\ 182 | );\ 183 | 184 | // NSLog 185 | #define NSLog(format, ...) \ 186 | PrivateLog(0, NSLogTitle, format, ##__VA_ARGS__) 187 | 188 | // Information 189 | #define LogInfo(format, ...) \ 190 | PrivateLog(0, InfoTitle, format, ##__VA_ARGS__) 191 | 192 | #endif /* Color End */ 193 | 194 | #else /* Debug Else */ 195 | 196 | #define PrivateLog(color, title, format, ...) while(0){} 197 | #define NSLog(...) while(0){} 198 | #define LogInfo(...) while(0){} 199 | 200 | #endif /* Debug End */ 201 | 202 | 203 | ``` 204 | And then you can log within a Objective-C method like so: 205 | 206 | ```Objective-C 207 | LogInfo("StarConsoleLink"); 208 | ``` 209 | 210 | * Swift 211 | ```swift 212 | 213 | let StarDebug = true 214 | 215 | struct LogColor { 216 | 217 | static let XcodeColors = true 218 | 219 | static let ESCAPE = "\u{001b}[" 220 | static let ESCAPE_FG = "\u{001b}[fg" 221 | static let ESCAPE_BG = "\u{001b}[bg" 222 | 223 | static let RESET = ESCAPE + ";" // Clear any foreground or background color 224 | static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color 225 | static let RESET_BG = ESCAPE + "bg;" // Clear any background color 226 | } 227 | 228 | let InfoColor = "22,22,22" // 黑色 229 | let InfoTitle = "Info" 230 | 231 | let DebugColor = "28,0,207" // 蓝色 232 | let DebugTitle = "Debug" 233 | 234 | let WarningColor = "218,130,53" // 黄色 235 | let WarningTitle = "Warning" 236 | 237 | let ErrorColor = "196,26,22" // 红色 238 | let ErrorTitle = "Error" 239 | 240 | let ImportantColor = "196,26,22" // 红色 241 | let ImportantTitle = "Important - 如果发现该行日志,应该及时处理" 242 | 243 | 244 | class Logger: NSObject { 245 | 246 | class func print(value: T, title: String, color: String, functionName: String, fileName: String, lineNumber: Int) { 247 | guard StarDebug else { 248 | return 249 | } 250 | if LogColor.XcodeColors { 251 | Swift.print("\(LogColor.ESCAPE_FG)\(color);[\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)\(LogColor.RESET_FG)") 252 | } 253 | else { 254 | Swift.print("[\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)") 255 | } 256 | } 257 | class func info(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 258 | print(value, title: InfoTitle, color: InfoColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 259 | } 260 | class func debug(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 261 | print(value, title: DebugTitle, color: DebugColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 262 | } 263 | class func warning(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 264 | print(value, title: WarningTitle, color: WarningColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 265 | } 266 | class func error(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 267 | print(value, title: ErrorTitle, color: ErrorColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 268 | } 269 | class func important(value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 270 | print(value, title: ImportantTitle, color: ImportantColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 271 | } 272 | } 273 | 274 | ``` 275 | And then you can log within a Swift method like so: 276 | 277 | ```Swift 278 | Logger.info("StarConsoleLink") 279 | ``` 280 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/Scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Set up the environment. 4 | 5 | PLUGIN_DIR="$HOME/Library/Application Support/Developer/Shared/Xcode/Plug-ins" 6 | STARCONSOLELINK_PATH="$PLUGIN_DIR/StarConsoleLink.xcplugin" 7 | 8 | # Check path, Remove if exist 9 | 10 | if [ -d "$PLUGIN_DIR" ]; then 11 | if [ -d "$STARCONSOLELINK_PATH" ]; then 12 | echo "" 13 | echo "Remove $STARCONSOLELINK_PATH" 14 | rm -rf "$STARCONSOLELINK_PATH" 15 | fi 16 | fi 17 | 18 | echo "" 19 | echo "Downloading StarConsoleLink..." 20 | 21 | # Prepare 22 | mkdir -p /var/tmp/StarConsoleLink.tmp && cd /var/tmp/StarConsoleLink.tmp 23 | 24 | echo "" 25 | # Clone from git 26 | git clone https://github.com/iStarEternal/StarConsoleLink.git --depth 1 /var/tmp/StarConsoleLink.tmp > /dev/null 27 | 28 | echo "" 29 | echo "Installing StarConsoleLink..." 30 | 31 | # Then build 32 | xcodebuild clean > /dev/null 33 | xcodebuild > /dev/null 34 | 35 | # Remove tmp files 36 | cd ~ 37 | rm -rf /var/tmp/StarConsoleLink.tmp 38 | 39 | # Done 40 | echo "" 41 | if [ -d "$PLUGIN_DIR" ]; then 42 | if [ -d "$STARCONSOLELINK_PATH" ]; then 43 | echo "StarConsoleLink successfully installed! 🍻 Please restart your Xcode." 44 | else 45 | echo "StarConsoleLink installation failed! I'm sorry 😭😭😭." 46 | fi 47 | fi 48 | echo "" -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/Scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Set up the environment. 4 | 5 | PLUGIN_DIR="$HOME/Library/Application Support/Developer/Shared/Xcode/Plug-ins" 6 | STARCONSOLELINK_PATH="$PLUGIN_DIR/StarConsoleLink.xcplugin" 7 | 8 | # Remove 9 | 10 | echo "" 11 | echo "Remove StarConsoleLink..." 12 | 13 | if [ -d "$PLUGIN_DIR" ]; then 14 | if [ -d "$STARCONSOLELINK_PATH" ]; then 15 | echo "" 16 | echo "Remove $STARCONSOLELINK_PATH" 17 | rm -rf "$STARCONSOLELINK_PATH" 18 | fi 19 | fi 20 | 21 | # Done 22 | echo "" 23 | echo "StarConsoleLink successfully uninstalled. Loved. Agoni.😢 Please restart your Xcode." 24 | echo "" -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/project.xcworkspace/xcshareddata/StarConsoleLink.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : { 5 | 6 | } 7 | }, 8 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 9 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : 0 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "D2FA363F-FEE5-49FD-AA34-F2535129D2CD", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : "StarProject_XcodePlugins\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "StarConsoleLink", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "OwnPlugins\/StarConsoleLink\/StarConsoleLink.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "http:\/\/code.taobao.org\/svn\/StarProject_XcodePlugins", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/xcshareddata/xcschemes/StarConsoleLink.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 58 | 60 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/xcuserdata/Star.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink.xcodeproj/xcuserdata/Star.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SuppressBuildableAutocreation 6 | 7 | F8FC45E71C59E7570037FEE5 8 | 9 | primary 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Business/Settings/ConsoleLinkConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConsoleLinkConfig.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ConsoleLinkConfig: NSObject { 12 | 13 | 14 | private struct ConsoleLinkConfigSingleton { 15 | static var predicate: dispatch_once_t = 0 16 | static var instance: ConsoleLinkConfig! = nil 17 | } 18 | 19 | static var shared: ConsoleLinkConfig { 20 | dispatch_once(&ConsoleLinkConfigSingleton.predicate) { () -> Void in 21 | ConsoleLinkConfigSingleton.instance = ConsoleLinkConfig() 22 | } 23 | return ConsoleLinkConfigSingleton.instance 24 | } 25 | 26 | 27 | static func setConfig(config: AnyObject, forKey key: String) { 28 | NSUserDefaults.standardUserDefaults().setObject(config, forKey: key) 29 | NSUserDefaults.standardUserDefaults().synchronize() 30 | } 31 | 32 | static func configForKey(key: String, defaultValue: T) -> T { 33 | if let obj = NSUserDefaults.standardUserDefaults().objectForKey(key) { 34 | return obj as? T ?? defaultValue 35 | } 36 | else { 37 | return defaultValue 38 | } 39 | } 40 | 41 | static func configForKey(key: String) -> T? { 42 | if let obj = NSUserDefaults.standardUserDefaults().objectForKey(key) { 43 | return obj as? T 44 | } 45 | else { 46 | return nil 47 | } 48 | } 49 | 50 | 51 | // MARK: - 是否打开StarConsoleLink 52 | 53 | private static var consoleLinkEnabledKey = "iStar.StarConsoleLink.IsOpenConsoleLink" 54 | private var consoleLinkEnabled: Bool? 55 | static var consoleLinkEnabled: Bool { 56 | get { 57 | if shared.consoleLinkEnabled == nil { 58 | let enabled: Bool? = configForKey(consoleLinkEnabledKey) 59 | return enabled ?? true 60 | } 61 | return shared.consoleLinkEnabled! 62 | } 63 | set { 64 | setConfig(newValue, forKey: consoleLinkEnabledKey) 65 | shared.consoleLinkEnabled = newValue 66 | } 67 | } 68 | 69 | 70 | // MARK: - 中文Unicode 71 | 72 | private static var ChineseUnicodeEnabledKey = "iStar.StarConsoleLink.ChineseUnicodeEnabledKey" 73 | private var ChineseUnicodeEnabled: Bool? 74 | static var ChineseUnicodeEnabled: Bool { 75 | get { 76 | if shared.ChineseUnicodeEnabled == nil { 77 | let enabled: Bool? = configForKey(ChineseUnicodeEnabledKey) 78 | return enabled ?? true 79 | } 80 | return shared.ChineseUnicodeEnabled! 81 | } 82 | set { 83 | setConfig(newValue, forKey: ChineseUnicodeEnabledKey) 84 | shared.ChineseUnicodeEnabled = newValue 85 | } 86 | } 87 | 88 | 89 | private static let linkColorKeywordKey = "iStar.StarConsoleLink.LinkColorKey" 90 | private static let linkColorDefaultValue = 0x0000ff 91 | private var linkColor: NSColor? 92 | static var linkColor: NSColor { 93 | get { 94 | if shared.linkColor == nil { 95 | let intRGB: Int = configForKey(linkColorKeywordKey, defaultValue: linkColorDefaultValue) 96 | shared.linkColor = NSColor(rgb: intRGB) 97 | } 98 | return shared.linkColor! 99 | } 100 | set { 101 | setConfig(newValue.rgb, forKey: linkColorKeywordKey) 102 | shared.linkColor = newValue 103 | } 104 | } 105 | } 106 | 107 | // MARK: - Log config: Base 108 | extension ConsoleLinkConfig { 109 | 110 | 111 | private static let debugLogKeywordKey = "iStar.StarConsoleLink.DebugLogColorKey" 112 | private static let infoLogKeywordKey = "iStar.StarConsoleLink.InfoLogKeywordKey" 113 | private static let warningLogKeywordKey = "iStar.StarConsoleLink.WarningLogKeywordKey" 114 | private static let errorLogKeywordKey = "iStar.StarConsoleLink.ErrorLogKeywordKey" 115 | 116 | private static let debugLogColorKey = "iStar.StarConsoleLink.DebugLogColorKey" 117 | private static let infoLogColorKey = "iStar.StarConsoleLink.InfoLogColorKey" 118 | private static let warningLogColorKey = "iStar.StarConsoleLink.WarningLogColorKey" 119 | private static let errorLogColorKey = "iStar.StarConsoleLink.ErrorLogColorKey" 120 | 121 | 122 | static var debugLogKeyword: String { 123 | get { 124 | return configForKey(debugLogKeywordKey, defaultValue: "[Debug]") 125 | } 126 | set { 127 | setConfig(newValue, forKey: debugLogKeywordKey) 128 | } 129 | } 130 | 131 | static var infoLogKeyword: String { 132 | get { 133 | return configForKey(infoLogKeywordKey, defaultValue: "[Info]") 134 | } 135 | set { 136 | setConfig(newValue, forKey: infoLogKeywordKey) 137 | } 138 | } 139 | 140 | static var warningLogKeyword: String { 141 | get { 142 | return configForKey(warningLogKeywordKey, defaultValue: "[Warning]") 143 | } 144 | set { 145 | setConfig(newValue, forKey: warningLogKeywordKey) 146 | } 147 | } 148 | 149 | static var errorLogKeyword: String { 150 | get { 151 | return configForKey(errorLogKeywordKey, defaultValue: "[Error]") 152 | } 153 | set { 154 | setConfig(newValue, forKey: errorLogKeywordKey) 155 | } 156 | } 157 | 158 | 159 | 160 | 161 | static var debugLogColor: NSColor { 162 | get { 163 | let intRGB: Int = configForKey(debugLogColorKey, defaultValue: 0xFFFF00) 164 | return NSColor(rgb: intRGB) 165 | } 166 | set { 167 | setConfig(newValue.rgb, forKey: debugLogColorKey) 168 | } 169 | } 170 | 171 | static var infoLogColor: NSColor { 172 | get { 173 | let intRGB: Int = configForKey(infoLogColorKey, defaultValue: 0x000000) 174 | return NSColor(rgb: intRGB) 175 | } 176 | set { 177 | setConfig(newValue.rgb, forKey: infoLogColorKey) 178 | } 179 | } 180 | 181 | static var warningLogColor: NSColor { 182 | get { 183 | let intRGB: Int = configForKey(warningLogColorKey, defaultValue: 0xFFFF00) 184 | return NSColor(rgb: intRGB) 185 | } 186 | set { 187 | setConfig(newValue.rgb, forKey: warningLogColorKey) 188 | } 189 | } 190 | 191 | static var errorLogColor: NSColor { 192 | get { 193 | let intRGB: Int = configForKey(errorLogColorKey, defaultValue: 0x00FFFF) 194 | return NSColor(rgb: intRGB) 195 | } 196 | set { 197 | setConfig(newValue.rgb, forKey: errorLogColorKey) 198 | } 199 | } 200 | } 201 | 202 | // MARK: - Log color config: HttpRequest 203 | extension ConsoleLinkConfig { 204 | 205 | private static var successLogColorKey = "iStar.StarConsoleLink.SuccessLogColorKey" 206 | private static var failureLogColorKey = "iStar.StarConsoleLink.FailureLogColorKey" 207 | 208 | 209 | static var successLogColor: NSColor { 210 | get { 211 | let intRGB: Int = configForKey(successLogColorKey, defaultValue: 0x000000) 212 | return NSColor(rgb: intRGB) 213 | } 214 | set { 215 | setConfig(newValue.rgb, forKey: successLogColorKey) 216 | } 217 | } 218 | 219 | static var failureLogColor: NSColor { 220 | get { 221 | let intRGB: Int = configForKey(failureLogColorKey, defaultValue: 0x000000) 222 | return NSColor(rgb: intRGB) 223 | } 224 | set { 225 | setConfig(newValue.rgb, forKey: failureLogColorKey) 226 | } 227 | } 228 | } 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Business/Settings/SettingsWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingsWindowController.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/19. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | /// 开发中 未完成 以后颜色由Xcode配置,不再由代码配 11 | class SettingsWindowController: NSWindowController { 12 | 13 | 14 | var bundle: NSBundle! 15 | 16 | @IBOutlet weak var linkColorWell: NSColorWell! 17 | 18 | @IBOutlet weak var debugLogKeywordTextField: NSTextField! 19 | @IBOutlet weak var infoLogKeywordTextField: NSTextField! 20 | @IBOutlet weak var warningLogKeywordTextField: NSTextField! 21 | @IBOutlet weak var errorLogKeywordTextField: NSTextField! 22 | 23 | @IBOutlet weak var successLogKeywordTextField: NSTextField! 24 | @IBOutlet weak var failureLogKeywordTextField: NSTextField! 25 | 26 | @IBOutlet weak var assertLogKeywordTextField: NSTextField! 27 | @IBOutlet weak var fatalLogKeywordTextField: NSTextField! 28 | 29 | 30 | @IBOutlet weak var debugLogColorWell: NSColorWell! 31 | @IBOutlet weak var infoLogColorWell: NSColorWell! 32 | @IBOutlet weak var warningLogColorWell: NSColorWell! 33 | @IBOutlet weak var errorLogColorWell: NSColorWell! 34 | 35 | @IBOutlet weak var successLogColorWell: NSColorWell! 36 | @IBOutlet weak var failureLogColorWell: NSColorWell! 37 | 38 | @IBOutlet weak var assertLogColorWell: NSColorWell! 39 | @IBOutlet weak var fatalLogColorWell: NSColorWell! 40 | 41 | 42 | override func windowDidLoad() { 43 | super.windowDidLoad() 44 | loadConfig() 45 | } 46 | 47 | func loadConfig() { 48 | 49 | linkColorWell.color = ConsoleLinkConfig.linkColor 50 | 51 | debugLogKeywordTextField.stringValue = ConsoleLinkConfig.debugLogKeyword 52 | infoLogKeywordTextField.stringValue = ConsoleLinkConfig.infoLogKeyword 53 | warningLogKeywordTextField.stringValue = ConsoleLinkConfig.warningLogKeyword 54 | errorLogKeywordTextField.stringValue = ConsoleLinkConfig.errorLogKeyword 55 | 56 | debugLogColorWell.color = ConsoleLinkConfig.debugLogColor 57 | infoLogColorWell.color = ConsoleLinkConfig.infoLogColor 58 | warningLogColorWell.color = ConsoleLinkConfig.warningLogColor 59 | errorLogColorWell.color = ConsoleLinkConfig.errorLogColor 60 | } 61 | 62 | @IBAction func handleKeywordChanged(sender: NSTextField) { 63 | Logger.info(sender.stringValue) 64 | 65 | if sender == debugLogKeywordTextField { 66 | ConsoleLinkConfig.debugLogKeyword = sender.stringValue 67 | } 68 | else if sender == infoLogKeywordTextField { 69 | ConsoleLinkConfig.infoLogKeyword = sender.stringValue 70 | } 71 | else if sender == warningLogKeywordTextField { 72 | ConsoleLinkConfig.warningLogKeyword = sender.stringValue 73 | } 74 | else if sender == errorLogKeywordTextField { 75 | ConsoleLinkConfig.errorLogKeyword = sender.stringValue 76 | } 77 | 78 | } 79 | 80 | 81 | @IBAction func handleColorChanged(sender: NSColorWell) { 82 | if sender == linkColorWell { 83 | ConsoleLinkConfig.linkColor = sender.color 84 | } 85 | else if sender == debugLogColorWell { 86 | ConsoleLinkConfig.debugLogColor = sender.color 87 | } 88 | else if sender == infoLogColorWell { 89 | ConsoleLinkConfig.infoLogColor = sender.color 90 | } 91 | else if sender == warningLogColorWell { 92 | ConsoleLinkConfig.warningLogColor = sender.color 93 | } 94 | else if sender == errorLogColorWell { 95 | ConsoleLinkConfig.errorLogColor = sender.color 96 | } 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Extensions/Dispatch-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // dispatch_queue_t-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/17. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension dispatch_queue_t { 12 | 13 | func async(closure: dispatch_block_t) { 14 | dispatch_async(self, closure) 15 | } 16 | 17 | func sync(closure: dispatch_block_t) { 18 | dispatch_sync(self, closure) 19 | } 20 | 21 | func delay(delay: Double, _ block: dispatch_block_t) { 22 | dispatch_delay(delay, self, block) 23 | } 24 | } 25 | 26 | func dispatch_delay(delay: Double, _ block: dispatch_block_t) { 27 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), { () -> Void in 28 | block() 29 | }) 30 | } 31 | 32 | func dispatch_delay(delay: Double, _ queue: dispatch_queue_t, _ block: dispatch_block_t) { 33 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(delay * Double(NSEC_PER_SEC))), queue, { () -> Void in 34 | block() 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Extensions/NSColor-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor-Extension.swift 3 | // AviationLogin 4 | // 5 | // Created by 星星 on 15/7/28. 6 | // Copyright (c) 2015年 chinaaviationconsulting. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //#if swift(>=2.0) 12 | 13 | //#endif 14 | 15 | #if os(iOS) || os(tvOS) 16 | import UIKit 17 | public typealias Color = UIColor 18 | #else 19 | import AppKit 20 | public typealias Color = NSColor 21 | #endif 22 | 23 | 24 | extension Color { 25 | 26 | convenience init(r:Int, g:Int, b:Int, a:CGFloat) { 27 | self.init(red: CGFloat(r)/255.0, green: CGFloat(g)/255.0, blue: CGFloat(b)/255.0, alpha: a) 28 | } 29 | 30 | convenience init(rgb:Int) { 31 | let red = Double((rgb >> 16) & 0xff) / 255.0 32 | let green = Double((rgb >> 8) & 0xff) / 255.0 33 | let blue = Double(rgb & 0xff) / 255.0 34 | self.init(red:CGFloat(red), green:CGFloat(green), blue:CGFloat(blue), alpha:CGFloat(1)) 35 | } 36 | 37 | /// alpha range: 0 - 1.0 38 | convenience init(rgb: Int, alpha: CGFloat) { 39 | let red = Double((rgb >> 16) & 0xff) / 255.0 40 | let green = Double((rgb >> 8) & 0xff) / 255.0 41 | let blue = Double(rgb & 0xff) / 255.0 42 | self.init(red:CGFloat(red), green:CGFloat(green), blue:CGFloat(blue), alpha:alpha) 43 | } 44 | 45 | convenience init(rgba:Int) { 46 | let red = Double((rgba >> 32) & 0xff) / 255.0 47 | let green = Double((rgba >> 16) & 0xff) / 255.0 48 | let blue = Double((rgba >> 8) & 0xff) / 255.0 49 | let alpha = Double(rgba & 0xff) / 255.0 50 | self.init(red:CGFloat(red), green:CGFloat(green), blue:CGFloat(blue), alpha:CGFloat(alpha)) 51 | } 52 | 53 | 54 | static func rgb(rgb: Int) -> Color { 55 | return Color(rgb: rgb) 56 | } 57 | 58 | var rgb: Int { 59 | 60 | #if os(iOS) || os(tvOS) 61 | var red: CGFloat = 0 62 | var green: CGFloat = 0 63 | var blue: CGFloat = 0 64 | var alpha: CGFloat = 0 65 | self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) 66 | 67 | let intRed = Int(red * 255.0) 68 | let intGreen = Int(red * 255.0) 69 | let intBlue = Int(red * 255.0) 70 | return (intRed << 16) + (intGreen << 8) + intBlue 71 | #else 72 | let red = Int(self.redComponent * 255.0) 73 | let green = Int(self.greenComponent * 255.0) 74 | let blue = Int(self.blueComponent * 255.0) 75 | // let alpha = self.alphaComponent 76 | return (red << 16) + (green << 8) + blue 77 | #endif 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Extensions/Operator-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Operator-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | // MARK: - Int 和 CGfloat 加法 13 | public func +(lhs: Int, rhs: CGFloat) -> CGFloat { 14 | return CGFloat(lhs) + rhs 15 | } 16 | 17 | public func +(lhs: CGFloat, rhs: Int) -> CGFloat { 18 | return lhs + CGFloat(rhs) 19 | } 20 | 21 | 22 | // MARK: - Int 和 CGfloat 减法 23 | public func -(lhs: Int, rhs: CGFloat) -> CGFloat { 24 | return CGFloat(lhs) - rhs 25 | } 26 | 27 | public func -(lhs: CGFloat, rhs: Int) -> CGFloat { 28 | return lhs - CGFloat(rhs) 29 | } 30 | 31 | 32 | // MARK: - Int 和 CGfloat 乘法 33 | public func *(lhs: Int, rhs: CGFloat) -> CGFloat { 34 | return CGFloat(lhs) * rhs 35 | } 36 | 37 | public func *(lhs: CGFloat, rhs: Int) -> CGFloat { 38 | return lhs * CGFloat(rhs) 39 | } 40 | 41 | 42 | // MARK: - Int 和 CGfloat 除法 43 | public func /(lhs: Int, rhs: CGFloat) -> CGFloat { 44 | return CGFloat(lhs) / rhs 45 | } 46 | 47 | public func /(lhs: CGFloat, rhs: Int) -> CGFloat { 48 | return lhs / CGFloat(rhs) 49 | } -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Extensions/String-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Cocoa 11 | 12 | #if os(iOS) || os(tvOS) 13 | import UIKit 14 | public typealias Font = UIFont 15 | #else 16 | import AppKit 17 | public typealias Font = NSFont 18 | #endif 19 | 20 | extension NSString { 21 | 22 | var swiftString: String { 23 | get { 24 | return self as String 25 | } 26 | } 27 | 28 | func sizeWithFont(font: Font,maxSize:CGSize) -> CGSize { 29 | return self.boundingRectWithSize(maxSize, options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName : font], context: nil).size 30 | } 31 | } 32 | 33 | 34 | 35 | 36 | extension String { 37 | 38 | var OCString: NSString { 39 | get { 40 | return self as NSString 41 | } 42 | } 43 | 44 | subscript (r: Range) -> String { 45 | get { 46 | let startIndex = self.startIndex.advancedBy(r.startIndex) 47 | let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex) 48 | return self[startIndex ..< endIndex] 49 | // return self[Range(start: startIndex, end: endIndex)] 50 | } 51 | } 52 | 53 | func rangeFromNSRange(nsRange : NSRange) -> Range? { 54 | 55 | let from16 = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex) 56 | let to16 = from16.advancedBy(nsRange.length, limit: utf16.endIndex) 57 | if let from = String.Index(from16, within: self), 58 | let to = String.Index(to16, within: self) { 59 | return from ..< to 60 | } 61 | return nil 62 | } 63 | 64 | func NSRangeFromRange(range : Range) -> NSRange { 65 | let utf16view = self.utf16 66 | let from = String.UTF16View.Index(range.startIndex, within: utf16view) 67 | let to = String.UTF16View.Index(range.endIndex, within: utf16view) 68 | return NSMakeRange(utf16view.startIndex.distanceTo(from), from.distanceTo(to)) 69 | } 70 | 71 | var length:Int{ 72 | get { 73 | // return self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) 74 | return self.characters.count 75 | } 76 | } 77 | 78 | 79 | func stringByAppendingPathComponent(pathConmonent: String) -> String { 80 | 81 | var first = self 82 | var last = pathConmonent 83 | 84 | if first.hasSuffix("/") { 85 | var firstArray = first.componentsSeparatedByString("/") 86 | for var i = firstArray.count - 1; i >= 0; i -= 1 { 87 | if firstArray[i] == "" { 88 | firstArray.removeLast() 89 | } 90 | else { 91 | break 92 | } 93 | } 94 | first = firstArray.joinWithSeparator("/") 95 | } 96 | 97 | if last.hasPrefix("/") { 98 | var lastArray = last.componentsSeparatedByString("/") 99 | for i in lastArray { 100 | if i == "" { 101 | lastArray.removeFirst() 102 | } 103 | else { 104 | break 105 | } 106 | } 107 | last = lastArray.joinWithSeparator("/") 108 | } 109 | 110 | if !String.isNullOrWhiteSpace(last) { 111 | last = "/" + last 112 | } 113 | 114 | return first + last 115 | } 116 | 117 | var lastPathComponent: String { 118 | get { 119 | return self.OCString.lastPathComponent 120 | } 121 | } 122 | 123 | func isAllDigit() -> Bool { 124 | for uni in unicodeScalars{ 125 | if NSCharacterSet.decimalDigitCharacterSet().longCharacterIsMember(uni.value){ 126 | continue 127 | } 128 | return false 129 | } 130 | return true 131 | } 132 | 133 | var isEmptyOrWhiteSpace: Bool { 134 | if self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty { 135 | return true 136 | } 137 | return false 138 | } 139 | 140 | func sizeWithFont(font: Font, maxSize:CGSize) -> CGSize { 141 | return self.OCString.sizeWithFont(font, maxSize: maxSize) 142 | } 143 | 144 | static func isNullOrEmpty(str: String?) -> Bool { 145 | if str == nil { 146 | return true 147 | } 148 | if str!.isEmpty { 149 | return true 150 | } 151 | return false 152 | } 153 | 154 | static func isNullOrWhiteSpace(str: String?) -> Bool { 155 | if str == nil { 156 | return true 157 | } 158 | if str!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).isEmpty { 159 | return true 160 | } 161 | return false 162 | } 163 | 164 | } -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.4 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.4.1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | DVTPlugInCompatibilityUUIDs 28 | 29 | FEC992CC-CA4A-4CFD-8881-77300FCB848A 30 | C4A681B0-4A26-480E-93EC-1218098B9AA0 31 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 32 | AD68E85B-441B-4301-B564-A45E4919A6AD 33 | 63FC1C47-140D-42B0-BB4D-A10B2D225574 34 | 37B30044-3B14-46BA-ABAA-F01000C27B63 35 | 640F884E-CE55-4B40-87C0-8869546CAB7A 36 | 992275C1-432A-4CF7-B659-D84ED6D42D3F 37 | A16FF353-8441-459E-A50C-B071F53F51B7 38 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7 39 | E969541F-E6F9-4D25-8158-72DC3545A6C6 40 | 8DC44374-2B35-4C57-A6FE-2AD66A36AAD9 41 | AABB7188-E14E-4433-AD3B-5CD791EAD9A3 42 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90 43 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 44 | CC0D0F4F-05B3-431A-8F33-F84AFCB2C651 45 | 7265231C-39B4-402C-89E1-16167C4CC990 46 | 9AFF134A-08DC-4096-8CEE-62A4BB123046 47 | F41BD31E-2683-44B8-AE7F-5F09E919790E 48 | E71C2CFE-BFD8-4044-8F06-00AE685A406C 49 | ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C 50 | 51 | NSPrincipalClass 52 | StarConsoleLink 53 | XC4Compatible 54 | 55 | XCPluginHasUI 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Library/JRSwizzle/JRSwizzle.h: -------------------------------------------------------------------------------- 1 | // JRSwizzle.h semver:1.0 2 | // Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com 3 | // Some rights reserved: http://opensource.org/licenses/MIT 4 | // https://github.com/rentzsch/jrswizzle 5 | 6 | #import 7 | 8 | @interface NSObject (JRSwizzle) 9 | 10 | + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_; 11 | + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_; 12 | 13 | @end -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Library/JRSwizzle/JRSwizzle.m: -------------------------------------------------------------------------------- 1 | // JRSwizzle.m semver:1.0 2 | // Copyright (c) 2007-2011 Jonathan 'Wolf' Rentzsch: http://rentzsch.com 3 | // Some rights reserved: http://opensource.org/licenses/MIT 4 | // https://github.com/rentzsch/jrswizzle 5 | 6 | #import "JRSwizzle.h" 7 | 8 | #if TARGET_OS_IPHONE 9 | #import 10 | #import 11 | #else 12 | #import 13 | #endif 14 | 15 | #define SetNSErrorFor(FUNC, ERROR_VAR, FORMAT,...) \ 16 | if (ERROR_VAR) { \ 17 | NSString *errStr = [NSString stringWithFormat:@"%s: " FORMAT,FUNC,##__VA_ARGS__]; \ 18 | *ERROR_VAR = [NSError errorWithDomain:@"NSCocoaErrorDomain" \ 19 | code:-1 \ 20 | userInfo:[NSDictionary dictionaryWithObject:errStr forKey:NSLocalizedDescriptionKey]]; \ 21 | } 22 | #define SetNSError(ERROR_VAR, FORMAT,...) SetNSErrorFor(__func__, ERROR_VAR, FORMAT, ##__VA_ARGS__) 23 | 24 | #if OBJC_API_VERSION >= 2 25 | #define GetClass(obj) object_getClass(obj) 26 | #else 27 | #define GetClass(obj) (obj ? obj->isa : Nil) 28 | #endif 29 | 30 | @implementation NSObject (JRSwizzle) 31 | 32 | + (BOOL)jr_swizzleMethod:(SEL)origSel_ withMethod:(SEL)altSel_ error:(NSError**)error_ { 33 | #if OBJC_API_VERSION >= 2 34 | Method origMethod = class_getInstanceMethod(self, origSel_); 35 | if (!origMethod) { 36 | #if TARGET_OS_IPHONE 37 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self class]); 38 | #else 39 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); 40 | #endif 41 | return NO; 42 | } 43 | 44 | Method altMethod = class_getInstanceMethod(self, altSel_); 45 | if (!altMethod) { 46 | #if TARGET_OS_IPHONE 47 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self class]); 48 | #else 49 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); 50 | #endif 51 | return NO; 52 | } 53 | 54 | class_addMethod(self, 55 | origSel_, 56 | class_getMethodImplementation(self, origSel_), 57 | method_getTypeEncoding(origMethod)); 58 | class_addMethod(self, 59 | altSel_, 60 | class_getMethodImplementation(self, altSel_), 61 | method_getTypeEncoding(altMethod)); 62 | 63 | method_exchangeImplementations(class_getInstanceMethod(self, origSel_), class_getInstanceMethod(self, altSel_)); 64 | return YES; 65 | #else 66 | // Scan for non-inherited methods. 67 | Method directOriginalMethod = NULL, directAlternateMethod = NULL; 68 | 69 | void *iterator = NULL; 70 | struct objc_method_list *mlist = class_nextMethodList(self, &iterator); 71 | while (mlist) { 72 | int method_index = 0; 73 | for (; method_index < mlist->method_count; method_index++) { 74 | if (mlist->method_list[method_index].method_name == origSel_) { 75 | assert(!directOriginalMethod); 76 | directOriginalMethod = &mlist->method_list[method_index]; 77 | } 78 | if (mlist->method_list[method_index].method_name == altSel_) { 79 | assert(!directAlternateMethod); 80 | directAlternateMethod = &mlist->method_list[method_index]; 81 | } 82 | } 83 | mlist = class_nextMethodList(self, &iterator); 84 | } 85 | 86 | // If either method is inherited, copy it up to the target class to make it non-inherited. 87 | if (!directOriginalMethod || !directAlternateMethod) { 88 | Method inheritedOriginalMethod = NULL, inheritedAlternateMethod = NULL; 89 | if (!directOriginalMethod) { 90 | inheritedOriginalMethod = class_getInstanceMethod(self, origSel_); 91 | if (!inheritedOriginalMethod) { 92 | SetNSError(error_, @"original method %@ not found for class %@", NSStringFromSelector(origSel_), [self className]); 93 | return NO; 94 | } 95 | } 96 | if (!directAlternateMethod) { 97 | inheritedAlternateMethod = class_getInstanceMethod(self, altSel_); 98 | if (!inheritedAlternateMethod) { 99 | SetNSError(error_, @"alternate method %@ not found for class %@", NSStringFromSelector(altSel_), [self className]); 100 | return NO; 101 | } 102 | } 103 | 104 | int hoisted_method_count = !directOriginalMethod && !directAlternateMethod ? 2 : 1; 105 | struct objc_method_list *hoisted_method_list = malloc(sizeof(struct objc_method_list) + (sizeof(struct objc_method)*(hoisted_method_count-1))); 106 | hoisted_method_list->obsolete = NULL; // soothe valgrind - apparently ObjC runtime accesses this value and it shows as uninitialized in valgrind 107 | hoisted_method_list->method_count = hoisted_method_count; 108 | Method hoisted_method = hoisted_method_list->method_list; 109 | 110 | if (!directOriginalMethod) { 111 | bcopy(inheritedOriginalMethod, hoisted_method, sizeof(struct objc_method)); 112 | directOriginalMethod = hoisted_method++; 113 | } 114 | if (!directAlternateMethod) { 115 | bcopy(inheritedAlternateMethod, hoisted_method, sizeof(struct objc_method)); 116 | directAlternateMethod = hoisted_method; 117 | } 118 | class_addMethods(self, hoisted_method_list); 119 | } 120 | 121 | // Swizzle. 122 | IMP temp = directOriginalMethod->method_imp; 123 | directOriginalMethod->method_imp = directAlternateMethod->method_imp; 124 | directAlternateMethod->method_imp = temp; 125 | 126 | return YES; 127 | #endif 128 | } 129 | 130 | + (BOOL)jr_swizzleClassMethod:(SEL)origSel_ withClassMethod:(SEL)altSel_ error:(NSError**)error_ { 131 | return [GetClass((id)self) jr_swizzleMethod:origSel_ withMethod:altSel_ error:error_]; 132 | } 133 | 134 | @end -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Library/LogColor/LogColorKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // LogColorKit.h 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/19. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface LogColorKit : NSObject 13 | 14 | + (void)applyANSIColors:(NSTextStorage *)textStorage 15 | textStorageRange:(NSRange)textStorageRange 16 | escapeSeq:(NSString *)escapeSeq; 17 | void ApplyANSIColors(NSTextStorage *textStorage, NSRange textStorageRange, NSString *escapeSeq); 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Library/PluginHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PluginHelper.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AppKit 11 | 12 | 13 | // MARK: - File Cache & Find File 14 | 15 | // [workspacePath : [fileName : filePath]] 16 | var filePathCache = [String : [String : String]]() 17 | 18 | func findFile(workspacePath : String, _ fileName : String) -> String? { 19 | var thisWorkspaceCache = filePathCache[workspacePath] ?? [:] 20 | if let result = thisWorkspaceCache[fileName] { 21 | if NSFileManager.defaultManager().fileExistsAtPath(result) { 22 | return result 23 | } 24 | } 25 | 26 | var searchPath = workspacePath 27 | var prevSearchPath : String? = nil 28 | var searchCount = 0 29 | while true { 30 | if let result = findFile(fileName, searchPath, prevSearchPath) where !result.isEmpty { 31 | thisWorkspaceCache[fileName] = result 32 | filePathCache[workspacePath] = thisWorkspaceCache 33 | return result 34 | } 35 | 36 | prevSearchPath = searchPath 37 | searchPath = searchPath.OCString.stringByDeletingLastPathComponent 38 | searchCount += 1 39 | let searchPathCount = searchPath.componentsSeparatedByString("/").count 40 | if searchPathCount <= 3 || searchCount >= 2 { 41 | return nil 42 | } 43 | } 44 | } 45 | 46 | func findFile(fileName : String, _ searchPath : String, _ prevSearchPath : String?) -> String? { 47 | let args = (prevSearchPath == nil ? 48 | ["-L", searchPath, "-name", fileName, "-print", "-quit"] : 49 | ["-L", searchPath, "-name", prevSearchPath!, "-prune", "-o", "-name", fileName, "-print", "-quit"]) 50 | return PluginHelper.runShellCommand("/usr/bin/find", arguments: args) 51 | } 52 | 53 | 54 | // MARK: - PluginHelper 55 | 56 | class PluginHelper: NSObject { 57 | 58 | static func runShellCommand(launchPath: String, arguments: [String]) -> String? { 59 | let pipe = NSPipe() 60 | let task = NSTask() 61 | task.launchPath = launchPath 62 | task.arguments = arguments 63 | task.standardOutput = pipe 64 | let file = pipe.fileHandleForReading 65 | task.launch() 66 | guard let result = NSString(data: file.readDataToEndOfFile(), encoding: NSUTF8StringEncoding)?.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()) else { 67 | return nil 68 | } 69 | return result as String 70 | } 71 | 72 | static func getViewByClassName(name: String, inContainer container: NSView) -> NSView? { 73 | 74 | guard let targetClass = NSClassFromString(name) else { 75 | return nil 76 | } 77 | for subview in container.subviews { 78 | if subview.isKindOfClass(targetClass) { 79 | return subview 80 | } 81 | if let view = getViewByClassName(name, inContainer: subview) { 82 | return view 83 | } 84 | } 85 | return nil 86 | } 87 | } 88 | 89 | extension PluginHelper { 90 | 91 | static func workspacePath() -> String? { 92 | 93 | if let workspacePath = StarFunctions.workspacePath() { 94 | return workspacePath 95 | } 96 | 97 | guard let anyClass = NSClassFromString("IDEWorkspaceWindowController") as? NSObject.Type, 98 | let windowControllers = anyClass.valueForKey("workspaceWindowControllers") as? [NSObject], 99 | let window = NSApp.keyWindow ?? NSApp.windows.first else { 100 | Logger.info("Failed to establish workspace path") 101 | return nil 102 | } 103 | var workspace: NSObject? 104 | for controller in windowControllers { 105 | if controller.valueForKey("window")?.isEqual(window) == true { 106 | workspace = controller.valueForKey("_workspace") as? NSObject 107 | } 108 | } 109 | 110 | guard let workspacePath = workspace?.valueForKeyPath("representingFilePath._pathString") as? NSString else { 111 | Logger.info("Failed to establish workspace path") 112 | return nil 113 | } 114 | 115 | return workspacePath.stringByDeletingLastPathComponent as String 116 | } 117 | 118 | // 代码台 119 | static func editorTextView(inWindow window: NSWindow? = NSApp.mainWindow) -> NSTextView? { 120 | guard let window = window, 121 | let windowController = window.windowController, 122 | let editor = windowController.valueForKeyPath("editorArea.lastActiveEditorContext.editor"), 123 | let textView = editor.valueForKey("textView") as? NSTextView else { 124 | return nil 125 | } 126 | 127 | return textView 128 | } 129 | 130 | // DVTSourceTextView 控制台 131 | static func consoleTextView(inWindow window: NSWindow? = NSApp.mainWindow) -> NSTextView? { 132 | guard let contentView = window?.contentView, 133 | let consoleTextView = PluginHelper.getViewByClassName("IDEConsoleTextView", inContainer: contentView) as? NSTextView else { 134 | return nil 135 | } 136 | return consoleTextView 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Library/StarFunctions.h: -------------------------------------------------------------------------------- 1 | // 2 | // StarFunctions.h 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/25. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StarFunctions: NSObject 12 | + (NSString*)workspacePath; 13 | + (void)printMothList:(Class)class; 14 | + (NSArray *)getAllProperties:(Class)class; 15 | + (NSDictionary *)properties_aps:(Class)class; 16 | @end -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Library/StarFunctions.m: -------------------------------------------------------------------------------- 1 | // 2 | // StarFunctions.m 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/2/25. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import "StarFunctions.h" 10 | #import 11 | #import "JRSwizzle.h" 12 | 13 | @implementation StarFunctions 14 | 15 | + (NSString*)workspacePath { 16 | @try { 17 | NSDocument *document = [NSApp orderedDocuments].firstObject; 18 | return [[document valueForKeyPath:@"_workspace.representingFilePath.fileURL"] URLByDeletingLastPathComponent].path; 19 | } 20 | @catch (NSException *exception) { 21 | return nil; 22 | } 23 | return nil; 24 | } 25 | 26 | + (void)printMothList:(Class)class { 27 | unsigned int mothCout_f =0; 28 | Method* mothList_f = class_copyMethodList(class, &mothCout_f); 29 | for(int i=0;i [%s][%s:%d] %s %s %s\n",\ 62 | STAR_CONSOLE_COLOR_ESCAPE_FG,\ 63 | color,\ 64 | star_current_time(),\ 65 | title,\ 66 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 67 | __LINE__,\ 68 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String],\ 69 | STAR_CONSOLE_COLOR_RESET_FG,\ 70 | star_back_trace(stack, StarBackTraceDepth)\ 71 | )\ 72 | 73 | // NSLog 74 | #define NSLog(format, ...) \ 75 | PrivateLog(NSLogColor, NSLogTitle, StarBackTrace, format, ##__VA_ARGS__) 76 | 77 | // Information 78 | #define LogInfo(format, ...) \ 79 | PrivateLog(InfoColor, InfoTitle, StarBackTrace, format, ##__VA_ARGS__) 80 | 81 | // Debug 82 | #define LogDebug(format, ...) \ 83 | PrivateLog(DebugColor, DebugTitle, StarBackTrace, format, ##__VA_ARGS__) 84 | 85 | // Warning 86 | #define LogWarning(format, ...) \ 87 | PrivateLog(WarningColor, WarningTitle, StarBackTrace, format, ##__VA_ARGS__) 88 | 89 | // Error 90 | #define LogError(format, ...) \ 91 | PrivateLog(ErrorColor, ErrorTitle, StarBackTrace, format, ##__VA_ARGS__) 92 | 93 | // Success 94 | #define LogSuccess(format, ...) \ 95 | PrivateLog(SuccessColor, SuccessTitle, StarBackTrace, format, ##__VA_ARGS__) 96 | 97 | // Failure 98 | #define LogFailure(format, ...) \ 99 | PrivateLog(FailureColor, FailureTitle, StarBackTrace, format, ##__VA_ARGS__) 100 | 101 | // Assert 102 | #define LogAssert(condition, format, ...)\ 103 | PrivateLog(AssertColor, AssertTitle, StarBackTrace, format, ##__VA_ARGS__);\ 104 | NSAssert(condition, format, ##__VA_ARGS__) 105 | 106 | // LogBackTrace 107 | #define LogBackTrace(format, ...) \ 108 | PrivateLog(BackTraceColor, BackTraceTitle, 1, format, ##__VA_ARGS__)\ 109 | 110 | #else /* Color Else */ 111 | 112 | #define PrivateLog(color, title, stack, format, ...)\ 113 | printf("<%s> [%s][%s:%d] %s %s\n",\ 114 | star_current_time(),\ 115 | title,\ 116 | [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],\ 117 | __LINE__,\ 118 | [[NSString stringWithFormat:format,##__VA_ARGS__] UTF8String],\ 119 | star_back_trace(stack, StarBackTraceDepth)\ 120 | );\ 121 | 122 | // NSLog 123 | #define NSLog(format, ...) \ 124 | PrivateLog(0, NSLogTitle, StarBackTrace, format, ##__VA_ARGS__) 125 | 126 | // Information 127 | #define LogInfo(format, ...) \ 128 | PrivateLog(0, InfoTitle, StarBackTrace, format, ##__VA_ARGS__) 129 | 130 | // Debug 131 | #define LogDebug(format, ...) \ 132 | PrivateLog(0, DebugTitle, StarBackTrace, format, ##__VA_ARGS__) 133 | 134 | // Warning 135 | #define LogWarning(format, ...) \ 136 | PrivateLog(0, WarningTitle, StarBackTrace, format, ##__VA_ARGS__) 137 | 138 | // Error 139 | #define LogError(format, ...) \ 140 | PrivateLog(0, ErrorTitle, StarBackTrace, format, ##__VA_ARGS__) 141 | 142 | // Success 143 | #define LogSuccess(format, ...) \ 144 | PrivateLog(0, SuccessTitle, StarBackTrace, format, ##__VA_ARGS__) 145 | 146 | // Failure 147 | #define LogFailure(format, ...) \ 148 | PrivateLog(0, FailureTitle, StarBackTrace, format, ##__VA_ARGS__) 149 | 150 | // Assert 151 | #define LogAssert(condition, format, ...)\ 152 | PrivateLog(0, FailureTitle, StarBackTrace, format, ##__VA_ARGS__);\ 153 | NSAssert(condition, format, ##__VA_ARGS__) 154 | 155 | // Stack 156 | #define LogBackTrace(format, ...) \ 157 | PrivateLog(0, BackTraceTitle, 1, format, ##__VA_ARGS__)\ 158 | 159 | #endif /* Color End */ 160 | 161 | #else /* Debug Else */ 162 | 163 | #define PrivateLog(color, title, format, ...) while(0){} 164 | #define NSLog(...) while(0){} 165 | #define LogInfo(...) while(0){} 166 | #define LogDebug(...) while(0){} 167 | #define LogError(...) while(0){} 168 | #define LogWarning(...) while(0){} 169 | #define LogSuccess(...) while(0){} 170 | #define LogFailure(...) while(0){} 171 | #define LogAssert(condition, format, ...) while(0){} 172 | #define LogBackTrace(...) while(0){} 173 | 174 | #endif /* Debug End */ 175 | 176 | 177 | 178 | 179 | /* Function Begin */ 180 | 181 | #include 182 | #include 183 | #include 184 | #include 185 | #include 186 | #include 187 | 188 | #define STAR_BACK_TRACE_BUFFER 4096 189 | #define STAR_TIME_BUFFER 255 190 | 191 | 192 | static inline const char * star_back_trace(int open, int depth) { 193 | 194 | if (!open) { 195 | return ""; 196 | } 197 | 198 | static char star_back_trace_str[STAR_BACK_TRACE_BUFFER]; 199 | 200 | void *callstack[128]; 201 | int frames = backtrace(callstack, 128); 202 | char **strs = backtrace_symbols(callstack, frames); 203 | 204 | memset(star_back_trace_str, 0, STAR_BACK_TRACE_BUFFER * sizeof(char)); 205 | strcat(star_back_trace_str, "\n"); 206 | for (int i = 1; i < frames; i++) { 207 | // if (strlen(star_back_trace_str) + strlen(strs[i]) + 16 > STAR_BACK_TRACE_BUFFER) 208 | // break; 209 | strcat(star_back_trace_str, "\n\t"); 210 | strcat(star_back_trace_str, strs[i]); 211 | if (i == depth) 212 | break; 213 | } 214 | strcat(star_back_trace_str, "\n"); 215 | 216 | free(strs); 217 | strs = NULL; 218 | 219 | return star_back_trace_str; 220 | } 221 | 222 | static inline const char * star_current_time() { 223 | 224 | static char star_time_str[STAR_TIME_BUFFER]; 225 | 226 | time_t rawtime; 227 | struct tm * timeinfo; 228 | time(&rawtime); 229 | timeinfo = localtime(&rawtime); 230 | memset(star_time_str, 0, STAR_TIME_BUFFER * sizeof(char)); 231 | strftime(star_time_str, STAR_TIME_BUFFER, "%Y-%m-%d %H:%M:%S", timeinfo); 232 | return star_time_str; 233 | } 234 | 235 | /** 236 | * 如果需要用到毫秒,那就替换成下列函数好了 237 | */ 238 | static inline const char * star_current_time_milli() { 239 | 240 | static char star_time_str[STAR_TIME_BUFFER]; 241 | 242 | struct timeb timeinfo; 243 | ftime(&timeinfo); 244 | 245 | struct tm * second_timeinfo; 246 | second_timeinfo = localtime(&timeinfo.time); 247 | 248 | memset(star_time_str, 0, STAR_TIME_BUFFER * sizeof(char)); 249 | strftime(star_time_str, STAR_TIME_BUFFER, "%Y-%m-%d %H:%M:%S", second_timeinfo); 250 | 251 | //#if using_millitm 252 | char millitm[16]; 253 | sprintf(millitm, ".%03d", timeinfo.millitm); 254 | strcat(star_time_str, millitm); 255 | //#endif 256 | 257 | return star_time_str; 258 | } 259 | 260 | /* Function End */ 261 | 262 | 263 | 264 | #endif /* Logger_h */ 265 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/Logger/Logger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // 控制是否启用日志打印 12 | // 此处的DEBUG应该在target下 Build Settings 搜索 Other Swift Flags 13 | // 设置Debug 添加 -D DEBUG,注意不要好Release一起添加 14 | #if DEBUG 15 | let StarDebug = true 16 | #else 17 | let StarDebug = false 18 | #endif 19 | 20 | 21 | struct LogColor { 22 | 23 | static let XcodeColors = true 24 | 25 | static let ESCAPE = "\u{001b}[" 26 | static let ESCAPE_FG = "\u{001b}[fg" 27 | static let ESCAPE_BG = "\u{001b}[bg" 28 | 29 | static let RESET = ESCAPE + ";" // Clear any foreground or background color 30 | static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color 31 | static let RESET_BG = ESCAPE + "bg;" // Clear any background color 32 | } 33 | 34 | let InfoColor = "22,22,22" // 黑色 35 | let InfoTitle = "Info" 36 | 37 | let DebugColor = "28,0,207" // 蓝色 38 | let DebugTitle = "Debug" 39 | 40 | let WarningColor = "218,130,53" // 黄色 41 | let WarningTitle = "Warning" 42 | 43 | let ErrorColor = "196,26,22" // 红色 44 | let ErrorTitle = "Error" 45 | 46 | let ImportantColor = "196,26,22" // 红色 47 | let ImportantTitle = "Important - 如果发现该行日志,应该及时处理" 48 | 49 | let SuccessColor = "0,116,0" // 绿色 50 | let SuccessTitle = "Success" 51 | 52 | let FailureColor = "196,26,22" // 红色 53 | let FailureTitle = "Failure" 54 | 55 | let AssertColor = "196,26,22" // 红色 56 | let AssertTitle = "Assert" 57 | 58 | let FatalErrorColor = "196,26,22" // 红色 59 | let FatalErrorTitle = "FatalError" 60 | 61 | //#if swift(>=2.2) 62 | // let functionName = #function 63 | //#else 64 | // let functionName = __FUNCTION__ 65 | //#endif 66 | 67 | struct Logger { 68 | 69 | static func print(_ value: T, title: String, color: String, functionName: String, fileName: String, lineNumber: Int) { 70 | 71 | guard StarDebug else { 72 | return 73 | } 74 | if LogColor.XcodeColors { 75 | Swift.print("\(LogColor.ESCAPE_FG)\(color);<\(current_time())> [\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)\(LogColor.RESET_FG)") 76 | } 77 | else { 78 | Swift.print("<\(current_time())> [\(title)][\((fileName as NSString).lastPathComponent):\(lineNumber)] \(value)") 79 | } 80 | } 81 | 82 | static func info(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 83 | print(value, title: InfoTitle, color: InfoColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 84 | } 85 | 86 | static func debug(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 87 | print(value, title: DebugTitle, color: DebugColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 88 | } 89 | 90 | static func warning(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 91 | print(value, title: WarningTitle, color: WarningColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 92 | } 93 | 94 | static func error(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 95 | print(value, title: ErrorTitle, color: ErrorColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 96 | } 97 | 98 | static func important(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 99 | print(value, title: ImportantTitle, color: ImportantColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 100 | } 101 | 102 | fileprivate static func current_time() -> String { 103 | let bufferSize = 255 104 | var buffer = [Int8](repeating: 0, count: bufferSize) 105 | var rawtime = time(nil) 106 | let timeinfo = localtime(&rawtime) 107 | strftime(&buffer, 32, "%Y-%m-%d %H:%M:%S", timeinfo) // %B 108 | // String.init(CString) 109 | // String() 110 | let datetime = String(cString: buffer, encoding: String.Encoding.utf8)! 111 | // free(buffer) 112 | return datetime 113 | } 114 | 115 | static func star_back_trace(_ depth: UInt) -> String { 116 | 117 | 118 | Swift.print(Thread.callStackSymbols); 119 | 120 | 121 | // void *callstack[128]; 122 | // int frames = backtrace(callstack, 128); 123 | // char **strs = backtrace_symbols(callstack, frames); 124 | // 125 | // memset(star_back_trace_str, 0, STAR_BACK_TRACE_BUFFER * sizeof(char)); 126 | // strcat(star_back_trace_str, "\n"); 127 | // for (int i = 1; i < frames; i++) { 128 | // // if (strlen(star_back_trace_str) + strlen(strs[i]) + 16 > STAR_BACK_TRACE_BUFFER) 129 | // // break; 130 | // strcat(star_back_trace_str, "\n\t"); 131 | // strcat(star_back_trace_str, strs[i]); 132 | // if (i == depth) 133 | // break; 134 | // } 135 | // strcat(star_back_trace_str, "\n"); 136 | // 137 | // free(strs); 138 | // strs = NULL; 139 | // 140 | // return star_back_trace_str; 141 | return ""; 142 | } 143 | 144 | } 145 | 146 | // MARK: - Resoponse 147 | extension Logger { 148 | 149 | static func success(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 150 | print(value, title: SuccessTitle, color: SuccessColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 151 | } 152 | 153 | static func failure(_ value: T, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 154 | print(value, title: FailureTitle, color: FailureColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 155 | } 156 | } 157 | 158 | // MARK: - Assert 159 | extension Logger { 160 | 161 | static func assertionFailure(_ value: String, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 162 | print(value, title: AssertTitle, color: AssertColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 163 | Swift.assertionFailure(value) 164 | 165 | } 166 | 167 | static func assert(_ flag: Bool, value:String, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 168 | print(value, title: AssertTitle, color: AssertColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 169 | Swift.assert(flag) 170 | } 171 | 172 | static func fatalError(_ value: String, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) { 173 | print(value, title: FatalErrorTitle, color: FatalErrorColor, functionName: functionName, fileName: fileName, lineNumber: lineNumber) 174 | Swift.fatalError(value) 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/NSObject-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension NSObject { 12 | class func pluginDidLoad(bundle: NSBundle) { 13 | let appName = NSBundle.mainBundle().infoDictionary?["CFBundleName"] as? NSString 14 | if appName == "Xcode" { 15 | if sharedPlugin == nil { 16 | sharedPlugin = StarConsoleLink(bundle: bundle) 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/NSTextStorage-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSTextStorage-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | 13 | // used 14 | var UsedInConsoleKey = "Mark.By.Star.isUsedInXcodeConsole" 15 | 16 | // XcodeColors escape 17 | let XCODE_COLORS_ESCAPE = "\u{001b}[" 18 | 19 | // \[ 匹配[开头的 20 | // ([\w\+\-]+) 匹配文件名,包含+号-号 21 | // \. 匹配文件名中的点 22 | // (\w+) 匹配后缀 23 | // : 匹配冒号 24 | // (\d+) 匹配行号 25 | // \] 匹配]结尾的 26 | let RegularFileNameLineExpr = try! NSRegularExpression(pattern: "\\[(([\\w\\+\\-]+)\\.(\\w+):(\\d+))\\]", options: .CaseInsensitive) 27 | 28 | // ([\+\-]) 匹配OC方法的类型 29 | // \[ 匹配[开头的 30 | // ([\w\+\-]+) 匹配文件名,包含+号-号 31 | // \ 匹配文件名中的空格 32 | // ([\w\:]+) 匹配后缀 33 | // \] 匹配]结尾的 34 | let RegularFileNameMethodExpr = try! NSRegularExpression(pattern: "([\\+\\-])\\[(([\\w\\+\\-]+) ([\\w\\:]+))\\]", options: .CaseInsensitive) 35 | 36 | struct StarConsoleLinkFieldName { 37 | static let flag = "Star.StarConsoleLink.Flag" 38 | static let fileName = "Star.StarConsoleLink.FileName" 39 | static let line = "Star.StarConsoleLink.Line" 40 | static let methodName = "Star.StarConsoleLink.MethodName" 41 | static let methodType = "Star.StarConsoleLink.MethodType" 42 | } 43 | 44 | 45 | extension NSTextStorage { 46 | 47 | 48 | var usedInConsole: Bool { 49 | get { 50 | return (objc_getAssociatedObject(self, &UsedInConsoleKey) as? NSNumber)?.boolValue ?? false 51 | } 52 | set { 53 | objc_setAssociatedObject(self, &UsedInConsoleKey, NSNumber(bool: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 54 | } 55 | } 56 | 57 | func star_fixAttributesInRange(range: NSRange) { 58 | star_fixAttributesInRange(range) 59 | if usedInConsole && ConsoleLinkConfig.consoleLinkEnabled { 60 | LogColorKit.applyANSIColors(self, textStorageRange: range, escapeSeq: XCODE_COLORS_ESCAPE) 61 | self.injectNormalLinks() 62 | self.injectBackTraceLinks() 63 | } 64 | } 65 | 66 | 67 | private func injectNormalLinks() { 68 | 69 | let matches = RegularFileNameLineExpr.matchesInString(self.string, options: .ReportProgress, range: self.editedRange) 70 | for result in matches where result.numberOfRanges == 5 { 71 | 72 | let ocText = self.string.OCString 73 | 74 | // let fullRange = result.rangeAtIndex(0) 75 | let linkRange = result.rangeAtIndex(1) 76 | let link = ocText.substringWithRange(linkRange) 77 | 78 | let fileNameRange = result.rangeAtIndex(2) 79 | let fileName = ocText.substringWithRange(fileNameRange) 80 | 81 | let fileExtensionRange = result.rangeAtIndex(3) 82 | let fileExtension = ocText.substringWithRange(fileExtensionRange) 83 | 84 | let lineRange = result.rangeAtIndex(4) 85 | let line = ocText.substringWithRange(lineRange) 86 | 87 | self.addAttribute(StarConsoleLinkFieldName.flag, value: "1", range: linkRange) 88 | self.addAttribute(StarConsoleLinkFieldName.fileName, value: "\(fileName).\(fileExtension)", range: linkRange) 89 | self.addAttribute(StarConsoleLinkFieldName.line, value: line, range: linkRange) 90 | 91 | self.addAttribute(NSLinkAttributeName, value: link, range: linkRange) 92 | self.addAttribute(NSForegroundColorAttributeName, value: ConsoleLinkConfig.linkColor, range: linkRange) 93 | } 94 | 95 | } 96 | 97 | private func injectBackTraceLinks() { 98 | 99 | let matches = RegularFileNameMethodExpr.matchesInString(self.string, options: .ReportProgress, range: self.editedRange) 100 | for result in matches where result.numberOfRanges == 5 { 101 | 102 | let ocText = self.string.OCString 103 | 104 | let fullRange = result.rangeAtIndex(0) 105 | let fullText = ocText.substringWithRange(fullRange) 106 | Logger.error(fullText) 107 | 108 | let methodTypeRange = result.rangeAtIndex(1) 109 | let methodType = ocText.substringWithRange(methodTypeRange) 110 | 111 | let linkRange = result.rangeAtIndex(2) 112 | let link = ocText.substringWithRange(linkRange) 113 | 114 | let fileNameRange = result.rangeAtIndex(3) 115 | let fileName = ocText.substringWithRange(fileNameRange) 116 | 117 | let methodNameRange = result.rangeAtIndex(4) 118 | let methodName = ocText.substringWithRange(methodNameRange) 119 | 120 | self.addAttribute(StarConsoleLinkFieldName.flag, value: "2", range: linkRange) 121 | self.addAttribute(StarConsoleLinkFieldName.methodType, value:methodType, range: linkRange) 122 | self.addAttribute(StarConsoleLinkFieldName.fileName, value:fileName, range: linkRange) 123 | self.addAttribute(StarConsoleLinkFieldName.methodName, value:methodName, range: linkRange) 124 | 125 | self.addAttribute(NSLinkAttributeName, value: link, range: linkRange) 126 | self.addAttribute(NSForegroundColorAttributeName, value: ConsoleLinkConfig.linkColor, range: linkRange) 127 | } 128 | 129 | } 130 | 131 | } -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/NSTextView-Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSTextView-Extension.swift 3 | // StarConsoleLink 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | extension NSTextView { 13 | 14 | 15 | func star_mouseDown(theEvent: NSEvent) { 16 | 17 | 18 | // 当前点击的TextView是否是Xcode的Console 19 | guard let expectedClass = NSClassFromString("IDEConsoleTextView") where self.isKindOfClass(expectedClass) else { 20 | star_mouseDown(theEvent) 21 | return 22 | } 23 | 24 | // 点击区域是否是rich text 25 | let pos = self.convertPoint(theEvent.locationInWindow, fromView:nil) 26 | let index = self.characterIndexForInsertionAtPoint(pos) 27 | guard self.attributedString().length > 1 && index < self.attributedString().length else { 28 | star_mouseDown(theEvent) 29 | return 30 | } 31 | 32 | let attr = self.attributedString().attributesAtIndex(index, effectiveRange: nil) 33 | 34 | // 验证标志 35 | guard attr[StarConsoleLinkFieldName.flag] != nil else { 36 | star_mouseDown(theEvent) 37 | return 38 | } 39 | 40 | // 访问[filename.extension:line]的超链接 41 | if let fileName = attr[StarConsoleLinkFieldName.fileName] as? String, 42 | let lineNumber = attr[StarConsoleLinkFieldName.line] as? String { 43 | 44 | guard let workspacePath = PluginHelper.workspacePath(), let filePath = findFile(workspacePath, fileName) else { 45 | // 如果是按规则定义的链接,但是没有找到对应的文件,那么此次点击应该使其失效 46 | return 47 | } 48 | 49 | // 用编辑器打开文件 50 | if let open = NSApplication.sharedApplication().delegate?.application?(NSApplication.sharedApplication(), openFile: filePath) where open { 51 | // 主线程异步调用,防止闪退 52 | dispatch_get_main_queue().async { () -> Void in 53 | if let textView = PluginHelper.editorTextView(inWindow: self.window), 54 | let line = Int(lineNumber) 55 | where line >= 1 { 56 | textView.scrollToLine(line) 57 | } 58 | } 59 | } 60 | } 61 | 62 | // 访问[filename methodName:]的超链接 63 | if var fileName = attr[StarConsoleLinkFieldName.fileName] as? String, 64 | let methodType = attr[StarConsoleLinkFieldName.methodType] as? String, 65 | let methodName = attr[StarConsoleLinkFieldName.methodName] as? String { 66 | 67 | // 暂时只支持查找.m结尾的文件 68 | fileName.appendContentsOf(".m") 69 | guard let workspacePath = PluginHelper.workspacePath(), let filePath = findFile(workspacePath, fileName) else { 70 | return 71 | } 72 | if let open = NSApplication.sharedApplication().delegate?.application?(NSApplication.sharedApplication(), openFile: filePath) where open { 73 | dispatch_get_main_queue().async { 74 | if let textView = PluginHelper.editorTextView(inWindow: self.window) { 75 | textView.scrollToMethod(methodType, methodName) 76 | } 77 | } 78 | } 79 | } 80 | } 81 | 82 | private func scrollToLine(line: Int) { 83 | 84 | guard let text = self.string?.OCString else { 85 | return 86 | } 87 | 88 | var currentLine:Int = 0 89 | text.enumerateLinesUsingBlock { (lineText: String, stop: UnsafeMutablePointer) in 90 | currentLine += 1 91 | if line == currentLine { 92 | let lineRange = text.rangeOfString(lineText) 93 | if lineRange.location != NSNotFound { 94 | self.scrollRangeToVisible(lineRange) 95 | self.setSelectedRange(lineRange) 96 | } 97 | stop.memory = ObjCBool(true) 98 | } 99 | } 100 | } 101 | 102 | private func scrollToMethod(methodType: String, _ methodName: String) { 103 | 104 | guard let text = self.string?.OCString else { 105 | return 106 | } 107 | 108 | var passTotalCount = 0 109 | var passIndex = 0 110 | 111 | text.enumerateLinesUsingBlock { (lineText, stop) in 112 | 113 | var methodComponents = methodName.componentsSeparatedByString(":") 114 | 115 | // 无参函数直接处理 116 | if methodComponents.count == 1 { 117 | if lineText.rangeOfString(methodType) != nil 118 | && lineText.rangeOfString(methodName) != nil { 119 | 120 | let lineRange = text.rangeOfString(lineText) 121 | if lineRange.location != NSNotFound { 122 | self.scrollRangeToVisible(lineRange) 123 | self.setSelectedRange(lineRange) 124 | stop.memory = ObjCBool(true) 125 | } 126 | } 127 | } 128 | 129 | // 有参方法已经完成,但是没有考虑换行的情况,任性,不想做,想让我做给钱。。。。 130 | if methodComponents.count > 1 { 131 | methodComponents.removeLast() 132 | methodComponents = methodComponents.map { $0 + ":" } 133 | 134 | if lineText.rangeOfString(methodType) == nil { 135 | } 136 | 137 | if lineText.rangeOfString(methodType) != nil { 138 | passTotalCount = methodComponents.count 139 | 140 | for methodElement in methodComponents { 141 | if lineText.rangeOfString(methodElement) != nil { 142 | passIndex += 1 143 | } 144 | } 145 | if (passIndex == passTotalCount) { 146 | let lineRange = text.rangeOfString(lineText) 147 | if lineRange.location != NSNotFound { 148 | self.scrollRangeToVisible(lineRange) 149 | self.setSelectedRange(lineRange) 150 | stop.memory = ObjCBool(true) 151 | } 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | 159 | func star_insertNewline(arg1: AnyObject) { 160 | self.star_checkTextView() 161 | self.star_insertNewline(arg1) 162 | } 163 | 164 | func star_clearConsoleItems() { 165 | self.star_checkTextView() 166 | self.star_clearConsoleItems() 167 | } 168 | 169 | func star_shouldChangeTextInRanges(ranges: AnyObject, replacementStrings strings: AnyObject) -> Bool { 170 | self.star_checkTextView() 171 | return self.star_shouldChangeTextInRanges(ranges, replacementStrings: strings) 172 | } 173 | 174 | 175 | func star_checkTextView() { 176 | 177 | guard let expectedClass = NSClassFromString("IDEConsoleTextView") 178 | where self.isKindOfClass(expectedClass) else { 179 | return 180 | } 181 | guard let textStorage = self.textStorage else { 182 | return 183 | } 184 | if let startLocationOfLastLine = self.valueForKeyPath("_startLocationOfLastLine") as? Int 185 | where textStorage.length < startLocationOfLastLine { 186 | self.setValue(textStorage.length, forKeyPath: "_startLocationOfLastLine") 187 | } 188 | 189 | if let lastRemovableTextLocation = self.valueForKeyPath("_lastRemovableTextLocation") as? Int 190 | where textStorage.length < lastRemovableTextLocation { 191 | self.setValue(textStorage.length, forKeyPath: "_lastRemovableTextLocation") 192 | } 193 | } 194 | } 195 | 196 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLink/StarConsoleLink-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | 6 | 7 | #import "JRSwizzle.h" 8 | #import "LogColorKit.h" 9 | #import "StarFunctions.h" 10 | //#import "IDEConsoleTextView.h" -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/xcshareddata/StarConsoleLinkExample.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : { 5 | 6 | } 7 | }, 8 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 9 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : 0 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "ED8A9B23-49E3-454B-8058-94C4502E2310", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "df15618a-31c2-4806-83e1-cbe0fce2aea4" : "StarProject_XcodePlugins\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "StarConsoleLinkExample", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "OwnPlugins\/StarConsoleLink\/StarConsoleLinkExample\/StarConsoleLinkExample.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "http:\/\/code.taobao.org\/svn\/StarProject_XcodePlugins", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "df15618a-31c2-4806-83e1-cbe0fce2aea4" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iStarEternal/StarConsoleLink/f36cbc392b8fa3abbd936f6db80334a870f05e13/StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/project.xcworkspace/xcuserdata/Star.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/xcuserdata/Star.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/xcuserdata/Star.xcuserdatad/xcschemes/StarConsoleLinkExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample.xcodeproj/xcuserdata/Star.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | StarConsoleLinkExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | F8F23EFF1CD0EFE0002623E4 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample/OCLogger.h: -------------------------------------------------------------------------------- 1 | // 2 | // OCLogger.h 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface OCLogger : NSObject 12 | 13 | - (void)runLog; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample/OCLogger.m: -------------------------------------------------------------------------------- 1 | // 2 | // OCLogger.m 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/1/28. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | 10 | 11 | #import "OCLogger.h" 12 | #import "Logger.h" 13 | 14 | 15 | 16 | @interface OCLogger () 17 | 18 | @end 19 | 20 | @implementation OCLogger 21 | 22 | + (void)backTrace:(NSString *)bt arg1:(NSString *)arg1 arg2:(NSString *)agr2{ 23 | LogBackTrace(@"%@", bt); 24 | } 25 | 26 | 27 | - (void)POST:(NSString *)paramModal success:(NSInteger)success failure:(NSString *)failure { 28 | 29 | LogBackTrace(@"%@", @"你好"); 30 | } 31 | - (void)runLog { 32 | 33 | LogWarning(@"------------------ ObjectiveC Logger Test ------------------"); 34 | PrivateLog("0,0,0", "Hello", 0, @"你好:星星,%@", @"请不要使用PrivateLog"); 35 | NSLog(@"NSLog"); 36 | LogDebug(@"调试"); 37 | LogInfo(@"消息"); 38 | LogWarning(@"警告"); 39 | LogError(@"错误"); 40 | LogSuccess(@"成功"); 41 | LogFailure(@"失败"); 42 | LogBackTrace(@"堆栈信息"); 43 | 44 | 45 | LogWarning(@"%@", @{@"name": @"星星", @"age": @"18岁"}); 46 | 47 | [OCLogger backTrace:@"啦啦啦" arg1: @"" arg2: @""]; 48 | [self POST:@"" success:0 failure:@""]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample/StarConsoleLinkExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | //#import Logger.h 6 | #import "OCLogger.h" -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample/SwiftLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftLogger.swift 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/5/12. 6 | // Copyright © 2016年 星星. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class SwiftLogger: NSObject { 12 | 13 | func runLog() { 14 | Logger.info("当前在Swift中测试打印") 15 | Logger.info("测试打印不存在的文件链接:[viewController-abc.swift:25] ") 16 | Logger.info("测试打印URL链接:[192.168.8.250:8080]") 17 | Logger.info("测试打印不带方括号的链接:SwiftLogger.swift:19") 18 | Logger.info("测试打印行号超出的链接:[SwiftLogger.swift:100]") 19 | 20 | Logger.warning("------------------ Swift Logger Test ------------------") 21 | Logger.info("测试颜色打印") 22 | Logger.debug("测试颜色打印") 23 | Logger.warning("测试颜色打印") 24 | Logger.error("测试颜色打印") 25 | Logger.important("测试颜色打印") 26 | Logger.success("测试颜色打印") 27 | Logger.failure("测试颜色打印") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /StarConsoleLinkForXcode6-7/StarConsoleLinkExample/StarConsoleLinkExample/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // StarConsoleLinkExample 4 | // 5 | // Created by 星星 on 16/4/27. 6 | // Copyright © 2016年 AbsoluteStar. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | SwiftLogger().runLog() 13 | OCLogger().runLog() --------------------------------------------------------------------------------