@@ -171,19 +171,24 @@ else if (node instanceof ParameterNode<A, ?> parameter) {
171171
172172 List <ParameterNode <A , Object >> flags = filter (command .parameters ().values (), v -> v .isFlag () || v .isSwitch ());
173173 for (List <ParameterNode <A , Object >> permutation : Permutations .generatePermutations (flags )) {
174- List <Argument <?>> path = new ArrayList <>(arguments .size () + permutation .size ());
175- path .addAll (arguments );
174+ List <List <ArgumentColl >> formsPerParameter = new ArrayList <>(permutation .size ());
176175 for (ParameterNode <A , Object > parameter : permutation ) {
177176 if (parameter .isSwitch ()) {
178- ArgumentColl sw = ofSwitch (parameter );
179- path .addAll (sw .arguments ());
177+ formsPerParameter .add (ofSwitchForms (parameter ));
180178 } else if (parameter .isFlag ()) {
181- ArgumentColl argumentColl = ofFlag (parameter );
182- path .addAll (argumentColl .arguments ());
179+ formsPerParameter .add (ofFlagForms (parameter ));
183180 }
184181 }
185182
186- minestomCommand .addSyntax (generateAction (command ), path .toArray (Argument []::new ));
183+ // a switch/flag with a shorthand has two equivalent forms (e.g. --silent
184+ // and -s), each of which must be registered as its own Minestom syntax
185+ for (List <ArgumentColl > combination : cartesianProduct (formsPerParameter )) {
186+ List <Argument <?>> path = new ArrayList <>(arguments );
187+ for (ArgumentColl coll : combination ) {
188+ path .addAll (coll .arguments ());
189+ }
190+ minestomCommand .addSyntax (generateAction (command ), path .toArray (Argument []::new ));
191+ }
187192 }
188193 // we have <= 4 flags, so we create all possible permutations
189194 }
@@ -218,14 +223,70 @@ private ArgumentColl ofSwitch(ParameterNode<A, ?> parameter) {
218223 }
219224
220225 private ArgumentColl ofFlag (ParameterNode <A , ?> parameter ) {
221- ArgumentLiteral first = new ArgumentLiteral (DispatcherSettings .LONG_FORMAT_PREFIX + parameter .flagName ());
226+ return ofFlag (parameter , DispatcherSettings .LONG_FORMAT_PREFIX + parameter .flagName ());
227+ }
228+
229+ private ArgumentColl ofFlag (ParameterNode <A , ?> parameter , String literal ) {
230+ ArgumentLiteral first = new ArgumentLiteral (literal );
222231 first .setCallback (createCallback (parameter ));
223232 return new ArgumentColl (
224233 first ,
225234 toArgument (parameter )
226235 );
227236 }
228237
238+ /**
239+ * Returns every equivalent form a switch may be written as: its long form
240+ * (e.g. {@code --silent}), plus its shorthand form (e.g. {@code -s}) if
241+ * one is defined. Each form must be registered as its own Minestom syntax,
242+ * since {@link ArgumentLiteral} only matches a single fixed string.
243+ */
244+ private List <ArgumentColl > ofSwitchForms (ParameterNode <A , ?> parameter ) {
245+ List <ArgumentColl > forms = new ArrayList <>(2 );
246+ forms .add (ofSwitch (parameter ));
247+ Character shorthand = parameter .shorthand ();
248+ if (shorthand != null ) {
249+ forms .add (new ArgumentColl (
250+ new ArgumentLiteral (DispatcherSettings .SHORT_FORMAT_PREFIX + shorthand )
251+ ));
252+ }
253+ return forms ;
254+ }
255+
256+ /**
257+ * Returns every equivalent form a flag may be written as. See {@link #ofSwitchForms}.
258+ */
259+ private List <ArgumentColl > ofFlagForms (ParameterNode <A , ?> parameter ) {
260+ List <ArgumentColl > forms = new ArrayList <>(2 );
261+ forms .add (ofFlag (parameter ));
262+ Character shorthand = parameter .shorthand ();
263+ if (shorthand != null ) {
264+ forms .add (ofFlag (parameter , DispatcherSettings .SHORT_FORMAT_PREFIX + shorthand ));
265+ }
266+ return forms ;
267+ }
268+
269+ /**
270+ * Computes the cartesian product of the given dimensions, i.e. every
271+ * combination obtained by picking exactly one element from each dimension.
272+ */
273+ private static List <List <ArgumentColl >> cartesianProduct (List <List <ArgumentColl >> dimensions ) {
274+ List <List <ArgumentColl >> result = new ArrayList <>();
275+ result .add (new ArrayList <>());
276+ for (List <ArgumentColl > dimension : dimensions ) {
277+ List <List <ArgumentColl >> next = new ArrayList <>();
278+ for (List <ArgumentColl > partial : result ) {
279+ for (ArgumentColl choice : dimension ) {
280+ List <ArgumentColl > combined = new ArrayList <>(partial );
281+ combined .add (choice );
282+ next .add (combined );
283+ }
284+ }
285+ result = next ;
286+ }
287+ return result ;
288+ }
289+
229290 /**
230291 * Generates a {@link CommandExecutor} that invokes the given command from
231292 * the Minestom-provided context
0 commit comments