├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── CommandLineKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── CommandLineKit.xcscheme │ └── CommandLineKitDemo.xcscheme ├── CommandLineKitDemo └── main.swift ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── CommandLineKit │ ├── AnsiCodes.swift │ ├── BackgroundColor.swift │ ├── Command.swift │ ├── CommandLineKit.h │ ├── ControlCharacters.swift │ ├── ConvertibleFromString.swift │ ├── EditState.swift │ ├── Flag.swift │ ├── FlagError.swift │ ├── FlagWrapper.swift │ ├── Flags.swift │ ├── Info.plist │ ├── LineReader.swift │ ├── LineReaderError.swift │ ├── LineReaderHistory.swift │ ├── Terminal.swift │ ├── TextColor.swift │ ├── TextProperties.swift │ └── TextStyle.swift └── CommandLineKitDemo │ ├── Info.plist │ ├── LinuxMain.swift │ └── main.swift └── Tests ├── CommandLineKitTests ├── AnsiCodesTests.swift ├── EditStateTests.swift ├── FlagTests.swift ├── Info.plist └── LineReaderHistoryTests.swift └── LinuxMain.swift /.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 | .build 36 | Packages 37 | 38 | # CocoaPods 39 | # 40 | # We recommend against adding the Pods directory to your .gitignore. However 41 | # you should judge for yourself, the pros and cons are mentioned at: 42 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 43 | # 44 | # Pods/ 45 | 46 | # Carthage 47 | # 48 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 49 | # Carthage/Checkouts 50 | 51 | Carthage/Build 52 | 53 | # macOS 54 | .DS_Store 55 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # 0.3.5 (2023-01-29) 4 | - Be more clever about detecting color terminals 5 | - Migrate project to Xcode 14.2 6 | 7 | ## 0.3.4 (2021-05-12) 8 | - Minor bug fixes 9 | - Migrated project to Xcode 12.5 10 | 11 | ## 0.3.3 (2020-10-04) 12 | - Ported code to Swift 5.3 13 | - Migrated project to Xcode 12.0 14 | 15 | ## 0.3.2 (2020-02-01) 16 | - Fixed line reader to handle buffered output 17 | - Migrated project to Xcode 11.3 18 | 19 | ## 0.3.1 (2019-09-23) 20 | - Migrated project to Xcode 11.0 21 | - Ported code to Swift 5.1 22 | 23 | ## 0.3 (2019-03-30) 24 | - Migrated library to Xcode 10.2 25 | - Ported code to Swift 5 26 | 27 | ## 0.2 (2018-06-10) 28 | - Bug fixes 29 | - Support of usage descriptions 30 | - Initial documentation 31 | 32 | ## 0.1 (2018-05-14) 33 | - Initial version 34 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). 29 | -------------------------------------------------------------------------------- /CommandLineKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CommandLineKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CommandLineKit.xcodeproj/xcshareddata/xcschemes/CommandLineKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 63 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /CommandLineKit.xcodeproj/xcshareddata/xcschemes/CommandLineKitDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 64 | 70 | 71 | 72 | 73 | 77 | 78 | 79 | 80 | 86 | 88 | 94 | 95 | 96 | 97 | 99 | 100 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /CommandLineKitDemo/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // CommandLineKitDemo 4 | // 5 | // Created by Matthias Zenger on 26/10/2023. 6 | // Copyright © 2023 Matthias Zenger. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | print("Hello, World!") 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2018-2019 Google LLC 2 | Copyright © 2017 Andy Best 3 | Copyright © 2010-2014 Salvatore Sanfilippo 4 | Copyright © 2010-2013 Pieter Noordhuis 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its contributors 17 | may be used to endorse or promote products derived from this software without 18 | specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.4 2 | // 3 | // Package.swift 4 | // CommandLineKit 5 | // 6 | // Build targets by calling the Swift Package Manager in the following way for debug purposes: 7 | // swift build 8 | // 9 | // A release can be built with these options: 10 | // swift build -c release 11 | // 12 | // Created by Matthias Zenger on 06/05/2017. 13 | // Copyright © 2018-2023 Google LLC 14 | // 15 | // Redistribution and use in source and binary forms, with or without 16 | // modification, are permitted provided that the following conditions are met: 17 | // 18 | // * Redistributions of source code must retain the above copyright notice, 19 | // this list of conditions and the following disclaimer. 20 | // 21 | // * Redistributions in binary form must reproduce the above copyright notice, 22 | // this list of conditions and the following disclaimer in the documentation 23 | // and/or other materials provided with the distribution. 24 | // 25 | // * Neither the name of the copyright holder nor the names of its contributors 26 | // may be used to endorse or promote products derived from this software without 27 | // specific prior written permission. 28 | // 29 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 33 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 36 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | // 40 | 41 | import PackageDescription 42 | 43 | let package = Package( 44 | name: "CommandLineKit", 45 | platforms: [ 46 | .macOS(.v11) 47 | ], 48 | products: [ 49 | .library(name: "CommandLineKit", targets: ["CommandLineKit"]), 50 | .executable(name: "CommandLineKitDemo", targets: ["CommandLineKitDemo"]) 51 | ], 52 | dependencies: [ 53 | ], 54 | targets: [ 55 | .target(name: "CommandLineKit", 56 | dependencies: [], 57 | exclude: ["Info.plist"]), 58 | .executableTarget(name: "CommandLineKitDemo", 59 | dependencies: ["CommandLineKit"], 60 | exclude: []), 61 | .testTarget(name: "CommandLineKitTests", 62 | dependencies: ["CommandLineKit"], 63 | exclude: ["Info.plist"]) 64 | ], 65 | swiftLanguageVersions: [.v5] 66 | ) 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift CommandLineKit 2 | 3 | [![Platform: macOS](https://img.shields.io/badge/Platform-macOS-blue.svg?style=flat)](https://developer.apple.com/osx/) 4 | [![Platform: Linux](https://img.shields.io/badge/Platform-Linux-blue.svg?style=flat)](https://www.ubuntu.com/) 5 | [![Language: Swift 5.8](https://img.shields.io/badge/Language-Swift%205.8-green.svg?style=flat)](https://developer.apple.com/swift/) 6 | [![IDE: Xcode 14](https://img.shields.io/badge/IDE-Xcode%2014-orange.svg?style=flat)](https://developer.apple.com/xcode/) 7 | [![Carthage: compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 8 | [![License: BSD](https://img.shields.io/badge/License-BSD-lightgrey.svg?style=flat)](https://developers.google.com/open-source/licenses/bsd) 9 | 10 | ## Overview 11 | 12 | This is a library supporting the development of command-line tools in 13 | the programming language Swift on macOS. It also compiles under Linux. 14 | The library provides the following functionality: 15 | 16 | - Management of command-line arguments, 17 | - Usage of escape sequences on terminals, and 18 | - Reading strings on terminals using a lineread-inspired implementation 19 | based on the library [Linenoise-Swift](https://github.com/andybest/linenoise-swift), 20 | but supporting unicode input, multiple lines, and styled text. 21 | 22 | ## Command-line arguments 23 | 24 | ### Basics 25 | 26 | CommandLineKit handles command-line arguments with the following protocol: 27 | 28 | 1. A new [Flags](https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/Flags.swift) 29 | object gets created either for the system-provided command-line arguments or for a 30 | custom sequence of arguments. 31 | 2. For every flag, a [Flag](https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/Flag.swift) 32 | object is being created and registered in the `Flags` object. 33 | 3. Once all flag objects are declared and registered, the command-line gets parsed. After parsing 34 | is complete, the flag objects can be used to access the extracted options and arguments. 35 | 36 | CommandLineKit defines different types of 37 | [Flag](https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/Flag.swift) 38 | subclasses for handling _options_ (i.e. flags without 39 | parameters) and _arguments_ (i.e. flags with parameters). Arguments are either _singleton arguments_ (i.e. they 40 | have exactly one value) or they are _repeated arguments_ (i.e. they have many values). Arguments are 41 | parameterized with a type which defines how to parse values. The framework natively supports _int_, 42 | _double_, _string_, and _enum_ types, which means that in practice, just using the built-in flag classes 43 | are almost always sufficient. Nevertheless, 44 | [the framework is extensible](https://github.com/objecthub/swift-commandlinekit/tree/master/Sources/CommandLineKit) 45 | and supports arbitrary argument types. 46 | 47 | A flag is identified by a _short name_ character and a _long name_ string. At least one of the two needs to be 48 | defined. For instance, the "help" option could be defined by the short name "h" and the long name "help". 49 | On the command-line, a user could either use `-h` or `--help` to refer to this option; i.e. short names are 50 | prefixed with a single dash, long names are prefixed with a double dash. 51 | 52 | An argument is a parameterized flag. The parameters follow directly the flag identifier (typically separated by 53 | a space). For instance, an integer argument with long name "size" could be defined as: `--size 64`. If the 54 | argument is repeated, then multiple parameters may follow the flag identifier, as in this 55 | example: `--size 2 4 8 16`. The sequence is terminated by either the end of the command-line arguments, 56 | another flag, or the terminator "---". All command-line arguments following the terminator are not being parsed 57 | and are returned in the `parameters` field of the `Flags` object. 58 | 59 | ### Programmatic API 60 | 61 | Here is an [example](https://github.com/objecthub/swift-lispkit/blob/master/Sources/LispKitRepl/main.swift) 62 | from the [LispKit](https://github.com/objecthub/swift-lispkit) project. It uses factory methods (like `flags.string`, 63 | `flags.int`, `flags.option`, `flags.strings`, etc.) provided by the 64 | [Flags](https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/Flags.swift) 65 | class to create and register individual flags. 66 | 67 | ```swift 68 | // Create a new flags object for the system-provided command-line arguments 69 | var flags = Flags() 70 | 71 | // Define the various flags 72 | let filePaths = flags.strings("f", "filepath", 73 | description: "Adds file path in which programs are searched for.") 74 | let libPaths = flags.strings("l", "libpath", 75 | description: "Adds file path in which libraries are searched for.") 76 | let heapSize = flags.int("x", "heapsize", 77 | description: "Initial capacity of the heap", value: 1000) 78 | let importLibs = flags.strings("i", "import", 79 | description: "Imports library automatically after startup.") 80 | let prelude = flags.string("p", "prelude", 81 | description: "Path to prelude file which gets executed after " + 82 | "loading all provided libraries.") 83 | let prompt = flags.string("r", "prompt", 84 | description: "String used as prompt in REPL.", value: "> ") 85 | let quiet = flags.option("q", "quiet", 86 | description: "In quiet mode, optional messages are not printed.") 87 | let help = flags.option("h", "help", 88 | description: "Show description of usage and options of this tools.") 89 | 90 | // Parse the command-line arguments and return error message if parsing fails 91 | if let failure = flags.parsingFailure() { 92 | print(failure) 93 | exit(1) 94 | } 95 | ``` 96 | 97 | The framework supports printing the supported options via the `Flags.usageDescription` function. For the 98 | command-line flags as defined above, this function returns the following usage description: 99 | 100 | ``` 101 | usage: LispKitRepl [