mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-14 14:03:58 +00:00
Add string sub --end
(#6765)
This commit is contained in:
parent
979d3a18aa
commit
a3436110c1
5 changed files with 76 additions and 3 deletions
|
@ -7,6 +7,7 @@
|
|||
|
||||
### Scripting improvements
|
||||
- Range limits in index range expansions like `$x[$start..$end]` may be omitted: `$start` and `$end` default to 1 and -1 (the last item) respectively.
|
||||
- `string sub` has a new `--end` option to specify the end index of a substring (#6765).
|
||||
|
||||
### Interactive improvements
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Synopsis
|
|||
|
||||
::
|
||||
|
||||
string sub [(-s | --start) START] [(-l | --length) LENGTH] [(-q | --quiet)] [STRING...]
|
||||
string sub [(-s | --start) START] [(-e | --end) END] [(-l | --length) LENGTH] [(-q | --quiet)] [STRING...]
|
||||
|
||||
.. END SYNOPSIS
|
||||
|
||||
|
@ -17,7 +17,7 @@ Description
|
|||
|
||||
.. BEGIN DESCRIPTION
|
||||
|
||||
``string sub`` prints a substring of each string argument. The start of the substring can be specified with ``-s`` or ``--start`` followed by a 1-based index value. Positive index values are relative to the start of the string and negative index values are relative to the end of the string. The default start value is 1. The length of the substring can be specified with ``-l`` or ``--length``. If the length is not specified, the substring continues to the end of each STRING. Exit status: 0 if at least one substring operation was performed, 1 otherwise.
|
||||
``string sub`` prints a substring of each string argument. The start/end of the substring can be specified with ``-s``/``-e`` or ``--start``/``--end`` followed by a 1-based index value. Positive index values are relative to the start of the string and negative index values are relative to the end of the string. The default start value is 1. The length of the substring can be specified with ``-l`` or ``--length``. If the length or end is not specified, the substring continues to the end of each STRING. Exit status: 0 if at least one substring operation was performed, 1 otherwise. ``--length`` is mutually exclusive with ``--end``.
|
||||
|
||||
.. END DESCRIPTION
|
||||
|
||||
|
@ -37,4 +37,16 @@ Examples
|
|||
>_ string sub --start=-2 abcde
|
||||
de
|
||||
|
||||
>_ string sub --end=3 abcde
|
||||
abc
|
||||
|
||||
>_ string sub -e -1 abcde
|
||||
abcd
|
||||
|
||||
>_ string sub -s 2 -e -1 abcde
|
||||
bcd
|
||||
|
||||
>_ string sub -s -3 -e -2 abcde
|
||||
c
|
||||
|
||||
.. END EXAMPLES
|
||||
|
|
|
@ -8,6 +8,7 @@ complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a upper
|
|||
complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a length
|
||||
complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a sub
|
||||
complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s s -l start -xa "(seq 1 10)"
|
||||
complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s e -l end -xa "(seq 1 10)"
|
||||
complete -x -c string -n "test (count (commandline -opc)) -ge 2; and contains -- (commandline -opc)[2] sub" -s l -l length -xa "(seq 1 10)"
|
||||
complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a split
|
||||
complete -f -c string -n "test (count (commandline -opc)) -lt 2" -a split0
|
||||
|
|
|
@ -151,6 +151,7 @@ typedef struct { //!OCLINT(too many fields)
|
|||
bool regex_valid = false;
|
||||
bool right_valid = false;
|
||||
bool start_valid = false;
|
||||
bool end_valid = false;
|
||||
bool style_valid = false;
|
||||
bool no_empty_valid = false;
|
||||
bool no_trim_newlines_valid = false;
|
||||
|
@ -174,6 +175,7 @@ typedef struct { //!OCLINT(too many fields)
|
|||
long length = 0;
|
||||
long max = 0;
|
||||
long start = 0;
|
||||
long end = 0;
|
||||
|
||||
const wchar_t *chars_to_trim = L" \f\n\r\t";
|
||||
const wchar_t *arg1 = nullptr;
|
||||
|
@ -242,7 +244,17 @@ static int handle_flag_c(wchar_t **argv, parser_t &parser, io_streams_t &streams
|
|||
|
||||
static int handle_flag_e(wchar_t **argv, parser_t &parser, io_streams_t &streams,
|
||||
const wgetopter_t &w, options_t *opts) {
|
||||
if (opts->entire_valid) {
|
||||
if (opts->end_valid) {
|
||||
opts->end = fish_wcstol(w.woptarg);
|
||||
if (opts->end == 0 || opts->end == LONG_MIN || errno == ERANGE) {
|
||||
string_error(streams, _(L"%ls: Invalid end 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;
|
||||
}
|
||||
return STATUS_CMD_OK;
|
||||
} else if (opts->entire_valid) {
|
||||
opts->entire = true;
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
@ -408,6 +420,7 @@ static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath co
|
|||
if (opts->regex_valid) short_opts.append(L"r");
|
||||
if (opts->right_valid) short_opts.append(L"r");
|
||||
if (opts->start_valid) short_opts.append(L"s:");
|
||||
if (opts->end_valid) short_opts.append(L"e:");
|
||||
if (opts->no_empty_valid) short_opts.append(L"n");
|
||||
if (opts->no_trim_newlines_valid) short_opts.append(L"N");
|
||||
return short_opts;
|
||||
|
@ -420,6 +433,7 @@ static const struct woption long_options[] = {{L"all", no_argument, nullptr, 'a'
|
|||
{L"chars", required_argument, nullptr, 'c'},
|
||||
{L"count", required_argument, nullptr, 'n'},
|
||||
{L"entire", no_argument, nullptr, 'e'},
|
||||
{L"end", required_argument, nullptr, 'e'},
|
||||
{L"filter", no_argument, nullptr, 'f'},
|
||||
{L"ignore-case", no_argument, nullptr, 'i'},
|
||||
{L"index", no_argument, nullptr, 'n'},
|
||||
|
@ -1201,21 +1215,31 @@ static int string_repeat(parser_t &parser, io_streams_t &streams, int argc, wcha
|
|||
}
|
||||
|
||||
static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t **argv) {
|
||||
wchar_t *cmd = argv[0];
|
||||
|
||||
options_t opts;
|
||||
opts.length_valid = true;
|
||||
opts.quiet_valid = true;
|
||||
opts.start_valid = true;
|
||||
opts.end_valid = true;
|
||||
opts.length = -1;
|
||||
int optind;
|
||||
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
|
||||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.length != -1 && opts.end != 0) {
|
||||
streams.err.append_format(BUILTIN_ERR_COMBO2, cmd,
|
||||
_(L"--end and --length are mutually exclusive"));
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
int nsub = 0;
|
||||
arg_iterator_t aiter(argv, optind, streams);
|
||||
while (const wcstring *s = aiter.nextstr()) {
|
||||
using size_type = wcstring::size_type;
|
||||
size_type pos = 0;
|
||||
size_type count = wcstring::npos;
|
||||
|
||||
if (opts.start > 0) {
|
||||
pos = static_cast<size_type>(opts.start - 1);
|
||||
} else if (opts.start < 0) {
|
||||
|
@ -1223,12 +1247,23 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
|
|||
size_type n = static_cast<size_type>(-opts.start);
|
||||
pos = n > s->length() ? 0 : s->length() - n;
|
||||
}
|
||||
|
||||
if (pos > s->length()) {
|
||||
pos = s->length();
|
||||
}
|
||||
|
||||
if (opts.length >= 0) {
|
||||
count = static_cast<size_type>(opts.length);
|
||||
} else if (opts.end != 0) {
|
||||
size_type n;
|
||||
if (opts.end > 0) {
|
||||
n = static_cast<size_type>(opts.end);
|
||||
} else {
|
||||
assert(opts.end != LONG_MIN); // checked above
|
||||
n = static_cast<size_type>(-opts.end);
|
||||
n = n > s->length() ? 0 : s->length() - n;
|
||||
}
|
||||
count = n < pos ? 0 : n - pos;
|
||||
}
|
||||
|
||||
// Note that std::string permits count to extend past end of string.
|
||||
|
|
|
@ -51,6 +51,30 @@ string sub -s 2 -l 2 abcde
|
|||
string sub --start=-2 abcde
|
||||
# CHECK: de
|
||||
|
||||
string sub --end=3 abcde
|
||||
# CHECK: abc
|
||||
|
||||
string sub --end=-4 abcde
|
||||
# CHECK: a
|
||||
|
||||
string sub --start=2 --end=-2 abcde
|
||||
# CHECK: bc
|
||||
|
||||
string sub -s -5 -e -2 abcdefgh
|
||||
# CHECK: def
|
||||
|
||||
string sub -s -100 -e -2 abcde
|
||||
# CHECK: abc
|
||||
|
||||
string sub -s -5 -e 2 abcde
|
||||
# CHECK: ab
|
||||
|
||||
string sub -s -50 -e -100 abcde
|
||||
# CHECK:
|
||||
|
||||
string sub -s 2 -e -5 abcde
|
||||
# CHECK:
|
||||
|
||||
string split . example.com
|
||||
# CHECK: example
|
||||
# CHECK: com
|
||||
|
|
Loading…
Reference in a new issue