mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-10-02 13:16:35 -05:00
implement find/goto for pointers
This commit is contained in:
@@ -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) { }
|
||||
|
||||
@@ -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}'");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user