Skip to content

Commit eb8cb44

Browse files
committedDec 31, 2022
misc changed done before I went on holiday
2 parents 3307e84 + 537c543 commit eb8cb44

17 files changed

+341
-135
lines changed
 

‎Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

-70
Original file line numberDiff line numberDiff line change
@@ -1329,76 +1329,6 @@ protected override void SetClipboardDataImpl (string text)
13291329
}
13301330
}
13311331

1332-
internal static class ClipboardProcessRunner {
1333-
public static (int exitCode, string result) Bash (string commandLine, string inputText = "", bool waitForOutput = false)
1334-
{
1335-
var arguments = $"-c \"{commandLine}\"";
1336-
var (exitCode, result) = Process ("bash", arguments, inputText, waitForOutput);
1337-
1338-
return (exitCode, result.TrimEnd ());
1339-
}
1340-
1341-
public static (int exitCode, string result) Process (string cmd, string arguments, string input = null, bool waitForOutput = true)
1342-
{
1343-
var output = string.Empty;
1344-
1345-
using (Process process = new Process {
1346-
StartInfo = new ProcessStartInfo {
1347-
FileName = cmd,
1348-
Arguments = arguments,
1349-
RedirectStandardOutput = true,
1350-
RedirectStandardError = true,
1351-
RedirectStandardInput = true,
1352-
UseShellExecute = false,
1353-
CreateNoWindow = true,
1354-
}
1355-
}) {
1356-
var eventHandled = new TaskCompletionSource<bool> ();
1357-
process.Start ();
1358-
if (!string.IsNullOrEmpty (input)) {
1359-
process.StandardInput.Write (input);
1360-
process.StandardInput.Close ();
1361-
}
1362-
1363-
if (!process.WaitForExit (5000)) {
1364-
var timeoutError = $@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
1365-
throw new TimeoutException (timeoutError);
1366-
}
1367-
1368-
if (waitForOutput && process.StandardOutput.Peek () != -1) {
1369-
output = process.StandardOutput.ReadToEnd ();
1370-
}
1371-
1372-
if (process.ExitCode > 0) {
1373-
output = $@"Process failed to run. Command line: {cmd} {arguments}.
1374-
Output: {output}
1375-
Error: {process.StandardError.ReadToEnd ()}";
1376-
}
1377-
if (Application.Driver is CursesDriver) {
1378-
Curses.raw ();
1379-
Curses.noecho ();
1380-
}
1381-
1382-
return (process.ExitCode, output);
1383-
}
1384-
}
1385-
1386-
public static bool DoubleWaitForExit (this System.Diagnostics.Process process)
1387-
{
1388-
var result = process.WaitForExit (500);
1389-
if (result) {
1390-
process.WaitForExit ();
1391-
}
1392-
return result;
1393-
}
1394-
1395-
public static bool FileExists (this string value)
1396-
{
1397-
return !string.IsNullOrEmpty (value) && !value.Contains ("not found");
1398-
}
1399-
}
1400-
1401-
14021332
/// <summary>
14031333
/// A clipboard implementation for MacOSX.
14041334
/// This implementation uses the Mac clipboard API (via P/Invoke) to copy/paste.

‎Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1401,7 +1401,10 @@ public static void Write (char value)
14011401
/// <param name="buffer"></param>
14021402
public static void Write (char [] buffer)
14031403
{
1404-
throw new NotImplementedException ();
1404+
_buffer [CursorLeft, CursorTop] = (char)0;
1405+
foreach (var ch in buffer) {
1406+
_buffer [CursorLeft, CursorTop] += ch;
1407+
}
14051408
}
14061409

14071410
//

‎Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,12 @@ public override void AddRune (Rune rune)
132132
needMove = false;
133133
}
134134
if (runeWidth < 2 && ccol > 0
135-
&& Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) {
135+
&& Rune.ColumnWidth ((Rune)contents [crow, ccol - 1, 0]) > 1) {
136136

137137
contents [crow, ccol - 1, 0] = (int)(uint)' ';
138138

139139
} else if (runeWidth < 2 && ccol <= Clip.Right - 1
140-
&& Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) {
140+
&& Rune.ColumnWidth ((Rune)contents [crow, ccol, 0]) > 1) {
141141

142142
contents [crow, ccol + 1, 0] = (int)(uint)' ';
143143
contents [crow, ccol + 1, 2] = 1;
@@ -262,7 +262,12 @@ public override void UpdateScreen ()
262262
if (color != redrawColor)
263263
SetColor (color);
264264

265-
FakeConsole.Write ((char)contents [row, col, 0]);
265+
Rune rune = contents [row, col, 0];
266+
if (Rune.DecodeSurrogatePair (rune, out char [] spair)) {
267+
FakeConsole.Write (spair);
268+
} else {
269+
FakeConsole.Write ((char)rune);
270+
}
266271
contents [row, col, 2] = 0;
267272
}
268273
}

‎Terminal.Gui/Core/ConsoleDriver.cs

+76-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
using NStack;
99
using System;
1010
using System.Collections.Generic;
11+
using System.Diagnostics;
1112
using System.Linq;
1213
using System.Runtime.CompilerServices;
14+
using System.Threading.Tasks;
15+
using Unix.Terminal;
1316

1417
namespace Terminal.Gui {
1518
/// <summary>
@@ -681,7 +684,7 @@ public abstract class ConsoleDriver {
681684
/// <param name="col">Column to move the cursor to.</param>
682685
/// <param name="row">Row to move the cursor to.</param>
683686
public abstract void Move (int col, int row);
684-
687+
685688
/// <summary>
686689
/// Adds the specified rune to the display at the current cursor position.
687690
/// </summary>
@@ -696,11 +699,10 @@ public abstract class ConsoleDriver {
696699
/// <returns></returns>
697700
public static Rune MakePrintable (Rune c)
698701
{
699-
var controlChars = c & 0xFFFF;
700-
if (controlChars <= 0x1F || controlChars >= 0X7F && controlChars <= 0x9F) {
702+
if (c <= 0x1F || (c >= 0X7F && c <= 0x9F)) {
701703
// ASCII (C0) control characters.
702704
// C1 control characters (https://www.aivosto.com/articles/control-characters.html#c1)
703-
return new Rune (controlChars + 0x2400);
705+
return new Rune (c + 0x2400);
704706
}
705707

706708
return c;
@@ -1390,4 +1392,74 @@ public void CreateColors (bool hasColors = true)
13901392
Colors.Error.Disabled = MakeColor (Color.DarkGray, Color.White);
13911393
}
13921394
}
1395+
1396+
/// <summary>
1397+
/// Helper class for console drivers to invoke shell commands to interact with the clipboard.
1398+
/// Used primarily by CursesDriver, but also used in Unit tests which is why it is in
1399+
/// ConsoleDriver.cs.
1400+
/// </summary>
1401+
internal static class ClipboardProcessRunner {
1402+
public static (int exitCode, string result) Bash (string commandLine, string inputText = "", bool waitForOutput = false)
1403+
{
1404+
var arguments = $"-c \"{commandLine}\"";
1405+
var (exitCode, result) = Process ("bash", arguments, inputText, waitForOutput);
1406+
1407+
return (exitCode, result.TrimEnd ());
1408+
}
1409+
1410+
public static (int exitCode, string result) Process (string cmd, string arguments, string input = null, bool waitForOutput = true)
1411+
{
1412+
var output = string.Empty;
1413+
1414+
using (Process process = new Process {
1415+
StartInfo = new ProcessStartInfo {
1416+
FileName = cmd,
1417+
Arguments = arguments,
1418+
RedirectStandardOutput = true,
1419+
RedirectStandardError = true,
1420+
RedirectStandardInput = true,
1421+
UseShellExecute = false,
1422+
CreateNoWindow = true,
1423+
}
1424+
}) {
1425+
var eventHandled = new TaskCompletionSource<bool> ();
1426+
process.Start ();
1427+
if (!string.IsNullOrEmpty (input)) {
1428+
process.StandardInput.Write (input);
1429+
process.StandardInput.Close ();
1430+
}
1431+
1432+
if (!process.WaitForExit (5000)) {
1433+
var timeoutError = $@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
1434+
throw new TimeoutException (timeoutError);
1435+
}
1436+
1437+
if (waitForOutput && process.StandardOutput.Peek () != -1) {
1438+
output = process.StandardOutput.ReadToEnd ();
1439+
}
1440+
1441+
if (process.ExitCode > 0) {
1442+
output = $@"Process failed to run. Command line: {cmd} {arguments}.
1443+
Output: {output}
1444+
Error: {process.StandardError.ReadToEnd ()}";
1445+
}
1446+
1447+
return (process.ExitCode, output);
1448+
}
1449+
}
1450+
1451+
public static bool DoubleWaitForExit (this System.Diagnostics.Process process)
1452+
{
1453+
var result = process.WaitForExit (500);
1454+
if (result) {
1455+
process.WaitForExit ();
1456+
}
1457+
return result;
1458+
}
1459+
1460+
public static bool FileExists (this string value)
1461+
{
1462+
return !string.IsNullOrEmpty (value) && !value.Contains ("not found");
1463+
}
1464+
}
13931465
}

‎Terminal.Gui/Core/TextFormatter.cs

+8-14
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,6 @@ internal set {
293293
}
294294
}
295295

296-
/// <summary>
297-
/// Specifies the mask to apply to the hotkey to tag it as the hotkey. The default value of <c>0x100000</c> causes
298-
/// the underlying Rune to be identified as a "private use" Unicode character.
299-
/// </summary>HotKeyTagMask
300-
public uint HotKeyTagMask { get; set; } = 0x100000;
301-
302296
/// <summary>
303297
/// Gets the cursor position from <see cref="HotKey"/>. If the <see cref="HotKey"/> is defined, the cursor will be positioned over it.
304298
/// </summary>
@@ -317,8 +311,9 @@ public List<ustring> Lines {
317311
get {
318312
// With this check, we protect against subclasses with overrides of Text
319313
if (ustring.IsNullOrEmpty (Text) || Size.IsEmpty) {
320-
lines = new List<ustring> ();
321-
lines.Add (ustring.Empty);
314+
lines = new List<ustring> {
315+
ustring.Empty
316+
};
322317
NeedsFormat = false;
323318
return lines;
324319
}
@@ -716,7 +711,7 @@ public static ustring Justify (ustring text, int width, char spaceChar = ' ', Te
716711
}
717712

718713
static char [] whitespace = new char [] { ' ', '\t' };
719-
private int hotKeyPos;
714+
private int hotKeyPos = -1;
720715

721716
/// <summary>
722717
/// Reformats text into lines, applying text alignment and optionally wrapping text to new lines on word boundaries.
@@ -1113,14 +1108,13 @@ public static bool FindHotKey (ustring text, Rune hotKeySpecifier, bool firstUpp
11131108
/// <returns>The text with the hotkey tagged.</returns>
11141109
/// <remarks>
11151110
/// The returned string will not render correctly without first un-doing the tag. To undo the tag, search for
1116-
/// Runes with a bitmask of <c>otKeyTagMask</c> and remove that bitmask.
11171111
/// </remarks>
11181112
public ustring ReplaceHotKeyWithTag (ustring text, int hotPos)
11191113
{
11201114
// Set the high bit
11211115
var runes = text.ToRuneList ();
11221116
if (Rune.IsLetterOrNumber (runes [hotPos])) {
1123-
runes [hotPos] = new Rune ((uint)runes [hotPos] | HotKeyTagMask);
1117+
runes [hotPos] = new Rune ((uint)runes [hotPos]);
11241118
}
11251119
return ustring.Make (runes);
11261120
}
@@ -1297,13 +1291,13 @@ public void Draw (Rect bounds, Attribute normalColor, Attribute hotColor, Rect c
12971291
rune = runes [idx];
12981292
}
12991293
}
1300-
if ((rune & HotKeyTagMask) == HotKeyTagMask) {
1294+
if (idx == HotKeyPos) {
13011295
if ((isVertical && textVerticalAlignment == VerticalTextAlignment.Justified) ||
1302-
(!isVertical && textAlignment == TextAlignment.Justified)) {
1296+
(!isVertical && textAlignment == TextAlignment.Justified)) {
13031297
CursorPosition = idx - start;
13041298
}
13051299
Application.Driver?.SetAttribute (hotColor);
1306-
Application.Driver?.AddRune ((Rune)((uint)rune & ~HotKeyTagMask));
1300+
Application.Driver?.AddRune (rune);
13071301
Application.Driver?.SetAttribute (normalColor);
13081302
} else {
13091303
Application.Driver?.AddRune (rune);

‎Terminal.Gui/Core/View.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -987,13 +987,13 @@ public virtual void Remove (View view)
987987
if (view == null || subviews == null)
988988
return;
989989

990-
SetNeedsLayout ();
991-
SetNeedsDisplay ();
992990
var touched = view.Frame;
993991
subviews.Remove (view);
994992
tabIndexes.Remove (view);
995993
view.container = null;
996994
view.tabIndex = -1;
995+
SetNeedsLayout ();
996+
SetNeedsDisplay ();
997997
if (subviews.Count < 1) {
998998
CanFocus = false;
999999
}

‎Terminal.Gui/Core/Window.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -277,18 +277,17 @@ public override void Redraw (Rect bounds)
277277
{
278278
var padding = Border.GetSumThickness ();
279279
var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
280-
//var borderLength = Border.DrawMarginFrame ? 1 : 0;
281280

282-
// FIXED: Why do we draw the frame twice? This call is here to clear the content area, I think. Why not just clear that area?
283-
if (!NeedDisplay.IsEmpty) {
281+
if (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded) {
284282
Driver.SetAttribute (GetNormalColor ());
285283
Clear ();
284+
contentView.SetNeedsDisplay ();
286285
}
287286
var savedClip = contentView.ClipToBounds ();
288287

289288
// Redraw our contentView
290289
// DONE: smartly constrict contentView.Bounds to just be what intersects with the 'bounds' we were passed
291-
contentView.Redraw (!NeedDisplay.IsEmpty ? contentView.Bounds : bounds);
290+
contentView.Redraw (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded ? contentView.Bounds : bounds);
292291
Driver.Clip = savedClip;
293292

294293
ClearLayoutNeeded ();

‎Terminal.Gui/Terminal.Gui.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
</PropertyGroup>
1717
<ItemGroup>
1818
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
19-
<PackageReference Include="NStack.Core" Version="1.*" />
19+
<PackageReference Include="NStack.Core" Version="1.0.7" />
2020
<InternalsVisibleTo Include="UnitTests" />
2121
</ItemGroup>
2222
<!-- Uncomment the RestoreSources element to have dotnet restore pull NStack from a local dir for testing -->

‎Terminal.Gui/Views/Menu.cs

+17-1
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ bool MoveDown ()
690690
}
691691
} while (barItems.Children [current] == null || disabled);
692692
SetNeedsDisplay ();
693+
SetParentSetNeedsDisplay ();
693694
if (!host.UseSubMenusSingleFrame)
694695
host.OnMenuOpened ();
695696
return true;
@@ -737,11 +738,24 @@ bool MoveUp ()
737738
}
738739
} while (barItems.Children [current] == null || disabled);
739740
SetNeedsDisplay ();
741+
SetParentSetNeedsDisplay ();
740742
if (!host.UseSubMenusSingleFrame)
741743
host.OnMenuOpened ();
742744
return true;
743745
}
744746

747+
private void SetParentSetNeedsDisplay ()
748+
{
749+
if (host.openSubMenu != null) {
750+
foreach (var menu in host.openSubMenu) {
751+
menu.SetNeedsDisplay ();
752+
}
753+
}
754+
755+
host?.openMenu.SetNeedsDisplay ();
756+
host.SetNeedsDisplay ();
757+
}
758+
745759
public override bool MouseEvent (MouseEvent me)
746760
{
747761
if (!host.handled && !host.HandleGrabView (me, this)) {
@@ -778,6 +792,7 @@ public override bool MouseEvent (MouseEvent me)
778792
current = me.Y - 1;
779793
if (host.UseSubMenusSingleFrame || !CheckSubMenu ()) {
780794
SetNeedsDisplay ();
795+
SetParentSetNeedsDisplay ();
781796
return true;
782797
}
783798
host.OnMenuOpened ();
@@ -806,6 +821,7 @@ internal bool CheckSubMenu ()
806821
return host.CloseMenu (false, true);
807822
} else {
808823
SetNeedsDisplay ();
824+
SetParentSetNeedsDisplay ();
809825
}
810826
return true;
811827
}
@@ -1589,7 +1605,7 @@ internal void NextMenu (bool isSubMenu = false, bool ignoreUseSubMenusSingleFram
15891605
var subMenu = openCurrentMenu.current > -1 && openCurrentMenu.barItems.Children.Length > 0
15901606
? openCurrentMenu.barItems.SubMenu (openCurrentMenu.barItems.Children [openCurrentMenu.current])
15911607
: null;
1592-
if ((selectedSub == -1 || openSubMenu == null || openSubMenu?.Count == selectedSub) && subMenu == null) {
1608+
if ((selectedSub == -1 || openSubMenu == null || openSubMenu?.Count - 1 == selectedSub) && subMenu == null) {
15931609
if (openSubMenu != null && !CloseMenu (false, true))
15941610
return;
15951611
NextMenu (false, ignoreUseSubMenusSingleFrame);

0 commit comments

Comments
 (0)
Please sign in to comment.