diff --git a/SourceGen/AppSettings.cs b/SourceGen/AppSettings.cs index 40a81fa..3d8b53f 100644 --- a/SourceGen/AppSettings.cs +++ b/SourceGen/AppSettings.cs @@ -125,6 +125,7 @@ namespace SourceGen { public const string EXPORT_COL_WIDTHS = "export-col-widths"; public const string EXPORT_TEXT_MODE = "export-text-mode"; public const string EXPORT_SELECTION_ONLY = "export-selection-only"; + public const string EXPORT_LONG_LABEL_NEW_LINE = "export-long-label-new-line"; // Internal debugging features. public const string DEBUG_MENU_ENABLED = "debug-menu-enabled"; diff --git a/SourceGen/Exporter.cs b/SourceGen/Exporter.cs index 12a33d2..bdaca67 100644 --- a/SourceGen/Exporter.cs +++ b/SourceGen/Exporter.cs @@ -43,6 +43,11 @@ namespace SourceGen { /// public bool IncludeNotes { get; set; } + /// + /// If set, labels that are wider than the label column should go on their own line. + /// + public bool LongLabelNewLine { get; set; } + /// /// Bit flags, used to indicate which of the optional columns are active. /// @@ -96,11 +101,6 @@ namespace SourceGen { COUNT // number of elements, must be last } - /// - /// If set, labels that are wider than the label column should go on their own line. - /// - private bool mLongLabelNewLine; - /// /// Constructor. @@ -112,10 +112,6 @@ namespace SourceGen { mFormatter = formatter; mLeftFlags = leftFlags; - // Go ahead and latch this here. - mLongLabelNewLine = - AppSettings.Global.GetBool(AppSettings.SRCGEN_LONG_LABEL_NEW_LINE, false); - ConfigureColumns(leftFlags, rightWidths); } @@ -170,12 +166,12 @@ namespace SourceGen { total = mColStart[(int)Col.Label + 1] = total + rightWidths[0]; total = mColStart[(int)Col.Opcode + 1] = total + rightWidths[1]; total = mColStart[(int)Col.Operand + 1] = total + rightWidths[2]; - //total = mColStart[(int)Col.Comment] = total + rightWidths[3]; + //total = mColStart[(int)Col.Comment + 1] = total + rightWidths[3]; - Debug.WriteLine("Export col starts:"); - for (int i = 0; i < (int)Col.COUNT; i++) { - Debug.WriteLine(" " + i + "(" + ((Col)i) + ") " + mColStart[i]); - } + //Debug.WriteLine("Export col starts:"); + //for (int i = 0; i < (int)Col.COUNT; i++) { + // Debug.WriteLine(" " + i + "(" + ((Col)i) + ") " + mColStart[i]); + //} } /// @@ -185,31 +181,26 @@ namespace SourceGen { /// Result; holds text of all selected lines, in CSV format. public void SelectionToString(bool addCsv, out string fullText, out string csvText) { StringBuilder sb = new StringBuilder(128); - StringBuilder plainText = new StringBuilder(Selection.Count * 50); - StringBuilder csv = null; + StringWriter plainText = new StringWriter(); + StringWriter csv = null; if (addCsv) { - csv = new StringBuilder(Selection.Count * 40); + csv = new StringWriter(); } for (int lineIndex = 0; lineIndex < mCodeLineList.Count; lineIndex++) { if (!Selection[lineIndex]) { continue; } - if (GenerateTextLine(lineIndex, sb)) { - plainText.Append(sb.ToString()); - plainText.Append("\r\n"); - } - sb.Clear(); + GenerateTextLine(lineIndex, plainText, sb); if (addCsv) { - GenerateCsvLine(lineIndex, sb); - csv.Append(sb.ToString()); - csv.Append("\r\n"); - sb.Clear(); + GenerateCsvLine(lineIndex, csv, sb); } } + plainText.Close(); fullText = plainText.ToString(); if (addCsv) { + csv.Close(); csvText = csv.ToString(); } else { csvText = null; @@ -232,32 +223,49 @@ namespace SourceGen { } if (asCsv) { - GenerateCsvLine(lineIndex, sb); - sw.WriteLine(sb.ToString()); + GenerateCsvLine(lineIndex, sw, sb); } else { - if (GenerateTextLine(lineIndex, sb)) { - sw.WriteLine(sb.ToString()); - } + GenerateTextLine(lineIndex, sw, sb); } - sb.Clear(); } } } /// - /// Generates a line of plain text output. The line will not have EOL markers added. + /// Generates text output for one display line. This may result in more than one line + /// of output, e.g. if the label is longer than the field. EOL markers will be added. /// /// Index of line to output. - /// String builder to append text to. Must be cleared before - /// calling here. (This is a minor optimization.) - private bool GenerateTextLine(int index, StringBuilder sb) { - Debug.Assert(sb.Length == 0); + /// Text output destination. + /// Pre-allocated string builder (this is a minor optimization). + private void GenerateTextLine(int index, TextWriter tw, StringBuilder sb) { + LineListGen.Line line = mCodeLineList[index]; + if (line.LineType == LineListGen.Line.Type.Note && !IncludeNotes) { + return; + } // Width of "bytes" field, without '+' or trailing space. int bytesWidth = mColStart[(int)Col.Bytes + 1] - mColStart[(int)Col.Bytes] - 2; + // Width of "label" field, without trailing space. + int maxLabelLen = mColStart[(int)Col.Label + 1] - mColStart[(int)Col.Label] - 1; - LineListGen.Line line = mCodeLineList[index]; DisplayList.FormattedParts parts = mCodeLineList.GetFormattedParts(index); + sb.Clear(); + + // Put long labels on their own line if desired. + bool suppressLabel = false; + if (LongLabelNewLine && (line.LineType == LineListGen.Line.Type.Code || + line.LineType == LineListGen.Line.Type.Data)) { + int labelLen = string.IsNullOrEmpty(parts.Label) ? 0 : parts.Label.Length; + if (labelLen > maxLabelLen) { + // put on its own line + TextUtil.AppendPaddedString(sb, parts.Label, mColStart[(int)Col.Label]); + tw.WriteLine(sb); + sb.Clear(); + suppressLabel = true; + } + } + switch (line.LineType) { case LineListGen.Line.Type.Code: case LineListGen.Line.Type.Data: @@ -295,7 +303,9 @@ namespace SourceGen { if ((mLeftFlags & ActiveColumnFlags.Attr) != 0) { TextUtil.AppendPaddedString(sb, parts.Attr, mColStart[(int)Col.Attr]); } - TextUtil.AppendPaddedString(sb, parts.Label, mColStart[(int)Col.Label]); + if (!suppressLabel) { + TextUtil.AppendPaddedString(sb, parts.Label, mColStart[(int)Col.Label]); + } TextUtil.AppendPaddedString(sb, parts.Opcode, mColStart[(int)Col.Opcode]); TextUtil.AppendPaddedString(sb, parts.Operand, mColStart[(int)Col.Operand]); TextUtil.AppendPaddedString(sb, parts.Comment, mColStart[(int)Col.Comment]); @@ -310,12 +320,17 @@ namespace SourceGen { Debug.Assert(false); break; } - return true; + + tw.WriteLine(sb); } - private void GenerateCsvLine(int index, StringBuilder sb) { + private void GenerateCsvLine(int index, TextWriter tw, StringBuilder sb) { LineListGen.Line line = mCodeLineList[index]; + if (line.LineType == LineListGen.Line.Type.Note && !IncludeNotes) { + return; + } DisplayList.FormattedParts parts = mCodeLineList.GetFormattedParts(index); + sb.Clear(); if ((mLeftFlags & ActiveColumnFlags.Offset) != 0) { sb.Append(TextUtil.EscapeCSV(parts.Offset)); sb.Append(','); @@ -341,6 +356,8 @@ namespace SourceGen { sb.Append(TextUtil.EscapeCSV(parts.Operand)); sb.Append(','); sb.Append(TextUtil.EscapeCSV(parts.Comment)); } + + tw.WriteLine(sb); } #region HTML @@ -349,6 +366,12 @@ namespace SourceGen { private const string HTML_EXPORT_CSS_FILE = "SGStyle.css"; private const string LABEL_LINK_PREFIX = "Sym"; + /// + /// Generates HTML output to the specified path. + /// + /// Full pathname of output file. This defines the root + /// directory if there are additional files. + /// If set, existing CSS file will be replaced. public void OutputToHtml(string pathName, bool overwriteCss) { string exportTemplate = RuntimeDataAccess.GetPathName(HTML_EXPORT_TEMPLATE); string tmplStr; @@ -401,10 +424,7 @@ namespace SourceGen { continue; } - if (GenerateHtmlLine(lineIndex, sb)) { - sw.Write(sb.ToString()); - } - sb.Clear(); + GenerateHtmlLine(lineIndex, sw, sb); } sw.WriteLine("\r\n"); @@ -438,19 +458,25 @@ namespace SourceGen { /// every line as a table row, with HTML column definitions for each of our columns. /// /// Index of line to output. + /// Text output destination. /// String builder to append text to. Must be cleared before /// calling here. (This is a minor optimization.) - private bool GenerateHtmlLine(int index, StringBuilder sb) { - Debug.Assert(sb.Length == 0); + private void GenerateHtmlLine(int index, TextWriter tw, StringBuilder sb) { + LineListGen.Line line = mCodeLineList[index]; + if (line.LineType == LineListGen.Line.Type.Note && !IncludeNotes) { + return; + } + + sb.Clear(); // Width of "bytes" field, without '+' or trailing space. int bytesWidth = mColStart[(int)Col.Bytes + 1] - mColStart[(int)Col.Bytes] - 2; - - LineListGen.Line line = mCodeLineList[index]; - DisplayList.FormattedParts parts = mCodeLineList.GetFormattedParts(index); - + // Width of "label" field, without trailing space. int maxLabelLen = mColStart[(int)Col.Label + 1] - mColStart[(int)Col.Label] - 1; + DisplayList.FormattedParts parts = mCodeLineList.GetFormattedParts(index); + + // If needed, create an HTML anchor for the label field. string anchorLabel = null; if ((line.LineType == LineListGen.Line.Type.Code || line.LineType == LineListGen.Line.Type.Data || @@ -460,6 +486,7 @@ namespace SourceGen { "\">" + parts.Label + ""; } + // If needed, create an HTML link for the operand field. string linkOperand = null; if ((line.LineType == LineListGen.Line.Type.Code || line.LineType == LineListGen.Line.Type.Data) && @@ -467,8 +494,9 @@ namespace SourceGen { linkOperand = GetLinkOperand(index, parts.Operand); } + // Put long labels on their own line if desired. bool suppressLabel = false; - if (mLongLabelNewLine && (line.LineType == LineListGen.Line.Type.Code || + if (LongLabelNewLine && (line.LineType == LineListGen.Line.Type.Code || line.LineType == LineListGen.Line.Type.Data)) { int labelLen = string.IsNullOrEmpty(parts.Label) ? 0 : parts.Label.Length; if (labelLen > maxLabelLen) { @@ -480,7 +508,8 @@ namespace SourceGen { lstr = parts.Label; } AddSpacedString(sb, 0, mColStart[(int)Col.Label], lstr, parts.Label.Length); - sb.Append("\r\n"); + tw.WriteLine(sb); + sb.Clear(); suppressLabel = true; } } @@ -565,10 +594,6 @@ namespace SourceGen { break; case LineListGen.Line.Type.LongComment: case LineListGen.Line.Type.Note: - if (line.LineType == LineListGen.Line.Type.Note && !IncludeNotes) { - return false; - } - // Notes have a background color. Use this to highlight the text. We // don't apply it to the padding on the left columns. int rgb = 0; @@ -595,8 +620,7 @@ namespace SourceGen { break; } - sb.Append("\r\n"); - return true; + tw.WriteLine(sb); } /// diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index 485d6f2..3ef4737 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -1999,6 +1999,7 @@ namespace SourceGen { Exporter eport = new Exporter(mProject, CodeLineList, mOutputFormatter, dlg.ColFlags, rightWidths); eport.IncludeNotes = dlg.IncludeNotes; + eport.LongLabelNewLine = dlg.LongLabelNewLine; if (dlg.SelectionOnly) { DisplayListSelection selection = mMainWin.CodeDisplayList.SelectedIndices; if (selection.Count == 0) { diff --git a/SourceGen/WpfGui/EditAppSettings.xaml b/SourceGen/WpfGui/EditAppSettings.xaml index f6d08c8..db6e79c 100644 --- a/SourceGen/WpfGui/EditAppSettings.xaml +++ b/SourceGen/WpfGui/EditAppSettings.xaml @@ -486,7 +486,7 @@ limitations under the License. - diff --git a/SourceGen/WpfGui/Export.xaml b/SourceGen/WpfGui/Export.xaml index 86a38b7..de21f46 100644 --- a/SourceGen/WpfGui/Export.xaml +++ b/SourceGen/WpfGui/Export.xaml @@ -87,6 +87,9 @@ limitations under the License. + + diff --git a/SourceGen/WpfGui/Export.xaml.cs b/SourceGen/WpfGui/Export.xaml.cs index 163349b..3c591f0 100644 --- a/SourceGen/WpfGui/Export.xaml.cs +++ b/SourceGen/WpfGui/Export.xaml.cs @@ -95,6 +95,12 @@ namespace SourceGen.WpfGui { set { mSelectionOnly = value; OnPropertyChanged(); } } + private bool mLongLabelNewLine; + public bool LongLabelNewLine { + get { return mLongLabelNewLine; } + set { mLongLabelNewLine = value; OnPropertyChanged(); } + } + // // 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 @@ -202,6 +208,8 @@ namespace SourceGen.WpfGui { ShowFlags = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_FLAGS, false); ShowAttr = AppSettings.Global.GetBool(AppSettings.EXPORT_SHOW_ATTR, false); SelectionOnly = AppSettings.Global.GetBool(AppSettings.EXPORT_SELECTION_ONLY, false); + LongLabelNewLine = + AppSettings.Global.GetBool(AppSettings.EXPORT_LONG_LABEL_NEW_LINE, false); int[] colWidths = new int[] { 9, 8, 11, 72 }; // 100-col output string colStr = AppSettings.Global.GetString(AppSettings.EXPORT_COL_WIDTHS, null); @@ -239,6 +247,7 @@ namespace SourceGen.WpfGui { AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_FLAGS, ShowFlags); AppSettings.Global.SetBool(AppSettings.EXPORT_SHOW_ATTR, ShowAttr); AppSettings.Global.SetBool(AppSettings.EXPORT_SELECTION_ONLY, SelectionOnly); + AppSettings.Global.SetBool(AppSettings.EXPORT_LONG_LABEL_NEW_LINE, LongLabelNewLine); int[] colWidths = new int[] { AsmLabelColWidth, AsmOpcodeColWidth, AsmOperandColWidth, AsmCommentColWidth };