{"id":19611624,"url":"https://github.com/xenoatom/xenoatom.commandline","last_synced_at":"2026-02-14T16:16:22.355Z","repository":{"id":238205713,"uuid":"796010919","full_name":"XenoAtom/XenoAtom.CommandLine","owner":"XenoAtom","description":"XenoAtom.CommandLine is a lightweight, powerful and NativeAOT-friendly command-line parsing library for .NET","archived":false,"fork":false,"pushed_at":"2026-02-13T09:34:04.000Z","size":2840,"stargazers_count":73,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-13T13:58:35.266Z","etag":null,"topics":["cli-parser","command-line","command-line-parser","dotnet","dotnet-core","terminal-ui"],"latest_commit_sha":null,"homepage":"https://xenoatom.github.io/commandline","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/XenoAtom.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":["xoofx"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2024-05-04T17:01:18.000Z","updated_at":"2026-02-13T09:09:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"49f27b98-9f95-43a6-bf2d-a7ad4b294b66","html_url":"https://github.com/XenoAtom/XenoAtom.CommandLine","commit_stats":null,"previous_names":["xenoatom/xenoatom.commandline"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/XenoAtom/XenoAtom.CommandLine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XenoAtom%2FXenoAtom.CommandLine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XenoAtom%2FXenoAtom.CommandLine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XenoAtom%2FXenoAtom.CommandLine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XenoAtom%2FXenoAtom.CommandLine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/XenoAtom","download_url":"https://codeload.github.com/XenoAtom/XenoAtom.CommandLine/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/XenoAtom%2FXenoAtom.CommandLine/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29449364,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T15:52:44.973Z","status":"ssl_error","status_checked_at":"2026-02-14T15:52:11.208Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["cli-parser","command-line","command-line-parser","dotnet","dotnet-core","terminal-ui"],"created_at":"2024-11-11T10:41:25.791Z","updated_at":"2026-02-14T16:16:22.350Z","avatar_url":"https://github.com/XenoAtom.png","language":"C#","funding_links":["https://github.com/sponsors/xoofx"],"categories":[],"sub_categories":[],"readme":"# XenoAtom.CommandLine [![ci](https://github.com/XenoAtom/XenoAtom.CommandLine/actions/workflows/ci.yml/badge.svg)](https://github.com/XenoAtom/XenoAtom.CommandLine/actions/workflows/ci.yml) ![coverage](https://gist.githubusercontent.com/xoofx/4b1dc8d0fa14dd6a3846e78e5f0eafae/raw/dotnet-releaser-coverage-badge-XenoAtom-XenoAtom.CommandLine.svg)  [![NuGet](https://img.shields.io/nuget/v/XenoAtom.CommandLine.svg)](https://www.nuget.org/packages/XenoAtom.CommandLine/)\n\n\u003cimg align=\"right\" width=\"256px\" height=\"256px\" src=\"https://raw.githubusercontent.com/XenoAtom/XenoAtom.CommandLine/main/img/icon.png\"\u003e\n\n**XenoAtom.CommandLine** is a lightweight, powerful and NativeAOT-friendly command-line parsing library for .NET\n\n## ✨ Features\n\n- **Lightweight and NativeAOT-friendly** (`net8.0`+), with **zero dependencies**\n- **Composition-first API:** declare commands/options with collection initializers (**no attributes, no base classes, no required \"command classes\"**)\n- **Auto-generated usage/help:** \"what you declare is what you get\"\n- **Commands and sub-commands** (e.g. `git commit -m \"message\"`)\n- **Strict positional arguments by default** (named args + remainder): `\u003carg\u003e`, `\u003carg\u003e?`, `\u003carg\u003e*`, `\u003carg\u003e+`, `\u003c\u003e`\n- **Fast parsing:** optimized hot paths (**no regex**), **low GC allocations**\n- **Powerful option parsing**\n  - **Prefixes:** `-`, `--`, `/` (e.g. `-v`, `--verbose`, `/v`)\n  - **Aliases:** `-v`, `--verbose`\n  - **Bundled short options:** `-abc` == `-a -b -c` (tar/POSIX style)\n  - **Values:** required `=` / optional `:` (e.g. `-o`, `-oVALUE`, `-o:VALUE`, `-o=VALUE`)\n  - **Multiple values:** `-i foo -i bar`\n  - **Key/value pairs:** `-DMACRO=VALUE`\n- **Built-ins:** `--help` and `--version`\n- **Environment variable fallbacks:** bind options to env vars (with optional delimiter splitting)\n- **Option and argument validation:** built-in validators (`Validate.Range`, `Validate.NonEmpty`, `Validate.OneOf`, ...)\n- **Option constraints:** declare mutually-exclusive and requires relationships between options\n- **Test-friendly parse API:** inspect parse results via `CommandApp.Parse(...)` without invoking command actions\n- **Pluggable output rendering:** replace built-in help/error/version/license rendering via `CommandConfig.OutputFactory`\n  - Optional **`XenoAtom.CommandLine.Terminal`** package (`net10.0`) for colored markup output and Terminal.UI visual help (`TerminalVisualCommandOutput`, `Command.ToHelpVisual()`)\n  - Inline Terminal.UI visuals can be declared directly in command initializers and are rendered by default, markup, and visual outputs\n- **Better errors by default**\n  - **Strict unknown `-` / `--` options** (`CommandConfig.StrictOptionParsing`)\n  - **Helpful diagnostics:** suggestions + \"inactive in this context\" hints\n  - Use `--` to pass values starting with `-` (e.g. `myexe -- -5`); `/mnt/home` is treated as a positional value (not an option)\n- **Response files:** `@file.txt` (supports quotes, `#` comments, and basic escaping on non-Windows)\n- **Conditional groups:** declare commands/options that are only active when a condition is met\n- **Shell completions:** bash/zsh/fish/PowerShell via `CompletionCommands`, token protocol, optional value completions (`ValueCompleter`)\n\n![Terminal UI help output](https://raw.githubusercontent.com/XenoAtom/XenoAtom.CommandLine/main/site/img/xenoatom-commandline-show.gif)\n\n## 🧪 Example\n\n```csharp\nusing System;\nusing XenoAtom.CommandLine;\n\nconst string _ = \"\";\nstring? name = null;\nint age = 0;\nList\u003c(string, string?)\u003e keyValues = new List\u003c(string, string?)\u003e();\nList\u003cstring\u003e messages = new List\u003cstring\u003e();\nList\u003cstring\u003e commitFiles = new List\u003cstring\u003e();\n\nvar commandApp = new CommandApp(\"myexe\")\n{\n    new CommandUsage(),\n    _,\n    {\"D:\", \"Defines a {0:name} and optional {1:value}\", (key, value) =\u003e\n    {\n        if (key is null) throw new CommandOptionException(\"The key is mandatory for a define\", \"D\");\n        keyValues.Add((key, value));\n    }},\n    {\"n|name=\", \"Your {NAME}\", v =\u003e name = v},\n    {\"a|age=\", \"Your {AGE}\", (int v) =\u003e age = v},\n    new HelpOption(),\n    _,\n    \"Available commands:\",\n    new Command(\"commit\")\n    {\n        _,\n        \"Options:\",\n        {\"m|message=\", \"Add a {MESSAGE} to this commit\", messages},\n        new HelpOption(),\n        _,\n        \"Arguments:\",\n        { \"\u003cfiles\u003e*\", \"Files to commit\", commitFiles },\n\n        // Action for the commit command\n        (ctx, _) =\u003e\n        {\n            ctx.Out.WriteLine($\"Committing with name={name}, age={age}\");\n            foreach (var message in messages)\n            {\n                ctx.Out.WriteLine($\"Commit message: {message}\");\n            }\n            foreach (var file in commitFiles)\n            {\n                ctx.Out.WriteLine($\"Commit file: {file}\");\n            }\n            return ValueTask.FromResult(0);\n        }\n    },\n    // Default action if no command is specified\n    (ctx, _) =\u003e\n    {\n        ctx.Out.WriteLine($\"Hello {name}! You are {age} years old.\");\n        if (keyValues.Count \u003e 0)\n        {\n            foreach (var keyValue in keyValues)\n            {\n                ctx.Out.WriteLine($\"Define: {keyValue.Item1} =\u003e {keyValue.Item2}\");\n            }\n        }\n\n        return ValueTask.FromResult(0);\n    }\n};\n\nawait commandApp.RunAsync(args);\n```\n\nNotes:\n- `CommandUsage()` defaults to `Usage: {NAME} {SYNTAX}` and `{SYNTAX}` is derived from your declared options/commands/arguments.\n- Positional arguments are strict by default: declare `\u003carg\u003e` / `\u003carg\u003e?` / `\u003carg\u003e*` / `\u003carg\u003e+`, or declare `\u003c\u003e` to forward remaining arguments to the command action.\n- Convenience helpers are available when not using collection initializers: `AddRemainder(...)`, `AddSection(...)`, and `AddText(...)`.\n- A command graph instance is intended for one invocation at a time (`RunAsync`/`Parse` are not concurrent-safe on the same graph).\n\nRunning `myexe --help` will output:\n\n```\nUsage: myexe [options] \u003ccommand\u003e\n\n  -D[=name:value]            Defines a name and optional value\n  -n, --name=NAME            Your NAME\n  -a, --age=AGE              Your AGE\n  -h, -?, --help             Show this message and exit\n\nAvailable commands:\n  commit\n```\n\nRunning `myexe --name John -a50` will output:\n\n```\nHello John! You are 50 years old.\n```\n\nRunning `myexe --name John -a50 -DHello -DWorld=121` will output:\n\n```\nHello John! You are 50 years old.\nDefine: Hello =\u003e\nDefine: World =\u003e 121\n```\n\nRunning `myexe commit --help` will output:\n\n```\nUsage: myexe commit [options] \u003cfiles\u003e*\n\nOptions:\n  -m, --message=MESSAGE      Add a MESSAGE to this commit\n  -h, -?, --help             Show this message and exit\n\nArguments:\n  \u003cfiles\u003e*                   Files to commit\n```\n\nRunning `myexe --name John -a50 commit --message \"Hello!\" --message \"World!\"` will output:\n\n```\nCommitting with name=John, age=50\nCommit message: Hello!\nCommit message: World!\n```\n\n## 🎨 Terminal / Visual Output\n\nFor richer CLI output, use the optional `XenoAtom.CommandLine.Terminal` package:\n\n```csharp\nusing XenoAtom.CommandLine;\nusing XenoAtom.CommandLine.Terminal;\nusing XenoAtom.Terminal.UI;\nusing XenoAtom.Terminal.UI.Controls;\nusing XenoAtom.Terminal.UI.Figlet;\nusing XenoAtom.Terminal.UI.Styling;\n\nvar app = new CommandApp(\"myexe\", config: new CommandConfig\n{\n    OutputFactory = _ =\u003e new TerminalVisualCommandOutput()\n})\n{\n    new CommandUsage(),\n    new TextFiglet(\"XenoAtom\")\n        .Font(FigletPredefinedFont.Standard)\n        .LetterSpacing(1)\n        .TextAlignment(TextAlignment.Left)\n        .Style(TextFigletStyle.Default with\n        {\n            ForegroundBrush = Brush.LinearGradient(\n                new GradientPoint(0f, 0f),\n                new GradientPoint(1f, 0f),\n                [\n                    new GradientStop(0f, Colors.DodgerBlue),\n                    new GradientStop(0.5f, Colors.White),\n                    new GradientStop(1f, Colors.Orange),\n                ],\n                mixSpaceOverride: ColorMixSpace.Oklab),\n        }),\n    \"Options:\",\n    { \"n|name=\", \"Your {NAME}\", _ =\u003e { } },\n    new HelpOption(),\n    (ctx, _) =\u003e ValueTask.FromResult(0)\n};\n```\n\nThis package also provides `command.ToHelpVisual(...)` for embedding help in Terminal.UI apps.\nFor one-shot rendering, `Terminal.Write(...)` is lazily initialized and does not require an explicit terminal session.\n\n## 📃 Documentation\n\nSee the [website](https://xenoatom.github.io/commandline/) for documentation, API reference, and examples.\n\n## 🏗️ Build\n\nYou need to install the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). Then from the root folder:\n\n```console\n$ dotnet build src -c Release\n```\n\n## 🪪 License\n\nThis software is released under the [BSD-2-Clause license](https://opensource.org/licenses/BSD-2-Clause).\n\nIt is a fork of the excellent [NDesk.Options](http://www.ndesk.org/Options)/[Mono.Options](https://tirania.org/blog/archive/2008/Oct-14.html) with significant improvements and new features.\n\nThe license also integrate the original MIT license from [Mono.Options](https://github.com/mono/mono/blob/main/mcs/class/Mono.Options/Mono.Options/Options.cs).\n\n## 🤗 Author\n\nAlexandre Mutel aka [xoofx](https://xoofx.github.io).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxenoatom%2Fxenoatom.commandline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxenoatom%2Fxenoatom.commandline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxenoatom%2Fxenoatom.commandline/lists"}