1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-25 05:29:31 +00:00

Add Navigate > Jump to Operand

If you double-click on the opcode of an instruction whose operand is
an address or equate, the selection jumps to that address.  This
feature is now available in the Navigate menu, with the keyboard
shortcut Ctrl+J.

While testing the feature I noticed that the keyboard focus wasn't
following the selection, so if you jumped to an address and then
used the up/down arrows, you jumped back to the previous location.
(This was true when double-clicking an opcode to jump; it was just
less noticeable since the next action was likely mouse-based.)  This
has been fixed by updating the ListView item focus when we jump to a
new location.

See also issue #63 and issue #72.
This commit is contained in:
Andy McFadden 2020-06-07 16:28:29 -07:00
parent 3637bb964d
commit bb830a29db
5 changed files with 86 additions and 15 deletions

View File

@ -1559,7 +1559,7 @@ namespace SourceGen {
}
break;
case CodeListColumn.Opcode:
HandleDoubleClickOnOpcode(line);
JumpToOperandTarget(line, false);
break;
case CodeListColumn.Operand:
if (CanEditOperand()) {
@ -1581,11 +1581,17 @@ namespace SourceGen {
}
}
private void HandleDoubleClickOnOpcode(LineListGen.Line line) {
/// <summary>
/// Jumps to the line referenced by the operand of the selected line.
/// </summary>
/// <param name="line">Selected line.</param>
/// <param name="testOnly">If set, don't actually do the goto.</param>
/// <returns>True if a jump is available for this line.</returns>
private bool JumpToOperandTarget(LineListGen.Line line, bool testOnly) {
if (line.FileOffset < 0) {
// Double-click on project symbol EQUs and the file header comment are handled
// elsewhere.
return;
return false;
}
Anattrib attr = mProject.GetAnattrib(line.FileOffset);
@ -1595,20 +1601,29 @@ namespace SourceGen {
// (Resolve it as a numeric reference.)
if (attr.OperandOffset >= 0) {
// Yup, find the line for that offset and jump to it.
GoToLocation(new NavStack.Location(attr.OperandOffset, 0, false),
GoToMode.JumpToCodeData, true);
if (!testOnly) {
GoToLocation(new NavStack.Location(attr.OperandOffset, 0, false),
GoToMode.JumpToCodeData, true);
}
return true;
} else if (dfd != null && dfd.HasSymbol) {
// Operand has a symbol, do a symbol lookup.
if (dfd.SymbolRef.IsVariable) {
GoToVarDefinition(line.FileOffset, dfd.SymbolRef, true);
if (!testOnly) {
GoToVarDefinition(line.FileOffset, dfd.SymbolRef, true);
}
return true;
} else {
if (mProject.SymbolTable.TryGetValue(dfd.SymbolRef.Label, out Symbol sym)) {
if (sym.SymbolSource == Symbol.Source.User ||
sym.SymbolSource == Symbol.Source.Auto) {
int labelOffset = mProject.FindLabelOffsetByName(dfd.SymbolRef.Label);
if (labelOffset >= 0) {
GoToLocation(new NavStack.Location(labelOffset, 0, false),
GoToMode.JumpToCodeData, true);
if (!testOnly) {
GoToLocation(new NavStack.Location(labelOffset, 0, false),
GoToMode.JumpToCodeData, true);
}
return true;
}
} else if (sym.SymbolSource == Symbol.Source.Platform ||
sym.SymbolSource == Symbol.Source.Project) {
@ -1616,9 +1631,11 @@ namespace SourceGen {
for (int i = 0; i < mProject.ActiveDefSymbolList.Count; i++) {
if (mProject.ActiveDefSymbolList[i] == sym) {
int offset = LineListGen.DefSymOffsetFromIndex(i);
GoToLocation(new NavStack.Location(offset, 0, false),
GoToMode.JumpToCodeData, true);
break;
if (!testOnly) {
GoToLocation(new NavStack.Location(offset, 0, false),
GoToMode.JumpToCodeData, true);
}
return true;
}
}
} else {
@ -1635,10 +1652,15 @@ namespace SourceGen {
// previous clause, but Address entries would not have been.)
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset);
if (operandOffset >= 0) {
GoToLocation(new NavStack.Location(operandOffset, 0, false),
GoToMode.JumpToCodeData, true);
if (!testOnly) {
GoToLocation(new NavStack.Location(operandOffset, 0, false),
GoToMode.JumpToCodeData, true);
}
return true;
}
}
return false;
}
public bool CanDeleteMlc() {
@ -2704,6 +2726,10 @@ namespace SourceGen {
// Update the selection.
mMainWin.CodeListView_SelectRange(topLineIndex, lastLineIndex - topLineIndex);
// Set the focus to the first selected item. The focus is used by the keyboard
// handler to decide what the up/down arrows select next.
mMainWin.CodeListView_SetSelectionFocus();
if (doPush) {
// Update the back stack and associated controls.
mNavStack.Push(prevLoc);
@ -2783,6 +2809,27 @@ namespace SourceGen {
}
}
public bool CanJumpToOperand() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
}
LineListGen.Line.Type lineType = SelectionAnalysis.mLineType;
if (lineType != LineListGen.Line.Type.Code &&
lineType != LineListGen.Line.Type.Data) {
return false;
}
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
Debug.Assert(selIndex >= 0);
return JumpToOperandTarget(CodeLineList[selIndex], true);
}
public void JumpToOperand() {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
Debug.Assert(selIndex >= 0);
JumpToOperandTarget(CodeLineList[selIndex], false);
}
/// <summary>
/// Calculates the currently-selected location.
/// </summary>

View File

@ -381,6 +381,10 @@ address, like "FEED", the label takes precedence. To jump to the address
write "$FEED" instead. If you enter a non-unique label, the selection
will jump to the nearest instance.</p>
<p>If an instruction or data line has an operand that references an address
in the file, you can navigate to the operand's location with
Navigate &gt; Jump to Operand.</p>
<p>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

View File

@ -20,6 +20,7 @@ using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows.Media;
using Asm65;
using CommonUtil;
using SourceGen.AsmGen;

View File

@ -143,6 +143,11 @@ limitations under the License.
<RoutedUICommand x:Key="HintAsCodeEntryPointCmd" Text="Hint As Code Entry Point"/>
<RoutedUICommand x:Key="HintAsDataStartCmd" Text="Hint As Data Start"/>
<RoutedUICommand x:Key="HintAsInlineDataCmd" Text="Hint As Inline Data"/>
<RoutedUICommand x:Key="JumpToOperandCmd" Text="Jump to Operand">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+J</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="NavigateBackwardCmd" Text="Nav Backward">
<RoutedUICommand.InputGestures>
<KeyGesture>Alt+Left</KeyGesture>
@ -274,6 +279,8 @@ limitations under the License.
CanExecute="CanHintAsDataStart" Executed="HintAsDataStartCmd_Executed"/>
<CommandBinding Command="{StaticResource HintAsInlineDataCmd}"
CanExecute="CanHintAsInlineData" Executed="HintAsInlineDataCmd_Executed"/>
<CommandBinding Command="{StaticResource JumpToOperandCmd}"
CanExecute="CanJumpToOperand" Executed="JumpToOperandCmd_Executed"/>
<CommandBinding Command="{StaticResource NavigateBackwardCmd}"
CanExecute="CanNavigateBackward" Executed="NavigateBackwardCmd_Executed"/>
<CommandBinding Command="{StaticResource NavigateForwardCmd}"
@ -379,6 +386,7 @@ limitations under the License.
<MenuItem Command="{StaticResource NavigateBackwardCmd}"/>
<MenuItem Command="{StaticResource GotoCmd}"/>
<MenuItem Command="{StaticResource GotoLastChangeCmd}"/>
<MenuItem Command="{StaticResource JumpToOperandCmd}"/>
<Separator/>
<MenuItem Command="Find"/>
<MenuItem Command="{StaticResource FindNextCmd}"/>

View File

@ -881,6 +881,10 @@ namespace SourceGen.WpfGui {
mIsSplitterBeingDragged = false;
}
public void CodeListView_SetSelectionFocus() {
ItemContainerGenerator_StatusChanged(null, null);
}
/// <summary>
/// Returns the index of the line that's currently at the top of the control.
/// </summary>
@ -1089,9 +1093,12 @@ namespace SourceGen.WpfGui {
(counts.mCodeHints != 0 || counts.mDataHints != 0 || counts.mInlineDataHints != 0);
}
private void CanJumpToOperand(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanJumpToOperand();
}
private void CanSaveProject(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = mMainCtrl != null && mMainCtrl.IsProjectOpen &&
!mMainCtrl.IsProjectReadOnly;
e.CanExecute = IsProjectOpen() && !mMainCtrl.IsProjectReadOnly;
}
private void CanToggleSingleByteFormat(object sender, CanExecuteRoutedEventArgs e) {
@ -1258,6 +1265,10 @@ namespace SourceGen.WpfGui {
mMainCtrl.MarkAsType(CodeAnalysis.TypeHint.InlineData, false);
}
private void JumpToOperandCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.JumpToOperand();
}
private void NavigateBackwardCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.NavigateBackward();
}