diff --git a/src/ac-power/ac-power.c b/src/ac-power/ac-power.c index dad4384ada..e773d8d431 100644 --- a/src/ac-power/ac-power.c +++ b/src/ac-power/ac-power.c @@ -1,14 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "alloc-util.h" -#include "ansi-color.h" #include "battery-util.h" #include "build.h" #include "format-table.h" +#include "help-util.h" #include "log.h" #include "main-func.h" #include "options.h" -#include "pretty-print.h" #include "string-util.h" static bool arg_verbose = false; @@ -19,29 +17,22 @@ static enum { } arg_action = ACTION_AC_POWER; static int help(void) { - _cleanup_free_ char *link = NULL; - _cleanup_(table_unrefp) Table *options = NULL; int r; - r = terminal_urlify_man("systemd-ac-power", "1", &link); - if (r < 0) - return log_oom(); - + _cleanup_(table_unrefp) Table *options = NULL; r = option_parser_get_help_table(&options); if (r < 0) return r; - printf("%s [OPTIONS...]\n" - "\n%sReport whether we are connected to an external power source.%s\n" - "\nOptions:\n", - program_invocation_short_name, - ansi_highlight(), - ansi_normal()); + help_cmdline("[OPTIONS...]"); + help_abstract("Report whether we are connected to an external power source."); + + help_section("Options:"); r = table_print_or_warn(options); if (r < 0) return r; - printf("\nSee the %s for details.\n", link); + help_man_page_reference("systemd-ac-power", "1"); return 0; } diff --git a/src/basic/ansi-color.h b/src/basic/ansi-color.h index 1ddb9c6681..20f6b3bf62 100644 --- a/src/basic/ansi-color.h +++ b/src/basic/ansi-color.h @@ -91,6 +91,8 @@ bool looks_like_ansi_color_code(const char *str); #define ANSI_UNDERLINE "\x1B[0;4m" #define ANSI_ADD_UNDERLINE "\x1B[4m" #define ANSI_ADD_UNDERLINE_GREY ANSI_ADD_UNDERLINE "\x1B[58:5:245m" +#define ANSI_ITALICS "\x1B[0;3m" +#define ANSI_ADD_ITALICS "\x1B[3m" #define ANSI_HIGHLIGHT "\x1B[0;1;39m" #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m" @@ -180,6 +182,15 @@ static inline const char* ansi_add_underline_grey(void) { (colors_enabled() ? ANSI_ADD_UNDERLINE_GREY : ANSI_ADD_UNDERLINE) : ""; } +static inline const char* ansi_italics(void) { + /* We hook italics also into the underline checks, close enough */ + return underline_enabled() ? ANSI_ITALICS : ""; +} + +static inline const char* ansi_add_italics(void) { + return underline_enabled() ? ANSI_ADD_ITALICS : ""; +} + #define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME) \ static inline const char* ansi_##name##_underline(void) { \ return underline_enabled() ? ANSI_##NAME##_UNDERLINE : \ diff --git a/src/notify/notify.c b/src/notify/notify.c index 2ac0129bae..d3201c66bc 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -17,13 +17,13 @@ #include "fdset.h" #include "format-table.h" #include "format-util.h" +#include "help-util.h" #include "log.h" #include "main-func.h" #include "notify-recv.h" #include "options.h" #include "parse-util.h" #include "pidref.h" -#include "pretty-print.h" #include "process-util.h" #include "signal-util.h" #include "string-util.h" @@ -57,31 +57,24 @@ STATIC_DESTRUCTOR_REGISTER(arg_fds, fdset_freep); STATIC_DESTRUCTOR_REGISTER(arg_fdname, freep); static int help(void) { - _cleanup_free_ char *link = NULL; - _cleanup_(table_unrefp) Table *options = NULL; int r; - r = terminal_urlify_man("systemd-notify", "1", &link); - if (r < 0) - return log_oom(); - + _cleanup_(table_unrefp) Table *options = NULL; r = option_parser_get_help_table(&options); if (r < 0) return r; - printf("%1$s [OPTIONS...] [VARIABLE=VALUE...]\n" - "%1$s [OPTIONS...] --exec [VARIABLE=VALUE...] ; -- CMDLINE...\n" - "%1$s [OPTIONS...] --fork -- CMDLINE...\n" - "\n%2$sNotify the init system about service status updates.%3$s\n\n", - program_invocation_short_name, - ansi_highlight(), - ansi_normal()); + help_cmdline("[OPTIONS...] [VARIABLE=VALUE...]"); + help_cmdline("[OPTIONS...] --exec [VARIABLE=VALUE...] ; -- CMDLINE..."); + help_cmdline("[OPTIONS...] --fork -- CMDLINE..."); + help_abstract("Notify the init system about service status updates."); + help_section("Options:"); r = table_print_or_warn(options); if (r < 0) return r; - printf("\nSee the %s for details.\n", link); + help_man_page_reference("systemd-notify", "1"); return 0; } diff --git a/src/shared/help-util.c b/src/shared/help-util.c new file mode 100644 index 0000000000..b88da2d259 --- /dev/null +++ b/src/shared/help-util.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "ansi-color.h" +#include "help-util.h" +#include "pretty-print.h" + +/* These are helpers for putting together --help texts in a uniform way with a common output style. Each + * function generates a separate part of the --help text: + * + * 1. help_cmdline() outputs a brief summary of the command line syntax. (used at least once, in some cases + * multiple times.) This generally comes first in the output. + * + * 2. help_abstract() outputs a brief prose abstract of the command, should carry a single line of text + * that gives the user a hint what this tool does. Use only once, right after the last help_cmdline(). + * + * 3. help_section() can be used to format multiple sections of the --help text. It should be used at least + * once for an "Options:" section, but can be used more than once, for programs with many + * options/verbs. The first invocation should come right after help_abstract(). + * + * 4. Finally, help_man_page_reference() adds a final line linking the man page of the tool. This should be + * used only once, and terminates the --help text. + * + * Switches and verbs documentation should be inserted after each help_section(). For that ideally use + * options.[ch] APIs. */ + +void help_cmdline(const char *arguments) { + assert(arguments); + + printf("%s>%s %s %s\n", + ansi_grey(), + ansi_normal(), + program_invocation_short_name, + arguments); +} + +void help_abstract(const char *text) { + assert(text); + + printf("\n%s%s%s%s\n", + ansi_highlight(), + ansi_add_italics(), + text, + ansi_normal()); +} + +void help_section(const char *title) { + assert(title); + + printf("\n%s%s%s\n", + ansi_underline(), + title, + ansi_normal()); +} + +void help_man_page_reference(const char *page, const char *section) { + assert(page); + assert(section); + + /* Displaying --help texts generally should not fail, hence let's fall back to a simple string in + * case of OOM. */ + _cleanup_free_ char *link = NULL; + if (terminal_urlify_man(page, section, &link) < 0) + printf("\nSee the %s(%s) man page for details.\n", page, section); + else + printf("\nSee the %s for details.\n", link); +} diff --git a/src/shared/help-util.h b/src/shared/help-util.h new file mode 100644 index 0000000000..380487213f --- /dev/null +++ b/src/shared/help-util.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +void help_cmdline(const char *arguments); + +void help_abstract(const char *text); + +void help_section(const char *title); + +void help_man_page_reference(const char *page, const char *section); diff --git a/src/shared/meson.build b/src/shared/meson.build index a94b78ba94..84acaf698b 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -94,6 +94,7 @@ shared_sources = files( 'gnutls-util.c', 'gpt.c', 'group-record.c', + 'help-util.c', 'hibernate-util.c', 'hostname-setup.c', 'hwdb-util.c', diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e5e7b412f5..4f76c51500 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -10,6 +10,7 @@ #include "bus-util.h" #include "capsule-util.h" #include "extract-word.h" +#include "help-util.h" #include "image-policy.h" #include "install.h" #include "output-mode.h" @@ -17,7 +18,6 @@ #include "parse-argument.h" #include "parse-util.h" #include "path-util.h" -#include "pretty-print.h" #include "static-destruct.h" #include "string-table.h" #include "string-util.h" @@ -108,19 +108,13 @@ STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep); STATIC_DESTRUCTOR_REGISTER(arg_kill_subgroup, freep); static int systemctl_help(void) { - _cleanup_free_ char *link = NULL; - int r; - pager_open(arg_pager_flags); - r = terminal_urlify_man("systemctl", "1", &link); - if (r < 0) - return log_oom(); + help_cmdline("[OPTIONS...] COMMAND ..."); + help_abstract("Query or send control commands to the system manager."); - printf("%1$s [OPTIONS...] COMMAND ...\n\n" - "%5$sQuery or send control commands to the system manager.%6$s\n" - "\n%3$sUnit Commands:%4$s\n" - " list-units [PATTERN...] List units currently in memory\n" + help_section("Unit Commands:"); + printf(" list-units [PATTERN...] List units currently in memory\n" " list-automounts [PATTERN...] List automount units currently in memory,\n" " ordered by path\n" " list-paths [PATTERN...] List path units currently in memory,\n" @@ -166,9 +160,10 @@ static int systemctl_help(void) { " reset-failed [PATTERN...] Reset failed state for all, one, or more\n" " units\n" " whoami [PID...] Return unit caller or specified PIDs are\n" - " part of\n" - "\n%3$sUnit File Commands:%4$s\n" - " list-unit-files [PATTERN...] List installed unit files\n" + " part of\n"); + + help_section("Unit File Commands:"); + printf(" list-unit-files [PATTERN...] List installed unit files\n" " enable [UNIT...|PATH...] Enable one or more unit files\n" " disable UNIT... Disable one or more unit files\n" " reenable UNIT... Reenable one or more unit files\n" @@ -189,25 +184,30 @@ static int systemctl_help(void) { " on specified one or more units\n" " edit UNIT... Edit one or more unit files\n" " get-default Get the name of the default target\n" - " set-default TARGET Set the default target\n" - "\n%3$sMachine Commands:%4$s\n" - " list-machines [PATTERN...] List local containers and host\n" - "\n%3$sJob Commands:%4$s\n" - " list-jobs [PATTERN...] List jobs\n" - " cancel [JOB...] Cancel all, one, or more jobs\n" - "\n%3$sEnvironment Commands:%4$s\n" - " show-environment Dump environment\n" + " set-default TARGET Set the default target\n"); + + help_section("Machine Commands:"); + printf(" list-machines [PATTERN...] List local containers and host\n"); + + help_section("Job Commands:"); + printf(" list-jobs [PATTERN...] List jobs\n" + " cancel [JOB...] Cancel all, one, or more jobs\n"); + + help_section("Environment Commands:"); + printf(" show-environment Dump environment\n" " set-environment VARIABLE=VALUE... Set one or more environment variables\n" " unset-environment VARIABLE... Unset one or more environment variables\n" - " import-environment VARIABLE... Import all or some environment variables\n" - "\n%3$sManager State Commands:%4$s\n" - " daemon-reload Reload systemd manager configuration\n" + " import-environment VARIABLE... Import all or some environment variables\n"); + + help_section("Manager State Commands:"); + printf(" daemon-reload Reload systemd manager configuration\n" " daemon-reexec Reexecute systemd manager\n" " log-level [LEVEL] Get/set logging threshold for manager\n" " log-target [TARGET] Get/set logging target for manager\n" - " service-watchdogs [BOOL] Get/set service watchdog state\n" - "\n%3$sSystem Commands:%4$s\n" - " is-system-running Check whether system is fully running\n" + " service-watchdogs [BOOL] Get/set service watchdog state\n"); + + help_section("System Commands:"); + printf(" is-system-running Check whether system is fully running\n" " default Enter system default mode\n" " rescue Enter system rescue mode\n" " emergency Enter system emergency mode\n" @@ -224,9 +224,10 @@ static int systemctl_help(void) { " hibernate Hibernate the system\n" " hybrid-sleep Hibernate and suspend the system\n" " suspend-then-hibernate Suspend the system, wake after a period of\n" - " time, and hibernate" - "\n%3$sOptions:%4$s\n" - " -h --help Show this help\n" + " time, and hibernate\n"); + + help_section("Options:"); + printf(" -h --help Show this help\n" " --version Show package version\n" " --system Connect to system manager\n" " --user Connect to user service manager\n" @@ -319,14 +320,9 @@ static int systemctl_help(void) { " --drop-in=NAME Edit unit files using the specified drop-in file name\n" " --when=TIME Schedule halt/power-off/reboot/kexec action after\n" " a certain timestamp\n" - " --stdin Read new contents of edited file from stdin\n" - "\nSee the %2$s for details.\n", - program_invocation_short_name, - link, - ansi_underline(), - ansi_normal(), - ansi_highlight(), - ansi_normal()); + " --stdin Read new contents of edited file from stdin\n"); + + help_man_page_reference("systemctl", "1"); return 0; }