shell_command_generator.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * shell_word_generator.c
  3. */
  4. #include <string.h>
  5. #include "private.h"
  6. #include "lub/string.h"
  7. #include "lub/argv.h"
  8. /*-------------------------------------------------------- */
  9. void
  10. clish_shell_iterator_init(clish_shell_iterator_t * iter,
  11. clish_nspace_visibility_t field)
  12. {
  13. iter->last_cmd = NULL;
  14. iter->field = field;
  15. }
  16. /*-------------------------------------------------------- */
  17. void
  18. clish_shell_iterator_fini(clish_shell_iterator_t * iter)
  19. {
  20. lub_string_free(iter->last_cmd);
  21. iter->last_cmd = NULL;
  22. }
  23. /*-------------------------------------------------------- */
  24. const clish_command_t *clish_shell_find_next_completion(const clish_shell_t *
  25. this, const char *line,
  26. clish_shell_iterator_t *
  27. iter)
  28. {
  29. const clish_command_t *result, *cmd;
  30. clish_nspace_t *nspace;
  31. clish_view_t *view;
  32. unsigned view_cnt = clish_view__get_nspace_count(this->view);
  33. int i;
  34. /* ask the local view for next command */
  35. result = clish_view_find_next_completion(this->view,
  36. iter->last_cmd, line, iter->field, BOOL_TRUE);
  37. /* ask the global view for next command */
  38. cmd = clish_view_find_next_completion(this->global,
  39. iter->last_cmd, line, iter->field, BOOL_TRUE);
  40. if (clish_command_diff(result, cmd) > 0)
  41. result = cmd;
  42. lub_string_free(iter->last_cmd);
  43. if (!result)
  44. iter->last_cmd = NULL;
  45. else
  46. iter->last_cmd = lub_string_dup(
  47. clish_command__get_name(result));
  48. return result;
  49. }
  50. /*--------------------------------------------------------- */
  51. static char *clish_shell_param_generator(clish_shell_t * this,
  52. const clish_command_t * cmd,
  53. const char *line,
  54. unsigned offset, unsigned state)
  55. {
  56. char *result = NULL;
  57. const char *name = clish_command__get_name(cmd);
  58. char *text = lub_string_dup(&line[offset]);
  59. unsigned index;
  60. const clish_param_t *param = NULL;
  61. clish_ptype_t *ptype;
  62. unsigned idx;
  63. /* get the index of the current parameter */
  64. index = lub_argv_wordcount(line) - lub_argv_wordcount(name);
  65. if ((0 != index) || (line[offset - 1] == ' ')) {
  66. if (0 == state) {
  67. lub_argv_t *argv;
  68. clish_pargv_t *pargv;
  69. unsigned i;
  70. if ((0 != index) && (text[0] != '\0')) {
  71. /* if there is some text for the parameter then adjust the index */
  72. index--;
  73. }
  74. argv = lub_argv_new(line, 0);
  75. idx = lub_argv_wordcount(name);
  76. if (this->completion_pargv) {
  77. clish_pargv_delete(this->completion_pargv);
  78. this->completion_pargv = NULL;
  79. }
  80. this->completion_pargv = clish_pargv_create();
  81. pargv = clish_pargv_create();
  82. clish_pargv_parse(pargv, cmd, clish_command__get_paramv(cmd),
  83. argv, &idx, this->completion_pargv, index + idx);
  84. clish_pargv_delete(pargv);
  85. lub_argv_delete(argv);
  86. this->completion_index = 0;
  87. this->completion_pindex = 0;
  88. }
  89. while ((param = clish_pargv__get_param(this->completion_pargv,
  90. this->completion_index++))) {
  91. if (param == clish_command__get_args(cmd)) {
  92. /* The param is args so it has no format */
  93. result = lub_string_dup(text);
  94. } else if (CLISH_PARAM_SUBCOMMAND ==
  95. clish_param__get_mode(param)) {
  96. /* The subcommand is identified by it's value */
  97. result = lub_string_dup(clish_param__get_value(param));
  98. } else if (CLISH_PARAM_SWITCH ==
  99. clish_param__get_mode(param)) {
  100. /* The switch has no completion string */
  101. result = NULL;
  102. } else {
  103. /* The common param. Let ptype do the work */
  104. if (ptype = clish_param__get_ptype(param)) {
  105. result = clish_ptype_word_generator(ptype, text,
  106. this->completion_pindex++);
  107. if (!result)
  108. this->completion_pindex = 0;
  109. else
  110. this->completion_index--;
  111. } else {
  112. result = NULL;
  113. }
  114. }
  115. if (result)
  116. break;
  117. }
  118. } else if (0 == state) {
  119. /* simply return the command name */
  120. result = lub_string_dup(clish_command__get_suffix(cmd));
  121. }
  122. if (!result) {
  123. clish_pargv_delete(this->completion_pargv);
  124. this->completion_pargv = NULL;
  125. /* make sure we reset the line state */
  126. // tinyrl_crlf(this->tinyrl);
  127. // tinyrl_reset_line_state(this->tinyrl);
  128. // tinyrl_completion_error_over(this->tinyrl);
  129. }
  130. lub_string_free(text);
  131. return result;
  132. }
  133. /*--------------------------------------------------------- */
  134. static char *clish_shell_command_generator(clish_shell_t * this,
  135. const char *line,
  136. unsigned offset, unsigned state)
  137. {
  138. char *result = NULL;
  139. const clish_command_t *cmd = NULL;
  140. if (0 == state) {
  141. cmd =
  142. clish_shell_getfirst_command(this, line,
  143. CLISH_NSPACE_COMPLETION);
  144. } else {
  145. cmd = clish_shell_getnext_command(this, line);
  146. }
  147. if (NULL != cmd) {
  148. result = lub_string_dup(clish_command__get_suffix(cmd));
  149. }
  150. /* keep the compiler happy */
  151. offset = offset;
  152. return result;
  153. }
  154. /*--------------------------------------------------------- */
  155. char *clish_shell_word_generator(clish_shell_t * this,
  156. const char *line,
  157. unsigned offset, unsigned state)
  158. {
  159. char *result = NULL;
  160. const clish_command_t *cmd, *next = NULL;
  161. /* try and resolve a command which is a prefix of the line */
  162. cmd = clish_shell_resolve_command(this, line);
  163. if (NULL != cmd) {
  164. clish_shell_iterator_t iter;
  165. /* see whether there is an extended extension */
  166. clish_shell_iterator_init(&iter, CLISH_NSPACE_COMPLETION);
  167. next = clish_shell_find_next_completion(this, line, &iter);
  168. clish_shell_iterator_fini(&iter);
  169. }
  170. if ((NULL != cmd) && (NULL == next)) {
  171. /* this needs to be completed as a parameter */
  172. result =
  173. clish_shell_param_generator(this, cmd, line, offset,
  174. state);
  175. } else {
  176. /* this needs to be completed as a command */
  177. result =
  178. clish_shell_command_generator(this, line, offset, state);
  179. }
  180. if (0 == state) {
  181. /* reset the state from a help perspective */
  182. this->state = SHELL_STATE_READY;
  183. }
  184. return result;
  185. }
  186. /*--------------------------------------------------------- */