浏览代码

Merge pull request #2215 from BDisp/textview-textfield-isdrirty-fix-2212

Fixes #2212. Editor Scenario: Crashes on Exit.
Tig 2 年之前
父节点
当前提交
92f641568f
共有 4 个文件被更改,包括 111 次插入47 次删除
  1. 4 1
      Terminal.Gui/Views/TextField.cs
  2. 5 5
      Terminal.Gui/Views/TextView.cs
  3. 15 0
      UnitTests/TextFieldTests.cs
  4. 87 41
      UnitTests/TextViewTests.cs

+ 4 - 1
Terminal.Gui/Views/TextField.cs

@@ -235,7 +235,10 @@ namespace Terminal.Gui {
 
 
 		private void HistoryText_ChangeText (HistoryText.HistoryTextItem obj)
 		private void HistoryText_ChangeText (HistoryText.HistoryTextItem obj)
 		{
 		{
-			Text = ustring.Make (obj.Lines [obj.CursorPosition.Y]);
+			if (obj == null)
+				return;
+
+			Text = ustring.Make (obj?.Lines [obj.CursorPosition.Y]);
 			CursorPosition = obj.CursorPosition.X;
 			CursorPosition = obj.CursorPosition.X;
 			Adjust ();
 			Adjust ();
 		}
 		}

+ 5 - 5
Terminal.Gui/Views/TextView.cs

@@ -851,7 +851,7 @@ namespace Terminal.Gui {
 			var firstLine = wrappedModelLines.IndexOf (r => r.ModelLine == modelLine);
 			var firstLine = wrappedModelLines.IndexOf (r => r.ModelLine == modelLine);
 			int modelCol = 0;
 			int modelCol = 0;
 
 
-			for (int i = firstLine; i <= line; i++) {
+			for (int i = firstLine; i <= Math.Min (line, wrappedModelLines.Count - 1); i++) {
 				var wLine = wrappedModelLines [i];
 				var wLine = wrappedModelLines [i];
 
 
 				if (i < line) {
 				if (i < line) {
@@ -1165,7 +1165,7 @@ namespace Terminal.Gui {
 		/// Unlike the <see cref="TextChanged"/> event, this event is raised whenever the user types or
 		/// Unlike the <see cref="TextChanged"/> event, this event is raised whenever the user types or
 		/// otherwise changes the contents of the <see cref="TextView"/>.
 		/// otherwise changes the contents of the <see cref="TextView"/>.
 		/// </remarks>
 		/// </remarks>
-		public Action<ContentsChangedEventArgs> ContentsChanged;
+		public event Action<ContentsChangedEventArgs> ContentsChanged;
 
 
 		/// <summary>
 		/// <summary>
 		/// Invoked with the unwrapped <see cref="CursorPosition"/>.
 		/// Invoked with the unwrapped <see cref="CursorPosition"/>.
@@ -1432,7 +1432,7 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			UpdateWrapModel ();
 			UpdateWrapModel ();
-			
+
 			Adjust ();
 			Adjust ();
 			OnContentsChanged ();
 			OnContentsChanged ();
 		}
 		}
@@ -1830,6 +1830,7 @@ namespace Terminal.Gui {
 			try {
 			try {
 				SetWrapModel ();
 				SetWrapModel ();
 				res = model.LoadFile (path);
 				res = model.LoadFile (path);
+				historyText.Clear (Text);
 				ResetPosition ();
 				ResetPosition ();
 			} catch (Exception) {
 			} catch (Exception) {
 				throw;
 				throw;
@@ -1837,7 +1838,6 @@ namespace Terminal.Gui {
 				UpdateWrapModel ();
 				UpdateWrapModel ();
 				SetNeedsDisplay ();
 				SetNeedsDisplay ();
 				Adjust ();
 				Adjust ();
-				OnContentsChanged ();
 			}
 			}
 			return res;
 			return res;
 		}
 		}
@@ -1850,9 +1850,9 @@ namespace Terminal.Gui {
 		public void LoadStream (Stream stream)
 		public void LoadStream (Stream stream)
 		{
 		{
 			model.LoadStream (stream);
 			model.LoadStream (stream);
+			historyText.Clear (Text);
 			ResetPosition ();
 			ResetPosition ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
-			OnContentsChanged ();
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>

+ 15 - 0
UnitTests/TextFieldTests.cs

@@ -1281,5 +1281,20 @@ namespace Terminal.Gui.Views {
 			Assert.Equal (0, tf.ScrollOffset);
 			Assert.Equal (0, tf.ScrollOffset);
 			Assert.Equal (16, tf.CursorPosition);
 			Assert.Equal (16, tf.CursorPosition);
 		}
 		}
+
+		[Fact]
+		public void HistoryText_IsDirty_ClearHistoryChanges ()
+		{
+			var text = "Testing";
+			var tf = new TextField (text);
+
+			Assert.Equal (text, tf.Text);
+			tf.ClearHistoryChanges ();
+			Assert.False (tf.IsDirty);
+
+			Assert.True (tf.ProcessKey (new KeyEvent (Key.A, new KeyModifiers ())));
+			Assert.Equal ($"{text}A", tf.Text);
+			Assert.True (tf.IsDirty);
+		}
 	}
 	}
 }
 }

+ 87 - 41
UnitTests/TextViewTests.cs

@@ -1,6 +1,5 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Diagnostics.Tracing;
 using System.Linq;
 using System.Linq;
 using System.Reflection;
 using System.Reflection;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
@@ -1930,6 +1929,51 @@ namespace Terminal.Gui.Views {
 			Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", tv.Text);
 			Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", tv.Text);
 		}
 		}
 
 
+		[Fact]
+		public void LoadStream_IsDirty ()
+		{
+			var text = "Testing";
+			using (System.IO.MemoryStream stream = new System.IO.MemoryStream ()) {
+
+				var writer = new System.IO.StreamWriter (stream);
+				writer.Write (text);
+				writer.Flush ();
+				stream.Position = 0;
+
+				var tv = new TextView ();
+				tv.LoadStream (stream);
+
+				Assert.Equal (7, text.Length);
+				Assert.Equal (text.Length, tv.Text.Length);
+				Assert.Equal (text, tv.Text);
+				Assert.False (tv.IsDirty);
+			}
+		}
+
+		[Fact]
+		public void LoadStream_IsDirty_With_Null_On_The_Text ()
+		{
+			var text = "Test\0ing";
+			using (System.IO.MemoryStream stream = new System.IO.MemoryStream ()) {
+
+				var writer = new System.IO.StreamWriter (stream);
+				writer.Write (text);
+				writer.Flush ();
+				stream.Position = 0;
+
+				var tv = new TextView ();
+				tv.LoadStream (stream);
+
+				Assert.Equal (8, text.Length);
+				Assert.Equal (text.Length, tv.Text.Length);
+				Assert.Equal (8, text.Length);
+				Assert.Equal (8, tv.Text.Length);
+				Assert.Equal (text, tv.Text);
+				Assert.False (tv.IsDirty);
+				Assert.Equal ('\u2400', ConsoleDriver.MakePrintable ((Rune)tv.Text [4]));
+			}
+		}
+
 		[Fact]
 		[Fact]
 		public void StringToRunes_Slipts_CRLF ()
 		public void StringToRunes_Slipts_CRLF ()
 		{
 		{
@@ -6430,16 +6474,17 @@ This is the second line.
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void ContentsChanged_Event_NoFires_On_CursorPosition ()
 		public void ContentsChanged_Event_NoFires_On_CursorPosition ()
 		{
 		{
+			var eventcount = 0;
+
 			var tv = new TextView {
 			var tv = new TextView {
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
 			};
 			};
 
 
-			var eventcount = 0;
-			Assert.Null (tv.ContentsChanged);
 			tv.ContentsChanged += (e) => {
 			tv.ContentsChanged += (e) => {
 				eventcount++;
 				eventcount++;
 			};
 			};
+			Assert.Equal (0, eventcount);
 
 
 			tv.CursorPosition = new Point (0, 0);
 			tv.CursorPosition = new Point (0, 0);
 
 
@@ -6449,19 +6494,19 @@ This is the second line.
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void ContentsChanged_Event_Fires_On_InsertText ()
 		public void ContentsChanged_Event_Fires_On_InsertText ()
 		{
 		{
+			var eventcount = 0;
+
 			var tv = new TextView {
 			var tv = new TextView {
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
 			};
 			};
 			tv.CursorPosition = new Point (0, 0);
 			tv.CursorPosition = new Point (0, 0);
 
 
-			var eventcount = 0;
-
-			Assert.Null (tv.ContentsChanged);
 			tv.ContentsChanged += (e) => {
 			tv.ContentsChanged += (e) => {
 				eventcount++;
 				eventcount++;
 			};
 			};
 
 
+			Assert.Equal (0, eventcount);
 
 
 			tv.InsertText ("a");
 			tv.InsertText ("a");
 			Assert.Equal (1, eventcount);
 			Assert.Equal (1, eventcount);
@@ -6469,7 +6514,7 @@ This is the second line.
 			tv.CursorPosition = new Point (0, 0);
 			tv.CursorPosition = new Point (0, 0);
 			tv.InsertText ("bcd");
 			tv.InsertText ("bcd");
 			Assert.Equal (4, eventcount);
 			Assert.Equal (4, eventcount);
-			
+
 			tv.InsertText ("e");
 			tv.InsertText ("e");
 			Assert.Equal (5, eventcount);
 			Assert.Equal (5, eventcount);
 
 
@@ -6494,11 +6539,11 @@ This is the second line.
 			var tv = new TextView {
 			var tv = new TextView {
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
-				ContentsChanged = (e) => {
-					eventcount++;
-					Assert.Equal (expectedRow, e.Row);
-					Assert.Equal (expectedCol, e.Col);
-				}
+			};
+			tv.ContentsChanged += (e) => {
+				eventcount++;
+				Assert.Equal (expectedRow, e.Row);
+				Assert.Equal (expectedCol, e.Col);
 			};
 			};
 
 
 			Application.Top.Add (tv);
 			Application.Top.Add (tv);
@@ -6523,12 +6568,13 @@ This is the second line.
 				// you'd think col would be 3, but it's 0 because TextView sets
 				// you'd think col would be 3, but it's 0 because TextView sets
 				// row/col = 0 when you set Text
 				// row/col = 0 when you set Text
 				Text = "abc",
 				Text = "abc",
-				ContentsChanged = (e) => {
-					eventcount++;
-					Assert.Equal (expectedRow, e.Row);
-					Assert.Equal (expectedCol, e.Col);
-				}
 			};
 			};
+			tv.ContentsChanged += (e) => {
+				eventcount++;
+				Assert.Equal (expectedRow, e.Row);
+				Assert.Equal (expectedCol, e.Col);
+			};
+
 			Assert.Equal ("abc", tv.Text);
 			Assert.Equal ("abc", tv.Text);
 
 
 			Application.Top.Add (tv);
 			Application.Top.Add (tv);
@@ -6554,11 +6600,11 @@ This is the second line.
 			var tv = new TextView {
 			var tv = new TextView {
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
-				ContentsChanged = (e) => {
-					eventcount++;
-					Assert.Equal (expectedRow, e.Row);
-					Assert.Equal (expectedCol, e.Col);
-				}
+			};
+			tv.ContentsChanged += (e) => {
+				eventcount++;
+				Assert.Equal (expectedRow, e.Row);
+				Assert.Equal (expectedCol, e.Col);
 			};
 			};
 
 
 			Application.Top.Add (tv);
 			Application.Top.Add (tv);
@@ -6580,7 +6626,7 @@ This is the second line.
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
 
 
-			_textView.ContentsChanged = (e) => {
+			_textView.ContentsChanged += (e) => {
 				eventcount++;
 				eventcount++;
 			};
 			};
 
 
@@ -6601,13 +6647,12 @@ This is the second line.
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 		}
 		}
 
 
-
 		[Fact, InitShutdown]
 		[Fact, InitShutdown]
 		public void ContentsChanged_Event_Fires_Using_Copy_Or_Cut_Tests ()
 		public void ContentsChanged_Event_Fires_Using_Copy_Or_Cut_Tests ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
 
 
-			_textView.ContentsChanged = (e) => {
+			_textView.ContentsChanged += (e) => {
 				eventcount++;
 				eventcount++;
 			};
 			};
 
 
@@ -6656,7 +6701,7 @@ This is the second line.
 			expectedEventCount += 4;
 			expectedEventCount += 4;
 			Copy_Without_Selection ();
 			Copy_Without_Selection ();
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
-			
+
 			// reset
 			// reset
 			expectedEventCount += 1;
 			expectedEventCount += 1;
 			_textView.Text = InitShutdown.txt;
 			_textView.Text = InitShutdown.txt;
@@ -6673,7 +6718,7 @@ This is the second line.
 			var eventcount = 0;
 			var eventcount = 0;
 			var expectedEventCount = 0;
 			var expectedEventCount = 0;
 
 
-			_textView.ContentsChanged = (e) => {
+			_textView.ContentsChanged += (e) => {
 				eventcount++;
 				eventcount++;
 			};
 			};
 
 
@@ -6716,9 +6761,9 @@ This is the second line.
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
 				Text = text,
 				Text = text,
-				ContentsChanged = (e) => {
-					eventcount++;
-				}
+			};
+			tv.ContentsChanged += (e) => {
+				eventcount++;
 			};
 			};
 
 
 			Assert.True (tv.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ())));
 			Assert.True (tv.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ())));
@@ -6727,46 +6772,47 @@ This is the second line.
 
 
 			var expectedEventCount = 1; // for ENTER key
 			var expectedEventCount = 1; // for ENTER key
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
-			
+
 			tv.ClearHistoryChanges ();
 			tv.ClearHistoryChanges ();
 			expectedEventCount = 2;
 			expectedEventCount = 2;
 			Assert.Equal (expectedEventCount, eventcount);
 			Assert.Equal (expectedEventCount, eventcount);
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void ContentsChanged_Event_Fires_LoadStream ()
+		public void ContentsChanged_Event_Fires_LoadStream_By_Calling_HistoryText_Clear ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
 
 
 			var tv = new TextView {
 			var tv = new TextView {
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
-				ContentsChanged = (e) => {
-					eventcount++;
-				}
+			};
+			tv.ContentsChanged += (e) => {
+				eventcount++;
 			};
 			};
 
 
 			var text = "This is the first line.\r\nThis is the second line.\r\n";
 			var text = "This is the first line.\r\nThis is the second line.\r\n";
 			tv.LoadStream (new System.IO.MemoryStream (System.Text.Encoding.ASCII.GetBytes (text)));
 			tv.LoadStream (new System.IO.MemoryStream (System.Text.Encoding.ASCII.GetBytes (text)));
 			Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", tv.Text);
 			Assert.Equal ($"This is the first line.{Environment.NewLine}This is the second line.{Environment.NewLine}", tv.Text);
-			
+
 			Assert.Equal (1, eventcount);
 			Assert.Equal (1, eventcount);
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void ContentsChanged_Event_Fires_LoadFile ()
+		public void ContentsChanged_Event_Fires_On_LoadFile_By_Calling_HistoryText_Clear ()
 		{
 		{
 			var eventcount = 0;
 			var eventcount = 0;
 
 
 			var tv = new TextView {
 			var tv = new TextView {
 				Width = 50,
 				Width = 50,
 				Height = 10,
 				Height = 10,
-				ContentsChanged = (e) => {
-					eventcount++;
-				}
 			};
 			};
+			tv.ContentsChanged += (e) => {
+				eventcount++;
+			};
+
 			var fileName = "textview.txt";
 			var fileName = "textview.txt";
-			System.IO.File.WriteAllText (fileName, "This is the first line.\r\nThis is the second line.\r\n") ;
+			System.IO.File.WriteAllText (fileName, "This is the first line.\r\nThis is the second line.\r\n");
 
 
 			tv.LoadFile (fileName);
 			tv.LoadFile (fileName);
 			Assert.Equal (1, eventcount);
 			Assert.Equal (1, eventcount);