From 48d2c3291937f1a2411daada450949cb2ccd884d Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 29 May 2018 20:45:45 -0700 Subject: [PATCH 1/2] fix rendering where large content is pasted to console that is wider than console and also causes the screen buffer to scroll --- PSReadLine/Render.cs | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/PSReadLine/Render.cs b/PSReadLine/Render.cs index 791c2046..6efb69a4 100644 --- a/PSReadLine/Render.cs +++ b/PSReadLine/Render.cs @@ -427,15 +427,42 @@ int PhysicalLineCount(int columns, bool isFirstLogicalLine, out int lenLastPhysi var logicalLine = 0; var physicalLine = 0; var lenPrevLastLine = 0; + var suppressTopLineIfScrolled = true; for (; logicalLine < renderLines.Length; logicalLine++) { if (logicalLine != 0) _console.Write("\n"); var lineData = renderLines[logicalLine]; - _console.Write(lineData.line); + var physicalLineCount = PhysicalLineCount(lineData.columns, logicalLine == 0, out var lenLastLine); - physicalLine += PhysicalLineCount(lineData.columns, logicalLine == 0, out var lenLastLine); + // If the initial position was scrolled off the screen, only output for lines still + // in the screen buffer + if (_initialY + physicalLine >= 0) + { + // First time redrawing from the top + if (_initialY < 0 && suppressTopLineIfScrolled) + { + suppressTopLineIfScrolled = false; + // Handle case where top of screen buffer is a partial line + if (_console.CursorTop != 0 && _initialY + physicalLine != physicalLineCount) + { + var linesToSkip = _initialY + physicalLine; + PlaceCursor(0, linesToSkip); + } + } + _console.Write(lineData.line); + } + + physicalLine += physicalLineCount; + + // On non-Windows, if the last line fills the width exactly, it doesn't automatically scroll, so we + // need to decrement the count to make sure the y location is correct next time + if (_console.CursorTop == _console.BufferHeight - 1 && lineData.columns % _console.BufferWidth == 0) + { + physicalLine--; + previousPhysicalLine--; + } // Find the previous logical line (if any) that would have rendered // the current physical line because we may need to clear it. @@ -671,6 +698,12 @@ private void PlaceCursor(int x, int y) _initialY -= scrollCount; y -= scrollCount; } + + // y can be less than the screen buffer when a more text than the height of the buffer is pasted at once + if (y < 0) + { + y = 0; + } _console.SetCursorPosition(x, y); } From 4aebcddc21defa96aaff532b10a0a7aad7f3a8e9 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Wed, 31 Oct 2018 13:55:30 -0700 Subject: [PATCH 2/2] address feedback --- PSReadLine/Render.cs | 7 +++++-- test/KillYankTest.cs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/PSReadLine/Render.cs b/PSReadLine/Render.cs index 6efb69a4..ac487338 100644 --- a/PSReadLine/Render.cs +++ b/PSReadLine/Render.cs @@ -50,6 +50,9 @@ class RenderData lines = new[] { new RenderedLineData{ columns = 0, line = ""}} }; private int _initialX; + + // This represents the initial Y position of the cursor. If this position has scrolled off screen, this value will be negative indicating + // the number of lines off screen. private int _initialY; private ConsoleColor _initialForeground; private ConsoleColor _initialBackground; @@ -436,8 +439,8 @@ int PhysicalLineCount(int columns, bool isFirstLogicalLine, out int lenLastPhysi var lineData = renderLines[logicalLine]; var physicalLineCount = PhysicalLineCount(lineData.columns, logicalLine == 0, out var lenLastLine); - // If the initial position was scrolled off the screen, only output for lines still - // in the screen buffer + // If the initial position was scrolled off the screen, _initialY will be negative. + // Only output for lines still in the screen buffer. if (_initialY + physicalLine >= 0) { // First time redrawing from the top diff --git a/test/KillYankTest.cs b/test/KillYankTest.cs index 548c4d42..d64a6472 100644 --- a/test/KillYankTest.cs +++ b/test/KillYankTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Windows; using Microsoft.PowerShell; using Xunit; @@ -313,6 +314,23 @@ public void Paste() "echo foobar", _.CtrlShiftLeftArrow, _.CtrlV)); } + [Fact] + public void PasteLarge() + { + TestSetup(KeyMode.Cmd); + + StringBuilder text = new StringBuilder(); + text.Append("@{"); + for (int i = 0; i < _console.BufferHeight + 10; i++) + { + text.Append(string.Format("prop{0}={0}", i)); + } + text.Append("}"); + + Clipboard.SetText(text.ToString()); + Test(text.ToString(), Keys(_.CtrlV)); + } + [Fact] public void Cut() {