mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-29 06:13:20 +00:00
builtin_string: implement "width" argument for "string pad"
This commit is contained in:
parent
bfa699c556
commit
2afa354c14
2 changed files with 47 additions and 66 deletions
|
@ -158,6 +158,7 @@ using options_t = struct options_t { //!OCLINT(too many fields)
|
||||||
bool no_trim_newlines_valid = false;
|
bool no_trim_newlines_valid = false;
|
||||||
bool fields_valid = false;
|
bool fields_valid = false;
|
||||||
bool allow_empty_valid = false;
|
bool allow_empty_valid = false;
|
||||||
|
bool width_valid = false;
|
||||||
|
|
||||||
bool all = false;
|
bool all = false;
|
||||||
bool entire = false;
|
bool entire = false;
|
||||||
|
@ -180,6 +181,7 @@ using options_t = struct options_t { //!OCLINT(too many fields)
|
||||||
long max = 0;
|
long max = 0;
|
||||||
long start = 0;
|
long start = 0;
|
||||||
long end = 0;
|
long end = 0;
|
||||||
|
size_t width = 0;
|
||||||
|
|
||||||
wchar_t char_to_pad = ' ';
|
wchar_t char_to_pad = ' ';
|
||||||
|
|
||||||
|
@ -461,6 +463,25 @@ static int handle_flag_v(wchar_t **argv, parser_t &parser, io_streams_t &streams
|
||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_flag_w(wchar_t **argv, parser_t &parser, io_streams_t &streams,
|
||||||
|
const wgetopter_t &w, options_t *opts) {
|
||||||
|
long width = 0;
|
||||||
|
if (opts->width_valid) {
|
||||||
|
width = fish_wcstol(w.woptarg);
|
||||||
|
if (width < 0) {
|
||||||
|
string_error(streams, _(L"%ls: Invalid width value '%ls'\n"), argv[0], w.woptarg);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
} else if (errno) {
|
||||||
|
string_error(streams, BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
opts->width = static_cast<size_t>(width);
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
}
|
||||||
|
string_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||||
|
return STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
/// This constructs the wgetopt() short options string based on which arguments are valid for the
|
/// This constructs the wgetopt() short options string based on which arguments are valid for the
|
||||||
/// subcommand. We have to do this because many short flags have multiple meanings and may or may
|
/// subcommand. We have to do this because many short flags have multiple meanings and may or may
|
||||||
/// not require an argument depending on the meaning.
|
/// not require an argument depending on the meaning.
|
||||||
|
@ -489,6 +510,7 @@ static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath co
|
||||||
if (opts->no_trim_newlines_valid) short_opts.append(L"N");
|
if (opts->no_trim_newlines_valid) short_opts.append(L"N");
|
||||||
if (opts->fields_valid) short_opts.append(L"f:");
|
if (opts->fields_valid) short_opts.append(L"f:");
|
||||||
if (opts->allow_empty_valid) short_opts.append(L"a");
|
if (opts->allow_empty_valid) short_opts.append(L"a");
|
||||||
|
if (opts->width_valid) short_opts.append(L"w:");
|
||||||
return short_opts;
|
return short_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,13 +540,14 @@ static const struct woption long_options[] = {{L"all", no_argument, nullptr, 'a'
|
||||||
{L"no-trim-newlines", no_argument, nullptr, 'N'},
|
{L"no-trim-newlines", no_argument, nullptr, 'N'},
|
||||||
{L"fields", required_argument, nullptr, 'f'},
|
{L"fields", required_argument, nullptr, 'f'},
|
||||||
{L"allow-empty", no_argument, nullptr, 'a'},
|
{L"allow-empty", no_argument, nullptr, 'a'},
|
||||||
|
{L"width", required_argument, nullptr, 'w'},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
static const std::unordered_map<char, decltype(*handle_flag_N)> flag_to_function = {
|
static const std::unordered_map<char, decltype(*handle_flag_N)> flag_to_function = {
|
||||||
{'N', handle_flag_N}, {'a', handle_flag_a}, {'c', handle_flag_c}, {'e', handle_flag_e},
|
{'N', handle_flag_N}, {'a', handle_flag_a}, {'c', handle_flag_c}, {'e', handle_flag_e},
|
||||||
{'f', handle_flag_f}, {'i', handle_flag_i}, {'l', handle_flag_l}, {'m', handle_flag_m},
|
{'f', handle_flag_f}, {'i', handle_flag_i}, {'l', handle_flag_l}, {'m', handle_flag_m},
|
||||||
{'n', handle_flag_n}, {'q', handle_flag_q}, {'r', handle_flag_r}, {'s', handle_flag_s},
|
{'n', handle_flag_n}, {'q', handle_flag_q}, {'r', handle_flag_r}, {'s', handle_flag_s},
|
||||||
{'v', handle_flag_v}, {1, handle_flag_1}};
|
{'v', handle_flag_v}, {'w', handle_flag_w}, {1, handle_flag_1}};
|
||||||
|
|
||||||
/// Parse the arguments for flags recognized by a specific string subcommand.
|
/// Parse the arguments for flags recognized by a specific string subcommand.
|
||||||
static int parse_opts(options_t *opts, int *optind, int n_req_args, int argc, wchar_t **argv,
|
static int parse_opts(options_t *opts, int *optind, int n_req_args, int argc, wchar_t **argv,
|
||||||
|
@ -949,74 +972,38 @@ static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar
|
||||||
}
|
}
|
||||||
|
|
||||||
static int string_pad(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
|
static int string_pad(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
|
||||||
wchar_t *cmd = argv[0];
|
|
||||||
|
|
||||||
options_t opts;
|
options_t opts;
|
||||||
opts.char_to_pad_valid = true;
|
opts.char_to_pad_valid = true;
|
||||||
opts.count_valid = true;
|
|
||||||
opts.max_valid = true;
|
|
||||||
opts.left_valid = true;
|
|
||||||
opts.right_valid = true;
|
opts.right_valid = true;
|
||||||
|
opts.width_valid = true;
|
||||||
int optind;
|
int optind;
|
||||||
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
|
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
|
||||||
if (retval != STATUS_CMD_OK) return retval;
|
if (retval != STATUS_CMD_OK) return retval;
|
||||||
|
|
||||||
// If neither left or right is specified, we pad only on the left.
|
// Pad left by default
|
||||||
if (!opts.left && !opts.right) {
|
if (!opts.right) {
|
||||||
opts.left = true;
|
opts.left = true;
|
||||||
opts.right = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If both count and max is specified, we raise an error.
|
|
||||||
if (opts.count && opts.max) {
|
|
||||||
streams.err.append_format(BUILTIN_ERR_COMBO2, cmd,
|
|
||||||
_(L"--count and --max are mutually exclusive"));
|
|
||||||
return STATUS_INVALID_ARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t npad = 0;
|
|
||||||
|
|
||||||
arg_iterator_t aiter(argv, optind, streams);
|
arg_iterator_t aiter(argv, optind, streams);
|
||||||
while (const wcstring *arg = aiter.nextstr()) {
|
while (const wcstring *arg = aiter.nextstr()) {
|
||||||
wcstring padded = *arg;
|
wcstring padded = *arg;
|
||||||
size_t pad_left = 0;
|
if (opts.width >= padded.size()) {
|
||||||
size_t pad_right = 0;
|
size_t pad = opts.width - padded.size();
|
||||||
|
if (opts.left) {
|
||||||
if (opts.count && opts.right) {
|
padded.insert(0, pad, opts.char_to_pad);
|
||||||
pad_right = opts.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.count && opts.left) {
|
|
||||||
pad_left = opts.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.max >= padded.size()) {
|
|
||||||
if (opts.left && opts.right) {
|
|
||||||
// pad_left will get one more character
|
|
||||||
pad_left = (opts.max - padded.size() + 1) / 2;
|
|
||||||
pad_right = (opts.max - padded.size()) / 2;
|
|
||||||
}
|
}
|
||||||
|
if (opts.right) {
|
||||||
if (!opts.left && opts.right) {
|
padded.append(pad, opts.char_to_pad);
|
||||||
pad_right = opts.max - padded.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.left && !opts.right) {
|
|
||||||
pad_left = opts.max - padded.size();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
padded.insert(0, pad_left, opts.char_to_pad);
|
|
||||||
padded.append(pad_right, opts.char_to_pad);
|
|
||||||
|
|
||||||
npad += padded.size();
|
|
||||||
if (!opts.quiet) {
|
if (!opts.quiet) {
|
||||||
streams.out.append(padded);
|
streams.out.append(padded);
|
||||||
streams.out.append(L'\n');
|
streams.out.append(L'\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return npad > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR;
|
return STATUS_CMD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
class string_replacer_t {
|
class string_replacer_t {
|
||||||
|
|
|
@ -42,26 +42,20 @@ string length "hello, world"
|
||||||
string length -q ""; and echo not zero length; or echo zero length
|
string length -q ""; and echo not zero length; or echo zero length
|
||||||
# CHECK: zero length
|
# CHECK: zero length
|
||||||
|
|
||||||
string pad -l foo
|
string pad foo
|
||||||
# CHECK: foo
|
# CHECK: foo
|
||||||
|
|
||||||
string pad -l -n 2 foo
|
string pad -r -w 4 foo
|
||||||
# CHECK: foo
|
# CHECK: foo
|
||||||
|
|
||||||
string pad -r -n 4 -c '-' foo
|
string pad -r -w 7 -c '-' foo
|
||||||
# CHECK: foo----
|
# CHECK: foo----
|
||||||
|
|
||||||
string pad --left --right -n 2 -c '=' foo
|
string pad --width 7 -c '=' foo
|
||||||
# CHECK: ==foo==
|
# CHECK: ====foo
|
||||||
|
|
||||||
string pad --left -m 4 -c '=' foo
|
string pad --width 10 --right foo
|
||||||
# CHECK: =foo
|
# CHECK: foo
|
||||||
|
|
||||||
string pad --left --right -m 6 --chars '=' foo
|
|
||||||
# CHECK: ==foo=
|
|
||||||
|
|
||||||
string pad --left --right -m 7 --chars '-' bar
|
|
||||||
# CHECK: --bar--
|
|
||||||
|
|
||||||
string sub --length 2 abcde
|
string sub --length 2 abcde
|
||||||
# CHECK: ab
|
# CHECK: ab
|
||||||
|
|
Loading…
Reference in a new issue