diff --git a/SourceGen/Exporter.cs b/SourceGen/Exporter.cs
new file mode 100644
index 0000000..fb8a97c
--- /dev/null
+++ b/SourceGen/Exporter.cs
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2019 faddenSoft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+using Asm65;
+using CommonUtil;
+using ClipLineFormat = SourceGen.MainController.ClipLineFormat;
+
+namespace SourceGen {
+ public class Exporter {
+ ///
+ /// Project reference.
+ ///
+ private DisasmProject mProject;
+
+ ///
+ /// List of formatted parts.
+ ///
+ private LineListGen mCodeLineList;
+
+ ///
+ /// Text formatter.
+ ///
+ private Formatter mFormatter;
+
+
+ ///
+ /// Constructor.
+ ///
+ public Exporter(DisasmProject project, LineListGen codeLineList, Formatter formatter) {
+ mProject = project;
+ mCodeLineList = codeLineList;
+ mFormatter = formatter;
+ }
+
+ ///
+ /// Converts the selected lines to formatted text.
+ ///
+ /// Set of lines to select.
+ /// Line format.
+ /// Result; holds text of all selected lines.
+ /// Result; holds text of all selected lines, in CSV format.
+ public void SelectionToText(DisplayListSelection selection, ClipLineFormat lineFormat,
+ bool addCsv, out string fullText, out string csvText) {
+
+ StringBuilder plainText = new StringBuilder(selection.Count * 50);
+ StringBuilder sb = new StringBuilder(100);
+ StringBuilder csv = null;
+ if (addCsv) {
+ csv = new StringBuilder(selection.Count * 40);
+ }
+
+ int addrAdj = mProject.CpuDef.HasAddr16 ? 6 : 9;
+ int disAdj = 0;
+ int bytesWidth = 0;
+ if (lineFormat == MainController.ClipLineFormat.Disassembly) {
+ // A limit of 8 gets us 4 bytes from dense display ("20edfd60") and 3 if spaces
+ // are included ("20 ed fd") with no excess. We want to increase it to 11 so
+ // we can always show 4 bytes.
+ bytesWidth = (mFormatter.Config.mSpacesBetweenBytes ? 11 : 8);
+ disAdj = addrAdj + bytesWidth + 2;
+ }
+
+ // Walking through the selected indices can be slow for a large file, so we
+ // run through the full list and pick out the selected items with our parallel
+ // structure. (I'm assuming that "select all" will be a common precursor.)
+ foreach (int index in selection) {
+ LineListGen.Line line = mCodeLineList[index];
+ DisplayList.FormattedParts parts = mCodeLineList.GetFormattedParts(index);
+ switch (line.LineType) {
+ case LineListGen.Line.Type.Code:
+ case LineListGen.Line.Type.Data:
+ case LineListGen.Line.Type.EquDirective:
+ case LineListGen.Line.Type.RegWidthDirective:
+ case LineListGen.Line.Type.OrgDirective:
+ case LineListGen.Line.Type.LocalVariableTable:
+ if (lineFormat == ClipLineFormat.Disassembly) {
+ if (!string.IsNullOrEmpty(parts.Addr)) {
+ sb.Append(parts.Addr);
+ sb.Append(": ");
+ }
+
+ // Shorten the "...".
+ string bytesStr = parts.Bytes;
+ if (bytesStr != null && bytesStr.Length > bytesWidth) {
+ bytesStr = bytesStr.Substring(0, bytesWidth) + "+";
+ }
+ TextUtil.AppendPaddedString(sb, bytesStr, disAdj);
+ }
+ TextUtil.AppendPaddedString(sb, parts.Label, disAdj + 9);
+ TextUtil.AppendPaddedString(sb, parts.Opcode, disAdj + 9 + 8);
+ TextUtil.AppendPaddedString(sb, parts.Operand, disAdj + 9 + 8 + 11);
+ if (string.IsNullOrEmpty(parts.Comment)) {
+ // Trim trailing spaces off opcode or operand.
+ TextUtil.TrimEnd(sb);
+ } else {
+ sb.Append(parts.Comment);
+ }
+ sb.Append("\r\n");
+ break;
+ case LineListGen.Line.Type.LongComment:
+ if (lineFormat == ClipLineFormat.Disassembly) {
+ TextUtil.AppendPaddedString(sb, string.Empty, disAdj);
+ }
+ sb.Append(parts.Comment);
+ sb.Append("\r\n");
+ break;
+ case LineListGen.Line.Type.Note:
+ // don't include notes
+ break;
+ case LineListGen.Line.Type.Blank:
+ sb.Append("\r\n");
+ break;
+ default:
+ Debug.Assert(false);
+ break;
+ }
+ plainText.Append(sb);
+ sb.Clear();
+
+ if (addCsv) {
+ csv.Append(TextUtil.EscapeCSV(parts.Offset)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Addr)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Bytes)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Flags)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Attr)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Label)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Opcode)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Operand)); csv.Append(',');
+ csv.Append(TextUtil.EscapeCSV(parts.Comment));
+ csv.Append("\r\n");
+ }
+ }
+
+ fullText = plainText.ToString();
+ csvText = csv.ToString();
+ }
+ }
+}
diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs
index d4446f8..27039ac 100644
--- a/SourceGen/MainController.cs
+++ b/SourceGen/MainController.cs
@@ -1290,99 +1290,15 @@ namespace SourceGen {
/// Copies the selection to the clipboard as formatted text.
///
public void CopyToClipboard() {
- const bool addCsv = true;
-
+ DisplayListSelection selection = mMainWin.CodeDisplayList.SelectedIndices;
ClipLineFormat format = (ClipLineFormat)AppSettings.Global.GetEnum(
AppSettings.CLIP_LINE_FORMAT,
typeof(ClipLineFormat),
(int)ClipLineFormat.AssemblerSource);
- DisplayListSelection selection = mMainWin.CodeDisplayList.SelectedIndices;
- StringBuilder fullText = new StringBuilder(selection.Count * 50);
- StringBuilder csv = new StringBuilder(selection.Count * 40);
- StringBuilder sb = new StringBuilder(100);
- int addrAdj = mProject.CpuDef.HasAddr16 ? 6 : 9;
- int disAdj = 0;
- int bytesWidth = 0;
- if (format == ClipLineFormat.Disassembly) {
- // A limit of 8 gets us 4 bytes from dense display ("20edfd60") and 3 if spaces
- // are included ("20 ed fd") with no excess. We want to increase it to 11 so
- // we can always show 4 bytes.
- bytesWidth = (mFormatterConfig.mSpacesBetweenBytes ? 11 : 8);
- disAdj = addrAdj + bytesWidth + 2;
- }
-
- // Walking through the selected indices can be slow for a large file, so we
- // run through the full list and pick out the selected items with our parallel
- // structure. (I'm assuming that "select all" will be a common precursor.)
- foreach (int index in selection) {
- LineListGen.Line line = CodeLineList[index];
- DisplayList.FormattedParts parts = CodeLineList.GetFormattedParts(index);
- switch (line.LineType) {
- case LineListGen.Line.Type.Code:
- case LineListGen.Line.Type.Data:
- case LineListGen.Line.Type.EquDirective:
- case LineListGen.Line.Type.RegWidthDirective:
- case LineListGen.Line.Type.OrgDirective:
- case LineListGen.Line.Type.LocalVariableTable:
- if (format == ClipLineFormat.Disassembly) {
- if (!string.IsNullOrEmpty(parts.Addr)) {
- sb.Append(parts.Addr);
- sb.Append(": ");
- }
-
- // Shorten the "...".
- string bytesStr = parts.Bytes;
- if (bytesStr != null && bytesStr.Length > bytesWidth) {
- bytesStr = bytesStr.Substring(0, bytesWidth) + "+";
- }
- TextUtil.AppendPaddedString(sb, bytesStr, disAdj);
- }
- TextUtil.AppendPaddedString(sb, parts.Label, disAdj + 9);
- TextUtil.AppendPaddedString(sb, parts.Opcode, disAdj + 9 + 8);
- TextUtil.AppendPaddedString(sb, parts.Operand, disAdj + 9 + 8 + 11);
- if (string.IsNullOrEmpty(parts.Comment)) {
- // Trim trailing spaces off opcode or operand.
- TextUtil.TrimEnd(sb);
- } else {
- sb.Append(parts.Comment);
- }
- sb.Append("\r\n");
- break;
- case LineListGen.Line.Type.LongComment:
- if (format == ClipLineFormat.Disassembly) {
- TextUtil.AppendPaddedString(sb, string.Empty, disAdj);
- }
- sb.Append(parts.Comment);
- sb.Append("\r\n");
- break;
- case LineListGen.Line.Type.Note:
- // don't include notes
- break;
- case LineListGen.Line.Type.Blank:
- sb.Append("\r\n");
- break;
- default:
- Debug.Assert(false);
- break;
- }
- fullText.Append(sb);
-
- if (addCsv) {
- csv.Append(TextUtil.EscapeCSV(parts.Offset)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Addr)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Bytes)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Flags)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Attr)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Label)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Opcode)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Operand)); csv.Append(',');
- csv.Append(TextUtil.EscapeCSV(parts.Comment));
- csv.Append("\r\n");
- }
-
- sb.Clear();
- }
+ Exporter eport = new Exporter(mProject, CodeLineList, mOutputFormatter);
+ eport.SelectionToText(selection, format, true,
+ out string fullText, out string csvText);
DataObject dataObject = new DataObject();
dataObject.SetText(fullText.ToString());
@@ -1395,8 +1311,9 @@ namespace SourceGen {
// should probably be optional.)
//
// https://stackoverflow.com/a/369219/294248
+ const bool addCsv = true;
if (addCsv) {
- byte[] csvData = Encoding.UTF8.GetBytes(csv.ToString());
+ byte[] csvData = Encoding.UTF8.GetBytes(csvText.ToString());
MemoryStream stream = new MemoryStream(csvData);
dataObject.SetData(DataFormats.CommaSeparatedValue, stream);
}
@@ -2036,6 +1953,15 @@ namespace SourceGen {
}
}
+ public void Export() {
+ Export dlg = new Export(mMainWin);
+ if (dlg.ShowDialog() == false) {
+ return;
+ }
+
+ // TODO
+ }
+
public void Find() {
FindBox dlg = new FindBox(mMainWin, mFindString);
if (dlg.ShowDialog() == true) {
diff --git a/SourceGen/SGTestData/2019-local-variables.dis65 b/SourceGen/SGTestData/2019-local-variables.dis65
index 88b9f38..e7eb92c 100644
--- a/SourceGen/SGTestData/2019-local-variables.dis65
+++ b/SourceGen/SGTestData/2019-local-variables.dis65
@@ -2,7 +2,7 @@
{
"_ContentVersion":2,"FileDataLength":137,"FileDataCrc32":708791740,"ProjectProps":{
"CpuName":"65816","IncludeUndocumentedInstr":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
-"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true},
+"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":false},
"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":[],"ProjectSyms":{
"CONST_ONE":{
"DataDescriptor":{
@@ -38,7 +38,8 @@
"81":{
"Text":"Test name redefinition. This is mostly of interest for assemblers without redefinable variables, but also of interest to the cross-reference window.","BoxMode":false,"MaxWidth":80,"BackgroundColor":0}},
"Notes":{
-},
+"0":{
+"Text":"Should add a variable that conflicts with an auto-label.","BoxMode":false,"MaxWidth":80,"BackgroundColor":-256}},
"UserLabels":{
"87":{
"Label":"PTR_1","Value":4183,"Source":"User","Type":"LocalOrGlobalAddr"},
diff --git a/SourceGen/SourceGen.csproj b/SourceGen/SourceGen.csproj
index a060190..a35cd11 100644
--- a/SourceGen/SourceGen.csproj
+++ b/SourceGen/SourceGen.csproj
@@ -76,6 +76,7 @@
+
@@ -127,6 +128,9 @@
EditProjectProperties.xaml
+
+ Export.xaml
+
FindBox.xaml
@@ -290,6 +294,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml b/SourceGen/WpfGui/EditAppSettings.xaml
index 543a499..f6d08c8 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml
+++ b/SourceGen/WpfGui/EditAppSettings.xaml
@@ -88,7 +88,7 @@ limitations under the License.
-
@@ -444,8 +444,7 @@ limitations under the License.
-
+
@@ -454,8 +453,7 @@ limitations under the License.
-
+
@@ -464,8 +462,7 @@ limitations under the License.
-
+
@@ -474,8 +471,7 @@ limitations under the License.
-
+
diff --git a/SourceGen/WpfGui/EditAppSettings.xaml.cs b/SourceGen/WpfGui/EditAppSettings.xaml.cs
index 9ea72a5..a845c7a 100644
--- a/SourceGen/WpfGui/EditAppSettings.xaml.cs
+++ b/SourceGen/WpfGui/EditAppSettings.xaml.cs
@@ -577,6 +577,11 @@ namespace SourceGen.WpfGui {
// Apply/OK buttons when invalid input is present. Instead we just set the width to
// the minimum value when validation fails.
//
+ // Note that the "set" property is only called when the value changes, which only
+ // happens when a valid integer is typed. If you enter garbage, the dirty flag doesn't
+ // get set. That's just fine for us, but if you need to disable an "is valid" flag
+ // on bad input you can't rely on updating it at "set" time.
+ //
// See also https://stackoverflow.com/a/44586784/294248
//
private int mAsmLabelColWidth;
@@ -586,7 +591,7 @@ namespace SourceGen.WpfGui {
if (mAsmLabelColWidth != value) {
mAsmLabelColWidth = value;
OnPropertyChanged();
- IsDirty = true;
+ AsmColWidthTextChanged();
}
}
}
@@ -597,7 +602,7 @@ namespace SourceGen.WpfGui {
if (mAsmOpcodeColWidth != value) {
mAsmOpcodeColWidth = value;
OnPropertyChanged();
- IsDirty = true;
+ AsmColWidthTextChanged();
}
}
}
@@ -608,7 +613,7 @@ namespace SourceGen.WpfGui {
if (mAsmOperandColWidth != value) {
mAsmOperandColWidth = value;
OnPropertyChanged();
- IsDirty = true;
+ AsmColWidthTextChanged();
}
}
}
@@ -619,7 +624,7 @@ namespace SourceGen.WpfGui {
if (mAsmCommentColWidth != value) {
mAsmCommentColWidth = value;
OnPropertyChanged();
- IsDirty = true;
+ AsmColWidthTextChanged();
}
}
}
@@ -711,7 +716,7 @@ namespace SourceGen.WpfGui {
/// populated. That means we'll have incorrect intermediate states, but should
/// finish up correctly.
///
- private void AsmColWidthTextBox_TextChanged(object sender, TextChangedEventArgs e) {
+ private void AsmColWidthTextChanged() {
AssemblerInfo asm = (AssemblerInfo)asmConfigComboBox.SelectedItem;
if (asm == null) {
// fires during dialog initialization, before anything is selected
diff --git a/SourceGen/WpfGui/Export.xaml b/SourceGen/WpfGui/Export.xaml
new file mode 100644
index 0000000..25285b7
--- /dev/null
+++ b/SourceGen/WpfGui/Export.xaml
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SourceGen/WpfGui/Export.xaml.cs b/SourceGen/WpfGui/Export.xaml.cs
new file mode 100644
index 0000000..6ca5fac
--- /dev/null
+++ b/SourceGen/WpfGui/Export.xaml.cs
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019 faddenSoft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace SourceGen.WpfGui {
+ ///
+ /// Export selection dialog.
+ ///
+ public partial class Export : Window, INotifyPropertyChanged {
+ //
+ // Numeric input fields, bound directly to TextBox.Text. These rely on a TextChanged
+ // field to update the IsValid flag, because the "set" method is only called when the
+ // field contains a valid integer.
+ //
+ private int mAsmLabelColWidth;
+ public int AsmLabelColWidth {
+ get { return mAsmLabelColWidth; }
+ set {
+ if (mAsmLabelColWidth != value) {
+ mAsmLabelColWidth = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+ private int mAsmOpcodeColWidth;
+ public int AsmOpcodeColWidth {
+ get { return mAsmOpcodeColWidth; }
+ set {
+ if (mAsmOpcodeColWidth != value) {
+ mAsmOpcodeColWidth = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+ private int mAsmOperandColWidth;
+ public int AsmOperandColWidth {
+ get { return mAsmOperandColWidth; }
+ set {
+ if (mAsmOperandColWidth != value) {
+ mAsmOperandColWidth = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+ private int mAsmCommentColWidth;
+ public int AsmCommentColWidth {
+ get { return mAsmCommentColWidth; }
+ set {
+ if (mAsmCommentColWidth != value) {
+ mAsmCommentColWidth = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+
+ ///
+ /// Valid flag, used to enable the "generate" buttons.
+ ///
+ public bool IsValid {
+ get { return mIsValid; }
+ set { mIsValid = value; OnPropertyChanged(); }
+ }
+ private bool mIsValid;
+
+
+ // INotifyPropertyChanged implementation
+ public event PropertyChangedEventHandler PropertyChanged;
+ private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ public Export(Window owner) {
+ InitializeComponent();
+ Owner = owner;
+ DataContext = this;
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e) {
+ // TODO
+ }
+
+ private void UpdateControls() {
+ bool isValid = true;
+
+ isValid &= !Validation.GetHasError(asmLabelColWidthTextBox);
+ isValid &= !Validation.GetHasError(asmOpcodeColWidthTextBox);
+ isValid &= !Validation.GetHasError(asmOperandColWidthTextBox);
+ isValid &= !Validation.GetHasError(asmCommentColWidthTextBox);
+
+ IsValid = isValid;
+ }
+
+ private void AsmColWidthTextBox_TextChanged(object sender, TextChangedEventArgs e) {
+ UpdateControls();
+ }
+ }
+}
diff --git a/SourceGen/WpfGui/MainWindow.xaml b/SourceGen/WpfGui/MainWindow.xaml
index 18fcc73..ad2dbb2 100644
--- a/SourceGen/WpfGui/MainWindow.xaml
+++ b/SourceGen/WpfGui/MainWindow.xaml
@@ -94,6 +94,7 @@ limitations under the License.
+
F3
@@ -207,6 +208,8 @@ limitations under the License.
CanExecute="CanEditStatusFlags" Executed="EditStatusFlagsCmd_Executed"/>
+
-
+
+