diff options
| author | 2019-08-17 18:48:06 +0200 | |
|---|---|---|
| committer | 2019-08-17 18:48:06 +0200 | |
| commit | 3990ea204ce06c470ff9401eb5af8752dce800f0 (patch) | |
| tree | 57d8185833d12730666b350506149d00472ee092 | |
| parent | add missing word (diff) | |
| download | zig-clap-3990ea204ce06c470ff9401eb5af8752dce800f0.tar.gz zig-clap-3990ea204ce06c470ff9401eb5af8752dce800f0.tar.xz zig-clap-3990ea204ce06c470ff9401eb5af8752dce800f0.zip | |
make help message look more like other tools
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | build.zig | 26 | ||||
| -rw-r--r-- | clap.zig | 144 | ||||
| -rw-r--r-- | example/comptime-clap.zig | 4 | ||||
| -rw-r--r-- | src/comptime.zig | 6 |
5 files changed, 101 insertions, 85 deletions
| @@ -91,10 +91,10 @@ pub fn main() !void { | |||
| 91 | const allocator = std.heap.direct_allocator; | 91 | const allocator = std.heap.direct_allocator; |
| 92 | 92 | ||
| 93 | // First we specify what parameters our program can take. | 93 | // First we specify what parameters our program can take. |
| 94 | // We can use `parseParam` parse a string to a `Param(Help)` | 94 | // We can use `parseParam` to parse a string to a `Param(Help)` |
| 95 | const params = comptime [_]clap.Param(clap.Help){ | 95 | const params = comptime [_]clap.Param(clap.Help){ |
| 96 | clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, | 96 | clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, |
| 97 | clap.parseParam("-n, --number=NUM An option parameter, which takes a value.") catch unreachable, | 97 | clap.parseParam("-n, --number <NUM> An option parameter, which takes a value.") catch unreachable, |
| 98 | clap.Param(clap.Help){ | 98 | clap.Param(clap.Help){ |
| 99 | .takes_value = true, | 99 | .takes_value = true, |
| 100 | }, | 100 | }, |
| @@ -7,6 +7,19 @@ const Builder = std.build.Builder; | |||
| 7 | pub fn build(b: *Builder) void { | 7 | pub fn build(b: *Builder) void { |
| 8 | const mode = b.standardReleaseOptions(); | 8 | const mode = b.standardReleaseOptions(); |
| 9 | 9 | ||
| 10 | const test_all_step = b.step("test", "Run all tests in all modes."); | ||
| 11 | inline for ([_]Mode{ Mode.Debug, Mode.ReleaseFast, Mode.ReleaseSafe, Mode.ReleaseSmall }) |test_mode| { | ||
| 12 | const mode_str = comptime modeToString(test_mode); | ||
| 13 | |||
| 14 | const tests = b.addTest("clap.zig"); | ||
| 15 | tests.setBuildMode(test_mode); | ||
| 16 | tests.setNamePrefix(mode_str ++ " "); | ||
| 17 | |||
| 18 | const test_step = b.step("test-" ++ mode_str, "Run all tests in " ++ mode_str ++ "."); | ||
| 19 | test_step.dependOn(&tests.step); | ||
| 20 | test_all_step.dependOn(test_step); | ||
| 21 | } | ||
| 22 | |||
| 10 | const example_step = b.step("examples", "Build examples"); | 23 | const example_step = b.step("examples", "Build examples"); |
| 11 | inline for ([_][]const u8{ | 24 | inline for ([_][]const u8{ |
| 12 | "comptime-clap", | 25 | "comptime-clap", |
| @@ -21,19 +34,6 @@ pub fn build(b: *Builder) void { | |||
| 21 | example_step.dependOn(&example.step); | 34 | example_step.dependOn(&example.step); |
| 22 | } | 35 | } |
| 23 | 36 | ||
| 24 | const test_all_step = b.step("test", "Run all tests in all modes."); | ||
| 25 | inline for ([_]Mode{ Mode.Debug, Mode.ReleaseFast, Mode.ReleaseSafe, Mode.ReleaseSmall }) |test_mode| { | ||
| 26 | const mode_str = comptime modeToString(test_mode); | ||
| 27 | |||
| 28 | const tests = b.addTest("clap.zig"); | ||
| 29 | tests.setBuildMode(test_mode); | ||
| 30 | tests.setNamePrefix(mode_str ++ " "); | ||
| 31 | |||
| 32 | const test_step = b.step("test-" ++ mode_str, "Run all tests in " ++ mode_str ++ "."); | ||
| 33 | test_step.dependOn(&tests.step); | ||
| 34 | test_all_step.dependOn(test_step); | ||
| 35 | } | ||
| 36 | |||
| 37 | const readme_step = b.step("test", "Remake README."); | 37 | const readme_step = b.step("test", "Remake README."); |
| 38 | const readme = readMeStep(b); | 38 | const readme = readMeStep(b); |
| 39 | readme.dependOn(example_step); | 39 | readme.dependOn(example_step); |
| @@ -71,29 +71,24 @@ pub fn parseParam(line: []const u8) !Param(Help) { | |||
| 71 | if (found_comma) | 71 | if (found_comma) |
| 72 | param_str = param_str[0..param_str.len - 1]; | 72 | param_str = param_str[0..param_str.len - 1]; |
| 73 | 73 | ||
| 74 | switch (param_str.len) { | 74 | if (param_str.len != 2) |
| 75 | 1 => return error.InvalidShortParam, | 75 | return error.InvalidShortParam; |
| 76 | 2 => { | 76 | |
| 77 | res.names.short = param_str[1]; | 77 | res.names.short = param_str[1]; |
| 78 | if (!found_comma) { | 78 | if (!found_comma) { |
| 79 | res.id.msg = mem.trim(u8, it.rest(), " \t"); | 79 | var help_msg = it.rest(); |
| 80 | return res; | 80 | if (it.next()) |next| blk: { |
| 81 | if (mem.startsWith(u8, next, "<")) { | ||
| 82 | const start = mem.indexOfScalar(u8, help_msg, '<').? + 1; | ||
| 83 | const len = mem.indexOfScalar(u8, help_msg[start..], '>') orelse break :blk; | ||
| 84 | res.id.value = help_msg[start..][0..len]; | ||
| 85 | res.takes_value = true; | ||
| 86 | help_msg = help_msg[start + len + 1..]; | ||
| 81 | } | 87 | } |
| 82 | }, | 88 | } |
| 83 | else => { | ||
| 84 | res.names.short = param_str[1]; | ||
| 85 | if (param_str[2] != '=') | ||
| 86 | return error.InvalidShortParam; | ||
| 87 | |||
| 88 | res.id.value = param_str[3..]; | ||
| 89 | res.takes_value = true; | ||
| 90 | 89 | ||
| 91 | if (found_comma) | 90 | res.id.msg = mem.trim(u8, help_msg, " \t"); |
| 92 | return error.TrailingComma; | 91 | return res; |
| 93 | |||
| 94 | res.id.msg = mem.trim(u8, it.rest(), " \t"); | ||
| 95 | return res; | ||
| 96 | }, | ||
| 97 | } | 92 | } |
| 98 | 93 | ||
| 99 | param_str = it.next() orelse return error.NoParamFound; | 94 | param_str = it.next() orelse return error.NoParamFound; |
| @@ -101,16 +96,22 @@ pub fn parseParam(line: []const u8) !Param(Help) { | |||
| 101 | 96 | ||
| 102 | if (mem.startsWith(u8, param_str, "--")) { | 97 | if (mem.startsWith(u8, param_str, "--")) { |
| 103 | res.names.long = param_str[2..]; | 98 | res.names.long = param_str[2..]; |
| 104 | if (mem.indexOfScalar(u8, param_str, '=')) |eql_index| { | ||
| 105 | res.names.long = param_str[2..eql_index]; | ||
| 106 | res.id.value = param_str[eql_index + 1 ..]; | ||
| 107 | res.takes_value = true; | ||
| 108 | } | ||
| 109 | 99 | ||
| 110 | if (param_str[param_str.len - 1] == ',') | 100 | if (param_str[param_str.len - 1] == ',') |
| 111 | return error.TrailingComma; | 101 | return error.TrailingComma; |
| 102 | |||
| 103 | var help_msg = it.rest(); | ||
| 104 | if (it.next()) |next| blk: { | ||
| 105 | if (mem.startsWith(u8, next, "<")) { | ||
| 106 | const start = mem.indexOfScalar(u8, help_msg, '<').? + 1; | ||
| 107 | const len = mem.indexOfScalar(u8, help_msg[start..], '>') orelse break :blk; | ||
| 108 | res.id.value = help_msg[start..][0..len]; | ||
| 109 | res.takes_value = true; | ||
| 110 | help_msg = help_msg[start + len + 1..]; | ||
| 111 | } | ||
| 112 | } | ||
| 112 | 113 | ||
| 113 | res.id.msg = mem.trim(u8, it.rest(), " \t"); | 114 | res.id.msg = mem.trim(u8, help_msg, " \t"); |
| 114 | return res; | 115 | return res; |
| 115 | } | 116 | } |
| 116 | 117 | ||
| @@ -118,37 +119,37 @@ pub fn parseParam(line: []const u8) !Param(Help) { | |||
| 118 | } | 119 | } |
| 119 | 120 | ||
| 120 | test "parseParam" { | 121 | test "parseParam" { |
| 121 | var text: []const u8 = "-s, --long=value Help text"; | 122 | var text: []const u8 = "-s, --long <value> Help text"; |
| 122 | testing.expectEqual(Param(Help){ | 123 | testing.expectEqual(Param(Help){ |
| 123 | .id = Help{ | 124 | .id = Help{ |
| 124 | .msg = text[17..], | 125 | .msg = find(text, "Help text"), |
| 125 | .value = text[11..16], | 126 | .value = find(text, "value"), |
| 126 | }, | 127 | }, |
| 127 | .names = Names{ | 128 | .names = Names{ |
| 128 | .short = 's', | 129 | .short = 's', |
| 129 | .long = text[6..10], | 130 | .long = find(text, "long"), |
| 130 | }, | 131 | }, |
| 131 | .takes_value = true, | 132 | .takes_value = true, |
| 132 | }, try parseParam(text)); | 133 | }, try parseParam(text)); |
| 133 | 134 | ||
| 134 | text = "--long=value Help text"; | 135 | text = "--long <value> Help text"; |
| 135 | testing.expectEqual(Param(Help){ | 136 | testing.expectEqual(Param(Help){ |
| 136 | .id = Help{ | 137 | .id = Help{ |
| 137 | .msg = text[13..], | 138 | .msg = find(text, "Help text"), |
| 138 | .value = text[7..12], | 139 | .value = find(text, "value"), |
| 139 | }, | 140 | }, |
| 140 | .names = Names{ | 141 | .names = Names{ |
| 141 | .short = null, | 142 | .short = null, |
| 142 | .long = text[2..6], | 143 | .long = find(text, "long"), |
| 143 | }, | 144 | }, |
| 144 | .takes_value = true, | 145 | .takes_value = true, |
| 145 | }, try parseParam(text)); | 146 | }, try parseParam(text)); |
| 146 | 147 | ||
| 147 | text = "-s=value Help text"; | 148 | text = "-s <value> Help text"; |
| 148 | testing.expectEqual(Param(Help){ | 149 | testing.expectEqual(Param(Help){ |
| 149 | .id = Help{ | 150 | .id = Help{ |
| 150 | .msg = text[9..], | 151 | .msg = find(text, "Help text"), |
| 151 | .value = text[3..8], | 152 | .value = find(text, "value"), |
| 152 | }, | 153 | }, |
| 153 | .names = Names{ | 154 | .names = Names{ |
| 154 | .short = 's', | 155 | .short = 's', |
| @@ -160,12 +161,12 @@ test "parseParam" { | |||
| 160 | text = "-s, --long Help text"; | 161 | text = "-s, --long Help text"; |
| 161 | testing.expectEqual(Param(Help){ | 162 | testing.expectEqual(Param(Help){ |
| 162 | .id = Help{ | 163 | .id = Help{ |
| 163 | .msg = text[11..], | 164 | .msg = find(text, "Help text"), |
| 164 | .value = text[0..0], | 165 | .value = text[0..0], |
| 165 | }, | 166 | }, |
| 166 | .names = Names{ | 167 | .names = Names{ |
| 167 | .short = 's', | 168 | .short = 's', |
| 168 | .long = text[6..10], | 169 | .long = find(text, "long"), |
| 169 | }, | 170 | }, |
| 170 | .takes_value = false, | 171 | .takes_value = false, |
| 171 | }, try parseParam(text)); | 172 | }, try parseParam(text)); |
| @@ -173,7 +174,7 @@ test "parseParam" { | |||
| 173 | text = "-s Help text"; | 174 | text = "-s Help text"; |
| 174 | testing.expectEqual(Param(Help){ | 175 | testing.expectEqual(Param(Help){ |
| 175 | .id = Help{ | 176 | .id = Help{ |
| 176 | .msg = text[3..], | 177 | .msg = find(text, "Help text"), |
| 177 | .value = text[0..0], | 178 | .value = text[0..0], |
| 178 | }, | 179 | }, |
| 179 | .names = Names{ | 180 | .names = Names{ |
| @@ -186,34 +187,49 @@ test "parseParam" { | |||
| 186 | text = "--long Help text"; | 187 | text = "--long Help text"; |
| 187 | testing.expectEqual(Param(Help){ | 188 | testing.expectEqual(Param(Help){ |
| 188 | .id = Help{ | 189 | .id = Help{ |
| 189 | .msg = text[7..], | 190 | .msg = find(text, "Help text"), |
| 190 | .value = text[0..0], | 191 | .value = text[0..0], |
| 191 | }, | 192 | }, |
| 192 | .names = Names{ | 193 | .names = Names{ |
| 193 | .short = null, | 194 | .short = null, |
| 194 | .long = text[2..6], | 195 | .long = find(text, "long"), |
| 195 | }, | 196 | }, |
| 196 | .takes_value = false, | 197 | .takes_value = false, |
| 197 | }, try parseParam(text)); | 198 | }, try parseParam(text)); |
| 198 | 199 | ||
| 200 | text = "--long <A | B> Help text"; | ||
| 201 | testing.expectEqual(Param(Help){ | ||
| 202 | .id = Help{ | ||
| 203 | .msg = find(text, "Help text"), | ||
| 204 | .value = find(text, "A | B"), | ||
| 205 | }, | ||
| 206 | .names = Names{ | ||
| 207 | .short = null, | ||
| 208 | .long = find(text, "long"), | ||
| 209 | }, | ||
| 210 | .takes_value = true, | ||
| 211 | }, try parseParam(text)); | ||
| 212 | |||
| 199 | testing.expectError(error.NoParamFound, parseParam("Help")); | 213 | testing.expectError(error.NoParamFound, parseParam("Help")); |
| 200 | testing.expectError(error.TrailingComma, parseParam("--long, Help")); | 214 | testing.expectError(error.TrailingComma, parseParam("--long, Help")); |
| 201 | testing.expectError(error.TrailingComma, parseParam("--long=value, Help")); | ||
| 202 | testing.expectError(error.NoParamFound, parseParam("-s, Help")); | 215 | testing.expectError(error.NoParamFound, parseParam("-s, Help")); |
| 203 | testing.expectError(error.TrailingComma, parseParam("-s=value, Help")); | ||
| 204 | testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); | 216 | testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); |
| 205 | testing.expectError(error.InvalidShortParam, parseParam("-ss=value Help")); | 217 | testing.expectError(error.InvalidShortParam, parseParam("-ss <value> Help")); |
| 206 | testing.expectError(error.InvalidShortParam, parseParam("- Help")); | 218 | testing.expectError(error.InvalidShortParam, parseParam("- Help")); |
| 207 | } | 219 | } |
| 208 | 220 | ||
| 221 | fn find(str: []const u8, f: []const u8) []const u8 { | ||
| 222 | const i = mem.indexOf(u8, str, f).?; | ||
| 223 | return str[i..][0..f.len]; | ||
| 224 | } | ||
| 209 | 225 | ||
| 210 | 226 | ||
| 211 | /// Will print a help message in the following format: | 227 | /// Will print a help message in the following format: |
| 212 | /// -s, --long=value_text help_text | 228 | /// -s, --long <value_text> help_text |
| 213 | /// -s, help_text | 229 | /// -s, help_text |
| 214 | /// -s=value_text help_text | 230 | /// -s <value_text> help_text |
| 215 | /// --long help_text | 231 | /// --long help_text |
| 216 | /// --long=value_text help_text | 232 | /// --long <value_text> help_text |
| 217 | pub fn helpFull( | 233 | pub fn helpFull( |
| 218 | stream: var, | 234 | stream: var, |
| 219 | comptime Id: type, | 235 | comptime Id: type, |
| @@ -270,7 +286,7 @@ fn printParam( | |||
| 270 | try stream.print("--{}", l); | 286 | try stream.print("--{}", l); |
| 271 | } | 287 | } |
| 272 | if (param.takes_value) | 288 | if (param.takes_value) |
| 273 | try stream.print("={}", value_text(context, param)); | 289 | try stream.print(" <{}>", value_text(context, param)); |
| 274 | } | 290 | } |
| 275 | 291 | ||
| 276 | /// A wrapper around helpFull for simple help_text and value_text functions that | 292 | /// A wrapper around helpFull for simple help_text and value_text functions that |
| @@ -333,12 +349,12 @@ test "clap.help" { | |||
| 333 | try help( | 349 | try help( |
| 334 | &slice_stream.stream, | 350 | &slice_stream.stream, |
| 335 | comptime [_]Param(Help){ | 351 | comptime [_]Param(Help){ |
| 336 | parseParam("-a Short flag. ") catch unreachable, | 352 | parseParam("-a Short flag. ") catch unreachable, |
| 337 | parseParam("-b=V1 Short option.") catch unreachable, | 353 | parseParam("-b <V1> Short option.") catch unreachable, |
| 338 | parseParam("--aa Long flag. ") catch unreachable, | 354 | parseParam("--aa Long flag. ") catch unreachable, |
| 339 | parseParam("--bb=V2 Long option. ") catch unreachable, | 355 | parseParam("--bb <V2> Long option. ") catch unreachable, |
| 340 | parseParam("-c, --cc Both flag. ") catch unreachable, | 356 | parseParam("-c, --cc Both flag. ") catch unreachable, |
| 341 | parseParam("-d, --dd=V3 Both option. ") catch unreachable, | 357 | parseParam("-d, --dd <V3> Both option. ") catch unreachable, |
| 342 | Param(Help){ | 358 | Param(Help){ |
| 343 | .id = Help{ | 359 | .id = Help{ |
| 344 | .msg = "Positional. This should not appear in the help message.", | 360 | .msg = "Positional. This should not appear in the help message.", |
| @@ -349,12 +365,12 @@ test "clap.help" { | |||
| 349 | ); | 365 | ); |
| 350 | 366 | ||
| 351 | const expected = "" ++ | 367 | const expected = "" ++ |
| 352 | "\t-a \tShort flag.\n" ++ | 368 | "\t-a \tShort flag.\n" ++ |
| 353 | "\t-b=V1 \tShort option.\n" ++ | 369 | "\t-b <V1> \tShort option.\n" ++ |
| 354 | "\t --aa \tLong flag.\n" ++ | 370 | "\t --aa \tLong flag.\n" ++ |
| 355 | "\t --bb=V2\tLong option.\n" ++ | 371 | "\t --bb <V2>\tLong option.\n" ++ |
| 356 | "\t-c, --cc \tBoth flag.\n" ++ | 372 | "\t-c, --cc \tBoth flag.\n" ++ |
| 357 | "\t-d, --dd=V3\tBoth option.\n"; | 373 | "\t-d, --dd <V3>\tBoth option.\n"; |
| 358 | 374 | ||
| 359 | const actual = slice_stream.getWritten(); | 375 | const actual = slice_stream.getWritten(); |
| 360 | if (!mem.eql(u8, actual, expected)) { | 376 | if (!mem.eql(u8, actual, expected)) { |
diff --git a/example/comptime-clap.zig b/example/comptime-clap.zig index 5df215b..8e0eb12 100644 --- a/example/comptime-clap.zig +++ b/example/comptime-clap.zig | |||
| @@ -9,8 +9,8 @@ pub fn main() !void { | |||
| 9 | // First we specify what parameters our program can take. | 9 | // First we specify what parameters our program can take. |
| 10 | // We can use `parseParam` to parse a string to a `Param(Help)` | 10 | // We can use `parseParam` to parse a string to a `Param(Help)` |
| 11 | const params = comptime [_]clap.Param(clap.Help){ | 11 | const params = comptime [_]clap.Param(clap.Help){ |
| 12 | clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, | 12 | clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, |
| 13 | clap.parseParam("-n, --number=NUM An option parameter, which takes a value.") catch unreachable, | 13 | clap.parseParam("-n, --number <NUM> An option parameter, which takes a value.") catch unreachable, |
| 14 | clap.Param(clap.Help){ | 14 | clap.Param(clap.Help){ |
| 15 | .takes_value = true, | 15 | .takes_value = true, |
| 16 | }, | 16 | }, |
diff --git a/src/comptime.zig b/src/comptime.zig index 8fd3c1d..f5c2762 100644 --- a/src/comptime.zig +++ b/src/comptime.zig | |||
| @@ -114,9 +114,9 @@ pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) | |||
| 114 | 114 | ||
| 115 | test "clap.comptime.ComptimeClap" { | 115 | test "clap.comptime.ComptimeClap" { |
| 116 | const Clap = ComptimeClap(clap.Help, comptime [_]clap.Param(clap.Help){ | 116 | const Clap = ComptimeClap(clap.Help, comptime [_]clap.Param(clap.Help){ |
| 117 | clap.parseParam("-a, --aa ") catch unreachable, | 117 | clap.parseParam("-a, --aa ") catch unreachable, |
| 118 | clap.parseParam("-b, --bb ") catch unreachable, | 118 | clap.parseParam("-b, --bb ") catch unreachable, |
| 119 | clap.parseParam("-c, --cc=V") catch unreachable, | 119 | clap.parseParam("-c, --cc <V>") catch unreachable, |
| 120 | clap.Param(clap.Help){ | 120 | clap.Param(clap.Help){ |
| 121 | .takes_value = true, | 121 | .takes_value = true, |
| 122 | }, | 122 | }, |