mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-02 01:03:29 +01:00
Fixes #4243 - ConsoleDriverFacade.CreateClipboard now honors FakeDriver.FakeBehaviors.UseFakeClipboard (#4244)
* updatd ConsoleDriverFacade.CreateClipboard to honor FakeDriver.FakeBehaviors.UseFakeClipboard * Code cleanup of fake driver v2
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
#nullable enable
|
||||
namespace Terminal.Gui.App;
|
||||
|
||||
/// <summary>Provides cut, copy, and paste support for the OS clipboard.</summary>
|
||||
@@ -20,10 +19,10 @@ namespace Terminal.Gui.App;
|
||||
/// </remarks>
|
||||
public static class Clipboard
|
||||
{
|
||||
private static string _contents = string.Empty;
|
||||
private static string? _contents = string.Empty;
|
||||
|
||||
/// <summary>Gets (copies from) or sets (pastes to) the contents of the OS clipboard.</summary>
|
||||
public static string Contents
|
||||
public static string? Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -31,13 +30,8 @@ public static class Clipboard
|
||||
{
|
||||
if (IsSupported)
|
||||
{
|
||||
string clipData = Application.Driver?.Clipboard.GetClipboardData ();
|
||||
|
||||
if (clipData is null)
|
||||
{
|
||||
// throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty");
|
||||
clipData = string.Empty;
|
||||
}
|
||||
// throw new InvalidOperationException ($"{Application.Driver?.GetType ().Name}.GetClipboardData returned null instead of string.Empty");
|
||||
string? clipData = Application.Driver?.Clipboard?.GetClipboardData () ?? string.Empty;
|
||||
|
||||
_contents = clipData;
|
||||
}
|
||||
@@ -55,12 +49,9 @@ public static class Clipboard
|
||||
{
|
||||
if (IsSupported)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
value = string.Empty;
|
||||
}
|
||||
value ??= string.Empty;
|
||||
|
||||
Application.Driver?.Clipboard.SetClipboardData (value);
|
||||
Application.Driver?.Clipboard?.SetClipboardData (value);
|
||||
}
|
||||
|
||||
_contents = value;
|
||||
@@ -74,126 +65,5 @@ public static class Clipboard
|
||||
|
||||
/// <summary>Returns true if the environmental dependencies are in place to interact with the OS clipboard.</summary>
|
||||
/// <remarks></remarks>
|
||||
public static bool IsSupported => Application.Driver?.Clipboard.IsSupported ?? false;
|
||||
|
||||
/// <summary>Copies the _contents of the OS clipboard to <paramref name="result"/> if possible.</summary>
|
||||
/// <param name="result">The _contents of the OS clipboard if successful, <see cref="string.Empty"/> if not.</param>
|
||||
/// <returns><see langword="true"/> the OS clipboard was retrieved, <see langword="false"/> otherwise.</returns>
|
||||
public static bool TryGetClipboardData (out string result)
|
||||
{
|
||||
if (IsSupported && Application.Driver!.Clipboard.TryGetClipboardData (out result))
|
||||
{
|
||||
_contents = result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
result = string.Empty;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Pastes the <paramref name="text"/> to the OS clipboard if possible.</summary>
|
||||
/// <param name="text">The text to paste to the OS clipboard.</param>
|
||||
/// <returns><see langword="true"/> the OS clipboard was set, <see langword="false"/> otherwise.</returns>
|
||||
public static bool TrySetClipboardData (string text)
|
||||
{
|
||||
if (IsSupported && Application.Driver!.Clipboard.TrySetClipboardData (text))
|
||||
{
|
||||
_contents = text;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for console drivers to invoke shell commands to interact with the clipboard. Used primarily by
|
||||
/// CursesDriver, but also used in Unit tests which is why it is in IConsoleDriver.cs.
|
||||
/// </summary>
|
||||
internal static class ClipboardProcessRunner
|
||||
{
|
||||
public static (int exitCode, string result) Bash (
|
||||
string commandLine,
|
||||
string inputText = "",
|
||||
bool waitForOutput = false
|
||||
)
|
||||
{
|
||||
var arguments = $"-c \"{commandLine}\"";
|
||||
(int exitCode, string result) = Process ("bash", arguments, inputText, waitForOutput);
|
||||
|
||||
return (exitCode, result.TrimEnd ());
|
||||
}
|
||||
|
||||
public static bool DoubleWaitForExit (this Process process)
|
||||
{
|
||||
bool result = process.WaitForExit (500);
|
||||
|
||||
if (result)
|
||||
{
|
||||
process.WaitForExit ();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool FileExists (this string value) { return !string.IsNullOrEmpty (value) && !value.Contains ("not found"); }
|
||||
|
||||
public static (int exitCode, string result) Process (
|
||||
string cmd,
|
||||
string arguments,
|
||||
string input = null,
|
||||
bool waitForOutput = true
|
||||
)
|
||||
{
|
||||
var output = string.Empty;
|
||||
|
||||
using (var process = new Process
|
||||
{
|
||||
StartInfo = new()
|
||||
{
|
||||
FileName = cmd,
|
||||
Arguments = arguments,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
})
|
||||
{
|
||||
TaskCompletionSource<bool> eventHandled = new ();
|
||||
process.Start ();
|
||||
|
||||
if (!string.IsNullOrEmpty (input))
|
||||
{
|
||||
process.StandardInput.Write (input);
|
||||
process.StandardInput.Close ();
|
||||
}
|
||||
|
||||
if (!process.WaitForExit (5000))
|
||||
{
|
||||
var timeoutError =
|
||||
$@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
|
||||
|
||||
throw new TimeoutException (timeoutError);
|
||||
}
|
||||
|
||||
if (waitForOutput && process.StandardOutput.Peek () != -1)
|
||||
{
|
||||
output = process.StandardOutput.ReadToEnd ();
|
||||
}
|
||||
|
||||
if (process.ExitCode > 0)
|
||||
{
|
||||
output = $@"Process failed to run. Command line: {cmd} {arguments}.
|
||||
Output: {output}
|
||||
Error: {process.StandardError.ReadToEnd ()}";
|
||||
}
|
||||
|
||||
return (process.ExitCode, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static bool IsSupported => Application.Driver?.Clipboard?.IsSupported ?? false;
|
||||
}
|
||||
79
Terminal.Gui/App/Clipboard/ClipboardProcessRunner.cs
Normal file
79
Terminal.Gui/App/Clipboard/ClipboardProcessRunner.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
#nullable enable
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Terminal.Gui.App;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for console drivers to invoke shell commands to interact with the clipboard. Used primarily by
|
||||
/// CursesDriver, but also used in Unit tests which is why it is in IConsoleDriver.cs.
|
||||
/// </summary>
|
||||
internal static class ClipboardProcessRunner
|
||||
{
|
||||
public static (int exitCode, string result) Bash (
|
||||
string commandLine,
|
||||
string inputText = "",
|
||||
bool waitForOutput = false
|
||||
)
|
||||
{
|
||||
var arguments = $"-c \"{commandLine}\"";
|
||||
(int exitCode, string result) = Process ("bash", arguments, inputText, waitForOutput);
|
||||
|
||||
return (exitCode, result.TrimEnd ());
|
||||
}
|
||||
|
||||
public static bool FileExists (this string value) { return !string.IsNullOrEmpty (value) && !value.Contains ("not found"); }
|
||||
|
||||
public static (int exitCode, string result) Process (
|
||||
string cmd,
|
||||
string arguments,
|
||||
string? input = null,
|
||||
bool waitForOutput = true
|
||||
)
|
||||
{
|
||||
var output = string.Empty;
|
||||
|
||||
using var process = new Process ();
|
||||
|
||||
process.StartInfo = new()
|
||||
{
|
||||
FileName = cmd,
|
||||
Arguments = arguments,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
TaskCompletionSource<bool> eventHandled = new ();
|
||||
process.Start ();
|
||||
|
||||
if (!string.IsNullOrEmpty (input))
|
||||
{
|
||||
process.StandardInput.Write (input);
|
||||
process.StandardInput.Close ();
|
||||
}
|
||||
|
||||
if (!process.WaitForExit (5000))
|
||||
{
|
||||
var timeoutError =
|
||||
$@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
|
||||
|
||||
throw new TimeoutException (timeoutError);
|
||||
}
|
||||
|
||||
if (waitForOutput && process.StandardOutput.Peek () != -1)
|
||||
{
|
||||
output = process.StandardOutput.ReadToEnd ();
|
||||
}
|
||||
|
||||
if (process.ExitCode > 0)
|
||||
{
|
||||
output = $@"Process failed to run. Command line: {cmd} {arguments}.
|
||||
Output: {output}
|
||||
Error: {process.StandardError.ReadToEnd ()}";
|
||||
}
|
||||
|
||||
return (process.ExitCode, output);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
//
|
||||
#nullable enable
|
||||
//
|
||||
// FakeDriver.cs: A fake IConsoleDriver for unit tests.
|
||||
//
|
||||
|
||||
@@ -36,7 +37,7 @@ public class FakeDriver : ConsoleDriver
|
||||
public bool UseFakeClipboard { get; internal set; }
|
||||
}
|
||||
|
||||
public static Behaviors FakeBehaviors = new ();
|
||||
public static Behaviors FakeBehaviors { get; } = new ();
|
||||
public override bool SupportsTrueColor => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -47,8 +48,8 @@ public class FakeDriver : ConsoleDriver
|
||||
|
||||
public FakeDriver ()
|
||||
{
|
||||
Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
|
||||
Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
|
||||
base.Cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
|
||||
base.Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
|
||||
|
||||
if (FakeBehaviors.UseFakeClipboard)
|
||||
{
|
||||
@@ -87,7 +88,7 @@ public class FakeDriver : ConsoleDriver
|
||||
FakeConsole.Clear ();
|
||||
}
|
||||
|
||||
private FakeMainLoop _mainLoopDriver;
|
||||
private FakeMainLoop? _mainLoopDriver;
|
||||
|
||||
public override MainLoop Init ()
|
||||
{
|
||||
@@ -124,7 +125,7 @@ public class FakeDriver : ConsoleDriver
|
||||
|
||||
for (int row = top; row < rows; row++)
|
||||
{
|
||||
if (!_dirtyLines [row])
|
||||
if (!_dirtyLines! [row])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -144,7 +145,7 @@ public class FakeDriver : ConsoleDriver
|
||||
|
||||
for (; col < cols; col++)
|
||||
{
|
||||
if (!Contents [row, col].IsDirty)
|
||||
if (!Contents! [row, col].IsDirty)
|
||||
{
|
||||
if (output.Length > 0)
|
||||
{
|
||||
@@ -168,7 +169,7 @@ public class FakeDriver : ConsoleDriver
|
||||
lastCol = col;
|
||||
}
|
||||
|
||||
Attribute attr = Contents [row, col].Attribute.Value;
|
||||
Attribute attr = Contents [row, col].Attribute!.Value;
|
||||
|
||||
// Performance: Only send the escape sequence if the attribute has changed.
|
||||
if (attr != redrawAttr)
|
||||
@@ -209,18 +210,18 @@ public class FakeDriver : ConsoleDriver
|
||||
|
||||
//SetCursorVisibility (savedVisibility);
|
||||
|
||||
void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int outputWidth)
|
||||
void WriteToConsole (StringBuilder outputSb, ref int lastColumn, int row, ref int outputWidth)
|
||||
{
|
||||
FakeConsole.CursorTop = row;
|
||||
FakeConsole.CursorLeft = lastCol;
|
||||
FakeConsole.CursorLeft = lastColumn;
|
||||
|
||||
foreach (char c in output.ToString ())
|
||||
foreach (char c in outputSb.ToString ())
|
||||
{
|
||||
FakeConsole.Write (c);
|
||||
}
|
||||
|
||||
output.Clear ();
|
||||
lastCol += outputWidth;
|
||||
outputSb.Clear ();
|
||||
lastColumn += outputWidth;
|
||||
outputWidth = 0;
|
||||
}
|
||||
|
||||
@@ -506,7 +507,7 @@ public class FakeDriver : ConsoleDriver
|
||||
|
||||
public class FakeClipboard : ClipboardBase
|
||||
{
|
||||
public Exception FakeException;
|
||||
public Exception? FakeException { get; set; }
|
||||
|
||||
private readonly bool _isSupportedAlwaysFalse;
|
||||
private string _contents = string.Empty;
|
||||
@@ -536,19 +537,14 @@ public class FakeDriver : ConsoleDriver
|
||||
return _contents;
|
||||
}
|
||||
|
||||
protected override void SetClipboardDataImpl (string text)
|
||||
protected override void SetClipboardDataImpl (string? text)
|
||||
{
|
||||
if (text is null)
|
||||
{
|
||||
throw new ArgumentNullException (nameof (text));
|
||||
}
|
||||
|
||||
if (FakeException is { })
|
||||
{
|
||||
throw FakeException;
|
||||
}
|
||||
|
||||
_contents = text;
|
||||
_contents = text ?? throw new ArgumentNullException (nameof (text));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.Logging;
|
||||
#nullable enable
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
@@ -11,7 +11,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
private CursorVisibility _lastCursor = CursorVisibility.Default;
|
||||
|
||||
/// <summary>The event fired when the terminal is resized.</summary>
|
||||
public event EventHandler<SizeChangedEventArgs> SizeChanged;
|
||||
public event EventHandler<SizeChangedEventArgs>? SizeChanged;
|
||||
|
||||
public IInputProcessor InputProcessor { get; }
|
||||
public IOutputBuffer OutputBuffer => _outputBuffer;
|
||||
@@ -48,6 +48,13 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
|
||||
private void CreateClipboard ()
|
||||
{
|
||||
if (FakeDriver.FakeBehaviors.UseFakeClipboard)
|
||||
{
|
||||
Clipboard = new FakeDriver.FakeClipboard ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PlatformID p = Environment.OSVersion.Platform;
|
||||
|
||||
if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows)
|
||||
@@ -88,7 +95,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
/// to.
|
||||
/// </summary>
|
||||
/// <value>The rectangle describing the of <see cref="Clip"/> region.</value>
|
||||
public Region Clip
|
||||
public Region? Clip
|
||||
{
|
||||
get => _outputBuffer.Clip;
|
||||
set => _outputBuffer.Clip = value;
|
||||
@@ -114,7 +121,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
/// The contents of the application output. The driver outputs this buffer to the terminal.
|
||||
/// <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
|
||||
/// </summary>
|
||||
public Cell [,] Contents
|
||||
public Cell [,]? Contents
|
||||
{
|
||||
get => _outputBuffer.Contents;
|
||||
set => _outputBuffer.Contents = value;
|
||||
@@ -229,7 +236,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
/// <summary>
|
||||
/// Raised each time <see cref="ConsoleDriver.ClearContents"/> is called. For benchmarking.
|
||||
/// </summary>
|
||||
public event EventHandler<EventArgs> ClearedContents;
|
||||
public event EventHandler<EventArgs>? ClearedContents;
|
||||
|
||||
/// <summary>
|
||||
/// Fills the specified rectangle with the specified rune, using <see cref="ConsoleDriver.CurrentAttribute"/>
|
||||
@@ -397,7 +404,7 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
}
|
||||
|
||||
/// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="ConsoleDriver.KeyUp"/>.</summary>
|
||||
public event EventHandler<Key> KeyDown;
|
||||
public event EventHandler<Key>? KeyDown;
|
||||
|
||||
/// <summary>Event fired when a key is released.</summary>
|
||||
/// <remarks>
|
||||
@@ -405,10 +412,10 @@ internal class ConsoleDriverFacade<T> : IConsoleDriver, IConsoleDriverFacade
|
||||
/// processing is
|
||||
/// complete.
|
||||
/// </remarks>
|
||||
public event EventHandler<Key> KeyUp;
|
||||
public event EventHandler<Key>? KeyUp;
|
||||
|
||||
/// <summary>Event fired when a mouse event occurs.</summary>
|
||||
public event EventHandler<MouseEventArgs> MouseEvent;
|
||||
public event EventHandler<MouseEventArgs>? MouseEvent;
|
||||
|
||||
/// <summary>Simulates a key press.</summary>
|
||||
/// <param name="keyChar">The key character.</param>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace Terminal.Gui.Drivers;
|
||||
#nullable enable
|
||||
namespace Terminal.Gui.Drivers;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for v2 driver abstraction layer
|
||||
|
||||
@@ -12,7 +12,7 @@ public interface IOutputBuffer
|
||||
/// <summary>
|
||||
/// The contents of the application output. The driver outputs this buffer to the terminal when UpdateScreen is called.
|
||||
/// </summary>
|
||||
Cell [,] Contents { get; set; }
|
||||
Cell [,]? Contents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject
|
||||
|
||||
Reference in New Issue
Block a user