Commit 8071ba12 authored by Rusty Russell's avatar Rusty Russell

opt: don't wordwrap when description line starts with whitespace.

This was suggested by Luke, though his version insisted on using tab.
This one is a bit more complex, but allows either tab or space.
Suggested-by: default avatarLuke Dashjr <luke-jr+git@utopios.org>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 76565e3d
...@@ -350,11 +350,25 @@ char *opt_invalid_argument(const char *arg); ...@@ -350,11 +350,25 @@ char *opt_invalid_argument(const char *arg);
* and a table of all the options with their descriptions. If an option has * and a table of all the options with their descriptions. If an option has
* description opt_hidden, it is not shown here. * description opt_hidden, it is not shown here.
* *
* The table of options is formatted such that descriptions are
* wrapped on space boundaries. If a description has a "\n" that is
* left intact, and the following characters indented appropriately.
* If the description begins with one or more space/tab (or has a
* space or tab following a "\n") that line is output without wrapping.
*
* If "extra" is NULL, then the extra information is taken from any * If "extra" is NULL, then the extra information is taken from any
* registered option which calls opt_usage_and_exit(). This avoids duplicating * registered option which calls opt_usage_and_exit(). This avoids duplicating
* that string in the common case. * that string in the common case.
* *
* The result should be passed to free(). * The result should be passed to free().
*
* See Also:
* opt_usage_and_exit()
*
* Example:
* opt_register_arg("--explode|--boom", explode, NULL, NULL,
* "This line will be wrapped by opt_usage\n"
* " But this won't because it's indented.");
*/ */
char *opt_usage(const char *argv0, const char *extra); char *opt_usage(const char *argv0, const char *extra);
......
...@@ -7,31 +7,58 @@ ...@@ -7,31 +7,58 @@
/* Test consume_words helper. */ /* Test consume_words helper. */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
size_t start, len; size_t prefix, len;
bool start = true;
plan_tests(13); plan_tests(27);
/* Every line over width. */ /* Every line over width. */
len = consume_words("hello world", 1, &start); len = consume_words("hello world", 1, &prefix, &start);
ok1(start == 0); ok1(prefix == 0);
ok1(!start);
ok1(len == strlen("hello")); ok1(len == strlen("hello"));
len = consume_words(" world", 1, &start); len = consume_words(" world", 1, &prefix, &start);
ok1(start == 1); ok1(prefix == 1);
ok1(len == strlen("world")); ok1(len == strlen("world"));
ok1(consume_words("", 1, &start) == 0); ok1(!start);
ok1(consume_words("", 1, &prefix, &start) == 0);
/* Same with width where won't both fit. */ /* Same with width where won't both fit. */
len = consume_words("hello world", 5, &start); start = true;
ok1(start == 0); len = consume_words("hello world", 5, &prefix, &start);
ok1(!start);
ok1(prefix == 0);
ok1(len == strlen("hello")); ok1(len == strlen("hello"));
len = consume_words(" world", 5, &start); len = consume_words(" world", 5, &prefix, &start);
ok1(start == 1); ok1(!start);
ok1(prefix == 1);
ok1(len == strlen("world")); ok1(len == strlen("world"));
ok1(consume_words("", 5, &start) == 0); ok1(consume_words("", 5, &prefix, &start) == 0);
len = consume_words("hello world", 11, &start); start = true;
ok1(start == 0); len = consume_words("hello world", 11, &prefix, &start);
ok1(!start);
ok1(prefix == 0);
ok1(len == strlen("hello world")); ok1(len == strlen("hello world"));
ok1(consume_words("", 11, &start) == 0); ok1(consume_words("", 11, &prefix, &start) == 0);
/* Now try a literal, should not be broken */
start = true;
len = consume_words(" hello world", 5, &prefix, &start);
ok1(!start);
ok1(prefix == 1);
ok1(len == strlen("hello world"));
/* A literal after an explicit \n also not broken */
start = true;
len = consume_words("hi\n hello world", 5, &prefix, &start);
ok1(start);
ok1(prefix == 0);
ok1(len == strlen("hi\n"));
len = consume_words(" hello world", 5, &prefix, &start);
ok1(!start);
ok1(prefix == 1);
ok1(len == strlen("hello world"));
return exit_status(); return exit_status();
} }
...@@ -41,27 +41,35 @@ static unsigned int get_columns(void) ...@@ -41,27 +41,35 @@ static unsigned int get_columns(void)
/* Return number of chars of words to put on this line. /* Return number of chars of words to put on this line.
* Prefix is set to number to skip at start, maxlen is max width, returns * Prefix is set to number to skip at start, maxlen is max width, returns
* length (after prefix) to put on this line. */ * length (after prefix) to put on this line.
static size_t consume_words(const char *words, size_t maxlen, size_t *prefix) * start is set if we start a new line in the source description. */
static size_t consume_words(const char *words, size_t maxlen, size_t *prefix,
bool *start)
{ {
size_t oldlen, len; size_t oldlen, len;
/* Swallow leading whitespace. */ /* Always swollow leading whitespace. */
*prefix = strspn(words, " \n"); *prefix = strspn(words, " \n");
words += *prefix; words += *prefix;
/* Use at least one word, even if it takes us over maxlen. */ /* Leading whitespace at start of line means literal. */
oldlen = len = strcspn(words, " "); if (*start && *prefix) {
while (len <= maxlen) { oldlen = strcspn(words, "\n");
oldlen = len; } else {
len += strspn(words+len, " "); /* Use at least one word, even if it takes us over maxlen. */
if (words[len] == '\n') oldlen = len = strcspn(words, " ");
break; while (len <= maxlen) {
len += strcspn(words+len, " \n"); oldlen = len;
if (len == oldlen) len += strspn(words+len, " ");
break; if (words[len] == '\n')
break;
len += strcspn(words+len, " \n");
if (len == oldlen)
break;
}
} }
*start = (words[oldlen - 1] == '\n');
return oldlen; return oldlen;
} }
...@@ -95,7 +103,7 @@ static char *add_desc(char *base, size_t *len, size_t *max, ...@@ -95,7 +103,7 @@ static char *add_desc(char *base, size_t *len, size_t *max,
{ {
size_t off, prefix, l; size_t off, prefix, l;
const char *p; const char *p;
bool same_line = false; bool same_line = false, start = true;
base = add_str(base, len, max, opt->names); base = add_str(base, len, max, opt->names);
off = strlen(opt->names); off = strlen(opt->names);
...@@ -118,7 +126,7 @@ static char *add_desc(char *base, size_t *len, size_t *max, ...@@ -118,7 +126,7 @@ static char *add_desc(char *base, size_t *len, size_t *max,
/* Indent description. */ /* Indent description. */
p = opt->desc; p = opt->desc;
while ((l = consume_words(p, width - indent, &prefix)) != 0) { while ((l = consume_words(p, width - indent, &prefix, &start)) != 0) {
if (!same_line) if (!same_line)
base = add_indent(base, len, max, indent); base = add_indent(base, len, max, indent);
p += prefix; p += prefix;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment