#include "log.h"
#include "string-util.h"
#include "strv.h"
+#include "terminal-util.h"
#include "verbs.h"
#include "virt.h"
return _dispatch_verb_with_args(strv_skip(argv, optind), verbs, verbs + n, userdata);
}
+#define VERB_SYNOPSIS_WIDTH_SANE 25
+
+static const char* find_point_to_break(const char *s, size_t max_width) {
+ /* Locate the first space, preferably after max_width, or the last space otherwise.
+ * Return the part after the space. */
+
+ if (strlen(s) <= max_width)
+ return NULL;
+
+ const char *p = strchr(s + max_width, ' ') ?: strrchr(s, ' ');
+ return p ? p + 1 : NULL;
+}
+
+static int verb_add_help_one(Table *table, const Verb *verb) {
+ assert(table);
+ assert(verb);
+
+ bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
+ int r;
+
+ /* We indent the option string by two spaces. We could set the minimum cell width and
+ * right-align for a similar result, but that'd be more work. This is only used for
+ * display. */
+ _cleanup_free_ char *s = strjoin(" ",
+ is_default ? "[" : "",
+ verb->verb,
+ verb->argspec ? " " : "",
+ strempty(verb->argspec),
+ is_default ? "]" : "");
+ if (!s)
+ return log_oom();
+
+ const char *ss = NULL;
+ if (columns() < VERB_SYNOPSIS_WIDTH_SANE * 4) {
+ /* If the synopsis is very wide, try to split it up. But do this only if the terminal
+ * is not very wide. If it _is_ wide, the broken up synopsis would look silly. */
+ const char *p = find_point_to_break(s, VERB_SYNOPSIS_WIDTH_SANE), *p2 = NULL;
+ if (p) {
+ const char *s1 = strndupa_safe(s, p - s), *s2 = NULL;
+
+ p2 = find_point_to_break(p, VERB_SYNOPSIS_WIDTH_SANE - 4); /* we indent by two spaces more */
+ if (p2)
+ s2 = strndupa_safe(p, p2 - p);
+
+ if (s2)
+ ss = strjoina(s1, "\n ", s2, "\n ", p2);
+ else
+ ss = strjoina(s1, "\n ", p);
+ }
+ }
+
+ r = table_add_cell(table, NULL, TABLE_STRING, ss ?: s);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ _cleanup_strv_free_ char **t = strv_split(verb->help, /* separators= */ NULL);
+ if (!t)
+ return log_oom();
+
+ r = table_add_many(table, TABLE_STRV_WRAPPED, t);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ return 0;
+}
+
int _verbs_get_help_table(
const Verb verbs[],
const Verb verbs_end[],
/* No help string — we do not show the verb */
continue;
- bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
-
- /* We indent the option string by two spaces. We could set the minimum cell width and
- * right-align for a similar result, but that'd be more work. This is only used for
- * display. */
- r = table_add_cell_stringf(table, NULL, " %s%s%s%s%s",
- is_default ? "[" : "",
- verb->verb,
- verb->argspec ? " " : "",
- strempty(verb->argspec),
- is_default ? "]" : "");
- if (r < 0)
- return table_log_add_error(r);
-
- _cleanup_strv_free_ char **s = strv_split(verb->help, /* separators= */ NULL);
- if (!s)
- return log_oom();
-
- r = table_add_many(table, TABLE_STRV_WRAPPED, s);
+ r = verb_add_help_one(table, verb);
if (r < 0)
- return table_log_add_error(r);
+ return r;
}
table_set_header(table, false);