Skip to content

Commit 79fecff

Browse files
committed
done GlobalOptions
1 parent d72cb99 commit 79fecff

File tree

7 files changed

+320
-136
lines changed

7 files changed

+320
-136
lines changed

sandbox/GeneratorSandbox/Program.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.Extensions.DependencyInjection;
44
using Microsoft.Extensions.Logging;
55
using System.Diagnostics.CodeAnalysis;
6+
using System.Runtime.CompilerServices;
67

78
//args = ["--x", "10", "--y", "20", "-v", "--prefix-output", "takoyakix"];
89

@@ -20,7 +21,12 @@
2021
var verbose = builder.AddGlobalOption<bool>($"-v", "");
2122
var noColor = builder.AddGlobalOption<bool>("--no-color", "Don't colorize output.");
2223
var dryRun = builder.AddGlobalOption<bool>("--dry-run", "");
23-
var prefixOutput = builder.AddRequiredGlobalOption<string>("--prefix-output|-pp|-po", "Prefix output with level.");
24+
25+
var dame = builder.AddGlobalOption<int>("hoge", "huga", 0);
26+
27+
var takoyaki = builder.AddGlobalOption<int?>("hogemoge", defaultValue: null);
28+
29+
var prefixOutput = builder.AddRequiredGlobalOption<string>(description: "Prefix output with level.", name: "--prefix-output|-pp|-po");
2430

2531
// var tako = builder.AddGlobalOption<int>("--in", "");
2632
//var tako = builder.AddGlobalOption<MyFruit>("--fruit", "");
@@ -74,12 +80,10 @@ internal class MyCommand(GlobalOptions globalOptions)
7480
/// <summary>
7581
/// my command
7682
/// </summary>
77-
/// <param name="xxx">-x, takoyaki</param>
78-
/// <param name="yyyy">-yy|-y, naninuneno</param>
7983
[Command("")]
80-
public void Run(int xxx, int yyyy, bool z, bool zzz, Int128 iiii, int? takoyaki = null, MyFruit myFruit = default, Version version = null)
84+
public void Run(int x)
8185
{
82-
Console.WriteLine(xxx + yyyy + ":" + globalOptions);
86+
Console.WriteLine(globalOptions);
8387
}
8488
}
8589

@@ -89,3 +93,7 @@ public enum MyFruit
8993
}
9094

9195

96+
public class Takoyaki
97+
{
98+
99+
}

src/ConsoleAppFramework/ConsoleAppBaseCode.cs

Lines changed: 171 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,42 @@ static T ParseArgument<T>(ref Span<string> args, int i)
690690
return default;
691691
}
692692
693+
static void RemoveRange(ref Span<string> args, int index, int length)
694+
{
695+
if (length <= 0) return;
696+
697+
// Fast path(removing from start/end) no need copy
698+
if (index == 0)
699+
{
700+
args = args.Slice(length);
701+
return;
702+
}
703+
else if (index + length == args.Length)
704+
{
705+
args = args.Slice(0, index);
706+
return;
707+
}
708+
709+
// Otherwise, need to copy
710+
var temp = new string[args.Length - length];
711+
args.Slice(0, index).CopyTo(temp);
712+
args.Slice(index + length).CopyTo(temp.AsSpan(index));
713+
args = temp;
714+
}
715+
716+
static bool Contains(ReadOnlySpan<char> nameToSlice, Span<Range> ranges, string target)
717+
{
718+
for (int i = 0; i < ranges.Length; i++)
719+
{
720+
var name = nameToSlice[ranges[i]].Trim();
721+
if (name.Equals(target, StringComparison.OrdinalIgnoreCase))
722+
{
723+
return true;
724+
}
725+
}
726+
return false;
727+
}
728+
693729
static bool TryParse<T>(string s, out T result)
694730
{
695731
if (typeof(T) == typeof(string))
@@ -737,31 +773,31 @@ static bool TryParse<T>(string s, out T result)
737773
result = default;
738774
return false;
739775
}
740-
else if (typeof(T) == typeof(ushort))
776+
else if (typeof(T) == typeof(int))
741777
{
742-
if (ushort.TryParse(s, out var v))
778+
if (int.TryParse(s, out var v))
743779
{
744-
result = Unsafe.As<ushort, T>(ref v);
780+
result = Unsafe.As<int, T>(ref v);
745781
return true;
746782
}
747783
result = default;
748784
return false;
749785
}
750-
else if (typeof(T) == typeof(int))
786+
else if (typeof(T) == typeof(long))
751787
{
752-
if (int.TryParse(s, out var v))
788+
if (long.TryParse(s, out var v))
753789
{
754-
result = Unsafe.As<int, T>(ref v);
790+
result = Unsafe.As<long, T>(ref v);
755791
return true;
756792
}
757793
result = default;
758794
return false;
759795
}
760-
else if (typeof(T) == typeof(long))
796+
else if (typeof(T) == typeof(ushort))
761797
{
762-
if (long.TryParse(s, out var v))
798+
if (ushort.TryParse(s, out var v))
763799
{
764-
result = Unsafe.As<long, T>(ref v);
800+
result = Unsafe.As<ushort, T>(ref v);
765801
return true;
766802
}
767803
result = default;
@@ -787,31 +823,31 @@ static bool TryParse<T>(string s, out T result)
787823
result = default;
788824
return false;
789825
}
790-
else if (typeof(T) == typeof(decimal))
826+
else if (typeof(T) == typeof(float))
791827
{
792-
if (decimal.TryParse(s, out var v))
828+
if (float.TryParse(s, out var v))
793829
{
794-
result = Unsafe.As<decimal, T>(ref v);
830+
result = Unsafe.As<float, T>(ref v);
795831
return true;
796832
}
797833
result = default;
798834
return false;
799835
}
800-
else if (typeof(T) == typeof(float))
836+
else if (typeof(T) == typeof(double))
801837
{
802-
if (float.TryParse(s, out var v))
838+
if (double.TryParse(s, out var v))
803839
{
804-
result = Unsafe.As<float, T>(ref v);
840+
result = Unsafe.As<double, T>(ref v);
805841
return true;
806842
}
807843
result = default;
808844
return false;
809845
}
810-
else if (typeof(T) == typeof(double))
846+
else if (typeof(T) == typeof(decimal))
811847
{
812-
if (double.TryParse(s, out var v))
848+
if (decimal.TryParse(s, out var v))
813849
{
814-
result = Unsafe.As<double, T>(ref v);
850+
result = Unsafe.As<decimal, T>(ref v);
815851
return true;
816852
}
817853
result = default;
@@ -827,44 +863,138 @@ static bool TryParse<T>(string s, out T result)
827863
return true;
828864
}
829865
}
866+
867+
var underlyingType = Nullable.GetUnderlyingType(typeof(T));
868+
if (underlyingType != null)
869+
{
870+
return TryParseNullable<T>(underlyingType, s, out result);
871+
}
872+
830873
result = default;
831874
return false;
832875
}
833876
}
834877
835-
static void RemoveRange(ref Span<string> args, int index, int length)
878+
static bool TryParseNullable<T>(Type underlyingType, string s, out T result)
836879
{
837-
if (length <= 0) return;
838-
839-
// Fast path(removing from start/end) no need copy
840-
if (index == 0)
880+
if (underlyingType == typeof(char))
841881
{
842-
args = args.Slice(length);
843-
return;
882+
if (char.TryParse(s, out var v))
883+
{
884+
var nullableValue = new char?(v);
885+
result = Unsafe.As<char?, T>(ref nullableValue);
886+
return true;
887+
}
844888
}
845-
else if (index + length == args.Length)
889+
else if (underlyingType == typeof(sbyte))
846890
{
847-
args = args.Slice(0, index);
848-
return;
891+
if (sbyte.TryParse(s, out var v))
892+
{
893+
var nullableValue = new sbyte?(v);
894+
result = Unsafe.As<sbyte?, T>(ref nullableValue);
895+
return true;
896+
}
849897
}
850-
851-
// Otherwise, need to copy
852-
var temp = new string[args.Length - length];
853-
args.Slice(0, index).CopyTo(temp);
854-
args.Slice(index + length).CopyTo(temp.AsSpan(index));
855-
args = temp;
856-
}
857-
858-
static bool Contains(ReadOnlySpan<char> nameToSlice, Span<Range> ranges, string target)
859-
{
860-
for (int i = 0; i < ranges.Length; i++)
898+
else if (underlyingType == typeof(byte))
861899
{
862-
var name = nameToSlice[ranges[i]].Trim();
863-
if (name.Equals(target, StringComparison.OrdinalIgnoreCase))
900+
if (byte.TryParse(s, out var v))
901+
{
902+
var nullableValue = new byte?(v);
903+
result = Unsafe.As<byte?, T>(ref nullableValue);
904+
return true;
905+
}
906+
}
907+
else if (underlyingType == typeof(short))
908+
{
909+
if (short.TryParse(s, out var v))
910+
{
911+
var nullableValue = new short?(v);
912+
result = Unsafe.As<short?, T>(ref nullableValue);
913+
return true;
914+
}
915+
}
916+
else if (underlyingType == typeof(int))
917+
{
918+
if (int.TryParse(s, out var v))
919+
{
920+
var nullableValue = new int?(v);
921+
result = Unsafe.As<int?, T>(ref nullableValue);
922+
return true;
923+
}
924+
}
925+
else if (underlyingType == typeof(long))
926+
{
927+
if (long.TryParse(s, out var v))
864928
{
929+
var nullableValue = new long?(v);
930+
result = Unsafe.As<long?, T>(ref nullableValue);
865931
return true;
866932
}
867933
}
934+
else if (underlyingType == typeof(ushort))
935+
{
936+
if (ushort.TryParse(s, out var v))
937+
{
938+
var nullableValue = new ushort?(v);
939+
result = Unsafe.As<ushort?, T>(ref nullableValue);
940+
return true;
941+
}
942+
}
943+
else if (underlyingType == typeof(uint))
944+
{
945+
if (uint.TryParse(s, out var v))
946+
{
947+
var nullableValue = new uint?(v);
948+
result = Unsafe.As<uint?, T>(ref nullableValue);
949+
return true;
950+
}
951+
}
952+
else if (underlyingType == typeof(ulong))
953+
{
954+
if (ulong.TryParse(s, out var v))
955+
{
956+
var nullableValue = new ulong?(v);
957+
result = Unsafe.As<ulong?, T>(ref nullableValue);
958+
return true;
959+
}
960+
}
961+
else if (underlyingType == typeof(float))
962+
{
963+
if (float.TryParse(s, out var v))
964+
{
965+
var nullableValue = new float?(v);
966+
result = Unsafe.As<float?, T>(ref nullableValue);
967+
return true;
968+
}
969+
}
970+
else if (underlyingType == typeof(double))
971+
{
972+
if (double.TryParse(s, out var v))
973+
{
974+
var nullableValue = new double?(v);
975+
result = Unsafe.As<double?, T>(ref nullableValue);
976+
return true;
977+
}
978+
}
979+
else if (underlyingType == typeof(decimal))
980+
{
981+
if (decimal.TryParse(s, out var v))
982+
{
983+
var nullableValue = new decimal?(v);
984+
result = Unsafe.As<decimal?, T>(ref nullableValue);
985+
return true;
986+
}
987+
}
988+
else if (underlyingType.IsEnum)
989+
{
990+
if (Enum.TryParse(underlyingType, s, ignoreCase: true, out var v))
991+
{
992+
result = (T)v;
993+
return true;
994+
}
995+
}
996+
997+
result = default;
868998
return false;
869999
}
8701000
}

src/ConsoleAppFramework/ConsoleAppGenerator.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,9 @@ public CollectBuilderContext(ConsoleAppFrameworkGeneratorOptions generatorOption
495495
var configureGlobalOptionsGroup = methodGroup["ConfigureGlobalOptions"];
496496
if (configureGlobalOptionsGroup.Count() >= 2)
497497
{
498-
// TODO: Diagnostics, not allows multiple configureglobaloptions.
498+
var node = configureGlobalOptionsGroup.Last().Item1.Node;
499+
500+
DiagnosticReporter.ReportDiagnostic(DiagnosticDescriptors.DuplicateConfigureGlobalOptions, node.Expression.GetLocation());
499501
}
500502

501503
if (configureGlobalOptionsGroup.Count() == 1)

src/ConsoleAppFramework/DiagnosticDescriptors.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,12 @@ public static DiagnosticDescriptor Create(int id, string title, string messageFo
122122
public static DiagnosticDescriptor ReturnTypeMethodAsyncVoid { get; } = Create(
123123
16,
124124
"Command method return type does not allow async void.");
125+
126+
public static DiagnosticDescriptor DuplicateConfigureGlobalOptions { get; } = Create(
127+
17,
128+
"ConfigureGlobalOptions does not allow to invoke twice.");
129+
130+
public static DiagnosticDescriptor InvalidGlobalOptionsType { get; } = Create(
131+
18,
132+
"GlobalOption parameter type only allows compile-time constant(primitives, string, enum) and there nullable.");
125133
}

0 commit comments

Comments
 (0)