diff --git a/src/HexManiac.Core/Models/PokemonModel.cs b/src/HexManiac.Core/Models/PokemonModel.cs index c8b80b77..a6ab1134 100644 --- a/src/HexManiac.Core/Models/PokemonModel.cs +++ b/src/HexManiac.Core/Models/PokemonModel.cs @@ -238,7 +238,7 @@ namespace HavenSoft.HexManiac.Core.Models { var arrayName = GetAnchorFromAddress(-1, array.Start); var arrayIndex = (address - array.Start) / array.ElementLength; var indexMod = (address - array.Start) % array.ElementLength; - if (indexMod == 0) return $"{arrayName}/{arrayIndex}"; + if (indexMod == 0) return $"{arrayName}{ArrayAnchorSeparator}{arrayIndex}"; } return string.Empty; @@ -337,7 +337,13 @@ namespace HavenSoft.HexManiac.Core.Models { var destination = ReadPointer(start); if (destination < 0 || destination >= Count) return; int index = BinarySearch(destination); - if (index < 0) { + if (index < 0 && ~index > 0 && runs[~index - 1] is ArrayRun array && array.SupportsPointersToElements && (destination - array.Start) % array.ElementLength == 0) { + // the pointer points into an array that supports inner anchors + index = ~index - 1; + changeToken.RemoveRun(array); + runs[index] = array.AddSourcePointingWithinArray(start); + changeToken.AddRun(runs[index]); + } else if (index < 0) { // the pointer is brand new index = ~index; var newRun = new NoInfoRun(destination, new[] { start }); diff --git a/src/HexManiac.Core/Models/Runs/ArrayRun.cs b/src/HexManiac.Core/Models/Runs/ArrayRun.cs index 01f3eb47..2a03f49f 100644 --- a/src/HexManiac.Core/Models/Runs/ArrayRun.cs +++ b/src/HexManiac.Core/Models/Runs/ArrayRun.cs @@ -72,6 +72,7 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { public const char ArrayEnd = ']'; public const char SingleByteIntegerFormat = '.'; public const char DoubleByteIntegerFormat = ':'; + public const char ArrayAnchorSeparator = '/'; private readonly IDataModel owner; @@ -254,6 +255,16 @@ namespace HavenSoft.HexManiac.Core.Models.Runs { return new ArrayRun(owner, newFormat, Start, ElementCount + elementCount, ElementContent, PointerSources, PointerSourcesForInnerElements); } + public ArrayRun AddSourcePointingWithinArray(int source) { + var destination = owner.ReadPointer(source); + var index = (destination - Start) / ElementLength; + if (index < 0 || index >= ElementCount) throw new IndexOutOfRangeException(); + if (index == 0) throw new NotImplementedException(); + var newInnerPointerSources = PointerSourcesForInnerElements.ToList(); + newInnerPointerSources[index] = newInnerPointerSources[index].Concat(new[] { source }).ToList(); + return new ArrayRun(owner, FormatString, Start, ElementCount, ElementContent, PointerSources, newInnerPointerSources); + } + public ArrayRun AddSourcesPointingWithinArray(ModelDelta changeToken) { if (ElementCount < 2) return this; diff --git a/src/HexManiac.Core/ViewModels/ViewPort.cs b/src/HexManiac.Core/ViewModels/ViewPort.cs index a796f9ca..651b9cc6 100644 --- a/src/HexManiac.Core/ViewModels/ViewPort.cs +++ b/src/HexManiac.Core/ViewModels/ViewPort.cs @@ -747,7 +747,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels { return true; } } else if (underEdit.CurrentText.StartsWith(PointerStart.ToString())) { - return char.IsLetterOrDigit(input) || input == PointerEnd; + return char.IsLetterOrDigit(input) || input == ArrayAnchorSeparator || input == PointerEnd; } else if (underEdit.CurrentText.StartsWith(GotoMarker.ToString())) { return char.IsLetterOrDigit(input) || char.IsWhiteSpace(input); } else if (underEdit.CurrentText.StartsWith(AnchorStart.ToString())) { diff --git a/src/HexManiac.Tests/ArrayRunTests.cs b/src/HexManiac.Tests/ArrayRunTests.cs index 483cf633..423c13b4 100644 --- a/src/HexManiac.Tests/ArrayRunTests.cs +++ b/src/HexManiac.Tests/ArrayRunTests.cs @@ -588,6 +588,22 @@ namespace HavenSoft.HexManiac.Tests { Assert.StartsWith("^", run.FormatString); } + [Fact] + public void CanCreateNewPointerUsingArrayNameAndIndex() { + var data = new byte[0x200]; + var changeToken = new ModelDelta(); + var model = new PokemonModel(data); + var viewport = new ViewPort("name", model) { Width = 0x10, Height = 0x10 }; + + viewport.Edit("^array^[content\"\"8]8 "); + + viewport.SelectionStart = new Point(0, 6); + viewport.Edit(""); + + var run = (ArrayRun)model.GetNextRun(0); + Assert.Single(run.PointerSourcesForInnerElements[3]); + } + private static void WriteStrings(byte[] buffer, int start, params string[] content) { foreach (var item in content) { var bytes = PCSString.Convert(item).ToArray();