diff --git a/SourceGen/MultiLineComment.cs b/SourceGen/MultiLineComment.cs index b6c4ae7..9ca0479 100644 --- a/SourceGen/MultiLineComment.cs +++ b/SourceGen/MultiLineComment.cs @@ -152,11 +152,17 @@ public List FormatText(Asm65.Formatter formatter, string textPrefix) { return mPreviousRender; } List lines; - if (IsFancy) { - Debug.Assert(string.IsNullOrEmpty(textPrefix)); - lines = FormatFancyText(formatter); - } else { - lines = FormatSimpleText(formatter, textPrefix); + try { + if (IsFancy) { + Debug.Assert(string.IsNullOrEmpty(textPrefix)); + lines = FormatFancyText(formatter); + } else { + lines = FormatSimpleText(formatter, textPrefix); + } + } catch (Exception ex) { + Debug.WriteLine("FormatText failed: " + ex); + lines = new List(); + lines.Add("Internal error: " + ex.Message); } // Cache result. mPreviousRender = lines; @@ -335,12 +341,25 @@ private List FormatSimpleText(Asm65.Formatter formatter, string textPref /// /// Input data source. /// + /// + /// When we encounter a tag, we create a new DataSource that has the contents of + /// the tag in it, and skip over the full original extent. This is especially handy for + /// generated text, e.g. [url=x] link text, where the source isn't simply a subset of + /// the original. + /// Various bits of state are also stored here, so that we can prevent + /// inappropriate nesting and track options set by the format tags. + /// private class DataSource { private string mString; private int mPosn; public string Text => mString; - public char this[int i] { get { return mString[i]; } } + public char this[int i] { + get { + Debug.Assert(i >= 0 && i < mString.Length); + return mString[i]; + } + } public int Posn { get { return mPosn; } set { mPosn = value; } } public int Length => mString.Length; public char CurChar => mString[mPosn]; @@ -348,18 +367,20 @@ private class DataSource { // These are true if the text is appearing inside start/end tags. public bool InBox { get; set; } public bool InUrl { get; set; } - public bool InSym { get; set; } public bool InsideElement { get { return InBox || InsideNonBoxElement; } } - public bool InsideNonBoxElement { get { return InUrl || InSym; } } + public bool InsideNonBoxElement { get { return InUrl; } } - // If true, don't prefix lines with the comment delimiter. + // If true, don't prefix lines with the comment delimiter (used for [br]). public bool SuppressPrefix { get; set; } // True if using default char (comment delimiter) for boxes. public bool BoxCharIsDefault { get; set; } = true; public char BoxChar { get; set; } = '?'; + // If true, don't inset text inside a box (used for [hr]). + public bool FullWidth { get; set; } = false; + public DataSource(string str, int posn, DataSource outer) { mString = str; mPosn = posn; @@ -368,10 +389,10 @@ public DataSource(string str, int posn, DataSource outer) { // Inherit the values from the "outer" source. InBox = outer.InBox; InUrl = outer.InUrl; - InSym = outer.InSym; SuppressPrefix = outer.SuppressPrefix; BoxCharIsDefault = outer.BoxCharIsDefault; BoxChar = outer.BoxChar; + FullWidth = outer.FullWidth; } } @@ -384,38 +405,47 @@ public bool Match(string str, int offset) { return false; } for (int i = 0; i < str.Length; i++) { + // Shouldn't need to worry about InvariantCultureIgnoreCase since this is + // only used for tags. if (char.ToUpper(str[i]) != char.ToUpper(mString[mPosn + offset + i])) { return false; } } return true; } + + /// + /// Returns the position of the matching string. The search starts at the current + /// position, and is case-insensitive. + /// + public int FindNext(string str) { + return Text.IndexOf(str, mPosn, StringComparison.InvariantCultureIgnoreCase); + } } private Stack mSourceStack = new Stack(); private StringBuilder mLineBuilder = new StringBuilder(MAX_WIDTH); - //private const char DEFAULT_CHAR = '\0'; private const char DEFAULT_RULE_CHAR = '-'; private int mLineWidth; - private char mBoxCharActual; - private string mLinePrefix, mBoxPrefix; + private string mLinePrefix; private bool mDebugMode; /// /// Calculates the width of the usable text area, given the current attributes. /// - private int CalcTextWidth(DataSource source) { + private int CalcTextWidth(DataSource source, bool forceFullWidth = false) { + bool fullWidth = source.FullWidth | forceFullWidth; if (source.InBox) { if (source.BoxCharIsDefault) { - // Leave space for left/right box edges. - return mLineWidth - mBoxPrefix.Length - 4; + // Leave space for left/right box edges, no comment delimiter. + return mLineWidth - (fullWidth ? 2 : 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; + return mLineWidth - (fullWidth ? 3 : 5); } } else { return mLineWidth - mLinePrefix.Length; @@ -435,8 +465,7 @@ private List FormatFancyText(Asm65.Formatter formatter) { mSourceStack.Clear(); mLinePrefix = formatter.FullLineCommentDelimiterPlus; // does not change - mBoxPrefix = formatter.FullLineCommentDelimiterBase; // changes if box char set - mBoxCharActual = mBoxPrefix[0]; + //mBoxPrefix = "! "; // changes with [box] DataSource source = new DataSource(Text, 0, null); int textWidth = CalcTextWidth(source); @@ -493,7 +522,7 @@ private List FormatFancyText(Asm65.Formatter formatter) { } } else if (thisCh == '[' && !escapeNext) { // Start of format tag? - if (TryParseTag(source, out int skipLen, out DataSource subSource, + if (TryParseTag(source, formatter, out int skipLen, out DataSource subSource, out bool requireLineStart)) { if (requireLineStart && outIndex != 0) { OutputLine(outBuf, outIndex, source, lines); @@ -521,6 +550,7 @@ private List FormatFancyText(Asm65.Formatter formatter) { // We need to add a character to the out buffer. Will this put us over the limit? if (outIndex == textWidth) { int outputCount; + int adj = 0; if (outBreakIndex <= 0) { // No break found, or break char was at start of line. Just chop what // we have. @@ -532,11 +562,10 @@ private List FormatFancyText(Asm65.Formatter formatter) { // Break was a hyphen or space. outputCount = outBreakIndex; - } - int adj = 0; - if (outBuf[outputCount] == '-') { - // Break was a hyphen, include it. - adj = 1; + if (outBuf[outputCount] == '-') { + // Break was a hyphen, include it. + adj = 1; + } } // Output everything up to the break point, but not the break char itself @@ -556,6 +585,7 @@ private List FormatFancyText(Asm65.Formatter formatter) { } outIndex -= outputCount; outBreakIndex = -1; + Debug.Assert(outIndex >= 0); // If we're at the start of a line, eat all leading spaces. (This is what // the WPF TextEdit dialog does when word-wrapping.) @@ -576,6 +606,7 @@ private List FormatFancyText(Asm65.Formatter formatter) { outBreakIndex = outIndex; } + Debug.Assert(outIndex >= 0 && outIndex < outBuf.Length); outBuf[outIndex++] = source[source.Posn++]; } @@ -599,13 +630,30 @@ private void OutputLine(char[] outBuf, int length, DataSource source, List= 0); mLineBuilder.Clear(); if (source.InBox) { - mLineBuilder.Append(mBoxPrefix); + // If the box character doesn't match the comment delimiter, output the + // comment delimiter. + bool boxMatchesCmt = (mLinePrefix[0] == source.BoxChar); + if (!boxMatchesCmt) { + mLineBuilder.Append(mLinePrefix[0]); + } + mLineBuilder.Append(source.BoxChar); + if (!source.FullWidth) { + mLineBuilder.Append(' '); // inset text, unless we're doing an [hr] + } mLineBuilder.Append(outBuf, 0, length); - int trailingCount = mLineWidth - mBoxPrefix.Length - length - 1; - if (trailingCount > 0) { - mLineBuilder.Append(SPACES, 0, trailingCount); + // Fill out the rest of the line with spaces, then add the final char. + int trailingCount = mLineWidth - mLineBuilder.Length; + // Line is one char shorter when the box character is specified and it matches + // the comment. (If the box character isn't specified then it always matches + // the comment; if the box doesn't match the comment then we're shoved over one + // char because the comment delimiter is present.) + if (!source.BoxCharIsDefault && boxMatchesCmt) { + trailingCount--; + } + if (trailingCount > 1) { + mLineBuilder.Append(SPACES, 0, trailingCount - 1); } - mLineBuilder.Append(mBoxCharActual); + mLineBuilder.Append(source.BoxChar); } else { if (!source.SuppressPrefix) { mLineBuilder.Append(mLinePrefix); @@ -620,10 +668,8 @@ private void OutputLine(char[] outBuf, int length, DataSource source, List @@ -653,13 +695,14 @@ public TagMatch(string pat, Tag tag) { /// appropriate. /// /// Input data source. + /// Output formatter. /// Number of characters to advance in data source. /// Result: data source with tag contents. May be null. /// Result: if true, and the output buffer has characters /// in it, they must be flushed before continuing. /// True if the tag was successfully parsed. - private bool TryParseTag(DataSource source, out int skipLen, out DataSource subSource, - out bool requireLineStart) { + private bool TryParseTag(DataSource source, Asm65.Formatter formatter, + out int skipLen, out DataSource subSource, out bool requireLineStart) { skipLen = 0; requireLineStart = false; subSource = null; @@ -675,18 +718,21 @@ private bool TryParseTag(DataSource source, out int skipLen, out DataSource subS if (tag != Tag.Unknown) { // Look for the end. for (int endpos = source.Posn + 2; endpos < source.Length; endpos++) { - if (source[endpos] == ']') { + char ch = source[endpos]; + if (ch == ']') { // Found the end of the tag. tagStr = source.Text.Substring(source.Posn, endpos - source.Posn + 1); break; + } else if (ch == '\r' || ch == '\n') { + // Stop looking if we hit a line break mid-tag. + break; } } } if (tagStr == null) { - Debug.WriteLine("Unterminated match at " + source.Posn + ": " + tag); return false; } - Debug.WriteLine("Probable match at " + source.Posn + ": " + tag + " '" + tagStr + "'"); + //Debug.WriteLine("Initial match at " + source.Posn + ": " + tag + " '" + tagStr + "'"); bool eatNextIfNewline = false; switch (tag) { @@ -695,9 +741,8 @@ private bool TryParseTag(DataSource source, out int skipLen, out DataSource subS if (tagStr.Length != brWidth) { return false; } - if (source.InBox) { - Debug.WriteLine("Can't use [br] inside a box"); - return false; + if (source.InsideElement) { + return false; // can't use inside a box } skipLen = brWidth; // Just a blank line, but with "suppress prefix" enabled. @@ -715,20 +760,21 @@ private bool TryParseTag(DataSource source, out int skipLen, out DataSource subS } else { defaultCh = DEFAULT_RULE_CHAR; } - char hrChar = HandleHorizRule(tagStr, defaultCh, out skipLen); - if (hrChar == '\0') { + if (!HandleHorizRule(tagStr, defaultCh, out skipLen, out char hrChar)) { return false; } - int ruleWidth = CalcTextWidth(source); + int ruleWidth = CalcTextWidth(source, true); StringBuilder rulerSb = new StringBuilder(ruleWidth); for (int i = 0; i < ruleWidth; i++) { rulerSb.Append(hrChar); } + rulerSb.Append("\r\n"); subSource = new DataSource(rulerSb.ToString(), 0, source); + subSource.FullWidth = true; requireLineStart = eatNextIfNewline = true; break; case Tag.Width: - if (source.InsideNonBoxElement) { + if (source.InsideElement) { return false; } int newWidth = HandleWidth(tagStr, out skipLen); @@ -738,6 +784,32 @@ private bool TryParseTag(DataSource source, out int skipLen, out DataSource subS requireLineStart = eatNextIfNewline = true; mLineWidth = newWidth; break; + case Tag.BoxStart: + if (source.InsideElement) { + return false; + } + char defBoxChar = formatter.FullLineCommentDelimiterBase[0]; + if (!HandleBox(tagStr, source, defBoxChar, out skipLen, out char boxChar, + out bool isBoxCharDef, out string insideBox)) { + return false; + } + requireLineStart = eatNextIfNewline = true; + subSource = new DataSource(insideBox, 0, source); + subSource.InBox = true; + subSource.BoxChar = boxChar; + subSource.BoxCharIsDefault = isBoxCharDef; + break; + case Tag.UrlStart: + if (source.InsideNonBoxElement) { + return false; + } + if (!HandleUrl(tagStr, source, out skipLen, out string showText)) { + return false; + } + requireLineStart = eatNextIfNewline = false; + subSource = new DataSource(showText, 0, source); + subSource.InUrl = true; + break; default: return false; } @@ -758,18 +830,17 @@ private bool TryParseTag(DataSource source, out int skipLen, out DataSource subS return true; } - /// /// Parses an [hr] or [hr char='x'] tag. Returns the ruler char, or '\0' on error. /// - private static char HandleHorizRule(string tagStr, char defaultChar, out int skipLen) { + private static bool HandleHorizRule(string tagStr, char defaultChar, out int skipLen, + out char hrChar) { const string simpleForm = "[hr]"; const string prefix = "[hr char='"; const string suffix = "']"; - const char FAILED = '\0'; + hrChar = '\0'; skipLen = tagStr.Length; - char hrChar; if (tagStr.Equals(simpleForm, StringComparison.OrdinalIgnoreCase)) { // use default char hrChar = defaultChar; @@ -777,16 +848,16 @@ private static char HandleHorizRule(string tagStr, char defaultChar, out int ski // char explicitly set int charStrLen = tagStr.Length - prefix.Length - suffix.Length; if (charStrLen != 1) { - return FAILED; + return false; } if (!tagStr.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase)) { - return FAILED; + return false; } hrChar = tagStr[prefix.Length]; } else { - return FAILED; + return false; } - return hrChar; + return true; } /// @@ -822,6 +893,89 @@ private static int HandleWidth(string tagStr, out int skipLen) { return newWidth; } + /// + /// Parses a [box]...[/box] tag, which could also be [box char='x']. + /// + private static bool HandleBox(string tagStr, DataSource source, char defBoxChar, + out int skipLen, out char boxChar, out bool isBoxCharDef, out string insideBox) { + const string startTagDefault = "[box]"; + const string startTagPrefix = "[box char='"; + const string startTagSuffix = "']"; + const string endTag = "[/box]"; + skipLen = 0; + boxChar = '?'; + isBoxCharDef = false; + insideBox = "!!!"; + + if (tagStr.Equals(startTagDefault, StringComparison.InvariantCultureIgnoreCase)) { + boxChar = defBoxChar; + isBoxCharDef = true; + } else if (tagStr.StartsWith(startTagPrefix, + StringComparison.InvariantCultureIgnoreCase) && + tagStr.EndsWith(startTagSuffix, + StringComparison.InvariantCultureIgnoreCase) && + tagStr.Length == startTagPrefix.Length + 1 + startTagSuffix.Length) { + boxChar = tagStr[startTagPrefix.Length]; + isBoxCharDef = false; + } else { + return false; + } + + int boxEndPosn = source.FindNext(endTag); + if (boxEndPosn < 0) { + return false; + } + + int innerLen = boxEndPosn - (source.Posn + tagStr.Length); + skipLen = tagStr.Length + innerLen + endTag.Length; + insideBox = "[hr]" + source.Text.Substring(source.Posn + tagStr.Length, innerLen) + + "[hr]"; + + return true; + } + + /// + /// Parses a [url]...[/url] tag, which could also be [url=xyzzy]. + /// + private static bool HandleUrl(string tagStr, DataSource source, + out int skipLen, out string showText) { + const string simpleStart = "[url]"; + const string linkStartPrefix = "[url="; + const string linkStartSuffix = "]"; + const string endTag = "[/url]"; + skipLen = 0; + showText = string.Empty; + + string linkStr; + if (tagStr.Equals(simpleStart, StringComparison.InvariantCultureIgnoreCase)) { + // The text is also the link. + linkStr = string.Empty; + } else if (tagStr.StartsWith(linkStartPrefix, + StringComparison.InvariantCultureIgnoreCase) && + tagStr.EndsWith(linkStartSuffix, + StringComparison.InvariantCultureIgnoreCase) && + tagStr.Length > linkStartPrefix.Length + linkStartSuffix.Length) { + // URI is specified in tag. + linkStr = tagStr.Substring(linkStartPrefix.Length, + tagStr.Length - (linkStartPrefix.Length + linkStartSuffix.Length)); + } else { + return false; + } + + int urlEndPosn = source.FindNext(endTag); + if (urlEndPosn < 0) { + return false; + } + + int innerLen = urlEndPosn - (source.Posn + tagStr.Length); + skipLen = tagStr.Length + innerLen + endTag.Length; + showText = source.Text.Substring(source.Posn + tagStr.Length, innerLen); + if (!string.IsNullOrEmpty(linkStr)) { + showText += " (" + linkStr + ")"; + } + return true; + } + #endregion Fancy public override string ToString() { diff --git a/SourceGen/SGTestData/20090-notes-and-comments.dis65 b/SourceGen/SGTestData/20090-notes-and-comments.dis65 index e4c3d05..a095acf 100644 --- a/SourceGen/SGTestData/20090-notes-and-comments.dis65 +++ b/SourceGen/SGTestData/20090-notes-and-comments.dis65 @@ -150,6 +150,34 @@ "IsFancy":true, "BoxMode":false, "MaxWidth":80, +"BackgroundColor":0}, + +"111":{ +"Text":"[hr]\r\nFull width box, with default char.\r\n[box]stuff in the box zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz aaaa bbb cccc[/box]\r\n[box char=\u0027;\u0027]Explicit char=\u0027;\u0027.[/box]\r\nNow with reduced width and char=\u0027#\u0027.\r\n[width=10][box char=\u0027#\u0027]A much smaller box.[/box]\r\n[width=*]\r\n[box char=\u0027*\u0027]\r\nWidth changes are illegal inside[width=20]a box (with char=\u0027*\u0027). Word wrap at the end.\r\n[/box]", +"IsFancy":true, +"BoxMode":false, +"MaxWidth":80, +"BackgroundColor":0}, + +"113":{ +"Text":"Simple URL [url]https://example.com/[/url], fancier URL [url=https://example.com/]link text[/url].\r\n[box]In a box [url]https://example.com/[/url].[/box]\r\n\r\nA URL may not [url]have a [box]...[/box] tag[/url] inside.\r\nNor may it have [url]an [hr], [br], or [width=2] tag[/url].\r\nLine wrapping the contents of a URL link area should work [url=https://example.com]+this is the area inside+[/url].\r\n", +"IsFancy":true, +"BoxMode":false, +"MaxWidth":80, +"BackgroundColor":0}, + +"115":{ +"Text":"[BOX]ALL CAPS [URL=HTTPS://EXAMPLE.COM/]FOR EVERYTHING[/URL][HR][/BOX]\r\n[BR]\r\n[WIDTH=10]SHORT LINES\r\n[BOX CHAR=\u0027X\u0027]BOXED[/BOX]\r\n", +"IsFancy":true, +"BoxMode":false, +"MaxWidth":80, +"BackgroundColor":0}, + +"117":{ +"Text":"[width=20]\r\nTest some folding with \\[width=20].\r\n01234567890123456789\r\n012345678901234567-89\r\n0123456789012345678 9\r\n 1234567890123456789\r\n-1234567890123456789\r\n -234567890123456789\r\n", +"IsFancy":true, +"BoxMode":false, +"MaxWidth":80, "BackgroundColor":0}}, "Notes":{ diff --git a/SourceGen/SGTestData/Expected/20090-notes-and-comments_64tass.S b/SourceGen/SGTestData/Expected/20090-notes-and-comments_64tass.S index f08cd0c..83ab9fc 100644 --- a/SourceGen/SGTestData/Expected/20090-notes-and-comments_64tass.S +++ b/SourceGen/SGTestData/Expected/20090-notes-and-comments_64tass.S @@ -129,9 +129,63 @@ L1062 bit plataddr ;Pull in plataddr to see the comment on the platform ;three above, one below lda #$14 +;------------------------------------------------------------------------------- +;Full width box, with default char. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; stuff in the box zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz aaaa bbb ; +; cccc ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Explicit char=';'. ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;Now with reduced width and char='#'. +;######### +;# A # +;# much # +;# small # +;# er # +;# box. # +;######### +;******************************************************************************* +;* Width changes are illegal inside[width=20]a box (with char='*'). Word wrap * +;* at the end. * +;******************************************************************************* lda #$15 +;Simple URL https://example.com/, fancier URL link text (https://example.com/). +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; In a box https://example.com/. ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +;A URL may not have a [box]...[/box] tag inside. +;Nor may it have an [hr], [br], or [width=2] tag. +;Line wrapping the contents of a URL link area should work +this is the area +;inside+ (https://example.com). lda #$16 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ALL CAPS FOR EVERYTHING (HTTPS://EXAMPLE.COM/) ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;SHORT +;LINES +;XXXXXXXXX +;X BOXED X +;XXXXXXXXX lda #$17 +;Test some folding +;with [width=20]. +;0123456789012345678 +;9 +;012345678901234567- +;89 +;0123456789012345678 +;9 +; 123456789012345678 +;9 +;-123456789012345678 +;9 +; - +;234567890123456789 lda #$18 lda #$19 lda #$1a diff --git a/SourceGen/SGTestData/Expected/20090-notes-and-comments_acme.S b/SourceGen/SGTestData/Expected/20090-notes-and-comments_acme.S index 9bd5cfe..f74647d 100644 --- a/SourceGen/SGTestData/Expected/20090-notes-and-comments_acme.S +++ b/SourceGen/SGTestData/Expected/20090-notes-and-comments_acme.S @@ -127,9 +127,63 @@ L1062 bit plataddr ;Pull in plataddr to see the comment on the platform ;three above, one below lda #$14 +;------------------------------------------------------------------------------- +;Full width box, with default char. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; stuff in the box zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz aaaa bbb ; +; cccc ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Explicit char=';'. ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;Now with reduced width and char='#'. +;######### +;# A # +;# much # +;# small # +;# er # +;# box. # +;######### +;******************************************************************************* +;* Width changes are illegal inside[width=20]a box (with char='*'). Word wrap * +;* at the end. * +;******************************************************************************* lda #$15 +;Simple URL https://example.com/, fancier URL link text (https://example.com/). +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; In a box https://example.com/. ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +;A URL may not have a [box]...[/box] tag inside. +;Nor may it have an [hr], [br], or [width=2] tag. +;Line wrapping the contents of a URL link area should work +this is the area +;inside+ (https://example.com). lda #$16 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ALL CAPS FOR EVERYTHING (HTTPS://EXAMPLE.COM/) ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;SHORT +;LINES +;XXXXXXXXX +;X BOXED X +;XXXXXXXXX lda #$17 +;Test some folding +;with [width=20]. +;0123456789012345678 +;9 +;012345678901234567- +;89 +;0123456789012345678 +;9 +; 123456789012345678 +;9 +;-123456789012345678 +;9 +; - +;234567890123456789 lda #$18 lda #$19 lda #$1a diff --git a/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S b/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S index ec3bb37..2dd8de2 100644 --- a/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S +++ b/SourceGen/SGTestData/Expected/20090-notes-and-comments_cc65.S @@ -129,9 +129,63 @@ L1062: bit plataddr ;Pull in plataddr to see the comment on the platform ;three above, one below lda #$14 +;------------------------------------------------------------------------------- +;Full width box, with default char. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; stuff in the box zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz aaaa bbb ; +; cccc ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Explicit char=';'. ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;Now with reduced width and char='#'. +;######### +;# A # +;# much # +;# small # +;# er # +;# box. # +;######### +;******************************************************************************* +;* Width changes are illegal inside[width=20]a box (with char='*'). Word wrap * +;* at the end. * +;******************************************************************************* lda #$15 +;Simple URL https://example.com/, fancier URL link text (https://example.com/). +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; In a box https://example.com/. ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +;A URL may not have a [box]...[/box] tag inside. +;Nor may it have an [hr], [br], or [width=2] tag. +;Line wrapping the contents of a URL link area should work +this is the area +;inside+ (https://example.com). lda #$16 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; ALL CAPS FOR EVERYTHING (HTTPS://EXAMPLE.COM/) ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;SHORT +;LINES +;XXXXXXXXX +;X BOXED X +;XXXXXXXXX lda #$17 +;Test some folding +;with [width=20]. +;0123456789012345678 +;9 +;012345678901234567- +;89 +;0123456789012345678 +;9 +; 123456789012345678 +;9 +;-123456789012345678 +;9 +; - +;234567890123456789 lda #$18 lda #$19 lda #$1a diff --git a/SourceGen/SGTestData/Expected/20090-notes-and-comments_merlin32.S b/SourceGen/SGTestData/Expected/20090-notes-and-comments_merlin32.S index 95b8eb0..32bbd0e 100644 --- a/SourceGen/SGTestData/Expected/20090-notes-and-comments_merlin32.S +++ b/SourceGen/SGTestData/Expected/20090-notes-and-comments_merlin32.S @@ -124,9 +124,63 @@ L1062 bit plataddr ;Pull in plataddr to see the comment on the platform f *three above, one below lda #$14 +*------------------------------------------------------------------------------- +*Full width box, with default char. +******************************************************************************** +* stuff in the box zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz aaaa bbb * +* cccc * +******************************************************************************** +*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +*; Explicit char=';'. ; +*;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +*Now with reduced width and char='#'. +*######### +*# A # +*# much # +*# small # +*# er # +*# box. # +*######### +******************************************************************************* +* Width changes are illegal inside[width=20]a box (with char='*'). Word wrap * +* at the end. * +******************************************************************************* lda #$15 +*Simple URL https://example.com/, fancier URL link text (https://example.com/). +******************************************************************************** +* In a box https://example.com/. * +******************************************************************************** +* +*A URL may not have a [box]...[/box] tag inside. +*Nor may it have an [hr], [br], or [width=2] tag. +*Line wrapping the contents of a URL link area should work +this is the area +*inside+ (https://example.com). lda #$16 +******************************************************************************** +* ALL CAPS FOR EVERYTHING (HTTPS://EXAMPLE.COM/) * +******************************************************************************** +******************************************************************************** + +*SHORT +*LINES +*XXXXXXXXX +*X BOXED X +*XXXXXXXXX lda #$17 +*Test some folding +*with [width=20]. +*0123456789012345678 +*9 +*012345678901234567- +*89 +*0123456789012345678 +*9 +* 123456789012345678 +*9 +*-123456789012345678 +*9 +* - +*234567890123456789 lda #$18 lda #$19 lda #$1a