{"id":18768598,"url":"https://github.com/slimenull/nulllib.commandline","last_synced_at":"2025-04-13T06:32:44.516Z","repository":{"id":49257454,"uuid":"348997777","full_name":"SlimeNull/NullLib.CommandLine","owner":"SlimeNull","description":"CommandLine! Calling Methods defined in CSharp Source file by using a command line string, with this library, you can easily do that; 命令行! 通过类似于CMD命令行的方式来调用 C# 中的函数吧, 有了这个库, 你可以轻松的实现上述功能.","archived":false,"fork":false,"pushed_at":"2022-03-10T08:10:28.000Z","size":211,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T01:17:07.642Z","etag":null,"topics":["command-line","parser"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SlimeNull.png","metadata":{"files":{"readme":"ReadMe.en.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-18T08:35:13.000Z","updated_at":"2024-07-09T00:39:24.000Z","dependencies_parsed_at":"2022-08-29T21:52:18.911Z","dependency_job_id":null,"html_url":"https://github.com/SlimeNull/NullLib.CommandLine","commit_stats":null,"previous_names":["slimenull/nulllib.commandhelper"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlimeNull%2FNullLib.CommandLine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlimeNull%2FNullLib.CommandLine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlimeNull%2FNullLib.CommandLine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SlimeNull%2FNullLib.CommandLine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SlimeNull","download_url":"https://codeload.github.com/SlimeNull/NullLib.CommandLine/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248674677,"owners_count":21143760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line","parser"],"created_at":"2024-11-07T19:13:15.913Z","updated_at":"2025-04-13T06:32:42.654Z","avatar_url":"https://github.com/SlimeNull.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NullLib.CommandLine\n\nEasily calling methods defined in C# with a command string.\n\nMore information about using this Library, see [Manual](./Manual.en.md)\n\n## Usage\n\nFirst of all, the basic type in **NullLib.CommandLine** for calling methods is `CommandObject`, it contains methods' information, such as `MethodInfo`, `ParameterInfo`, and attributes.\n\nThen, a class which contains methods for being called should be defined, in this class, each method which will be called must has a Command attribute, and then, we will initialize a `CommandObject` instance with this type. \n\nAn example class:\n\n```csharp\npublic class AppCommands\n{\n    [Command]\n    public void HelloWorld()\n    {\n        Console.WriteLine(\"Hello world!\");\n    }\n}\n```\n\nInitialize a `CommandObject` instance, and loop execute command.\n\n```csharp\nusing System;\nusing NullLib.CommandLine;\n\nclass Program\n{\n    static CommandObject\u003cAppCommands\u003e AppCommandObject = new CommandObject\u003cAppCommands\u003e();   // new CommandObject instance\n    static void Main(string[] args)\n    {\n        Console.WriteLine(\"Now input commands.\");\n        while (true)\n        {\n            Console.Write(\"\u003e\u003e\u003e \");          // prompt\n            string cmdline = Console.ReadLine();\n            if (AppCommandObject.TryExecuteCommand(cmdline, out var result))\n            {\n                if (result != null)             // if a method has no return value, then result is null.\n                    Console.WriteLine(result);\n            }\n            else\n            {\n                Console.WriteLine(\"Command execute failed.\");\n            }\n        }\n    }\n}\n```\n\nRun application, and input command:\n\n```txt\nNow input commands.\n\u003e\u003e\u003e HelloWorld\nHello world!\n```\n\nTo pass parameters to method, specify `ArguConverter` for each parameter.\n\nLet's add these methods to `AppCommands`\n\n```csharp\n[Command(typeof(FloatArguConverter), typeof(FloatArguConverter))]      // the build-in ArguConverter in NullLib.CommandLine\npublic float Plus(float a, float b)\n{\n    return a + b;\n}\n[Command(typeof(FloatArguConverter))]        // if the following converters is same as the last one, you can ignore these\npublic float Mul(float a, float b)\n{\n    return a * b;\n}\n[Command(typeof(DoubleArguConverter))]\npublic double Log(double n, double newBase = Math.E)    // you can also use optional parameter\n{\n    return Math.Log(n, newBase);\n}\n[Command(typeof(ForeachArguConverter\u003cFloatArguConverter\u003e))]   // each string of array will be converted by FloatArguConverter\npublic float Sum(params float[] nums)                 // variable length parameter method is supported\n{\n    float result = 0;\n    foreach (var i in nums)\n        result += i;\n    return result;\n}\n[Command(typeof(ArgutConverter))]        // if don't need to do any convertion, specify an 'ArguConverter'\npublic void Print(string txt)\n{\n    Console.WriteLine(txt);\n}\n[Command]                                   // the defualt converter is 'ArguConverter', you can ignore these\npublic bool StringEquals(string txt1, string txt2)   // or specify 'null' to use the last converter (here is ArguConverter)\n{\n    return txt1.Equals(txt2);\n}\n[Command(typeof(EnumArguConverter\u003cConsoleColor\u003e))]   // EnumConverter helps convert string to Enum type automatically.\npublic void SetBackground(ConsoleColor color)\n{\n    Console.BackgroundColor = color;\n}\n```\n\nRun and input:\n\n```txt\nNow input commands.\n\u003e\u003e\u003e Plus 1 1\n2\n\u003e\u003e\u003e Mul 2 4\n8\n\u003e\u003e\u003e Log 8 2\n3\n\u003e\u003e\u003e Log 8\n2.07944154167984\n\u003e\u003e\u003e Sum 1 2 3 4\n10\n\u003e\u003e\u003e Print \"some text`tescaped char is also supported\"\nsome text       escaped char is also supported\n\u003e\u003e\u003e StringEquals qwq awa\nFalse\n\u003e\u003e\u003e SetBackground White\n\u003e\u003e\u003e SetBackground 0\n\u003e\u003e\u003e Print \"you can convert to a enum type by it's name or integer value\"\nyou can convert to a enum type by it's name or integer value\n```\n\nNested Commands:\n\n```csharp\npublic class MyCommand\n{\n    [CommandHost]   // Add CommandHost Attribute for CommandObject Property member to use 'Nested Commands'\n    public CommandObject\u003cMathCommand\u003e Math { get; } = new();   // 实例化成员\n\n    [Command]\n    public string Hello() =\u003e \"Hello, world.\";\n\n    public class MathCommand\n    {\n        // implement Plus command in nested commands\n        [Command(typeof(DoubleArguConverter))]\n        public double Plus(double a, double b) =\u003e a + b;\n    }\n}\n\n/*\n    In codes above, we added a 'Nested Commands' command, and these commands will be supported:\n    Math Plus a:Double b:Double\n    Hello\n*/\n```\n\nIntergrated commands overview text generation:\n\n```csharp\nCommandObject\u003cAppCommand\u003e AppCommandObject = new();\nConsole.WriteLine(AppCommandObject.GenCommandOverviewText());    // Show all available commands\nConsole.WriteLine(AppCommandObject.GenCommandDetailsText(\"Help\", StringComparison.OrdinalIgnoreCase));  // See document of Help command\n```\n\nGet the CommandObject which is using the current custom Command class instance\n\n```csharp\nusing System;\nusing NullLib.CommandLine;\n\nclass MyCommands : CommandHome  // Inherit from CommandHome\n{\n    [Command]\n    public void Hello()\n    {\n        Console.WriteLine(CommandObject.GenCommandOverviewText());  // Use the CommandObject property of CommandHome\n\n        // If there is not CommandObject is using the current instance, it will returns null\n    }\n}\n```\n\nChange the escape char for your program\n\n```csharp\nCommandParser.EscapeChar = '^';  // Change escape char to '^' (default is '`')\n```\n\n## Types\n\n1. CommandAttribute:\n   \n   Method that can be execute by command string must has a `CommandAttribute`\n\n2. CommandObject:\n   \n   Class for invoking methods by command string.\n\n3. CommandInvoker:\n   \n   Helps invoking methods by `IArguments`.\n\n4. CommandParser:\n   \n   Helps to parse a command string for method calling.\n\n5. ArguConverter:\n   \n   Implemented `IArguConverter` interface, abstract class, should be inherited by custom Converter.\n\n6. ArguConverterManager:\n   \n   Helps create `ArguConverter` rapidly.\n\n7. CommandLineSegment:\n   \n   Component of command line string.\n\n8. ArguParser:\n   \n   Helps parse `CommandLineSegment` to `IArgument`\n\n## CommandLineSegment\n\nCommandLineSegment is a component of command line string.\n\nFor example, in `myprogram param1 \"param2\"`, there is three CommandLineSegment:\n\n1. {Quoted: false, Content: \"myprogram\"}\n2. {Quoted: false, Content: \"param1\"}\n3. {Quoted: true, Content: \"\\\\\"param2\\\\\"\"}\n\nTo split a command line string to CommandLineSegment[], use `CommandParser.SplitCommandLine(string str)`\n\n## Argument\n\nArgument of command, can have a name, implemented `IArgument`, when invoking method, will be passed.\n\n## ArguParser\n\nHere is all build-in `ArguParsers`:\n\n1. ArguParser:\n   \n   It can parse any segment as an Argument.\n\n2. IdentifierArguParser:\n   \n   It can parse an identifier segment as an `Argument`. The corresponding regex string is *\"{A-Za-z\\_}{A-Za-z0-9\\_}\\*\"*\n\n3. StringArguParser:\n   \n   It can parse any segments as an `Argument`, but the segment must be `Quoted`.\n\n4. FieldArguParser:\n   \n   It can parse a segment like \u003cu\u003e*name=value*\u003c/u\u003e or two segments like \u003cu\u003e*name= value*\u003c/u\u003e to a `Argument`, also, you can specify the separator, default is '='.\n\n5. PropertyArguParser:\n   \n   It can parse two segments like \u003cu\u003e*-name value*\u003c/u\u003e to a `Argument`, and you can also specify the start string of \u003cu\u003e*name*\u003c/u\u003e, default is \"-\".\n\n## ArguConverter\n\nHere is all build-in `ArguConverter`:\n\n1. ArguConverter:\n   \n   The default `ArguConverter` which returns the source value without any conversion\n\n2. BoolArguConverter:\n   \n   Helps convert to bool, for source value, if it's \"true\", then return true, if it's \"false\", then return false, otherwise, convert failed. (Cases is ignored).\n\n3. CharArguConverter:\n   \n   Helps convert to char, only when source string has one char, returns the char, otherwise, convert failed.\n\n4. ByteArguConverter:\n\n5. ShortArguConverter:\n\n6. IntArguConverter:\n\n7. LongArguConverter:\n\n8. FloatArguConverter:\n\n9. DoubleArguConverter:\n\n10. BigIntArguConverter:\n\n11. DecimalArguConverter:\n    \n    The converters mentioned above all returns the corresponding number type, and all calls `Parse` and `TryParse` method of corresponding number type.\n\n12. EnumArguConverter\u0026lt;T\u0026gt;:\n    \n    Helps convert to `Enum` type. T should specified a `Enum` type. It can convert from a name or number value of `Enum` type.\n\n13. ForeachArguConverter\u0026lt;TConverter\u0026gt;:\n    \n    Helps convert to Array, only used for variable-length parameter (decorated by `params`), `TConverter` must implement `IArguConverter`, each value of source string array will be converted by the specified Converter.\n\n14. CharArrayArguConverter:\n    \n    Helps convert to char array, it calls `string.ToCharArray()` to do conversion.\n\n## About ArguParser\n\n### Custom Parser:\n\nTo define custom `ArguParser`, your must follow these rules:\n\n1. Implements `IArguParser`\n2. After parsing, the reference parameter `index` must leave the parts of result(IArgument), for example, at the index 3, in your custom parser, it will return the result (result was parsed successfully), and the result is from two `CommandLineSegment`s, then the index must be 5 (out of 3 and 4).\n\n## About ArguConverter\n\n### Custom Converter:\n\nThe recommended way to define a custom `ArguConverter` is this:\n\n```csharp\nclass MyConverter : ArguConverterBase\u003cMyType\u003e    // inherit ArguConverter\u003cT\u003e but not IArguConverter\u003cT\u003e\n{\n    public override MyType Convert(string argument)\n    {\n        // your code here\n    }\n    public override bool TryConvert(string argument, out MyType result)\n    {\n        // your code here\n    }\n}\n```\n\nThe reason to inherit `ArguConverterBase\u003cT\u003e` but not `IArguConverter\u003cT\u003e` is, in `ArguConverterBase\u003cT\u003e`, all overloads calls two methods:\n\n1. T Convert(string argument);\n2. bool TryConverter(string argument, out T result);\n\nSo, if you inherit `ArguConverterBase\u003cT\u003e`, you just need to override these two methods.\n\n### Tips:\n\n1. Do NOT create a `ArguConverter` with new expression, use `ArguConverterManager.GetConverter\u003cT\u003e()`.\n\n## FAQ\n\n1. When I calling `CommandObject.ExecuteCommand(IArguParser[] parsers, string cmdline)`, but some of parsers don't work:\n   \n   ```csharp\n   // you must specify parsers in a correct order, or it will like this:\n   CommandObject\u003cAppCommands\u003e myCmds = new CommandObject\u003cAppCommands\u003e();\n   myCmds.ExecuteCommand(new IArguParser[]\n   {\n       new ArguParser(),                // in this case, FieldArguParser and PropertyArguParser will not work.\n       new FieldArguParser(),           // this is because that ArguParser can parse ANY CommandLineSegments\n       new PropertyArguParser()         // so you should place ArguParser as the last parser.\n   }, Console.ReadLine());\n   ```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslimenull%2Fnulllib.commandline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslimenull%2Fnulllib.commandline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslimenull%2Fnulllib.commandline/lists"}