001/* 002 * PermissionsEx 003 * Copyright (C) zml and PermissionsEx contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package ca.stellardrift.permissionsex.minecraft.command.argument; 018 019import ca.stellardrift.permissionsex.impl.util.PCollections; 020import ca.stellardrift.permissionsex.minecraft.MinecraftPermissionsEx; 021import ca.stellardrift.permissionsex.minecraft.command.PEXCommandPreprocessor; 022import ca.stellardrift.permissionsex.subject.InvalidIdentifierException; 023import ca.stellardrift.permissionsex.subject.SubjectType; 024import cloud.commandframework.arguments.parser.ArgumentParseResult; 025import cloud.commandframework.arguments.parser.ArgumentParser; 026import cloud.commandframework.context.CommandContext; 027import cloud.commandframework.exceptions.parsing.NoInputProvidedException; 028import org.checkerframework.checker.nullness.qual.NonNull; 029import org.checkerframework.checker.nullness.qual.Nullable; 030 031import java.util.List; 032import java.util.Queue; 033import java.util.function.Function; 034import java.util.stream.Collectors; 035 036public final class SubjectIdentifierParser<C, I> implements ArgumentParser<C, I> { 037 private final boolean contextFree; 038 private final Function<CommandContext<C>, SubjectType<I>> subjectTypeExtractor; 039 040 SubjectIdentifierParser(final SubjectType<I> identifier) { 041 this.subjectTypeExtractor = ctx -> identifier; 042 this.contextFree = true; 043 } 044 045 SubjectIdentifierParser(final Function<CommandContext<C>, SubjectType<I>> subjectTypeExtractor) { 046 this.subjectTypeExtractor = subjectTypeExtractor; 047 this.contextFree = false; 048 } 049 050 @Override 051 public @NonNull ArgumentParseResult<@NonNull I> parse( 052 @NonNull final CommandContext<@NonNull C> commandContext, 053 @NonNull final Queue<@NonNull String> inputQueue 054 ) { 055 final @Nullable String input = inputQueue.peek(); 056 if (input == null) { 057 return ArgumentParseResult.failure(new NoInputProvidedException( 058 SubjectIdentifierParser.class, 059 commandContext) 060 ); 061 } 062 final SubjectType<I> subjectType = this.subjectTypeExtractor.apply(commandContext); 063 @Nullable InvalidIdentifierException possibleException = null; 064 @Nullable I identifier; 065 try { 066 identifier = subjectType.parseIdentifier(input); 067 } catch (final InvalidIdentifierException ex) { 068 possibleException = ex; 069 identifier = subjectType.parseOrCoerceIdentifier(input); 070 } 071 072 if (identifier == null) { 073 return ArgumentParseResult.failure(possibleException); 074 } 075 076 inputQueue.remove(); 077 return ArgumentParseResult.success(identifier); 078 } 079 080 @Override 081 public @NonNull List<@NonNull String> suggestions( 082 @NonNull final CommandContext<C> commandContext, 083 @NonNull final String input 084 ) { 085 final MinecraftPermissionsEx<?> manager = commandContext.get(PEXCommandPreprocessor.PEX_MANAGER); 086 final SubjectType<I> type = this.subjectTypeExtractor.apply(commandContext); 087 if (type == null) { 088 return PCollections.vector(); 089 } 090 // TODO: Include friendly names here? 091 // TODO: Do we want to filter this 092 return manager.engine().subjects(type).allIdentifiers() 093 .limit(100) 094 .map(type::serializeIdentifier) 095 .collect(Collectors.toList()); 096 } 097 098 @Override 099 public boolean isContextFree() { 100 return this.contextFree; 101 } 102 103}