Skip to content

Commit fd9af03

Browse files
authored
Fix ArgumentOutOfRangeException thrown when changing color of the error prompt (#967)
1 parent 527fa6a commit fd9af03

File tree

1 file changed

+39
-8
lines changed

1 file changed

+39
-8
lines changed

PSReadLine/Render.cs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,14 +377,45 @@ void UpdateColorsIfNecessary(string newColor)
377377
// We need to update the prompt
378378

379379
// promptBufferCells is the number of visible characters in the prompt
380-
var promptBufferCells = LengthInBufferCells(promptText);
381-
_console.CursorLeft -= promptBufferCells;
382-
var color = renderData.errorPrompt ? _options._errorColor : defaultColor;
383-
if (renderData.errorPrompt && promptBufferCells != promptText.Length)
384-
promptText = promptText.Substring(promptText.Length - promptBufferCells);
385-
UpdateColorsIfNecessary(color);
386-
_console.Write(promptText);
387-
_console.Write("\x1b[0m");
380+
int promptBufferCells = LengthInBufferCells(promptText);
381+
bool renderErrorPrompt = false;
382+
383+
if (_console.CursorLeft >= promptBufferCells)
384+
{
385+
renderErrorPrompt = true;
386+
_console.CursorLeft -= promptBufferCells;
387+
}
388+
else
389+
{
390+
// The 'CursorLeft' could be less than error-prompt-cell-length in one of the following 3 cases:
391+
// 1. console buffer was resized, which causes the initial cursor to appear on the next line;
392+
// 2. prompt string gets longer (e.g. by 'cd' into nested folders), which causes the line to be wrapped to the next line;
393+
// 3. the prompt function was changed, which causes the new prompt string is shorter than the error prompt.
394+
// Here, we always assume it's the case 1 or 2, and wrap back to the previous line to change the error prompt color.
395+
// In case of case 3, the rendering would be off, but it's more of a user error because the prompt is changed without
396+
// updating 'PromptText' with 'Set-PSReadLineOption'.
397+
398+
int diffs = promptBufferCells - _console.CursorLeft;
399+
int newX = bufferWidth - diffs % bufferWidth;
400+
int newY = _initialY - diffs / bufferWidth - 1;
401+
402+
// newY could be less than 0 if 'PromptText' is manually set to be a long string.
403+
if (newY >= 0)
404+
{
405+
renderErrorPrompt = true;
406+
_console.SetCursorPosition(newX, newY);
407+
}
408+
}
409+
410+
if (renderErrorPrompt)
411+
{
412+
var color = renderData.errorPrompt ? _options._errorColor : defaultColor;
413+
if (renderData.errorPrompt && promptBufferCells != promptText.Length)
414+
promptText = promptText.Substring(promptText.Length - promptBufferCells);
415+
UpdateColorsIfNecessary(color);
416+
_console.Write(promptText);
417+
_console.Write("\x1b[0m");
418+
}
388419
}
389420
}
390421

0 commit comments

Comments
 (0)