├── .gitignore ├── LICENSE ├── README.md ├── bin └── zipline ├── screenshot.png ├── zipline.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── zipline └── main.swift └── zl.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zipline 2 | 3 | Mac OS X CLI utility I wrote to deal with the annoyance of never knowing how many times I have to type ```..``` to ```cd``` to a certain directory. 4 | 5 | This utility should really be a bash script but then I'd have to write Bash and neither of us wants that, do we. 6 | 7 | ## Installation 8 | 9 | Put the binary from ```/bin``` in your path and add the contents of ```zl.sh``` to your rc file. 10 | 11 | 12 | ![screenshot](https://raw.github.com/adamnemecek/zipline/master/screenshot.png) 13 | 14 | -------------------------------------------------------------------------------- /bin/zipline: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamnemecek/zipline/89801c98270185e8fabfa6715b6e21a76d04e889/bin/zipline -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamnemecek/zipline/89801c98270185e8fabfa6715b6e21a76d04e889/screenshot.png -------------------------------------------------------------------------------- /zipline.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 37D3F95E1CF2824E006E26E7 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C3A1351CED5469007679C8 /* main.swift */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 37C3A1301CED5469007679C8 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = /usr/share/man/man1/; 18 | dstSubfolderSpec = 0; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 1; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 37C3A1321CED5469007679C8 /* zipline */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zipline; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 37C3A1351CED5469007679C8 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 37C3A12F1CED5469007679C8 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 37C3A1291CED5469007679C8 = { 42 | isa = PBXGroup; 43 | children = ( 44 | 37C3A1341CED5469007679C8 /* zipline */, 45 | 37C3A1331CED5469007679C8 /* Products */, 46 | ); 47 | sourceTree = ""; 48 | }; 49 | 37C3A1331CED5469007679C8 /* Products */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 37C3A1321CED5469007679C8 /* zipline */, 53 | ); 54 | name = Products; 55 | sourceTree = ""; 56 | }; 57 | 37C3A1341CED5469007679C8 /* zipline */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 37C3A1351CED5469007679C8 /* main.swift */, 61 | ); 62 | name = zipline; 63 | path = ZipLine; 64 | sourceTree = ""; 65 | }; 66 | /* End PBXGroup section */ 67 | 68 | /* Begin PBXNativeTarget section */ 69 | 37C3A1311CED5469007679C8 /* zipline */ = { 70 | isa = PBXNativeTarget; 71 | buildConfigurationList = 37C3A1391CED5469007679C8 /* Build configuration list for PBXNativeTarget "zipline" */; 72 | buildPhases = ( 73 | 37C3A12E1CED5469007679C8 /* Sources */, 74 | 37C3A12F1CED5469007679C8 /* Frameworks */, 75 | 37C3A1301CED5469007679C8 /* CopyFiles */, 76 | ); 77 | buildRules = ( 78 | ); 79 | dependencies = ( 80 | ); 81 | name = zipline; 82 | productName = ZipLine; 83 | productReference = 37C3A1321CED5469007679C8 /* zipline */; 84 | productType = "com.apple.product-type.tool"; 85 | }; 86 | /* End PBXNativeTarget section */ 87 | 88 | /* Begin PBXProject section */ 89 | 37C3A12A1CED5469007679C8 /* Project object */ = { 90 | isa = PBXProject; 91 | attributes = { 92 | LastSwiftUpdateCheck = 0730; 93 | LastUpgradeCheck = 0730; 94 | ORGANIZATIONNAME = "Adam Nemecek"; 95 | TargetAttributes = { 96 | 37C3A1311CED5469007679C8 = { 97 | CreatedOnToolsVersion = 7.3.1; 98 | }; 99 | }; 100 | }; 101 | buildConfigurationList = 37C3A12D1CED5469007679C8 /* Build configuration list for PBXProject "zipline" */; 102 | compatibilityVersion = "Xcode 3.2"; 103 | developmentRegion = English; 104 | hasScannedForEncodings = 0; 105 | knownRegions = ( 106 | en, 107 | ); 108 | mainGroup = 37C3A1291CED5469007679C8; 109 | productRefGroup = 37C3A1331CED5469007679C8 /* Products */; 110 | projectDirPath = ""; 111 | projectRoot = ""; 112 | targets = ( 113 | 37C3A1311CED5469007679C8 /* zipline */, 114 | ); 115 | }; 116 | /* End PBXProject section */ 117 | 118 | /* Begin PBXSourcesBuildPhase section */ 119 | 37C3A12E1CED5469007679C8 /* Sources */ = { 120 | isa = PBXSourcesBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | 37D3F95E1CF2824E006E26E7 /* main.swift in Sources */, 124 | ); 125 | runOnlyForDeploymentPostprocessing = 0; 126 | }; 127 | /* End PBXSourcesBuildPhase section */ 128 | 129 | /* Begin XCBuildConfiguration section */ 130 | 37C3A1371CED5469007679C8 /* Debug */ = { 131 | isa = XCBuildConfiguration; 132 | buildSettings = { 133 | ALWAYS_SEARCH_USER_PATHS = NO; 134 | CLANG_ANALYZER_NONNULL = YES; 135 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 136 | CLANG_CXX_LIBRARY = "libc++"; 137 | CLANG_ENABLE_MODULES = YES; 138 | CLANG_ENABLE_OBJC_ARC = YES; 139 | CLANG_WARN_BOOL_CONVERSION = YES; 140 | CLANG_WARN_CONSTANT_CONVERSION = YES; 141 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 142 | CLANG_WARN_EMPTY_BODY = YES; 143 | CLANG_WARN_ENUM_CONVERSION = YES; 144 | CLANG_WARN_INT_CONVERSION = YES; 145 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 146 | CLANG_WARN_UNREACHABLE_CODE = YES; 147 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 148 | CODE_SIGN_IDENTITY = "-"; 149 | COPY_PHASE_STRIP = NO; 150 | DEBUG_INFORMATION_FORMAT = dwarf; 151 | ENABLE_STRICT_OBJC_MSGSEND = YES; 152 | ENABLE_TESTABILITY = YES; 153 | GCC_C_LANGUAGE_STANDARD = gnu99; 154 | GCC_DYNAMIC_NO_PIC = NO; 155 | GCC_NO_COMMON_BLOCKS = YES; 156 | GCC_OPTIMIZATION_LEVEL = 0; 157 | GCC_PREPROCESSOR_DEFINITIONS = ( 158 | "DEBUG=1", 159 | "$(inherited)", 160 | ); 161 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 162 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 163 | GCC_WARN_UNDECLARED_SELECTOR = YES; 164 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 165 | GCC_WARN_UNUSED_FUNCTION = YES; 166 | GCC_WARN_UNUSED_VARIABLE = YES; 167 | MACOSX_DEPLOYMENT_TARGET = 10.11; 168 | MTL_ENABLE_DEBUG_INFO = YES; 169 | ONLY_ACTIVE_ARCH = YES; 170 | SDKROOT = macosx; 171 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 172 | }; 173 | name = Debug; 174 | }; 175 | 37C3A1381CED5469007679C8 /* Release */ = { 176 | isa = XCBuildConfiguration; 177 | buildSettings = { 178 | ALWAYS_SEARCH_USER_PATHS = NO; 179 | CLANG_ANALYZER_NONNULL = YES; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_WARN_BOOL_CONVERSION = YES; 185 | CLANG_WARN_CONSTANT_CONVERSION = YES; 186 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 187 | CLANG_WARN_EMPTY_BODY = YES; 188 | CLANG_WARN_ENUM_CONVERSION = YES; 189 | CLANG_WARN_INT_CONVERSION = YES; 190 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 191 | CLANG_WARN_UNREACHABLE_CODE = YES; 192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 193 | CODE_SIGN_IDENTITY = "-"; 194 | COPY_PHASE_STRIP = NO; 195 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 196 | ENABLE_NS_ASSERTIONS = NO; 197 | ENABLE_STRICT_OBJC_MSGSEND = YES; 198 | GCC_C_LANGUAGE_STANDARD = gnu99; 199 | GCC_NO_COMMON_BLOCKS = YES; 200 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 201 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 202 | GCC_WARN_UNDECLARED_SELECTOR = YES; 203 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 204 | GCC_WARN_UNUSED_FUNCTION = YES; 205 | GCC_WARN_UNUSED_VARIABLE = YES; 206 | MACOSX_DEPLOYMENT_TARGET = 10.11; 207 | MTL_ENABLE_DEBUG_INFO = NO; 208 | SDKROOT = macosx; 209 | }; 210 | name = Release; 211 | }; 212 | 37C3A13A1CED5469007679C8 /* Debug */ = { 213 | isa = XCBuildConfiguration; 214 | buildSettings = { 215 | PRODUCT_NAME = zipline; 216 | }; 217 | name = Debug; 218 | }; 219 | 37C3A13B1CED5469007679C8 /* Release */ = { 220 | isa = XCBuildConfiguration; 221 | buildSettings = { 222 | PRODUCT_NAME = zipline; 223 | }; 224 | name = Release; 225 | }; 226 | /* End XCBuildConfiguration section */ 227 | 228 | /* Begin XCConfigurationList section */ 229 | 37C3A12D1CED5469007679C8 /* Build configuration list for PBXProject "zipline" */ = { 230 | isa = XCConfigurationList; 231 | buildConfigurations = ( 232 | 37C3A1371CED5469007679C8 /* Debug */, 233 | 37C3A1381CED5469007679C8 /* Release */, 234 | ); 235 | defaultConfigurationIsVisible = 0; 236 | defaultConfigurationName = Release; 237 | }; 238 | 37C3A1391CED5469007679C8 /* Build configuration list for PBXNativeTarget "zipline" */ = { 239 | isa = XCConfigurationList; 240 | buildConfigurations = ( 241 | 37C3A13A1CED5469007679C8 /* Debug */, 242 | 37C3A13B1CED5469007679C8 /* Release */, 243 | ); 244 | defaultConfigurationIsVisible = 0; 245 | defaultConfigurationName = Release; 246 | }; 247 | /* End XCConfigurationList section */ 248 | }; 249 | rootObject = 37C3A12A1CED5469007679C8 /* Project object */; 250 | } 251 | -------------------------------------------------------------------------------- /zipline.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /zipline/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // zipline 4 | // 5 | // Created by Adam Nemecek on 5/18/16. 6 | // Copyright © 2016 Adam Nemecek. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | func printErr(string: String, newLine: Bool = true) { 12 | if newLine { 13 | fputs(string + "\n", stderr) 14 | } 15 | else { 16 | fputs(string, stderr) 17 | } 18 | } 19 | 20 | func *(string: String, factor: Int) -> String { 21 | return [String](count: factor, repeatedValue: string).reduce("", combine: +) 22 | } 23 | 24 | extension String { 25 | func trim() -> String { 26 | return stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) 27 | .stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()) 28 | } 29 | } 30 | 31 | extension NSFileManager { 32 | static var pwd: String { 33 | return defaultManager().currentDirectoryPath 34 | } 35 | 36 | static func dirExistsAtPath(path: String) -> Bool { 37 | var directory: ObjCBool = ObjCBool(false) 38 | return defaultManager().fileExistsAtPath(path, isDirectory: &directory) && directory 39 | } 40 | 41 | static func gitAtPath(path: String) -> Bool { 42 | let p = NSString.pathWithComponents([path, ".git"]) 43 | return dirExistsAtPath(p) 44 | } 45 | } 46 | 47 | struct ZipLine: CollectionType { 48 | let components: [String] 49 | 50 | init(path: String? = nil) { 51 | let p = path ?? NSFileManager.pwd 52 | self.components = (p as NSString).pathComponents 53 | } 54 | 55 | var startIndex: Int { 56 | return 0 57 | } 58 | 59 | var endIndex: Int { 60 | return components.endIndex 61 | } 62 | 63 | var lastIndex: Int { 64 | return endIndex - 1 65 | } 66 | 67 | subscript (idx: Int) -> String { 68 | return components[idx] 69 | } 70 | 71 | subscript (bounds: Range) -> String { 72 | let pathComponents = [String](components[bounds]) 73 | 74 | return NSString.pathWithComponents(pathComponents) as String 75 | } 76 | 77 | func segments() -> [(Int, String, Bool)] { 78 | return enumerate().map { (lastIndex - $0, $1, NSFileManager.gitAtPath($1)) } 79 | } 80 | 81 | func displayPaths() { 82 | for (idx, (choice, path, git)) in segments().enumerate() { 83 | let spaceString = " " * idx 84 | var s = "\(spaceString) \(choice): \(path)" 85 | if git { 86 | s += " (git)" 87 | } 88 | printErr(s) 89 | } 90 | } 91 | 92 | func getLevel() -> Int? { 93 | printErr("Zipline to [\(startIndex)-\(lastIndex)]: ", newLine: false) 94 | 95 | let i = readLine(stripNewline: true)?.trim() 96 | if let i = i, input = Int(i) where indices.contains(input) { 97 | return lastIndex - input 98 | } 99 | 100 | printErr("The input should be between [\(startIndex)-\(lastIndex)]") 101 | return nil 102 | } 103 | 104 | func promptUser() -> Int? { 105 | printErr("Which directory do you want to zipline to?") 106 | displayPaths() 107 | while true { 108 | if let choice = getLevel() { 109 | return choice 110 | } 111 | } 112 | } 113 | } 114 | 115 | func zipLine() { 116 | let z = ZipLine(path: nil) 117 | if let input = z.promptUser() { 118 | let path = z[0...input] 119 | print(path) 120 | } 121 | } 122 | 123 | zipLine() 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /zl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function zl { 4 | cd "${zipline}" 5 | } 6 | --------------------------------------------------------------------------------