From 3bb3e30befea5a22be42469cc062a653f88739eb Mon Sep 17 00:00:00 2001 From: "jason@truewheels.net" Date: Fri, 26 Sep 2014 18:15:19 -0700 Subject: [PATCH] Fix exception after AcceptAndGetNext The "current" line cleared after accepting via AcceptAndGetNext and we would crash trying to recall this current line. I've changed how history search works after AcceptAndGetNext to work in a more natural way so that arrow keys can be used to recall commands near the accepted command instead of searching for other commands with the same prefix. Fixes #152. --- PSReadLine/Changes.txt | 1 + PSReadLine/History.cs | 15 +++++++++++---- PSReadLine/ReadLine.cs | 13 ++++++++++++- TestPSReadLine/Program.cs | 7 ++++--- UnitTestPSReadLine/BasicEditingTest.cs | 23 +++++++++++++++++++++++ 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/PSReadLine/Changes.txt b/PSReadLine/Changes.txt index 268a3bb..1ee4369 100644 --- a/PSReadLine/Changes.txt +++ b/PSReadLine/Changes.txt @@ -10,6 +10,7 @@ New features: Set-PSReadlineKeyHandler -Key Enter -Function AcceptLine Bug fixes: +* Occasional exception with AcceptAndGetNext (Ctrl+O) followed by something other than Enter New functions: * ValidateAndAcceptLine diff --git a/PSReadLine/History.cs b/PSReadLine/History.cs index ac8e78b..1bf2d07 100644 --- a/PSReadLine/History.cs +++ b/PSReadLine/History.cs @@ -62,9 +62,16 @@ namespace PSConsoleUtilities { ClearDemoWindow(); } - _savedCurrentLine._line = null; - _savedCurrentLine._edits = null; - _savedCurrentLine._undoEditIndex = 0; + + // Clear the saved line unless we used AcceptAndGetNext in which + // case we're really still in middle of history and might want + // to recall the saved line. + if (_getNextHistoryIndex == 0) + { + _savedCurrentLine._line = null; + _savedCurrentLine._edits = null; + _savedCurrentLine._undoEditIndex = 0; + } return result; } @@ -284,7 +291,7 @@ namespace PSConsoleUtilities // to check if we need to load history from another sessions now. MaybeReadHistoryFile(); - if (_singleton._currentHistoryIndex == _history.Count) + if (_savedCurrentLine._line == null) { _savedCurrentLine._line = _buffer.ToString(); _savedCurrentLine._edits = _edits; diff --git a/PSReadLine/ReadLine.cs b/PSReadLine/ReadLine.cs index d41f755..9c4c7a8 100644 --- a/PSReadLine/ReadLine.cs +++ b/PSReadLine/ReadLine.cs @@ -528,7 +528,6 @@ namespace PSConsoleUtilities _yankCommandCount = 0; _yankLastArgCommandCount = 0; _tabCommandCount = 0; - _searchHistoryCommandCount = 0; _recallHistoryCommandCount = 0; _visualSelectionCommandCount = 0; _hashedHistory = null; @@ -538,6 +537,18 @@ namespace PSConsoleUtilities _currentHistoryIndex = _getNextHistoryIndex; UpdateFromHistory(moveCursor: true); _getNextHistoryIndex = 0; + if (_searchHistoryCommandCount > 0) + { + _searchHistoryPrefix = ""; + if (Options.HistoryNoDuplicates) + { + _hashedHistory = new Dictionary(); + } + } + } + else + { + _searchHistoryCommandCount = 0; } } diff --git a/TestPSReadLine/Program.cs b/TestPSReadLine/Program.cs index 428060c..df54d45 100644 --- a/TestPSReadLine/Program.cs +++ b/TestPSReadLine/Program.cs @@ -106,13 +106,13 @@ namespace TestPSReadLine PSConsoleReadLine.SetOptions(new SetPSReadlineOption { - EditMode = EditMode.Windows, + EditMode = EditMode.Emacs, HistoryNoDuplicates = true, }); PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+LeftArrow"}, PSConsoleReadLine.ShellBackwardWord, "", ""); PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+RightArrow"}, PSConsoleReadLine.ShellNextWord, "", ""); - PSConsoleReadLine.SetKeyHandler(new[] {"UpArrow"}, PSConsoleReadLine.HistorySearchBackward, "", ""); - PSConsoleReadLine.SetKeyHandler(new[] {"DownArrow"}, PSConsoleReadLine.HistorySearchForward, "", ""); + PSConsoleReadLine.SetKeyHandler(new[] {"F4"}, PSConsoleReadLine.HistorySearchBackward, "", ""); + PSConsoleReadLine.SetKeyHandler(new[] {"F5"}, PSConsoleReadLine.HistorySearchForward, "", ""); //PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+E"}, PSConsoleReadLine.EnableDemoMode, "", ""); //PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+D"}, PSConsoleReadLine.DisableDemoMode, "", ""); PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+C"}, PSConsoleReadLine.CaptureScreen, "", ""); @@ -121,6 +121,7 @@ namespace TestPSReadLine PSConsoleReadLine.SetKeyHandler(new[] {"F6"}, PSConsoleReadLine.PreviousLine, "", ""); PSConsoleReadLine.SetKeyHandler(new[] {"F7"}, PSConsoleReadLine.NextLine, "", ""); PSConsoleReadLine.SetKeyHandler(new[] {"F2"}, PSConsoleReadLine.ValidateAndAcceptLine, "", ""); + PSConsoleReadLine.SetKeyHandler(new[] {"Enter"}, PSConsoleReadLine.AcceptLine, "", ""); EngineIntrinsics executionContext; diff --git a/UnitTestPSReadLine/BasicEditingTest.cs b/UnitTestPSReadLine/BasicEditingTest.cs index 95f450f..6b9149f 100644 --- a/UnitTestPSReadLine/BasicEditingTest.cs +++ b/UnitTestPSReadLine/BasicEditingTest.cs @@ -166,6 +166,29 @@ namespace UnitTestPSReadLine SetHistory("echo 1", "echo 2"); Test("echo 1", Keys(_.UpArrow, _.UpArrow, _.CtrlO, InputAcceptedNow)); Test("echo 2", Keys(_.Enter)); + + // Test that the current saved line is saved after AcceptAndGetNext + SetHistory("echo 1", "echo 2"); + Test("echo 1", Keys("e", _.UpArrow, _.UpArrow, _.CtrlO, InputAcceptedNow)); + Test("e", Keys(_.DownArrow, _.DownArrow, _.Enter)); + + // Test that we can edit after recalling the current line + SetHistory("echo 1", "echo 2"); + Test("echo 1", Keys("e", _.UpArrow, _.UpArrow, _.CtrlO, InputAcceptedNow)); + Test("eee", Keys(_.DownArrow, _.DownArrow, "ee", _.Enter)); + } + + [TestMethod] + public void TestAcceptAndGetNextWithHistorySearch() + { + TestSetup(KeyMode.Emacs, + new KeyHandler("UpArrow", PSConsoleReadLine.HistorySearchBackward), + new KeyHandler("DownArrow", PSConsoleReadLine.HistorySearchForward)); + + // Test that after AcceptAndGetNext, the previous search is not applied + SetHistory("echo 1", "echo 2", "zzz"); + Test("echo 1", Keys("e", _.UpArrow, _.UpArrow, _.CtrlO, InputAcceptedNow)); + Test("zzz", Keys(_.DownArrow, _.Enter)); } [TestMethod]