4343 */
4444public abstract class PatternMatchingCommandElement extends CommandElement {
4545 private static final Text nullKeyArg = t ("argument" );
46+ final boolean useRegex ;
4647
47- protected PatternMatchingCommandElement (@ Nullable Text key ) {
48+ /**
49+ * @param yesIWantRegex Specify if you want to allow regex for users of
50+ * the command element. Note that this will open up for DoS attacks.
51+ */
52+ protected PatternMatchingCommandElement (@ Nullable Text key , boolean yesIWantRegex ) {
4853 super (key );
54+ this .useRegex = yesIWantRegex ;
55+ }
56+
57+ protected PatternMatchingCommandElement (@ Nullable Text key ) {
58+ this (key , false );
4959 }
5060
5161 @ Nullable
5262 @ Override
5363 protected Object parseValue (CommandSource source , CommandArgs args ) throws ArgumentParseException {
54- final String unformattedPattern = args .next ();
5564 Iterable <String > choices = getChoices (source );
56-
57- // Check for an exact match before we create the regex.
58- // We do this because anything with ^[abc] would not match [abc]
59- Optional <Object > exactMatch = getExactMatch (choices , unformattedPattern );
60- if (exactMatch .isPresent ()) {
61- // Return this as a collection as this can get transformed by the subclass.
62- return Collections .singleton (exactMatch .get ());
65+ Iterable <Object > ret ;
66+ String arg = args .next ();
67+
68+ if (useRegex ) {
69+ // Check for an exact match before we create the regex.
70+ // We do this because anything with ^[abc] would not match [abc]
71+ Optional <Object > exactMatch = getExactMatch (choices , arg );
72+ if (exactMatch .isPresent ()) {
73+ // Return this as a collection as this can get transformed by the subclass.
74+ return Collections .singleton (exactMatch .get ());
75+ }
76+
77+ Pattern pattern = getFormattedPattern (arg );
78+ ret = Iterables .transform (Iterables .filter (choices , element -> pattern .matcher (element ).find ()), this ::getValue );
79+ } else {
80+ Iterable <String > startsWith = Iterables .filter (choices , element -> element .regionMatches (true , 0 , arg , 0 , arg .length ()));
81+ ret = Iterables .transform (startsWith , this ::getValue );
6382 }
6483
65- Pattern pattern = getFormattedPattern (unformattedPattern );
66- Iterable <Object > ret = Iterables .transform (Iterables .filter (choices , element -> pattern .matcher (element ).find ()), this ::getValue );
67-
6884 if (!ret .iterator ().hasNext ()) {
69- throw args .createError (t ("No values matching pattern '%s' present for %s!" , unformattedPattern , getKey () == null
70- ? nullKeyArg : getKey ()));
85+ throw args .createError (t ("No values matching pattern '%s' present for %s!" , arg , getKey () == null
86+ ? nullKeyArg : getKey ()));
7187 }
7288 return ret ;
7389 }
@@ -77,7 +93,12 @@ public List<String> complete(CommandSource src, CommandArgs args, CommandContext
7793 Iterable <String > choices = getChoices (src );
7894 final Optional <String > nextArg = args .nextIfPresent ();
7995 if (nextArg .isPresent ()) {
80- choices = Iterables .filter (choices , input -> getFormattedPattern (nextArg .get ()).matcher (input ).find ());
96+ if (useRegex ) {
97+ choices = Iterables .filter (choices , input -> getFormattedPattern (nextArg .get ()).matcher (input ).find ());
98+ } else {
99+ String arg = nextArg .get ();
100+ choices = Iterables .filter (choices , input -> input .regionMatches (true , 0 , arg , 0 , arg .length ()));
101+ }
81102 }
82103 return ImmutableList .copyOf (choices );
83104 }
0 commit comments