shellmatta_autocomplete.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) 2019 - 2021 Stefan Strobel <stefan.strobel@shimatta.net>
  3. *
  4. * This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  7. */
  8. /**
  9. * @file shellmatta_autocomplete.c
  10. * @brief autocomplete function of shellmatta
  11. * @author Stefan Strobel <stefan.strobel@shimatta.net>
  12. */
  13. /**
  14. * @addtogroup shellmatta_autocomplete
  15. * @{
  16. */
  17. #include "shellmatta.h"
  18. #include "shellmatta_autocomplete.h"
  19. #include "shellmatta_utils.h"
  20. #include <stdint.h>
  21. #include <string.h>
  22. /**
  23. * @brief searches the registered commands for matching ones and prints
  24. * the common part of all matching commands on the output
  25. * if called twice all matching commands are printed
  26. * @param[in] inst pointer to a shellmatta instance
  27. */
  28. void autocomplete_run(shellmatta_instance_t *inst)
  29. {
  30. shellmatta_cmd_t *cmd = inst->cmdList;
  31. char *tempCmd = NULL;
  32. uint32_t minLen = 0u;
  33. bool exactMatch = true;
  34. uint32_t printedLen = 0u;
  35. uint32_t sizeDiff;
  36. uint32_t tempCursor;
  37. /** -# increase the tab counter to print all matching commands next time */
  38. inst->tabCounter++;
  39. /** -# on douple tab show all matching commands */
  40. if (inst->tabCounter > 1u)
  41. {
  42. inst->tabCounter = 0u;
  43. /** -# loop through all registered commands */
  44. while (NULL != cmd)
  45. {
  46. /** -# check if command matches the input */
  47. if( (strlen(cmd->cmd) >= inst->cursor)
  48. && (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor)))
  49. {
  50. /** -# add newline on first find */
  51. if(0u == printedLen)
  52. {
  53. SHELLMATTA_WRITE("\r\n", 2u);
  54. }
  55. SHELLMATTA_WRITE(cmd->cmd, strlen(cmd->cmd));
  56. printedLen += strlen(cmd->cmd);
  57. SHELLMATTA_WRITE(" ", 4u);
  58. printedLen += 4u;
  59. }
  60. /** -# check if command alias matches the input */
  61. if( (NULL != cmd->cmdAlias)
  62. && (strlen(cmd->cmdAlias) >= inst->cursor)
  63. && (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
  64. {
  65. /** -# add newline on first find */
  66. if(0u == printedLen)
  67. {
  68. SHELLMATTA_WRITE("\r\n", 2u);
  69. }
  70. SHELLMATTA_WRITE(cmd->cmdAlias, strlen(cmd->cmdAlias));
  71. printedLen += strlen(cmd->cmdAlias);
  72. SHELLMATTA_WRITE(" ", 4u);
  73. printedLen += 4u;
  74. }
  75. cmd = cmd->next;
  76. }
  77. /** -# print input again if a commands was found */
  78. if(printedLen > 0u)
  79. {
  80. utils_writeEcho(inst, "\r\n", 2u);
  81. utils_writeEcho(inst, inst->prompt, strlen(inst->prompt));
  82. utils_writeEcho(inst, inst->buffer, inst->inputCount);
  83. tempCursor = inst->cursor;
  84. inst->cursor = inst->inputCount;
  85. utils_rewindCursor(inst, inst->inputCount - tempCursor);
  86. }
  87. }
  88. /** -# on single tab autocomplete as far as possible */
  89. else if(0u != inst->cursor)
  90. {
  91. /** -# loop through all registered commands */
  92. while (NULL != cmd)
  93. {
  94. /** -# check if command matches the input */
  95. if( (strlen(cmd->cmd) >= inst->cursor)
  96. && (0 == strncmp(cmd->cmd, inst->buffer, inst->cursor)))
  97. {
  98. /** -# store first match */
  99. if(NULL == tempCmd)
  100. {
  101. tempCmd = cmd->cmd;
  102. minLen = strlen(cmd->cmd);
  103. }
  104. /** -# find common part of the matching commands */
  105. else
  106. {
  107. exactMatch = false;
  108. minLen = SHELLMATTA_MIN(strlen(cmd->cmd), minLen);
  109. for(uint32_t i = 0u; i < minLen; i++)
  110. {
  111. if(cmd->cmd[i] != tempCmd[i])
  112. {
  113. minLen = i;
  114. }
  115. }
  116. }
  117. }
  118. /** -# check if command Alias matches the input */
  119. if( (NULL != cmd->cmdAlias)
  120. && (strlen(cmd->cmdAlias) >= inst->cursor)
  121. && (0 == strncmp(cmd->cmdAlias, inst->buffer, inst->cursor)))
  122. {
  123. /** -# store first match */
  124. if(NULL == tempCmd)
  125. {
  126. tempCmd = cmd->cmdAlias;
  127. minLen = strlen(cmd->cmdAlias);
  128. }
  129. /** -# find common part of the matches */
  130. else
  131. {
  132. exactMatch = false;
  133. minLen = SHELLMATTA_MIN(strlen(cmd->cmdAlias), minLen);
  134. for(uint32_t i = 0u; i < minLen; i++)
  135. {
  136. if(cmd->cmdAlias[i] != tempCmd[i])
  137. {
  138. minLen = i;
  139. }
  140. }
  141. }
  142. }
  143. cmd = cmd->next;
  144. }
  145. /** -# autocomplete found command */
  146. if(NULL != tempCmd)
  147. {
  148. /** -# calculate the size of the command to be inserted */
  149. sizeDiff = minLen - inst->cursor;
  150. /** -# copy the found part into the buffer and display it */
  151. utils_insertChars(inst, &(tempCmd[inst->cursor]), sizeDiff);
  152. /** -# on exact match there is no need to double Tab to display all */
  153. if(true == exactMatch)
  154. {
  155. inst->tabCounter = 0u;
  156. }
  157. }
  158. }
  159. else
  160. {
  161. /* nothing to do here */
  162. }
  163. }
  164. /**
  165. * @}
  166. */