2
0

TextView.Find.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. namespace Terminal.Gui.Views;
  2. /// <summary>Find and Replace functionality</summary>
  3. public partial class TextView
  4. {
  5. #region Public Find/Replace Methods
  6. /// <summary>Find the next text based on the match case with the option to replace it.</summary>
  7. /// <param name="textToFind">The text to find.</param>
  8. /// <param name="gaveFullTurn"><c>true</c>If all the text was forward searched.<c>false</c>otherwise.</param>
  9. /// <param name="matchCase">The match case setting.</param>
  10. /// <param name="matchWholeWord">The match whole word setting.</param>
  11. /// <param name="textToReplace">The text to replace.</param>
  12. /// <param name="replace"><c>true</c>If is replacing.<c>false</c>otherwise.</param>
  13. /// <returns><c>true</c>If the text was found.<c>false</c>otherwise.</returns>
  14. public bool FindNextText (
  15. string textToFind,
  16. out bool gaveFullTurn,
  17. bool matchCase = false,
  18. bool matchWholeWord = false,
  19. string? textToReplace = null,
  20. bool replace = false
  21. )
  22. {
  23. if (_model.Count == 0)
  24. {
  25. gaveFullTurn = false;
  26. return false;
  27. }
  28. SetWrapModel ();
  29. ResetContinuousFind ();
  30. (Point current, bool found) foundPos =
  31. _model.FindNextText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
  32. return SetFoundText (textToFind, foundPos, textToReplace, replace);
  33. }
  34. /// <summary>Find the previous text based on the match case with the option to replace it.</summary>
  35. /// <param name="textToFind">The text to find.</param>
  36. /// <param name="gaveFullTurn"><c>true</c>If all the text was backward searched.<c>false</c>otherwise.</param>
  37. /// <param name="matchCase">The match case setting.</param>
  38. /// <param name="matchWholeWord">The match whole word setting.</param>
  39. /// <param name="textToReplace">The text to replace.</param>
  40. /// <param name="replace"><c>true</c>If the text was found.<c>false</c>otherwise.</param>
  41. /// <returns><c>true</c>If the text was found.<c>false</c>otherwise.</returns>
  42. public bool FindPreviousText (
  43. string textToFind,
  44. out bool gaveFullTurn,
  45. bool matchCase = false,
  46. bool matchWholeWord = false,
  47. string? textToReplace = null,
  48. bool replace = false
  49. )
  50. {
  51. if (_model.Count == 0)
  52. {
  53. gaveFullTurn = false;
  54. return false;
  55. }
  56. SetWrapModel ();
  57. ResetContinuousFind ();
  58. (Point current, bool found) foundPos =
  59. _model.FindPreviousText (textToFind, out gaveFullTurn, matchCase, matchWholeWord);
  60. return SetFoundText (textToFind, foundPos, textToReplace, replace);
  61. }
  62. /// <summary>Reset the flag to stop continuous find.</summary>
  63. public void FindTextChanged () { _continuousFind = false; }
  64. /// <summary>Replaces all the text based on the match case.</summary>
  65. /// <param name="textToFind">The text to find.</param>
  66. /// <param name="matchCase">The match case setting.</param>
  67. /// <param name="matchWholeWord">The match whole word setting.</param>
  68. /// <param name="textToReplace">The text to replace.</param>
  69. /// <returns><c>true</c>If the text was found.<c>false</c>otherwise.</returns>
  70. public bool ReplaceAllText (
  71. string textToFind,
  72. bool matchCase = false,
  73. bool matchWholeWord = false,
  74. string? textToReplace = null
  75. )
  76. {
  77. if (_isReadOnly || _model.Count == 0)
  78. {
  79. return false;
  80. }
  81. SetWrapModel ();
  82. ResetContinuousFind ();
  83. (Point current, bool found) foundPos =
  84. _model.ReplaceAllText (textToFind, matchCase, matchWholeWord, textToReplace);
  85. return SetFoundText (textToFind, foundPos, textToReplace, false, true);
  86. }
  87. #endregion
  88. #region Private Find Helper Methods
  89. private void ResetContinuousFind ()
  90. {
  91. if (!_continuousFind)
  92. {
  93. int col = IsSelecting ? _selectionStartColumn : CurrentColumn;
  94. int row = IsSelecting ? _selectionStartRow : CurrentRow;
  95. _model.ResetContinuousFind (new (col, row));
  96. }
  97. }
  98. private void ResetContinuousFindTrack ()
  99. {
  100. // Handle some state here - whether the last command was a kill
  101. // operation and the column tracking (up/down)
  102. _lastWasKill = false;
  103. _continuousFind = false;
  104. }
  105. private bool SetFoundText (
  106. string text,
  107. (Point current, bool found) foundPos,
  108. string? textToReplace = null,
  109. bool replace = false,
  110. bool replaceAll = false
  111. )
  112. {
  113. if (foundPos.found)
  114. {
  115. StartSelecting ();
  116. _selectionStartColumn = foundPos.current.X;
  117. _selectionStartRow = foundPos.current.Y;
  118. if (!replaceAll)
  119. {
  120. CurrentColumn = _selectionStartColumn + text.GetRuneCount ();
  121. }
  122. else
  123. {
  124. CurrentColumn = _selectionStartColumn + textToReplace!.GetRuneCount ();
  125. }
  126. CurrentRow = foundPos.current.Y;
  127. if (!_isReadOnly && replace)
  128. {
  129. Adjust ();
  130. ClearSelectedRegion ();
  131. InsertAllText (textToReplace!);
  132. StartSelecting ();
  133. _selectionStartColumn = CurrentColumn - textToReplace!.GetRuneCount ();
  134. }
  135. else
  136. {
  137. UpdateWrapModel ();
  138. SetNeedsDraw ();
  139. Adjust ();
  140. }
  141. _continuousFind = true;
  142. return foundPos.found;
  143. }
  144. UpdateWrapModel ();
  145. _continuousFind = false;
  146. return foundPos.found;
  147. }
  148. private IEnumerable<(int col, int row, Cell rune)> ForwardIterator (int col, int row)
  149. {
  150. if (col < 0 || row < 0)
  151. {
  152. yield break;
  153. }
  154. if (row >= _model.Count)
  155. {
  156. yield break;
  157. }
  158. List<Cell> line = GetCurrentLine ();
  159. if (col >= line.Count)
  160. {
  161. yield break;
  162. }
  163. while (row < _model.Count)
  164. {
  165. for (int c = col; c < line.Count; c++)
  166. {
  167. yield return (c, row, line [c]);
  168. }
  169. col = 0;
  170. row++;
  171. line = GetCurrentLine ();
  172. }
  173. }
  174. #endregion
  175. }