From 597ab9b8f90502d713c0d0d1b7538db5cf65daeb Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 16 Jul 2019 15:07:09 -0700 Subject: [PATCH 1/2] Fix one variant of the OutOfRange exception --- PSReadLine/Render.cs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/PSReadLine/Render.cs b/PSReadLine/Render.cs index 125abe648..61e78e7f1 100644 --- a/PSReadLine/Render.cs +++ b/PSReadLine/Render.cs @@ -378,13 +378,22 @@ void UpdateColorsIfNecessary(string newColor) // promptBufferCells is the number of visible characters in the prompt var promptBufferCells = LengthInBufferCells(promptText); - _console.CursorLeft -= promptBufferCells; - var color = renderData.errorPrompt ? _options._errorColor : defaultColor; - if (renderData.errorPrompt && promptBufferCells != promptText.Length) - promptText = promptText.Substring(promptText.Length - promptBufferCells); - UpdateColorsIfNecessary(color); - _console.Write(promptText); - _console.Write("\x1b[0m"); + + // The 'CursorLeft' could be less than error-prompt-cell-length when + // 1. console buffer was resized, which causes the initial cursor to appear on the next line; + // 2. prompt string gets longer (e.g. by 'cd' into nested folders), which causes the line to be wrapped to the next line; + // 3. the prompt function was changed, which causes the new prompt string is shorter than the error prompt. + // when this happens, we skip changing the color of the prompt. + if (_console.CursorLeft >= promptBufferCells) + { + _console.CursorLeft -= promptBufferCells; + var color = renderData.errorPrompt ? _options._errorColor : defaultColor; + if (renderData.errorPrompt && promptBufferCells != promptText.Length) + promptText = promptText.Substring(promptText.Length - promptBufferCells); + UpdateColorsIfNecessary(color); + _console.Write(promptText); + _console.Write("\x1b[0m"); + } } } From bae155642d7cc6f0876d237ec8fbc86b8af4892e Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 19 Jul 2019 14:45:57 -0700 Subject: [PATCH 2/2] Wrap to the previous line to update the error prompt --- PSReadLine/Render.cs | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/PSReadLine/Render.cs b/PSReadLine/Render.cs index 61e78e7f1..df6c9e9ad 100644 --- a/PSReadLine/Render.cs +++ b/PSReadLine/Render.cs @@ -377,16 +377,38 @@ void UpdateColorsIfNecessary(string newColor) // We need to update the prompt // promptBufferCells is the number of visible characters in the prompt - var promptBufferCells = LengthInBufferCells(promptText); + int promptBufferCells = LengthInBufferCells(promptText); + bool renderErrorPrompt = false; - // The 'CursorLeft' could be less than error-prompt-cell-length when - // 1. console buffer was resized, which causes the initial cursor to appear on the next line; - // 2. prompt string gets longer (e.g. by 'cd' into nested folders), which causes the line to be wrapped to the next line; - // 3. the prompt function was changed, which causes the new prompt string is shorter than the error prompt. - // when this happens, we skip changing the color of the prompt. if (_console.CursorLeft >= promptBufferCells) { + renderErrorPrompt = true; _console.CursorLeft -= promptBufferCells; + } + else + { + // The 'CursorLeft' could be less than error-prompt-cell-length in one of the following 3 cases: + // 1. console buffer was resized, which causes the initial cursor to appear on the next line; + // 2. prompt string gets longer (e.g. by 'cd' into nested folders), which causes the line to be wrapped to the next line; + // 3. the prompt function was changed, which causes the new prompt string is shorter than the error prompt. + // Here, we always assume it's the case 1 or 2, and wrap back to the previous line to change the error prompt color. + // In case of case 3, the rendering would be off, but it's more of a user error because the prompt is changed without + // updating 'PromptText' with 'Set-PSReadLineOption'. + + int diffs = promptBufferCells - _console.CursorLeft; + int newX = bufferWidth - diffs % bufferWidth; + int newY = _initialY - diffs / bufferWidth - 1; + + // newY could be less than 0 if 'PromptText' is manually set to be a long string. + if (newY >= 0) + { + renderErrorPrompt = true; + _console.SetCursorPosition(newX, newY); + } + } + + if (renderErrorPrompt) + { var color = renderData.errorPrompt ? _options._errorColor : defaultColor; if (renderData.errorPrompt && promptBufferCells != promptText.Length) promptText = promptText.Substring(promptText.Length - promptBufferCells);