mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-05-04 08:32:52 +08:00
120 lines
3.6 KiB
C#
120 lines
3.6 KiB
C#
namespace Spectre.Console.Cli;
|
|
|
|
internal sealed class CommandValueBinder
|
|
{
|
|
private readonly CommandValueLookup _lookup;
|
|
|
|
public CommandValueBinder(CommandValueLookup lookup)
|
|
{
|
|
_lookup = lookup;
|
|
}
|
|
|
|
public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value)
|
|
{
|
|
if (parameter.ParameterKind == ParameterKind.Pair)
|
|
{
|
|
value = GetLookup(parameter, resolver, value);
|
|
}
|
|
else if (parameter.ParameterKind == ParameterKind.Vector)
|
|
{
|
|
value = GetArray(parameter, value);
|
|
}
|
|
else if (parameter.ParameterKind == ParameterKind.FlagWithValue)
|
|
{
|
|
value = GetFlag(parameter, value);
|
|
}
|
|
|
|
_lookup.SetValue(parameter, value);
|
|
}
|
|
|
|
private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value)
|
|
{
|
|
var genericTypes = parameter.Property.PropertyType.GetGenericArguments();
|
|
|
|
var multimap = (IMultiMap?)_lookup.GetValue(parameter);
|
|
if (multimap == null)
|
|
{
|
|
multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap;
|
|
if (multimap == null)
|
|
{
|
|
throw new InvalidOperationException("Could not create multimap");
|
|
}
|
|
}
|
|
|
|
// Create deconstructor.
|
|
var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor);
|
|
if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor))
|
|
{
|
|
if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor))
|
|
{
|
|
throw new InvalidOperationException($"Could not create pair deconstructor.");
|
|
}
|
|
|
|
deconstructor = activatedDeconstructor;
|
|
}
|
|
|
|
// Deconstruct and add to multimap.
|
|
var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string);
|
|
if (pair.Key != null)
|
|
{
|
|
multimap.Add(pair);
|
|
}
|
|
|
|
return multimap;
|
|
}
|
|
|
|
private object GetArray(CommandParameter parameter, object? value)
|
|
{
|
|
if (value is Array)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
// Add a new item to the array
|
|
var array = (Array?)_lookup.GetValue(parameter);
|
|
Array newArray;
|
|
|
|
var elementType = parameter.Property.PropertyType.GetElementType();
|
|
if (elementType == null)
|
|
{
|
|
throw new InvalidOperationException("Could not get property type.");
|
|
}
|
|
|
|
if (array == null)
|
|
{
|
|
newArray = Array.CreateInstance(elementType, 1);
|
|
}
|
|
else
|
|
{
|
|
newArray = Array.CreateInstance(elementType, array.Length + 1);
|
|
array.CopyTo(newArray, 0);
|
|
}
|
|
|
|
newArray.SetValue(value, newArray.Length - 1);
|
|
return newArray;
|
|
}
|
|
|
|
private object GetFlag(CommandParameter parameter, object? value)
|
|
{
|
|
var flagValue = (IFlagValue?)_lookup.GetValue(parameter);
|
|
if (flagValue == null)
|
|
{
|
|
flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType);
|
|
if (flagValue == null)
|
|
{
|
|
throw new InvalidOperationException("Could not create flag value.");
|
|
}
|
|
}
|
|
|
|
if (value != null)
|
|
{
|
|
// Null means set, but not with a valid value.
|
|
flagValue.Value = value;
|
|
}
|
|
|
|
// If the parameter was mapped, then it's set.
|
|
flagValue.IsSet = true;
|
|
|
|
return flagValue;
|
|
}
|
|
} |