shellmatta_escape.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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_escape.c
  10. * @brief functions to parse and generate escape sequences
  11. * @author Stefan Strobel <stefan.strobel@shimatta.net>
  12. */
  13. /**
  14. * @addtogroup shellmatta_escape
  15. * @{
  16. */
  17. #include "shellmatta.h"
  18. #include "shellmatta_escape.h"
  19. #include "shellmatta_utils.h"
  20. #include "shellmatta_history.h"
  21. #include "shellmatta_autocomplete.h"
  22. #include <stdint.h>
  23. /**
  24. * @brief processes the excape character stream of the instance and checks
  25. * if an arrow key was pressed
  26. * @param[in] inst pointer to a shellmatta instance
  27. * @return #SHELLMATTA_OK if an arrow key was pressed
  28. */
  29. shellmatta_retCode_t escape_processArrowKeys(shellmatta_instance_t *inst)
  30. {
  31. shellmatta_retCode_t ret = SHELLMATTA_USE_FAULT;
  32. if ('[' == inst->escapeChars[0])
  33. {
  34. ret = SHELLMATTA_OK;
  35. switch (inst->escapeChars[1])
  36. {
  37. case 'A': /* arrow up */
  38. history_storeCmd(inst);
  39. if(false == inst->historyReadUp)
  40. {
  41. (void)history_navigate(inst, -1);
  42. }
  43. inst->historyReadUp = true;
  44. history_restoreCmd(inst);
  45. (void)history_navigate(inst, -1);
  46. break;
  47. case 'B': /* arrow down */
  48. /*! -# ignore the key if the history buffer points to the last entry */
  49. if((inst->historyRead != inst->historyEnd))
  50. {
  51. history_storeCmd(inst);
  52. if(true == inst->historyReadUp)
  53. {
  54. (void)history_navigate(inst, 1);
  55. }
  56. inst->historyReadUp = false;
  57. (void)history_navigate(inst, 1);
  58. history_restoreCmd(inst);
  59. }
  60. break;
  61. case 'C': /* arrow right */
  62. utils_forwardCursor(inst, 1u);
  63. break;
  64. case 'D': /* arrow left */
  65. utils_rewindCursor(inst, 1u);
  66. break;
  67. default:
  68. /** ignore unknown escape */
  69. ret = SHELLMATTA_USE_FAULT;
  70. break;
  71. }
  72. }
  73. return ret;
  74. }
  75. /**
  76. * @brief handles a ANSI escape sequence to be able to react to some
  77. * special keys
  78. * @param[in] inst pointer to a shellmatta instance
  79. * @param[in] data new received character of the escape sequence
  80. */
  81. void escape_handleSequence(shellmatta_instance_t *inst, char data)
  82. {
  83. switch (inst->escapeCounter)
  84. {
  85. case 1u:
  86. inst->escapeChars[inst->escapeCounter - 1] = data;
  87. inst->escapeCounter ++;
  88. break;
  89. case 2u:
  90. inst->escapeChars[inst->escapeCounter - 1] = data;
  91. /** -# check if an arrow key was pressed */
  92. if(SHELLMATTA_OK == escape_processArrowKeys(inst))
  93. {
  94. inst->escapeCounter = 0u;
  95. }
  96. /** -# check if end was pressed */
  97. else if ( (0x4f == inst->escapeChars[0])
  98. && (0x46 == inst->escapeChars[1]))
  99. {
  100. utils_forwardCursor(inst, inst->inputCount - inst->cursor);
  101. inst->escapeCounter = 0u;
  102. }
  103. /** -# if the highest bit is not set this is usually not the end of the
  104. * sequence - so we go on */
  105. else if(0u == (0x40 & data))
  106. {
  107. inst->escapeCounter ++;
  108. }
  109. else
  110. {
  111. inst->escapeCounter = 0u;
  112. }
  113. break;
  114. case 3u:
  115. /** -# check if delete was pressed */
  116. inst->escapeChars[inst->escapeCounter - 1] = data;
  117. if( (0x5b == inst->escapeChars[0])
  118. && (0x33 == inst->escapeChars[1])
  119. && (0x7e == inst->escapeChars[2]))
  120. {
  121. utils_removeChars(inst, 1u, false);
  122. inst->escapeCounter = 0u;
  123. }
  124. /** -# check if pos1 was pressed */
  125. else if ( (0x5bu == inst->escapeChars[0])
  126. && (0x31u == inst->escapeChars[1])
  127. && (0x7eu == inst->escapeChars[2]))
  128. {
  129. utils_rewindCursor(inst, inst->cursor);
  130. inst->escapeCounter = 0u;
  131. }
  132. else if(0u == (0x40u & data))
  133. {
  134. inst->escapeCounter ++;
  135. }
  136. else
  137. {
  138. inst->escapeCounter = 0u;
  139. }
  140. break;
  141. default:
  142. inst->escapeCounter = 0u;
  143. break;
  144. }
  145. }
  146. /**
  147. * @}
  148. */