Browse Source

Fixes #1148. TextFormatter.Format does not keep the end spaces on wrapped text. (#1149)

* Fixes #1148. TextFormatter.Format does not keep the end spaces on wrapped text.

* Added comments.

* Changing keepEndSapces to preserveTrailingSpaces.
BDisp 4 years ago
parent
commit
482f9db7da
2 changed files with 132 additions and 7 deletions
  1. 12 7
      Terminal.Gui/Core/TextFormatter.cs
  2. 120 0
      UnitTests/TextFormatterTests.cs

+ 12 - 7
Terminal.Gui/Core/TextFormatter.cs

@@ -113,7 +113,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// <para>
 		/// Upon a 'get' of this property, if the text needs to be formatted (if <see cref="NeedsFormat"/> is <c>true</c>)
-		/// <see cref="Format(ustring, int, TextAlignment, bool)"/> will be called internally. 
+		/// <see cref="Format(ustring, int, TextAlignment, bool, bool)"/> will be called internally. 
 		/// </para>
 		/// </remarks>
 		public List<ustring> Lines {
@@ -203,6 +203,8 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// <param name="text">The text to word wrap</param>
 		/// <param name="width">The width to contain the text to</param>
+		/// <param name="preserveTrailingSpaces">If <c>true</c>, the wrapped text will keep the trailing spaces.
+		///  If <c>false</c>, the trailing spaces will be trimmed.</param>
 		/// <returns>Returns a list of word wrapped lines.</returns>
 		/// <remarks>
 		/// <para>
@@ -212,7 +214,7 @@ namespace Terminal.Gui {
 		/// This method strips Newline ('\n' and '\r\n') sequences before processing.
 		/// </para>
 		/// </remarks>
-		public static List<ustring> WordWrap (ustring text, int width)
+		public static List<ustring> WordWrap (ustring text, int width, bool preserveTrailingSpaces = false)
 		{
 			if (width < 0) {
 				throw new ArgumentOutOfRangeException ("Width cannot be negative.");
@@ -234,7 +236,7 @@ namespace Terminal.Gui {
 					end = start + width;
 				lines.Add (ustring.Make (runes.GetRange (start, end - start)));
 				start = end;
-				if (runes[end] == ' ') {
+				if (runes [end] == ' ' && !preserveTrailingSpaces) {
 					start++;
 				}
 			}
@@ -321,6 +323,7 @@ namespace Terminal.Gui {
 		/// <param name="width">The width to bound the text to for word wrapping and clipping.</param>
 		/// <param name="talign">Specifies how the text will be aligned horizontally.</param>
 		/// <param name="wordWrap">If <c>true</c>, the text will be wrapped to new lines as need. If <c>false</c>, forces text to fit a single line. Line breaks are converted to spaces. The text will be clipped to <c>width</c></param>
+		/// <param name="preserveTrailingSpaces">If <c>true</c> and 'wordWrap' also true, the wrapped text will keep the trailing spaces. If <c>false</c>, the trailing spaces will be trimmed.</param>
 		/// <returns>A list of word wrapped lines.</returns>
 		/// <remarks>
 		/// <para>
@@ -333,12 +336,14 @@ namespace Terminal.Gui {
 		/// If <c>width</c> is int.MaxValue, the text will be formatted to the maximum width possible. 
 		/// </para>
 		/// </remarks>
-		public static List<ustring> Format (ustring text, int width, TextAlignment talign, bool wordWrap)
+		public static List<ustring> Format (ustring text, int width, TextAlignment talign, bool wordWrap, bool preserveTrailingSpaces = false)
 		{
 			if (width < 0) {
 				throw new ArgumentOutOfRangeException ("width cannot be negative");
 			}
-
+			if (preserveTrailingSpaces && !wordWrap) {
+				throw new ArgumentException ("if 'preserveTrailingSpaces' is true, then 'wordWrap' must be true either.");
+			}
 			List<ustring> lineResult = new List<ustring> ();
 
 			if (ustring.IsNullOrEmpty (text) || width == 0) {
@@ -358,7 +363,7 @@ namespace Terminal.Gui {
 			for (int i = 0; i < runeCount; i++) {
 				Rune c = runes [i];
 				if (c == '\n') {
-					var wrappedLines = WordWrap (ustring.Make (runes.GetRange (lp, i - lp)), width);
+					var wrappedLines = WordWrap (ustring.Make (runes.GetRange (lp, i - lp)), width, preserveTrailingSpaces);
 					foreach (var line in wrappedLines) {
 						lineResult.Add (ClipAndJustify (line, width, talign));
 					}
@@ -368,7 +373,7 @@ namespace Terminal.Gui {
 					lp = i + 1;
 				}
 			}
-			foreach (var line in WordWrap (ustring.Make (runes.GetRange (lp, runeCount - lp)), width)) {
+			foreach (var line in WordWrap (ustring.Make (runes.GetRange (lp, runeCount - lp)), width, preserveTrailingSpaces)) {
 				lineResult.Add (ClipAndJustify (line, width, talign));
 			}
 

+ 120 - 0
UnitTests/TextFormatterTests.cs

@@ -2306,5 +2306,125 @@ namespace Terminal.Gui {
 			c = new System.Text.Rune (127);
 			Assert.Equal (1, c.Utf8SequenceLength);		// non printable character
 		}
+
+		[Fact]
+		public void Format_WordWrap_Keep_End_Spaces ()
+		{
+			ustring text = " A sentence has words. \n This is the second Line - 2. ";
+
+			// With preserveTrailingSpaces = false by default.
+			var list1 = TextFormatter.Format (text, 4, TextAlignment.Left, true);
+			ustring wrappedText1 = ustring.Empty;
+			var idx = 0;
+			foreach (var txt in list1) {
+				wrappedText1 += txt;
+				switch (idx) {
+				case 0:
+					Assert.Equal (" A", txt);
+					break;
+				case 1:
+					Assert.Equal ("sent", txt);
+					break;
+				case 2:
+					Assert.Equal ("ence", txt);
+					break;
+				case 3:
+					Assert.Equal ("has", txt);
+					break;
+				case 4:
+					Assert.Equal ("word", txt);
+					break;
+				case 5:
+					Assert.Equal ("s. ", txt);
+					break;
+				case 6:
+					Assert.Equal (" Thi", txt);
+					break;
+				case 7:
+					Assert.Equal ("s is", txt);
+					break;
+				case 8:
+					Assert.Equal ("the", txt);
+					break;
+				case 9:
+					Assert.Equal ("seco", txt);
+					break;
+				case 10:
+					Assert.Equal ("nd", txt);
+					break;
+				case 11:
+					Assert.Equal ("Line", txt);
+					break;
+				case 12:
+					Assert.Equal ("- 2.", txt);
+					break;
+				}
+				idx++;
+			}
+			Assert.Equal (" Asentencehaswords.  This isthesecondLine- 2.", wrappedText1);
+
+			// With preserveTrailingSpaces = true.
+			var list2 = TextFormatter.Format (text, 4, TextAlignment.Left, true, true);
+			ustring wrappedText2 = ustring.Empty;
+			idx = 0;
+			foreach (var txt in list2) {
+				wrappedText2 += txt;
+				switch (idx) {
+				case 0:
+					Assert.Equal (" A", txt);
+					break;
+				case 1:
+					Assert.Equal (" sen", txt);
+					break;
+				case 2:
+					Assert.Equal ("tenc", txt);
+					break;
+				case 3:
+					Assert.Equal ("e", txt);
+					break;
+				case 4:
+					Assert.Equal (" has", txt);
+					break;
+				case 5:
+					Assert.Equal (" wor", txt);
+					break;
+				case 6:
+					Assert.Equal ("ds. ", txt);
+					break;
+				case 7:
+					Assert.Equal (" Thi", txt);
+					break;
+				case 8:
+					Assert.Equal ("s is", txt);
+					break;
+				case 9:
+					Assert.Equal (" the", txt);
+					break;
+				case 10:
+					Assert.Equal (" sec", txt);
+					break;
+				case 11:
+					Assert.Equal ("ond", txt);
+					break;
+				case 12:
+					Assert.Equal (" Lin", txt);
+					break;
+				case 13:
+					Assert.Equal ("e -", txt);
+					break;
+				case 14:
+					Assert.Equal (" 2. ", txt);
+					break;
+				}
+				idx++;
+			}
+			Assert.Equal (" A sentence has words.  This is the second Line - 2. ", wrappedText2);
+		}
+
+		[Fact]
+		public void Format_Throw_ArgumentException_With_WordWrap_As_False_And_Keep_End_Spaces_As_True ()
+		{
+			Assert.Throws<ArgumentException> (() => TextFormatter.Format ("Some text", 4, TextAlignment.Left, false, true));
+		}
 	}
 }