implement find/goto for pointers

This commit is contained in:
Benjamin Popp
2018-12-09 13:07:14 -06:00
parent 40d70817a9
commit af64d4aad2
5 changed files with 82 additions and 23 deletions

View File

@@ -102,6 +102,8 @@ namespace HavenSoft.Gen3Hex.Core.Models {
return address;
}
if (requestSource < 0) return Pointer.NULL;
// the named anchor does not exist! Add it to the list of desired anchors
if (!unmappedNameToSources.ContainsKey(anchor)) {
unmappedNameToSources[anchor] = new List<int>();
@@ -264,7 +266,7 @@ namespace HavenSoft.Gen3Hex.Core.Models {
public class BasicModel : IModel {
public static IModel Instance { get; } = new BasicModel();
public int GetAddressFromAnchor(int requestSource, string anchor) => 0;
public int GetAddressFromAnchor(int requestSource, string anchor) => Pointer.NULL;
public string GetAnchorFromAddress(int requestSource, int destination) => string.Empty;
public IFormattedRun GetNextRun(int dataIndex) => null;
public void ObserveRunWritten(byte[] data, IFormattedRun run) { }

View File

@@ -1,4 +1,5 @@
using HavenSoft.Gen3Hex.Core.Models;
using HavenSoft.Gen3Hex.Core.ViewModels.DataFormats;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -65,7 +66,18 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
/// </summary>
public event EventHandler<Point> PreviewSelectionStartChanged;
public Selection(ScrollRegion scrollRegion) {
private void GotoAddress(int address) {
backStack.Push(scroll.DataIndex);
if (backStack.Count == 1) backward.CanExecuteChanged.Invoke(backward, EventArgs.Empty);
if (forwardStack.Count > 0) {
forward.CanExecuteChanged.Invoke(forward, EventArgs.Empty);
forwardStack.Clear();
}
SelectionStart = scroll.DataIndexToViewPoint(address);
scroll.ScrollValue += selectionStart.Y;
}
public Selection(ScrollRegion scrollRegion, IModel model) {
scroll = scrollRegion;
scroll.ScrollChanged += (sender, e) => ShiftSelectionFromScroll(e);
@@ -78,15 +90,11 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
CanExecute = args => true,
Execute = args => {
var address = args.ToString();
if (int.TryParse(address, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int result)) {
backStack.Push(scroll.DataIndex);
if (backStack.Count == 1) backward.CanExecuteChanged.Invoke(backward, EventArgs.Empty);
if (forwardStack.Count > 0) {
forward.CanExecuteChanged.Invoke(forward, EventArgs.Empty);
forwardStack.Clear();
}
SelectionStart = scroll.DataIndexToViewPoint(result);
scroll.ScrollValue += selectionStart.Y;
var anchor = model.GetAddressFromAnchor(-1, address);
if (anchor != Pointer.NULL) {
GotoAddress(anchor);
} else if (int.TryParse(address, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int result)) {
GotoAddress(result);
} else {
OnError?.Invoke(this, $"Unable to goto address '{address}'");
}

View File

@@ -222,7 +222,7 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
scroll = new ScrollRegion { DataLength = data.Length };
scroll.PropertyChanged += ScrollPropertyChanged;
selection = new Selection(scroll);
selection = new Selection(scroll, Model);
selection.PropertyChanged += SelectionPropertyChanged;
selection.PreviewSelectionStartChanged += ClearActiveEditBeforeSelectionChanges;
selection.OnError += (sender, e) => OnError?.Invoke(this, e);
@@ -321,19 +321,41 @@ namespace HavenSoft.Gen3Hex.Core.ViewModels {
}
}
private byte[] Parse(string content) {
var hex = "0123456789ABCDEF";
var result = new byte[content.Length / 2];
for (int i = 0; i < result.Length; i++) {
var thisByte = content.Substring(i * 2, 2);
result[i] += (byte)(hex.IndexOf(thisByte[0]) * 0x10);
result[i] += (byte)hex.IndexOf(thisByte[1]);
}
return result;
}
public IReadOnlyList<int> Find(string rawSearch) {
var results = new List<int>();
// basic attempt: see if the search term is a string of bytes
var cleanedSearch = rawSearch.Replace(" ", string.Empty).ToUpper();
var hex = "0123456789ABCDEF";
if (cleanedSearch.All(hex.Contains) && cleanedSearch.Length % 2 == 0) {
var search = new byte[cleanedSearch.Length / 2];
for (int i = 0; i < search.Length; i++) {
var thisByte = cleanedSearch.Substring(i * 2, 2);
search[i] += (byte)(hex.IndexOf(thisByte[0]) * 0x10);
search[i] += (byte)hex.IndexOf(thisByte[1]);
// pointer attempt: see if the search term is a pointer
if (cleanedSearch.StartsWith("<") && cleanedSearch.EndsWith(">")) {
var content = cleanedSearch.Substring(1, cleanedSearch.Length - 2);
int destination = 0;
if (content.All(hex.Contains) && content.Length == 6) {
var bytes = Parse(content);
destination = (bytes[0] << 16) + (bytes[1] << 8) + (bytes[2] << 0);
}
for (var run = Model.GetNextRun(0); run != null; run = Model.GetNextRun(run.Start + run.Length)) {
if (run is PointerRun pointerRun) {
var pointer = (Pointer)pointerRun.CreateDataFormat(data, pointerRun.Start);
if (pointer.Destination == destination || pointer.DestinationName == content) results.Add(run.Start);
}
}
}
// basic attempt: see if the search term is a string of bytes
if (cleanedSearch.All(hex.Contains) && cleanedSearch.Length % 2 == 0) {
var search = Parse(cleanedSearch);
for (int i = 0; i < data.Length - search.Length; i++) {
for (int j = 0; j < search.Length; j++) {
if (data[i + j] != search[j]) break;

View File

@@ -353,9 +353,36 @@ namespace HavenSoft.Gen3Hex.Tests {
Assert.IsNotType<Pointer>(viewPort[4, 1].Format);
}
[Fact]
public void CanGotoAnchorName() {
var buffer = new byte[0x100];
var model = new PointerModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
int errorCalls = 0;
viewPort.OnError += (sender, e) => errorCalls++;
viewPort.SelectionStart = new Point(2, 1);
viewPort.Edit("^bob ");
viewPort.Goto.Execute("bob");
Assert.Equal(0, errorCalls);
}
[Fact]
public void CanFindPointer() {
var buffer = new byte[0x100];
var model = new PointerModel(buffer);
var viewPort = new ViewPort(new LoadedFile("test.txt", buffer), model) { Width = 0x10, Height = 0x10 };
viewPort.SelectionStart = new Point(4, 1);
viewPort.Edit("<000058>");
var results = viewPort.Find("<000058>");
Assert.Single(results);
}
// TODO putting a new anchor with the same name: delete any run that starts at that anchor, repoint everything from the old location to the new location
// TODO goto named anchor
// TODO find pointer
// TODO undo/redo
}

View File

@@ -203,7 +203,7 @@ namespace HavenSoft.Gen3Hex.Tests {
[Fact]
public void CannotMoveSelectEndFarPassedEndOfFile() {
var selection = new Selection(new ScrollRegion { DataLength = 8 });
var selection = new Selection(new ScrollRegion { DataLength = 8 }, new BasicModel());
selection.SelectionEnd = new Point(3, 3);