1
1
# Swift CommandLineKit
2
2
3
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/ )
4
5
[ ![ Language: Swift 4.1] ( https://img.shields.io/badge/Language-Swift%204.1-green.svg?style=flat )] ( https://developer.apple.com/swift/ )
5
6
[ ![ IDE: Xcode 9.3] ( https://img.shields.io/badge/IDE-Xcode%209.3-orange.svg?style=flat )] ( https://developer.apple.com/xcode/ )
6
7
[ ![ Carthage: compatible] ( https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat )] ( https://github.com/Carthage/Carthage )
@@ -18,8 +19,184 @@ functionality:
18
19
based on the library [ Linenoise-Swift] ( https://github.com/andybest/linenoise-swift ) ,
19
20
but supporting unicode input, multiple lines, and styled text.
20
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
+ ### Example
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 (" h" , " 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 : AppInfo.prompt )
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 = self .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 [<option> ...] [---] [<program> <arg> ...]
102
+ options:
103
+ -f, --filepath <value> ...
104
+ Adds file path in which programs are searched for.
105
+ -l, --libpath <value> ...
106
+ Adds file path in which libraries are searched for.
107
+ -h, --heapsize <value>
108
+ Initial capacity of the heap
109
+ -i, --import <value> ...
110
+ Imports library automatically after startup.
111
+ -p, --prelude <value>
112
+ Path to prelude file which gets executed after loading all provided libraries.
113
+ -r, --prompt <value>
114
+ String used as prompt in REPL.
115
+ -q, --quiet
116
+ In quiet mode, optional messages are not printed.
117
+ -h, --help
118
+ Show description of usage and options of this tools.
119
+ ```
120
+
121
+ Command-line tools can inspect whether a flag was set via the ` Flag.wasSet ` field. For flags with
122
+ parameters, the parameters are stored in the ` Flag.value ` field. The type of this field is dependent on the
123
+ flag type. For repeated flags, an array is used.
124
+
125
+
126
+ ## Text style and colors
127
+
128
+ CommandLineKit provides a
129
+ [ TextProperties] ( https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/TextProperties.swift )
130
+ structure for bundling a text color, a background color, and a text style in a single object. Text properties can be
131
+ merged with the ` with(:) ` functions and applied to a string with the ` apply(to:) ` function.
132
+
133
+ Individual enumerations for
134
+ [ TextColor] ( https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/TextColor.swift ) ,
135
+ [ BackgroundColor] ( https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/BackgroundColor.swift ) , and
136
+ [ TextStyle] ( https://github.com/objecthub/swift-commandlinekit/blob/master/Sources/CommandLineKit/TextStyle.swift )
137
+ define the individual properties.
138
+
139
+ ## Reading strings
140
+
141
+ CommandLineKit includes a significantly improved version of the "readline" API originally defined by the library
142
+ [ Linenoise-Swift] ( https://github.com/andybest/linenoise-swift ) . It supports unicode text, multi-line text entry, and
143
+ styled text. It supports all the existing features such as _ advanced keyboard support_ , _ history_ ,
144
+ _ text completion_ , and _ hints_ .
145
+
146
+ The following code illustrates the usage of the LineReader API:
147
+
148
+ ```
149
+ if let ln = LineReader() {
150
+ ln.setCompletionCallback { currentBuffer in
151
+ let completions = [
152
+ "Hello!",
153
+ "Hello Google",
154
+ "Scheme is awesome!"
155
+ ]
156
+ return completions.filter { $0.hasPrefix(currentBuffer) }
157
+ }
158
+ ln.setHintsCallback { currentBuffer in
159
+ let hints = [
160
+ "Foo",
161
+ "Lorem Ipsum",
162
+ "Scheme is awesome!"
163
+ ]
164
+ let filtered = hints.filter { $0.hasPrefix(currentBuffer) }
165
+ if let hint = filtered.first {
166
+ let hintText = String(hint.dropFirst(currentBuffer.count))
167
+ return (hintText, TextColor.grey.properties)
168
+ } else {
169
+ return nil
170
+ }
171
+ }
172
+ print("Type 'exit' to quit")
173
+ var done = false
174
+ while !done {
175
+ do {
176
+ let output = try ln.readLine(prompt: "> ",
177
+ maxCount: 200,
178
+ strippingNewline: true,
179
+ promptProperties: TextProperties(.green, nil, .bold),
180
+ readProperties: TextProperties(.blue, nil),
181
+ parenProperties: TextProperties(.red, nil, .bold))
182
+ print("Entered: \(output)")
183
+ ln.addHistory(output)
184
+ if output == "exit" {
185
+ break
186
+ }
187
+ } catch LineReaderError.CTRLC {
188
+ print("\nCaptured CTRL+C. Quitting.")
189
+ done = true
190
+ } catch {
191
+ print(error)
192
+ }
193
+ }
194
+ }
195
+ ```
196
+
21
197
## Requirements
22
198
23
- - XCode 9.3
24
- - Swift 4.1
25
- - Carthage or Swift Package Manager
199
+ - [ Xcode 9.3] ( https://developer.apple.com/xcode/ )
200
+ - [ Swift 4.1] ( https://developer.apple.com/swift/ )
201
+ - [ Carthage] ( https://github.com/Carthage/Carthage )
202
+ - [ Swift Package Manager] ( https://swift.org/package-manager/ )
0 commit comments