-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix the 'ArgumentOutOfRangeException' caused by top of the text being scrolled up-off the buffer #979
Conversation
- Update 'ReallyRender' to avoid writing everything every time when editing the text. Instead, we find the first different logical line, and starting writing from there. - Support editing text even if the top of the text has been scrolled up-off the buffer. - Disallow cursor to be set to a position that is off the buffer. - Fix a bug in 'ConvertLineAndColumnToOffset' so that a point can be translated to the offset correctly.
@lzybkr The PR is ready for review. Please take a look when you have time. Thanks! |
For some reason, I had to add this to build on my dev machine:
|
I haven't looked closely at the changes, but I'll try the changes out for awhile and see if I notice any issues. The first two things I've noticed:
These two issues might make it annoying for some people to undo, e.g. some Emacs users will use Ctrl+aCtrl+k to delete the whole line. |
Weird. I don't need that line and the CI builds fine ... But I can add |
Can you be more specific about the those two things?
Yes please. I'm dogfooding my changes. You trying out it will definitely help to find issues. |
|
Thanks @lzybkr, I can repro the Shift+Home issue. I will look into it. For the second issue, it's by design. As you mentioned, PSReadLine is not designed for editing files, at least not yet. It's not perfect, but the experience is much better than before this change. |
I can't load PSReadLine in Windows PowerShell anymore, I'm not sure if it's from the PR or a previous one though. |
…at has been scrolled up-off the buffer
The rendering issue when shift-selecting text that had been scrolled up-off the buffer has been fixed.
Did you build targeting |
I used the binary built in CI (AppVeyor). |
I guess you didn't |
Thanks for the hints, locally I did build the wrong target, and I did forget to unblock the file from AppVeyor. |
@lzybkr Any feedback after using |
I've tested this PR just briefly. Noticed a couple small things, they may or not be related to this PR:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed I started a review but didn't finish it. I'm on vacation and will finish when I return.
{ | ||
// This could happen when adding a new line in the end of the very last line. | ||
// In this case, we scroll up by writing out a new line. | ||
_console.SetCursorPosition(left: bufferWidth - 1, top: bufferHeight - 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the method name, I thought this method would be side effect free, so moving the cursor is surprising.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. It's not just calculation, but also set the cursor to the about-to-start-rendering
position.
How about rename the method to PrepareToRender
?
PSReadLine/Render.cs
Outdated
// then it's possible we are facing this special case and thus would need to do additional checks later. | ||
|
||
minLineLength = renderLines.Length; | ||
if (cursorX == Options.ContinuationPrompt.Length && cursorY == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I understand this check, but couldn't it be true by luck, e.g. you have a short prompt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the cursorY > _initialY
check above, this won't happen, because of the cursorY == 0
check here implies _initialY < 0
, meaning that this won't be the first physical line where the user prompt is at.
Now that the cursorY > _initialY
check is removed, we need to check for _initialY < 0
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This piece of code has been changed, to cover the more general scenarios -- after editing, the cursor is supposed to be moved off the buffer.
Please take another look.
PSReadLine/Render.cs
Outdated
// newY could be less than 0 if 'PromptText' is manually set to be a long string. | ||
if (newY >= 0) | ||
// Additional check for the special case mentioned above: the cursor is supposed to be moved to the previous line. | ||
if (ConvertOffsetToPoint(_current).Y == -1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code feels wrong, but I'm not sure how precisely to address your concerns.
At any rate, in testing this out, you can get an exception if you delete multiple characters such that -1
is the wrong value, e.g. have a few blank lines at the start, get to this line of code, then type Alt+4Backspace to delete 4 characters at once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for spotting the issue. I didn't know about the key binding to delete arbitrary number of characters. This changes the assumption of the code. I will rework the related part of the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This issue has been addressed, the logic is changed to cover the more general scenarios where the cursor is supposed to be moved to a position that is off the buffer after the editing.
In the following screenshot, the Hello world
line and the following 3 empty lines are moved off the buffer, and then Alt+4Backspace works as expected.
However, as you might noticed, I removed the last empty line before moving the cursor to <0, 0>
position. This is because if I don't remove the last line, Alt+4 scroll up the buffer to show the digit-argument:
line, and will move the cursor one line above. In this case, the cursor will be moved to <0, -1>
, and thus causes an exception.
This is not a problem introduced by this change. See the following screenshot with the beta.4
PSReadLine:
if (isFirstLogicalLine) | ||
// The editing was in the first logical line. We have to write everything in this case. | ||
// Move the cursor to the initial position if we haven't done so. | ||
if (_initialY < 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this condition makes some logical sense, it should be documented on the field and all references to the field should be checked and tested to verify a negative value is safe because I don't think it could have happened before this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will go through all the uses of _initialY
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will take some time to go through all uses of _initialY
and verify those uses when _initialY
is negative. I would like to do this in follow-up PRs. I opened #1015 to track this work.
because I don't think it could have happened before this PR.
This happens before this PR, but the code never handles this situation properly and that's causing the ArgumentOutOfRangeException
issues.
_console.Write("\x1b[2J"); | ||
_console.SetCursorPosition(0, _console.WindowTop); | ||
|
||
string newPrompt = GetPrompt(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've mostly duplicated InvokePrompt
, at least the bit starting with this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InvokePrompt
calls back to ReallyRender
. I don't want that here.
PSReadLine/Render.cs
Outdated
@@ -28,6 +28,13 @@ public override string ToString() | |||
|
|||
public partial class PSConsoleReadLine | |||
{ | |||
struct RenderedLineInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This struct is really just the return value of CalculateWhereAndWhatToRender
, but you return 2 of them. Maybe you should merge them into 1 struct instead and give it a better name (it's too similar to RenderedLineData
anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Use one struct to hold both the current and previous line info. Rename the struct to be LineInfoForRendering
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the updated code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay. The PR has been updated.
@msftrncs Thanks for playing with the changes! To reply to your comments:
The buffer of integrated terminal in VSCode doesn't work like the console host on windows. Anything scrolled off the screen is out of the buffer. You can check the
This behavior already exists today, without this PR. Can you please open an issue, if there isn't one already?
This behavior already exists today. I personally don't think this is an issue though. |
I noticed something else now, playing, (no exceptions yet) if one resizes the console window while editing (really just viewing) a multiline history, things get out of sync. In this case I had a previous multiline item up, larger than the window, sitting the end, and made the window full screen. The text doesn't change, but then switching the history, between other multiline items, draws the items without clear the previous content. Then with a multiline history item back in the screen, restore the window size to normal, the item is now too long, but only the last 8 lines are shown at the top of the screen, and moving through the history at this point is now unusable as the screen is all out of sync. |
@msftclas Yes, this is because of the optimization to not redraw the whole buffer if possible. Those 2 history entries have the exactly the same first N logical lines, and thus the rendering starting from the N+1 logical line. |
@lzybkr Could you please take another look when you have time? Thanks! |
Major change includes:
ReallyRender
to avoid writing everything every time when editing the text. Instead, we find the first different logical line, and starting writing from there.ReallyRender
by moving some logic to separate methods.ConvertLineAndColumnToOffset
so that a point can be translated to the offset correctly.Note: I would like to add some more tests, but not yet clear what tests to add.
Edit long text in small buffer console (66 x 17, Windows)
Copy long text to small buffer console (66 x 17, Windows)
Function
Get-IniContent
copied from https://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91Copy long text in Ubuntu terminal
Function
Get-IniContent
copied from https://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91Edit long text in Ubuntu terminal