{"id":16375033,"url":"https://github.com/moderocky/commander","last_synced_at":"2025-09-11T17:44:00.759Z","repository":{"id":49294227,"uuid":"312837598","full_name":"Moderocky/Commander","owner":"Moderocky","description":"A framework for building command systems, suitable for system input, terminal-style commands, Discord or Minecraft, etc.","archived":false,"fork":false,"pushed_at":"2021-06-19T15:52:40.000Z","size":23,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-01T04:15:14.501Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Moderocky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-14T14:52:33.000Z","updated_at":"2021-06-19T15:52:42.000Z","dependencies_parsed_at":"2022-08-19T08:50:26.308Z","dependency_job_id":null,"html_url":"https://github.com/Moderocky/Commander","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FCommander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FCommander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FCommander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FCommander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Moderocky","download_url":"https://codeload.github.com/Moderocky/Commander/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239954709,"owners_count":19724289,"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":[],"created_at":"2024-10-11T03:19:13.773Z","updated_at":"2025-02-21T04:25:54.631Z","avatar_url":"https://github.com/Moderocky.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Commander\n=====\nA framework for building standard command systems.\n\n### Features\n* [x]  Simple lambda-based system\n* [x]  Works with literal (preset) arguments, and dynamic (accepting input) arguments\n* [x]  Works with **any** system, as long as there is a string input\n* [x]  Automatic argument input serialisation\n* [x]  Argument overloading\n* [x]  Automatic pattern generation, e.g. `/command \u003cstring\u003e arg [\u003c*int\u003e \u003cstring...\u003e]`\n* [x]  Argument/command aliases and descriptions\n* [x]  Fast, pre-parsed, type-safe argument handling\n* [x]  Fallback argument handling\n* [x]  Optional thread dispatch (async) execution\n\n### Maven Information\n```xml\n\u003crepository\u003e\n    \u003cid\u003epan-repo\u003c/id\u003e\n    \u003cname\u003ePandaemonium Repository\u003c/name\u003e\n    \u003curl\u003ehttps://gitlab.com/api/v4/projects/18568066/packages/maven\u003c/url\u003e\n\u003c/repository\u003e\n``` \n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003emx.kenzie\u003c/groupId\u003e\n    \u003cartifactId\u003ecommander\u003c/artifactId\u003e\n    \u003cversion\u003e4.0.1\u003c/version\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\nExamples\n---\nSome examples are available at [the Mask v3 Wiki](https://gitlab.com/Pandaemonium/Mask/-/wikis/Commander/Examples) however some of these may now be out-of-date.\n\n#### Exception Handlers\n```java \ncommand(\"test\")\n    .errorHandler((context, throwable) -\u003e {\n        if (!throwable.getMessage().contains(\"potato\"))\n            Overlord.UNSAFE.throwException(ex);\n        context.sender(); // The sender object\n    })\n```\n\n#### Default Behaviour\n```java \ncommand(\"test\")\n    .defaultAction(sender -\u003e sender.println(\"Hello!\"));\n    // Assumes the \"sender\" is a print stream (like System::out)\n```\n\n#### Literal Arguments\n(Assumes the sender has a \"reply\" method - the sender can be anything you want.)\n```java \ncommand(\"test\")\n    .arg(\"xyz\", sender -\u003e {\n        throw new RuntimeException();\n    })\n    .arg(\"foo\", sender -\u003e sender.reply(\"foo\"))\n    .arg(\"bar\", sender -\u003e sender.reply(\"bar\"));\n```\n\nThis generates:\n```css \ntest xyz -\u003e throws exception\ntest foo -\u003e replies with \"foo\"\ntest bar -\u003e replies with \"bar\"\n```\n\n#### Dynamic (Input) Arguments\n(Assumes the sender has a \"reply\" method - the sender can be anything you want.)\n```java \ncommand(\"test\")\n    .arg(\"bar\", sender -\u003e sender.reply(\"blue\"))\n    // Generates '%command-label% bar'\n    .arg(\n        (sender, inputs) -\u003e sender.reply(inputs[0] + \"\"),\n        new ArgBoolean() // inputs[0] will be this!\n    // Generates '%command-label% %arg-label%'\n    ).arg(\"blob\",\n        arg(\n            (sender, inputs) -\u003e sender.reply(inputs[0] + \"\"),\n            new ArgBoolean() // inputs[0] will be this!\n        )\n    );\n    // Generates '%command-label% blob %arg-label%'\n```\n\n```css \ntest bar -\u003e replies with \"blue\"\ntest \u003cboolean\u003e -\u003e replies with boolean input\ntest blob \u003cboolean\u003e -\u003e replies with boolean input\n```\n\nLiteral arguments will always be prioritised over dynamic arguments.\n\nThis means that if you had `/test \u003cstring\u003e` and `/test hello`, passing the argument \"hello\" would ALWAYS trigger the `/test hello` action rather than the dynamic `\u003cstring\u003e` input.\n\n#### Order of Execution\n```java \ncommand(\"test\")\n    .arg(\"bar\", sender -\u003e sender.reply(\"red\"))\n    .arg(\"bar\", sender -\u003e sender.reply(\"blue\"));\n```\n\n```css \ntest bar -\u003e replies with \"red\"\ntest bar -\u003e replies with \"blue\"\n```\n\nIn this situation we have two identical patterns.\nAs they are always tested in order, this means the FIRST one will always be used.\n\nThe result will always be \"red\".\n\n#### Stacking Arguments\nThere are two ways to stack arguments.\n\nSimple:\n```java \ncommand(\"test\")\n    .arg(\"num\",\n        arg(\n            (sender, inputs) -\u003e sender.send(inputs[0] + \", \" + inputs[1]),\n            new ArgInteger(), new ArgInteger()\n        )\n    );\n```\n\n```css \ntest num \u003cint\u003e \u003cint\u003e\n```\n\nIn this case, we have behaviour only for two integers being provided.\nHowever, if only one is provided (e.g. `test num 6`) we have no \n\nComplex:\n```java \ncommand(\"test\")\n    .arg(\"num\",\n        arg(\n            (sender, inputs) -\u003e sender.send(inputs[0] + \"\"),\n            Argument.INTEGER\n        ),\n        arg(\n            (sender, inputs) -\u003e sender.send(inputs[0] + \", \" + inputs[1]),\n            Argument.INTEGER\n        )\n    );\n```\n\n```css \ntest num \u003cint\u003e\ntest num \u003cint\u003e \u003cint\u003e\n```\n\nIn this case we have TWO patterns generated, for one or two integers.\n\nStacking arguments using `arg, arg, ...` will generate a new pattern for each one with the new argument appended.\n\nNOTE: this is equivalent to the following:\n```java \ncommand(\"test\")\n    .arg(\"num\",\n        arg(\n            (sender, inputs) -\u003e sender.send(inputs[0] + \"\"),\n            Argument.INTEGER\n        )\n    )\n    .arg(\"num\",\n        arg(\n            (sender, inputs) -\u003e sender.send(inputs[0] + \", \" + inputs[1]),\n            Argument.INTEGER, Argument.INTEGER\n        )\n    );\n```\n\n```css \ntest num \u003cint\u003e\ntest num \u003cint\u003e \u003cint\u003e\n```\n\nAs you can see, there are multiple ways to generate patterns.\n\nAt runtime, Commander simply resolves your command tree into a map of `patterns -\u003e executions`.\n\nThis means that you can generate the SAME behaviour using completely different trees.\n\n#### Proof of Tree Equivalence\n\nThe following two command trees will be resolved to the same result.\n\n1.\n```java \ncommand(\"tree\")\n    .arg(\"alice\", sender -\u003e {})\n    .arg(\"bob\", sender -\u003e {})\n    .arg(\"cecil\",\n        arg(\"ex1\", sender -\u003e {}),\n        arg(\"ex2\", sender -\u003e {})\n    )\n    .arg(\"cecil\",\n        arg((sender, inputs) -\u003e {},\n            new ArgString()\n        )\n    );\n```\n\n2.\n```java \ncommand(\"tree\")\n    .arg(sender -\u003e {}, \"alice\")\n    .arg(\"bob\", sender -\u003e {})\n    .arg(sender -\u003e {}, \"cecil\", \"ex1\")\n    .arg(sender -\u003e {}, \"cecil\", \"ex1\", \"ex2\")\n    .arg((sender, inputs) -\u003e {},\n        new ArgLiteral(\"cecil\"), new ArgString()\n    );\n```\n\nResult:\n```css \ntree alice\ntree bob\ntree cecil \u003cstring\u003e\ntree cecil ex1\ntree cecil ex1 ex2\n```\n\nThis demonstrates that there are many ways to produce the same result, so it is down to the user's personal preference.\n\n#### Execution Dispatch (Async)\n\nIf you provide an ExecutorService to the command tree, the commands will be dispatched to the service for execution.\nParsing of the arguments will still be done on the original thread.\n\nThis is as simple as:\n```java \ncommand(\"test\")\n    .allowAsyncExecution(Executors.newCachedThreadPool())\n    .defaultAction(sender -\u003e sender.send(\"default\"))\n    .arg(\"foo\", sender -\u003e sender.send(\"foo\"))\n    .arg(\"bar\", sender -\u003e sender.send(\"bar\"));\n```\n\nRemember: if your command has an async executor, you can get a CompletableFuture using `executeAsync` as opposed to the traditional execute method.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderocky%2Fcommander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoderocky%2Fcommander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderocky%2Fcommander/lists"}