Add 'matchExactCase' parameter for ViewPort.Find

This commit is contained in:
Benjamin Popp 2021-06-21 22:20:12 -05:00
parent cde4328bc0
commit a278d91f9f
7 changed files with 34 additions and 24 deletions

View File

@ -24,8 +24,10 @@ namespace HavenSoft.HexManiac.Core.Models {
private static readonly int CapitalE = PCSString.PCS.IndexOf("E");
private static readonly int LowerE = PCSString.PCS.IndexOf("e");
private readonly byte match1, match2;
public static ISearchByte Create(byte value) {
if (value == CapitalE || value == CapitalEWithAccent || value == LowerE || value == LowerEWithAccent) {
public static ISearchByte Create(byte value, bool matchExactCase) {
if (matchExactCase) {
return new ExactMatchSearchByte(value);
} else if (value == CapitalE || value == CapitalEWithAccent || value == LowerE || value == LowerEWithAccent) {
return MatchESearchByte.Instance;
} else {
return new PCSSearchByte(value);
@ -51,5 +53,11 @@ namespace HavenSoft.HexManiac.Core.Models {
private MatchESearchByte() { }
public bool Match(byte value) => value == CapitalE || value == CapitalEWithAccent || value == LowerE || value == LowerEWithAccent;
}
private class ExactMatchSearchByte : ISearchByte {
private byte value;
public ExactMatchSearchByte(byte value) => this.value = value;
public bool Match(byte value) => value == this.value;
}
}
}

View File

@ -159,7 +159,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public void ExpandSelection(int x, int y) => ForEach(child => child.ExpandSelection(x, y));
public IReadOnlyList<(int start, int end)> Find(string search) => new (int, int)[0];
public IReadOnlyList<(int start, int end)> Find(string search, bool matchExactCase = false) => new (int, int)[0];
public void FindAllSources(int x, int y) { }

View File

@ -139,7 +139,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public void ExpandSelection(int x, int y) { }
public IReadOnlyList<(int start, int end)> Find(string search) => throw new NotImplementedException();
public IReadOnlyList<(int start, int end)> Find(string search, bool matchExactCase = false) => throw new NotImplementedException();
public void FindAllSources(int x, int y) { }

View File

@ -45,7 +45,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
bool IsSelected(Point point);
bool IsTable(Point point);
IReadOnlyList<(int start, int end)> Find(string search);
IReadOnlyList<(int start, int end)> Find(string search, bool matchExactCase = false);
IChildViewPort CreateChildView(int startAddress, int endAddress);
void FollowLink(int x, int y);
void ExpandSelection(int x, int y);

View File

@ -174,7 +174,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
public IChildViewPort CreateChildView(int startAddress, int endAddress) => throw new NotImplementedException();
// if asked to search the search results... just don't
public IReadOnlyList<(int, int)> Find(string search) => new (int, int)[0];
public IReadOnlyList<(int, int)> Find(string search, bool matchExactCase = false) => new (int, int)[0];
public bool UseCustomHeaders {
get => children.FirstOrDefault()?.UseCustomHeaders ?? false;

View File

@ -1458,14 +1458,15 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
#region Find
public IReadOnlyList<(int start, int end)> Find(string rawSearch) {
public IReadOnlyList<(int start, int end)> Find(string rawSearch, bool matchExactCase = false) {
var results = new List<(int start, int end)>();
var cleanedSearchString = rawSearch.ToUpper();
var cleanedSearchString = rawSearch;
if (!matchExactCase) cleanedSearchString = rawSearch.ToUpper();
var searchBytes = new List<ISearchByte>();
// it might be a string with no quotes, we should check for matches for that.
if (cleanedSearchString.Length > 3 && !cleanedSearchString.Contains(StringDelimeter) && !cleanedSearchString.All(AllHexCharacters.Contains)) {
results.AddRange(FindUnquotedText(cleanedSearchString, searchBytes));
results.AddRange(FindUnquotedText(cleanedSearchString, searchBytes, matchExactCase));
}
// it might be a matched-word
@ -1548,14 +1549,14 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
}
}
private IEnumerable<(int start, int end)> FindUnquotedText(string cleanedSearchString, List<ISearchByte> searchBytes) {
private IEnumerable<(int start, int end)> FindUnquotedText(string cleanedSearchString, List<ISearchByte> searchBytes, bool matchExactCase) {
var pcsBytes = PCSString.Convert(cleanedSearchString);
pcsBytes.RemoveAt(pcsBytes.Count - 1); // remove the 0xFF that was added, since we're searching for a string segment instead of a whole string.
// only search for the string if every character in the search string is allowed
if (pcsBytes.Count != cleanedSearchString.Length) yield break;
searchBytes.AddRange(pcsBytes.Select(PCSSearchByte.Create));
searchBytes.AddRange(pcsBytes.Select(b => PCSSearchByte.Create(b, matchExactCase)));
var textResults = Model.Search(searchBytes).ToList();
Model.ConsiderResultsAsTextRuns(history.CurrentChange, textResults);
foreach (var result in textResults) {

View File

@ -12,6 +12,7 @@ namespace HavenSoft.HexManiac.Tests {
public class FindTests {
private static Func<int, int, ChildViewPort> CreateCreateChildView(Func<IViewPort> tab) => (start, end) => new ChildViewPort(tab(), InstantDispatch.Instance, BaseViewModelTestClass.Singletons);
private static ViewPort NewViewPort(IDataModel model) => new ViewPort("test.gba", model, InstantDispatch.Instance, BaseViewModelTestClass.Singletons);
private static Func<string, bool, (int, int)[]> DefaultFind(params (int, int)[] results) => (text, matchExactCase) => results;
[Fact]
public void FindCanFindSingle() {
@ -45,7 +46,7 @@ namespace HavenSoft.HexManiac.Tests {
var tab = new StubViewPort();
var editor = new EditorViewModel(new StubFileSystem()) { tab };
tab.Find = str => new (int, int)[0];
tab.Find = DefaultFind();
editor.Find.Execute("something");
Assert.True(editor.ShowError);
@ -58,7 +59,7 @@ namespace HavenSoft.HexManiac.Tests {
var editor = new EditorViewModel(new StubFileSystem()) { tab };
string gotoArg = string.Empty;
tab.Find = str => new[] { (0x54, 0x54) };
tab.Find = DefaultFind((0x54, 0x54));
tab.Goto = new StubCommand { CanExecute = arg => true, Execute = arg => gotoArg = (string)arg };
editor.Find.Execute("something");
@ -72,7 +73,7 @@ namespace HavenSoft.HexManiac.Tests {
var editor = new EditorViewModel(new StubFileSystem()) { tab };
var count = 0;
tab.Find = str => new[] { (0x54, 0x54), (0x154, 0x154) };
tab.Find = DefaultFind((0x54, 0x54), (0x154, 0x154));
tab.Model = new BasicModel(new byte[0x200]);
tab.CreateChildView = (int startAddress, int endAddress) => {
var child = new ChildViewPort(tab, InstantDispatch.Instance, BaseViewModelTestClass.Singletons);
@ -92,7 +93,7 @@ namespace HavenSoft.HexManiac.Tests {
int gotoCount = 0;
StubViewPort tab = null;
tab = new StubViewPort {
Find = str => new[] { (0x54, 0x54), (0x154, 0x154) },
Find = DefaultFind((0x54, 0x54), (0x154, 0x154)),
Model = new BasicModel(new byte[0x200]),
Goto = new StubCommand { CanExecute = arg => true, Execute = arg => gotoCount++ },
CreateChildView = (start, end) => new ChildViewPort(tab, InstantDispatch.Instance, BaseViewModelTestClass.Singletons),
@ -114,7 +115,7 @@ namespace HavenSoft.HexManiac.Tests {
public void EditorFindNextDoesNotSwitchTabs() {
StubViewPort tab1 = null;
tab1 = new StubViewPort {
Find = query => new[] { (0x60, 0x60) },
Find = DefaultFind((0x60, 0x60)),
Goto = new StubCommand(),
Model = new BasicModel(new byte[0x200]),
CreateChildView = CreateCreateChildView(() => tab1),
@ -124,7 +125,7 @@ namespace HavenSoft.HexManiac.Tests {
};
StubViewPort tab2 = null;
tab2 = new StubViewPort {
Find = query => new[] { (0x50, 0x50), (0x70, 0x70) },
Find = DefaultFind((0x50, 0x50), (0x70, 0x70)),
Goto = new StubCommand(),
Model = new BasicModel(new byte[0x200]),
CreateChildView = CreateCreateChildView(() => tab2),
@ -152,7 +153,7 @@ namespace HavenSoft.HexManiac.Tests {
public void FindResultsHasHeadersAndGaps() {
StubViewPort tab = null;
tab = new StubViewPort {
Find = query => new[] { (0x50, 0x50), (0x70, 0x70) },
Find = DefaultFind((0x50, 0x50), (0x70, 0x70)),
Goto = new StubCommand(),
Model = new BasicModel(new byte[0x200]),
CreateChildView = CreateCreateChildView(() => tab),
@ -173,7 +174,7 @@ namespace HavenSoft.HexManiac.Tests {
public void FindClosesAfterRun() {
StubViewPort tab = null;
tab = new StubViewPort {
Find = query => new[] { (0x50, 0x50), (0x70, 0x70) },
Find = DefaultFind((0x50, 0x50), (0x70, 0x70)),
Goto = new StubCommand(),
Model = new BasicModel(new byte[0x200]),
CreateChildView = CreateCreateChildView(() => tab),
@ -234,7 +235,7 @@ namespace HavenSoft.HexManiac.Tests {
var tab1 = new StubTabContent();
var editor = new EditorViewModel(new StubFileSystem()) { tab0, tab1 };
tab0.Find = query => new[] { (0x50, 0x50) };
tab0.Find = DefaultFind((0x50, 0x50));
editor.Find.Execute("search");
Assert.Equal(0, editor.SelectedIndex);
@ -253,7 +254,7 @@ namespace HavenSoft.HexManiac.Tests {
var editor = new EditorViewModel(new StubFileSystem());
StubViewPort tab = null;
tab = new StubViewPort {
Find = query => new[] { (0x50, 0x50) },
Find = DefaultFind((0x50, 0x50)),
Goto = new StubCommand(),
CreateChildView = CreateCreateChildView(() => tab),
Headers = new ObservableCollection<string> { "00", "01", "02", "03" },
@ -273,7 +274,7 @@ namespace HavenSoft.HexManiac.Tests {
var editor = new EditorViewModel(new StubFileSystem());
StubViewPort tab = null;
tab = new StubViewPort {
Find = query => new[] { (0x50, 0x50), (0x70, 0x70) },
Find = DefaultFind((0x50, 0x50), (0x70, 0x70)),
Goto = new StubCommand(),
Model = new BasicModel(new byte[0x200]),
CreateChildView = CreateCreateChildView(() => tab),
@ -404,7 +405,7 @@ namespace HavenSoft.HexManiac.Tests {
[Fact]
public void SameModelDoesNotGetSearchedMultipleTimes() {
int findCalls = 0;
IReadOnlyList<(int, int)> Find(string input) {
IReadOnlyList<(int, int)> Find(string input, bool matchExactCase = false) {
findCalls += 1;
return new List<(int, int)>();
}
@ -422,7 +423,7 @@ namespace HavenSoft.HexManiac.Tests {
[Fact]
public void DifferentModelsAllGetSearched() {
int findCalls = 0;
IReadOnlyList<(int, int)> Find(string input) {
IReadOnlyList<(int, int)> Find(string input, bool matchExactCase = false) {
findCalls += 1;
return new List<(int, int)>();
}