namespace Terminal.Gui.Views; /// Find and Replace functionality public partial class TextView { #region Public Find/Replace Methods /// Find the next text based on the match case with the option to replace it. /// The text to find. /// trueIf all the text was forward searched.falseotherwise. /// The match case setting. /// The match whole word setting. /// The text to replace. /// trueIf is replacing.falseotherwise. /// trueIf the text was found.falseotherwise. public bool FindNextText ( string textToFind, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false, string? textToReplace = null, bool replace = false ) { if (_model.Count == 0) { gaveFullTurn = false; return false; } SetWrapModel (); ResetContinuousFind (); (Point current, bool found) foundPos = _model.FindNextText (textToFind, out gaveFullTurn, matchCase, matchWholeWord); return SetFoundText (textToFind, foundPos, textToReplace, replace); } /// Find the previous text based on the match case with the option to replace it. /// The text to find. /// trueIf all the text was backward searched.falseotherwise. /// The match case setting. /// The match whole word setting. /// The text to replace. /// trueIf the text was found.falseotherwise. /// trueIf the text was found.falseotherwise. public bool FindPreviousText ( string textToFind, out bool gaveFullTurn, bool matchCase = false, bool matchWholeWord = false, string? textToReplace = null, bool replace = false ) { if (_model.Count == 0) { gaveFullTurn = false; return false; } SetWrapModel (); ResetContinuousFind (); (Point current, bool found) foundPos = _model.FindPreviousText (textToFind, out gaveFullTurn, matchCase, matchWholeWord); return SetFoundText (textToFind, foundPos, textToReplace, replace); } /// Reset the flag to stop continuous find. public void FindTextChanged () { _continuousFind = false; } /// Replaces all the text based on the match case. /// The text to find. /// The match case setting. /// The match whole word setting. /// The text to replace. /// trueIf the text was found.falseotherwise. public bool ReplaceAllText ( string textToFind, bool matchCase = false, bool matchWholeWord = false, string? textToReplace = null ) { if (_isReadOnly || _model.Count == 0) { return false; } SetWrapModel (); ResetContinuousFind (); (Point current, bool found) foundPos = _model.ReplaceAllText (textToFind, matchCase, matchWholeWord, textToReplace); return SetFoundText (textToFind, foundPos, textToReplace, false, true); } #endregion #region Private Find Helper Methods private void ResetContinuousFind () { if (!_continuousFind) { int col = IsSelecting ? _selectionStartColumn : CurrentColumn; int row = IsSelecting ? _selectionStartRow : CurrentRow; _model.ResetContinuousFind (new (col, row)); } } private void ResetContinuousFindTrack () { // Handle some state here - whether the last command was a kill // operation and the column tracking (up/down) _lastWasKill = false; _continuousFind = false; } private bool SetFoundText ( string text, (Point current, bool found) foundPos, string? textToReplace = null, bool replace = false, bool replaceAll = false ) { if (foundPos.found) { StartSelecting (); _selectionStartColumn = foundPos.current.X; _selectionStartRow = foundPos.current.Y; if (!replaceAll) { CurrentColumn = _selectionStartColumn + text.GetRuneCount (); } else { CurrentColumn = _selectionStartColumn + textToReplace!.GetRuneCount (); } CurrentRow = foundPos.current.Y; if (!_isReadOnly && replace) { Adjust (); ClearSelectedRegion (); InsertAllText (textToReplace!); StartSelecting (); _selectionStartColumn = CurrentColumn - textToReplace!.GetRuneCount (); } else { UpdateWrapModel (); SetNeedsDraw (); Adjust (); } _continuousFind = true; return foundPos.found; } UpdateWrapModel (); _continuousFind = false; return foundPos.found; } private IEnumerable<(int col, int row, Cell rune)> ForwardIterator (int col, int row) { if (col < 0 || row < 0) { yield break; } if (row >= _model.Count) { yield break; } List line = GetCurrentLine (); if (col >= line.Count) { yield break; } while (row < _model.Count) { for (int c = col; c < line.Count; c++) { yield return (c, row, line [c]); } col = 0; row++; line = GetCurrentLine (); } } #endregion }