shell_help.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. * shell_help.c
  3. */
  4. #include "private.h"
  5. #include "lub/string.h"
  6. #include <stdio.h>
  7. #include <string.h>
  8. /*--------------------------------------------------------- */
  9. /*
  10. * Provide a detailed list of the possible command completions
  11. */
  12. static void
  13. available_commands(clish_shell_t * this, const char *line, bool_t full)
  14. {
  15. char *buf = NULL;
  16. size_t max_width = 0;
  17. const clish_command_t *cmd;
  18. if (NULL == clish_shell_getfirst_command(this, line, CLISH_NSPACE_HELP)) {
  19. /*
  20. * A totally wrong command has been inputed
  21. * Indicate the point of error and display
  22. * a list of possible commands
  23. */
  24. char *prompt = clish_view__get_prompt(this->view,
  25. this->viewid);
  26. unsigned error_offset = strlen(prompt) + 1;
  27. lub_string_free(prompt);
  28. /* find the best match... */
  29. cmd = clish_shell_resolve_prefix(this, line);
  30. if (cmd) {
  31. error_offset +=
  32. strlen(clish_command__get_name(cmd)) + 1;
  33. /* take a copy for help purposes */
  34. buf = lub_string_dup(clish_command__get_name(cmd));
  35. } else {
  36. /* show all possible commands */
  37. buf = lub_string_dup("");
  38. }
  39. /* indicate the point of error */
  40. fprintf(stderr, "%*s\n", error_offset, "^");
  41. } else {
  42. /* take a copy */
  43. buf = lub_string_dup(line);
  44. }
  45. /* iterate round to determine max_width */
  46. for (cmd = clish_shell_getfirst_command(this, buf, CLISH_NSPACE_HELP);
  47. cmd; cmd = clish_shell_getnext_command(this, buf)) {
  48. size_t width;
  49. const char *name;
  50. if (full) {
  51. name = clish_command__get_name(cmd);
  52. } else {
  53. name = clish_command__get_suffix(cmd);
  54. }
  55. width = strlen(name);
  56. if (width > max_width) {
  57. max_width = width;
  58. }
  59. }
  60. /* now iterate round to print the help */
  61. for (cmd = clish_shell_getfirst_command(this, buf, CLISH_NSPACE_HELP);
  62. cmd; cmd = clish_shell_getnext_command(this, buf)) {
  63. const char *name;
  64. if (full) {
  65. name = clish_command__get_name(cmd);
  66. } else {
  67. name = clish_command__get_suffix(cmd);
  68. }
  69. fprintf(stderr, " %-*s %s\n",
  70. (int)max_width, name, clish_command__get_text(cmd));
  71. }
  72. /* cleanup */
  73. lub_string_free(buf);
  74. }
  75. /*--------------------------------------------------------- */
  76. void clish_shell_help(clish_shell_t * this, const char *line)
  77. {
  78. const clish_command_t *cmd, *next_cmd, *first_cmd;
  79. /* if there are further commands then we need to show them too */
  80. cmd = clish_shell_resolve_prefix(this, line);
  81. if (cmd) {
  82. clish_shell_iterator_t iter;
  83. /* skip the command already known about */
  84. clish_shell_iterator_init(&iter, CLISH_NSPACE_HELP);
  85. first_cmd = clish_shell_find_next_completion(this, line, &iter);
  86. next_cmd = clish_shell_find_next_completion(this, line, &iter);
  87. } else {
  88. first_cmd = next_cmd = NULL;
  89. }
  90. if (cmd && !next_cmd && (!first_cmd || (first_cmd == cmd))) {
  91. /* we've resolved a particular command */
  92. switch (this->state) {
  93. case SHELL_STATE_HELPING:
  94. {
  95. const char *detail =
  96. clish_command__get_detail(cmd);
  97. if (NULL != detail)
  98. fprintf(stderr, "%s\n", detail);
  99. else
  100. clish_command_help(cmd, this->viewid, line);
  101. break;
  102. }
  103. case SHELL_STATE_OK:
  104. case SHELL_STATE_SCRIPT_ERROR:
  105. case SHELL_STATE_SYNTAX_ERROR:
  106. /* get the command to provide help */
  107. clish_command_help(cmd, this->viewid, line);
  108. break;
  109. default:
  110. /* do nothing */
  111. break;
  112. }
  113. } else {
  114. /* dump the available commands */
  115. available_commands(this, line, BOOL_FALSE);
  116. }
  117. /* update the state */
  118. if (this->state == SHELL_STATE_HELPING)
  119. this->state = SHELL_STATE_OK;
  120. else
  121. this->state = SHELL_STATE_HELPING;
  122. }
  123. /*--------------------------------------------------------- */