Skip to content

Commit 18b602e

Browse files
authored
Fixes #4243 - ConsoleDriverFacade.CreateClipboard now honors FakeDriver.FakeBehaviors.UseFakeClipboard (#4244)
* updatd ConsoleDriverFacade.CreateClipboard to honor FakeDriver.FakeBehaviors.UseFakeClipboard * Code cleanup of fake driver v2
1 parent e869f84 commit 18b602e

File tree

15 files changed

+292
-331
lines changed

15 files changed

+292
-331
lines changed
Lines changed: 9 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Diagnostics;
2-
1+
#nullable enable
32
namespace Terminal.Gui.App;
43

54
/// <summary>Provides cut, copy, and paste support for the OS clipboard.</summary>
@@ -20,24 +19,19 @@ namespace Terminal.Gui.App;
2019
/// </remarks>
2120
public static class Clipboard
2221
{
23-
private static string _contents = string.Empty;
22+
private static string? _contents = string.Empty;
2423

2524
/// <summary>Gets (copies from) or sets (pastes to) the contents of the OS clipboard.</summary>
26-
public static string Contents
25+
public static string? Contents
2726
{
2827
get
2928
{
3029
try
3130
{
3231
if (IsSupported)
3332
{
34-
string clipData = Application.Driver?.Clipboard.GetClipboardData ();
35-
36-
if (clipData is null)
37-
{
38-
// throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty");
39-
clipData = string.Empty;
40-
}
33+
// throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty");
34+
string? clipData = Application.Driver?.Clipboard?.GetClipboardData () ?? string.Empty;
4135

4236
_contents = clipData;
4337
}
@@ -55,12 +49,9 @@ public static string Contents
5549
{
5650
if (IsSupported)
5751
{
58-
if (value is null)
59-
{
60-
value = string.Empty;
61-
}
52+
value ??= string.Empty;
6253

63-
Application.Driver?.Clipboard.SetClipboardData (value);
54+
Application.Driver?.Clipboard?.SetClipboardData (value);
6455
}
6556

6657
_contents = value;
@@ -74,126 +65,5 @@ public static string Contents
7465

7566
/// <summary>Returns true if the environmental dependencies are in place to interact with the OS clipboard.</summary>
7667
/// <remarks></remarks>
77-
public static bool IsSupported => Application.Driver?.Clipboard.IsSupported ?? false;
78-
79-
/// <summary>Copies the _contents of the OS clipboard to <paramref name="result"/> if possible.</summary>
80-
/// <param name="result">The _contents of the OS clipboard if successful, <see cref="string.Empty"/> if not.</param>
81-
/// <returns><see langword="true"/> the OS clipboard was retrieved, <see langword="false"/> otherwise.</returns>
82-
public static bool TryGetClipboardData (out string result)
83-
{
84-
if (IsSupported && Application.Driver!.Clipboard.TryGetClipboardData (out result))
85-
{
86-
_contents = result;
87-
88-
return true;
89-
}
90-
91-
result = string.Empty;
92-
93-
return false;
94-
}
95-
96-
/// <summary>Pastes the <paramref name="text"/> to the OS clipboard if possible.</summary>
97-
/// <param name="text">The text to paste to the OS clipboard.</param>
98-
/// <returns><see langword="true"/> the OS clipboard was set, <see langword="false"/> otherwise.</returns>
99-
public static bool TrySetClipboardData (string text)
100-
{
101-
if (IsSupported && Application.Driver!.Clipboard.TrySetClipboardData (text))
102-
{
103-
_contents = text;
104-
105-
return true;
106-
}
107-
108-
return false;
109-
}
110-
}
111-
112-
/// <summary>
113-
/// Helper class for console drivers to invoke shell commands to interact with the clipboard. Used primarily by
114-
/// CursesDriver, but also used in Unit tests which is why it is in IConsoleDriver.cs.
115-
/// </summary>
116-
internal static class ClipboardProcessRunner
117-
{
118-
public static (int exitCode, string result) Bash (
119-
string commandLine,
120-
string inputText = "",
121-
bool waitForOutput = false
122-
)
123-
{
124-
var arguments = $"-c \"{commandLine}\"";
125-
(int exitCode, string result) = Process ("bash", arguments, inputText, waitForOutput);
126-
127-
return (exitCode, result.TrimEnd ());
128-
}
129-
130-
public static bool DoubleWaitForExit (this Process process)
131-
{
132-
bool result = process.WaitForExit (500);
133-
134-
if (result)
135-
{
136-
process.WaitForExit ();
137-
}
138-
139-
return result;
140-
}
141-
142-
public static bool FileExists (this string value) { return !string.IsNullOrEmpty (value) && !value.Contains ("not found"); }
143-
144-
public static (int exitCode, string result) Process (
145-
string cmd,
146-
string arguments,
147-
string input = null,
148-
bool waitForOutput = true
149-
)
150-
{
151-
var output = string.Empty;
152-
153-
using (var process = new Process
154-
{
155-
StartInfo = new()
156-
{
157-
FileName = cmd,
158-
Arguments = arguments,
159-
RedirectStandardOutput = true,
160-
RedirectStandardError = true,
161-
RedirectStandardInput = true,
162-
UseShellExecute = false,
163-
CreateNoWindow = true
164-
}
165-
})
166-
{
167-
TaskCompletionSource<bool> eventHandled = new ();
168-
process.Start ();
169-
170-
if (!string.IsNullOrEmpty (input))
171-
{
172-
process.StandardInput.Write (input);
173-
process.StandardInput.Close ();
174-
}
175-
176-
if (!process.WaitForExit (5000))
177-
{
178-
var timeoutError =
179-
$@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
180-
181-
throw new TimeoutException (timeoutError);
182-
}
183-
184-
if (waitForOutput && process.StandardOutput.Peek () != -1)
185-
{
186-
output = process.StandardOutput.ReadToEnd ();
187-
}
188-
189-
if (process.ExitCode > 0)
190-
{
191-
output = $@"Process failed to run. Command line: {cmd} {arguments}.
192-
Output: {output}
193-
Error: {process.StandardError.ReadToEnd ()}";
194-
}
195-
196-
return (process.ExitCode, output);
197-
}
198-
}
199-
}
68+
public static bool IsSupported => Application.Driver?.Clipboard?.IsSupported ?? false;
69+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#nullable enable
2+
using System.Diagnostics;
3+
4+
namespace Terminal.Gui.App;
5+
6+
/// <summary>
7+
/// Helper class for console drivers to invoke shell commands to interact with the clipboard. Used primarily by
8+
/// CursesDriver, but also used in Unit tests which is why it is in IConsoleDriver.cs.
9+
/// </summary>
10+
internal static class ClipboardProcessRunner
11+
{
12+
public static (int exitCode, string result) Bash (
13+
string commandLine,
14+
string inputText = "",
15+
bool waitForOutput = false
16+
)
17+
{
18+
var arguments = $"-c \"{commandLine}\"";
19+
(int exitCode, string result) = Process ("bash", arguments, inputText, waitForOutput);
20+
21+
return (exitCode, result.TrimEnd ());
22+
}
23+
24+
public static bool FileExists (this string value) { return !string.IsNullOrEmpty (value) && !value.Contains ("not found"); }
25+
26+
public static (int exitCode, string result) Process (
27+
string cmd,
28+
string arguments,
29+
string? input = null,
30+
bool waitForOutput = true
31+
)
32+
{
33+
var output = string.Empty;
34+
35+
using var process = new Process ();
36+
37+
process.StartInfo = new()
38+
{
39+
FileName = cmd,
40+
Arguments = arguments,
41+
RedirectStandardOutput = true,
42+
RedirectStandardError = true,
43+
RedirectStandardInput = true,
44+
UseShellExecute = false,
45+
CreateNoWindow = true
46+
};
47+
48+
TaskCompletionSource<bool> eventHandled = new ();
49+
process.Start ();
50+
51+
if (!string.IsNullOrEmpty (input))
52+
{
53+
process.StandardInput.Write (input);
54+
process.StandardInput.Close ();
55+
}
56+
57+
if (!process.WaitForExit (5000))
58+
{
59+
var timeoutError =
60+
$@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
61+
62+
throw new TimeoutException (timeoutError);
63+
}
64+
65+
if (waitForOutput && process.StandardOutput.Peek () != -1)
66+
{
67+
output = process.StandardOutput.ReadToEnd ();
68+
}
69+
70+
if (process.ExitCode > 0)
71+
{
72+
output = $@"Process failed to run. Command line: {cmd} {arguments}.
73+
Output: {output}
74+
Error: {process.StandardError.ReadToEnd ()}";
75+
}
76+
77+
return (process.ExitCode, output);
78+
}
79+
}

Terminal.Gui/Drivers/FakeDriver/FakeDriver.cs

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//
1+
#nullable enable
2+
//
23
// FakeDriver.cs: A fake IConsoleDriver for unit tests.
34
//
45

@@ -36,7 +37,7 @@ public Behaviors (
3637
public bool UseFakeClipboard { get; internal set; }
3738
}
3839

39-
public static Behaviors FakeBehaviors = new ();
40+
public static Behaviors FakeBehaviors { get; } = new ();
4041
public override bool SupportsTrueColor => false;
4142

4243
/// <inheritdoc />
@@ -47,8 +48,8 @@ public override void WriteRaw (string ansi)
4748

4849
public FakeDriver ()
4950
{
50-
Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
51-
Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
51+
base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
52+
base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
5253

5354
if (FakeBehaviors.UseFakeClipboard)
5455
{
@@ -87,7 +88,7 @@ public override void End ()
8788
FakeConsole.Clear ();
8889
}
8990

90-
private FakeMainLoop _mainLoopDriver;
91+
private FakeMainLoop? _mainLoopDriver;
9192

9293
public override MainLoop Init ()
9394
{
@@ -124,7 +125,7 @@ public override bool UpdateScreen ()
124125

125126
for (int row = top; row < rows; row++)
126127
{
127-
if (!_dirtyLines [row])
128+
if (!_dirtyLines! [row])
128129
{
129130
continue;
130131
}
@@ -144,7 +145,7 @@ public override bool UpdateScreen ()
144145

145146
for (; col < cols; col++)
146147
{
147-
if (!Contents [row, col].IsDirty)
148+
if (!Contents! [row, col].IsDirty)
148149
{
149150
if (output.Length > 0)
150151
{
@@ -168,7 +169,7 @@ public override bool UpdateScreen ()
168169
lastCol = col;
169170
}
170171

171-
Attribute attr = Contents [row, col].Attribute.Value;
172+
Attribute attr = Contents [row, col].Attribute!.Value;
172173

173174
// Performance: Only send the escape sequence if the attribute has changed.
174175
if (attr != redrawAttr)
@@ -209,18 +210,18 @@ public override bool UpdateScreen ()
209210

210211
//SetCursorVisibility (savedVisibility);
211212

212-
void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int outputWidth)
213+
void WriteToConsole (StringBuilder outputSb, ref int lastColumn, int row, ref int outputWidth)
213214
{
214215
FakeConsole.CursorTop = row;
215-
FakeConsole.CursorLeft = lastCol;
216+
FakeConsole.CursorLeft = lastColumn;
216217

217-
foreach (char c in output.ToString ())
218+
foreach (char c in outputSb.ToString ())
218219
{
219220
FakeConsole.Write (c);
220221
}
221222

222-
output.Clear ();
223-
lastCol += outputWidth;
223+
outputSb.Clear ();
224+
lastColumn += outputWidth;
224225
outputWidth = 0;
225226
}
226227

@@ -506,7 +507,7 @@ public override void Suspend ()
506507

507508
public class FakeClipboard : ClipboardBase
508509
{
509-
public Exception FakeException;
510+
public Exception? FakeException { get; set; }
510511

511512
private readonly bool _isSupportedAlwaysFalse;
512513
private string _contents = string.Empty;
@@ -536,19 +537,14 @@ protected override string GetClipboardDataImpl ()
536537
return _contents;
537538
}
538539

539-
protected override void SetClipboardDataImpl (string text)
540+
protected override void SetClipboardDataImpl (string? text)
540541
{
541-
if (text is null)
542-
{
543-
throw new ArgumentNullException (nameof (text));
544-
}
545-
546542
if (FakeException is { })
547543
{
548544
throw FakeException;
549545
}
550546

551-
_contents = text;
547+
_contents = text ?? throw new ArgumentNullException (nameof (text));
552548
}
553549
}
554550

0 commit comments

Comments
 (0)