Skip to content

Commit

Permalink
Implemented Abbreviated Commands
Browse files Browse the repository at this point in the history
- Added `allow_abbreviated_cmds` and `abbreviated_min_len` to the Command Config.
- Updated `cova.parseCtx()` to enable Command Abbreviations in a similar fashion to the `ip` program on Linux.
  • Loading branch information
00JCIV00 committed Dec 1, 2024
1 parent 894173a commit 3abd6f9
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
1 change: 1 addition & 0 deletions examples/covademo.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub const CommandT = Command.Custom(.{
.global_help_prefix = "CovaDemo",
.global_vals_mandatory = false,
.help_category_order = &.{ .Prefix, .Header, .Aliases, .Values, .Options, .Commands },
.allow_abbreviated_cmds = true,
//.allow_arg_indices = false,
.global_usage_fn = struct{
fn usage(self: anytype, writer: anytype, _: ?mem.Allocator) !void {
Expand Down
12 changes: 12 additions & 0 deletions src/Command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ pub const Config = struct {
/// During parsing, mandate that Command instances of this Command Type, and their aliases, must be used in a case-sensitive manner.
/// This will also affect Command Validation, but will NOT affect Tab-Completion.
global_case_sensitive: bool = true,
/// During parsing, allow Abbreviated Command Names. (i.e. 'com' working for 'command')
/// This is seen in programs like `ip` on Linux, but may not be ideal in every use case.
/// Note, this does not check for uniqueness and will simply match on the first Command matching the abbreviation.
allow_abbreviated_cmds: bool = false,
/// The minimum length for an Abbreviated Command Name.
abbreviated_min_len: u16 = 3,


/// Help Categories.
Expand Down Expand Up @@ -320,6 +326,12 @@ pub fn Custom(comptime config: Config) type {
/// Include Examples.
/// Check (`Command.Config`) for details.
pub const include_examples = config.include_examples;
/// Allow Abbreviated Commands.
/// Check (`Command.Config`) for details.
pub const allow_abbreviated_cmds = config.allow_abbreviated_cmds;
/// The minimum length for an Abbreviated Command Name.
/// Check (`Command.Config`) for details.
pub const abbreviated_min_len = config.abbreviated_min_len;


/// The Root Allocator for this Command.
Expand Down
27 changes: 24 additions & 3 deletions src/cova.zig
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,26 @@ fn parseArgsCtx(
checkCmds: for (cmds) |*sub_cmd| {
const should_parse = shouldParse: {
if (sub_cmd.case_sensitive) {
if (mem.eql(u8, sub_cmd.name, arg)) break :shouldParse true
else for (sub_cmd.alias_names orelse continue :checkCmds) |alias| if (mem.eql(u8, alias, arg)) break :shouldParse true;
if (
mem.eql(u8, sub_cmd.name, arg) or
(
CommandT.allow_abbreviated_cmds and
arg.len >= @min(sub_cmd.name.len, CommandT.abbreviated_min_len) and
mem.indexOf(u8, sub_cmd.name, arg) != null and sub_cmd.name[0] == arg[0]
)
) break :shouldParse true
else {
for (sub_cmd.alias_names orelse continue :checkCmds) |alias| {
if (
mem.eql(u8, alias, arg) or
(
CommandT.allow_abbreviated_cmds and
arg.len >= @min(alias.len, CommandT.abbreviated_min_len) and
mem.indexOf(u8, alias, arg) != null and alias[0] == arg[0]
)
) break :shouldParse true;
}
}
}
else {
if (ascii.eqlIgnoreCase(sub_cmd.name, arg)) break :shouldParse true
Expand Down Expand Up @@ -436,7 +454,10 @@ fn parseArgsCtx(
if (matchOpt: {
break :matchOpt if (opt.case_sensitive)
mem.eql(u8, long_opt, long_name) or
(OptionT.allow_abbreviated_long_opts and mem.indexOf(u8, long_name, long_opt) != null and long_name[0] == long_opt[0])
(
OptionT.allow_abbreviated_long_opts and
mem.indexOf(u8, long_name, long_opt) != null and long_name[0] == long_opt[0]
)
else
ascii.eqlIgnoreCase(long_opt, long_name) or
(
Expand Down

0 comments on commit 3abd6f9

Please sign in to comment.