mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Use a pager to view long outputs of builtin --help
Every builtin or function shipped with fish supports flag -h or --help to print a slightly condensed version of its manpage. Some of those help messages are longer than a typical screen; this commit pipes the help to a pager to make it easier to read. As in other places in fish we assume that either $PAGER or "less" is a valid pager and use that. In three places (error messages for bg, break and continue) the help is printed to stderr instead of stdout. To make sure the error message is visible in the pager, we pass it to builtin_print_help, every call of which needs to be updated. Fixes #6227
This commit is contained in:
parent
d992480204
commit
61486954bc
33 changed files with 78 additions and 75 deletions
|
@ -1,4 +1,4 @@
|
|||
function __fish_print_help --description "Print help message for the specified fish function or builtin" --argument item
|
||||
function __fish_print_help --description "Print help message for the specified fish function or builtin" --argument item error_message
|
||||
if test "$item" = '.'
|
||||
set item source
|
||||
end
|
||||
|
@ -53,6 +53,8 @@ function __fish_print_help --description "Print help message for the specified f
|
|||
# the `-s` flag to `less` that `man` passes.
|
||||
set -l state blank
|
||||
set -l have_name
|
||||
begin
|
||||
string join \n $error_message
|
||||
for line in $help
|
||||
# categorize the line
|
||||
set -l line_type
|
||||
|
@ -103,5 +105,22 @@ function __fish_print_help --description "Print help message for the specified f
|
|||
# skip it
|
||||
end
|
||||
end
|
||||
end | string replace -ra '^ ' '' | ul # post-process with `ul`, to interpret the old-style grotty escapes
|
||||
end
|
||||
end | string replace -ra '^ ' '' | ul | # post-process with `ul`, to interpret the old-style grotty escapes
|
||||
begin
|
||||
set -l pager less
|
||||
set -q PAGER
|
||||
and set pager $PAGER
|
||||
not isatty stdout
|
||||
and set pager cat # cannot use a builtin here
|
||||
# similar to man, but add -F to quit paging when the help output is brief (#6227)
|
||||
set -xl LESS "$LESS"isrFX
|
||||
# less options:
|
||||
# -i (--ignore-case) search case-insensitively, like man
|
||||
# -s (--squeeze-blank-lines) not strictly necessary since we already do that above
|
||||
# -r (--raw-control-chars) to display bold, underline and colors
|
||||
# -F (--quit-if-one-screen) to maintain the non-paging behavior for small outputs
|
||||
# -X (--no-init) not sure if this is needed but git uses it
|
||||
$pager
|
||||
end
|
||||
end
|
||||
|
|
|
@ -146,42 +146,27 @@ int parse_help_only_cmd_opts(struct help_only_cmd_opts_t &opts, int *optind, int
|
|||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
/// Obtain help/usage information for the specified builtin from manpage in subshell
|
||||
/// Display help/usage information for the specified builtin or function from manpage
|
||||
///
|
||||
/// @param name
|
||||
/// builtin name to get up help for
|
||||
/// builtin or function name to get up help for
|
||||
///
|
||||
/// @return
|
||||
/// A wcstring with a formatted manpage.
|
||||
///
|
||||
wcstring builtin_help_get(parser_t &parser, io_streams_t &streams, const wchar_t *name) {
|
||||
UNUSED(parser);
|
||||
/// Process and print help for the specified builtin or function.
|
||||
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *name,
|
||||
wcstring *error_message) {
|
||||
UNUSED(streams);
|
||||
// This won't ever work if no_exec is set.
|
||||
if (no_exec()) return wcstring();
|
||||
|
||||
wcstring_list_t lst;
|
||||
wcstring out;
|
||||
const wcstring name_esc = escape_string(name, 1);
|
||||
wcstring cmd = format_string(L"__fish_print_help %ls", name_esc.c_str());
|
||||
if (exec_subshell(cmd, parser, lst, false /* don't apply exit status */) >= 0) {
|
||||
for (size_t i = 0; i < lst.size(); i++) {
|
||||
out.append(lst.at(i));
|
||||
out.push_back(L'\n');
|
||||
if (no_exec()) return;
|
||||
const wcstring name_esc = escape_string(name, ESCAPE_ALL);
|
||||
wcstring cmd = format_string(L"__fish_print_help %ls ", name_esc.c_str());
|
||||
io_chain_t ios;
|
||||
if (error_message) {
|
||||
cmd.append(escape_string(*error_message, ESCAPE_ALL));
|
||||
// If it's an error, redirect the output of __fish_print_help to stderr
|
||||
ios.push_back(std::make_shared<io_fd_t>(STDOUT_FILENO, STDERR_FILENO, false));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Process and print for the specified builtin. If @c b is `sb_err`, also print the line
|
||||
/// information.
|
||||
///
|
||||
/// If @c b is the buffer representing standard error, and the help message is about to be printed
|
||||
/// to an interactive screen, it may be shortened to fit the screen.
|
||||
///
|
||||
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
|
||||
output_stream_t &b) {
|
||||
b.append(builtin_help_get(parser, streams, cmd));
|
||||
parser.eval(cmd, ios, TOP);
|
||||
// ignore the exit status of __fish_print_help
|
||||
}
|
||||
|
||||
/// Perform error reporting for encounter with unknown option.
|
||||
|
@ -221,14 +206,14 @@ static int builtin_generic(parser_t &parser, io_streams_t &streams, wchar_t **ar
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
// Hackish - if we have no arguments other than the command, we are a "naked invocation" and we
|
||||
// just print help.
|
||||
if (argc == 1) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
@ -272,9 +257,8 @@ static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar
|
|||
int argc = builtin_count_args(argv);
|
||||
|
||||
if (argc != 1) {
|
||||
streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0], argv[1]);
|
||||
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
wcstring error_message = format_string(BUILTIN_ERR_UNKNOWN, argv[0], argv[1]);
|
||||
builtin_print_help(parser, streams, argv[0], &error_message);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
@ -286,8 +270,8 @@ static int builtin_break_continue(parser_t &parser, io_streams_t &streams, wchar
|
|||
if (b->type() == FUNCTION_CALL) break;
|
||||
}
|
||||
if (!has_loop) {
|
||||
streams.err.append_format(_(L"%ls: Not inside of loop\n"), argv[0]);
|
||||
builtin_print_help(parser, streams, argv[0], streams.err);
|
||||
wcstring error_message = format_string(_(L"%ls: Not inside of loop\n"), argv[0]);
|
||||
builtin_print_help(parser, streams, argv[0], &error_message);
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
|
||||
|
@ -455,7 +439,7 @@ proc_status_t builtin_run(parser_t &parser, int job_pgid, wchar_t **argv, io_str
|
|||
// follows the keyword by `-h` or `--help`. Since it isn't really a builtin command we need to
|
||||
// handle displaying help for it here.
|
||||
if (argv[1] && !argv[2] && parse_util_argument_is_help(argv[1]) && cmd_needs_help(argv[0])) {
|
||||
builtin_print_help(parser, streams, argv[0], streams.out);
|
||||
builtin_print_help(parser, streams, argv[0]);
|
||||
return proc_status_t::from_exit_code(STATUS_CMD_OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ const wchar_t *builtin_get_desc(const wcstring &b);
|
|||
wcstring builtin_help_get(parser_t &parser, const wchar_t *cmd);
|
||||
|
||||
void builtin_print_help(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
|
||||
output_stream_t &b);
|
||||
wcstring *error_message = nullptr);
|
||||
int builtin_count_args(const wchar_t *const *argv);
|
||||
|
||||
void builtin_unknown_option(parser_t &parser, io_streams_t &streams, const wchar_t *cmd,
|
||||
|
|
|
@ -699,7 +699,7 @@ int builtin_argparse(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j) {
|
||||
assert(j != NULL);
|
||||
if (!j->wants_job_control()) {
|
||||
streams.err.append_format(
|
||||
wcstring error_message = format_string(
|
||||
_(L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n"),
|
||||
L"bg", j->job_id, j->command_wcstr());
|
||||
builtin_print_help(parser, streams, L"bg", streams.err);
|
||||
builtin_print_help(parser, streams, L"bg", &error_message);
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -431,7 +431,7 @@ int builtin_bind_t::builtin_bind(parser_t &parser, io_streams_t &streams, wchar_
|
|||
return STATUS_CMD_OK;
|
||||
}
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ int builtin_block(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ int builtin_builtin(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,13 +84,13 @@ int builtin_command(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
// Quiet implies find_path.
|
||||
if (!opts.find_path && !opts.all_paths && !opts.quiet) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ int builtin_commandline(parser_t &parser, io_streams_t &streams, wchar_t **argv)
|
|||
break;
|
||||
}
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
case ':': {
|
||||
|
|
|
@ -247,7 +247,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
break;
|
||||
}
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
case ':': {
|
||||
|
|
|
@ -68,7 +68,7 @@ int builtin_contains(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ int builtin_emit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ int builtin_functions(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ int builtin_history(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
break;
|
||||
}
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
case ':': {
|
||||
|
|
|
@ -243,7 +243,7 @@ int builtin_math(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -742,7 +742,7 @@ int builtin_printf(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ int builtin_pwd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
resolve_symlinks = true;
|
||||
break;
|
||||
case 'h':
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
case '?': {
|
||||
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
|
||||
|
|
|
@ -38,7 +38,7 @@ int builtin_random(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -431,7 +431,7 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
}
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,13 +28,13 @@ int builtin_realpath(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
if (optind + 1 != argc) { // TODO: allow arbitrary args. `realpath *` should print many paths
|
||||
streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, cmd, 1, argc - optind);
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ int builtin_return(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -807,7 +807,7 @@ int builtin_set(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
argc -= optind;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ int builtin_set_color(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
break;
|
||||
}
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, argv[0], streams.out);
|
||||
builtin_print_help(parser, streams, argv[0]);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
case 'o': {
|
||||
|
|
|
@ -33,7 +33,7 @@ int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ int builtin_status(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
||||
if (opts.print_help) {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -1358,7 +1358,7 @@ int builtin_string(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
}
|
||||
|
||||
if (std::wcscmp(argv[1], L"-h") == 0 || std::wcscmp(argv[1], L"--help") == 0) {
|
||||
builtin_print_help(parser, streams, L"string", streams.out);
|
||||
builtin_print_help(parser, streams, L"string");
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ int builtin_ulimit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
}
|
||||
#endif
|
||||
case 'h': {
|
||||
builtin_print_help(parser, streams, cmd, streams.out);
|
||||
builtin_print_help(parser, streams, cmd);
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
case ':': {
|
||||
|
|
Loading…
Reference in a new issue