Преглед на файлове

Fixes #1925. Preserve trailing spaces on word wrap must be refactored… (#1929)

* Fixes #1925. Preserve trailing spaces on word wrap must be refactored on TextFormatter.

* Fixes a bug on Format when the preserveTrailingSpaces is enabled.

Co-authored-by: Tig Kindel <[email protected]>
BDisp преди 3 години
родител
ревизия
a23c1bee19
променени са 5 файла, в които са добавени 106 реда и са изтрити 67 реда
  1. 15 6
      Terminal.Gui/Core/TextFormatter.cs
  2. 2 26
      Terminal.Gui/Views/TextView.cs
  3. 10 10
      UnitTests/ScrollBarViewTests.cs
  4. 57 4
      UnitTests/TextFormatterTests.cs
  5. 22 21
      UnitTests/TextViewTests.cs

+ 15 - 6
Terminal.Gui/Core/TextFormatter.cs

@@ -366,22 +366,28 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public bool NeedsFormat { get => needsFormat; set => needsFormat = value; }
 
-		static ustring StripCRLF (ustring str)
+		static ustring StripCRLF (ustring str, bool keepNewLine = false)
 		{
 			var runes = str.ToRuneList ();
 			for (int i = 0; i < runes.Count; i++) {
 				switch (runes [i]) {
 				case '\n':
-					runes.RemoveAt (i);
+					if (!keepNewLine) {
+						runes.RemoveAt (i);
+					}
 					break;
 
 				case '\r':
 					if ((i + 1) < runes.Count && runes [i + 1] == '\n') {
 						runes.RemoveAt (i);
-						runes.RemoveAt (i + 1);
+						if (!keepNewLine) {
+							runes.RemoveAt (i);
+						}
 						i++;
 					} else {
-						runes.RemoveAt (i);
+						if (!keepNewLine) {
+							runes.RemoveAt (i);
+						}
 					}
 					break;
 				}
@@ -515,6 +521,7 @@ namespace Terminal.Gui {
 
 			int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = 0)
 			{
+				var lastFrom = from;
 				var to = from;
 				var length = cLength;
 				incomplete = false;
@@ -552,8 +559,10 @@ namespace Terminal.Gui {
 					}
 					to++;
 				}
-				if (cLength > 0 && to < runes.Count && runes [to] != ' ') {
+				if (cLength > 0 && to < runes.Count && runes [to] != ' ' && runes [to] != '\t') {
 					return from;
+				} else if (cLength > 0 && to < runes.Count && (runes [to] == ' ' || runes [to] == '\t')) {
+					return lastFrom;
 				} else {
 					return to;
 				}
@@ -727,7 +736,7 @@ namespace Terminal.Gui {
 				return lineResult;
 			}
 
-			var runes = text.ToRuneList ();
+			var runes = StripCRLF (text, true).ToRuneList ();
 			int runeCount = runes.Count;
 			int lp = 0;
 			for (int i = 0; i < runeCount; i++) {

+ 2 - 26
Terminal.Gui/Views/TextView.cs

@@ -1519,7 +1519,7 @@ namespace Terminal.Gui {
 					out int nStartRow, out int nStartCol,
 					currentRow, currentColumn,
 					selectionStartRow, selectionStartColumn,
-					tabWidth, preserveTrailingSpaces: !ReadOnly);
+					tabWidth, preserveTrailingSpaces: true);
 				currentRow = nRow;
 				currentColumn = nCol;
 				selectionStartRow = nStartRow;
@@ -1610,10 +1610,7 @@ namespace Terminal.Gui {
 				}
 
 				SetWrapModel ();
-				var savedCurrentColumn = CurrentColumn;
-				currentColumn = GetCurrentColumnReadOnyWrapModel (true);
 				var sel = GetRegion ();
-				currentColumn = savedCurrentColumn;
 				UpdateWrapModel ();
 				Adjust ();
 
@@ -1993,9 +1990,6 @@ namespace Terminal.Gui {
 				if (value != isReadOnly) {
 					isReadOnly = value;
 
-					SetWrapModel ();
-					currentColumn = GetCurrentColumnReadOnyWrapModel ();
-					UpdateWrapModel ();
 					SetNeedsDisplay ();
 					Adjust ();
 				}
@@ -2316,7 +2310,7 @@ namespace Terminal.Gui {
 				wrapManager.UpdateModel (model, out int nRow, out int nCol,
 					out int nStartRow, out int nStartCol,
 					currentRow, currentColumn,
-					selectionStartRow, selectionStartColumn, preserveTrailingSpaces: !ReadOnly);
+					selectionStartRow, selectionStartColumn, preserveTrailingSpaces: true);
 				currentRow = nRow;
 				currentColumn = nCol;
 				selectionStartRow = nStartRow;
@@ -2327,21 +2321,6 @@ namespace Terminal.Gui {
 				throw new InvalidOperationException ($"WordWrap settings was changed after the {currentCaller} call.");
 		}
 
-		int GetCurrentColumnReadOnyWrapModel (bool forcePreserveTrailingSpaces = false)
-		{
-			if (wordWrap) {
-				var wManager = new WordWrapManager (wrapManager.Model);
-				if (ReadOnly && !forcePreserveTrailingSpaces) {
-					wManager.WrapModel (frameWidth, out _, out _, out _, out _, preserveTrailingSpaces: false);
-				} else {
-					wManager.WrapModel (frameWidth, out _, out _, out _, out _, preserveTrailingSpaces: true);
-				}
-				var currentLine = wrapManager.GetWrappedLineColWidth (CurrentRow, CurrentColumn, wManager);
-				return currentLine;
-			}
-			return currentColumn;
-		}
-
 		///<inheritdoc/>
 		public override void Redraw (Rect bounds)
 		{
@@ -3803,8 +3782,6 @@ namespace Terminal.Gui {
 		public void Copy ()
 		{
 			SetWrapModel ();
-			var savedCurrentColumn = CurrentColumn;
-			currentColumn = GetCurrentColumnReadOnyWrapModel (true);
 			if (selecting) {
 				SetClipboard (GetRegion ());
 				copyWithoutSelection = false;
@@ -3813,7 +3790,6 @@ namespace Terminal.Gui {
 				SetClipboard (ustring.Make (currentLine));
 				copyWithoutSelection = true;
 			}
-			currentColumn = savedCurrentColumn;
 			UpdateWrapModel ();
 			DoNeededAction ();
 		}

+ 10 - 10
UnitTests/ScrollBarViewTests.cs

@@ -745,7 +745,7 @@ namespace Terminal.Gui.Views {
 			Assert.True (textView.WordWrap);
 			Assert.True (scrollBar.AutoHideScrollBars);
 			Assert.Equal (7, textView.Lines);
-			Assert.Equal (23, textView.Maxlength);
+			Assert.Equal (22, textView.Maxlength);
 			Assert.Equal (0, textView.LeftColumn);
 			Assert.Equal (0, scrollBar.Position);
 			Assert.Equal (0, scrollBar.OtherScrollBarView.Position);
@@ -754,8 +754,8 @@ namespace Terminal.Gui.Views {
 │This is the help text   │
 │for the Second Step.    │
 │                        │
-│Press the button to see
-│ a message box.   
+│Press the button to    
+│see a message box.      │
 │                        │
 │Enter name too.         │
 │                        │
@@ -780,21 +780,21 @@ namespace Terminal.Gui.Views {
 
 			Assert.True (textView.WordWrap);
 			Assert.True (scrollBar.AutoHideScrollBars);
-			Assert.Equal (19, textView.Lines);
+			Assert.Equal (20, textView.Lines);
 			Assert.Equal (7, textView.Maxlength);
 			Assert.Equal (0, textView.LeftColumn);
 			Assert.Equal (0, scrollBar.Position);
 			Assert.Equal (0, scrollBar.OtherScrollBarView.Position);
 			expected = @"
 ┌ Test ──┐
-│This is▲│
-│ the   ┬│
+│This   ▲│
+│is the ┬│
 │help   ││
 │text   ┴│
-│for the░│
-│ Second░│
-│ Step. ░│
-│       ▼│
+│for    ░│
+│the    ░│
+│Second ░│
+│Step.  ▼│
 └────────┘
 ";
 

+ 57 - 4
UnitTests/TextFormatterTests.cs

@@ -2006,10 +2006,33 @@ namespace Terminal.Gui.Core {
 			wrappedLines = TextFormatter.WordWrap (text, maxWidth, true);
 			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.RuneCount));
 			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.ConsoleWidth));
-			Assert.Equal ("A sentence has", wrappedLines [0].ToString ());
-			Assert.Equal (" words.", wrappedLines [1].ToString ());
+			Assert.Equal ("A sentence ", wrappedLines [0].ToString ());
+			Assert.Equal ("has words.", wrappedLines [1].ToString ());
 			Assert.True (wrappedLines.Count == 2);
 
+			maxWidth = 8;
+			expectedClippedWidth = 8;
+			wrappedLines = TextFormatter.WordWrap (text, maxWidth, true);
+			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.RuneCount));
+			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.ConsoleWidth));
+			Assert.Equal ("A ", wrappedLines [0].ToString ());
+			Assert.Equal ("sentence", wrappedLines [1].ToString ());
+			Assert.Equal (" has ", wrappedLines [2].ToString ());
+			Assert.Equal ("words.", wrappedLines [^1].ToString ());
+			Assert.True (wrappedLines.Count == 4);
+
+			maxWidth = 6;
+			expectedClippedWidth = 6;
+			wrappedLines = TextFormatter.WordWrap (text, maxWidth, true);
+			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.RuneCount));
+			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.ConsoleWidth));
+			Assert.Equal ("A ", wrappedLines [0].ToString ());
+			Assert.Equal ("senten", wrappedLines [1].ToString ());
+			Assert.Equal ("ce ", wrappedLines [2].ToString ());
+			Assert.Equal ("has ", wrappedLines [3].ToString ());
+			Assert.Equal ("words.", wrappedLines [^1].ToString ());
+			Assert.True (wrappedLines.Count == 5);
+
 			maxWidth = 3;
 			expectedClippedWidth = 3;
 			wrappedLines = TextFormatter.WordWrap (text, maxWidth, true);
@@ -2312,6 +2335,18 @@ namespace Terminal.Gui.Core {
 			Assert.Equal ("words.", wrappedLines [2].ToString ());
 			Assert.True (wrappedLines.Count == 3);
 
+			maxWidth = 8;
+			expectedClippedWidth = 8;
+			wrappedLines = TextFormatter.WordWrap (text, maxWidth, true, tabWidth);
+			Assert.True (expectedClippedWidth >= wrappedLines.Max (l => l.RuneCount));
+			Assert.Equal ("A ", wrappedLines [0].ToString ());
+			Assert.Equal ("sentence", wrappedLines [1].ToString ());
+			Assert.Equal ("\t\t", wrappedLines [2].ToString ());
+			Assert.Equal ("\t ", wrappedLines [3].ToString ());
+			Assert.Equal ("has ", wrappedLines [4].ToString ());
+			Assert.Equal ("words.", wrappedLines [^1].ToString ());
+			Assert.True (wrappedLines.Count == 6);
+
 			maxWidth = 3;
 			expectedClippedWidth = 3;
 			wrappedLines = TextFormatter.WordWrap (text, maxWidth, true, tabWidth);
@@ -2873,8 +2908,8 @@ namespace Terminal.Gui.Core {
 			Assert.Equal (" A ", list2 [0].ToString ());
 			Assert.Equal ("sent", list2 [1].ToString ());
 			Assert.Equal ("ence", list2 [2].ToString ());
-			Assert.Equal (" has", list2 [3].ToString ());
-			Assert.Equal (" ", list2 [4].ToString ());
+			Assert.Equal (" ", list2 [3].ToString ());
+			Assert.Equal ("has ", list2 [4].ToString ());
 			Assert.Equal ("word", list2 [5].ToString ());
 			Assert.Equal ("s. ", list2 [6].ToString ());
 			Assert.Equal (" ", list2 [7].ToString ());
@@ -3959,5 +3994,23 @@ e
 			pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output);
 			Assert.Equal (new Rect (0, 0, 4, 10), pos);
 		}
+
+		[Fact]
+		public void Format_With_PreserveTrailingSpaces_And_Without_PreserveTrailingSpaces ()
+		{
+			var text = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3{Environment.NewLine}";
+			var width = 60;
+			var preserveTrailingSpaces = false;
+			var formated = TextFormatter.Format (text, width, false, true, preserveTrailingSpaces);
+			Assert.Equal ("Line1", formated [0]);
+			Assert.Equal ("Line2", formated [1]);
+			Assert.Equal ("Line3", formated [^1]);
+
+			preserveTrailingSpaces = true;
+			formated = TextFormatter.Format (text, width, false, true, preserveTrailingSpaces);
+			Assert.Equal ("Line1", formated [0]);
+			Assert.Equal ("Line2", formated [1]);
+			Assert.Equal ("Line3", formated [^1]);
+		}
 	}
 }

+ 22 - 21
UnitTests/TextViewTests.cs

@@ -1967,17 +1967,16 @@ namespace Terminal.Gui.Views {
 
 			tv.Redraw (tv.Bounds);
 
-			string expected = @"
+			GraphViewTests.AssertDriverContentsWithFrameAre (@"
 This is
-the first
- line.
+the    
+first  
+line.  
 This is
-the
-second
-line.
-";
-
-			GraphViewTests.AssertDriverContentsAre (expected, output);
+the    
+second 
+line.  
+", output);
 		}
 
 		[Fact]
@@ -2050,26 +2049,28 @@ a
 			Application.Top.Add (tv);
 
 			tv.Redraw (tv.Bounds);
-			GraphViewTests.AssertDriverContentsAre (@"
-This is
+			GraphViewTests.AssertDriverContentsWithFrameAre (@"
+This is  
 the first
-line.
-This is
-the second
- line.
+line.    
+This is  
+the      
+second   
+line.    
 ", output);
 
 			tv.ReadOnly = true;
 			tv.CursorPosition = new Point (6, 2);
 			Assert.Equal (new Point (5, 2), tv.CursorPosition);
 			tv.Redraw (tv.Bounds);
-			GraphViewTests.AssertDriverContentsAre (@"
-This is
+			GraphViewTests.AssertDriverContentsWithFrameAre (@"
+This is  
 the first
-line.
-This is
-the second
-line.
+line.    
+This is  
+the      
+second   
+line.    
 ", output);
 
 			tv.SelectionStartRow = 0;