diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index c9ef7cb..d6be468 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -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) {
+ ///
+ /// Jumps to the line referenced by the operand of the selected line.
+ ///
+ /// Selected line.
+ /// If set, don't actually do the goto.
+ /// True if a jump is available for this line.
+ 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);
+ }
+
///
/// Calculates the currently-selected location.
///
diff --git a/SourceGen/RuntimeData/Help/mainwin.html b/SourceGen/RuntimeData/Help/mainwin.html
index 4f53bbf..e7646bc 100644
--- a/SourceGen/RuntimeData/Help/mainwin.html
+++ b/SourceGen/RuntimeData/Help/mainwin.html
@@ -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.
+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 > Jump to Operand.
+
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
diff --git a/SourceGen/Tests/GenTest.cs b/SourceGen/Tests/GenTest.cs
index 9dc1378..d2fe0d7 100644
--- a/SourceGen/Tests/GenTest.cs
+++ b/SourceGen/Tests/GenTest.cs
@@ -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;
diff --git a/SourceGen/WpfGui/MainWindow.xaml b/SourceGen/WpfGui/MainWindow.xaml
index fead078..6f9b1c5 100644
--- a/SourceGen/WpfGui/MainWindow.xaml
+++ b/SourceGen/WpfGui/MainWindow.xaml
@@ -143,6 +143,11 @@ limitations under the License.
+
+
+ Ctrl+J
+
+
Alt+Left
@@ -274,6 +279,8 @@ limitations under the License.
CanExecute="CanHintAsDataStart" Executed="HintAsDataStartCmd_Executed"/>
+
+
diff --git a/SourceGen/WpfGui/MainWindow.xaml.cs b/SourceGen/WpfGui/MainWindow.xaml.cs
index 3586546..3259a11 100644
--- a/SourceGen/WpfGui/MainWindow.xaml.cs
+++ b/SourceGen/WpfGui/MainWindow.xaml.cs
@@ -881,6 +881,10 @@ namespace SourceGen.WpfGui {
mIsSplitterBeingDragged = false;
}
+ public void CodeListView_SetSelectionFocus() {
+ ItemContainerGenerator_StatusChanged(null, null);
+ }
+
///
/// Returns the index of the line that's currently at the top of the control.
///
@@ -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();
}