mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Merge branch 'v2_develop' into v2_4239-Charmap
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet clean -c Debug
|
||||
dotnet build -c Debug
|
||||
dotnet publish -c Debug -r linux-x64 --self-contained
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet clean -c Release
|
||||
dotnet build -c Release
|
||||
dotnet publish -c Release -r linux-x64 --self-contained
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet clean -c Debug
|
||||
dotnet build -c Debug
|
||||
dotnet publish -c Debug -r osx-x64 --self-contained
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet clean
|
||||
dotnet build
|
||||
dotnet clean -c Release
|
||||
dotnet build -c Release
|
||||
dotnet publish -c Release -r osx-x64 --self-contained
|
||||
|
||||
@@ -278,17 +278,37 @@ public static class DeepCloner
|
||||
|
||||
// Determine dictionary type and comparer
|
||||
Type [] genericArgs = type.GetGenericArguments ();
|
||||
Type dictType = genericArgs.Length == 2
|
||||
? typeof (Dictionary<,>).MakeGenericType (genericArgs)
|
||||
: typeof (Dictionary<object, object>);
|
||||
Type dictType;
|
||||
|
||||
if (genericArgs.Length == 2)
|
||||
{
|
||||
if (type.GetGenericTypeDefinition () == typeof (Dictionary<,>))
|
||||
{
|
||||
dictType = typeof (Dictionary<,>).MakeGenericType (genericArgs);
|
||||
}
|
||||
else if (type.GetGenericTypeDefinition () == typeof (ConcurrentDictionary<,>))
|
||||
{
|
||||
dictType = typeof (ConcurrentDictionary<,>).MakeGenericType (genericArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException (
|
||||
$"Unsupported dictionary type: {type}. Only Dictionary<,> and ConcurrentDictionary<,> are supported.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dictType = typeof (Dictionary<object, object>);
|
||||
}
|
||||
|
||||
object? comparer = type.GetProperty ("Comparer")?.GetValue (source);
|
||||
|
||||
// Create a temporary dictionary to hold cloned key-value pairs
|
||||
IDictionary tempDict = CreateDictionaryInstance (dictType, comparer);
|
||||
visited.TryAdd (source, tempDict);
|
||||
|
||||
|
||||
object? lastKey = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Clone all key-value pairs
|
||||
@@ -311,7 +331,9 @@ public static class DeepCloner
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
// Handle cases where the dictionary is modified during enumeration
|
||||
throw new InvalidOperationException ($"Error cloning dictionary ({source}) (last key was \"{lastKey}\"). Ensure the source dictionary is not modified during cloning.", ex);
|
||||
throw new InvalidOperationException (
|
||||
$"Error cloning dictionary ({source}) (last key was \"{lastKey}\"). Ensure the source dictionary is not modified during cloning.",
|
||||
ex);
|
||||
}
|
||||
|
||||
// If the original dictionary type has a parameterless constructor, create a new instance
|
||||
|
||||
@@ -536,6 +536,8 @@ internal class CursesDriver : ConsoleDriver
|
||||
return true;
|
||||
}
|
||||
|
||||
private EscSeqUtils.DECSCUSR_Style? _currentDecscusrStyle;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool SetCursorVisibility (CursorVisibility visibility)
|
||||
{
|
||||
@@ -547,17 +549,19 @@ internal class CursesDriver : ConsoleDriver
|
||||
if (!RunningUnitTests)
|
||||
{
|
||||
Curses.curs_set (((int)visibility >> 16) & 0x000000FF);
|
||||
Curses.leaveok (_window!.Handle, !Force16Colors);
|
||||
}
|
||||
|
||||
if (visibility != CursorVisibility.Invisible)
|
||||
{
|
||||
_mainLoopDriver?.WriteRaw (
|
||||
EscSeqUtils.CSI_SetCursorStyle (
|
||||
(EscSeqUtils.DECSCUSR_Style)
|
||||
(((int)visibility >> 24)
|
||||
& 0xFF)
|
||||
)
|
||||
);
|
||||
if (_currentDecscusrStyle is null || _currentDecscusrStyle != (EscSeqUtils.DECSCUSR_Style)(((int)visibility >> 24) & 0xFF))
|
||||
{
|
||||
_currentDecscusrStyle = (EscSeqUtils.DECSCUSR_Style)(((int)visibility >> 24) & 0xFF);
|
||||
|
||||
_mainLoopDriver?.WriteRaw (
|
||||
EscSeqUtils.CSI_SetCursorStyle ((EscSeqUtils.DECSCUSR_Style)_currentDecscusrStyle)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_currentCursorVisibility = visibility;
|
||||
|
||||
@@ -249,8 +249,7 @@ internal class UnixMainLoop : IMainLoopDriver
|
||||
|
||||
private class Watch
|
||||
{
|
||||
// BUGBUG: Fix this nullable issue.
|
||||
public Func<MainLoop, bool> Callback;
|
||||
public Func<MainLoop, bool>? Callback;
|
||||
public Condition Condition;
|
||||
public int File;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ internal static class ViewCollectionHelpers
|
||||
// The list parameter might be the live `_subviews`, so freeze it under a lock
|
||||
lock (list)
|
||||
{
|
||||
return [.. list]; // C# 12 slice copy (= new List<View>(list).ToArray())
|
||||
return list.ToArray (); // It’s slightly less “fancy C# 12”, but much safer in multithreaded code
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -551,4 +551,91 @@ public class DeepClonerTests
|
||||
Assert.True (stopwatch.ElapsedMilliseconds < 1000); // Ensure it completes within 1 second
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneDictionary_ShouldClone_NormalDictionary ()
|
||||
{
|
||||
// Arrange: A supported generic dictionary
|
||||
var original = new Dictionary<string, int>
|
||||
{
|
||||
["one"] = 1,
|
||||
["two"] = 2,
|
||||
["three"] = 3
|
||||
};
|
||||
|
||||
// Act
|
||||
var cloned = DeepCloner.DeepClone (original);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull (cloned);
|
||||
Assert.NotSame (original, cloned); // must be a new instance
|
||||
Assert.Equal (original, cloned); // must have same contents
|
||||
Assert.Equal (original.Count, cloned.Count);
|
||||
Assert.Equal (original ["one"], cloned ["one"]);
|
||||
Assert.Equal (original ["two"], cloned ["two"]);
|
||||
Assert.Equal (original ["three"], cloned ["three"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneDictionary_ShouldClone_ConcurrentDictionary ()
|
||||
{
|
||||
// Arrange
|
||||
var original = new ConcurrentDictionary<string, string>
|
||||
{
|
||||
["a"] = "alpha",
|
||||
["b"] = "beta"
|
||||
};
|
||||
|
||||
// Act
|
||||
var cloned = DeepCloner.DeepClone (original);
|
||||
|
||||
// Assert
|
||||
Assert.NotSame (original, cloned);
|
||||
Assert.Equal (original, cloned);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneDictionary_Empty_Dictionary_ShouldWork ()
|
||||
{
|
||||
// Arrange
|
||||
var original = new Dictionary<int, string> ();
|
||||
|
||||
// Act
|
||||
var cloned = DeepCloner.DeepClone (original);
|
||||
|
||||
// Assert
|
||||
Assert.NotSame (original, cloned);
|
||||
Assert.Empty (cloned!);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneDictionary_Empty_ConcurrentDictionary_ShouldWork ()
|
||||
{
|
||||
// Arrange
|
||||
var original = new ConcurrentDictionary<int, string> ();
|
||||
|
||||
// Act
|
||||
var cloned = DeepCloner.DeepClone (original);
|
||||
|
||||
// Assert
|
||||
Assert.NotSame (original, cloned);
|
||||
Assert.Empty (cloned!);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneDictionary_With_Unsupported_Dictionary_Throws ()
|
||||
{
|
||||
// Arrange: A generic dictionary type (SortedDictionary for example)
|
||||
var unsupportedDict = new SortedDictionary<int, string>
|
||||
{
|
||||
{ 1, "A" },
|
||||
{ 2, "B" }
|
||||
};
|
||||
|
||||
// Act & Assert: DeepCloner should throw
|
||||
Assert.ThrowsAny<InvalidOperationException> (() =>
|
||||
{
|
||||
// This should throw, because DeepCloner does not support SortedDictionary
|
||||
_ = DeepCloner.DeepClone (unsupportedDict);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user