diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index fe322d20a..9cc00a8bf 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -1260,6 +1260,13 @@ namespace Terminal.Gui { } } + /// + /// A clipboard implementation for Linux. + /// This implementation uses the xclip command to access the clipboard. + /// + /// + /// If xclip is not installed, this implementation will not work. + /// class CursesClipboard : ClipboardBase { public CursesClipboard () { @@ -1373,6 +1380,12 @@ namespace Terminal.Gui { } } + /// + /// A clipboard implementation for MacOSX. + /// This implementation uses the Mac clipboard API (via P/Invoke) to copy/paste. + /// The existance of the Mac pbcopy and pbpaste commands + /// is used to determine if copy/paste is supported. + /// class MacOSXClipboard : ClipboardBase { IntPtr nsString = objc_getClass ("NSString"); IntPtr nsPasteboard = objc_getClass ("NSPasteboard"); @@ -1447,6 +1460,12 @@ namespace Terminal.Gui { static extern IntPtr sel_registerName (string selectorName); } + /// + /// A clipboard implementation for Linux, when running under WSL. + /// This implementation uses the Windows clipboard to store the data, and uses Windows' + /// powershell.exe (launched via WSL interop services) to set/get the Windows + /// clipboard. + /// class WSLClipboard : ClipboardBase { public WSLClipboard () { @@ -1460,9 +1479,10 @@ namespace Terminal.Gui { bool CheckSupport () { if (string.IsNullOrEmpty (powershellCommand)) { - var (exitCode, result) = BashRunner.Run ("which pwsh"); + // Specify pwsh.exe (not pwsh) to ensure we get the Windows version (invoked via WSL) + var (exitCode, result) = BashRunner.Run ("which pwsh.exe"); if (exitCode > 0) { - (exitCode, result) = BashRunner.Run ("which powershell"); + (exitCode, result) = BashRunner.Run ("which powershell.exe"); } if (exitCode == 0) { @@ -1536,18 +1556,6 @@ namespace Terminal.Gui { Curses.noecho (); } } - - //using (var clipExe = new System.Diagnostics.Process { - // StartInfo = new System.Diagnostics.ProcessStartInfo { - // FileName = "clip.exe", - // RedirectStandardInput = true - // } - //}) { - // clipExe.Start (); - // clipExe.StandardInput.Write (text); - // clipExe.StandardInput.Close (); - // clipExe.WaitForExit (); - //} } } } diff --git a/Terminal.Gui/Core/Clipboard/Clipboard.cs b/Terminal.Gui/Core/Clipboard/Clipboard.cs index 4570bba5e..a260ef8e9 100644 --- a/Terminal.Gui/Core/Clipboard/Clipboard.cs +++ b/Terminal.Gui/Core/Clipboard/Clipboard.cs @@ -3,8 +3,27 @@ using System; namespace Terminal.Gui { /// - /// Provides cut, copy, and paste support for the clipboard with OS interaction. + /// Provides cut, copy, and paste support for the OS clipboard. /// + /// + /// + /// On Windows, the class uses the Windows Clipboard APIs via P/Invoke. + /// + /// + /// On Linux, when not running under Windows Subsystem for Linux (WSL), + /// the class uses the xclip command line tool. If xclip is not installed, + /// the clipboard will not work. + /// + /// + /// On Linux, when running under Windows Subsystem for Linux (WSL), + /// the class launches Windows' powershell.exe via WSL interop and uses the + /// "Set-Clipboard" and "Get-Clipboard" Powershell CmdLets. + /// + /// + /// On the Mac, the class uses the MacO OS X pbcopy and pbpaste command line tools + /// and the Mac clipboard APIs vai P/Invoke. + /// + /// public static class Clipboard { static ustring contents; @@ -25,7 +44,10 @@ namespace Terminal.Gui { } set { try { - if (IsSupported && value != null) { + if (IsSupported) { + if (value == null) { + value = string.Empty; + } Application.Driver.Clipboard.SetClipboardData (value.ToString ()); } contents = value; @@ -40,32 +62,37 @@ namespace Terminal.Gui { /// /// Returns true if the environmental dependencies are in place to interact with the OS clipboard. /// + /// + /// The first time IsSupported is called, it will spawn a process (e.g. "bash xclip" or "powershell.exe" + /// to determine if the clipboard is supported byt the OS platform. This is a one-time cost. + /// public static bool IsSupported { get => Application.Driver.Clipboard.IsSupported; } /// - /// Gets the operation system clipboard if possible. + /// Copies the contents of the OS clipboard to if possible. /// - /// Clipboard contents read - /// true if it was possible to read the OS clipboard. + /// The contents of the OS clipboard if successful, if not. + /// the OS clipboard was retrieved, otherwise. public static bool TryGetClipboardData (out string result) { - if (Application.Driver.Clipboard.TryGetClipboardData (out result)) { + if (IsSupported && Application.Driver.Clipboard.TryGetClipboardData (out result)) { if (contents != result) { contents = result; } return true; } + result = string.Empty; return false; } /// - /// Sets the operation system clipboard if possible. + /// Pastes the to the OS clipboard if possible. /// - /// - /// True if the clipboard content was set successfully. + /// The text to paste to the OS clipboard. + /// the OS clipboard was set, otherwise. public static bool TrySetClipboardData (string text) { - if (Application.Driver.Clipboard.TrySetClipboardData (text)) { + if (IsSupported && Application.Driver.Clipboard.TrySetClipboardData (text)) { contents = text; return true; } diff --git a/UnitTests/ClipboardTests.cs b/UnitTests/ClipboardTests.cs index d8d242e56..6ba45d76e 100644 --- a/UnitTests/ClipboardTests.cs +++ b/UnitTests/ClipboardTests.cs @@ -120,7 +120,8 @@ namespace Terminal.Gui.ConsoleDrivers { } else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) { if (Is_WSL_Platform ()) { try { - RunClipboardProcess ("pwsh", $"-noprofile -command \"Set-Clipboard -Value \\\"{clipText}\\\"\""); + // This runs the WINDOWS version of powershell.exe via WSL. + RunClipboardProcess ("powershell.exe", $"-noprofile -command \"Set-Clipboard -Value \\\"{clipText}\\\"\""); } catch { failed = true; }