Stop printing help summary on error

This now displays

- the error message

- a (significantly shorter) backtrace

- A call to open `help $cmd` if necessary

See #5434.
Fixes #3404.
This commit is contained in:
Fabian Homborg 2019-03-26 19:13:01 +01:00
parent 88a935d8d1
commit 88d2d54276
15 changed files with 71 additions and 132 deletions

View file

@ -187,92 +187,29 @@ wcstring builtin_help_get(parser_t &parser, io_streams_t &streams, const wchar_t
///
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
output_stream_t &b) {
bool is_stderr = &b == &streams.err;
if (is_stderr) {
b.append(parser.current_line());
}
const wcstring h = builtin_help_get(parser, streams, cmd);
if (!h.size()) return;
wchar_t *str = wcsdup(h.c_str());
if (str) {
bool is_short = false;
if (is_stderr) {
// Interactive mode help to screen - only print synopsis if the rest won't fit.
int screen_height, my_lines;
screen_height = common_get_height();
my_lines = count_char(str, L'\n');
if (!shell_is_interactive() || (my_lines > 2 * screen_height / 3)) {
wchar_t *pos;
int cut = 0;
int i;
is_short = true;
// First move down 4 lines.
pos = str;
for (i = 0; (i < 4) && pos && *pos; i++) {
pos = std::wcschr(pos + 1, L'\n');
}
if (pos && *pos) {
// Then find the next empty line.
for (; *pos; pos++) {
if (*pos != L'\n') {
continue;
}
int is_empty = 1;
wchar_t *pos2;
for (pos2 = pos + 1; *pos2; pos2++) {
if (*pos2 == L'\n') break;
if (*pos2 != L'\t' && *pos2 != L' ') {
is_empty = 0;
break;
}
}
if (is_empty) {
// And cut it.
*(pos2 + 1) = L'\0';
cut = 1;
break;
}
}
}
// We did not find a good place to cut message to shorten it - so we make sure we
// don't print anything.
if (!cut) {
*str = 0;
}
}
}
b.append(str);
if (is_short) {
b.append_format(_(L"%ls: Type 'help %ls' for related documentation\n\n"), cmd, cmd);
}
free(str);
}
b.append(builtin_help_get(parser, streams, cmd));
}
/// Perform error reporting for encounter with unknown option.
void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
const wchar_t *opt) {
streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, opt);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
}
/// Perform error reporting for encounter with missing argument.
void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
const wchar_t *opt) {
streams.err.append_format(BUILTIN_ERR_MISSING, cmd, opt);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
}
/// Print the backtrace and call for help that we use at the end of error messages.
void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wchar_t *cmd) {
b.append(L"\n");
b.append(parser.current_line());
b.append(L"\n");
b.append_format(_(L"(Type 'help %ls' for related documentation)\n"), cmd);
}
/// A generic bultin that only supports showing a help message. This is only a placeholder that

View file

@ -115,6 +115,8 @@ void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar
void builtin_missing_argument(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
const wchar_t *opt);
void builtin_print_error_trailer(parser_t &parser, output_stream_t &b, const wchar_t *cmd);
void builtin_wperror(const wchar_t *s, io_streams_t &streams);
struct help_only_cmd_opts_t {

View file

@ -548,7 +548,13 @@ static int argparse_parse_flags(parser_t &parser, const argparse_cmd_opts_t &opt
retval = validate_and_store_implicit_int(parser, opts, arg_contents, w, long_idx,
streams);
} else {
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
streams.err.append_format(BUILTIN_ERR_UNKNOWN, cmd, argv[w.woptind - 1]);
// We don't use builtin_print_error_trailer as that
// says to use the cmd help,
// which doesn't work if it's a command that does not belong to fish.
//
// Plus this particular error is not an error in argparse usage.
streams.err.append(parser.current_line());
retval = STATUS_INVALID_ARGS;
}
if (retval != STATUS_CMD_OK) return retval;

View file

@ -196,7 +196,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
streams.err.append(argv[0]);
streams.err.append(L": Can not set commandline in non-interactive mode\n");
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
@ -315,7 +315,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
if (buffer_part || cut_at_cursor || append_mode || tokenize || cursor_mode || line_mode ||
search_mode || paging_mode) {
streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -331,7 +331,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
input_queue_ch(*mc);
} else {
streams.err.append_format(_(L"%ls: Unknown input function '%ls'"), cmd, argv[i]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
}
@ -351,14 +351,14 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
// Check for invalid switch combinations.
if ((search_mode || line_mode || cursor_mode || paging_mode) && (argc - w.woptind > 1)) {
streams.err.append_format(L"%ls: Too many arguments", argv[0]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
if ((buffer_part || tokenize || cut_at_cursor) &&
(cursor_mode || line_mode || search_mode || paging_mode)) {
streams.err.append_format(BUILTIN_ERR_COMBO, argv[0]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -366,7 +366,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
streams.err.append_format(
BUILTIN_ERR_COMBO2, cmd,
L"--cut-at-cursor and --tokenize can not be used when setting the commandline");
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -374,7 +374,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
streams.err.append_format(
BUILTIN_ERR_COMBO2, cmd,
L"insertion mode switches can not be used when not in insertion mode");
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -392,7 +392,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
long new_pos = fish_wcstol(argv[w.woptind]);
if (errno) {
streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[w.woptind]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
}
current_buffer = reader_get_buffer();

View file

@ -270,7 +270,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (w.woptind != argc) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}

View file

@ -19,7 +19,7 @@
static int disown_job(const wchar_t *cmd, parser_t &parser, io_streams_t &streams, job_t *j) {
if (j == 0) {
streams.err.append_format(_(L"%ls: Unknown job '%ls'\n"), L"bg");
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}

View file

@ -73,7 +73,7 @@ int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (optind + 1 < argc) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -84,7 +84,7 @@ int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (errno) {
streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd,
argv[optind]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
}

View file

@ -68,14 +68,14 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), cmd, argv[optind]);
}
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
j = 0;
} else {
int pid = abs(fish_wcstoi(argv[optind]));
if (errno) {
streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[optind]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
} else {
j = job_t::from_pid(pid);
if (!j || !j->is_constructed() || j->is_completed()) {

View file

@ -230,7 +230,7 @@ int builtin_function(parser_t &parser, io_streams_t &streams, const wcstring_lis
if (retval != STATUS_CMD_OK) return retval;
if (opts.print_help) {
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_OK;
}

View file

@ -282,7 +282,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
bool describe = opts.description ? true : false;
if (describe + opts.erase + opts.list + opts.query + opts.copy > 1) {
streams.err.append_format(_(L"%ls: Invalid combination of options\n"), cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -296,14 +296,14 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (argc - optind != 1) {
streams.err.append_format(_(L"%ls: Expected exactly one function name\n"), cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
func = argv[optind];
if (!function_exists(func)) {
streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd, func);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
@ -370,7 +370,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
streams.err.append_format(_(L"%ls: Expected exactly two names (current function name, "
L"and new function name)\n"),
cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
current_func = argv[optind];
@ -379,14 +379,14 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (!function_exists(current_func)) {
streams.err.append_format(_(L"%ls: Function '%ls' does not exist\n"), cmd,
current_func.c_str());
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
if (!valid_func_name(new_func) || parser_keywords_is_reserved(new_func)) {
streams.err.append_format(_(L"%ls: Illegal function name '%ls'\n"), cmd,
new_func.c_str());
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -395,7 +395,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
streams.err.append_format(
_(L"%ls: Function '%ls' already exists. Cannot create copy '%ls'\n"), cmd,
new_func.c_str(), current_func.c_str());
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}

View file

@ -130,13 +130,13 @@ static int parse_cmd_opts(read_cmd_opts_t &opts, int *optind, //!OCLINT(high nc
if (errno == ERANGE) {
streams.err.append_format(_(L"%ls: Argument '%ls' is out of range\n"), cmd,
w.woptarg);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd,
w.woptarg);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
break;
@ -351,7 +351,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
const wchar_t *const *argv, parser_t &parser, io_streams_t &streams) {
if (opts.prompt && opts.prompt_str) {
streams.err.append_format(_(L"%ls: Options %ls and %ls cannot be used together\n"), cmd, L"-p", L"-P");
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -373,7 +373,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
if ((opts.place & ENV_UNEXPORT) && (opts.place & ENV_EXPORT)) {
streams.err.append_format(BUILTIN_ERR_EXPUNEXP, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -381,7 +381,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
(opts.place & ENV_UNIVERSAL ? 1 : 0) >
1) {
streams.err.append_format(BUILTIN_ERR_GLOCAL, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -404,7 +404,7 @@ static int validate_read_args(const wchar_t *cmd, read_cmd_opts_t &opts, int arg
for (int i = 0; i < argc; i++) {
if (!valid_var_name(argv[i])) {
streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, argv[i]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
}

View file

@ -73,7 +73,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (optind + 1 < argc) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -83,7 +83,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
retval = fish_wcstoi(argv[1]);
if (errno) {
streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd, argv[1]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
retval &= 0xFF;
@ -98,7 +98,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (function_block_idx >= parser.block_count()) {
streams.err.append_format(_(L"%ls: Not inside of function\n"), cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}

View file

@ -175,42 +175,42 @@ static int validate_cmd_opts(const wchar_t *cmd, set_cmd_opts_t &opts, //!OCLIN
// Can't query and erase or list.
if (opts.query && (opts.erase || opts.list)) {
streams.err.append_format(BUILTIN_ERR_COMBO, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
// We can't both list and erase variables.
if (opts.erase && opts.list) {
streams.err.append_format(BUILTIN_ERR_COMBO, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
// Variables can only have one scope.
if (opts.local + opts.global + opts.universal > 1) {
streams.err.append_format(BUILTIN_ERR_GLOCAL, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
// Variables can only have one export status.
if (opts.exportv && opts.unexport) {
streams.err.append_format(BUILTIN_ERR_EXPUNEXP, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
// Variables can only have one path status.
if (opts.pathvar && opts.unpathvar) {
streams.err.append_format(BUILTIN_ERR_EXPUNEXP, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
// Trying to erase and (un)export at the same time doesn't make sense.
if (opts.erase && (opts.exportv || opts.unexport)) {
streams.err.append_format(BUILTIN_ERR_COMBO, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -218,13 +218,13 @@ static int validate_cmd_opts(const wchar_t *cmd, set_cmd_opts_t &opts, //!OCLIN
if (opts.show &&
(opts.local || opts.global || opts.erase || opts.list || opts.exportv || opts.universal)) {
streams.err.append_format(BUILTIN_ERR_COMBO, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
if (argc == 0 && opts.erase) {
streams.err.append_format(BUILTIN_SET_ERASE_NO_VAR, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -519,7 +519,7 @@ static int builtin_set_query(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
int idx_count = parse_index(indexes, dest, scope, streams, parser.vars());
if (idx_count == -1) {
free(dest);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
@ -612,7 +612,7 @@ static int builtin_set_show(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
if (std::wcschr(arg, L'[')) {
streams.err.append_format(
_(L"%ls: `set --show` does not allow slices with the var names\n"), cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
@ -631,7 +631,7 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
parser_t &parser, io_streams_t &streams) {
if (argc != 1) {
streams.err.append_format(BUILTIN_ERR_ARG_COUNT2, cmd, L"--erase", 1, argc);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
@ -641,14 +641,14 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
std::vector<long> indexes;
int idx_count = parse_index(indexes, dest, scope, streams, parser.vars());
if (idx_count == -1) {
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_CMD_ERROR;
}
int retval;
if (!valid_var_name(dest)) {
streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, dest);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -709,7 +709,7 @@ static int set_var_slices(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_
if (opts.append || opts.prepend) {
streams.err.append_format(
L"%ls: Cannot use --append or --prepend when assigning to a slice", cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -740,7 +740,7 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
parser_t &parser, io_streams_t &streams) {
if (argc == 0) {
streams.err.append_format(BUILTIN_ERR_MIN_ARG_COUNT1, cmd, 1);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -752,13 +752,13 @@ static int builtin_set_set(const wchar_t *cmd, set_cmd_opts_t &opts, int argc, w
std::vector<long> indexes;
int idx_count = parse_index(indexes, varname, scope, streams, parser.vars());
if (idx_count == -1) {
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
if (!valid_var_name(varname)) {
streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, varname);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}

View file

@ -269,7 +269,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
return STATUS_CMD_OK;
} else if (arg_count != 1) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
@ -282,7 +282,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
rlim_t new_limit;
if (*argv[w.woptind] == L'\0') {
streams.err.append_format(_(L"%ls: New limit cannot be an empty string\n"), cmd);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
} else if (wcscasecmp(argv[w.woptind], L"unlimited") == 0) {
new_limit = RLIM_INFINITY;
@ -294,7 +294,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
new_limit = fish_wcstol(argv[w.woptind]);
if (errno) {
streams.err.append_format(_(L"%ls: Invalid limit '%ls'\n"), cmd, argv[w.woptind]);
builtin_print_help(parser, streams, cmd, streams.err);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
new_limit *= get_multiplier(what);

View file

@ -185,9 +185,6 @@ string match: ^
####################
# string invalidarg
string: Subcommand 'invalidarg' is not valid
Standard input (line 211):
string invalidarg; and echo "unexpected exit 0"
^
####################
# string length
@ -270,9 +267,6 @@ string repeat: Expected argument
####################
# string repeat -l fakearg 2>&1
string repeat: Unknown option '-l'
Standard input (line 287):
string repeat -l fakearg
^
####################
# string repeat ""