1
0
mirror of https://github.com/fadden/6502bench.git synced 2026-04-20 04:16:47 +00:00

Add "edit operand target label" action

This adds a shortcut for editing the label at the address referenced
by an instruction operand or data address pseudo-op.  This can be
activated from the Actions menu, or with Ctrl+Shift+L.

For references inside the file, the Edit Label dialog is opened.  For
external addresses, the project symbol editor is opened.

Local variable table entries are currently not supported.

(issue #166)
This commit is contained in:
Andy McFadden
2025-06-21 17:11:18 -07:00
parent 898307eb73
commit 0eb417ac46
17 changed files with 312 additions and 79 deletions
+4 -2
View File
@@ -317,8 +317,10 @@ namespace SourceGen {
/// </summary>
/// <param name="proj">Project reference.</param>
/// <param name="offset">Offset of data item.</param>
/// <param name="address">Result: decoded address.</param>
/// <returns>Operand offset, or -1 if not applicable.</returns>
public static int GetDataOperandOffset(DisasmProject proj, int offset) {
public static int GetDataOperandOffset(DisasmProject proj, int offset, out int address) {
address = -1;
Anattrib attr = proj.GetAnattrib(offset);
if (!attr.IsDataStart && !attr.IsInlineDataStart) {
return -1;
@@ -335,7 +337,7 @@ namespace SourceGen {
// Treat like an absolute address. Convert the operand
// to an address, then resolve the file offset.
int address = RawData.GetWord(proj.FileData, offset, dfd.Length,
address = RawData.GetWord(proj.FileData, offset, dfd.Length,
(dfd.FormatType == FormatDescriptor.Type.NumericBE));
if (dfd.Length < 3) {
// Add the program bank where the data bank should go. Not perfect but
+1 -1
View File
@@ -875,7 +875,7 @@ namespace SourceGen {
/// project file.)
/// </summary>
/// <param name="index">Index into DisasmProject.ActiveDefSymbolListlist.</param>
/// <returns>Synthetic file offset. Value will be < 0.</returns>
/// <returns>Synthetic file offset. Value will be &lt; 0.</returns>
public static int DefSymOffsetFromIndex(int index) {
Debug.Assert(index >= 0 && index < (1 << 24));
return index - (1 << 24);
+1 -1
View File
@@ -45,7 +45,7 @@ namespace SourceGen {
///
/// To reduce confusion, the fact that something has been de-duped should be obvious.
///
/// A few quick clicks in the 2019-local-variables test should confirm these.
/// A few quick clicks in the 20150-local-variables test should confirm these.
/// </remarks>
public class LocalVariableLookup {
/// <summary>
+162 -7
View File
@@ -60,7 +60,6 @@ namespace SourceGen {
#endregion Project state
/// <summary>
/// Reference back to MainWindow object.
/// </summary>
@@ -239,7 +238,6 @@ namespace SourceGen {
}
}
#region Init and settings
/// <summary>
@@ -726,7 +724,6 @@ namespace SourceGen {
#endregion Init and settings
#region Auto-save
private const string RECOVERY_EXT_ADD = "_rec";
@@ -1016,7 +1013,6 @@ namespace SourceGen {
#endregion Auto-save
#region Project management
private bool PrepareNewProject(string dataPathName, SystemDef sysDef) {
@@ -2114,7 +2110,8 @@ namespace SourceGen {
// If it's an Address or Symbol, we can try to resolve
// the value. (Symbols should have been resolved by the
// previous clause, but Address entries would not have been.)
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset);
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset,
out int unused);
if (operandOffset >= 0) {
if (!testOnly) {
GoToLocation(new NavStack.Location(operandOffset, 0,
@@ -2373,7 +2370,9 @@ namespace SourceGen {
public void EditLabel() {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int offset = CodeLineList[selIndex].FileOffset;
DoEditLabel(offset);
}
private void DoEditLabel(int offset) {
Anattrib attr = mProject.GetAnattrib(offset);
int addr = attr.Address;
if (attr.IsNonAddressable) {
@@ -2412,6 +2411,158 @@ namespace SourceGen {
}
}
/// <summary>
/// Determines the address and offset referenced by an instruction or data operand.
/// </summary>
/// <remarks>
/// <para>There are five distinct situations (see issue #166):</para>
/// <list type="number">
/// <item>instruction, target address is inside file</item>
/// <item>instruction, target address is outside file</item>
/// <item>instruction, target is a zero-page address currently defined in an LVT</item>
/// <item>data item with address operand, target address is inside file</item>
/// <item>data item with address operand, target address is outside file</item>
/// </list>
/// <para>For the case of wanting to edit the label at the target location, the caller
/// will either need to open the LVT editor, the user label editor, or the project
/// symbol editor. Determining priority in the event of a conflict is up to the
/// caller.</para>
/// <para>It is possible to have an LVT entry and also an internal or external reference
/// to zero-page (e.g. zero page is included in the file, or there's a project/platform
/// symbol for the address). We don't currently try to handle LVT entries.</para>
/// <para>Sometimes instruction operands are formatted with an explicit symbol. We pay
/// no attention to that here. This causes us to differ from the Ctrl+J "jump to operand"
/// behavior, which prefers to jump to symbols when available.</para>
/// <para>This currently ignores explicit symbolic references, and goes directly to
/// the address referenced. If you have a jump table that includes address FOO, but
/// encodes it as FOO-1 (for RTS), we will set a label on FOO-1.</para>
/// </remarks>
/// <param name="project">Disassembly project.</param>
/// <param name="selOffset">File offset of selection.</param>
/// <param name="isInternal">Result: true if target is internal.</param>
/// <param name="internalTargetOffset">Result: offset of target in project file.</param>
/// <param name="externalSym">Result: first matching project/platform symbol,
/// if any.</param>
/// <param name="externalAddr">Result: decoded external address.</param>
/// <returns>True if a target was found.</returns>
public static bool GetOperandTargetOffset(DisasmProject project, int selOffset,
out bool isInternal, out int internalTargetOffset, out Symbol externalSym,
out int externalAddr, out bool isLV) {
isInternal = isLV = false;
internalTargetOffset = externalAddr = -1;
externalSym = null;
Anattrib attr = project.GetAnattrib(selOffset);
if (attr.IsInstructionStart) {
if (!attr.IsInstructionWithOperand) {
return false;
}
if (attr.OperandOffset >= 0) {
// Internal address. Walk back to start of line if necessary.
isInternal = true;
internalTargetOffset =
DataAnalysis.GetBaseOperandOffset(project, attr.OperandOffset);
} else if (attr.OperandAddress >= 0) {
// External address. Do a symbol table lookup, which will give us the correct
// answer when there are overlapping multi-byte values and masks. If we don't
// find a match, we still want to return "true" so that the caller can offer
// to create a new project symbol.
externalSym = project.SymbolTable.FindNonVariableByAddress(attr.OperandAddress,
OpDef.MemoryEffect.ReadModifyWrite); // could get effect from op
externalAddr = attr.OperandAddress;
} else {
// Probably an immediate operand, nothing to do.
return false;
}
// TODO(someday): see if a local variable is defined for this operand.
OpDef opDef = project.CpuDef.GetOpDef(project.FileData[selOffset]);
if ((opDef.IsDirectPageInstruction || opDef.IsStackRelInstruction) &&
attr.DataDescriptor != null && attr.DataDescriptor.HasSymbol &&
attr.DataDescriptor.SymbolRef.IsVariable) {
// The operand is formatted as a local variable.
isLV = true;
}
//Debug.WriteLine("Instr ref: offset=+" + internalTargetOffset.ToString("x6") +
// " extSym=" + externalSym);
return true;
} else if (attr.IsDataStart || attr.IsInlineDataStart) {
// If it's address or symbol, get the target offset. This only works for
// internal addresses.
int operandOffset = DataAnalysis.GetDataOperandOffset(project, selOffset,
out int extAddr);
if (operandOffset >= 0) {
// Internal address reference. Walk back to start of line if necessary.
isInternal = true;
internalTargetOffset =
DataAnalysis.GetBaseOperandOffset(project, operandOffset);
} else if (extAddr >= 0) {
// External address reference.
externalSym = project.SymbolTable.FindNonVariableByAddress(extAddr,
OpDef.MemoryEffect.ReadModifyWrite); // mem effect unknowable
externalAddr = extAddr;
} else {
return false;
}
//Debug.WriteLine("Data ref: offset=+" + internalTargetOffset.ToString("x6") +
// " extSym=" + externalSym);
return true;
} else {
Debug.Assert(false, "should be some sort of start");
return false;
}
}
public bool CanEditOperandTargetLabel() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
}
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int selOffset = CodeLineList[selIndex].FileOffset;
return GetOperandTargetOffset(mProject, selOffset, out bool unused1,
out int unused2, out Symbol unused3, out int unused4, out bool unused5);
}
public void EditOperandTargetLabel() {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int selOffset = CodeLineList[selIndex].FileOffset;
if (!GetOperandTargetOffset(mProject, selOffset, out bool isInternal,
out int internalLabelOffset, out Symbol externalSym, out int externalAddr,
out bool isLV)) {
Debug.Assert(false, "should not be here");
return;
}
Debug.WriteLine("EOTL: isInternal=" + isInternal + " intOff=+" +
internalLabelOffset.ToString("x6") + " extSym=" + externalSym +
" extAddr=" + externalAddr + " isLV=" + isLV);
// Operand targets can be internal or external, and can be in an LVT. Internal
// address user labels have the highest priority, LVTs are next, then external
// project/platform symbols.
if (isInternal) {
Debug.Assert(internalLabelOffset >= 0);
DoEditLabel(internalLabelOffset);
} else if (isLV) {
// Formatted as a local variable, do nothing.
// TODO(someday): make this edit the specific symbol in the table
} else {
// Create or edit project symbol.
if (externalSym != null && externalSym.SymbolSource == Symbol.Source.Project) {
// Edit existing project symbol.
DoEditProjectSymbol(CodeListColumn.Label, (DefSymbol)externalSym);
} else {
// Platform symbol or nothing at all. Create a new project symbol.
// (Should we refuse to act if there's only a platform symbol? Could be
// confusing if they think they're editing the platform, but it's also
// convenient to be able to create the project sym here.)
DefSymbol initVals = new DefSymbol("SYM", externalAddr, Symbol.Source.Project,
Symbol.Type.ExternalAddr, FormatDescriptor.SubType.None);
DoEditProjectSymbol(CodeListColumn.Label, initVals);
}
}
}
public bool CanCreateLocalVariableTable() {
if (SelectionAnalysis.mNumItemsSelected != 1) {
return false;
@@ -2743,6 +2894,9 @@ namespace SourceGen {
int selIndex = mMainWin.CodeListView_GetFirstSelectedIndex();
int symIndex = LineListGen.DefSymIndexFromOffset(CodeLineList[selIndex].FileOffset);
DefSymbol origDefSym = mProject.ActiveDefSymbolList[symIndex];
DoEditProjectSymbol(col, origDefSym);
}
private void DoEditProjectSymbol(CodeListColumn col, DefSymbol origDefSym) {
Debug.Assert(origDefSym.SymbolSource == Symbol.Source.Project);
EditDefSymbol dlg = new EditDefSymbol(mMainWin, mFormatter,
@@ -3919,7 +4073,8 @@ namespace SourceGen {
} else if (attr.IsDataStart || attr.IsInlineDataStart) {
// If it's an Address or Symbol, we can try to resolve
// the value.
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset);
int operandOffset = DataAnalysis.GetDataOperandOffset(mProject, line.FileOffset,
out int unused);
if (operandOffset >= 0) {
return CodeLineList.FindCodeDataIndexByOffset(operandOffset);
}
Binary file not shown.
+45 -31
View File
@@ -1,8 +1,8 @@
### 6502bench SourceGen dis65 v1.0 ###
{
"_ContentVersion":6,
"FileDataLength":183,
"FileDataCrc32":-593505978,
"FileDataLength":193,
"FileDataCrc32":960553569,
"ProjectProps":{
"CpuName":"6502",
"IncludeUndocumentedInstr":false,
@@ -132,7 +132,7 @@
{
"Offset":53,
"Addr":8704,
"Length":130,
"Length":140,
"PreLabel":"",
"DisallowInward":false,
"DisallowOutward":false,
@@ -197,16 +197,16 @@
"Type":"GlobalAddr",
"LabelAnno":"None"},
"182":{
"192":{
"Label":"done",
"Value":8833,
"Value":8843,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"},
"157":{
"163":{
"Label":"bitsy",
"Value":8808,
"Value":8814,
"Source":"User",
"Type":"GlobalAddr",
"LabelAnno":"None"}},
@@ -260,7 +260,7 @@
"SymbolRef":null,
"Extra":null},
"137":{
"143":{
"Length":3,
"Format":"NumericLE",
"SubFormat":"Symbol",
@@ -270,7 +270,7 @@
"Extra":null},
"155":{
"161":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Symbol",
@@ -280,27 +280,6 @@
"Extra":null},
"163":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"165":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"167":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"169":{
"Length":2,
"Format":"NumericLE",
@@ -332,6 +311,41 @@
"177":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"179":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"181":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"183":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"185":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
"SymbolRef":null,
"Extra":null},
"187":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Symbol",
"SymbolRef":{
"Label":"line2",
@@ -339,7 +353,7 @@
"Extra":null},
"179":{
"189":{
"Length":2,
"Format":"NumericLE",
"SubFormat":"Address",
@@ -3,6 +3,7 @@
.cdef $20,$7e,$20
FOOZP = $f0
OVERL = $3000
projover = $3100 ;replaced by proj symbol w/same name, diff addr (no match)
FOO = $f000
FOO_5 = $f005
@@ -45,8 +46,10 @@ next1 lda addr1
sta FOO_5
sta FOO+8
ldx OVERL
ldx projover
ldx $4000
ldx line1
ldx line2
ldx line2+1
ldx L221C
ldx L221C+1
ldx line2+35
@@ -67,8 +70,10 @@ bitsy .byte $2c
.word FOO_5
.word FOO+9
.word OVERL
.word projover
.word $4000
.word line1
.word line2
.word line2+5
.word L221C
.word line2+33
.word zf4
@@ -1,6 +1,7 @@
!cpu 6502
FOOZP = $f0
OVERL = $3000
projover = $3100 ;replaced by proj symbol w/same name, diff addr (no match)
FOO = $f000
FOO_5 = $f005
@@ -44,8 +45,10 @@ next1 lda addr1
sta FOO_5
sta FOO+8
ldx OVERL
ldx projover
ldx $4000
ldx line1
ldx line2
ldx line2+1
ldx L221C
ldx L221C+1
ldx line2+35
@@ -66,8 +69,10 @@ bitsy !byte $2c
!word FOO_5
!word FOO+9
!word OVERL
!word projover
!word $4000
!word line1
!word line2
!word line2+5
!word L221C
!word line2+33
!word zf4
@@ -1,6 +1,7 @@
.setcpu "6502"
FOOZP = $f0
OVERL = $3000
projover = $3100 ;replaced by proj symbol w/same name, diff addr (no match)
FOO = $f000
FOO_5 = $f005
@@ -40,8 +41,10 @@ next1: lda addr1
sta FOO_5
sta FOO+8
ldx OVERL
ldx projover
ldx $4000
ldx line1
ldx line2
ldx line2+1
ldx L221C
ldx L221C+1
ldx line2+35
@@ -62,8 +65,10 @@ bitsy: .byte $2c
.word FOO_5
.word FOO+9
.word OVERL
.word projover
.word $4000
.word line1
.word line2
.word line2+5
.word L221C
.word line2+33
.word zf4
@@ -1,5 +1,6 @@
FOOZP equ $f0
OVERL equ $3000
projover equ $3100 ;replaced by proj symbol w/same name, diff addr (no match)
FOO equ $f000
FOO_5 equ $f005
@@ -39,8 +40,10 @@ next1 lda addr1
sta FOO_5
sta FOO+8
ldx OVERL
ldx projover
ldx $4000
ldx line1
ldx line2
ldx line2+1
ldx L221C
ldx L221C+1
ldx line2+35
@@ -61,8 +64,10 @@ bitsy dfb $2c
dw FOO_5
dw FOO+9
dw OVERL
dw projover
dw $4000
dw line1
dw line2
dw line2+5
dw L221C
dw line2+33
dw zf4
@@ -41,7 +41,9 @@ addr2 asc '?'
FOO equ $f000
FOO_5 equ $f005
FOOZP equ $f0
OVERL equ $3000
plataddr equ $3000
OVERL equ $3100
NOLAB equ $4000
; Define a slice of zero page inside the program.
org $f4 ;EDIT: add this
@@ -61,11 +63,13 @@ next1
sta FOO ;external addr
sta FOO_5 ;external addr (overlaps w/FOO)
sta FOO+8 ;external addr (range)
ldx plataddr ;external addr, platform only
ldx OVERL ;external addr, plat and proj
ldx NOLAB ;external addr, no symbol
ldx line1 ;internal addr
ldx line2 ;internal addr
ldx line3 ;internal addr with offset, line start
ldx line3+1 ;internal addr with offset, inside line
ldx line2+1 ;internal addr with offset
ldx line3 ;internal addr, auto label
ldx line3+1 ;internal addr, auto label, offset
ldx line4+7 ;EDIT: set operand symbol "line2"
; EDIT: add local variable entry "foo_f0", value $f0, width 2
@@ -88,9 +92,11 @@ bitsy bit $ffa9 ;EDIT: set label "bitsy" on BIT instruction
dw FOO
dw FOO_5
dw FOO+9
dw plataddr
dw OVERL
dw NOLAB
dw line1
dw line2
dw line2+5
dw line3
dw line4+5 ;EDIT: set operand symbol "line2"
dw zf4
+20 -23
View File
@@ -912,23 +912,24 @@ namespace SourceGen.WpfGui {
private void NumericReferences_Loaded() {
SymbolEditOffsetResult = -1;
if (!MainController.GetOperandTargetOffset(mProject, mOffset, out bool isInternal,
out int internalTargetOffset, out Symbol externalSym, out int unused1,
out bool unused2)) {
// Probably an immediate operand.
ShowNarNotAddress = true;
return;
}
Anattrib attr = mProject.GetAnattrib(mOffset);
if (attr.OperandOffset >= 0) {
if (isInternal) {
// Operand target is inside the file.
ShowNarEditLabel = true;
Debug.Assert(internalTargetOffset >= 0);
// Seek back to the start of the instruction or data item if the operand points
// into the middle of one. This is *not* the same as the "nearby" search,
// which will traverse multiple items to find a match.
// TODO: this can create a situation where the code list shows FUBAR-1 but we
// edit an earlier label, if the earlier label has a multi-byte format that
// includes the target address. (An example can be found in 20200-ui-edge-cases.)
mEditedLabelOffset =
DataAnalysis.GetBaseOperandOffset(mProject, attr.OperandOffset);
ShowNarEditLabel = true;
mEditedLabelOffset = internalTargetOffset;
mLabelTargetAddress = mProject.GetAnattrib(mEditedLabelOffset).Address;
if (mProject.UserLabels.TryGetValue(mEditedLabelOffset, out Symbol sym)) {
// Has a label.
// Has a user label.
ShowNarCurrentLabel = true;
if (mEditedLabelOffset != attr.OperandOffset) {
NarLabelOffsetText = string.Format(CURRENT_LABEL_ADJUSTED_FMT,
@@ -940,10 +941,11 @@ namespace SourceGen.WpfGui {
mEditedLabel = sym;
CreateEditLabelText = EDIT_LABEL;
} else {
// Does not have a user label. Probably has an auto label.
NarLabelOffsetText = CURRENT_LABEL;
CreateEditLabelText = CREATE_LABEL;
}
} else if (attr.OperandAddress >= 0) {
} else {
ShowNarExternalSymbol = true;
// There can be multiple symbols with the same address, so we walk through the
@@ -956,14 +958,12 @@ namespace SourceGen.WpfGui {
// Start by doing a symbol table lookup, which will give us the correct answer
// when there are overlapping multi-byte values and masks.
Symbol lsym = mProject.SymbolTable.FindNonVariableByAddress(attr.OperandAddress,
OpDef.MemoryEffect.ReadModifyWrite); // just guess at the mem effect
if (lsym == null) {
if (externalSym == null) {
// Nothing currently defined.
} else if (lsym.SymbolSource == Symbol.Source.Platform) {
firstPlatform = lsym;
} else if (lsym.SymbolSource == Symbol.Source.Project) {
firstProject = lsym;
} else if (externalSym.SymbolSource == Symbol.Source.Platform) {
firstPlatform = externalSym;
} else if (externalSym.SymbolSource == Symbol.Source.Project) {
firstProject = externalSym;
} else {
Debug.Assert(false, "was expecting project or platform for external addr");
}
@@ -1005,9 +1005,6 @@ namespace SourceGen.WpfGui {
ShowNarNoProjectMatch = true;
CreateEditProjectSymbolText = CREATE_PROJECT_SYMBOL;
}
} else {
// Probably an immediate operand.
ShowNarNotAddress = true;
}
}
+5 -1
View File
@@ -39,7 +39,7 @@ namespace SourceGen.WpfGui {
private int mUniqueTag;
/// <summary>
/// Address we are editing the label for.
/// Address we are editing the label for. This is needed when creating the Symbol result.
/// </summary>
private int mAddress;
@@ -150,6 +150,10 @@ namespace SourceGen.WpfGui {
} else {
NonAddrWarningVis = Visibility.Collapsed;
}
#if DEBUG
this.Title += " (" + formatter.FormatAddress(address, true) + ")";
#endif
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
+8
View File
@@ -102,6 +102,11 @@ limitations under the License.
<KeyGesture>Ctrl+N</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="EditOperandTargetLabelCmd" Text="Edit Operand Target Label...">
<RoutedUICommand.InputGestures>
<KeyGesture>Ctrl+Shift+L</KeyGesture>
</RoutedUICommand.InputGestures>
</RoutedUICommand>
<RoutedUICommand x:Key="EditProjectPropertiesSymbolsCmd">
<RoutedUICommand.InputGestures>
<KeyGesture>F6</KeyGesture>
@@ -263,6 +268,8 @@ limitations under the License.
CanExecute="CanEditNote" Executed="EditNoteCmd_Executed"/>
<CommandBinding Command="{StaticResource EditOperandCmd}"
CanExecute="CanEditOperand" Executed="EditOperandCmd_Executed"/>
<CommandBinding Command="{StaticResource EditOperandTargetLabelCmd}"
CanExecute="CanEditOperandTargetLabel" Executed="EditOperandTargetLabelCmd_Executed"/>
<CommandBinding Command="{StaticResource EditProjectPropertiesSymbolsCmd}"
CanExecute="IsProjectOpen" Executed="EditProjectPropertiesSymbolsCmd_Executed"/>
<CommandBinding Command="{StaticResource EditProjectSymbolCmd}"
@@ -436,6 +443,7 @@ limitations under the License.
<MenuItem Command="{StaticResource EditCommentCmd}" InputGestureText="Ctrl+;"/>
<MenuItem Command="{StaticResource EditLongCommentCmd}"/>
<MenuItem Command="{StaticResource EditNoteCmd}"/>
<MenuItem Command="{StaticResource EditOperandTargetLabelCmd}"/>
<MenuItem Command="{StaticResource EditAddressCmd}"/>
<MenuItem Command="{StaticResource EditStatusFlagsCmd}"/>
<MenuItem Command="{StaticResource EditDataBankCmd}"/>
+8
View File
@@ -1122,6 +1122,10 @@ namespace SourceGen.WpfGui {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanEditOperand();
}
private void CanEditOperandTargetLabel(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanEditOperandTargetLabel();
}
private void CanEditProjectSymbol(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = IsProjectOpen() && mMainCtrl.CanEditProjectSymbol();
}
@@ -1288,6 +1292,10 @@ namespace SourceGen.WpfGui {
mMainCtrl.EditOperand();
}
private void EditOperandTargetLabelCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.EditOperandTargetLabel();
}
private void EditProjectPropertiesCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
mMainCtrl.EditProjectProperties(WpfGui.EditProjectProperties.Tab.Unknown);
}
+18
View File
@@ -338,6 +338,24 @@ CODE LDA LABEL+2
<p>With the label out of the way, the data can be formatted as desired.</p>
<h2 id="operand-target-label">Edit Operand Target Label</h2>
<p>This is an Actions menu shortcut that is equivalent to moving to the
address specified by the operand and editing the label there. For example,
if you use this on the line <code>LDA $1234</code>, it would open the
label edit dialog for the line at address $1234.</p>
<p>When used on references to addresses outside the scope of the file, the
project symbol editor will be opened instead. This does not currently
allow editing of local variable table entries.</p>
<p>This also works for data items formatted as 16- or 24-bit addresses.</p>
<p>Note: the target address is taken from the operand even when a symbol is
provided. For example, sometimes jump tables will encode (address - 1)
for the benefit of a PHA/RTS combination, so the entry for <code>FOO</code>
will appear as <samp>FOO-1</samp>. The operand target is actually
<code>FOO-1</code>, so using this feature won't edit the <code>FOO</code>
label but instead try to add a new one at the previous address.</p>
<h2 id="comment">Edit Comment</h2>
<p>Enter an end-of-line (EOL) comment, or leave the text field blank to
delete it. EOL comments may be placed on instruction and data lines, but
+1
View File
@@ -105,6 +105,7 @@ using the <samp>Help &gt; Help</samp> menu item or by hitting
<li><a href="editors.html#shortcut-local-var">Local Variable References</a></li>
</ul></li>
<li><a href="editors.html#data-operand">Edit Operand (Data)</a></li>
<li><a href="editors.html#operand-target-label">Edit Operand Target Label</a></li>
<li><a href="editors.html#comment">Edit Comment</a></li>
<li><a href="editors.html#long-comment">Edit Long Comment</a></li>
<li><a href="editors.html#data-bank">Edit Data Bank (65816 only)</a></li>