forked from PowerShell/PSReadLine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConsoleLib.cs
More file actions
156 lines (137 loc) · 6.04 KB
/
Copy pathConsoleLib.cs
File metadata and controls
156 lines (137 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Text;
namespace Microsoft.PowerShell.Internal
{
internal class VirtualTerminal : IConsole
{
// These two fields are used by PowerShellEditorServices to inject a
// custom ReadKey implementation. This is not a public API, but it is
// part of a private contract with that project.
#pragma warning disable CS0649
private static Func<bool, ConsoleKeyInfo> _readKeyOverride;
#pragma warning restore CS0649
private static Lazy<Func<bool, ConsoleKeyInfo>> _readKeyMethod = new Lazy<Func<bool, ConsoleKeyInfo>>(
() => _readKeyOverride == null ? Console.ReadKey : _readKeyOverride);
public int CursorLeft
{
get => Console.CursorLeft;
set => Console.CursorLeft = value;
}
public int CursorTop
{
get => Console.CursorTop;
set => Console.CursorTop = value;
}
// .NET doesn't fully implement this API on all platforms, so we fake it with a commonly supported escape sequence.
protected int _unixCursorSize = 25;
public virtual int CursorSize
{
get => PlatformWindows.IsConsoleApiAvailable(input: false, output: true) ? Console.CursorSize : _unixCursorSize;
set
{
if (PlatformWindows.IsConsoleApiAvailable(input: false, output: true))
{
Console.CursorSize = value;
}
else
{
_unixCursorSize = value;
}
// See the cursor ANSI codes at https://www.real-world-systems.com/docs/ANSIcode.html, searching for 'blinking block'.
// We write out the ANSI escape sequence even if we are on Windows, where the 'Console.CursorSize' API is supported by .NET.
// This is because this API works fine in console host, but not in Windows Terminal. The escape sequence will configure the
// cursor as expected in Windows Terminal, while in console host, the escape sequence works after it's written out, but then
// will be overwritten by 'CursorSize' when the user continues typing.
// We use blinking block and blinking underscore, so as to mimic the cursor size 100 and 25 in console host.
Write(value > 50 ? "\x1b[1 q" : "\x1b[3 q");
}
}
public bool CursorVisible
{
get => Console.CursorVisible;
set => Console.CursorVisible = value;
}
public int BufferWidth
{
get => Console.BufferWidth;
set => Console.BufferWidth = value;
}
public int BufferHeight
{
get => Console.BufferHeight;
set => Console.BufferHeight = value;
}
public int WindowWidth
{
get => Console.WindowWidth;
set => Console.WindowWidth = value;
}
public int WindowHeight
{
get => Console.WindowHeight;
set => Console.WindowHeight = value;
}
public int WindowTop
{
get => Console.WindowTop;
set => Console.WindowTop = value;
}
public ConsoleColor BackgroundColor
{
get => Console.BackgroundColor;
set => Console.BackgroundColor = value;
}
public ConsoleColor ForegroundColor
{
get => Console.ForegroundColor;
set => Console.ForegroundColor = value;
}
public Encoding OutputEncoding
{
// Catch and ignore exceptions - if we can't change the encoding, output is
// probably redirected, but it can also happen with the legacy console on Windows.
get { try { return Console.OutputEncoding; } catch { return Encoding.Default; } }
set { try { Console.OutputEncoding = value; } catch { } }
}
private static T _TryIgnoreIOE<T>(Func<T> f)
{
int triesLeft = 10;
while (true)
{
try
{
triesLeft--;
return f();
}
catch (InvalidOperationException)
{
// Ignore it. An IOE could be thrown if the "application does not have a
// console or when console input has been redirected"... but we don't
// expect PSReadLine to be involved in such a situation. So we are
// actually probably running into this Issue (wherein another process
// attached to the same console terminated at just the right/wrong time):
//
// https://github.com/dotnet/runtime/issues/88697
//
// In the event there is some *other* pathological situation
// happening, we have limited the number of times we will
// swallow/retry this exception/operation.
if (triesLeft <= 0)
{
throw;
}
}
}
}
public ConsoleKeyInfo ReadKey() => _TryIgnoreIOE(() => _readKeyMethod.Value(true));
public bool KeyAvailable => _TryIgnoreIOE(() => Console.KeyAvailable);
public void SetWindowPosition(int left, int top) => Console.SetWindowPosition(left, top);
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 BlankRestOfLine() => Console.Write("\x1b[K");
}
}