33import com .mojang .brigadier .exceptions .DynamicCommandExceptionType ;
44import com .mojang .brigadier .exceptions .SimpleCommandExceptionType ;
55import dev .jorel .commandapi .UnimplementedMethodException ;
6- import dev .jorel .commandapi .arguments .parser .ParameterGetter ;
76import dev .jorel .commandapi .arguments .parser .Parser ;
7+ import dev .jorel .commandapi .arguments .parser .ParserLiteral ;
8+ import dev .jorel .commandapi .arguments .parser .Result ;
89import dev .jorel .commandapi .arguments .parser .SuggestionProvider ;
910import org .bukkit .Bukkit ;
1011import org .bukkit .entity .Entity ;
1112import org .bukkit .entity .EntityType ;
1213
1314import java .util .UUID ;
15+ import java .util .function .Function ;
1416import java .util .function .Predicate ;
1517
1618public class EntitySelectorParser {
@@ -48,16 +50,12 @@ private EntitySelector build() {
4850 }
4951
5052 // Parsing
51- private static final Parser .Literal isSelectorStart = reader -> {
52- if (!(reader .canRead () && reader .peek () == '@' )) throw ArgumentUtilities .NEXT_BRANCH ;
53- };
54-
55- private static Parser .Literal parseSelector (ParameterGetter <EntitySelectorParser > selectorBuilderGetter ) {
56- return reader -> {
53+ private static ParserLiteral parseSelector (EntitySelectorParser selectorBuilder ) {
54+ return Parser .read (reader -> {
5755 reader .skip (); // skip @
5856 if (!reader .canRead ()) throw ERROR_MISSING_SELECTOR_TYPE .createWithContext (reader );
5957 char selectorCode = reader .read ();
60- EntitySelectorParser selectorBuilder = selectorBuilderGetter . get ();
58+
6159 switch (selectorCode ) {
6260 case 'p' -> {
6361 selectorBuilder .maxResults = 1 ;
@@ -101,29 +99,19 @@ private static Parser.Literal parseSelector(ParameterGetter<EntitySelectorParser
10199 throw ERROR_UNKNOWN_SELECTOR_TYPE .createWithContext (reader , "@" + selectorCode );
102100 }
103101 }
104- };
102+ }). suggests ( suggestSelector ) ;
105103 }
106104
107- private static final Parser .Literal isSelectorOptionsStart = reader -> {
108- if (!(reader .canRead () && reader .peek () == '[' )) throw ArgumentUtilities .NEXT_BRANCH ;
109- };
110-
111- private static Parser .Literal parseSelectorOptions (ParameterGetter <EntitySelectorParser > selectorBuilderGetter ) {
105+ private static ParserLiteral parseSelectorOptions (EntitySelectorParser selectorBuilder ) {
112106 return reader -> {
113107 // TODO: Implement looping to parse these selector options
114108 // I'm pretty sure it would basically reuse many other object parsers as well, so maybe do those first
115109 throw new UnimplementedMethodException ("Entity selectors with options are not supported" );
116110 };
117111 }
118112
119- private static final Parser .Literal isNameStart = reader -> {
120- if (!(reader .canRead () && reader .peek () != ' ' )) throw ERROR_INVALID_NAME_OR_UUID .createWithContext (reader );
121- };
122-
123- private static Parser .Literal parseNameOrUUID (ParameterGetter <EntitySelectorParser > selectorBuilderGetter ) {
124- return reader -> {
125- EntitySelectorParser selectorBuilder = selectorBuilderGetter .get ();
126-
113+ private static ParserLiteral parseNameOrUUID (EntitySelectorParser selectorBuilder ) {
114+ return Parser .read (reader -> {
127115 int start = reader .getCursor ();
128116 String input = reader .readString ();
129117 try {
@@ -132,7 +120,7 @@ private static Parser.Literal parseNameOrUUID(ParameterGetter<EntitySelectorPars
132120 selectorBuilder .includesEntities = true ;
133121 } catch (IllegalArgumentException ignored ) {
134122 // Not a valid UUID string
135- if (input .length () > 16 ) {
123+ if (input .isEmpty () || input . length () > 16 ) {
136124 // Also not a valid player name
137125 reader .setCursor (start );
138126 throw ERROR_INVALID_NAME_OR_UUID .createWithContext (reader );
@@ -143,11 +131,7 @@ private static Parser.Literal parseNameOrUUID(ParameterGetter<EntitySelectorPars
143131 }
144132
145133 selectorBuilder .maxResults = 1 ;
146- };
147- }
148-
149- private static Parser .Argument <EntitySelector > conclude (ParameterGetter <EntitySelectorParser > selectorBuilderGetter ) {
150- return reader -> selectorBuilderGetter .get ().build ();
134+ }).suggests (suggestName );
151135 }
152136
153137 private static final SuggestionProvider suggestName = (context , builder ) -> {
@@ -173,44 +157,43 @@ private static Parser.Argument<EntitySelector> conclude(ParameterGetter<EntitySe
173157 suggestName .addSuggestions (context , builder );
174158 };
175159 private static final SuggestionProvider suggestOpenOptions = (context , builder ) -> builder .suggest ("[" );
176- private static final SuggestionProvider suggestOptionsKeyOrClose = (context , builder ) -> {
177- throw new UnimplementedMethodException ("Entity selectors with options are not supported" );
178- };
179160
180- public static final Parser <EntitySelector > PARSER = Parser
181- .parse (reader -> new EntitySelectorParser ())
182- .suggests (suggestNameOrSelector )
183- .alwaysThrowException ()
184- .continueWith (selectorBuilder ->
185- Parser .tryParse (Parser .read (isSelectorStart )
186- .neverThrowException ()
187- .continueWith (
188- Parser .read (parseSelector (selectorBuilder ))
189- .suggests (suggestSelector )
190- .alwaysThrowException ()
191- .continueWith (
192- Parser .tryParse (Parser .read (isSelectorOptionsStart )
193- .suggests (suggestOpenOptions )
194- .neverThrowException ()
195- .continueWith (
196- Parser .read (parseSelectorOptions (selectorBuilder ))
197- .suggests (suggestOptionsKeyOrClose )
198- .alwaysThrowException ()
199- // Input @?[???]
200- .continueWith (conclude (selectorBuilder ))
201- )
202- ).then (conclude (selectorBuilder )) // Input @?
203- )
204- )
205- ).then (Parser .read (isNameStart )
206- .alwaysThrowException ()
207- .continueWith (
208- Parser .read (parseNameOrUUID (selectorBuilder ))
209- .suggests (suggestName )
210- .alwaysThrowException ()
211- // Input name or uuid
212- .continueWith (conclude (selectorBuilder ))
213- )
214- )
161+ public static final Parser <EntitySelector > parser = reader -> {
162+ if (!reader .canRead ()) {
163+ // Empty input
164+ return Result .withExceptionAndSuggestions (ERROR_INVALID_NAME_OR_UUID .createWithContext (reader ), reader .getCursor (), suggestNameOrSelector );
165+ }
166+
167+ // Build our selector
168+ EntitySelectorParser selectorBuilder = new EntitySelectorParser ();
169+ Function <Result .Void , Result <EntitySelector >> conclude = Result .wrapFunctionResult (success -> selectorBuilder .build ());
170+
171+ if (reader .peek () == '@' ) {
172+ // Looks like selector
173+ return parseSelector (selectorBuilder ).getResult (reader ).continueWith (
174+ // Successfully read selector
175+ success -> {
176+ if (reader .canRead () && reader .peek () == '[' ) {
177+ // Looks like includes selector options
178+ return parseSelectorOptions (selectorBuilder ).getResult (reader ).continueWith (
179+ // If successful, build the final selector
180+ conclude
181+ // Otherwise, pass original exception
182+ );
183+ }
184+
185+ // Otherwise, valid selector, but suggest opening options
186+ return Result .withValueAndSuggestions (selectorBuilder .build (), reader .getCursor (), suggestOpenOptions );
187+ }
188+ // Otherwise pass original exception
189+ );
190+ }
191+
192+ // Looks like name/uuid
193+ return parseNameOrUUID (selectorBuilder ).getResult (reader ).continueWith (
194+ // If successful, build the final selector
195+ conclude
196+ // Otherwise pass original exception
215197 );
198+ };
216199}
0 commit comments