Skip to content

Remove uses of CSI # S / ScrollConsoleScreenBuffer #790

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

Merged
merged 2 commits into from
Nov 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion PSReadLine/BasicEditing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ private bool AcceptLineImpl(bool validate)
}

var point = ConvertOffsetToPoint(_current);
PlaceCursor(0, point.Y + 1);
_console.SetCursorPosition(point.X, point.Y);
_console.Write("\n");
_inputAccepted = true;
return true;
}
Expand Down
1 change: 0 additions & 1 deletion PSReadLine/ConsoleLib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ public Encoding OutputEncoding
public void SetCursorPosition(int left, int top) => Console.SetCursorPosition(left, top);
public virtual void Write(string value) => Console.Write(value);
public virtual void WriteLine(string value) => Console.WriteLine(value);
public virtual void ScrollBuffer(int lines) => Console.Write("\x1b[" + lines + "S");
public virtual void BlankRestOfLine() => Console.Write("\x1b[K");
}
}
11 changes: 7 additions & 4 deletions PSReadLine/KeyBindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,8 @@ public static void ShowKeyBindings(ConsoleKeyInfo? key = null, object arg = null

// Don't overwrite any of the line - so move to first line after the end of our buffer.
var point = _singleton.ConvertOffsetToPoint(_singleton._buffer.Length);
_singleton.PlaceCursor(0, point.Y + 1);
console.SetCursorPosition(point.X, point.Y);
console.Write("\n");

console.WriteLine(buffer.ToString());
InvokePrompt(key: null, arg: _singleton._console.CursorTop);
Expand Down Expand Up @@ -677,12 +678,14 @@ public static void WhatIsKey(ConsoleKeyInfo? key = null, object arg = null)

_singleton.ClearStatusMessage(render: false);

var console = _singleton._console;
// Don't overwrite any of the line - so move to first line after the end of our buffer.
var point = _singleton.ConvertOffsetToPoint(_singleton._buffer.Length);
_singleton.PlaceCursor(0, point.Y + 1);
console.SetCursorPosition(point.X, point.Y);
console.Write("\n");

_singleton._console.WriteLine(buffer.ToString());
InvokePrompt(key: null, arg: _singleton._console.CursorTop);
console.WriteLine(buffer.ToString());
InvokePrompt(key: null, arg: console.CursorTop);
}
}
}
14 changes: 2 additions & 12 deletions PSReadLine/Movement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,18 +394,8 @@ public static void GotoBrace(ConsoleKeyInfo? key = null, object arg = null)
public static void ClearScreen(ConsoleKeyInfo? key = null, object arg = null)
{
var console = _singleton._console;
int newY = _singleton._initialY - _singleton.Options.ExtraPromptLineCount;
if (newY + console.WindowHeight > console.BufferHeight)
{
var scrollCount = newY - console.WindowTop;
console.ScrollBuffer(scrollCount);
_singleton._initialY -= scrollCount;
console.SetCursorPosition(console.CursorLeft, console.CursorTop - scrollCount);
}
else
{
console.SetWindowPosition(0, newY);
}
console.Write("\x1b[2J");
InvokePrompt(null, console.WindowTop);
}

// Try to convert the arg to a char, return 0 for failure
Expand Down
77 changes: 38 additions & 39 deletions PSReadLine/PlatformWindows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.PowerShell;
using Microsoft.PowerShell.Internal;
Expand Down Expand Up @@ -414,6 +415,7 @@ internal class LegacyWin32Console : VirtualTerminal
{
private static ConsoleColor InitialFG = Console.ForegroundColor;
private static ConsoleColor InitialBG = Console.BackgroundColor;
private static int maxTop = 0;

private static readonly Dictionary<int, Action> VTColorAction = new Dictionary<int, Action> {
{40, () => Console.BackgroundColor = ConsoleColor.Black},
Expand Down Expand Up @@ -463,7 +465,12 @@ private void WriteHelper(string s, bool line)
// The shortest pattern is 4 characters, <ESC>[0m
if (s[i] != '\x1b' || (i + 3) >= s.Length || s[i + 1] != '[') continue;

Console.Write(s.Substring(from, i - from));
var prefix = s.Substring(from, i - from);
if (prefix.Length > 0)
{
Console.Write(prefix);
maxTop = Console.CursorTop;
}
from = i;

Action action1 = null;
Expand Down Expand Up @@ -492,6 +499,23 @@ private void WriteHelper(string s, bool line)
done = true;
goto case ';';

case 'J':
// We'll only support entire display for ED (Erase in Display)
if (color == 2) {
var cursorVisible = Console.CursorVisible;
var left = Console.CursorLeft;
var toScroll = maxTop - Console.WindowTop + 1;
Console.CursorVisible = false;
Console.SetCursorPosition(0, Console.WindowTop + Console.WindowHeight - 1);
for (int k = 0; k < toScroll; k++)
{
Console.WriteLine();
}
Console.SetCursorPosition(left, Console.WindowTop + toScroll - 1);
Console.CursorVisible = cursorVisible;
}
break;

case ';':
if (VTColorAction.TryGetValue(color, out var action))
{
Expand Down Expand Up @@ -525,8 +549,19 @@ private void WriteHelper(string s, bool line)
}

var tailSegment = s.Substring(from);
if (line) Console.WriteLine(tailSegment);
else Console.Write(tailSegment);
if (line)
{
Console.WriteLine(tailSegment);
maxTop = Console.CursorTop;
}
else
{
Console.Write(tailSegment);
if (tailSegment.Length > 0)
{
maxTop = Console.CursorTop;
}
}
}

public override void Write(string s)
Expand All @@ -539,20 +574,6 @@ public override void WriteLine(string s)
WriteHelper(s, true);
}

public struct SMALL_RECT
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}

internal struct COORD
{
public short X;
public short Y;
}

public struct CHAR_INFO
{
public ushort UnicodeChar;
Expand All @@ -564,28 +585,6 @@ public CHAR_INFO(char c, ConsoleColor foreground, ConsoleColor background)
}
}

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ScrollConsoleScreenBuffer(IntPtr hConsoleOutput,
ref SMALL_RECT lpScrollRectangle,
IntPtr lpClipRectangle,
COORD dwDestinationOrigin,
ref CHAR_INFO lpFill);

public override void ScrollBuffer(int lines)
{
var handle = GetStdHandle((uint) StandardHandleId.Output);
var scrollRectangle = new SMALL_RECT
{
Top = (short) lines,
Left = 0,
Bottom = (short)(Console.BufferHeight - 1),
Right = (short)Console.BufferWidth
};
var destinationOrigin = new COORD {X = 0, Y = 0};
var fillChar = new CHAR_INFO(' ', Console.ForegroundColor, Console.BackgroundColor);
ScrollConsoleScreenBuffer(handle, ref scrollRectangle, IntPtr.Zero, destinationOrigin, ref fillChar);
}

public override int CursorSize
{
get => IsConsoleApiAvailable(input: false, output: true) ? Console.CursorSize : _unixCursorSize;
Expand Down
1 change: 0 additions & 1 deletion PSReadLine/PublicAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public interface IConsole
void SetCursorPosition(int left, int top);
void WriteLine(string s);
void Write(string s);
void ScrollBuffer(int lines);
void BlankRestOfLine();
}

Expand Down
6 changes: 0 additions & 6 deletions PSReadLine/ReadLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -955,12 +955,6 @@ public static void InvokePrompt(ConsoleKeyInfo? key = null, object arg = null)

if (arg is int newY)
{
if (newY >= console.BufferHeight)
{
var toScroll = newY - console.BufferHeight + 1;
console.ScrollBuffer(toScroll);
newY -= toScroll;
}
console.SetCursorPosition(0, newY);
}
else
Expand Down
21 changes: 5 additions & 16 deletions PSReadLine/Render.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
Expand Down Expand Up @@ -51,6 +52,7 @@ class RenderData
};
private int _initialX;
private int _initialY;

private ConsoleColor _initialForeground;
private ConsoleColor _initialBackground;
private int _current;
Expand Down Expand Up @@ -363,7 +365,7 @@ void UpdateColorsIfNecessary(string newColor)

// Move the cursor to where we started, but make cursor invisible while we're rendering.
_console.CursorVisible = false;
PlaceCursor(_initialX, _initialY);
_console.SetCursorPosition(_initialX, _initialY);

// Possibly need to flip the color on the prompt if the error state changed.
var promptText = _options.PromptText;
Expand Down Expand Up @@ -512,7 +514,7 @@ int PhysicalLineCount(int columns, bool isFirstLogicalLine, out int lenLastPhysi
}

var point = ConvertOffsetToPoint(_current);
PlaceCursor(point.X, point.Y);
_console.SetCursorPosition(point.X, point.Y);
_console.CursorVisible = true;

// TODO: set WindowTop if necessary
Expand Down Expand Up @@ -661,19 +663,6 @@ private void RecomputeInitialCoords()
}
}

private void PlaceCursor(int x, int y)
{
int statusLineCount = GetStatusLineCount();
if ((y + statusLineCount) >= _console.BufferHeight)
{
var scrollCount = y + statusLineCount - _console.BufferHeight + 1;
_console.ScrollBuffer(scrollCount);
_initialY -= scrollCount;
y -= scrollCount;
}
_console.SetCursorPosition(x, y);
}

private void MoveCursor(int newCursor)
{
// In case the buffer was resized
Expand All @@ -682,7 +671,7 @@ private void MoveCursor(int newCursor)
_previousRender.bufferHeight = _console.BufferHeight;

var point = ConvertOffsetToPoint(newCursor);
PlaceCursor(point.X, point.Y);
_console.SetCursorPosition(point.X, point.Y);
_current = newCursor;
}

Expand Down
6 changes: 0 additions & 6 deletions PSReadLine/ScreenCapture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,6 @@ internal static void WriteBufferLines(CHAR_INFO[] buffer, int top, IConsole cons

int bufferWidth = Console.BufferWidth;
int bufferLineCount = buffer.Length / bufferWidth;
if ((top + bufferLineCount) > Console.BufferHeight)
{
var scrollCount = (top + bufferLineCount) - Console.BufferHeight;
console.ScrollBuffer(scrollCount);
top -= scrollCount;
}
var bufferSize = new COORD
{
X = (short) bufferWidth,
Expand Down
47 changes: 23 additions & 24 deletions TestPSReadLine/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ static void CauseCrash(ConsoleKeyInfo? key = null, object arg = null)
static void Main()
{
var handle = GetStdHandle((uint)StandardHandleId.Output);
uint mode;
GetConsoleMode(handle, out mode);
var b = SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
GetConsoleMode(handle, out var mode);
var vtEnabled = SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);

var iss = InitialSessionState.CreateDefault2();
var rs = RunspaceFactory.CreateRunspace(iss);
Expand All @@ -51,33 +50,33 @@ static void Main()
EditMode = EditMode.Emacs,
HistoryNoDuplicates = false,
});
var options = PSConsoleReadLine.GetOptions();
options.CommandColor = "#8181f7";
options.StringColor = "\x1b[38;5;100m";
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+LeftArrow"}, PSConsoleReadLine.ShellBackwardWord, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+RightArrow"}, PSConsoleReadLine.ShellNextWord, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F4"}, PSConsoleReadLine.HistorySearchBackward, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F5"}, PSConsoleReadLine.HistorySearchForward, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+C"}, PSConsoleReadLine.CaptureScreen, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+P"}, PSConsoleReadLine.InvokePrompt, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+D,Ctrl+X"}, CauseCrash, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F6"}, PSConsoleReadLine.PreviousLine, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F7"}, PSConsoleReadLine.NextLine, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F2"}, PSConsoleReadLine.ValidateAndAcceptLine, "", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Enter"}, PSConsoleReadLine.AcceptLine, "", "");


EngineIntrinsics executionContext;

if (vtEnabled)
{
var options = PSConsoleReadLine.GetOptions();
options.CommandColor = "#8181f7";
options.StringColor = "\x1b[38;5;100m";
}
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+LeftArrow"}, PSConsoleReadLine.ShellBackwardWord, "ShellBackwardWord", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+RightArrow"}, PSConsoleReadLine.ShellNextWord, "ShellNextWord", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F4"}, PSConsoleReadLine.HistorySearchBackward, "HistorySearchBackward", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F5"}, PSConsoleReadLine.HistorySearchForward, "HistorySearchForward", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+d,Ctrl+c"}, PSConsoleReadLine.CaptureScreen, "CaptureScreen", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+d,Ctrl+p"}, PSConsoleReadLine.InvokePrompt, "InvokePrompt", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Ctrl+d,Ctrl+x"}, CauseCrash, "CauseCrash", "Throw exception to test error handling");
PSConsoleReadLine.SetKeyHandler(new[] {"F6"}, PSConsoleReadLine.PreviousLine, "PreviousLine", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F7"}, PSConsoleReadLine.NextLine, "NextLine", "");
PSConsoleReadLine.SetKeyHandler(new[] {"F2"}, PSConsoleReadLine.ValidateAndAcceptLine, "ValidateAndAcceptLine", "");
PSConsoleReadLine.SetKeyHandler(new[] {"Enter"}, PSConsoleReadLine.AcceptLine, "AcceptLine", "");

using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
executionContext =
ps.AddScript("$ExecutionContext").Invoke<EngineIntrinsics>().FirstOrDefault();
var executionContext = ps.AddScript("$ExecutionContext").Invoke<EngineIntrinsics>().First();

// Detect if the read loop will enter VT input mode.
var vtInputEnvVar = Environment.GetEnvironmentVariable("PSREADLINE_VTINPUT");
var stdin = GetStdHandle((uint)StandardHandleId.Input);
uint inputMode;
GetConsoleMode(stdin, out inputMode);
GetConsoleMode(stdin, out var inputMode);
if (vtInputEnvVar == "1" || (inputMode & ENABLE_VIRTUAL_TERMINAL_INPUT) != 0)
{
Console.WriteLine("\x1b[33mDefault input mode = virtual terminal\x1b[m");
Expand Down
3 changes: 2 additions & 1 deletion test/CompletionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public void PossibleCompletions()
ps.AddScript($@"function prompt {{ ""{promptLine1}`n{promptLine2}"" }}");
ps.Invoke();
}
PSConsoleReadLine.SetOptions(new SetPSReadLineOption {ExtraPromptLineCount = 1});

_console.Clear();
Test("psvar", Keys(
Expand All @@ -108,7 +109,7 @@ public void PossibleCompletions()

using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
ps.AddCommand("Remove-Item").AddArgument("prompt");
ps.AddCommand("Remove-Item").AddArgument("function:prompt");
ps.Invoke();
}

Expand Down
Loading