Fix AcceptAndGetNext skipping history problem · PowerShell/PSReadLine@44fc8cb · GitHub
Skip to content

Commit 44fc8cb

Browse files
committed
Fix AcceptAndGetNext skipping history problem
1 parent 2984546 commit 44fc8cb

6 files changed

Lines changed: 39 additions & 48 deletions

File tree

‎PSReadLine/History.cs‎

Lines changed: 8 additions & 2 deletions

‎PSReadLine/Options.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private void SetOptionsInternal(SetPSReadLineOption options)
4747
Options.MaximumHistoryCount = options.MaximumHistoryCount;
4848
if (_history != null)
4949
{
50-
var newHistory = new HistoryQueue<HistoryItem>(Options.MaximumHistoryCount);
50+
var newHistory = new RingBuffer<HistoryItem>(Options.MaximumHistoryCount);
5151
while (_history.Count > Options.MaximumHistoryCount)
5252
{
5353
_history.Dequeue();

‎PSReadLine/ReadLine.cs‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public partial class PSConsoleReadLine : IPSConsoleReadLineMockableMethods
7979
private static readonly Stopwatch _readkeyStopwatch = new Stopwatch();
8080

8181
// Save a fixed # of keys so we can reconstruct a repro after a crash
82-
private static readonly HistoryQueue<PSKeyInfo> _lastNKeys = new HistoryQueue<PSKeyInfo>(200);
82+
private static readonly RingBuffer<PSKeyInfo> _lastNKeys = new RingBuffer<PSKeyInfo>(200);
8383

8484
// Tokens etc.
8585
private Token[] _tokens;
@@ -818,7 +818,11 @@ private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics)
818818

819819
if (_getNextHistoryIndex > 0)
820820
{
821-
_currentHistoryIndex = _getNextHistoryIndex;
821+
// This branch is specifically reached after AcceptAndGetNext and the command execution finished,
822+
// a new history item will be enqueued into `_history`.
823+
// If `_history` ring buffer is full, the original history item `_currentHistoryIndex` pointed to
824+
// will be pushed forward after new item is enqueued, so we need to decrement the index by 1 here
825+
_currentHistoryIndex = _getNextHistoryIndex - (_history.Count == _history.Capacity ? 1 : 0);
822826
UpdateFromHistory(HistoryMoveCursor.ToEnd);
823827
_getNextHistoryIndex = 0;
824828
if (_searchHistoryCommandCount > 0)
@@ -891,8 +895,8 @@ private void DelayedOneTimeInitialize()
891895

892896
_historyFileMutex = new Mutex(false, GetHistorySaveFileMutexName());
893897

894-
_history = new HistoryQueue<HistoryItem>(Options.MaximumHistoryCount);
895-
_recentHistory = new HistoryQueue<string>(capacity: 5);
898+
_history = new RingBuffer<HistoryItem>(Options.MaximumHistoryCount);
899+
_recentHistory = new RingBuffer<string>(capacity: 5);
896900
_currentHistoryIndex = 0;
897901

898902
bool readHistoryFile = true;

‎PSReadLine/Render.cs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ struct LineInfoForRendering
171171

172172
private ConsoleColor _initialForeground;
173173
private ConsoleColor _initialBackground;
174+
175+
// Current cursor position
174176
private int _current;
175177
private int _emphasisStart;
176178
private int _emphasisLength;
Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
--********************************************************************/
44

55
using System;
6-
using System.Collections.Generic;
76
using System.Diagnostics;
87
using System.Diagnostics.CodeAnalysis;
98

@@ -12,63 +11,41 @@ namespace Microsoft.PowerShell
1211
[ExcludeFromCodeCoverage]
1312
internal sealed class QueueDebugView<T>
1413
{
15-
private readonly HistoryQueue<T> _queue;
14+
private readonly RingBuffer<T> _queue;
1615

1716
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
1817
public T[] Items => this._queue.ToArray();
1918

20-
public QueueDebugView(HistoryQueue<T> queue)
19+
public QueueDebugView(RingBuffer<T> queue)
2120
{
2221
this._queue = queue ?? throw new ArgumentNullException(nameof(queue));
2322
}
2423
}
2524

2625
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
2726
[DebuggerTypeProxy(typeof(QueueDebugView<>))]
28-
internal class HistoryQueue<T>
27+
internal class RingBuffer<T>
2928
{
3029
private readonly T[] _array;
3130
private int _head;
3231
private int _tail;
3332

34-
public HistoryQueue(int capacity)
33+
public int Capacity => _array.Length;
34+
public int Count { get; private set; }
35+
36+
public RingBuffer(int capacity)
3537
{
36-
Debug.Assert(capacity > 0);
38+
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(capacity, 0);
3739
_array = new T[capacity];
3840
_head = _tail = Count = 0;
3941
}
4042

4143
public void Clear()
4244
{
43-
for (int i = 0; i < Count; i++)
44-
{
45-
this[i] = default(T);
46-
}
45+
Array.Clear(_array);
4746
_head = _tail = Count = 0;
4847
}
4948

50-
public bool Contains(T item)
51-
{
52-
return IndexOf(item) != -1;
53-
}
54-
55-
public int Count { get; private set; }
56-
57-
public int IndexOf(T item)
58-
{
59-
// REVIEW: should we use case insensitive here?
60-
var eqComparer = EqualityComparer<T>.Default;
61-
for (int i = 0; i < Count; i++)
62-
{
63-
if (eqComparer.Equals(this[i], item))
64-
{
65-
return i;
66-
}
67-
}
68-
69-
return -1;
70-
}
71-
7249
public void Enqueue(T item)
7350
{
7451
if (Count == _array.Length)
@@ -82,10 +59,10 @@ public void Enqueue(T item)
8259

8360
public T Dequeue()
8461
{
85-
Debug.Assert(Count > 0);
62+
if (Count == 0) throw new InvalidOperationException("RingBuffer is empty");
8663

8764
T obj = _array[_head];
88-
_array[_head] = default(T);
65+
_array[_head] = default;
8966
_head = (_head + 1) % _array.Length;
9067
Count -= 1;
9168
return obj;
@@ -113,14 +90,10 @@ public T[] ToArray()
11390
public T this[int index]
11491
{
11592
get
116-
{
117-
Debug.Assert(index >= 0 && index < Count);
118-
return _array[(_head + index) % _array.Length];
119-
}
120-
set
12193
{
122-
Debug.Assert(index >= 0 && index < Count);
123-
_array[(_head + index) % _array.Length] = value;
94+
ArgumentOutOfRangeException.ThrowIfNegative(index);
95+
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count);
96+
return _array[(_head + index) % _array.Length];
12497
}
12598
}
12699
}

‎test/BasicEditingTest.cs‎

Lines changed: 6 additions & 0 deletions

0 commit comments

Comments
 (0)