1
0
mirror of https://github.com/fadden/6502bench.git synced 2025-02-08 05:30:35 +00:00

Add Actions > Format As Word (Ctrl+W)

Formats a pair of bytes into a 16-bit word.  As a special case,
attempts to grab the next byte if only one byte is selected.

(issue #29)
This commit is contained in:
Andy McFadden 2018-11-11 17:20:12 -08:00
parent f5b36afd2e
commit 0e1530fe0f
6 changed files with 171 additions and 11 deletions

View File

@ -175,6 +175,7 @@ namespace SourceGen.AppForms
this.symbolNameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.infoGroupBox = new System.Windows.Forms.GroupBox();
this.infoTextBox = new System.Windows.Forms.TextBox();
this.formatAsWordToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.mainMenuStrip.SuspendLayout();
this.mainStatusStrip.SuspendLayout();
this.mainToolStrip.SuspendLayout();
@ -474,6 +475,7 @@ namespace SourceGen.AppForms
this.toolStripMenuItem11,
this.formatSplitAddressTableToolStripMenuItem,
this.toggleSingleBytesToolStripMenuItem,
this.formatAsWordToolStripMenuItem,
this.deleteNoteCommentToolStripMenuItem,
this.toolStripMenuItem9,
this.showHexDumpToolStripMenuItem});
@ -591,7 +593,7 @@ namespace SourceGen.AppForms
//
this.formatSplitAddressTableToolStripMenuItem.Name = "formatSplitAddressTableToolStripMenuItem";
this.formatSplitAddressTableToolStripMenuItem.Size = new System.Drawing.Size(289, 22);
this.formatSplitAddressTableToolStripMenuItem.Text = "Format Split-Address Table";
this.formatSplitAddressTableToolStripMenuItem.Text = "Format Split-Address Table...";
this.formatSplitAddressTableToolStripMenuItem.Click += new System.EventHandler(this.FormatSplitAddressTable_Click);
//
// toggleSingleBytesToolStripMenuItem
@ -1451,6 +1453,14 @@ namespace SourceGen.AppForms
this.infoTextBox.Size = new System.Drawing.Size(177, 120);
this.infoTextBox.TabIndex = 0;
//
// formatAsWordToolStripMenuItem
//
this.formatAsWordToolStripMenuItem.Name = "formatAsWordToolStripMenuItem";
this.formatAsWordToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.W)));
this.formatAsWordToolStripMenuItem.Size = new System.Drawing.Size(289, 22);
this.formatAsWordToolStripMenuItem.Text = "Format As Word";
this.formatAsWordToolStripMenuItem.Click += new System.EventHandler(this.formatAsWordToolStripMenuItem_Click);
//
// ProjectView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -1636,6 +1646,7 @@ namespace SourceGen.AppForms
private System.Windows.Forms.ToolStripMenuItem deleteNoteCommentToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem formatSplitAddressTableToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem toggleDataScanToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem formatAsWordToolStripMenuItem;
}
}

View File

@ -2325,6 +2325,12 @@ namespace SourceGen.AppForms {
toggleSingleBytesToolStripMenuItem.Enabled =
(entityCounts.mDataLines > 0 && entityCounts.mCodeLines == 0);
// This is insufficient -- we need to know how many bytes are selected, and
// whether they're already formatted as multi-byte items. Too expensive to
// deal with here, so we'll need to show failure dialogs instead (ugh).
formatAsWordToolStripMenuItem.Enabled =
(entityCounts.mDataLines > 0 && entityCounts.mCodeLines == 0);
// So long as some code or data is highlighted, allow these. Don't worry about
// control lines. Disable options that would have no effect.
@ -2835,6 +2841,94 @@ namespace SourceGen.AppForms {
}
}
private void formatAsWordToolStripMenuItem_Click(object sender, EventArgs e) {
TypedRangeSet trs = GroupedOffsetSetFromSelected();
if (trs.Count == 0) {
Debug.Assert(false, "nothing to edit"); // shouldn't happen
return;
}
// If the user has only selected a single byte, we want to add the following byte
// to the selection, then proceed as usual. We can't simply modify the ListView
// selection because the following item might be an auto-detected string or fill,
// and we'd be adding multiple bytes. We have to be careful when grabbing the byte
// in case there's a region-split at that point (e.g. user label or .ORG).
//
// We could expand this to allow multiple regions, each of which is a single byte,
// but we'd need to deal with the case where the user selects two adjacent bytes that
// cross a region boundary.
if (trs.RangeCount == 1) {
// Exactly one range entry. Check its size.
IEnumerator<TypedRangeSet.TypedRange> checkIter = trs.RangeListIterator;
checkIter.MoveNext();
TypedRangeSet.TypedRange rng = checkIter.Current;
if (rng.Low == rng.High && rng.Low < mProject.FileDataLength - 1) {
// Single byte selected. Check to see if it's okay to grab the next byte.
Anattrib thisAttr = mProject.GetAnattrib(rng.Low);
Debug.Assert(thisAttr.DataDescriptor.Length == 1);
int nextOffset = rng.Low + 1;
Anattrib nextAttr = mProject.GetAnattrib(nextOffset);
// This must match what GroupedOffsetSetFromSelected() does.
if (!mProject.UserLabels.ContainsKey(nextOffset) &&
!mProject.HasCommentOrNote(nextOffset) &&
thisAttr.Address == nextAttr.Address - 1) {
// Good to go.
Debug.WriteLine("Grabbing second byte from +" + nextOffset.ToString("x6"));
trs.Add(nextOffset, rng.Type);
}
}
}
// Confirm that every selected byte is a single-byte data item (either set by
// the user or as part of the uncategorized data scan).
foreach (TypedRangeSet.Tuple tup in trs) {
FormatDescriptor dfd = mProject.GetAnattrib(tup.Value).DataDescriptor;
if (dfd != null && dfd.Length != 1) {
Debug.WriteLine("Can't format as word: offset +" + tup.Value.ToString("x6") +
" has len=" + dfd.Length + " (must be 1)");
string msg = string.Format(Properties.Resources.INVALID_FORMAT_WORD_SEL_NON1,
"\r\n\r\n");
MessageBox.Show(this, msg,
Properties.Resources.INVALID_FORMAT_WORD_SEL_CAPTION,
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
// Confirm that, in each region, an even number of bytes are selected.
IEnumerator<TypedRangeSet.TypedRange> rngIter = trs.RangeListIterator;
while (rngIter.MoveNext()) {
TypedRangeSet.TypedRange rng = rngIter.Current;
int rangeLen = rng.High - rng.Low + 1;
if ((rangeLen & 0x01) != 0) {
string msg = string.Format(Properties.Resources.INVALID_FORMAT_WORD_SEL_UNEVEN,
trs.RangeCount);
MessageBox.Show(this, msg,
Properties.Resources.INVALID_FORMAT_WORD_SEL_CAPTION,
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
// Selection is good, generate changes.
SortedList<int, FormatDescriptor> newFmts = new SortedList<int, FormatDescriptor>();
rngIter.Reset();
FormatDescriptor newDfd = FormatDescriptor.Create(2, FormatDescriptor.Type.NumericLE,
FormatDescriptor.SubType.None);
while (rngIter.MoveNext()) {
TypedRangeSet.TypedRange rng = rngIter.Current;
for (int i = rng.Low; i <= rng.High; i += 2) {
newFmts.Add(i, newDfd);
}
}
ChangeSet cs = mProject.GenerateFormatMergeSet(newFmts);
if (cs.Count != 0) {
ApplyUndoableChanges(cs);
}
}
private void DeleteNoteComment_Click(object sender, EventArgs e) {
Debug.Assert(IsSingleItemSelected());
ListView.SelectedIndexCollection sel = codeListView.SelectedIndices;
@ -3216,16 +3310,15 @@ namespace SourceGen.AppForms {
// The code does "LDA table,X / STA / LDA table+1,X / STA", which puts auto
// labels at the first two addresses -- splitting the region. That's good
// for the uncategorized data analyzer, but very annoying if you want to
// slap a 16-bit numeric format on all entries.
// slap a 16-bit numeric format on all entries in a table.
groupNum++;
} else if (mProject.HasCommentOrNote(offset)) {
// Don't carry across a long comment or note.
groupNum++;
} else if (attr.Address != expectedAddr) {
// For a contiguous selection, this should only happen if there's a .ORG
// address change. For a selection that skips code/data lines this is
// expected. In the later case, incrementing the group number is
// unnecessary but harmless.
// address change. For non-contiguous selection this is expected. In the
// latter case, incrementing the group number is unnecessary but harmless.
Debug.WriteLine("Address break: " + attr.Address + " vs. " + expectedAddr);
//Debug.Assert(mProject.AddrMap.Get(offset) >= 0);
@ -3757,7 +3850,7 @@ namespace SourceGen.AppForms {
int row = info.Item.Index;
Symbol sym = mSymbolSubset.GetSubsetItem(row);
if (sym.SymbolSource == Symbol.Source.Auto || sym.SymbolSource == Symbol.Source.User) {
if (sym.IsInternalLabel) {
int offset = mProject.FindLabelOffsetByName(sym.Label);
if (offset >= 0) {
GoToOffset(offset, false, true);

View File

@ -591,6 +591,33 @@ namespace SourceGen.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Invalid Selection.
/// </summary>
internal static string INVALID_FORMAT_WORD_SEL_CAPTION {
get {
return ResourceManager.GetString("INVALID_FORMAT_WORD_SEL_CAPTION", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unable to format as word: selection must be an even number of bytes that have not previously been formatted as multi-byte values.{0}Use Toggle Data Scan (Ctrl+D) to turn off auto-detection of strings and memory fill..
/// </summary>
internal static string INVALID_FORMAT_WORD_SEL_NON1 {
get {
return ResourceManager.GetString("INVALID_FORMAT_WORD_SEL_NON1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unable to format as word: each selected region must have an even number of bytes ({0} region(s) are selected)..
/// </summary>
internal static string INVALID_FORMAT_WORD_SEL_UNEVEN {
get {
return ResourceManager.GetString("INVALID_FORMAT_WORD_SEL_UNEVEN", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Legal Stuff.
/// </summary>

View File

@ -294,6 +294,15 @@
<data name="INVALID_ADDRESS" xml:space="preserve">
<value>(unknown address)</value>
</data>
<data name="INVALID_FORMAT_WORD_SEL_CAPTION" xml:space="preserve">
<value>Invalid Selection</value>
</data>
<data name="INVALID_FORMAT_WORD_SEL_NON1" xml:space="preserve">
<value>Unable to format as word: selection must be an even number of bytes that have not previously been formatted as multi-byte values.{0}Use Toggle Data Scan (Ctrl+D) to turn off auto-detection of strings and memory fill.</value>
</data>
<data name="INVALID_FORMAT_WORD_SEL_UNEVEN" xml:space="preserve">
<value>Unable to format as word: each selected region must have an even number of bytes ({0} region(s) are selected).</value>
</data>
<data name="LEGAL_STUFF_TITLE" xml:space="preserve">
<value>Legal Stuff</value>
</data>

View File

@ -55,7 +55,8 @@ and 65816 code. The official web site is
<li><a href="mainwin.html#navigation">Navigation</a></li>
<li><a href="mainwin.html#hints">Adding and Removing Hints</a></li>
<li><a href="mainwin.html#split-address">Format Split-Address Table</a></li>
<li><a href="mainwin.html#toggle-format">Quick Format Toggle</a></li>
<li><a href="mainwin.html#toggle-format">Toggle Single-Byte Format</a></li>
<li><a href="mainwin.html#format-as-word">Format As Word</a></li>
<li><a href="mainwin.html#toggle-data">Toggle Data Scan</a></li>
<li><a href="mainwin.html#clipboard">Copying to Clipboard</a></li>
</ul></li>

View File

@ -388,7 +388,7 @@ is just significantly more convenient. It also does everything as a single
undoable action, so if it comes out looking wrong, just hit "undo".</p>
<h3><a name="toggle-format">Quick Format Toggle</a></h3>
<h3><a name="toggle-format">Toggle Single-Byte Format</a></h3>
<p>The "Toggle Single-Byte Format" feature provides a quick way to
change a range of bytes to single bytes
@ -399,6 +399,25 @@ selecting "Default".</p>
string, but you want to see it as bytes or set a label in the middle.</p>
<h3><a name="format-as-word">Format As Word</a></h3>
<p>This is a quick way to format pairs of bytes as 16-bit words. It's
equivalent to opening the Edit Data Format dialog and selecting
"16-bit words, little-endian", displayed as hex.</p>
<p>To avoid some confusing situations, it only works on sets of
single-byte values. This means, for example, that you can't select a
10-byte string and have it turn into five 16-bit words. You can select as
many bytes as you want, but they must come in pairs. (Remember that you
can turn off auto-generation of strings and .FILLs with
<a href="#toggle-data">Toggle Data Scan</a>.)</p>
<p>As a special case, if you select a single byte, the following byte will
also be selected. This won't work if the following byte is part of a
multi-byte data item, is the start of a new region (see
<a href="editors.html#data">Edit Data Format</a> for a definition of
what splits a region), or is the last byte in the file.</p>
<h3><a name="toggle-data">Toggle Data Scan</a></h3>
<p>This menu item is in the Edit menu, and acts as a shortcut to opening
@ -406,9 +425,9 @@ the Project Properties editor, and clicking on the "Analyze Uncategorized
Data" checkbox. When enabled, SourceGen will look for ASCII strings and
regions of identical bytes, and generate .STR and .FILL directives. When
disabled, uncategorized data is presented as one byte per line, which can
be handy if you're trying to get at a bit in the middle of a string.</p>
<p>As with all other project properties changes, this is an undoable
event.</p>
be handy if you're trying to get at a byte in the middle of a string.</p>
<p>As with all other project property changes, this is an undoable
action.</p>
<h3><a name="clipboard">Copying to Clipboard</a></h3>