mirror of
https://github.com/fadden/6502bench.git
synced 2025-02-06 08:30:04 +00:00
Fancy comments, part 2
Started implementing the fancy formatter. It currently doesn't do anything fancy, just word-wrapping. Moved the static DebugShowRuler field into Formatter, so that the cached data is discarded when the setting changes. Also, updated SourceNotes with instructions for publishing a release.
This commit is contained in:
parent
83da0d952c
commit
1c84357bbf
@ -72,6 +72,8 @@ namespace Asm65 {
|
|||||||
|
|
||||||
/// <summary>Insert space after delimiter for long comments?</summary>
|
/// <summary>Insert space after delimiter for long comments?</summary>
|
||||||
public bool AddSpaceLongComment { get; set; } = false;
|
public bool AddSpaceLongComment { get; set; } = false;
|
||||||
|
/// <summary>Enable debug mode for long comments?</summary>
|
||||||
|
public bool DebugLongComments { get; set; } = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Functional changes to assembly output.
|
// Functional changes to assembly output.
|
||||||
@ -163,6 +165,7 @@ namespace Asm65 {
|
|||||||
UpperOperandXY = src.UpperOperandXY;
|
UpperOperandXY = src.UpperOperandXY;
|
||||||
|
|
||||||
AddSpaceLongComment = src.AddSpaceLongComment;
|
AddSpaceLongComment = src.AddSpaceLongComment;
|
||||||
|
DebugLongComments = src.DebugLongComments;
|
||||||
|
|
||||||
SuppressHexNotation = src.SuppressHexNotation;
|
SuppressHexNotation = src.SuppressHexNotation;
|
||||||
SuppressImpliedAcc = src.SuppressImpliedAcc;
|
SuppressImpliedAcc = src.SuppressImpliedAcc;
|
||||||
@ -539,6 +542,13 @@ namespace Asm65 {
|
|||||||
get { return mFullLineCommentDelimiterPlus; }
|
get { return mFullLineCommentDelimiterPlus; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, enable debug mode when rendering long comments.
|
||||||
|
/// </summary>
|
||||||
|
public bool DebugLongComments {
|
||||||
|
get { return mFormatConfig.DebugLongComments; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prefix for non-unique address labels.
|
/// Prefix for non-unique address labels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -565,7 +575,7 @@ namespace Asm65 {
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor. Initializes various fields based on the configuration. We want to
|
/// Constructor. Initializes various fields based on the configuration. We want to
|
||||||
/// do as much work as possible here.
|
/// pre-compute as many things as possible, to speed up formatting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Formatter(FormatConfig config) {
|
public Formatter(FormatConfig config) {
|
||||||
mFormatConfig = new FormatConfig(config); // make a copy
|
mFormatConfig = new FormatConfig(config); // make a copy
|
||||||
@ -573,7 +583,9 @@ namespace Asm65 {
|
|||||||
if (string.IsNullOrEmpty(mFormatConfig.NonUniqueLabelPrefix)) {
|
if (string.IsNullOrEmpty(mFormatConfig.NonUniqueLabelPrefix)) {
|
||||||
mFormatConfig.NonUniqueLabelPrefix = "@";
|
mFormatConfig.NonUniqueLabelPrefix = "@";
|
||||||
}
|
}
|
||||||
|
if (string.IsNullOrEmpty(mFormatConfig.FullLineCommentDelimiterBase)) {
|
||||||
|
mFormatConfig.FullLineCommentDelimiterBase = "!";
|
||||||
|
}
|
||||||
if (mFormatConfig.AddSpaceLongComment) {
|
if (mFormatConfig.AddSpaceLongComment) {
|
||||||
mFullLineCommentDelimiterPlus = mFormatConfig.FullLineCommentDelimiterBase + " ";
|
mFullLineCommentDelimiterPlus = mFormatConfig.FullLineCommentDelimiterBase + " ";
|
||||||
} else {
|
} else {
|
||||||
|
@ -500,6 +500,7 @@ namespace SourceGen {
|
|||||||
settings.GetString(AppSettings.FMT_LOCAL_VARIABLE_PREFIX, string.Empty);
|
settings.GetString(AppSettings.FMT_LOCAL_VARIABLE_PREFIX, string.Empty);
|
||||||
mFormatterConfig.CommaSeparatedDense =
|
mFormatterConfig.CommaSeparatedDense =
|
||||||
settings.GetBool(AppSettings.FMT_COMMA_SEP_BULK_DATA, true);
|
settings.GetBool(AppSettings.FMT_COMMA_SEP_BULK_DATA, true);
|
||||||
|
mFormatterConfig.DebugLongComments = DebugLongComments;
|
||||||
|
|
||||||
string chrDelCereal = settings.GetString(AppSettings.FMT_CHAR_DELIM, null);
|
string chrDelCereal = settings.GetString(AppSettings.FMT_CHAR_DELIM, null);
|
||||||
if (chrDelCereal != null) {
|
if (chrDelCereal != null) {
|
||||||
@ -4721,6 +4722,11 @@ namespace SourceGen {
|
|||||||
|
|
||||||
#region Debug features
|
#region Debug features
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set, show rulers and visible spaces in long comments.
|
||||||
|
/// </summary>
|
||||||
|
internal bool DebugLongComments { get; private set; } = false;
|
||||||
|
|
||||||
public void Debug_ExtensionScriptInfo() {
|
public void Debug_ExtensionScriptInfo() {
|
||||||
string info = mProject.DebugGetLoadedScriptInfo();
|
string info = mProject.DebugGetLoadedScriptInfo();
|
||||||
|
|
||||||
@ -4793,13 +4799,16 @@ namespace SourceGen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Debug_ToggleCommentRulers() {
|
public void Debug_ToggleCommentRulers() {
|
||||||
MultiLineComment.DebugShowRuler = !MultiLineComment.DebugShowRuler;
|
DebugLongComments = !DebugLongComments;
|
||||||
// Don't need to repeat the analysis, but we do want to save/restore the
|
mFormatterConfig.DebugLongComments = DebugLongComments;
|
||||||
// selection and top position when the comment fields change size.
|
mFormatterConfig.AddSpaceLongComment = !DebugLongComments;
|
||||||
|
mFormatterCpuDef = null; // force mFormatter refresh on next analysis
|
||||||
|
if (CodeLineList != null) {
|
||||||
UndoableChange uc =
|
UndoableChange uc =
|
||||||
UndoableChange.CreateDummyChange(UndoableChange.ReanalysisScope.DataOnly);
|
UndoableChange.CreateDummyChange(UndoableChange.ReanalysisScope.DisplayOnly);
|
||||||
ApplyChanges(new ChangeSet(uc), false);
|
ApplyChanges(new ChangeSet(uc), false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Debug_ToggleKeepAliveHack() {
|
public void Debug_ToggleKeepAliveHack() {
|
||||||
ScriptManager.UseKeepAliveHack = !ScriptManager.UseKeepAliveHack;
|
ScriptManager.UseKeepAliveHack = !ScriptManager.UseKeepAliveHack;
|
||||||
|
@ -19,6 +19,17 @@ using System.Diagnostics;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
// Spaces and hyphens are different. For example, if width is 10,
|
||||||
|
// "long words<space>more words" becomes:
|
||||||
|
// 0123456789
|
||||||
|
// long words
|
||||||
|
// more words
|
||||||
|
// However, "long words-more words" becomes:
|
||||||
|
// long
|
||||||
|
// words-more
|
||||||
|
// words
|
||||||
|
// because the hyphen is retained but the space is discarded.
|
||||||
|
|
||||||
namespace SourceGen {
|
namespace SourceGen {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Representation of a multi-line comment, which is a string plus some format options.
|
/// <para>Representation of a multi-line comment, which is a string plus some format options.
|
||||||
@ -30,11 +41,6 @@ namespace SourceGen {
|
|||||||
/// calls.</para>
|
/// calls.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MultiLineComment {
|
public class MultiLineComment {
|
||||||
/// <summary>
|
|
||||||
/// If set, sticks a MaxWidth "ruler" at the top, and makes spaces visible.
|
|
||||||
/// </summary>
|
|
||||||
public static bool DebugShowRuler { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unformatted text.
|
/// Unformatted text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -68,6 +74,10 @@ namespace SourceGen {
|
|||||||
|
|
||||||
private const int DEFAULT_WIDTH = 80;
|
private const int DEFAULT_WIDTH = 80;
|
||||||
private const int MIN_WIDTH = 8;
|
private const int MIN_WIDTH = 8;
|
||||||
|
private const int MAX_WIDTH = 128;
|
||||||
|
private const string SPACES = // MAX_WIDTH spaces
|
||||||
|
" " +
|
||||||
|
" ";
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -166,44 +176,48 @@ namespace SourceGen {
|
|||||||
const char spcRep = '\u2219'; // BULLET OPERATOR
|
const char spcRep = '\u2219'; // BULLET OPERATOR
|
||||||
string workString = string.IsNullOrEmpty(textPrefix) ? Text : textPrefix + Text;
|
string workString = string.IsNullOrEmpty(textPrefix) ? Text : textPrefix + Text;
|
||||||
List<string> lines = new List<string>();
|
List<string> lines = new List<string>();
|
||||||
|
bool debugMode = formatter.DebugLongComments;
|
||||||
|
|
||||||
|
if (MaxWidth > MAX_WIDTH) {
|
||||||
|
lines.Add("!Bad MaxWidth!");
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
string linePrefix;
|
string linePrefix;
|
||||||
if (!string.IsNullOrEmpty(textPrefix)) {
|
if (!string.IsNullOrEmpty(textPrefix)) {
|
||||||
|
// This is a Note, no comment delimiter needed.
|
||||||
linePrefix = string.Empty;
|
linePrefix = string.Empty;
|
||||||
} else if (BoxMode) {
|
} else if (BoxMode) {
|
||||||
if (formatter.FullLineCommentDelimiterBase.Length == 1 &&
|
if (formatter.FullLineCommentDelimiterBase.Length == 1 &&
|
||||||
formatter.FullLineCommentDelimiterBase[0] == BASIC_BOX_CHAR) {
|
formatter.FullLineCommentDelimiterBase[0] == BASIC_BOX_CHAR) {
|
||||||
|
// Box char is same as comment delimiter, don't double-up.
|
||||||
linePrefix = string.Empty;
|
linePrefix = string.Empty;
|
||||||
} else {
|
} else {
|
||||||
|
// Prefix with comment delimiter, but don't include optional space.
|
||||||
linePrefix = formatter.FullLineCommentDelimiterBase;
|
linePrefix = formatter.FullLineCommentDelimiterBase;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// No box, prefix every line with comment delimiter and optional space.
|
||||||
linePrefix = formatter.FullLineCommentDelimiterPlus;
|
linePrefix = formatter.FullLineCommentDelimiterPlus;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(MaxWidth);
|
StringBuilder sb = new StringBuilder(MaxWidth);
|
||||||
if (DebugShowRuler) {
|
if (debugMode) {
|
||||||
for (int i = 0; i < MaxWidth; i++) {
|
for (int i = 0; i < MaxWidth; i++) {
|
||||||
sb.Append((i % 10).ToString());
|
sb.Append((i % 10).ToString());
|
||||||
}
|
}
|
||||||
lines.Add(sb.ToString());
|
lines.Add(sb.ToString());
|
||||||
sb.Clear();
|
sb.Clear();
|
||||||
}
|
}
|
||||||
string boxLine, spaces;
|
string boxLine;
|
||||||
if (BoxMode) {
|
if (BoxMode) {
|
||||||
for (int i = 0; i < MaxWidth - linePrefix.Length; i++) {
|
for (int i = 0; i < MaxWidth - linePrefix.Length; i++) {
|
||||||
sb.Append(BASIC_BOX_CHAR);
|
sb.Append(BASIC_BOX_CHAR);
|
||||||
}
|
}
|
||||||
boxLine = sb.ToString();
|
boxLine = sb.ToString();
|
||||||
sb.Clear();
|
sb.Clear();
|
||||||
for (int i = 0; i < MaxWidth; i++) {
|
|
||||||
sb.Append(' ');
|
|
||||||
}
|
|
||||||
spaces = sb.ToString();
|
|
||||||
sb.Clear();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
boxLine = spaces = null;
|
boxLine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BoxMode && workString.Length > 0) {
|
if (BoxMode && workString.Length > 0) {
|
||||||
@ -213,24 +227,14 @@ namespace SourceGen {
|
|||||||
int lineWidth = BoxMode ?
|
int lineWidth = BoxMode ?
|
||||||
MaxWidth - linePrefix.Length - 4 :
|
MaxWidth - linePrefix.Length - 4 :
|
||||||
MaxWidth - linePrefix.Length;
|
MaxWidth - linePrefix.Length;
|
||||||
|
Debug.Assert(lineWidth > 0);
|
||||||
int startIndex = 0;
|
int startIndex = 0;
|
||||||
int breakIndex = -1;
|
int breakIndex = -1;
|
||||||
for (int i = 0; i < workString.Length; i++) {
|
for (int i = 0; i < workString.Length; i++) {
|
||||||
// Spaces and hyphens are different. For example, if width is 10,
|
|
||||||
// "long words<space>more words" becomes:
|
|
||||||
// 0123456789
|
|
||||||
// long words
|
|
||||||
// more words
|
|
||||||
// However, "long words-more words" becomes:
|
|
||||||
// long
|
|
||||||
// words-more
|
|
||||||
// words
|
|
||||||
// because the hyphen is retained but the space is discarded.
|
|
||||||
|
|
||||||
if (workString[i] == '\r' || workString[i] == '\n') {
|
if (workString[i] == '\r' || workString[i] == '\n') {
|
||||||
// explicit line break, emit line
|
// explicit line break, emit line
|
||||||
string str = workString.Substring(startIndex, i - startIndex);
|
string str = workString.Substring(startIndex, i - startIndex);
|
||||||
if (DebugShowRuler) { str = str.Replace(' ', spcRep); }
|
if (debugMode) { str = str.Replace(' ', spcRep); }
|
||||||
if (BoxMode) {
|
if (BoxMode) {
|
||||||
if (str == "" + BASIC_BOX_CHAR) {
|
if (str == "" + BASIC_BOX_CHAR) {
|
||||||
// asterisk on a line by itself means "output row of asterisks"
|
// asterisk on a line by itself means "output row of asterisks"
|
||||||
@ -238,16 +242,15 @@ namespace SourceGen {
|
|||||||
} else {
|
} else {
|
||||||
int padLen = lineWidth - str.Length;
|
int padLen = lineWidth - str.Length;
|
||||||
str = linePrefix + BASIC_BOX_CHAR + " " + str +
|
str = linePrefix + BASIC_BOX_CHAR + " " + str +
|
||||||
spaces.Substring(0, padLen + 1) + BASIC_BOX_CHAR;
|
SPACES.Substring(0, padLen + 1) + BASIC_BOX_CHAR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
str = linePrefix + str;
|
str = linePrefix + str;
|
||||||
}
|
}
|
||||||
lines.Add(str);
|
lines.Add(str);
|
||||||
// Eat the LF in CRLF. We don't actually work right with just LF,
|
// Eat the LF in CRLF.
|
||||||
// because this will consume LFLF, but it's okay to insist that the
|
if (workString[i] == '\r' && i < workString.Length - 1 &&
|
||||||
// string use CRLF for line breaks.
|
workString[i + 1] == '\n') {
|
||||||
if (i < workString.Length - 1 && workString[i + 1] == '\n') {
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
startIndex = i + 1;
|
startIndex = i + 1;
|
||||||
@ -258,11 +261,11 @@ namespace SourceGen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i - startIndex >= lineWidth) {
|
if (i - startIndex >= lineWidth) {
|
||||||
// this character was one too many, break line one back
|
// this character was one too many, break line at last break point
|
||||||
if (breakIndex <= 0) {
|
if (breakIndex <= 0) {
|
||||||
// no break found, just chop it
|
// no break found, just chop it
|
||||||
string str = workString.Substring(startIndex, i - startIndex);
|
string str = workString.Substring(startIndex, i - startIndex);
|
||||||
if (DebugShowRuler) { str = str.Replace(' ', spcRep); }
|
if (debugMode) { str = str.Replace(' ', spcRep); }
|
||||||
if (BoxMode) {
|
if (BoxMode) {
|
||||||
str = linePrefix + BASIC_BOX_CHAR + " " + str + " " + BASIC_BOX_CHAR;
|
str = linePrefix + BASIC_BOX_CHAR + " " + str + " " + BASIC_BOX_CHAR;
|
||||||
} else {
|
} else {
|
||||||
@ -279,11 +282,11 @@ namespace SourceGen {
|
|||||||
}
|
}
|
||||||
string str = workString.Substring(startIndex,
|
string str = workString.Substring(startIndex,
|
||||||
breakIndex + adj - startIndex);
|
breakIndex + adj - startIndex);
|
||||||
if (DebugShowRuler) { str = str.Replace(' ', spcRep); }
|
if (debugMode) { str = str.Replace(' ', spcRep); }
|
||||||
if (BoxMode) {
|
if (BoxMode) {
|
||||||
int padLen = lineWidth - str.Length;
|
int padLen = lineWidth - str.Length;
|
||||||
str = linePrefix + BASIC_BOX_CHAR + " " + str +
|
str = linePrefix + BASIC_BOX_CHAR + " " + str +
|
||||||
spaces.Substring(0, padLen + 1) + BASIC_BOX_CHAR;
|
SPACES.Substring(0, padLen + 1) + BASIC_BOX_CHAR;
|
||||||
} else {
|
} else {
|
||||||
str = linePrefix + str;
|
str = linePrefix + str;
|
||||||
}
|
}
|
||||||
@ -309,11 +312,11 @@ namespace SourceGen {
|
|||||||
if (startIndex < workString.Length) {
|
if (startIndex < workString.Length) {
|
||||||
// Output remainder.
|
// Output remainder.
|
||||||
string str = workString.Substring(startIndex, workString.Length - startIndex);
|
string str = workString.Substring(startIndex, workString.Length - startIndex);
|
||||||
if (DebugShowRuler) { str = str.Replace(' ', spcRep); }
|
if (debugMode) { str = str.Replace(' ', spcRep); }
|
||||||
if (BoxMode) {
|
if (BoxMode) {
|
||||||
int padLen = lineWidth - str.Length;
|
int padLen = lineWidth - str.Length;
|
||||||
str = linePrefix + BASIC_BOX_CHAR + " " + str +
|
str = linePrefix + BASIC_BOX_CHAR + " " + str +
|
||||||
spaces.Substring(0, padLen + 1) + BASIC_BOX_CHAR;
|
SPACES.Substring(0, padLen + 1) + BASIC_BOX_CHAR;
|
||||||
} else {
|
} else {
|
||||||
str = linePrefix + str;
|
str = linePrefix + str;
|
||||||
}
|
}
|
||||||
@ -327,25 +330,283 @@ namespace SourceGen {
|
|||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Fancy
|
||||||
|
|
||||||
|
private enum Tag {
|
||||||
|
Unknown = 0, Width, HorizRule, Break,
|
||||||
|
BoxStart, BoxEnd, UrlStart, UrlEnd, SymStart, SymEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DataSource {
|
||||||
|
private string mString;
|
||||||
|
private int mPosn;
|
||||||
|
public bool mInBox, mInUrl, mInSym;
|
||||||
|
|
||||||
|
public char this[int i] {
|
||||||
|
get { return mString[i]; }
|
||||||
|
}
|
||||||
|
public int Posn { get { return mPosn; } set { mPosn = value; } }
|
||||||
|
public int Length => mString.Length;
|
||||||
|
public char CurChar => mString[mPosn]; // mostly for debugger
|
||||||
|
|
||||||
|
public DataSource(string str, int posn, DataSource outer) {
|
||||||
|
mString = str;
|
||||||
|
mPosn = posn;
|
||||||
|
|
||||||
|
if (outer != null) {
|
||||||
|
// Inherit the values from the "outer" source.
|
||||||
|
mInBox = outer.mInBox;
|
||||||
|
mInUrl = outer.mInUrl;
|
||||||
|
mInSym = outer.mInSym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Stack<DataSource> mSourceStack = new Stack<DataSource>();
|
||||||
|
private StringBuilder mLineBuilder = new StringBuilder(MAX_WIDTH);
|
||||||
|
|
||||||
|
private const char DEFAULT_CHAR = '\0';
|
||||||
|
|
||||||
|
private int mLineWidth;
|
||||||
|
private char mBoxCharOrDef, mHorizRuleCharOrDef;
|
||||||
|
private char mBoxCharActual;
|
||||||
|
private bool mEscapeNext, mEatNextIfNewline;
|
||||||
|
private string mLinePrefix, mBoxPrefix;
|
||||||
|
private bool mDebugMode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the width of the usable text area, given the current attributes.
|
||||||
|
/// </summary>
|
||||||
|
private int CalcTextWidth(DataSource source) {
|
||||||
|
if (source.mInBox) {
|
||||||
|
if (mBoxCharOrDef == DEFAULT_CHAR) {
|
||||||
|
// Leave space for left/right box edges.
|
||||||
|
return mLineWidth - mBoxPrefix.Length - 4;
|
||||||
|
} else {
|
||||||
|
// Also leave space for a leading comment delimiter, even if the chosen
|
||||||
|
// box char happens to match the current delimiter. It might not match when
|
||||||
|
// it's rendered for asm gen, and we don't want the output to change.
|
||||||
|
return mLineWidth - mBoxPrefix.Length - 5;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return mLineWidth - mLinePrefix.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates one or more lines of formatted text, using the fancy formatter.
|
/// Generates one or more lines of formatted text, using the fancy formatter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="formatter">Formatter, with comment delimiters.</param>
|
/// <param name="formatter">Formatter, with comment delimiters.</param>
|
||||||
/// <returns>List of formatted strings.</returns>
|
/// <returns>List of formatted strings.</returns>
|
||||||
private List<string> FormatFancyText(Asm65.Formatter formatter) {
|
private List<string> FormatFancyText(Asm65.Formatter formatter) {
|
||||||
|
Debug.Assert(SPACES.Length == MAX_WIDTH);
|
||||||
|
|
||||||
|
mLineWidth = DEFAULT_WIDTH;
|
||||||
|
mBoxCharOrDef = mHorizRuleCharOrDef = DEFAULT_CHAR;
|
||||||
|
mEscapeNext = mEatNextIfNewline = false;
|
||||||
|
mDebugMode = formatter.DebugLongComments;
|
||||||
|
mSourceStack.Clear();
|
||||||
|
|
||||||
|
mLinePrefix = formatter.FullLineCommentDelimiterPlus; // does not change
|
||||||
|
mBoxPrefix = formatter.FullLineCommentDelimiterBase; // changes if box char set
|
||||||
|
mBoxCharActual = mBoxPrefix[0];
|
||||||
|
|
||||||
|
DataSource source = new DataSource(Text, 0, null);
|
||||||
|
int textWidth = CalcTextWidth(source);
|
||||||
|
|
||||||
|
char[] outBuf = new char[MAX_WIDTH];
|
||||||
|
int outIndex = 0;
|
||||||
|
int outBreakIndex = -1;
|
||||||
|
|
||||||
List<string> lines = new List<string>();
|
List<string> lines = new List<string>();
|
||||||
string mod = Text.Replace("\r\n", "CRLF");
|
if (mDebugMode) {
|
||||||
for (int i = 0; i < mod.Length; i += 10) {
|
for (int i = 0; i < mLineWidth; i++) {
|
||||||
lines.Add(formatter.FullLineCommentDelimiterPlus +
|
outBuf[i] = (char)('0' + i % 10);
|
||||||
mod.Substring(i, Math.Min(10, mod.Length - i)));
|
|
||||||
}
|
}
|
||||||
|
lines.Add(new string(outBuf, 0, mLineWidth));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through the input source.
|
||||||
|
while (true) {
|
||||||
|
if (source.Posn == source.Length) {
|
||||||
|
if (mSourceStack.Count != 0) {
|
||||||
|
source = mSourceStack.Pop();
|
||||||
|
textWidth = CalcTextWidth(source);
|
||||||
|
continue; // resume earlier string
|
||||||
|
}
|
||||||
|
break; // all done
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.CurChar == '\r' || source.CurChar == '\n') {
|
||||||
|
// Explicit line break. If it's a CRLF, eat both.
|
||||||
|
if (source.CurChar == '\r' && source.Posn + 1 < source.Length &&
|
||||||
|
source[source.Posn + 1] == '\n') {
|
||||||
|
source.Posn++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEscapeNext = false; // can't escape newlines
|
||||||
|
|
||||||
|
if (mEatNextIfNewline) {
|
||||||
|
mEatNextIfNewline = false;
|
||||||
|
} else {
|
||||||
|
// Output what we have.
|
||||||
|
OutputLine(outBuf, outIndex, source.mInBox, lines);
|
||||||
|
outIndex = 0;
|
||||||
|
outBreakIndex = -1;
|
||||||
|
}
|
||||||
|
source.Posn++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mEatNextIfNewline = false;
|
||||||
|
|
||||||
|
char thisCh = source.CurChar;
|
||||||
|
if (thisCh == '\\') {
|
||||||
|
if (!mEscapeNext) {
|
||||||
|
mEscapeNext = true;
|
||||||
|
source.Posn++; // eat the backslash
|
||||||
|
continue; // restart loop; backslash might have been last char
|
||||||
|
}
|
||||||
|
} else if (thisCh == '[' && !mEscapeNext) {
|
||||||
|
// Start of format tag?
|
||||||
|
if (TryParseTag(source, out int skipLen, out DataSource subSource)) {
|
||||||
|
source.Posn += skipLen;
|
||||||
|
if (subSource != null) {
|
||||||
|
mSourceStack.Push(source);
|
||||||
|
source = subSource;
|
||||||
|
textWidth = CalcTextWidth(source);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (thisCh == ' ') {
|
||||||
|
// Remember position of space for line break. If there are multiple
|
||||||
|
// consecutive spaces, remember the position of the first one.
|
||||||
|
if (outBreakIndex < 0 || outBuf[outBreakIndex] != ' ' ||
|
||||||
|
(outIndex > 0 && outBuf[outIndex - 1] != ' ')) {
|
||||||
|
outBreakIndex = outIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to add a character to the buffer. Will this put us over the limit?
|
||||||
|
if (outIndex == textWidth) {
|
||||||
|
int outputCount;
|
||||||
|
if (outBreakIndex <= 0) {
|
||||||
|
// No break found, or break char was at start of line. Just chop what
|
||||||
|
// we have.
|
||||||
|
outputCount = outIndex;
|
||||||
|
} else {
|
||||||
|
// Break was a hyphen or space.
|
||||||
|
outputCount = outBreakIndex;
|
||||||
|
|
||||||
|
}
|
||||||
|
int adj = 0;
|
||||||
|
if (outBuf[outputCount] == '-') {
|
||||||
|
// Break was a hyphen, include it.
|
||||||
|
adj = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output everything up to the break point, but not the break char itself
|
||||||
|
// unless it's a hyphen.
|
||||||
|
OutputLine(outBuf, outputCount + adj, source.mInBox, lines);
|
||||||
|
|
||||||
|
// Consume any trailing spaces (which are about to become leading spaces).
|
||||||
|
while (outputCount < outIndex && outBuf[outputCount] == ' ') {
|
||||||
|
outputCount++;
|
||||||
|
}
|
||||||
|
// Copy any remaining chars to start of buffer.
|
||||||
|
outputCount += adj;
|
||||||
|
if (outputCount < outIndex) {
|
||||||
|
for (int i = 0; i < outIndex - outputCount; i++) {
|
||||||
|
outBuf[i] = outBuf[outputCount + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outIndex -= outputCount;
|
||||||
|
outBreakIndex = -1;
|
||||||
|
|
||||||
|
// If we're at the start of a line, eat all leading spaces. (This is what
|
||||||
|
// the WPF TextEdit dialog does when word-wrapping.)
|
||||||
|
if (outIndex == 0) {
|
||||||
|
while (source.Posn < source.Length && source.CurChar == ' ') {
|
||||||
|
source.Posn++;
|
||||||
|
}
|
||||||
|
if (source.Posn == source.Length) {
|
||||||
|
// Whoops, ran out of input.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.CurChar == '-') {
|
||||||
|
// Can break on hyphen if it fits in line.
|
||||||
|
outBreakIndex = outIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
outBuf[outIndex++] = source[source.Posn++];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't end with a CRLF, output the last bits.
|
||||||
|
if (outIndex > 0) {
|
||||||
|
OutputLine(outBuf, outIndex, source.mInBox, lines);
|
||||||
|
}
|
||||||
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
/// <summary>
|
||||||
return "MLC box=" + BoxMode + " width=" + MaxWidth + " text='" + Text + "'";
|
/// Attempts to parse a tag at the current source position.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>This attempts to parse the full tag, including the closing tag if such is
|
||||||
|
/// appropriate.</para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="source">Input data source.</param>
|
||||||
|
/// <param name="skipLen">Number of characters to advance in data source.</param>
|
||||||
|
/// <param name="subSource">Result: data source with tag contents. May be null.</param>
|
||||||
|
/// <returns>True if the tag was successfully parsed.</returns>
|
||||||
|
private bool TryParseTag(DataSource source, out int skipLen, out DataSource subSource) {
|
||||||
|
skipLen = 0;
|
||||||
|
subSource = null;
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the contents of the output buffer to the line list, prefixing it with comment
|
||||||
|
/// delimiters and/or wrapping it in a box.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="outBuf">Output buffer.</param>
|
||||||
|
/// <param name="length">Length of data in output buffer.</param>
|
||||||
|
/// <param name="inBox">True if we're inside a box.</param>
|
||||||
|
/// <param name="lines">Line list to add the line to.</param>
|
||||||
|
private void OutputLine(char[] outBuf, int length, bool inBox, List<string> lines) {
|
||||||
|
Debug.Assert(length >= 0);
|
||||||
|
mLineBuilder.Clear();
|
||||||
|
if (inBox) {
|
||||||
|
mLineBuilder.Append(mBoxPrefix);
|
||||||
|
mLineBuilder.Append(outBuf, 0, length);
|
||||||
|
int trailingCount = mLineWidth - mBoxPrefix.Length - length - 1;
|
||||||
|
if (trailingCount > 0) {
|
||||||
|
mLineBuilder.Append(SPACES, 0, trailingCount);
|
||||||
|
}
|
||||||
|
mLineBuilder.Append(mBoxCharActual);
|
||||||
|
} else {
|
||||||
|
mLineBuilder.Append(mLinePrefix);
|
||||||
|
mLineBuilder.Append(outBuf, 0, length);
|
||||||
|
}
|
||||||
|
string str = mLineBuilder.ToString();
|
||||||
|
if (mDebugMode) {
|
||||||
|
str = str.Replace(' ', '\u2219'); // replace spaces with BULLET OPERATOR
|
||||||
|
}
|
||||||
|
lines.Add(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Fancy
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
if (IsFancy) {
|
||||||
|
return "MLC fancy text='" + Text + "'";
|
||||||
|
} else {
|
||||||
|
return "MLC box=" + BoxMode + " width=" + MaxWidth + " text='" + Text + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool operator ==(MultiLineComment a, MultiLineComment b) {
|
public static bool operator ==(MultiLineComment a, MultiLineComment b) {
|
||||||
if (ReferenceEquals(a, b)) {
|
if (ReferenceEquals(a, b)) {
|
||||||
|
@ -89,16 +89,10 @@ bytes .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
|
|||||||
.byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
|
.byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
|
||||||
|
|
||||||
L1062 bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
L1062 bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
||||||
;CRLFA triv
|
;
|
||||||
;ial fancy
|
;A trivial fancy comment. Nothing special about it at all. Go on about your
|
||||||
;comment.
|
|
||||||
;Nothing sp
|
|
||||||
;ecial abou
|
|
||||||
;t it at al
|
|
||||||
;l. Go on
|
|
||||||
;about your
|
|
||||||
;business.
|
;business.
|
||||||
;CRLFCRLF
|
;
|
||||||
lda #$10
|
lda #$10
|
||||||
lda #$11
|
lda #$11
|
||||||
lda #$12
|
lda #$12
|
||||||
|
@ -87,16 +87,10 @@ bytes !hex 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
|||||||
!hex 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
!hex 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||||
|
|
||||||
L1062 bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
L1062 bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
||||||
;CRLFA triv
|
;
|
||||||
;ial fancy
|
;A trivial fancy comment. Nothing special about it at all. Go on about your
|
||||||
;comment.
|
|
||||||
;Nothing sp
|
|
||||||
;ecial abou
|
|
||||||
;t it at al
|
|
||||||
;l. Go on
|
|
||||||
;about your
|
|
||||||
;business.
|
;business.
|
||||||
;CRLFCRLF
|
;
|
||||||
lda #$10
|
lda #$10
|
||||||
lda #$11
|
lda #$11
|
||||||
lda #$12
|
lda #$12
|
||||||
|
@ -89,16 +89,10 @@ bytes: .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
|
|||||||
.byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
|
.byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
|
||||||
|
|
||||||
L1062: bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
L1062: bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
||||||
;CRLFA triv
|
;
|
||||||
;ial fancy
|
;A trivial fancy comment. Nothing special about it at all. Go on about your
|
||||||
;comment.
|
|
||||||
;Nothing sp
|
|
||||||
;ecial abou
|
|
||||||
;t it at al
|
|
||||||
;l. Go on
|
|
||||||
;about your
|
|
||||||
;business.
|
;business.
|
||||||
;CRLFCRLF
|
;
|
||||||
lda #$10
|
lda #$10
|
||||||
lda #$11
|
lda #$11
|
||||||
lda #$12
|
lda #$12
|
||||||
|
@ -84,16 +84,10 @@ bytes hex 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
|||||||
hex 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
hex 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
|
||||||
|
|
||||||
L1062 bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
L1062 bit plataddr ;Pull in plataddr to see the comment on the platform file entry.
|
||||||
*CRLFA triv
|
*
|
||||||
*ial fancy
|
*A trivial fancy comment. Nothing special about it at all. Go on about your
|
||||||
*comment.
|
|
||||||
*Nothing sp
|
|
||||||
*ecial abou
|
|
||||||
*t it at al
|
|
||||||
*l. Go on
|
|
||||||
*about your
|
|
||||||
*business.
|
*business.
|
||||||
*CRLFCRLF
|
*
|
||||||
lda #$10
|
lda #$10
|
||||||
lda #$11
|
lda #$11
|
||||||
lda #$12
|
lda #$12
|
||||||
|
@ -1677,7 +1677,7 @@ namespace SourceGen.WpfGui {
|
|||||||
toggleInstructionChartMenuItem.IsChecked = mMainCtrl.IsInstructionChartOpen;
|
toggleInstructionChartMenuItem.IsChecked = mMainCtrl.IsInstructionChartOpen;
|
||||||
}
|
}
|
||||||
private void DebugMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
|
private void DebugMenu_SubmenuOpened(object sender, RoutedEventArgs e) {
|
||||||
debugCommentRulersMenuItem.IsChecked = MultiLineComment.DebugShowRuler;
|
debugCommentRulersMenuItem.IsChecked = mMainCtrl.DebugLongComments;
|
||||||
debugKeepAliveHackMenuItem.IsChecked = !Sandbox.ScriptManager.UseKeepAliveHack;
|
debugKeepAliveHackMenuItem.IsChecked = !Sandbox.ScriptManager.UseKeepAliveHack;
|
||||||
debugSecuritySandboxMenuItem.IsChecked = mMainCtrl.UseMainAppDomainForPlugins;
|
debugSecuritySandboxMenuItem.IsChecked = mMainCtrl.UseMainAppDomainForPlugins;
|
||||||
debugAnalysisTimersMenuItem.IsChecked = mMainCtrl.IsDebugAnalysisTimersOpen;
|
debugAnalysisTimersMenuItem.IsChecked = mMainCtrl.IsDebugAnalysisTimersOpen;
|
||||||
|
@ -38,3 +38,24 @@ SourceGen/RuntimeData directory has the system definitions used for the
|
|||||||
"new project" list, along with subdirectories with symbol files and extension
|
"new project" list, along with subdirectories with symbol files and extension
|
||||||
scripts. The [README file there](SourceGen/RuntimeData/README.md)
|
scripts. The [README file there](SourceGen/RuntimeData/README.md)
|
||||||
explains a bit more.
|
explains a bit more.
|
||||||
|
|
||||||
|
## Publishing a New Release ##
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
|
1. Run Debug > Source Generation Tests to verify that the code generation
|
||||||
|
tests pass. This requires that all cross-assemblers be installed and
|
||||||
|
configured.
|
||||||
|
2. Remove any existing `DIST_Release` directory from the top level.
|
||||||
|
3. In Visual Studio, change the build configuration to Release, and the startup project
|
||||||
|
to MakeDist.
|
||||||
|
4. Do a full clean build.
|
||||||
|
5. Hit F5 to start MakeDist. Click "Build" to generate a release build. The files will be
|
||||||
|
copied into `DIST_Release`.
|
||||||
|
6. Create an empty ZIP file (e.g. `6502bench123d1.zip`).
|
||||||
|
7. Copy all files from `DIST_Release` into it.
|
||||||
|
8. Submit all changes to git, push them to the server.
|
||||||
|
9. Create a new release on github. Drag the ZIP file into it.
|
||||||
|
10. Update/close any issues that have been addressed by the new release.
|
||||||
|
|
||||||
|
Version numbers should follow the semantic versioning scheme: v1.2.3, v1.2.3-dev1, etc.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user