Giter Club home page Giter Club logo

swiftline's Introduction

Build Status Platform Language: Swift CocoaPods Carthage GITTER: join chat GITTER: join chat

Swiftline is a set of tools to help you create command line applications. Swiftline is inspired by highline

Swiftline contains the following:

  • Colorize: Helps adding colors to strings written to the terminal
  • Ask , Choose and agree: Easily create prompt for asking the user more info
  • Run: A quick way to run an external command and read its standard output and standard error.
  • Env: Read and write environment variables ruby-flavored
  • Args: Parses command line arguments and return a hash of the passed flags

Contents

Usage Installation Examples Docs Tests

Usage

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:

print("Red String".f.Red)
print("Blue String".foreground.Blue)

To change the text background color, use either string.b or string.background:

print("I have a white background".b.White)
print("My background color is green".background.Green)

To change the text background style, use either string.s or string.style:

print("I am a bold string".s.Bold)
print("I have an underline".style.Underline)

You can compose foreground, background, and style:

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.

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:

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.

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

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:

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

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:

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.

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

Run ๐Ÿƒ

Run 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:

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:

let result = run("ls", args: "-all")

To customize the run function, you can pass in a customization block:

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.

Env

Env is used to read and write the environment variables passed to the script

// Set enviroment variable
Env.set("key1", "value1")

// Get environment variable
Env.get("SomeKey")

// Clear all variables
Env.clear()

// Get all keys and values
Env.keys()
Env.values()

Args

Returns the arguments passed to the script. For example when calling script -f1 val1 -f2 val2 -- val3 val4

Args.all returns an array of all the raw arguments, in this example it will be ["-f1", "val1", "-f2", "val2", "--", "val3", "val4"

Args.parsed returns a structure that contains a parsed map of arguments and an array of arguments, for this example:

Args.parsed.parameters returns ["val3", "val4"]

Args.parsed.flags returns a dictinary of flags ["f1": "val1", "f2", "val2"]

Args.parsed.command returns the name of the executable itself "script"

Installation

You can install Swiftline using CocoaPods, carthage and Swift package manager

CocoaPods

use_frameworks!
pod 'Swiftline'

Carthage

github 'swiftline/swiftline'

Swift Package Manager

Add swiftline as dependency in your Package.swift

  import PackageDescription

  let package = Package(name: "YourPackage",
    dependencies: [
      .Package(url: "https://github.com/Swiftline/Swiftline.git", majorVersion: 0, minor: 3),
    ]
  )

CocoaPods + Rome plugin

If you want to use swiftline in a script you can use Rome CocoaPods plugin. This plugin builds the framework from the pod file and place them in a Rome directory.

platform :osx, '10.10'
plugin 'cocoapods-rome'

pod 'Swiftline'

Manual

To install Swiftline manually, add Pod/Swiftline directory to your project.

Examples

A list of examples can be found here

Tests

Tests can be found here. They can be normally run from the Xcode .

Documentation

Documentation can be found here

Future Improvement

  • Add gather (from highline) to ask function
  • Figure out a way to eliminate the need of interactive
  • Add Glob handling
  • Better documentation

Credits

Daniel Beere for creating the logo @DanielBeere check out danielbeere on dribble Omar Abdelhafith current project maintainer @ifnottrue

swiftline's People

Contributors

armcknight avatar artemnovichkov avatar danappelxx avatar delebedev avatar filmhomage avatar mau888 avatar nsomar avatar ohayon avatar readmecritic avatar stupergenius avatar vittoriom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftline's Issues

Question - Compile script to executable

Was wondering how I can compile the script to be an executable?

Tried variations on this
swiftc -framework ./Rome/Swiftline.framework Script.swift -o SciptExectutable

splitCommandToArgs should honor quotes while splitting

If I do a run operation with a directory name with space, operation fails.
For example:
run("open '/Users/myname/path with space'")
or even
run("open \"/Users/myname/path with space\"")

Issue is with the splitCommandToArgs method implemented in RunResults.swift which uses components(separatedBy:) API

Warning with latest tagged version 0.5.0

Do you mind giving the most recent commit a tagged version? When using Swift Package Manager I get a warning in a file that is no longer present since Feb 1, 2017:

Source/RunResults.swift:39:82: Conditional downcast from 'NSString?' to 'String' is a bridging conversion; did you mean to use 'as'?

Run command stuck

I'm running in it seems to not do anything (it is a long running command but it seems to never finish)

If I run the command from the command line terminal it does complete

Is there a way to continually output the stdout (Not wait for the result)

let archiveCommand = "some command to run"
let res = run(archiveCommand) // never completing through my script

Cocoapods and Rome Issue?

I have the latest cocapods and rome installed

cocoapods (1.1.0.rc.2, 1.0.1)
cocoapods-core (1.1.0.rc.2, 1.0.1)
cocoapods-deintegrate (1.0.1)
cocoapods-downloader (1.1.1)
cocoapods-plugins (1.0.0)
cocoapods-rome (0.7.0)
cocoapods-search (1.0.0)
cocoapods-stats (1.0.0)
cocoapods-trunk (1.0.0)
cocoapods-try (1.1.0)

And I get error:

[!] The dependency `Swiftline (from `../Swiftline.podspec`)` is not used in any concrete target.

I believe Podfile syntax has changed to require a target, but I don't understand how thats supposed to work with these CLI rome framework scripts?

Is there something broken here or am I doing it wrong?

Missing tag for Swift 3

Currently there is no tag for any Swift 3 release.

This makes it impossible to be used in latest SwiftPM

Linux support?

Does Swiftline support Linux? It'd be great if the README noted whether it does or not!

Using pipeline commands in run

If I try to do the following command:

let gitCommand = "git ls-remote --tags \(gitURL) | awk '{print $2}' | grep -v '{}' | awk -F'/' '{print $3}' | sort -n -t. -k1,1 -k2,2 -k3,3 | tail -n 1"
        let latestVersion = run(gitCommand).stdout

but it fails. it doesn't give any output and I don't know why. If I execute that command in my terminal it works perfectly fine. I'm not sure if it has to do with the pipelines or with the '

Adding support for Globs and easy dealing with directories

The idea is to add support for globs and quickly iterating a directory. I think it would look very similar to how ruby solves that. Check the documentation for http://ruby-doc.org/core-1.9.3/Dir.html

We can think about translating the following ruby examples to swift

  • Dir["/**"] expand the glob and return all the matching files
  • Dir.chdir change the current directory
  • Dir.foreach(directory) enumerates the files in the directory
  • and so on...

dyld: Library not loaded

Hi there,

I'm trying to include swiftline into a fresh Swift command line template Xcode project. I've built swiftline using carthage and included it in the "Link Binaries With Libraries" section to no avail.

dyld: Library not loaded: @rpath/Swiftline.framework/Versions/A/Swiftline
  Referenced from: /Users/cooltrooper/Library/Developer/Xcode/DerivedData/wlV1-fnrxshgimtnooghhhpyaripgrewy/Build/Products/Debug/wlV1
  Reason: image not found

Any tips?

Unix executable error

Trying to run unix executable, however always come upon the same issue: "Operation not permitted" What I can do about that?)

Unused default values

I know it is possible to provide default values when prompting the user for input. See below:

let level = ask("Choose level: ", type: Int.self) { settings in
   settings.defaultValue = 1
}

Unfortunately this value is only used in preparedItem() which is not called anywhere. When the user does not provide an input he gets the message to enter a valid integer despite the fact I chose a default value.

public class AskSettings<T: ArgConvertibleType> {
    
    /// Default value to set incase the user entered a blank
    public var defaultValue: T?

    ...

    func preparedItem(originalString string: String) -> T {
        if string.isEmpty && defaultValue != nil {
            return defaultValue!
        }
        
        return T.fromString(string)!
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.