shell_command_generator.c 5.2 KB

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