From b4213de4c087c5705859ef212ee86592395a4e2a Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 1 Nov 2019 18:44:22 -0700 Subject: [PATCH] Add "Go to Last Change" feature Jumps to the first offset associated with the change at the top of the Undo stack. We generally jump to the code/data offset, not the specific line affected. It's possible to do better (and we do, for Notes), but probably not worthwhile. --- SourceGen/DisasmProject.cs | 14 ++++++ SourceGen/MainController.cs | 52 +++++++++++++++++++++++ SourceGen/RuntimeData/Help/end-notes.html | 4 +- SourceGen/RuntimeData/Help/mainwin.html | 22 +++++++--- SourceGen/UndoableChange.cs | 1 + SourceGen/WpfGui/MainWindow.xaml | 4 ++ SourceGen/WpfGui/MainWindow.xaml.cs | 4 ++ 7 files changed, 95 insertions(+), 6 deletions(-) diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs index bb828e7..7a87a46 100644 --- a/SourceGen/DisasmProject.cs +++ b/SourceGen/DisasmProject.cs @@ -1830,6 +1830,20 @@ namespace SourceGen { } } + /// + /// Returns the change at the top of the list, i.e. the one that would be popped off + /// if we hit "undo". + /// + /// The change set. The caller must not modify it. + public ChangeSet GetTopChange() { + Debug.Assert(mUndoList.Count > 0); + Debug.Assert(mUndoTop > 0); + return mUndoList[mUndoTop - 1]; + } + + /// + /// Generate undo/redo history, for the debug window. + /// public string DebugGetUndoRedoHistory() { StringBuilder sb = new StringBuilder(); sb.Append("Bracketed change will be overwritten by next action\r\n\r\n"); diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index 7137946..96df507 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -2570,6 +2570,58 @@ namespace SourceGen { return new NavStack.Location(offset, lineDelta, isNote); } + public void GotoLastChange() { + ChangeSet cs = mProject.GetTopChange(); + Debug.Assert(cs.Count > 0); + + // Get the offset from the first change in the set. Ignore the rest. + UndoableChange uc = cs[0]; + int offset; + bool isNote = false; + if (uc.HasOffset) { + offset = uc.Offset; + + // If we altered a Note, and didn't remove it, jump to the note instead of + // the nearby code/data. + // + // TODO(someday): we can do similar things for comment edits, e.g. if it's + // SetLongComment we can find the line on which the comment starts and + // pass that as a line delta. + if (uc.Type == UndoableChange.ChangeType.SetNote && + uc.NewValue != null) { + isNote = true; + } + } else if (uc.Type == UndoableChange.ChangeType.SetProjectProperties) { + // some chance it modified the EQU statements... jump there + offset = 0; + } else if (uc.Type == UndoableChange.ChangeType.SetTypeHint) { + TypedRangeSet newSet = (TypedRangeSet)uc.NewValue; + if (newSet.Count == 0) { + // unexpected + Debug.Assert(false); + return; + } + + // Get the offset of the first entry. + IEnumerator iter = + (IEnumerator)newSet.GetEnumerator(); + iter.MoveNext(); + TypedRangeSet.Tuple firstOffset = iter.Current; + offset = firstOffset.Value; + } else { + Debug.Assert(false); + return; + } + + if (isNote) { + GoToLocation(new NavStack.Location(offset, 0, true), + GoToMode.JumpToNote, true); + } else { + GoToLocation(new NavStack.Location(offset, 0, false), + GoToMode.JumpToCodeData, true); + } + } + public bool CanNavigateBackward() { return mNavStack.HasBackward; } diff --git a/SourceGen/RuntimeData/Help/end-notes.html b/SourceGen/RuntimeData/Help/end-notes.html index ccb1c67..7ace0fd 100644 --- a/SourceGen/RuntimeData/Help/end-notes.html +++ b/SourceGen/RuntimeData/Help/end-notes.html @@ -18,7 +18,9 @@ school in the late 1980s, I read Don Lancaster's Enhancing Your Apple II, Vol. 1 (available for download here). This -included a very detailed methodology for disassembling 6502 software. +included a very detailed methodology for disassembling 6502 software +(nicely reformatted +here). I wanted to give it a try, so I generated a monitor listing of an operating system (called "RDOS") that SSI used on their games, and printed it out on my Epson RX-80 -- tractor feed paper was helpful for diff --git a/SourceGen/RuntimeData/Help/mainwin.html b/SourceGen/RuntimeData/Help/mainwin.html index 07c4a57..48093fe 100644 --- a/SourceGen/RuntimeData/Help/mainwin.html +++ b/SourceGen/RuntimeData/Help/mainwin.html @@ -372,11 +372,23 @@ with a '+'. If you have a label that is also a valid hexadecimal address, like "FEED", the label takes precedence. To jump to the address write "$FEED" instead.

-

When you jump around, by double-clicking on an opcode or an entry -in one of the side windows, the currently-selected line is added to -a navigation stack. You can use the arrows on the toolbar to navigate -forward or backward, or Navigate > Nav Forward and -Navigate > Nav Backward. (You can use Alt+Left/Right Arrow, or +

When you edit something, lines throughout the listing can change. This +is different from a source code editor, where editing a line just changes +that line. To allow you to watch the effects changes have, the undo/redo +commands try to keep the listing in the same position. +If you want to go to the place where the last change (i.e. the change +that will be undone by the next Undo operation) was made, +Navigate > Go to Last Change will jump to the first offset +associated with the most recent change. +If the last change was to the project properties, it will jump to the +first offset in the file.

+ +

When you jump around, e.g. by double-clicking on an opcode or an entry +in one of the side windows, the previously-selected line is added to +a navigation stack. You can use Navigate > Nav Forward and +Navigate > Nav Backward to move forward and backward through the +stack. (The curly arrows on the left side of the toolbar may be more +convenient. You can use Alt+Left/Right Arrow, or Ctrl+- / Ctrl+Shift+-, as keyboard shortcuts.)

diff --git a/SourceGen/UndoableChange.cs b/SourceGen/UndoableChange.cs index e3bc1c5..35f6e5d 100644 --- a/SourceGen/UndoableChange.cs +++ b/SourceGen/UndoableChange.cs @@ -206,6 +206,7 @@ namespace SourceGen { /// Change record. public static UndoableChange CreateTypeHintChange(TypedRangeSet undoSet, TypedRangeSet newSet) { + Debug.Assert(undoSet != null && newSet != null); if (newSet.Count == 0) { Debug.WriteLine("Empty hint change?"); } diff --git a/SourceGen/WpfGui/MainWindow.xaml b/SourceGen/WpfGui/MainWindow.xaml index faf9013..c5f76e0 100644 --- a/SourceGen/WpfGui/MainWindow.xaml +++ b/SourceGen/WpfGui/MainWindow.xaml @@ -124,6 +124,7 @@ limitations under the License. Ctrl+G + @@ -239,6 +240,8 @@ limitations under the License. CanExecute="CanFormatAddressTable" Executed="FormatAddressTableCmd_Executed"/> + + diff --git a/SourceGen/WpfGui/MainWindow.xaml.cs b/SourceGen/WpfGui/MainWindow.xaml.cs index 0afe3c9..509d2f0 100644 --- a/SourceGen/WpfGui/MainWindow.xaml.cs +++ b/SourceGen/WpfGui/MainWindow.xaml.cs @@ -1211,6 +1211,10 @@ namespace SourceGen.WpfGui { mMainCtrl.Goto(); } + private void GotoLastChangeCmd_Executed(object sender, ExecutedRoutedEventArgs e) { + mMainCtrl.GotoLastChange(); + } + private void HelpCmd_Executed(object sender, ExecutedRoutedEventArgs e) { mMainCtrl.ShowHelp(); }