Skip to content

Commit 9ab0ea7

Browse files
committed
shell: Introduce structured help message
In order to enable better and more consistent help messages for shell commands, this commit introduces a new SHELL_HELP macro that allows to document a command's description and usage in a more structured way. This will allow to get rid of inconsistent (and duplicated!) variations of "Syntax: ...", "Syntax:\n ...", "Usage: ...", in the commands, and formatting of the description+usage will be taken care of by the shell when it detects the help message is using the "structured" format. Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
1 parent 7bdeffb commit 9ab0ea7

File tree

2 files changed

+108
-8
lines changed

2 files changed

+108
-8
lines changed

include/zephyr/shell/shell.h

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,82 @@ struct shell_static_entry {
234234
uint8_t padding[Z_SHELL_STATIC_ENTRY_PADDING];
235235
};
236236

237+
/**
238+
* @brief Shell structured help descriptor.
239+
*
240+
* @details This structure provides an organized way to specify command help
241+
* as opposed to a free-form string. This helps make help messages more
242+
* consistent and easier to read.
243+
*/
244+
struct shell_cmd_help {
245+
/* @cond INTERNAL_HIDDEN */
246+
uint32_t magic;
247+
/* @endcond */
248+
const char *description; /*!< Command description */
249+
const char *usage; /*!< Command usage string */
250+
};
251+
252+
/**
253+
* @cond INTERNAL_HIDDEN
254+
*/
255+
256+
/**
257+
* @brief Magic number used to identify the beginning of a structured help
258+
* message when cast to a char pointer.
259+
*/
260+
#define SHELL_STRUCTURED_HELP_MAGIC 0x86D20BC4
261+
262+
/**
263+
* @endcond
264+
*/
265+
266+
/**
267+
* @brief Check if help string is structured help.
268+
*
269+
* @param help Pointer to help string or structured help.
270+
* @return true if help is structured, false otherwise.
271+
*/
272+
static inline bool shell_help_is_structured(const char *help)
273+
{
274+
const struct shell_cmd_help *structured = (const struct shell_cmd_help *)help;
275+
276+
return structured != NULL && structured->magic == SHELL_STRUCTURED_HELP_MAGIC;
277+
}
278+
279+
#if defined(CONFIG_SHELL_HELP) || defined(__DOXYGEN__)
280+
/**
281+
* @brief Helper macro to create structured help inline.
282+
*
283+
* This macro allows you to pass structured help directly to existing shell macros.
284+
*
285+
* Example:
286+
*
287+
* @code{.c}
288+
* #define MY_CMD_HELP SHELL_HELP("Do stuff", "<device> <arg1> [<arg2>]")
289+
* SHELL_CMD_REGISTER(my_cmd, NULL, MY_CMD_HELP, &my_cmd_handler, 1, 1);
290+
* @endcode
291+
*
292+
* @param[in] _description Command description.
293+
* This can be a multi-line string. First line should be one sentence
294+
* describing the command. Additional lines might be used to provide
295+
* additional details.
296+
*
297+
* @param[in] _usage Command usage string.
298+
* This can be a multi-line string. First line should always be
299+
* indicating the command syntax (_without_ the command name).
300+
* Additional lines may be used to provide additional details, e.g.
301+
* explain the meaning of each argument, allowed values, etc.
302+
*/
303+
#define SHELL_HELP(_description, _usage) \
304+
((const char *)&(const struct shell_cmd_help){ \
305+
.magic = SHELL_STRUCTURED_HELP_MAGIC, \
306+
.description = (_description), \
307+
.usage = (_usage), \
308+
})
309+
#else
310+
#define SHELL_HELP(_description, _usage) NULL
311+
#endif /* CONFIG_SHELL_HELP */
312+
237313
/**
238314
* @brief Macro for defining and adding a root command (level 0) with required
239315
* number of arguments.
@@ -244,7 +320,7 @@ struct shell_static_entry {
244320
*
245321
* @param[in] syntax Command syntax (for example: history).
246322
* @param[in] subcmd Pointer to a subcommands array.
247-
* @param[in] help Pointer to a command help string.
323+
* @param[in] help Pointer to a command help string (use @ref SHELL_HELP for structured help)
248324
* @param[in] handler Pointer to a function handler.
249325
* @param[in] mandatory Number of mandatory arguments including command name.
250326
* @param[in] optional Number of optional arguments.
@@ -275,7 +351,7 @@ struct shell_static_entry {
275351
* exists and equals 1.
276352
* @param[in] syntax Command syntax (for example: history).
277353
* @param[in] subcmd Pointer to a subcommands array.
278-
* @param[in] help Pointer to a command help string.
354+
* @param[in] help Pointer to a command help string (use @ref SHELL_HELP for structured help).
279355
* @param[in] handler Pointer to a function handler.
280356
* @param[in] mandatory Number of mandatory arguments including command name.
281357
* @param[in] optional Number of optional arguments.
@@ -303,7 +379,7 @@ struct shell_static_entry {
303379
*
304380
* @param[in] syntax Command syntax (for example: history).
305381
* @param[in] subcmd Pointer to a subcommands array.
306-
* @param[in] help Pointer to a command help string.
382+
* @param[in] help Pointer to a command help string. Use @ref SHELL_HELP for structured help.
307383
* @param[in] handler Pointer to a function handler.
308384
*/
309385
#define SHELL_CMD_REGISTER(syntax, subcmd, help, handler) \
@@ -319,7 +395,7 @@ struct shell_static_entry {
319395
* exists and equals 1.
320396
* @param[in] syntax Command syntax (for example: history).
321397
* @param[in] subcmd Pointer to a subcommands array.
322-
* @param[in] help Pointer to a command help string.
398+
* @param[in] help Pointer to a command help string. Use @ref SHELL_HELP for structured help.
323399
* @param[in] handler Pointer to a function handler.
324400
*/
325401
#define SHELL_COND_CMD_REGISTER(flag, syntax, subcmd, help, handler) \
@@ -455,7 +531,7 @@ struct shell_static_entry {
455531
*
456532
* @param[in] syntax Command syntax (for example: history).
457533
* @param[in] subcmd Pointer to a subcommands array.
458-
* @param[in] help Pointer to a command help string.
534+
* @param[in] help Pointer to a command help string. Use @ref SHELL_HELP for structured help.
459535
* @param[in] handler Pointer to a function handler.
460536
* @param[in] mand Number of mandatory arguments including command name.
461537
* @param[in] opt Number of optional arguments.
@@ -477,7 +553,7 @@ struct shell_static_entry {
477553
* exists and equals 1.
478554
* @param[in] syntax Command syntax (for example: history).
479555
* @param[in] subcmd Pointer to a subcommands array.
480-
* @param[in] help Pointer to a command help string.
556+
* @param[in] help Pointer to a command help string. Use @ref SHELL_HELP for structured help.
481557
* @param[in] handler Pointer to a function handler.
482558
* @param[in] mand Number of mandatory arguments including command name.
483559
* @param[in] opt Number of optional arguments.

subsys/shell/shell_help.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ static void formatted_text_print(const struct shell *sh, const char *str,
113113
z_cursor_next_line_move(sh);
114114
}
115115

116+
static void formatted_structured_help_print(const struct shell *sh, const char *item_name,
117+
const char *item_help, size_t terminal_offset)
118+
{
119+
const struct shell_cmd_help *structured = (const struct shell_cmd_help *)item_help;
120+
121+
if (structured->description) {
122+
formatted_text_print(sh, structured->description, terminal_offset, false);
123+
}
124+
125+
if (structured->usage) {
126+
z_shell_op_cursor_horiz_move(sh, terminal_offset);
127+
z_shell_fprintf(sh, SHELL_NORMAL, "Usage: %s ", item_name);
128+
formatted_text_print(sh, structured->usage, terminal_offset + 7, false);
129+
}
130+
}
131+
116132
static void help_item_print(const struct shell *sh, const char *item_name,
117133
uint16_t item_name_width, const char *item_help)
118134
{
@@ -150,7 +166,11 @@ static void help_item_print(const struct shell *sh, const char *item_name,
150166
z_shell_fprintf(sh, SHELL_NORMAL, "%s: ", tabulator);
151167
}
152168
/* print option help */
153-
formatted_text_print(sh, item_help, offset, false);
169+
if (shell_help_is_structured(item_help)) {
170+
formatted_structured_help_print(sh, item_name, item_help, offset);
171+
} else {
172+
formatted_text_print(sh, item_help, offset, false);
173+
}
154174
}
155175

156176
/* Function prints all subcommands of the parent command together with their
@@ -197,7 +217,11 @@ void z_shell_help_cmd_print(const struct shell *sh,
197217

198218
z_shell_fprintf(sh, SHELL_NORMAL, "%s%s", cmd->syntax, cmd_sep);
199219

200-
formatted_text_print(sh, cmd->help, field_width, false);
220+
if (shell_help_is_structured(cmd->help)) {
221+
formatted_structured_help_print(sh, cmd->syntax, cmd->help, field_width);
222+
} else {
223+
formatted_text_print(sh, cmd->help, field_width, false);
224+
}
201225
}
202226

203227
bool z_shell_help_request(const char *str)

0 commit comments

Comments
 (0)