Skip to content

Commit

Permalink
Merge pull request #393 from AvaloniaUI/fix-355
Browse files Browse the repository at this point in the history
Fix replace next functionality
  • Loading branch information
maxkatz6 authored Feb 14, 2024
2 parents 17a7ee3 + db770d2 commit cfaddb7
Show file tree
Hide file tree
Showing 4 changed files with 378 additions and 140 deletions.
74 changes: 40 additions & 34 deletions src/AvaloniaEdit/Search/SearchPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ private static void SearchPatternChangedCallback(AvaloniaPropertyChangedEventArg
{
if (e.Sender is SearchPanel panel)
{
panel.ValidateSearchText();
panel.UpdateSearch();
}
}
Expand All @@ -156,7 +155,7 @@ private void UpdateSearch()
// if results are found by the next run, the message will be hidden inside DoSearch ...
try
{
if (_renderer.CurrentResults.Any())
if (_renderer.CurrentResults.Any() && _messageView != null)
_messageView.IsVisible = false;
_strategy = SearchStrategyFactory.Create(SearchPattern ?? "", !MatchCase, WholeWords, UseRegex ? SearchMode.RegEx : SearchMode.Normal);
OnSearchOptionsChanged(new SearchOptionsChangedEventArgs(SearchPattern, MatchCase, UseRegex, WholeWords));
Expand Down Expand Up @@ -270,14 +269,6 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
_messageViewContent = e.NameScope.Find<TextBlock>("PART_MessageContent");
}

private void ValidateSearchText()
{
if (_searchTextBox == null)
return;

UpdateSearch();
}

/// <summary>
/// Reactivates the SearchPanel by setting the focus on the search box and selecting all text.
/// </summary>
Expand All @@ -291,17 +282,15 @@ public void Reactivate()
}

/// <summary>
/// Moves to the next occurrence in the file.
/// Moves to the next occurrence in the file starting at the next position from current caret offset.
/// </summary>
public void FindNext()
public void FindNext(int startOffset = -1)
{
var result = _renderer.CurrentResults.FindFirstSegmentWithStartAfter(_textArea.Caret.Offset + 1) ??
var result = _renderer.CurrentResults.FindFirstSegmentWithStartAfter(startOffset == -1 ? _textArea.Caret.Offset : startOffset) ??
_renderer.CurrentResults.FirstSegment;
if (result != null)
{
_currentSearchResultIndex = GetSearchResultIndex(_renderer.CurrentResults, result);
SelectResult(result);
UpdateSearchLabel();
SetCurrentSearchResult(result);
}
}

Expand All @@ -310,24 +299,23 @@ public void FindNext()
/// </summary>
public void FindPrevious()
{
var result = _renderer.CurrentResults.FindFirstSegmentWithStartAfter(_textArea.Caret.Offset);
var result = _renderer.CurrentResults.FindFirstSegmentWithStartAfter(
Math.Max(_textArea.Caret.Offset - _textArea.Selection.Length, 0));
if (result != null)
result = _renderer.CurrentResults.GetPreviousSegment(result);
if (result == null)
result = _renderer.CurrentResults.LastSegment;
if (result != null)
{
_currentSearchResultIndex = GetSearchResultIndex(_renderer.CurrentResults, result);
SelectResult(result);
UpdateSearchLabel();
SetCurrentSearchResult(result);
}
}

public void ReplaceNext()
{
if (!IsReplaceMode) return;

FindNext();
FindNext(Math.Max(_textArea.Caret.Offset - _textArea.Selection.Length, 0));
if (!_textArea.Selection.IsEmpty)
{
_textArea.Selection.ReplaceSelectionWithText(ReplacePattern ?? string.Empty);
Expand Down Expand Up @@ -356,31 +344,46 @@ public void ReplaceAll()
private Panel _messageView;
private TextBlock _messageViewContent;

private void SetCurrentSearchResult(SearchResult result)
{
_currentSearchResultIndex = GetSearchResultIndex(_renderer.CurrentResults, result);
SelectResult(result);
UpdateSearchLabel();
}

private void DoSearch(bool changeSelection)
{
if (IsClosed)
return;

CleanSearchResults();

var offset = Math.Max(_textArea.Caret.Offset - _textArea.Selection.Length, 0);

if (changeSelection)
{
_textArea.ClearSelection();
}

if (!string.IsNullOrEmpty(SearchPattern))
{
var offset = _textArea.Caret.Offset;
if (changeSelection)
{
_textArea.ClearSelection();
}

// We cast from ISearchResult to SearchResult; this is safe because we always use the built-in strategy
foreach (var result in _strategy.FindAll(_textArea.Document, 0, _textArea.Document.TextLength).Cast<SearchResult>())
{
_renderer.CurrentResults.Add(result);
if (changeSelection && result.StartOffset >= offset)
{
}

if (changeSelection)
{
// select the first result after the caret position
// or the first result in document order if there is no result after the caret
var result = _renderer.CurrentResults.FindFirstSegmentWithStartAfter(offset) ??
_renderer.CurrentResults.FirstSegment;

if (result != null)
SelectResult(result);
_currentSearchResultIndex = _renderer.CurrentResults.Count - 1;
changeSelection = false;
}

_currentSearchResultIndex = _renderer.CurrentResults.Count - 1;
}
}

Expand Down Expand Up @@ -430,7 +433,7 @@ void UpdateSearchLabel()

private void SelectResult(TextSegment result)
{
_textArea.Caret.Offset = result.StartOffset;
_textArea.Caret.Offset = result.EndOffset;
_textArea.Selection = Selection.Create(_textArea, result.StartOffset, result.EndOffset);

double distanceToViewBorder = _border == null ?
Expand Down Expand Up @@ -480,7 +483,10 @@ private void SearchLayerKeyDown(object sender, KeyEventArgs e)
public void Close()
{
_textArea.RemoveChild(this);
_messageView.IsVisible = false;

if (_messageView != null)
_messageView.IsVisible = false;

_textArea.TextView.BackgroundRenderers.Remove(_renderer);

IsClosed = true;
Expand Down
15 changes: 13 additions & 2 deletions test/AvaloniaEdit.Tests/AvaloniaMocks/UnitTestApplication.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Avalonia;
using System;
using Avalonia;
using Avalonia.Headless;
using Avalonia.Markup.Xaml.Styling;
using AvaloniaEdit.AvaloniaMocks;

[assembly: AvaloniaTestApplication(typeof(UnitTestApplication))]
Expand All @@ -8,12 +10,21 @@ namespace AvaloniaEdit.AvaloniaMocks
{
public class UnitTestApplication : Application
{

public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<UnitTestApplication>()
.UseHeadless(new AvaloniaHeadlessPlatformOptions
{
UseHeadlessDrawing = true
});

public static void InitializeStyles()
{
ResourceInclude styleInclude = new ResourceInclude(new Uri("avares://AvaloniaEdit"))
{
Source = new Uri("/Themes/Base.xaml", UriKind.Relative)
};

Application.Current?.Resources.MergedDictionaries.Add(styleInclude);
}
}
}
Loading

0 comments on commit cfaddb7

Please sign in to comment.