mirror of
https://github.com/nsomar/Swiftline.git
synced 2024-09-11 05:35:42 +03:00
Adding documentation on the public methods
This commit is contained in:
parent
0398426282
commit
c642a4cf07
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[submodule "Nimble"]
|
||||||
|
path = Nimble
|
||||||
|
url = https://github.com/Quick/Nimble.git
|
||||||
|
[submodule "Quick"]
|
||||||
|
path = Quick
|
||||||
|
url = https://github.com/Quick/Quick.git
|
12
.travis.yml
Normal file
12
.travis.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
sudo: false
|
||||||
|
language: objective-c
|
||||||
|
osx_image: xcode7.1
|
||||||
|
|
||||||
|
install:
|
||||||
|
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
|
||||||
|
|
||||||
|
script:
|
||||||
|
- xctool -project Swiftline.xcodeproj -scheme Swiftline build test -sdk macosx GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
1
Nimble
Submodule
1
Nimble
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 13d4a2bca41d41e53b1c9681bc2039e5f5bca5fe
|
13
Podfile
13
Podfile
@ -1,13 +0,0 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
|
||||||
# platform :ios, '8.0'
|
|
||||||
# Uncomment this line if you're using Swift
|
|
||||||
use_frameworks!
|
|
||||||
|
|
||||||
target 'swiftline' do
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
target 'tests' do
|
|
||||||
pod 'Quick', '~> 0.8.0'
|
|
||||||
pod 'Nimble', '~> 3.0.0'
|
|
||||||
end
|
|
13
Podfile.lock
13
Podfile.lock
@ -1,13 +0,0 @@
|
|||||||
PODS:
|
|
||||||
- Nimble (3.0.0)
|
|
||||||
- Quick (0.8.0)
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
|
||||||
- Nimble (~> 3.0.0)
|
|
||||||
- Quick (~> 0.8.0)
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
|
||||||
Nimble: 4c353d43735b38b545cbb4cb91504588eb5de926
|
|
||||||
Quick: 563d0f6ec5f72e394645adb377708639b7dd38ab
|
|
||||||
|
|
||||||
COCOAPODS: 0.39.0
|
|
1
Quick
Submodule
1
Quick
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit a98f8e37867462c8f00fea1a7b255d12f5a4b611
|
231
Readme.md
231
Readme.md
@ -1,10 +1,235 @@
|
|||||||
# Swiftline
|
# Swiftline
|
||||||
Easier to do command line with swift
|
|
||||||
|
|
||||||
## 🏃
|
[![Build Status](https://travis-ci.org/oarrabi/swiftline.svg?branch=master)](https://travis-ci.org/oarrabi/swiftline)
|
||||||
|
|
||||||
## Ask, Choose, Agree
|
Swiftline is a set of tools to help you create command line applications. Swiftline is inspired by [highline](https://github.com/JEG2/highline)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Swiftline can be divided to three main parts:
|
||||||
|
|
||||||
|
- Colorize; Helps adding colors to strings written to the terminal
|
||||||
|
- Ask, Choose and agree; Easily create prompt for asking the user more info
|
||||||
|
- Runner; A quick way to run an external command and read its standard output and standard error.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
## Colorize
|
## Colorize
|
||||||
|
Colorize helps styling the strings before printing them to the terminal. You can change the text color, the text background and the text style.
|
||||||
|
Colorize works by extending `String` struct to add styling to it.
|
||||||
|
|
||||||
|
To change the text color, use either `string.f` or `string.foreground`:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
print("Red String".f.Red)
|
||||||
|
print("Blue String".foreground.Blue)
|
||||||
|
```
|
||||||
|
|
||||||
|
To change the text background color, use either `string.b` or `string.background`:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
print("I have a white background".b.White)
|
||||||
|
print("My background color is green".background.Green)
|
||||||
|
```
|
||||||
|
|
||||||
|
To change the text background color, use either `string.s` or `string.style`:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
print("I am a bold string".s.Bold)
|
||||||
|
print("I have an underline".style.Underline)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can compose foreground, background, and style:
|
||||||
|
```swift
|
||||||
|
print("I am an underlined red on white string".s.Underline.f.Red.b.White)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ask, Choose, Agree
|
||||||
|
Ask, Choose and Agree are used to prompt the user for more information.
|
||||||
|
|
||||||
|
### Ask
|
||||||
|
Ask presents the user with a prompt and waits for the user input.
|
||||||
|
```swift
|
||||||
|
let userName = ask("Enter user name?")
|
||||||
|
```
|
||||||
|
`userName` will contain the name entered by the user
|
||||||
|
|
||||||
|
Ask can be used to ask for value of Int, Double or Float types, to ask for an integer for example:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let age = ask("How old are you?", type: Int.self)
|
||||||
|
```
|
||||||
|
If the user prints something thats not convertible to integer, a new prompt is displayed to him, this prompt will keep displaying until the user enters an Int:
|
||||||
|
|
||||||
|
How old are you?
|
||||||
|
None
|
||||||
|
You must enter a valid Integer.
|
||||||
|
? Error
|
||||||
|
You must enter a valid Integer.
|
||||||
|
? 5
|
||||||
|
5
|
||||||
|
|
||||||
|
Validations are added by calling `addInvalidCase` on `AskSettings`.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let name = ask("Who are you?") { settings in
|
||||||
|
settings.addInvalidCase("Snuffles is not allowed") { value in
|
||||||
|
value.containsString("Snuffles")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
If the user entered `Snuffles` ask will keep displaying the invalid message passed to `addInvalidCase`
|
||||||
|
|
||||||
|
Who are you?
|
||||||
|
Snuffles
|
||||||
|
Snuffles is not allowed
|
||||||
|
? Snuffles
|
||||||
|
Snuffles is not allowed
|
||||||
|
? Snowball
|
||||||
|
|
||||||
|
Your name is Snowball
|
||||||
|
|
||||||
|
`AskSettings.confirm` will ask the user to confirm his choice after entering it
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let name = ask("Who are you?") { settings in
|
||||||
|
settings.confirm = true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The above will output:
|
||||||
|
|
||||||
|
Who are you?
|
||||||
|
Snuffles
|
||||||
|
Are you sure? YES
|
||||||
|
|
||||||
|
Your name is Snuffles
|
||||||
|
### Choose
|
||||||
|
Choose is used to prompt the user to select an item between several possible items.
|
||||||
|
|
||||||
|
To display a choice of programming lanaugage for example:
|
||||||
|
```swift
|
||||||
|
let choice = choose("Whats your favorite programming language? ",
|
||||||
|
choices: "Swift", "Objective C", "Ruby", "Python", "Java :S")
|
||||||
|
```
|
||||||
|
|
||||||
|
This will print:
|
||||||
|
|
||||||
|
1. Swift
|
||||||
|
2. Objective C
|
||||||
|
3. Ruby
|
||||||
|
4. Python
|
||||||
|
5. Java :S
|
||||||
|
Whats your favorite programming language?
|
||||||
|
|
||||||
|
The user can either choose the numbers (1..5) or the item itself. If the user enters a wrong input. A prompt will keep showing until the user makes a correct choice
|
||||||
|
|
||||||
|
Whats your favorite programming language? JavaScript
|
||||||
|
You must choose one of [1, 2, 3, 4, 5, Swift, Objective C, Ruby, Python, Java :S].
|
||||||
|
? BBB
|
||||||
|
You must choose one of [1, 2, 3, 4, 5, Swift, Objective C, Ruby, Python, Java :S].
|
||||||
|
? Swift
|
||||||
|
|
||||||
|
You selected Swift, good choice!
|
||||||
|
|
||||||
|
You can customize the return value for each choice element. For example if you want to get an Int from the choice, you would do this
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let choice = choose("Whats your favorite programming language? ", type: Int.self) { settings in
|
||||||
|
settings.addChoice("Swift") { 42 }
|
||||||
|
settings.addChoice("Objective C") { 20 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The number on the left can be changed to letters, here is how you could do that:
|
||||||
|
|
||||||
|
```siwft
|
||||||
|
let choice = choose("Whats your favorite programming language? ", type: String.self) { settings in
|
||||||
|
//choice value will be set to GOOD
|
||||||
|
settings.addChoice("Swift") { "GOOD" }
|
||||||
|
|
||||||
|
//choice value will be set to BAD
|
||||||
|
settings.addChoice("Java") { "BAD" }
|
||||||
|
|
||||||
|
settings.index = .Letters
|
||||||
|
settings.indexSuffix = " ----> "
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That will print:
|
||||||
|
|
||||||
|
a ----> Swift
|
||||||
|
b ----> Java
|
||||||
|
Whats your favorite programming language?
|
||||||
|
|
||||||
|
### Agree
|
||||||
|
Agree is used to ask a user for a Yes/No question. It returns a boolean representing the user input.
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let choice = agree("Are you sure you want to `rm -rf /` ?")
|
||||||
|
```
|
||||||
|
|
||||||
|
If the user enters any invalid input, agree will keep prompting him for a Yes/No question
|
||||||
|
|
||||||
|
Are you sure you want to `rm -rf /` ? What!
|
||||||
|
Please enter "yes" or "no".
|
||||||
|
Are you sure you want to `rm -rf /` ? Wait
|
||||||
|
Please enter "yes" or "no".
|
||||||
|
Are you sure you want to `rm -rf /` ? No
|
||||||
|
|
||||||
|
You entered false
|
||||||
|
|
||||||
|
## Runner
|
||||||
|
Runner provides a quick, concise way to run an external command and read its standard output and standard error.
|
||||||
|
|
||||||
|
To execute a simple command you would do:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let result = run("ls -all")
|
||||||
|
print(result.stdout)
|
||||||
|
```
|
||||||
|
`result` type is `RunResults`, it contains:
|
||||||
|
|
||||||
|
- `exitStatus`: The command exit status
|
||||||
|
- `stdout`: The standard output for the command executed
|
||||||
|
- `stderr`: The standard error for the command executed
|
||||||
|
|
||||||
|
While `run("command")` can split the arguments by spaces. Some times argument splitting is not trivial. If you have multiple argument to pass to the command to execute, you should use `run(command: String, args: String...)`. The above translates to:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let result = run("ls", args: "-all")
|
||||||
|
```
|
||||||
|
|
||||||
|
To costumize the run function, you can pass in a customization block:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
let result = run("ls -all") { settings in
|
||||||
|
settings.dryRun = true
|
||||||
|
settings.echo = [.Stdout, .Stderr, .Command]
|
||||||
|
settings.interactive = false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`settings` is an instance of RunSettings, which contains the following variables:
|
||||||
|
|
||||||
|
- `settings.dryRun`: defaults to false. If false, the command is actually run. If true, the command is logged to the stdout paramter of result
|
||||||
|
- `settings.echo`: Customize the message printed to stdout, `echo` can contain any of the following:
|
||||||
|
- `EchoSettings.Stdout`: The stdout returned from running the command will be printed to the terminal
|
||||||
|
- `EchoSettings.Stderr`: The stderr returned from running the command will be printed to the terminal
|
||||||
|
- `EchoSettings.Command`: The command executed will be printed to the terminal
|
||||||
|
- `settings.interactive`: defaults to false. If set to true the command will be executed using `system` kernel function and only the exit status will be captured. If set to false, the command will be executed using `NSTask` and both stdout and stderr will be captured.
|
||||||
|
Set `interactive` to true if you expect the launched command to ask input from the user through the stdin.
|
||||||
|
|
||||||
|
`runWithoutCapture("command")` is a quick way to run a command in interactive mode. The return value is the exit code of that command.
|
||||||
|
|
||||||
|
### Improvement
|
||||||
|
- Better documentation
|
||||||
|
- Add gather (from [highline](https://github.com/JEG2/highline)) to ask function
|
||||||
|
- Figure out a way to eliminate the need of `interactive`
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
Tests can be found [here](). They can be normally run from the Xcode
|
||||||
|
.
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
//
|
|
||||||
// main.swift
|
|
||||||
// swiftline
|
|
||||||
//
|
|
||||||
// Created by Omar Abdelhafith on 10/11/2015.
|
|
||||||
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
let choice = choose("Choose the best programming language? ", choices: "Swift", "Objective", "Ruby", "Python", "Java :S")
|
|
||||||
print("\nYou choosed " + choice.f.Green)
|
|
@ -1,55 +0,0 @@
|
|||||||
//
|
|
||||||
// Chooser.swift
|
|
||||||
// Choose
|
|
||||||
//
|
|
||||||
// Created by Omar Abdelhafith on 03/11/2015.
|
|
||||||
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
func choose(prompt: String, choices: String...) -> String {
|
|
||||||
return choose(prompt, type: String.self) {
|
|
||||||
for choice in choices {
|
|
||||||
$0.addChoice(choice) { return choice }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func choose<T>(callback: (ChooseSettings<T> -> Void)) -> T {
|
|
||||||
|
|
||||||
let settings = getChooseSettings(callback)
|
|
||||||
return choose(settings, type: T.self)
|
|
||||||
}
|
|
||||||
|
|
||||||
func choose<T>(prompt: String, type: T.Type, callback: (ChooseSettings<T> -> Void)) -> T {
|
|
||||||
|
|
||||||
let settings = getChooseSettings(callback)
|
|
||||||
settings.promptQuestion = prompt
|
|
||||||
return choose(settings, type: type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func choose<T>(type: T.Type, callback: (ChooseSettings<T> -> Void)) -> T {
|
|
||||||
|
|
||||||
let settings = getChooseSettings(callback)
|
|
||||||
return choose(settings, type: type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func choose<T>(settings: ChooseSettings<T>, type: T.Type) -> T {
|
|
||||||
|
|
||||||
let items = settings.preparePromptItems()
|
|
||||||
|
|
||||||
items.forEach { PromptSettings.print($0) }
|
|
||||||
PromptSettings.print("\(settings.promptQuestion)", terminator: "")
|
|
||||||
|
|
||||||
let stringRead = readStringOrEmpty()
|
|
||||||
|
|
||||||
return askForValidatedItem(originalValue: stringRead, validator: settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getChooseSettings<T>(callback: ChooseSettings<T> -> Void) -> ChooseSettings<T> {
|
|
||||||
let settings = ChooseSettings<T>()
|
|
||||||
callback(settings)
|
|
||||||
return settings
|
|
||||||
}
|
|
28
SwiftLine/Info.plist
Normal file
28
SwiftLine/Info.plist
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>Copyright © 2015 Omar Abdelhafith. All rights reserved.</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -1,48 +0,0 @@
|
|||||||
//
|
|
||||||
// ArgConvertible.swift
|
|
||||||
// ArgConvertible
|
|
||||||
//
|
|
||||||
// Created by Omar Abdelhafith on 02/11/2015.
|
|
||||||
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
protocol ArgConvertibleType {
|
|
||||||
static func fromString(string: String) -> Self?
|
|
||||||
static func typeName() -> String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extension Int: ArgConvertibleType {
|
|
||||||
static func fromString(string: String) -> Int? {
|
|
||||||
return Int(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func typeName() -> String {
|
|
||||||
return "Integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extension Double: ArgConvertibleType {
|
|
||||||
static func fromString(string: String) -> Double? {
|
|
||||||
return Double(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func typeName() -> String {
|
|
||||||
return "Double"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
extension String: ArgConvertibleType {
|
|
||||||
static func fromString(string: String) -> String? {
|
|
||||||
return string
|
|
||||||
}
|
|
||||||
|
|
||||||
static func typeName() -> String {
|
|
||||||
return "String"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
//
|
|
||||||
// RunSettings.swift
|
|
||||||
// RunSettings
|
|
||||||
//
|
|
||||||
// Created by Omar Abdelhafith on 05/11/2015.
|
|
||||||
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
class RunSettings {
|
|
||||||
var dryRun = false
|
|
||||||
var echo = EchoSettings.None
|
|
||||||
var interactive = false
|
|
||||||
}
|
|
||||||
|
|
||||||
struct EchoSettings: OptionSetType {
|
|
||||||
let rawValue: Int
|
|
||||||
|
|
||||||
static var None = EchoSettings(rawValue: 0)
|
|
||||||
static let Stdout = EchoSettings(rawValue: 1 << 0)
|
|
||||||
static let Stderr = EchoSettings(rawValue: 1 << 1)
|
|
||||||
static let Command = EchoSettings(rawValue: 1 << 2)
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// ShortHandRunner.swift
|
|
||||||
// ShortHandRunner
|
|
||||||
|
|
||||||
//
|
|
||||||
// Created by Omar Abdelhafith on 05/11/2015.
|
|
||||||
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
func runWithoutCapture(command: String) -> Int {
|
|
||||||
return 🏃.runWithoutCapture(command)
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(command: String, args: String...) -> RunResults {
|
|
||||||
return 🏃.run(command, args: args as [String])
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(command: String, args: [String]) -> RunResults {
|
|
||||||
return 🏃.run(command, args: args as [String])
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(command: String, settings: (RunSettings -> Void)) -> RunResults {
|
|
||||||
return 🏃.run(command, settings: settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(command: String, args: [String], settings: (RunSettings -> Void)) -> RunResults {
|
|
||||||
return 🏃.run(command, args: args, settings: settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
func run(command: String, echo: EchoSettings) -> RunResults {
|
|
||||||
return 🏃.run(command, echo: echo)
|
|
||||||
}
|
|
19
SwiftLine/Swiftline.h
Normal file
19
SwiftLine/Swiftline.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Swiftline.h
|
||||||
|
// Swiftline
|
||||||
|
//
|
||||||
|
// Created by Omar Abdelhafith on 11/11/2015.
|
||||||
|
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
//! Project version number for Swiftline.
|
||||||
|
FOUNDATION_EXPORT double SwiftlineVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for Swiftline.
|
||||||
|
FOUNDATION_EXPORT const unsigned char SwiftlineVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <Swiftline/PublicHeader.h>
|
||||||
|
|
||||||
|
|
@ -8,7 +8,13 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
func agree(prompt: String) -> Bool {
|
/**
|
||||||
|
Displays a yes/no prompt to the user
|
||||||
|
|
||||||
|
- parameter prompt: The prompt to display
|
||||||
|
- returns: the user decision
|
||||||
|
*/
|
||||||
|
public func agree(prompt: String) -> Bool {
|
||||||
PromptSettings.print(prompt, terminator: " ")
|
PromptSettings.print(prompt, terminator: " ")
|
||||||
let value = readStringOrEmpty()
|
let value = readStringOrEmpty()
|
||||||
|
|
@ -9,16 +9,34 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
func ask(prompt: String, callback: (AskSettings<String> -> Void)? = nil) -> String {
|
/**
|
||||||
return ask(prompt, type: String.self, callback: callback)
|
Display a promt to the user
|
||||||
|
|
||||||
|
- parameter prompt: The message to display
|
||||||
|
- parameter customizationBlock: The block to costumize the prompt before displaying
|
||||||
|
|
||||||
|
- returns: The string enters from the user
|
||||||
|
*/
|
||||||
|
public func ask(prompt: String, customizationBlock: (AskSettings<String> -> Void)? = nil) -> String {
|
||||||
|
return ask(prompt, type: String.self, customizationBlock: customizationBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ask<T: ArgConvertibleType>(prompt: String, type: T.Type, callback: (AskSettings<T> -> Void)? = nil) -> T {
|
|
||||||
|
/**
|
||||||
|
Display a promt to the user
|
||||||
|
|
||||||
|
- parameter prompt:The message to display
|
||||||
|
- parameter type: The value type to be expected from the user
|
||||||
|
- parameter customizationBlock: The block to costumize the prompt before displaying
|
||||||
|
|
||||||
|
- returns: The string casted to the type requested
|
||||||
|
- discussion: If the user enters a wrong type, ask will keep prompting until a correct value has been entered
|
||||||
|
*/
|
||||||
|
public func ask<T: ArgConvertibleType>(prompt: String, type: T.Type, customizationBlock: (AskSettings<T> -> Void)? = nil) -> T {
|
||||||
|
|
||||||
PromptSettings.print(prompt)
|
PromptSettings.print(prompt)
|
||||||
|
|
||||||
|
let settings = getSettings(customizationBlock)
|
||||||
let settings = getSettings(callback)
|
|
||||||
|
|
||||||
if settings.confirm {
|
if settings.confirm {
|
||||||
return getValidatedStringWithConfirmation(settings)
|
return getValidatedStringWithConfirmation(settings)
|
||||||
@ -27,11 +45,16 @@ func ask<T: ArgConvertibleType>(prompt: String, type: T.Type, callback: (AskSett
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK:- Internal functions
|
||||||
|
|
||||||
|
|
||||||
func getValidatedString<T: ArgConvertibleType, W: AskerValidator where W.Item == T>(validator: W) -> T {
|
func getValidatedString<T: ArgConvertibleType, W: AskerValidator where W.Item == T>(validator: W) -> T {
|
||||||
let stringOrEmpty = readStringOrEmpty()
|
let stringOrEmpty = readStringOrEmpty()
|
||||||
return askForValidatedItem(originalValue: stringOrEmpty, validator: validator)
|
return askForValidatedItem(originalValue: stringOrEmpty, validator: validator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func getValidatedStringWithConfirmation<T: ArgConvertibleType, W: AskerValidator where W.Item == T>(validator: W) -> T {
|
func getValidatedStringWithConfirmation<T: ArgConvertibleType, W: AskerValidator where W.Item == T>(validator: W) -> T {
|
||||||
|
|
||||||
while true {
|
while true {
|
||||||
@ -46,12 +69,14 @@ func getValidatedStringWithConfirmation<T: ArgConvertibleType, W: AskerValidator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func getSettings<T>(callback: (AskSettings<T> -> Void)?) -> AskSettings<T> {
|
func getSettings<T>(callback: (AskSettings<T> -> Void)?) -> AskSettings<T> {
|
||||||
let settings = AskSettings<T>()
|
let settings = AskSettings<T>()
|
||||||
callback?(settings)
|
callback?(settings)
|
||||||
return settings
|
return settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func readStringOrEmpty() -> String {
|
func readStringOrEmpty() -> String {
|
||||||
return PromptSettings.read() ?? ""
|
return PromptSettings.read() ?? ""
|
||||||
}
|
}
|
@ -9,13 +9,27 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
class AskSettings<T: ArgConvertibleType> {
|
/// Settings used to costumize the behaviour of ask()
|
||||||
var defaultValue: T?
|
public class AskSettings<T: ArgConvertibleType> {
|
||||||
|
|
||||||
|
/// Default value to set incase the user entered a blank
|
||||||
|
public var defaultValue: T?
|
||||||
|
|
||||||
|
/// If set to true, another message will follow successful user entry asking the user to confirm
|
||||||
|
/// his selection
|
||||||
|
public var confirm = false
|
||||||
|
|
||||||
var invalidClousures: [(T -> Bool, String)] = []
|
var invalidClousures: [(T -> Bool, String)] = []
|
||||||
var confirm = false
|
|
||||||
|
|
||||||
func addInvalidCase(description: String, invalidIfTrue: (T -> Bool)) {
|
|
||||||
|
/**
|
||||||
|
Add an invalid entry case
|
||||||
|
|
||||||
|
- parameter description: The string to be printed to the stdout if the case is invalid
|
||||||
|
- parameter invalidIfTrue: If true is returned, then the user input was invalid, if false, the
|
||||||
|
user input was valid.
|
||||||
|
*/
|
||||||
|
public func addInvalidCase(description: String, invalidIfTrue: (T -> Bool)) {
|
||||||
invalidClousures.append(invalidIfTrue, description)
|
invalidClousures.append(invalidIfTrue, description)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +42,11 @@ class AskSettings<T: ArgConvertibleType> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK:- Internal extension
|
||||||
|
|
||||||
extension AskSettings: AskerValidator {
|
extension AskSettings: AskerValidator {
|
||||||
|
|
||||||
func invalidItemMessage(string: String?) -> String? {
|
func invalidItemMessage(string: String?) -> String? {
|
||||||
guard let string = string else {
|
guard let string = string else {
|
||||||
return "You provided an empty message, pelase enter anything!"
|
return "You provided an empty message, pelase enter anything!"
|
95
SwiftLine/Swiftline/Choose/Choose.swift
Normal file
95
SwiftLine/Swiftline/Choose/Choose.swift
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// Chooser.swift
|
||||||
|
// Choose
|
||||||
|
//
|
||||||
|
// Created by Omar Abdelhafith on 03/11/2015.
|
||||||
|
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Presents a user with a menu of items to choose from
|
||||||
|
|
||||||
|
- parameter prompt: The menu prompt message
|
||||||
|
- parameter choices: List of choices
|
||||||
|
|
||||||
|
- returns: The user selected item
|
||||||
|
*/
|
||||||
|
public func choose(prompt: String, choices: String...) -> String {
|
||||||
|
return choose(prompt, type: String.self) {
|
||||||
|
for choice in choices {
|
||||||
|
$0.addChoice(choice) { return choice }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Presents a user with a menu of items to choose from
|
||||||
|
|
||||||
|
- parameter costumizationBlock: Closure to be called with a ChooseSettings, changes to the settings are reflected to the prompt
|
||||||
|
|
||||||
|
- returns: The user selected item
|
||||||
|
*/
|
||||||
|
public func choose<T>(costumizationBlock: (ChooseSettings<T> -> Void)) -> T {
|
||||||
|
|
||||||
|
let settings = getChooseSettings(costumizationBlock)
|
||||||
|
return choose(settings, type: T.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Presents a user with a menu of items to choose from
|
||||||
|
|
||||||
|
- parameter prompt: The menu prompt message
|
||||||
|
- parameter type: The value type to be expected from the user
|
||||||
|
- parameter costumizationBlock: Closure to be called with a ChooseSettings, changes to the settings are reflected to the prompt
|
||||||
|
|
||||||
|
- returns: The user selected item
|
||||||
|
*/
|
||||||
|
public func choose<T>(prompt: String, type: T.Type, costumizationBlock: (ChooseSettings<T> -> Void)) -> T {
|
||||||
|
|
||||||
|
let settings = getChooseSettings(costumizationBlock)
|
||||||
|
settings.promptQuestion = prompt
|
||||||
|
return choose(settings, type: type)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Presents a user with a menu of items to choose from
|
||||||
|
|
||||||
|
- parameter type: The value type to be expected from the user
|
||||||
|
- parameter costumizationBlock: Closure to be called with a ChooseSettings, changes to the settings are reflected to the prompt
|
||||||
|
|
||||||
|
- returns: The user selected item
|
||||||
|
*/
|
||||||
|
public func choose<T>(type: T.Type, costumizationBlock: (ChooseSettings<T> -> Void)) -> T {
|
||||||
|
|
||||||
|
let settings = getChooseSettings(costumizationBlock)
|
||||||
|
return choose(settings, type: type)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK :- Internal functions
|
||||||
|
|
||||||
|
|
||||||
|
func choose<T>(settings: ChooseSettings<T>, type: T.Type) -> T {
|
||||||
|
|
||||||
|
let items = settings.preparePromptItems()
|
||||||
|
|
||||||
|
items.forEach { PromptSettings.print($0) }
|
||||||
|
PromptSettings.print("\(settings.promptQuestion)", terminator: "")
|
||||||
|
|
||||||
|
let stringRead = readStringOrEmpty()
|
||||||
|
|
||||||
|
return askForValidatedItem(originalValue: stringRead, validator: settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChooseSettings<T>(costumizationBlock: ChooseSettings<T> -> Void) -> ChooseSettings<T> {
|
||||||
|
let settings = ChooseSettings<T>()
|
||||||
|
costumizationBlock(settings)
|
||||||
|
return settings
|
||||||
|
}
|
@ -9,26 +9,48 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
enum ChoiceIndexType {
|
/**
|
||||||
|
Choice index type
|
||||||
|
|
||||||
|
- Letters: Use letters as choice index (a. b. c.)
|
||||||
|
- Numbers: Use numbers as choice index (1. 2. 3.)
|
||||||
|
*/
|
||||||
|
public enum ChoiceIndexType {
|
||||||
case Letters
|
case Letters
|
||||||
case Numbers
|
case Numbers
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChooseSettings<T> {
|
|
||||||
|
|
||||||
|
/// Settings to costumize the behavior of choose
|
||||||
|
public class ChooseSettings<T> {
|
||||||
typealias Item = T
|
typealias Item = T
|
||||||
|
|
||||||
var choices: [(choice: String, callback: Void -> T)] = []
|
var choices: [(choice: String, callback: Void -> T)] = []
|
||||||
var promptQuestion = ""
|
|
||||||
|
|
||||||
var index = ChoiceIndexType.Numbers
|
/// Prompt message to use
|
||||||
var indexSuffix = ". "
|
public var promptQuestion = ""
|
||||||
|
|
||||||
func addChoice(choice: String..., callback: Void -> T) {
|
/// Choice index used for choose items
|
||||||
|
public var index = ChoiceIndexType.Numbers
|
||||||
|
|
||||||
|
/// Index suffix used between the index and the item
|
||||||
|
public var indexSuffix = ". "
|
||||||
|
|
||||||
|
/**
|
||||||
|
Add a new item to the list of choices
|
||||||
|
|
||||||
|
- parameter choice: Item name
|
||||||
|
- parameter callback: callback called when the item is selected, the value returned from this call back will be returned from choose
|
||||||
|
*/
|
||||||
|
public func addChoice(choice: String..., callback: Void -> T) {
|
||||||
choice.forEach {
|
choice.forEach {
|
||||||
choices.append(($0, callback))
|
choices.append(($0, callback))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK:- Internal
|
||||||
|
|
||||||
func validChoices() -> [String] {
|
func validChoices() -> [String] {
|
||||||
let validChoices = Array(1...choices.count).map { "\($0)" }
|
let validChoices = Array(1...choices.count).map { "\($0)" }
|
||||||
return validChoices + stringChoices()
|
return validChoices + stringChoices()
|
||||||
@ -84,6 +106,8 @@ class ChooseSettings<T> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK:- Internal Class
|
||||||
|
|
||||||
extension ChooseSettings: AskerValidator {
|
extension ChooseSettings: AskerValidator {
|
||||||
func validatedItem(forString string: String) -> T {
|
func validatedItem(forString string: String) -> T {
|
||||||
return choiceForInput(string)!
|
return choiceForInput(string)!
|
@ -9,6 +9,43 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
|
||||||
|
/// Access the methods to change the foreground color
|
||||||
|
public var f: StringForegroundColorizer {
|
||||||
|
get { return foreground }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the methods to change the foreground color
|
||||||
|
public var foreground: StringForegroundColorizer {
|
||||||
|
get { return StringForegroundColorizer(string: self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the methods to change the background color
|
||||||
|
public var b: StringBackgroundColorizer {
|
||||||
|
get { return background }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the methods to change the background color
|
||||||
|
public var background: StringBackgroundColorizer {
|
||||||
|
get { return StringBackgroundColorizer(string: self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the methods to change the text style
|
||||||
|
public var s: StringStyleColorizer {
|
||||||
|
get { return style }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the methods to change the text style
|
||||||
|
public var style: StringStyleColorizer {
|
||||||
|
get { return StringStyleColorizer(string: self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK- Internal
|
||||||
|
|
||||||
class Colorizer: CustomStringConvertible {
|
class Colorizer: CustomStringConvertible {
|
||||||
|
|
||||||
let color: StringStyle
|
let color: StringStyle
|
||||||
@ -26,33 +63,4 @@ class Colorizer: CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension String {
|
|
||||||
|
|
||||||
var f: StringForegroundColorizer {
|
|
||||||
get { return foreground }
|
|
||||||
}
|
|
||||||
|
|
||||||
var foreground: StringForegroundColorizer {
|
|
||||||
get { return StringForegroundColorizer(string: self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var b: StringBackgroundColorizer {
|
|
||||||
get { return background }
|
|
||||||
}
|
|
||||||
|
|
||||||
var background: StringBackgroundColorizer {
|
|
||||||
get { return StringBackgroundColorizer(string: self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var s: StringStyleColorizer {
|
|
||||||
get { return style }
|
|
||||||
}
|
|
||||||
|
|
||||||
var style: StringStyleColorizer {
|
|
||||||
get { return StringStyleColorizer(string: self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -11,53 +11,53 @@ import Foundation
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
struct StringBackgroundColorizer {
|
public struct StringBackgroundColorizer {
|
||||||
|
|
||||||
let string: String
|
let string: String
|
||||||
|
|
||||||
var Black: String {
|
public var Black: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Black).description
|
return Colorizer(string: string, color: BackgroundColor.Black).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Red: String {
|
public var Red: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Red).description
|
return Colorizer(string: string, color: BackgroundColor.Red).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Green: String {
|
public var Green: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Green).description
|
return Colorizer(string: string, color: BackgroundColor.Green).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Yellow: String {
|
public var Yellow: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Yellow).description
|
return Colorizer(string: string, color: BackgroundColor.Yellow).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Blue: String {
|
public var Blue: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Blue).description
|
return Colorizer(string: string, color: BackgroundColor.Blue).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Magenta: String {
|
public var Magenta: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Magenta).description
|
return Colorizer(string: string, color: BackgroundColor.Magenta).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Cyan: String {
|
public var Cyan: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.Cyan).description
|
return Colorizer(string: string, color: BackgroundColor.Cyan).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var White: String {
|
public var White: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: BackgroundColor.White).description
|
return Colorizer(string: string, color: BackgroundColor.White).description
|
||||||
}
|
}
|
@ -11,53 +11,53 @@ import Foundation
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
struct StringForegroundColorizer {
|
public struct StringForegroundColorizer {
|
||||||
|
|
||||||
let string: String
|
let string: String
|
||||||
|
|
||||||
var Black: String {
|
public var Black: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Black).description
|
return Colorizer(string: string, color: ForegroundColor.Black).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Red: String {
|
public var Red: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Red).description
|
return Colorizer(string: string, color: ForegroundColor.Red).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Green: String {
|
public var Green: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Green).description
|
return Colorizer(string: string, color: ForegroundColor.Green).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Yellow: String {
|
public var Yellow: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Yellow).description
|
return Colorizer(string: string, color: ForegroundColor.Yellow).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Blue: String {
|
public var Blue: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Blue).description
|
return Colorizer(string: string, color: ForegroundColor.Blue).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Magenta: String {
|
public var Magenta: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Magenta).description
|
return Colorizer(string: string, color: ForegroundColor.Magenta).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Cyan: String {
|
public var Cyan: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.Cyan).description
|
return Colorizer(string: string, color: ForegroundColor.Cyan).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var White: String {
|
public var White: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: ForegroundColor.White).description
|
return Colorizer(string: string, color: ForegroundColor.White).description
|
||||||
}
|
}
|
@ -9,73 +9,74 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
extension String {
|
|
||||||
|
public extension String {
|
||||||
|
|
||||||
struct StringStyleColorizer {
|
public struct StringStyleColorizer {
|
||||||
|
|
||||||
let string: String
|
let string: String
|
||||||
|
|
||||||
var Reset: String {
|
public var Reset: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.Reset).description
|
return Colorizer(string: string, color: StringTextStyle.Reset).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Bold: String {
|
public var Bold: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.Bold).description
|
return Colorizer(string: string, color: StringTextStyle.Bold).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Italic: String {
|
public var Italic: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.Italic).description
|
return Colorizer(string: string, color: StringTextStyle.Italic).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Underline: String {
|
public var Underline: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.Underline).description
|
return Colorizer(string: string, color: StringTextStyle.Underline).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Inverse: String {
|
public var Inverse: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.Inverse).description
|
return Colorizer(string: string, color: StringTextStyle.Inverse).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var Strikethrough: String {
|
public var Strikethrough: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.Strikethrough).description
|
return Colorizer(string: string, color: StringTextStyle.Strikethrough).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var BoldOff: String {
|
public var BoldOff: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.BoldOff).description
|
return Colorizer(string: string, color: StringTextStyle.BoldOff).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ItalicOff: String {
|
public var ItalicOff: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.ItalicOff).description
|
return Colorizer(string: string, color: StringTextStyle.ItalicOff).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var UnderlineOff: String {
|
public var UnderlineOff: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.UnderlineOff).description
|
return Colorizer(string: string, color: StringTextStyle.UnderlineOff).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var InverseOff: String {
|
public var InverseOff: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.InverseOff).description
|
return Colorizer(string: string, color: StringTextStyle.InverseOff).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var StrikethroughOff: String {
|
public var StrikethroughOff: String {
|
||||||
get {
|
get {
|
||||||
return Colorizer(string: string, color: StringTextStyle.StrikethroughOff).description
|
return Colorizer(string: string, color: StringTextStyle.StrikethroughOff).description
|
||||||
}
|
}
|
65
SwiftLine/Swiftline/Misc/ArgConvertible.swift
Normal file
65
SwiftLine/Swiftline/Misc/ArgConvertible.swift
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// ArgConvertible.swift
|
||||||
|
// ArgConvertible
|
||||||
|
//
|
||||||
|
// Created by Omar Abdelhafith on 02/11/2015.
|
||||||
|
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any type that extends ArgConvertibleType can be used in ask and choose
|
||||||
|
*/
|
||||||
|
public protocol ArgConvertibleType {
|
||||||
|
|
||||||
|
/// Create an instance out of a string
|
||||||
|
static func fromString(string: String) -> Self?
|
||||||
|
|
||||||
|
/// Return the display name of a type
|
||||||
|
static func typeName() -> String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension Int: ArgConvertibleType {
|
||||||
|
public static func fromString(string: String) -> Int? {
|
||||||
|
return Int(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func typeName() -> String {
|
||||||
|
return "Integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension Double: ArgConvertibleType {
|
||||||
|
public static func fromString(string: String) -> Double? {
|
||||||
|
return Double(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func typeName() -> String {
|
||||||
|
return "Double"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Float: ArgConvertibleType {
|
||||||
|
public static func fromString(string: String) -> Float? {
|
||||||
|
return Float(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func typeName() -> String {
|
||||||
|
return "Float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension String: ArgConvertibleType {
|
||||||
|
public static func fromString(string: String) -> String? {
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func typeName() -> String {
|
||||||
|
return "String"
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,15 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
struct RunResults {
|
public struct RunResults {
|
||||||
let exitStatus: Int
|
let exitStatus: Int
|
||||||
|
|
||||||
let stdout: String
|
let stdout: String
|
||||||
let stderr: String
|
let stderr: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK:- Internal
|
||||||
|
|
||||||
func splitCommandToArgs(command: String) -> [String] {
|
func splitCommandToArgs(command: String) -> [String] {
|
||||||
if command.containsString(" ") {
|
if command.containsString(" ") {
|
||||||
return command.componentsSeparatedByString(" ")
|
return command.componentsSeparatedByString(" ")
|
46
SwiftLine/Swiftline/Runner/RunnerSettings.swift
Normal file
46
SwiftLine/Swiftline/Runner/RunnerSettings.swift
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//
|
||||||
|
// RunSettings.swift
|
||||||
|
// RunSettings
|
||||||
|
//
|
||||||
|
// Created by Omar Abdelhafith on 05/11/2015.
|
||||||
|
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
/// Settings to costumize the run function
|
||||||
|
public class RunSettings {
|
||||||
|
|
||||||
|
/// If set to true, the command wont be run on the system, the stdout will contain the command executed
|
||||||
|
public var dryRun = false
|
||||||
|
|
||||||
|
/// Which parts of the command to be echoed during execution
|
||||||
|
public var echo = EchoSettings.None
|
||||||
|
|
||||||
|
/// Run the command in interactive mode; output wont be captured
|
||||||
|
public var interactive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Echo settings
|
||||||
|
public struct EchoSettings: OptionSetType {
|
||||||
|
|
||||||
|
public let rawValue: Int
|
||||||
|
|
||||||
|
public init(rawValue: Int) {
|
||||||
|
self.rawValue = rawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dont echo anything, this is the default settings
|
||||||
|
public static var None = EchoSettings(rawValue: 0)
|
||||||
|
|
||||||
|
/// Echo the stdout from the run command to the terminal
|
||||||
|
public static let Stdout = EchoSettings(rawValue: 1 << 0)
|
||||||
|
|
||||||
|
/// Echo the stderr from the run command to the terminal
|
||||||
|
public static let Stderr = EchoSettings(rawValue: 1 << 1)
|
||||||
|
|
||||||
|
/// Echo the command executed to the terminal
|
||||||
|
public static let Command = EchoSettings(rawValue: 1 << 2)
|
||||||
|
}
|
87
SwiftLine/Swiftline/Runner/ShortHandRunner.swift
Normal file
87
SwiftLine/Swiftline/Runner/ShortHandRunner.swift
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// ShortHandRunner.swift
|
||||||
|
// ShortHandRunner
|
||||||
|
|
||||||
|
//
|
||||||
|
// Created by Omar Abdelhafith on 05/11/2015.
|
||||||
|
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Executes a command and captures its output
|
||||||
|
|
||||||
|
- parameter command: the command to execute
|
||||||
|
- parameter args: the parameters to pass to the command
|
||||||
|
|
||||||
|
- returns: RunResults describing the command results
|
||||||
|
*/
|
||||||
|
public func run(command: String, args: String...) -> RunResults {
|
||||||
|
return 🏃.run(command, args: args as [String])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Executes a command and captures its output
|
||||||
|
|
||||||
|
- parameter command: the command to execute
|
||||||
|
- parameter args: the parameters to pass to the command
|
||||||
|
|
||||||
|
- returns: RunResults describing the command results
|
||||||
|
*/
|
||||||
|
public func run(command: String, args: [String]) -> RunResults {
|
||||||
|
return 🏃.run(command, args: args as [String])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Executes a command and captures its output
|
||||||
|
|
||||||
|
- parameter command: the command to execute
|
||||||
|
- parameter settingsBlock: block that receives the settings to costumize the behavior of run
|
||||||
|
|
||||||
|
- returns: RunResults describing the command results
|
||||||
|
*/
|
||||||
|
public func run(command: String, settingsBlock: (RunSettings -> Void)) -> RunResults {
|
||||||
|
return 🏃.run(command, settings: settingsBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Executes a command and captures its output
|
||||||
|
|
||||||
|
- parameter command: the command to execute
|
||||||
|
- parameter args: the parameters to pass to the command
|
||||||
|
- parameter settingsBlock: block that receives the settings to costumize the behavior of run
|
||||||
|
|
||||||
|
- returns: RunResults describing the command results
|
||||||
|
*/
|
||||||
|
public func run(command: String, args: [String], settings: (RunSettings -> Void)) -> RunResults {
|
||||||
|
return 🏃.run(command, args: args, settings: settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Executes a command and captures its output
|
||||||
|
|
||||||
|
- parameter command: the command to execute
|
||||||
|
- parameter echo: echo settings that describe what parts of the command to print
|
||||||
|
|
||||||
|
- returns: RunResults describing the command results
|
||||||
|
*/
|
||||||
|
func run(command: String, echo: EchoSettings) -> RunResults {
|
||||||
|
return 🏃.run(command, echo: echo)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Execute a command in interactive mode, output won't be captured
|
||||||
|
|
||||||
|
- parameter command: the command to execute
|
||||||
|
|
||||||
|
- returns: executed command exit code
|
||||||
|
*/
|
||||||
|
public func runWithoutCapture(command: String) -> Int {
|
||||||
|
return 🏃.runWithoutCapture(command)
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class AgreeSettingsTest: QuickSpec {
|
class AgreeSettingsTest: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class AgreeTest: QuickSpec {
|
class AgreeTest: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class AskSettingsTests: QuickSpec {
|
class AskSettingsTests: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class AskerTest: QuickSpec {
|
class AskerTest: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class ChooseSettingsTests: QuickSpec {
|
class ChooseSettingsTests: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class ChooseTests: QuickSpec {
|
class ChooseTests: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,6 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class ColorizerTest: QuickSpec {
|
class ColorizerTest: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
@ -1,5 +1,6 @@
|
|||||||
import Quick
|
import Quick
|
||||||
import Nimble
|
import Nimble
|
||||||
|
@testable import Swiftline
|
||||||
|
|
||||||
class RunnerTests: QuickSpec {
|
class RunnerTests: QuickSpec {
|
||||||
override func spec() {
|
override func spec() {
|
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,6 @@
|
|||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "self:swiftline.xcodeproj">
|
location = "self:Swiftline.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
100
swiftline.xcodeproj/xcshareddata/xcschemes/Swiftline.xcscheme
Normal file
100
swiftline.xcodeproj/xcshareddata/xcschemes/Swiftline.xcscheme
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "0710"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
|
||||||
|
BuildableName = "Swiftline.framework"
|
||||||
|
BlueprintName = "Swiftline"
|
||||||
|
ReferencedContainer = "container:Swiftline.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
codeCoverageEnabled = "YES">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D72762DC1BF2C9E900126D99"
|
||||||
|
BuildableName = "SwiftlineTests.xctest"
|
||||||
|
BlueprintName = "SwiftlineTests"
|
||||||
|
ReferencedContainer = "container:Swiftline.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
|
||||||
|
BuildableName = "Swiftline.framework"
|
||||||
|
BlueprintName = "Swiftline"
|
||||||
|
ReferencedContainer = "container:Swiftline.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
|
||||||
|
BuildableName = "Swiftline.framework"
|
||||||
|
BlueprintName = "Swiftline"
|
||||||
|
ReferencedContainer = "container:Swiftline.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
|
||||||
|
BuildableName = "Swiftline.framework"
|
||||||
|
BlueprintName = "Swiftline"
|
||||||
|
ReferencedContainer = "container:Swiftline.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
10
swiftline.xcworkspace/contents.xcworkspacedata
generated
10
swiftline.xcworkspace/contents.xcworkspacedata
generated
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "group:swiftline.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
Loading…
Reference in New Issue
Block a user