Skip to content
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

Adds "Clip Region" clipping to ConsoleDriver #2606

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b22c82a
Added ClipRegion; cleaned up driver code
tig May 7, 2023
31ba96c
clip region unit tests
tig May 7, 2023
90f368b
api docs
tig May 7, 2023
82b0bff
Moved color stuff from ConsoleDriver to Color.cs
tig May 8, 2023
953f4e6
Removes unused ConsoleDriver APIs
tig May 8, 2023
73a1b86
Code cleanup and Removes unused ConsoleDriver APIs
tig May 8, 2023
b688d8d
Code cleanup and Removes unused ConsoleDriver APIs
tig May 8, 2023
693c4ad
Work around https://github.com/gui-cs/Terminal.Gui/issues/2610
tig May 8, 2023
4658198
adjusted unit tests
tig May 8, 2023
5c79ba6
initial commit
tig May 8, 2023
066a9b9
Made Rows, Cols, Top, Left virtual
tig May 8, 2023
638e914
Made Clipboard non-virtual
tig May 8, 2023
b853af0
Made EnableConsoleScrolling non-virtual
tig May 8, 2023
6f365ef
Made Contents non-virtual
tig May 8, 2023
e173b79
Pulled Row/Col up
tig May 8, 2023
bc61b86
Made MoveTo virtual; fixed stupid FakeDriver cursor issue
tig May 8, 2023
93d81a1
Made CurrentAttribute non-virtual
tig May 8, 2023
af8a668
Made SetAttribute non-virtual
tig May 8, 2023
bf25b79
Moved clipboard code out
tig May 8, 2023
43e70ca
Code cleanup
tig May 8, 2023
0c0d434
Removes dependecy on NStack from ConsoleDrivers - WIP
tig May 9, 2023
1225e4b
Fixed unit tests
tig May 9, 2023
47f9cb8
Fixed unit tests
tig May 9, 2023
466a0c9
Added list of unit tests needed
tig May 9, 2023
679bfff
Did some perf testing; tweaked code and charmap to address
tig May 9, 2023
b4fa712
Brough in code from PR #2264 (but commented)
tig May 10, 2023
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
7 changes: 3 additions & 4 deletions Terminal.Gui/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Reflection;
using System.IO;
using System.Text.Json.Serialization;
using static Terminal.Gui.ConfigurationManager;

namespace Terminal.Gui {
/// <summary>
Expand Down Expand Up @@ -1087,7 +1086,7 @@ static void OnTerminalResized ()
{
var full = new Rect (0, 0, Driver.Cols, Driver.Rows);
TerminalResized?.Invoke (new ResizedEventArgs () { Cols = full.Width, Rows = full.Height });
Driver.Clip = full;
Driver.Clip = new Rect (0, 0, Driver.Cols, Driver.Rows);
foreach (var t in _toplevels) {
t.SetRelativeLayout (full);
t.LayoutSubviews ();
Expand Down Expand Up @@ -1149,7 +1148,7 @@ public static void GrabMouse (View view)
if (!OnGrabbingMouse (view)) {
OnGrabbedMouse (view);
_mouseGrabView = view;
Driver.UncookMouse ();
//Driver.UncookMouse ();
}
}

Expand All @@ -1163,7 +1162,7 @@ public static void UngrabMouse ()
if (!OnUnGrabbingMouse (_mouseGrabView)) {
OnUnGrabbedMouse (_mouseGrabView);
_mouseGrabView = null;
Driver.CookMouse ();
//Driver.CookMouse ();
}
}

Expand Down
234 changes: 153 additions & 81 deletions Terminal.Gui/Clipboard/Clipboard.cs
Original file line number Diff line number Diff line change
@@ -1,100 +1,172 @@
using NStack;
using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Terminal.Gui;

/// <summary>
/// Provides cut, copy, and paste support for the OS clipboard.
/// </summary>
/// <remarks>
/// <para>
/// On Windows, the <see cref="Clipboard"/> class uses the Windows Clipboard APIs via P/Invoke.
/// </para>
/// <para>
/// On Linux, when not running under Windows Subsystem for Linux (WSL),
/// the <see cref="Clipboard"/> class uses the xclip command line tool. If xclip is not installed,
/// the clipboard will not work.
/// </para>
/// <para>
/// On Linux, when running under Windows Subsystem for Linux (WSL),
/// the <see cref="Clipboard"/> class launches Windows' powershell.exe via WSL interop and uses the
/// "Set-Clipboard" and "Get-Clipboard" Powershell CmdLets.
/// </para>
/// <para>
/// On the Mac, the <see cref="Clipboard"/> class uses the MacO OS X pbcopy and pbpaste command line tools
/// and the Mac clipboard APIs vai P/Invoke.
/// </para>
/// </remarks>
public static class Clipboard {
static ustring contents;

namespace Terminal.Gui {
/// <summary>
/// Provides cut, copy, and paste support for the OS clipboard.
/// Gets (copies from) or sets (pastes to) the contents of the OS clipboard.
/// </summary>
/// <remarks>
/// <para>
/// On Windows, the <see cref="Clipboard"/> class uses the Windows Clipboard APIs via P/Invoke.
/// </para>
/// <para>
/// On Linux, when not running under Windows Subsystem for Linux (WSL),
/// the <see cref="Clipboard"/> class uses the xclip command line tool. If xclip is not installed,
/// the clipboard will not work.
/// </para>
/// <para>
/// On Linux, when running under Windows Subsystem for Linux (WSL),
/// the <see cref="Clipboard"/> class launches Windows' powershell.exe via WSL interop and uses the
/// "Set-Clipboard" and "Get-Clipboard" Powershell CmdLets.
/// </para>
/// <para>
/// On the Mac, the <see cref="Clipboard"/> class uses the MacO OS X pbcopy and pbpaste command line tools
/// and the Mac clipboard APIs vai P/Invoke.
/// </para>
/// </remarks>
public static class Clipboard {
static ustring contents;

/// <summary>
/// Gets (copies from) or sets (pastes to) the contents of the OS clipboard.
/// </summary>
public static ustring Contents {
get {
try {
if (IsSupported) {
return contents = ustring.Make (Application.Driver.Clipboard.GetClipboardData ());
} else {
return contents;
}
} catch (Exception) {
public static ustring Contents {
get {
try {
if (IsSupported) {
return contents = ustring.Make (Application.Driver.Clipboard.GetClipboardData ());
} else {
return contents;
}
} catch (Exception) {
return contents;
}
set {
try {
if (IsSupported) {
if (value == null) {
value = string.Empty;
}
Application.Driver.Clipboard.SetClipboardData (value.ToString ());
}
set {
try {
if (IsSupported) {
if (value == null) {
value = string.Empty;
}
contents = value;
} catch (NotSupportedException e) {
throw e;
} catch (Exception) {
contents = value;
Application.Driver.Clipboard.SetClipboardData (value.ToString ());
}
contents = value;
} catch (NotSupportedException e) {
throw e;
} catch (Exception) {
contents = value;
}
}
}

/// <summary>
/// Returns true if the environmental dependencies are in place to interact with the OS clipboard.
/// </summary>
/// <remarks>
/// </remarks>
public static bool IsSupported { get => Application.Driver.Clipboard.IsSupported; }

/// <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)) {
if (contents != result) {
contents = result;
}
return true;
/// <summary>
/// Returns true if the environmental dependencies are in place to interact with the OS clipboard.
/// </summary>
/// <remarks>
/// </remarks>
public static bool IsSupported { get => Application.Driver.Clipboard.IsSupported; }

/// <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)) {
if (contents != result) {
contents = result;
}
result = string.Empty;
return false;
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>
/// 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
/// ConsoleDriver.cs.
/// </summary>
internal static class ClipboardProcessRunner {
public static (int exitCode, string result) Bash (string commandLine, string inputText = "", bool waitForOutput = false)
{
var arguments = $"-c \"{commandLine}\"";
var (exitCode, result) = Process ("bash", arguments, inputText, waitForOutput);

return (exitCode, result.TrimEnd ());
}

public static (int exitCode, string result) Process (string cmd, string arguments, string input = null, bool waitForOutput = true)
{
var output = string.Empty;

using (Process process = new Process {
StartInfo = new ProcessStartInfo {
FileName = cmd,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
}) {
var eventHandled = new TaskCompletionSource<bool> ();
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 DoubleWaitForExit (this System.Diagnostics.Process process)
{
var 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");
}
}
4 changes: 0 additions & 4 deletions Terminal.Gui/Clipboard/IClipboard.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Terminal.Gui {
/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion Terminal.Gui/Configuration/ConfigurationManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
global using CM = Terminal.Gui.ConfigurationManager;
global using static Terminal.Gui.ConfigurationManager;
global using CM = Terminal.Gui.ConfigurationManager;

using System;
using System.Collections;
Expand Down
2 changes: 1 addition & 1 deletion Terminal.Gui/Configuration/ThemeScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class ThemeScope : Scope<ThemeScope> {
internal override bool Apply ()
{
var ret = base.Apply ();
Application.Driver?.InitalizeColorSchemes ();
Application.Driver?.InitializeColorSchemes ();
return ret;
}
}
Expand Down
Loading