builtin_string: add pad command

This commit is contained in:
Andrew Prokhorenkov 2020-06-17 23:11:03 -05:00 committed by ridiculousfish
parent d8e2cac83e
commit c8e1894c72
2 changed files with 98 additions and 4 deletions

View file

@ -0,0 +1,42 @@
string-pad - pad characters before and after string
========================================
Synopsis
--------
.. BEGIN SYNOPSIS
::
string pad [(-l | --left)] [(-r | --right)] [(-c | --char) CHAR] [(-n | --count) INTEGER] [(-q | --quiet)] [STRING...]
.. END SYNOPSIS
Description
-----------
.. BEGIN DESCRIPTION
``string pad`` pads before and after the string specified character for each STRING. If ``-l`` or ``--left`` is given, only padded before string. Left only is the default padding. If ``-r`` or ``--right`` is given, only padded after string. The ``-c`` or ``--char`` switch causes the characters in CHAR to be padded instead of whitespace. The ``-n`` or ``--count`` integer specifies the amount of characters to be padded. The default padding count is 0. Exit status: 0 if string was padded, or 1 otherwise.
.. END DESCRIPTION
Examples
--------
.. BEGIN EXAMPLES
::
>_ string pad -l -n 10 -c ' ' 'abc'
abc
>_ string pad --right --count 5 --char=z foo bar
foozzzzz
barzzzzz
>_ string pad --left --right -n 5 --char=- foo
-----foo-----
.. END EXAMPLES

View file

@ -135,7 +135,8 @@ class arg_iterator_t {
// valid and get the result of parsing the command for flags.
using options_t = struct options_t { //!OCLINT(too many fields)
bool all_valid = false;
bool chars_valid = false;
bool char_to_pad_valid = false;
bool chars_to_trim_valid = false;
bool count_valid = false;
bool entire_valid = false;
bool filter_valid = false;
@ -180,6 +181,8 @@ using options_t = struct options_t { //!OCLINT(too many fields)
long start = 0;
long end = 0;
wchar_t char_to_pad = ' ';
std::vector<int> fields;
const wchar_t *chars_to_trim = L" \f\n\r\t\v";
@ -242,9 +245,16 @@ static int handle_flag_a(wchar_t **argv, parser_t &parser, io_streams_t &streams
static int handle_flag_c(wchar_t **argv, parser_t &parser, io_streams_t &streams,
const wgetopter_t &w, options_t *opts) {
if (opts->chars_valid) {
if (opts->chars_to_trim_valid) {
opts->chars_to_trim = w.woptarg;
return STATUS_CMD_OK;
} else if (opts->char_to_pad_valid) {
if (wcslen(w.woptarg) != 1) {
string_error(streams, _(L"%ls: Padding should be a character '%ls'\n"), argv[0], w.woptarg);
return STATUS_INVALID_ARGS;
}
opts->char_to_pad = w.woptarg[0];
return STATUS_CMD_OK;
}
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
@ -457,7 +467,8 @@ static int handle_flag_v(wchar_t **argv, parser_t &parser, io_streams_t &streams
static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath complexity)
wcstring short_opts(L":");
if (opts->all_valid) short_opts.append(L"a");
if (opts->chars_valid) short_opts.append(L"c:");
if (opts->char_to_pad_valid) short_opts.append(L"c:");
if (opts->chars_to_trim_valid) short_opts.append(L"c:");
if (opts->count_valid) short_opts.append(L"n:");
if (opts->entire_valid) short_opts.append(L"e");
if (opts->filter_valid) short_opts.append(L"f");
@ -1245,6 +1256,46 @@ static int string_collect(parser_t &parser, io_streams_t &streams, int argc, wch
return appended > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR;
}
static int string_pad(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
options_t opts;
opts.char_to_pad_valid = true;
opts.count_valid = true;
opts.left_valid = true;
opts.right_valid = true;
opts.quiet_valid = true;
int optind;
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
if (retval != STATUS_CMD_OK) return retval;
// If neither left or right is specified, we pad only on the left.
if (!opts.left && !opts.right) {
opts.left = true;
opts.right = false;
}
size_t npad = 0;
arg_iterator_t aiter(argv, optind, streams);
while (const wcstring *arg = aiter.nextstr()) {
size_t begin = 0, end = arg->size();
wcstring padded_arg = wcstring(*arg, 0, arg->size());
if (opts.right) {
padded_arg.append(opts.count, opts.char_to_pad);
}
if (opts.left) {
padded_arg.insert(0, opts.count, opts.char_to_pad);
}
// assert(begin <= end && end <= arg->size());
npad += arg->size() - (end - begin);
if (!opts.quiet) {
streams.out.append(padded_arg);
streams.out.append(L'\n');
}
}
return npad > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR;
}
// Helper function to abstract the repeat logic from string_repeat
// returns the to_repeat string, repeated count times.
static wcstring wcsrepeat(const wcstring &to_repeat, size_t count) {
@ -1363,7 +1414,7 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
options_t opts;
opts.chars_valid = true;
opts.chars_to_trim_valid = true;
opts.left_valid = true;
opts.right_valid = true;
opts.quiet_valid = true;
@ -1448,6 +1499,7 @@ string_subcommands[] = {
{L"split", &string_split}, {L"split0", &string_split0}, {L"sub", &string_sub},
{L"trim", &string_trim}, {L"lower", &string_lower}, {L"upper", &string_upper},
{L"repeat", &string_repeat}, {L"unescape", &string_unescape}, {L"collect", &string_collect},
{L"pad", &string_pad},
{nullptr, nullptr}};
/// The string builtin, for manipulating strings.