(DEPLOYED ACF) Updated JavaDocs

This commit is contained in:
Aikar
2019-03-24 10:25:14 -04:00
parent 72d45739c9
commit 8f58676213
10 changed files with 1276 additions and 1192 deletions
@@ -524,7 +524,7 @@ public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseComman
<li class="blockList">
<h4>getCommandHelp</h4>
<pre><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html?is-external=true" title="class or interface in java.lang">@Deprecated</a>
public&nbsp;<a href="../../../co/aikar/commands/CommandHelp.html" title="class in co.aikar.commands">CommandHelp</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.755">getCommandHelp</a>()</pre>
public&nbsp;<a href="../../../co/aikar/commands/CommandHelp.html" title="class in co.aikar.commands">CommandHelp</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.759">getCommandHelp</a>()</pre>
<div class="block"><span class="deprecatedLabel">Deprecated.</span>&nbsp;<span class="deprecationComment">Unstable API</span></div>
</li>
</ul>
@@ -535,7 +535,7 @@ public&nbsp;<a href="../../../co/aikar/commands/CommandHelp.html" title="class i
<li class="blockList">
<h4>showCommandHelp</h4>
<pre><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Deprecated.html?is-external=true" title="class or interface in java.lang">@Deprecated</a>
public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.764">showCommandHelp</a>()</pre>
public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.768">showCommandHelp</a>()</pre>
<div class="block"><span class="deprecatedLabel">Deprecated.</span>&nbsp;<span class="deprecationComment">Unstable API</span></div>
</li>
</ul>
@@ -545,7 +545,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>help</h4>
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.768">help</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;issuer,
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.772">help</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;issuer,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)</pre>
</li>
</ul>
@@ -555,7 +555,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>help</h4>
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.772">help</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer,
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.776">help</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;args)</pre>
</li>
</ul>
@@ -565,7 +565,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>doHelp</h4>
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.776">doHelp</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;issuer,
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.780">doHelp</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;issuer,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>...&nbsp;args)</pre>
</li>
</ul>
@@ -575,7 +575,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>doHelp</h4>
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.780">doHelp</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer,
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.784">doHelp</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>...&nbsp;args)</pre>
</li>
</ul>
@@ -585,7 +585,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>showSyntax</h4>
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.784">showSyntax</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer,
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.788">showSyntax</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer,
<a href="../../../co/aikar/commands/RegisteredCommand.html" title="class in co.aikar.commands">RegisteredCommand</a>&lt;?&gt;&nbsp;cmd)</pre>
</li>
</ul>
@@ -595,7 +595,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>hasPermission</h4>
<pre>public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.791">hasPermission</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;issuer)</pre>
<pre>public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.795">hasPermission</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a>&nbsp;issuer)</pre>
</li>
</ul>
<a name="hasPermission-co.aikar.commands.CommandIssuer-">
@@ -604,7 +604,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>hasPermission</h4>
<pre>public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.795">hasPermission</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer)</pre>
<pre>public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.799">hasPermission</a>(<a href="../../../co/aikar/commands/CommandIssuer.html" title="interface in co.aikar.commands">CommandIssuer</a>&nbsp;issuer)</pre>
</li>
</ul>
<a name="getRequiredPermissions--">
@@ -613,7 +613,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>getRequiredPermissions</h4>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Set.html?is-external=true" title="class or interface in java.util">Set</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.799">getRequiredPermissions</a>()</pre>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Set.html?is-external=true" title="class or interface in java.util">Set</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.803">getRequiredPermissions</a>()</pre>
</li>
</ul>
<a name="requiresPermission-java.lang.String-">
@@ -622,7 +622,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>requiresPermission</h4>
<pre>public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.803">requiresPermission</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;permission)</pre>
<pre>public&nbsp;boolean&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.807">requiresPermission</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;permission)</pre>
</li>
</ul>
<a name="getName--">
@@ -631,7 +631,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>getName</h4>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.807">getName</a>()</pre>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.811">getName</a>()</pre>
</li>
</ul>
<a name="getExceptionHandler--">
@@ -640,7 +640,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>getExceptionHandler</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/ExceptionHandler.html" title="interface in co.aikar.commands">ExceptionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.811">getExceptionHandler</a>()</pre>
<pre>public&nbsp;<a href="../../../co/aikar/commands/ExceptionHandler.html" title="interface in co.aikar.commands">ExceptionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.815">getExceptionHandler</a>()</pre>
</li>
</ul>
<a name="setExceptionHandler-co.aikar.commands.ExceptionHandler-">
@@ -649,7 +649,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>setExceptionHandler</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/BaseCommand.html" title="class in co.aikar.commands">BaseCommand</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.815">setExceptionHandler</a>(<a href="../../../co/aikar/commands/ExceptionHandler.html" title="interface in co.aikar.commands">ExceptionHandler</a>&nbsp;exceptionHandler)</pre>
<pre>public&nbsp;<a href="../../../co/aikar/commands/BaseCommand.html" title="class in co.aikar.commands">BaseCommand</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.819">setExceptionHandler</a>(<a href="../../../co/aikar/commands/ExceptionHandler.html" title="interface in co.aikar.commands">ExceptionHandler</a>&nbsp;exceptionHandler)</pre>
</li>
</ul>
<a name="getDefaultRegisteredCommand--">
@@ -658,7 +658,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>getDefaultRegisteredCommand</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/RegisteredCommand.html" title="class in co.aikar.commands">RegisteredCommand</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.820">getDefaultRegisteredCommand</a>()</pre>
<pre>public&nbsp;<a href="../../../co/aikar/commands/RegisteredCommand.html" title="class in co.aikar.commands">RegisteredCommand</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.824">getDefaultRegisteredCommand</a>()</pre>
</li>
</ul>
<a name="setContextFlags-java.lang.Class-java.lang.String-">
@@ -667,7 +667,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>setContextFlags</h4>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.824">setContextFlags</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html?is-external=true" title="class or interface in java.lang">Class</a>&lt;?&gt;&nbsp;cls,
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.828">setContextFlags</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html?is-external=true" title="class or interface in java.lang">Class</a>&lt;?&gt;&nbsp;cls,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;flags)</pre>
</li>
</ul>
@@ -677,7 +677,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockList">
<li class="blockList">
<h4>getContextFlags</h4>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.828">getContextFlags</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html?is-external=true" title="class or interface in java.lang">Class</a>&lt;?&gt;&nbsp;cls)</pre>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.832">getContextFlags</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html?is-external=true" title="class or interface in java.lang">Class</a>&lt;?&gt;&nbsp;cls)</pre>
</li>
</ul>
<a name="getRegisteredCommands--">
@@ -686,7 +686,7 @@ public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.h
<ul class="blockListLast">
<li class="blockList">
<h4>getRegisteredCommands</h4>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../co/aikar/commands/RegisteredCommand.html" title="class in co.aikar.commands">RegisteredCommand</a>&gt;&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.832">getRegisteredCommands</a>()</pre>
<pre>public&nbsp;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html?is-external=true" title="class or interface in java.util">List</a>&lt;<a href="../../../co/aikar/commands/RegisteredCommand.html" title="class in co.aikar.commands">RegisteredCommand</a>&gt;&nbsp;<a href="../../../src-html/co/aikar/commands/BaseCommand.html#line.836">getRegisteredCommands</a>()</pre>
</li>
</ul>
</li>
@@ -102,7 +102,7 @@
</dl>
<hr>
<br>
<pre>public static interface <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.282">CommandCompletions.AsyncCommandCompletionHandler</a>&lt;C extends <a href="../../../co/aikar/commands/CommandCompletionContext.html" title="class in co.aikar.commands">CommandCompletionContext</a>&gt;
<pre>public static interface <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.302">CommandCompletions.AsyncCommandCompletionHandler</a>&lt;C extends <a href="../../../co/aikar/commands/CommandCompletionContext.html" title="class in co.aikar.commands">CommandCompletionContext</a>&gt;
extends <a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&lt;C&gt;</pre>
</li>
</ul>
@@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";
</dl>
<hr>
<br>
<pre>public static interface <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.278">CommandCompletions.CommandCompletionHandler</a>&lt;C extends <a href="../../../co/aikar/commands/CommandCompletionContext.html" title="class in co.aikar.commands">CommandCompletionContext</a>&gt;</pre>
<pre>public static interface <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.298">CommandCompletions.CommandCompletionHandler</a>&lt;C extends <a href="../../../co/aikar/commands/CommandCompletionContext.html" title="class in co.aikar.commands">CommandCompletionContext</a>&gt;</pre>
</li>
</ul>
</div>
@@ -154,7 +154,7 @@ var activeTableTab = "activeTableTab";
<ul class="blockListLast">
<li class="blockList">
<h4>getCompletions</h4>
<pre><a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html#line.279">getCompletions</a>(<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="type parameter in CommandCompletions.CommandCompletionHandler">C</a>&nbsp;context)
<pre><a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.CommandCompletionHandler.html#line.299">getCompletions</a>(<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="type parameter in CommandCompletions.CommandCompletionHandler">C</a>&nbsp;context)
throws <a href="../../../co/aikar/commands/InvalidCommandArgument.html" title="class in co.aikar.commands">InvalidCommandArgument</a></pre>
<dl>
<dt><span class="throwsLabel">Throws:</span></dt>
@@ -125,7 +125,7 @@
</dl>
<hr>
<br>
<pre>public static class <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.285">CommandCompletions.SyncCompletionRequired</a>
<pre>public static class <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.305">CommandCompletions.SyncCompletionRequired</a>
extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/RuntimeException.html?is-external=true" title="class or interface in java.lang">RuntimeException</a></pre>
<dl>
<dt><span class="seeLabel">See Also:</span></dt>
@@ -194,7 +194,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/RuntimeExce
<ul class="blockListLast">
<li class="blockList">
<h4>SyncCompletionRequired</h4>
<pre>public&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html#line.285">SyncCompletionRequired</a>()</pre>
<pre>public&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.SyncCompletionRequired.html#line.305">SyncCompletionRequired</a>()</pre>
</li>
</ul>
</li>
@@ -108,7 +108,7 @@ var activeTableTab = "activeTableTab";
<li class="blockList">
<hr>
<br>
<pre>public class <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.41">CommandCompletions</a>&lt;C extends <a href="../../../co/aikar/commands/CommandCompletionContext.html" title="class in co.aikar.commands">CommandCompletionContext</a>&gt;
<pre>public class <a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.42">CommandCompletions</a>&lt;C extends <a href="../../../co/aikar/commands/CommandCompletionContext.html" title="class in co.aikar.commands">CommandCompletionContext</a>&gt;
extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html?is-external=true" title="class or interface in java.lang">Object</a></pre>
</li>
</ul>
@@ -249,7 +249,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockListLast">
<li class="blockList">
<h4>CommandCompletions</h4>
<pre>public&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.48">CommandCompletions</a>(<a href="../../../co/aikar/commands/CommandManager.html" title="class in co.aikar.commands">CommandManager</a>&nbsp;manager)</pre>
<pre>public&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.49">CommandCompletions</a>(<a href="../../../co/aikar/commands/CommandManager.html" title="class in co.aikar.commands">CommandManager</a>&nbsp;manager)</pre>
</li>
</ul>
</li>
@@ -266,7 +266,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockList">
<li class="blockList">
<h4>registerCompletion</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.79">registerCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.80">registerCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&lt;<a href="../../../co/aikar/commands/CommandCompletions.html" title="type parameter in CommandCompletions">C</a>&gt;&nbsp;handler)</pre>
<div class="block">Registr a completion handler to provide command completions based on the user input.</div>
<dl>
@@ -283,7 +283,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockList">
<li class="blockList">
<h4>registerAsyncCompletion</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.98">registerAsyncCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.99">registerAsyncCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="../../../co/aikar/commands/CommandCompletions.AsyncCommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.AsyncCommandCompletionHandler</a>&lt;<a href="../../../co/aikar/commands/CommandCompletions.html" title="type parameter in CommandCompletions">C</a>&gt;&nbsp;handler)</pre>
<div class="block">Registr a completion handler to provide command completions based on the user input.
This handler is declared to be safe to be executed asynchronously.
@@ -308,7 +308,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockList">
<li class="blockList">
<h4>registerStaticCompletion</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.112">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.113">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;list)</pre>
<div class="block">Register a static list of command completions that will never change.
Like @CommandCompletion, values are | (PIPE) separated.
@@ -328,7 +328,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockList">
<li class="blockList">
<h4>registerStaticCompletion</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.123">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.124">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>[]&nbsp;completions)</pre>
<div class="block">Register a static list of command completions that will never change</div>
<dl>
@@ -345,7 +345,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockList">
<li class="blockList">
<h4>registerStaticCompletion</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.135">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.136">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html?is-external=true" title="class or interface in java.util.function">Supplier</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&gt;&nbsp;supplier)</pre>
<div class="block">Register a static list of command completions that will never change. The list is obtained from the supplier
immediately as part of this method call.</div>
@@ -363,7 +363,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockList">
<li class="blockList">
<h4>registerStaticCompletion</h4>
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.146">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;<a href="../../../co/aikar/commands/CommandCompletions.CommandCompletionHandler.html" title="interface in co.aikar.commands">CommandCompletions.CommandCompletionHandler</a>&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.147">registerStaticCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html?is-external=true" title="class or interface in java.util">Collection</a>&lt;<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&gt;&nbsp;completions)</pre>
<div class="block">Register a static list of command completions that will never change</div>
<dl>
@@ -380,7 +380,7 @@ extends <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
<ul class="blockListLast">
<li class="blockList">
<h4>setDefaultCompletion</h4>
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.158">setDefaultCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<pre>public&nbsp;void&nbsp;<a href="../../../src-html/co/aikar/commands/CommandCompletions.html#line.159">setDefaultCompletion</a>(<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/String.html?is-external=true" title="class or interface in java.lang">String</a>&nbsp;id,
<a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html?is-external=true" title="class or interface in java.lang">Class</a>...&nbsp;classes)</pre>
<div class="block">Registers a completion handler such as @players to default apply to all command parameters of the specified types
<p>
@@ -693,156 +693,160 @@
<span class="sourceLineNo">685</span> * @return All results to complete the command.<a name="line.685"></a>
<span class="sourceLineNo">686</span> */<a name="line.686"></a>
<span class="sourceLineNo">687</span> private List&lt;String&gt; completeCommand(CommandIssuer issuer, RegisteredCommand cmd, String[] args, String commandLabel, boolean isAsync) {<a name="line.687"></a>
<span class="sourceLineNo">688</span> if (!cmd.hasPermission(issuer) || args.length &gt; cmd.consumeInputResolvers || args.length == 0) {<a name="line.688"></a>
<span class="sourceLineNo">688</span> if (!cmd.hasPermission(issuer) || args.length == 0) {<a name="line.688"></a>
<span class="sourceLineNo">689</span> return Collections.emptyList();<a name="line.689"></a>
<span class="sourceLineNo">690</span> }<a name="line.690"></a>
<span class="sourceLineNo">691</span><a name="line.691"></a>
<span class="sourceLineNo">692</span> List&lt;String&gt; cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync);<a name="line.692"></a>
<span class="sourceLineNo">693</span> return filterTabComplete(args[args.length - 1], cmds);<a name="line.693"></a>
<span class="sourceLineNo">694</span> }<a name="line.694"></a>
<span class="sourceLineNo">692</span> if (!cmd.parameters[cmd.parameters.length - 1].consumesRest &amp;&amp; args.length &gt; cmd.consumeInputResolvers) {<a name="line.692"></a>
<span class="sourceLineNo">693</span> return Collections.emptyList();<a name="line.693"></a>
<span class="sourceLineNo">694</span> }<a name="line.694"></a>
<span class="sourceLineNo">695</span><a name="line.695"></a>
<span class="sourceLineNo">696</span> /**<a name="line.696"></a>
<span class="sourceLineNo">697</span> * Gets the actual args in string form the user typed<a name="line.697"></a>
<span class="sourceLineNo">698</span> * This returns a list of all tab complete options which are possible with the given argument and commands.<a name="line.698"></a>
<span class="sourceLineNo">699</span> *<a name="line.699"></a>
<span class="sourceLineNo">700</span> * @param arg Argument which was pressed tab on.<a name="line.700"></a>
<span class="sourceLineNo">701</span> * @param cmds The possibilities to return.<a name="line.701"></a>
<span class="sourceLineNo">702</span> * @return All possible options. This may be empty.<a name="line.702"></a>
<span class="sourceLineNo">703</span> */<a name="line.703"></a>
<span class="sourceLineNo">704</span> private static List&lt;String&gt; filterTabComplete(String arg, List&lt;String&gt; cmds) {<a name="line.704"></a>
<span class="sourceLineNo">705</span> return cmds.stream()<a name="line.705"></a>
<span class="sourceLineNo">706</span> .distinct()<a name="line.706"></a>
<span class="sourceLineNo">707</span> .filter(cmd -&gt; cmd != null &amp;&amp; (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg)))<a name="line.707"></a>
<span class="sourceLineNo">708</span> .collect(Collectors.toList());<a name="line.708"></a>
<span class="sourceLineNo">709</span> }<a name="line.709"></a>
<span class="sourceLineNo">710</span><a name="line.710"></a>
<span class="sourceLineNo">711</span> /**<a name="line.711"></a>
<span class="sourceLineNo">712</span> * Executes the precommand and sees whether something is wrong. Ideally, you get false from this.<a name="line.712"></a>
<span class="sourceLineNo">713</span> *<a name="line.713"></a>
<span class="sourceLineNo">714</span> * @param commandOperationContext The context to use.<a name="line.714"></a>
<span class="sourceLineNo">715</span> * @param cmd The command executed.<a name="line.715"></a>
<span class="sourceLineNo">716</span> * @param issuer The issuer who executed the command.<a name="line.716"></a>
<span class="sourceLineNo">717</span> * @param args The arguments the issuer provided.<a name="line.717"></a>
<span class="sourceLineNo">718</span> * @return Whether something went wrong.<a name="line.718"></a>
<span class="sourceLineNo">719</span> */<a name="line.719"></a>
<span class="sourceLineNo">720</span> private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) {<a name="line.720"></a>
<span class="sourceLineNo">721</span> Method pre = this.preCommandHandler;<a name="line.721"></a>
<span class="sourceLineNo">722</span> if (pre != null) {<a name="line.722"></a>
<span class="sourceLineNo">723</span> try {<a name="line.723"></a>
<span class="sourceLineNo">724</span> Class&lt;?&gt;[] types = pre.getParameterTypes();<a name="line.724"></a>
<span class="sourceLineNo">725</span> Object[] parameters = new Object[pre.getParameterCount()];<a name="line.725"></a>
<span class="sourceLineNo">726</span> for (int i = 0; i &lt; parameters.length; i++) {<a name="line.726"></a>
<span class="sourceLineNo">727</span> Class&lt;?&gt; type = types[i];<a name="line.727"></a>
<span class="sourceLineNo">728</span> Object issuerObject = issuer.getIssuer();<a name="line.728"></a>
<span class="sourceLineNo">729</span> if (manager.isCommandIssuer(type) &amp;&amp; type.isAssignableFrom(issuerObject.getClass())) {<a name="line.729"></a>
<span class="sourceLineNo">730</span> parameters[i] = issuerObject;<a name="line.730"></a>
<span class="sourceLineNo">731</span> } else if (CommandIssuer.class.isAssignableFrom(type)) {<a name="line.731"></a>
<span class="sourceLineNo">732</span> parameters[i] = issuer;<a name="line.732"></a>
<span class="sourceLineNo">733</span> } else if (RegisteredCommand.class.isAssignableFrom(type)) {<a name="line.733"></a>
<span class="sourceLineNo">734</span> parameters[i] = cmd;<a name="line.734"></a>
<span class="sourceLineNo">735</span> } else if (String[].class.isAssignableFrom((type))) {<a name="line.735"></a>
<span class="sourceLineNo">736</span> parameters[i] = args;<a name="line.736"></a>
<span class="sourceLineNo">737</span> } else {<a name="line.737"></a>
<span class="sourceLineNo">738</span> parameters[i] = null;<a name="line.738"></a>
<span class="sourceLineNo">739</span> }<a name="line.739"></a>
<span class="sourceLineNo">740</span> }<a name="line.740"></a>
<span class="sourceLineNo">741</span><a name="line.741"></a>
<span class="sourceLineNo">742</span> return (boolean) pre.invoke(this, parameters);<a name="line.742"></a>
<span class="sourceLineNo">743</span> } catch (IllegalAccessException | InvocationTargetException e) {<a name="line.743"></a>
<span class="sourceLineNo">744</span> this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e);<a name="line.744"></a>
<span class="sourceLineNo">745</span> }<a name="line.745"></a>
<span class="sourceLineNo">746</span> }<a name="line.746"></a>
<span class="sourceLineNo">747</span> return false;<a name="line.747"></a>
<span class="sourceLineNo">748</span> }<a name="line.748"></a>
<span class="sourceLineNo">749</span><a name="line.749"></a>
<span class="sourceLineNo">750</span> /**<a name="line.750"></a>
<span class="sourceLineNo">751</span> * @deprecated Unstable API<a name="line.751"></a>
<span class="sourceLineNo">752</span> */<a name="line.752"></a>
<span class="sourceLineNo">753</span> @Deprecated<a name="line.753"></a>
<span class="sourceLineNo">754</span> @UnstableAPI<a name="line.754"></a>
<span class="sourceLineNo">755</span> public CommandHelp getCommandHelp() {<a name="line.755"></a>
<span class="sourceLineNo">756</span> return manager.generateCommandHelp();<a name="line.756"></a>
<span class="sourceLineNo">757</span> }<a name="line.757"></a>
<span class="sourceLineNo">758</span><a name="line.758"></a>
<span class="sourceLineNo">759</span> /**<a name="line.759"></a>
<span class="sourceLineNo">760</span> * @deprecated Unstable API<a name="line.760"></a>
<span class="sourceLineNo">761</span> */<a name="line.761"></a>
<span class="sourceLineNo">762</span> @Deprecated<a name="line.762"></a>
<span class="sourceLineNo">763</span> @UnstableAPI<a name="line.763"></a>
<span class="sourceLineNo">764</span> public void showCommandHelp() {<a name="line.764"></a>
<span class="sourceLineNo">765</span> getCommandHelp().showHelp();<a name="line.765"></a>
<span class="sourceLineNo">766</span> }<a name="line.766"></a>
<span class="sourceLineNo">767</span><a name="line.767"></a>
<span class="sourceLineNo">768</span> public void help(Object issuer, String[] args) {<a name="line.768"></a>
<span class="sourceLineNo">769</span> help(manager.getCommandIssuer(issuer), args);<a name="line.769"></a>
<span class="sourceLineNo">696</span> List&lt;String&gt; cmds = manager.getCommandCompletions().of(cmd, issuer, args, isAsync);<a name="line.696"></a>
<span class="sourceLineNo">697</span> return filterTabComplete(args[args.length - 1], cmds);<a name="line.697"></a>
<span class="sourceLineNo">698</span> }<a name="line.698"></a>
<span class="sourceLineNo">699</span><a name="line.699"></a>
<span class="sourceLineNo">700</span> /**<a name="line.700"></a>
<span class="sourceLineNo">701</span> * Gets the actual args in string form the user typed<a name="line.701"></a>
<span class="sourceLineNo">702</span> * This returns a list of all tab complete options which are possible with the given argument and commands.<a name="line.702"></a>
<span class="sourceLineNo">703</span> *<a name="line.703"></a>
<span class="sourceLineNo">704</span> * @param arg Argument which was pressed tab on.<a name="line.704"></a>
<span class="sourceLineNo">705</span> * @param cmds The possibilities to return.<a name="line.705"></a>
<span class="sourceLineNo">706</span> * @return All possible options. This may be empty.<a name="line.706"></a>
<span class="sourceLineNo">707</span> */<a name="line.707"></a>
<span class="sourceLineNo">708</span> private static List&lt;String&gt; filterTabComplete(String arg, List&lt;String&gt; cmds) {<a name="line.708"></a>
<span class="sourceLineNo">709</span> return cmds.stream()<a name="line.709"></a>
<span class="sourceLineNo">710</span> .distinct()<a name="line.710"></a>
<span class="sourceLineNo">711</span> .filter(cmd -&gt; cmd != null &amp;&amp; (arg.isEmpty() || ApacheCommonsLangUtil.startsWithIgnoreCase(cmd, arg)))<a name="line.711"></a>
<span class="sourceLineNo">712</span> .collect(Collectors.toList());<a name="line.712"></a>
<span class="sourceLineNo">713</span> }<a name="line.713"></a>
<span class="sourceLineNo">714</span><a name="line.714"></a>
<span class="sourceLineNo">715</span> /**<a name="line.715"></a>
<span class="sourceLineNo">716</span> * Executes the precommand and sees whether something is wrong. Ideally, you get false from this.<a name="line.716"></a>
<span class="sourceLineNo">717</span> *<a name="line.717"></a>
<span class="sourceLineNo">718</span> * @param commandOperationContext The context to use.<a name="line.718"></a>
<span class="sourceLineNo">719</span> * @param cmd The command executed.<a name="line.719"></a>
<span class="sourceLineNo">720</span> * @param issuer The issuer who executed the command.<a name="line.720"></a>
<span class="sourceLineNo">721</span> * @param args The arguments the issuer provided.<a name="line.721"></a>
<span class="sourceLineNo">722</span> * @return Whether something went wrong.<a name="line.722"></a>
<span class="sourceLineNo">723</span> */<a name="line.723"></a>
<span class="sourceLineNo">724</span> private boolean checkPrecommand(CommandOperationContext commandOperationContext, RegisteredCommand cmd, CommandIssuer issuer, String[] args) {<a name="line.724"></a>
<span class="sourceLineNo">725</span> Method pre = this.preCommandHandler;<a name="line.725"></a>
<span class="sourceLineNo">726</span> if (pre != null) {<a name="line.726"></a>
<span class="sourceLineNo">727</span> try {<a name="line.727"></a>
<span class="sourceLineNo">728</span> Class&lt;?&gt;[] types = pre.getParameterTypes();<a name="line.728"></a>
<span class="sourceLineNo">729</span> Object[] parameters = new Object[pre.getParameterCount()];<a name="line.729"></a>
<span class="sourceLineNo">730</span> for (int i = 0; i &lt; parameters.length; i++) {<a name="line.730"></a>
<span class="sourceLineNo">731</span> Class&lt;?&gt; type = types[i];<a name="line.731"></a>
<span class="sourceLineNo">732</span> Object issuerObject = issuer.getIssuer();<a name="line.732"></a>
<span class="sourceLineNo">733</span> if (manager.isCommandIssuer(type) &amp;&amp; type.isAssignableFrom(issuerObject.getClass())) {<a name="line.733"></a>
<span class="sourceLineNo">734</span> parameters[i] = issuerObject;<a name="line.734"></a>
<span class="sourceLineNo">735</span> } else if (CommandIssuer.class.isAssignableFrom(type)) {<a name="line.735"></a>
<span class="sourceLineNo">736</span> parameters[i] = issuer;<a name="line.736"></a>
<span class="sourceLineNo">737</span> } else if (RegisteredCommand.class.isAssignableFrom(type)) {<a name="line.737"></a>
<span class="sourceLineNo">738</span> parameters[i] = cmd;<a name="line.738"></a>
<span class="sourceLineNo">739</span> } else if (String[].class.isAssignableFrom((type))) {<a name="line.739"></a>
<span class="sourceLineNo">740</span> parameters[i] = args;<a name="line.740"></a>
<span class="sourceLineNo">741</span> } else {<a name="line.741"></a>
<span class="sourceLineNo">742</span> parameters[i] = null;<a name="line.742"></a>
<span class="sourceLineNo">743</span> }<a name="line.743"></a>
<span class="sourceLineNo">744</span> }<a name="line.744"></a>
<span class="sourceLineNo">745</span><a name="line.745"></a>
<span class="sourceLineNo">746</span> return (boolean) pre.invoke(this, parameters);<a name="line.746"></a>
<span class="sourceLineNo">747</span> } catch (IllegalAccessException | InvocationTargetException e) {<a name="line.747"></a>
<span class="sourceLineNo">748</span> this.manager.log(LogLevel.ERROR, "Exception encountered while command pre-processing", e);<a name="line.748"></a>
<span class="sourceLineNo">749</span> }<a name="line.749"></a>
<span class="sourceLineNo">750</span> }<a name="line.750"></a>
<span class="sourceLineNo">751</span> return false;<a name="line.751"></a>
<span class="sourceLineNo">752</span> }<a name="line.752"></a>
<span class="sourceLineNo">753</span><a name="line.753"></a>
<span class="sourceLineNo">754</span> /**<a name="line.754"></a>
<span class="sourceLineNo">755</span> * @deprecated Unstable API<a name="line.755"></a>
<span class="sourceLineNo">756</span> */<a name="line.756"></a>
<span class="sourceLineNo">757</span> @Deprecated<a name="line.757"></a>
<span class="sourceLineNo">758</span> @UnstableAPI<a name="line.758"></a>
<span class="sourceLineNo">759</span> public CommandHelp getCommandHelp() {<a name="line.759"></a>
<span class="sourceLineNo">760</span> return manager.generateCommandHelp();<a name="line.760"></a>
<span class="sourceLineNo">761</span> }<a name="line.761"></a>
<span class="sourceLineNo">762</span><a name="line.762"></a>
<span class="sourceLineNo">763</span> /**<a name="line.763"></a>
<span class="sourceLineNo">764</span> * @deprecated Unstable API<a name="line.764"></a>
<span class="sourceLineNo">765</span> */<a name="line.765"></a>
<span class="sourceLineNo">766</span> @Deprecated<a name="line.766"></a>
<span class="sourceLineNo">767</span> @UnstableAPI<a name="line.767"></a>
<span class="sourceLineNo">768</span> public void showCommandHelp() {<a name="line.768"></a>
<span class="sourceLineNo">769</span> getCommandHelp().showHelp();<a name="line.769"></a>
<span class="sourceLineNo">770</span> }<a name="line.770"></a>
<span class="sourceLineNo">771</span><a name="line.771"></a>
<span class="sourceLineNo">772</span> public void help(CommandIssuer issuer, String[] args) {<a name="line.772"></a>
<span class="sourceLineNo">773</span> issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND);<a name="line.773"></a>
<span class="sourceLineNo">772</span> public void help(Object issuer, String[] args) {<a name="line.772"></a>
<span class="sourceLineNo">773</span> help(manager.getCommandIssuer(issuer), args);<a name="line.773"></a>
<span class="sourceLineNo">774</span> }<a name="line.774"></a>
<span class="sourceLineNo">775</span><a name="line.775"></a>
<span class="sourceLineNo">776</span> public void doHelp(Object issuer, String... args) {<a name="line.776"></a>
<span class="sourceLineNo">777</span> doHelp(manager.getCommandIssuer(issuer), args);<a name="line.777"></a>
<span class="sourceLineNo">776</span> public void help(CommandIssuer issuer, String[] args) {<a name="line.776"></a>
<span class="sourceLineNo">777</span> issuer.sendMessage(MessageType.ERROR, MessageKeys.UNKNOWN_COMMAND);<a name="line.777"></a>
<span class="sourceLineNo">778</span> }<a name="line.778"></a>
<span class="sourceLineNo">779</span><a name="line.779"></a>
<span class="sourceLineNo">780</span> public void doHelp(CommandIssuer issuer, String... args) {<a name="line.780"></a>
<span class="sourceLineNo">781</span> help(issuer, args);<a name="line.781"></a>
<span class="sourceLineNo">780</span> public void doHelp(Object issuer, String... args) {<a name="line.780"></a>
<span class="sourceLineNo">781</span> doHelp(manager.getCommandIssuer(issuer), args);<a name="line.781"></a>
<span class="sourceLineNo">782</span> }<a name="line.782"></a>
<span class="sourceLineNo">783</span><a name="line.783"></a>
<span class="sourceLineNo">784</span> public void showSyntax(CommandIssuer issuer, RegisteredCommand&lt;?&gt; cmd) {<a name="line.784"></a>
<span class="sourceLineNo">785</span> issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX,<a name="line.785"></a>
<span class="sourceLineNo">786</span> "{command}", manager.getCommandPrefix(issuer) + cmd.command,<a name="line.786"></a>
<span class="sourceLineNo">787</span> "{syntax}", cmd.syntaxText<a name="line.787"></a>
<span class="sourceLineNo">788</span> );<a name="line.788"></a>
<span class="sourceLineNo">789</span> }<a name="line.789"></a>
<span class="sourceLineNo">790</span><a name="line.790"></a>
<span class="sourceLineNo">791</span> public boolean hasPermission(Object issuer) {<a name="line.791"></a>
<span class="sourceLineNo">792</span> return hasPermission(manager.getCommandIssuer(issuer));<a name="line.792"></a>
<span class="sourceLineNo">784</span> public void doHelp(CommandIssuer issuer, String... args) {<a name="line.784"></a>
<span class="sourceLineNo">785</span> help(issuer, args);<a name="line.785"></a>
<span class="sourceLineNo">786</span> }<a name="line.786"></a>
<span class="sourceLineNo">787</span><a name="line.787"></a>
<span class="sourceLineNo">788</span> public void showSyntax(CommandIssuer issuer, RegisteredCommand&lt;?&gt; cmd) {<a name="line.788"></a>
<span class="sourceLineNo">789</span> issuer.sendMessage(MessageType.SYNTAX, MessageKeys.INVALID_SYNTAX,<a name="line.789"></a>
<span class="sourceLineNo">790</span> "{command}", manager.getCommandPrefix(issuer) + cmd.command,<a name="line.790"></a>
<span class="sourceLineNo">791</span> "{syntax}", cmd.syntaxText<a name="line.791"></a>
<span class="sourceLineNo">792</span> );<a name="line.792"></a>
<span class="sourceLineNo">793</span> }<a name="line.793"></a>
<span class="sourceLineNo">794</span><a name="line.794"></a>
<span class="sourceLineNo">795</span> public boolean hasPermission(CommandIssuer issuer) {<a name="line.795"></a>
<span class="sourceLineNo">796</span> return this.manager.hasPermission(issuer, getRequiredPermissions());<a name="line.796"></a>
<span class="sourceLineNo">795</span> public boolean hasPermission(Object issuer) {<a name="line.795"></a>
<span class="sourceLineNo">796</span> return hasPermission(manager.getCommandIssuer(issuer));<a name="line.796"></a>
<span class="sourceLineNo">797</span> }<a name="line.797"></a>
<span class="sourceLineNo">798</span><a name="line.798"></a>
<span class="sourceLineNo">799</span> public Set&lt;String&gt; getRequiredPermissions() {<a name="line.799"></a>
<span class="sourceLineNo">800</span> return this.permissions;<a name="line.800"></a>
<span class="sourceLineNo">799</span> public boolean hasPermission(CommandIssuer issuer) {<a name="line.799"></a>
<span class="sourceLineNo">800</span> return this.manager.hasPermission(issuer, getRequiredPermissions());<a name="line.800"></a>
<span class="sourceLineNo">801</span> }<a name="line.801"></a>
<span class="sourceLineNo">802</span><a name="line.802"></a>
<span class="sourceLineNo">803</span> public boolean requiresPermission(String permission) {<a name="line.803"></a>
<span class="sourceLineNo">804</span> return getRequiredPermissions().contains(permission);<a name="line.804"></a>
<span class="sourceLineNo">803</span> public Set&lt;String&gt; getRequiredPermissions() {<a name="line.803"></a>
<span class="sourceLineNo">804</span> return this.permissions;<a name="line.804"></a>
<span class="sourceLineNo">805</span> }<a name="line.805"></a>
<span class="sourceLineNo">806</span><a name="line.806"></a>
<span class="sourceLineNo">807</span> public String getName() {<a name="line.807"></a>
<span class="sourceLineNo">808</span> return commandName;<a name="line.808"></a>
<span class="sourceLineNo">807</span> public boolean requiresPermission(String permission) {<a name="line.807"></a>
<span class="sourceLineNo">808</span> return getRequiredPermissions().contains(permission);<a name="line.808"></a>
<span class="sourceLineNo">809</span> }<a name="line.809"></a>
<span class="sourceLineNo">810</span><a name="line.810"></a>
<span class="sourceLineNo">811</span> public ExceptionHandler getExceptionHandler() {<a name="line.811"></a>
<span class="sourceLineNo">812</span> return exceptionHandler;<a name="line.812"></a>
<span class="sourceLineNo">811</span> public String getName() {<a name="line.811"></a>
<span class="sourceLineNo">812</span> return commandName;<a name="line.812"></a>
<span class="sourceLineNo">813</span> }<a name="line.813"></a>
<span class="sourceLineNo">814</span><a name="line.814"></a>
<span class="sourceLineNo">815</span> public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) {<a name="line.815"></a>
<span class="sourceLineNo">816</span> this.exceptionHandler = exceptionHandler;<a name="line.816"></a>
<span class="sourceLineNo">817</span> return this;<a name="line.817"></a>
<span class="sourceLineNo">818</span> }<a name="line.818"></a>
<span class="sourceLineNo">819</span><a name="line.819"></a>
<span class="sourceLineNo">820</span> public RegisteredCommand getDefaultRegisteredCommand() {<a name="line.820"></a>
<span class="sourceLineNo">821</span> return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT));<a name="line.821"></a>
<span class="sourceLineNo">815</span> public ExceptionHandler getExceptionHandler() {<a name="line.815"></a>
<span class="sourceLineNo">816</span> return exceptionHandler;<a name="line.816"></a>
<span class="sourceLineNo">817</span> }<a name="line.817"></a>
<span class="sourceLineNo">818</span><a name="line.818"></a>
<span class="sourceLineNo">819</span> public BaseCommand setExceptionHandler(ExceptionHandler exceptionHandler) {<a name="line.819"></a>
<span class="sourceLineNo">820</span> this.exceptionHandler = exceptionHandler;<a name="line.820"></a>
<span class="sourceLineNo">821</span> return this;<a name="line.821"></a>
<span class="sourceLineNo">822</span> }<a name="line.822"></a>
<span class="sourceLineNo">823</span><a name="line.823"></a>
<span class="sourceLineNo">824</span> public String setContextFlags(Class&lt;?&gt; cls, String flags) {<a name="line.824"></a>
<span class="sourceLineNo">825</span> return this.contextFlags.put(cls, flags);<a name="line.825"></a>
<span class="sourceLineNo">824</span> public RegisteredCommand getDefaultRegisteredCommand() {<a name="line.824"></a>
<span class="sourceLineNo">825</span> return ACFUtil.getFirstElement(this.subCommands.get(DEFAULT));<a name="line.825"></a>
<span class="sourceLineNo">826</span> }<a name="line.826"></a>
<span class="sourceLineNo">827</span><a name="line.827"></a>
<span class="sourceLineNo">828</span> public String getContextFlags(Class&lt;?&gt; cls) {<a name="line.828"></a>
<span class="sourceLineNo">829</span> return this.contextFlags.get(cls);<a name="line.829"></a>
<span class="sourceLineNo">828</span> public String setContextFlags(Class&lt;?&gt; cls, String flags) {<a name="line.828"></a>
<span class="sourceLineNo">829</span> return this.contextFlags.put(cls, flags);<a name="line.829"></a>
<span class="sourceLineNo">830</span> }<a name="line.830"></a>
<span class="sourceLineNo">831</span><a name="line.831"></a>
<span class="sourceLineNo">832</span> public List&lt;RegisteredCommand&gt; getRegisteredCommands() {<a name="line.832"></a>
<span class="sourceLineNo">833</span> List&lt;RegisteredCommand&gt; registeredCommands = new ArrayList&lt;&gt;();<a name="line.833"></a>
<span class="sourceLineNo">834</span> registeredCommands.addAll(this.subCommands.values());<a name="line.834"></a>
<span class="sourceLineNo">835</span> return registeredCommands;<a name="line.835"></a>
<span class="sourceLineNo">836</span> }<a name="line.836"></a>
<span class="sourceLineNo">837</span>}<a name="line.837"></a>
<span class="sourceLineNo">832</span> public String getContextFlags(Class&lt;?&gt; cls) {<a name="line.832"></a>
<span class="sourceLineNo">833</span> return this.contextFlags.get(cls);<a name="line.833"></a>
<span class="sourceLineNo">834</span> }<a name="line.834"></a>
<span class="sourceLineNo">835</span><a name="line.835"></a>
<span class="sourceLineNo">836</span> public List&lt;RegisteredCommand&gt; getRegisteredCommands() {<a name="line.836"></a>
<span class="sourceLineNo">837</span> List&lt;RegisteredCommand&gt; registeredCommands = new ArrayList&lt;&gt;();<a name="line.837"></a>
<span class="sourceLineNo">838</span> registeredCommands.addAll(this.subCommands.values());<a name="line.838"></a>
<span class="sourceLineNo">839</span> return registeredCommands;<a name="line.839"></a>
<span class="sourceLineNo">840</span> }<a name="line.840"></a>
<span class="sourceLineNo">841</span>}<a name="line.841"></a>
@@ -31,269 +31,289 @@
<span class="sourceLineNo">023</span><a name="line.23"></a>
<span class="sourceLineNo">024</span>package co.aikar.commands;<a name="line.24"></a>
<span class="sourceLineNo">025</span><a name="line.25"></a>
<span class="sourceLineNo">026</span>import org.jetbrains.annotations.NotNull;<a name="line.26"></a>
<span class="sourceLineNo">027</span><a name="line.27"></a>
<span class="sourceLineNo">028</span>import java.util.ArrayList;<a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.Arrays;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Collection;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collections;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.HashMap;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.List;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.Map;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.function.Supplier;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.stream.Collectors;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.IntStream;<a name="line.37"></a>
<span class="sourceLineNo">038</span><a name="line.38"></a>
<span class="sourceLineNo">026</span>import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;<a name="line.26"></a>
<span class="sourceLineNo">027</span>import org.jetbrains.annotations.NotNull;<a name="line.27"></a>
<span class="sourceLineNo">028</span><a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.ArrayList;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Arrays;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collection;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.Collections;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.HashMap;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.List;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.Map;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.function.Supplier;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.Collectors;<a name="line.37"></a>
<span class="sourceLineNo">038</span>import java.util.stream.IntStream;<a name="line.38"></a>
<span class="sourceLineNo">039</span><a name="line.39"></a>
<span class="sourceLineNo">040</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.40"></a>
<span class="sourceLineNo">041</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.41"></a>
<span class="sourceLineNo">042</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.42"></a>
<span class="sourceLineNo">043</span> private final CommandManager manager;<a name="line.43"></a>
<span class="sourceLineNo">044</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.44"></a>
<span class="sourceLineNo">045</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span><a name="line.47"></a>
<span class="sourceLineNo">048</span> public CommandCompletions(CommandManager manager) {<a name="line.48"></a>
<span class="sourceLineNo">049</span> this.manager = manager;<a name="line.49"></a>
<span class="sourceLineNo">050</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.53"></a>
<span class="sourceLineNo">054</span> String config = c.getConfig();<a name="line.54"></a>
<span class="sourceLineNo">055</span> if (config == null) {<a name="line.55"></a>
<span class="sourceLineNo">056</span> return Collections.emptyList();<a name="line.56"></a>
<span class="sourceLineNo">057</span> }<a name="line.57"></a>
<span class="sourceLineNo">058</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.58"></a>
<span class="sourceLineNo">059</span> int start;<a name="line.59"></a>
<span class="sourceLineNo">060</span> int end;<a name="line.60"></a>
<span class="sourceLineNo">061</span> if (ranges.length != 2) {<a name="line.61"></a>
<span class="sourceLineNo">062</span> start = 0;<a name="line.62"></a>
<span class="sourceLineNo">063</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.63"></a>
<span class="sourceLineNo">064</span> } else {<a name="line.64"></a>
<span class="sourceLineNo">065</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.65"></a>
<span class="sourceLineNo">066</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> }<a name="line.67"></a>
<span class="sourceLineNo">068</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.68"></a>
<span class="sourceLineNo">069</span> });<a name="line.69"></a>
<span class="sourceLineNo">070</span> }<a name="line.70"></a>
<span class="sourceLineNo">071</span><a name="line.71"></a>
<span class="sourceLineNo">072</span> /**<a name="line.72"></a>
<span class="sourceLineNo">073</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.73"></a>
<span class="sourceLineNo">074</span> *<a name="line.74"></a>
<span class="sourceLineNo">075</span> * @param id<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param handler<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @return<a name="line.77"></a>
<span class="sourceLineNo">078</span> */<a name="line.78"></a>
<span class="sourceLineNo">079</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.79"></a>
<span class="sourceLineNo">080</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.80"></a>
<span class="sourceLineNo">081</span> }<a name="line.81"></a>
<span class="sourceLineNo">082</span><a name="line.82"></a>
<span class="sourceLineNo">083</span> /**<a name="line.83"></a>
<span class="sourceLineNo">084</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.84"></a>
<span class="sourceLineNo">085</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * &lt;p&gt;<a name="line.86"></a>
<span class="sourceLineNo">087</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.87"></a>
<span class="sourceLineNo">088</span> * your handler will be executed on the main thread.<a name="line.88"></a>
<span class="sourceLineNo">089</span> * &lt;p&gt;<a name="line.89"></a>
<span class="sourceLineNo">090</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.90"></a>
<span class="sourceLineNo">091</span> * &lt;p&gt;<a name="line.91"></a>
<span class="sourceLineNo">092</span> * Use context.isAsync() to determine if you are async or not.<a name="line.92"></a>
<span class="sourceLineNo">093</span> *<a name="line.93"></a>
<span class="sourceLineNo">094</span> * @param id<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param handler<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @return<a name="line.96"></a>
<span class="sourceLineNo">097</span> */<a name="line.97"></a>
<span class="sourceLineNo">098</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.98"></a>
<span class="sourceLineNo">099</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.99"></a>
<span class="sourceLineNo">100</span> }<a name="line.100"></a>
<span class="sourceLineNo">101</span><a name="line.101"></a>
<span class="sourceLineNo">102</span> /**<a name="line.102"></a>
<span class="sourceLineNo">103</span> * Register a static list of command completions that will never change.<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * &lt;p&gt;<a name="line.105"></a>
<span class="sourceLineNo">106</span> * Example: foo|bar|baz<a name="line.106"></a>
<span class="sourceLineNo">107</span> *<a name="line.107"></a>
<span class="sourceLineNo">108</span> * @param id<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param list<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @return<a name="line.110"></a>
<span class="sourceLineNo">111</span> */<a name="line.111"></a>
<span class="sourceLineNo">112</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.112"></a>
<span class="sourceLineNo">113</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.113"></a>
<span class="sourceLineNo">114</span> }<a name="line.114"></a>
<span class="sourceLineNo">115</span><a name="line.115"></a>
<span class="sourceLineNo">116</span> /**<a name="line.116"></a>
<span class="sourceLineNo">117</span> * Register a static list of command completions that will never change<a name="line.117"></a>
<span class="sourceLineNo">118</span> *<a name="line.118"></a>
<span class="sourceLineNo">119</span> * @param id<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param completions<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @return<a name="line.121"></a>
<span class="sourceLineNo">122</span> */<a name="line.122"></a>
<span class="sourceLineNo">123</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.123"></a>
<span class="sourceLineNo">124</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.124"></a>
<span class="sourceLineNo">125</span> }<a name="line.125"></a>
<span class="sourceLineNo">126</span><a name="line.126"></a>
<span class="sourceLineNo">127</span> /**<a name="line.127"></a>
<span class="sourceLineNo">128</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.128"></a>
<span class="sourceLineNo">129</span> * immediately as part of this method call.<a name="line.129"></a>
<span class="sourceLineNo">130</span> *<a name="line.130"></a>
<span class="sourceLineNo">131</span> * @param id<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param supplier<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @return<a name="line.133"></a>
<span class="sourceLineNo">134</span> */<a name="line.134"></a>
<span class="sourceLineNo">135</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.135"></a>
<span class="sourceLineNo">136</span> return registerStaticCompletion(id, supplier.get());<a name="line.136"></a>
<span class="sourceLineNo">137</span> }<a name="line.137"></a>
<span class="sourceLineNo">138</span><a name="line.138"></a>
<span class="sourceLineNo">139</span> /**<a name="line.139"></a>
<span class="sourceLineNo">140</span> * Register a static list of command completions that will never change<a name="line.140"></a>
<span class="sourceLineNo">141</span> *<a name="line.141"></a>
<span class="sourceLineNo">142</span> * @param id<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param completions<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @return<a name="line.144"></a>
<span class="sourceLineNo">145</span> */<a name="line.145"></a>
<span class="sourceLineNo">146</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.146"></a>
<span class="sourceLineNo">147</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.147"></a>
<span class="sourceLineNo">148</span> }<a name="line.148"></a>
<span class="sourceLineNo">149</span><a name="line.149"></a>
<span class="sourceLineNo">150</span> /**<a name="line.150"></a>
<span class="sourceLineNo">151</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.151"></a>
<span class="sourceLineNo">152</span> * &lt;p&gt;<a name="line.152"></a>
<span class="sourceLineNo">153</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.153"></a>
<span class="sourceLineNo">154</span> *<a name="line.154"></a>
<span class="sourceLineNo">155</span> * @param id<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param classes<a name="line.156"></a>
<span class="sourceLineNo">157</span> */<a name="line.157"></a>
<span class="sourceLineNo">158</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.158"></a>
<span class="sourceLineNo">159</span> // get completion with specified id<a name="line.159"></a>
<span class="sourceLineNo">160</span> id = prepareCompletionId(id);<a name="line.160"></a>
<span class="sourceLineNo">161</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span><a name="line.162"></a>
<span class="sourceLineNo">163</span> if (completion == null) {<a name="line.163"></a>
<span class="sourceLineNo">164</span> // Throw something because no completion with specified id<a name="line.164"></a>
<span class="sourceLineNo">165</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.165"></a>
<span class="sourceLineNo">166</span> }<a name="line.166"></a>
<span class="sourceLineNo">167</span><a name="line.167"></a>
<span class="sourceLineNo">168</span> for (Class clazz : classes) {<a name="line.168"></a>
<span class="sourceLineNo">169</span> defaultCompletions.put(clazz, id);<a name="line.169"></a>
<span class="sourceLineNo">170</span> }<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span><a name="line.172"></a>
<span class="sourceLineNo">173</span> @NotNull<a name="line.173"></a>
<span class="sourceLineNo">174</span> private static String prepareCompletionId(String id) {<a name="line.174"></a>
<span class="sourceLineNo">175</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.175"></a>
<span class="sourceLineNo">176</span> }<a name="line.176"></a>
<span class="sourceLineNo">177</span><a name="line.177"></a>
<span class="sourceLineNo">178</span> @NotNull<a name="line.178"></a>
<span class="sourceLineNo">179</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.179"></a>
<span class="sourceLineNo">180</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.180"></a>
<span class="sourceLineNo">181</span> final int argIndex = args.length - 1;<a name="line.181"></a>
<span class="sourceLineNo">182</span><a name="line.182"></a>
<span class="sourceLineNo">183</span> String input = args[argIndex];<a name="line.183"></a>
<span class="sourceLineNo">184</span><a name="line.184"></a>
<span class="sourceLineNo">185</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.185"></a>
<span class="sourceLineNo">186</span> if (completion == null || "*".equals(completion)) {<a name="line.186"></a>
<span class="sourceLineNo">187</span> completion = findDefaultCompletion(cmd, args);<a name="line.187"></a>
<span class="sourceLineNo">188</span> }<a name="line.188"></a>
<span class="sourceLineNo">189</span><a name="line.189"></a>
<span class="sourceLineNo">190</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.190"></a>
<span class="sourceLineNo">191</span> String last = completions[completions.length - 1];<a name="line.191"></a>
<span class="sourceLineNo">192</span> if (last.startsWith("repeat@")) {<a name="line.192"></a>
<span class="sourceLineNo">193</span> completion = last;<a name="line.193"></a>
<span class="sourceLineNo">194</span> }<a name="line.194"></a>
<span class="sourceLineNo">195</span> }<a name="line.195"></a>
<span class="sourceLineNo">196</span><a name="line.196"></a>
<span class="sourceLineNo">197</span> if (completion == null) {<a name="line.197"></a>
<span class="sourceLineNo">198</span> return Collections.singletonList(input);<a name="line.198"></a>
<span class="sourceLineNo">199</span> }<a name="line.199"></a>
<span class="sourceLineNo">200</span><a name="line.200"></a>
<span class="sourceLineNo">201</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">040</span><a name="line.40"></a>
<span class="sourceLineNo">041</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.41"></a>
<span class="sourceLineNo">042</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.42"></a>
<span class="sourceLineNo">043</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.43"></a>
<span class="sourceLineNo">044</span> private final CommandManager manager;<a name="line.44"></a>
<span class="sourceLineNo">045</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.47"></a>
<span class="sourceLineNo">048</span><a name="line.48"></a>
<span class="sourceLineNo">049</span> public CommandCompletions(CommandManager manager) {<a name="line.49"></a>
<span class="sourceLineNo">050</span> this.manager = manager;<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.53"></a>
<span class="sourceLineNo">054</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.54"></a>
<span class="sourceLineNo">055</span> String config = c.getConfig();<a name="line.55"></a>
<span class="sourceLineNo">056</span> if (config == null) {<a name="line.56"></a>
<span class="sourceLineNo">057</span> return Collections.emptyList();<a name="line.57"></a>
<span class="sourceLineNo">058</span> }<a name="line.58"></a>
<span class="sourceLineNo">059</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.59"></a>
<span class="sourceLineNo">060</span> int start;<a name="line.60"></a>
<span class="sourceLineNo">061</span> int end;<a name="line.61"></a>
<span class="sourceLineNo">062</span> if (ranges.length != 2) {<a name="line.62"></a>
<span class="sourceLineNo">063</span> start = 0;<a name="line.63"></a>
<span class="sourceLineNo">064</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.64"></a>
<span class="sourceLineNo">065</span> } else {<a name="line.65"></a>
<span class="sourceLineNo">066</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.67"></a>
<span class="sourceLineNo">068</span> }<a name="line.68"></a>
<span class="sourceLineNo">069</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.69"></a>
<span class="sourceLineNo">070</span> });<a name="line.70"></a>
<span class="sourceLineNo">071</span> }<a name="line.71"></a>
<span class="sourceLineNo">072</span><a name="line.72"></a>
<span class="sourceLineNo">073</span> /**<a name="line.73"></a>
<span class="sourceLineNo">074</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.74"></a>
<span class="sourceLineNo">075</span> *<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param id<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @param handler<a name="line.77"></a>
<span class="sourceLineNo">078</span> * @return<a name="line.78"></a>
<span class="sourceLineNo">079</span> */<a name="line.79"></a>
<span class="sourceLineNo">080</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.80"></a>
<span class="sourceLineNo">081</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.81"></a>
<span class="sourceLineNo">082</span> }<a name="line.82"></a>
<span class="sourceLineNo">083</span><a name="line.83"></a>
<span class="sourceLineNo">084</span> /**<a name="line.84"></a>
<span class="sourceLineNo">085</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.86"></a>
<span class="sourceLineNo">087</span> * &lt;p&gt;<a name="line.87"></a>
<span class="sourceLineNo">088</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.88"></a>
<span class="sourceLineNo">089</span> * your handler will be executed on the main thread.<a name="line.89"></a>
<span class="sourceLineNo">090</span> * &lt;p&gt;<a name="line.90"></a>
<span class="sourceLineNo">091</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.91"></a>
<span class="sourceLineNo">092</span> * &lt;p&gt;<a name="line.92"></a>
<span class="sourceLineNo">093</span> * Use context.isAsync() to determine if you are async or not.<a name="line.93"></a>
<span class="sourceLineNo">094</span> *<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param id<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @param handler<a name="line.96"></a>
<span class="sourceLineNo">097</span> * @return<a name="line.97"></a>
<span class="sourceLineNo">098</span> */<a name="line.98"></a>
<span class="sourceLineNo">099</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.99"></a>
<span class="sourceLineNo">100</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.100"></a>
<span class="sourceLineNo">101</span> }<a name="line.101"></a>
<span class="sourceLineNo">102</span><a name="line.102"></a>
<span class="sourceLineNo">103</span> /**<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Register a static list of command completions that will never change.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.105"></a>
<span class="sourceLineNo">106</span> * &lt;p&gt;<a name="line.106"></a>
<span class="sourceLineNo">107</span> * Example: foo|bar|baz<a name="line.107"></a>
<span class="sourceLineNo">108</span> *<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param id<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @param list<a name="line.110"></a>
<span class="sourceLineNo">111</span> * @return<a name="line.111"></a>
<span class="sourceLineNo">112</span> */<a name="line.112"></a>
<span class="sourceLineNo">113</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.113"></a>
<span class="sourceLineNo">114</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.114"></a>
<span class="sourceLineNo">115</span> }<a name="line.115"></a>
<span class="sourceLineNo">116</span><a name="line.116"></a>
<span class="sourceLineNo">117</span> /**<a name="line.117"></a>
<span class="sourceLineNo">118</span> * Register a static list of command completions that will never change<a name="line.118"></a>
<span class="sourceLineNo">119</span> *<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param id<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @param completions<a name="line.121"></a>
<span class="sourceLineNo">122</span> * @return<a name="line.122"></a>
<span class="sourceLineNo">123</span> */<a name="line.123"></a>
<span class="sourceLineNo">124</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.124"></a>
<span class="sourceLineNo">125</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.125"></a>
<span class="sourceLineNo">126</span> }<a name="line.126"></a>
<span class="sourceLineNo">127</span><a name="line.127"></a>
<span class="sourceLineNo">128</span> /**<a name="line.128"></a>
<span class="sourceLineNo">129</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.129"></a>
<span class="sourceLineNo">130</span> * immediately as part of this method call.<a name="line.130"></a>
<span class="sourceLineNo">131</span> *<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param id<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @param supplier<a name="line.133"></a>
<span class="sourceLineNo">134</span> * @return<a name="line.134"></a>
<span class="sourceLineNo">135</span> */<a name="line.135"></a>
<span class="sourceLineNo">136</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.136"></a>
<span class="sourceLineNo">137</span> return registerStaticCompletion(id, supplier.get());<a name="line.137"></a>
<span class="sourceLineNo">138</span> }<a name="line.138"></a>
<span class="sourceLineNo">139</span><a name="line.139"></a>
<span class="sourceLineNo">140</span> /**<a name="line.140"></a>
<span class="sourceLineNo">141</span> * Register a static list of command completions that will never change<a name="line.141"></a>
<span class="sourceLineNo">142</span> *<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param id<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @param completions<a name="line.144"></a>
<span class="sourceLineNo">145</span> * @return<a name="line.145"></a>
<span class="sourceLineNo">146</span> */<a name="line.146"></a>
<span class="sourceLineNo">147</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.147"></a>
<span class="sourceLineNo">148</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.148"></a>
<span class="sourceLineNo">149</span> }<a name="line.149"></a>
<span class="sourceLineNo">150</span><a name="line.150"></a>
<span class="sourceLineNo">151</span> /**<a name="line.151"></a>
<span class="sourceLineNo">152</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.152"></a>
<span class="sourceLineNo">153</span> * &lt;p&gt;<a name="line.153"></a>
<span class="sourceLineNo">154</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.154"></a>
<span class="sourceLineNo">155</span> *<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param id<a name="line.156"></a>
<span class="sourceLineNo">157</span> * @param classes<a name="line.157"></a>
<span class="sourceLineNo">158</span> */<a name="line.158"></a>
<span class="sourceLineNo">159</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.159"></a>
<span class="sourceLineNo">160</span> // get completion with specified id<a name="line.160"></a>
<span class="sourceLineNo">161</span> id = prepareCompletionId(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.162"></a>
<span class="sourceLineNo">163</span><a name="line.163"></a>
<span class="sourceLineNo">164</span> if (completion == null) {<a name="line.164"></a>
<span class="sourceLineNo">165</span> // Throw something because no completion with specified id<a name="line.165"></a>
<span class="sourceLineNo">166</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.166"></a>
<span class="sourceLineNo">167</span> }<a name="line.167"></a>
<span class="sourceLineNo">168</span><a name="line.168"></a>
<span class="sourceLineNo">169</span> for (Class clazz : classes) {<a name="line.169"></a>
<span class="sourceLineNo">170</span> defaultCompletions.put(clazz, id);<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span> }<a name="line.172"></a>
<span class="sourceLineNo">173</span><a name="line.173"></a>
<span class="sourceLineNo">174</span> @NotNull<a name="line.174"></a>
<span class="sourceLineNo">175</span> private static String prepareCompletionId(String id) {<a name="line.175"></a>
<span class="sourceLineNo">176</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.176"></a>
<span class="sourceLineNo">177</span> }<a name="line.177"></a>
<span class="sourceLineNo">178</span><a name="line.178"></a>
<span class="sourceLineNo">179</span> @NotNull<a name="line.179"></a>
<span class="sourceLineNo">180</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.180"></a>
<span class="sourceLineNo">181</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.181"></a>
<span class="sourceLineNo">182</span> final int argIndex = args.length - 1;<a name="line.182"></a>
<span class="sourceLineNo">183</span><a name="line.183"></a>
<span class="sourceLineNo">184</span> String input = args[argIndex];<a name="line.184"></a>
<span class="sourceLineNo">185</span><a name="line.185"></a>
<span class="sourceLineNo">186</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.186"></a>
<span class="sourceLineNo">187</span> if (completion == null || "*".equals(completion)) {<a name="line.187"></a>
<span class="sourceLineNo">188</span> completion = findDefaultCompletion(cmd, args);<a name="line.188"></a>
<span class="sourceLineNo">189</span> }<a name="line.189"></a>
<span class="sourceLineNo">190</span><a name="line.190"></a>
<span class="sourceLineNo">191</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.191"></a>
<span class="sourceLineNo">192</span> String last = completions[completions.length - 1];<a name="line.192"></a>
<span class="sourceLineNo">193</span> if (last.startsWith("repeat@")) {<a name="line.193"></a>
<span class="sourceLineNo">194</span> completion = last;<a name="line.194"></a>
<span class="sourceLineNo">195</span> } else if (argIndex &gt;= completions.length &amp;&amp; cmd.parameters[cmd.parameters.length - 1].consumesRest) {<a name="line.195"></a>
<span class="sourceLineNo">196</span> completion = last;<a name="line.196"></a>
<span class="sourceLineNo">197</span> }<a name="line.197"></a>
<span class="sourceLineNo">198</span> }<a name="line.198"></a>
<span class="sourceLineNo">199</span><a name="line.199"></a>
<span class="sourceLineNo">200</span> if (completion == null) {<a name="line.200"></a>
<span class="sourceLineNo">201</span> return Collections.singletonList(input);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">203</span><a name="line.203"></a>
<span class="sourceLineNo">204</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.204"></a>
<span class="sourceLineNo">205</span> int i = 0;<a name="line.205"></a>
<span class="sourceLineNo">206</span> for (CommandParameter param : cmd.parameters) {<a name="line.206"></a>
<span class="sourceLineNo">207</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> Class type = param.getType();<a name="line.208"></a>
<span class="sourceLineNo">209</span> while (type != null) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> String completion = this.defaultCompletions.get(type);<a name="line.210"></a>
<span class="sourceLineNo">211</span> if (completion != null) {<a name="line.211"></a>
<span class="sourceLineNo">212</span> return completion;<a name="line.212"></a>
<span class="sourceLineNo">213</span> }<a name="line.213"></a>
<span class="sourceLineNo">214</span> type = type.getSuperclass();<a name="line.214"></a>
<span class="sourceLineNo">215</span> }<a name="line.215"></a>
<span class="sourceLineNo">216</span> if (param.getType().isEnum()) {<a name="line.216"></a>
<span class="sourceLineNo">217</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.217"></a>
<span class="sourceLineNo">218</span> //noinspection unchecked<a name="line.218"></a>
<span class="sourceLineNo">219</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.219"></a>
<span class="sourceLineNo">220</span> return DEFAULT_ENUM_ID;<a name="line.220"></a>
<span class="sourceLineNo">221</span> }<a name="line.221"></a>
<span class="sourceLineNo">222</span> break;<a name="line.222"></a>
<span class="sourceLineNo">223</span> }<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> return null;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span><a name="line.227"></a>
<span class="sourceLineNo">228</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.228"></a>
<span class="sourceLineNo">229</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.229"></a>
<span class="sourceLineNo">230</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.230"></a>
<span class="sourceLineNo">231</span> return ctx.enumCompletionValues;<a name="line.231"></a>
<span class="sourceLineNo">232</span> }<a name="line.232"></a>
<span class="sourceLineNo">233</span> if (completion.startsWith("repeat@")) {<a name="line.233"></a>
<span class="sourceLineNo">234</span> completion = completion.substring(6);<a name="line.234"></a>
<span class="sourceLineNo">204</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.204"></a>
<span class="sourceLineNo">205</span> }<a name="line.205"></a>
<span class="sourceLineNo">206</span><a name="line.206"></a>
<span class="sourceLineNo">207</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> int i = 0;<a name="line.208"></a>
<span class="sourceLineNo">209</span> for (CommandParameter param : cmd.parameters) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.210"></a>
<span class="sourceLineNo">211</span> Class type = param.getType();<a name="line.211"></a>
<span class="sourceLineNo">212</span> while (type != null) {<a name="line.212"></a>
<span class="sourceLineNo">213</span> String completion = this.defaultCompletions.get(type);<a name="line.213"></a>
<span class="sourceLineNo">214</span> if (completion != null) {<a name="line.214"></a>
<span class="sourceLineNo">215</span> return completion;<a name="line.215"></a>
<span class="sourceLineNo">216</span> }<a name="line.216"></a>
<span class="sourceLineNo">217</span> type = type.getSuperclass();<a name="line.217"></a>
<span class="sourceLineNo">218</span> }<a name="line.218"></a>
<span class="sourceLineNo">219</span> if (param.getType().isEnum()) {<a name="line.219"></a>
<span class="sourceLineNo">220</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.220"></a>
<span class="sourceLineNo">221</span> //noinspection unchecked<a name="line.221"></a>
<span class="sourceLineNo">222</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.222"></a>
<span class="sourceLineNo">223</span> return DEFAULT_ENUM_ID;<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> break;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span> }<a name="line.227"></a>
<span class="sourceLineNo">228</span> return null;<a name="line.228"></a>
<span class="sourceLineNo">229</span> }<a name="line.229"></a>
<span class="sourceLineNo">230</span><a name="line.230"></a>
<span class="sourceLineNo">231</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.231"></a>
<span class="sourceLineNo">232</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.232"></a>
<span class="sourceLineNo">233</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.233"></a>
<span class="sourceLineNo">234</span> return ctx.enumCompletionValues;<a name="line.234"></a>
<span class="sourceLineNo">235</span> }<a name="line.235"></a>
<span class="sourceLineNo">236</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.236"></a>
<span class="sourceLineNo">237</span><a name="line.237"></a>
<span class="sourceLineNo">238</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.238"></a>
<span class="sourceLineNo">239</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.239"></a>
<span class="sourceLineNo">240</span><a name="line.240"></a>
<span class="sourceLineNo">241</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.241"></a>
<span class="sourceLineNo">242</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.242"></a>
<span class="sourceLineNo">243</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.243"></a>
<span class="sourceLineNo">244</span> if (handler != null) {<a name="line.244"></a>
<span class="sourceLineNo">245</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.246"></a>
<span class="sourceLineNo">247</span> return null;<a name="line.247"></a>
<span class="sourceLineNo">248</span> }<a name="line.248"></a>
<span class="sourceLineNo">249</span> String config = complete.length == 1 ? null : complete[1];<a name="line.249"></a>
<span class="sourceLineNo">250</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.250"></a>
<span class="sourceLineNo">251</span><a name="line.251"></a>
<span class="sourceLineNo">252</span> try {<a name="line.252"></a>
<span class="sourceLineNo">253</span> //noinspection unchecked<a name="line.253"></a>
<span class="sourceLineNo">254</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.254"></a>
<span class="sourceLineNo">255</span> if (completions != null) {<a name="line.255"></a>
<span class="sourceLineNo">256</span> allCompletions.addAll(completions);<a name="line.256"></a>
<span class="sourceLineNo">257</span> continue;<a name="line.257"></a>
<span class="sourceLineNo">258</span> }<a name="line.258"></a>
<span class="sourceLineNo">259</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.259"></a>
<span class="sourceLineNo">260</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.260"></a>
<span class="sourceLineNo">261</span> throw new CommandCompletionTextLookupException();<a name="line.261"></a>
<span class="sourceLineNo">262</span> }<a name="line.262"></a>
<span class="sourceLineNo">263</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> // This should only happen if some other feedback error occured.<a name="line.264"></a>
<span class="sourceLineNo">265</span> } catch (Exception e) {<a name="line.265"></a>
<span class="sourceLineNo">266</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.266"></a>
<span class="sourceLineNo">267</span> }<a name="line.267"></a>
<span class="sourceLineNo">268</span> // Something went wrong in lookup, fall back to input<a name="line.268"></a>
<span class="sourceLineNo">269</span> return Collections.singletonList(input);<a name="line.269"></a>
<span class="sourceLineNo">270</span> } else {<a name="line.270"></a>
<span class="sourceLineNo">271</span> // Plaintext value<a name="line.271"></a>
<span class="sourceLineNo">272</span> allCompletions.add(value);<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span> }<a name="line.274"></a>
<span class="sourceLineNo">275</span> return allCompletions;<a name="line.275"></a>
<span class="sourceLineNo">276</span> }<a name="line.276"></a>
<span class="sourceLineNo">277</span><a name="line.277"></a>
<span class="sourceLineNo">278</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.278"></a>
<span class="sourceLineNo">279</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.279"></a>
<span class="sourceLineNo">280</span> }<a name="line.280"></a>
<span class="sourceLineNo">281</span><a name="line.281"></a>
<span class="sourceLineNo">282</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.282"></a>
<span class="sourceLineNo">283</span> }<a name="line.283"></a>
<span class="sourceLineNo">284</span><a name="line.284"></a>
<span class="sourceLineNo">285</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.285"></a>
<span class="sourceLineNo">286</span> }<a name="line.286"></a>
<span class="sourceLineNo">287</span><a name="line.287"></a>
<span class="sourceLineNo">288</span>}<a name="line.288"></a>
<span class="sourceLineNo">236</span> boolean repeat = completion.startsWith("repeat@");<a name="line.236"></a>
<span class="sourceLineNo">237</span> if (repeat) {<a name="line.237"></a>
<span class="sourceLineNo">238</span> completion = completion.substring(6);<a name="line.238"></a>
<span class="sourceLineNo">239</span> }<a name="line.239"></a>
<span class="sourceLineNo">240</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.240"></a>
<span class="sourceLineNo">241</span><a name="line.241"></a>
<span class="sourceLineNo">242</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.242"></a>
<span class="sourceLineNo">243</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.243"></a>
<span class="sourceLineNo">244</span><a name="line.244"></a>
<span class="sourceLineNo">245</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.246"></a>
<span class="sourceLineNo">247</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.247"></a>
<span class="sourceLineNo">248</span> if (handler != null) {<a name="line.248"></a>
<span class="sourceLineNo">249</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.249"></a>
<span class="sourceLineNo">250</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.250"></a>
<span class="sourceLineNo">251</span> return null;<a name="line.251"></a>
<span class="sourceLineNo">252</span> }<a name="line.252"></a>
<span class="sourceLineNo">253</span> String config = complete.length == 1 ? null : complete[1];<a name="line.253"></a>
<span class="sourceLineNo">254</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.254"></a>
<span class="sourceLineNo">255</span><a name="line.255"></a>
<span class="sourceLineNo">256</span> try {<a name="line.256"></a>
<span class="sourceLineNo">257</span> //noinspection unchecked<a name="line.257"></a>
<span class="sourceLineNo">258</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.258"></a>
<span class="sourceLineNo">259</span><a name="line.259"></a>
<span class="sourceLineNo">260</span> //Handle completions with more than one word:<a name="line.260"></a>
<span class="sourceLineNo">261</span> if (!repeat &amp;&amp;<a name="line.261"></a>
<span class="sourceLineNo">262</span> command.parameters[command.parameters.length - 1].consumesRest<a name="line.262"></a>
<span class="sourceLineNo">263</span> &amp;&amp; args.length &gt; ACFPatterns.SPACE.split(command.complete).length) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> String start = String.join(" ", args);<a name="line.264"></a>
<span class="sourceLineNo">265</span> completions = completions.stream()<a name="line.265"></a>
<span class="sourceLineNo">266</span> .filter(s -&gt; s.split(" ").length &gt;= args.length)<a name="line.266"></a>
<span class="sourceLineNo">267</span> .filter(s -&gt; ApacheCommonsLangUtil.startsWithIgnoreCase(s, start))<a name="line.267"></a>
<span class="sourceLineNo">268</span> .map(s -&gt; {<a name="line.268"></a>
<span class="sourceLineNo">269</span> String[] completionArgs = s.split(" ");<a name="line.269"></a>
<span class="sourceLineNo">270</span> return String.join(" ",<a name="line.270"></a>
<span class="sourceLineNo">271</span> Arrays.copyOfRange(completionArgs, args.length - 1, completionArgs.length));<a name="line.271"></a>
<span class="sourceLineNo">272</span> }).collect(Collectors.toList());<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span><a name="line.274"></a>
<span class="sourceLineNo">275</span> if (completions != null) {<a name="line.275"></a>
<span class="sourceLineNo">276</span> allCompletions.addAll(completions);<a name="line.276"></a>
<span class="sourceLineNo">277</span> continue;<a name="line.277"></a>
<span class="sourceLineNo">278</span> }<a name="line.278"></a>
<span class="sourceLineNo">279</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.279"></a>
<span class="sourceLineNo">280</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.280"></a>
<span class="sourceLineNo">281</span> throw new CommandCompletionTextLookupException();<a name="line.281"></a>
<span class="sourceLineNo">282</span> }<a name="line.282"></a>
<span class="sourceLineNo">283</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.283"></a>
<span class="sourceLineNo">284</span> // This should only happen if some other feedback error occured.<a name="line.284"></a>
<span class="sourceLineNo">285</span> } catch (Exception e) {<a name="line.285"></a>
<span class="sourceLineNo">286</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.286"></a>
<span class="sourceLineNo">287</span> }<a name="line.287"></a>
<span class="sourceLineNo">288</span> // Something went wrong in lookup, fall back to input<a name="line.288"></a>
<span class="sourceLineNo">289</span> return Collections.singletonList(input);<a name="line.289"></a>
<span class="sourceLineNo">290</span> } else {<a name="line.290"></a>
<span class="sourceLineNo">291</span> // Plaintext value<a name="line.291"></a>
<span class="sourceLineNo">292</span> allCompletions.add(value);<a name="line.292"></a>
<span class="sourceLineNo">293</span> }<a name="line.293"></a>
<span class="sourceLineNo">294</span> }<a name="line.294"></a>
<span class="sourceLineNo">295</span> return allCompletions;<a name="line.295"></a>
<span class="sourceLineNo">296</span> }<a name="line.296"></a>
<span class="sourceLineNo">297</span><a name="line.297"></a>
<span class="sourceLineNo">298</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.298"></a>
<span class="sourceLineNo">299</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.299"></a>
<span class="sourceLineNo">300</span> }<a name="line.300"></a>
<span class="sourceLineNo">301</span><a name="line.301"></a>
<span class="sourceLineNo">302</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.302"></a>
<span class="sourceLineNo">303</span> }<a name="line.303"></a>
<span class="sourceLineNo">304</span><a name="line.304"></a>
<span class="sourceLineNo">305</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.305"></a>
<span class="sourceLineNo">306</span> }<a name="line.306"></a>
<span class="sourceLineNo">307</span><a name="line.307"></a>
<span class="sourceLineNo">308</span>}<a name="line.308"></a>
@@ -31,269 +31,289 @@
<span class="sourceLineNo">023</span><a name="line.23"></a>
<span class="sourceLineNo">024</span>package co.aikar.commands;<a name="line.24"></a>
<span class="sourceLineNo">025</span><a name="line.25"></a>
<span class="sourceLineNo">026</span>import org.jetbrains.annotations.NotNull;<a name="line.26"></a>
<span class="sourceLineNo">027</span><a name="line.27"></a>
<span class="sourceLineNo">028</span>import java.util.ArrayList;<a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.Arrays;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Collection;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collections;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.HashMap;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.List;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.Map;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.function.Supplier;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.stream.Collectors;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.IntStream;<a name="line.37"></a>
<span class="sourceLineNo">038</span><a name="line.38"></a>
<span class="sourceLineNo">026</span>import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;<a name="line.26"></a>
<span class="sourceLineNo">027</span>import org.jetbrains.annotations.NotNull;<a name="line.27"></a>
<span class="sourceLineNo">028</span><a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.ArrayList;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Arrays;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collection;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.Collections;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.HashMap;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.List;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.Map;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.function.Supplier;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.Collectors;<a name="line.37"></a>
<span class="sourceLineNo">038</span>import java.util.stream.IntStream;<a name="line.38"></a>
<span class="sourceLineNo">039</span><a name="line.39"></a>
<span class="sourceLineNo">040</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.40"></a>
<span class="sourceLineNo">041</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.41"></a>
<span class="sourceLineNo">042</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.42"></a>
<span class="sourceLineNo">043</span> private final CommandManager manager;<a name="line.43"></a>
<span class="sourceLineNo">044</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.44"></a>
<span class="sourceLineNo">045</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span><a name="line.47"></a>
<span class="sourceLineNo">048</span> public CommandCompletions(CommandManager manager) {<a name="line.48"></a>
<span class="sourceLineNo">049</span> this.manager = manager;<a name="line.49"></a>
<span class="sourceLineNo">050</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.53"></a>
<span class="sourceLineNo">054</span> String config = c.getConfig();<a name="line.54"></a>
<span class="sourceLineNo">055</span> if (config == null) {<a name="line.55"></a>
<span class="sourceLineNo">056</span> return Collections.emptyList();<a name="line.56"></a>
<span class="sourceLineNo">057</span> }<a name="line.57"></a>
<span class="sourceLineNo">058</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.58"></a>
<span class="sourceLineNo">059</span> int start;<a name="line.59"></a>
<span class="sourceLineNo">060</span> int end;<a name="line.60"></a>
<span class="sourceLineNo">061</span> if (ranges.length != 2) {<a name="line.61"></a>
<span class="sourceLineNo">062</span> start = 0;<a name="line.62"></a>
<span class="sourceLineNo">063</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.63"></a>
<span class="sourceLineNo">064</span> } else {<a name="line.64"></a>
<span class="sourceLineNo">065</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.65"></a>
<span class="sourceLineNo">066</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> }<a name="line.67"></a>
<span class="sourceLineNo">068</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.68"></a>
<span class="sourceLineNo">069</span> });<a name="line.69"></a>
<span class="sourceLineNo">070</span> }<a name="line.70"></a>
<span class="sourceLineNo">071</span><a name="line.71"></a>
<span class="sourceLineNo">072</span> /**<a name="line.72"></a>
<span class="sourceLineNo">073</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.73"></a>
<span class="sourceLineNo">074</span> *<a name="line.74"></a>
<span class="sourceLineNo">075</span> * @param id<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param handler<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @return<a name="line.77"></a>
<span class="sourceLineNo">078</span> */<a name="line.78"></a>
<span class="sourceLineNo">079</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.79"></a>
<span class="sourceLineNo">080</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.80"></a>
<span class="sourceLineNo">081</span> }<a name="line.81"></a>
<span class="sourceLineNo">082</span><a name="line.82"></a>
<span class="sourceLineNo">083</span> /**<a name="line.83"></a>
<span class="sourceLineNo">084</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.84"></a>
<span class="sourceLineNo">085</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * &lt;p&gt;<a name="line.86"></a>
<span class="sourceLineNo">087</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.87"></a>
<span class="sourceLineNo">088</span> * your handler will be executed on the main thread.<a name="line.88"></a>
<span class="sourceLineNo">089</span> * &lt;p&gt;<a name="line.89"></a>
<span class="sourceLineNo">090</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.90"></a>
<span class="sourceLineNo">091</span> * &lt;p&gt;<a name="line.91"></a>
<span class="sourceLineNo">092</span> * Use context.isAsync() to determine if you are async or not.<a name="line.92"></a>
<span class="sourceLineNo">093</span> *<a name="line.93"></a>
<span class="sourceLineNo">094</span> * @param id<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param handler<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @return<a name="line.96"></a>
<span class="sourceLineNo">097</span> */<a name="line.97"></a>
<span class="sourceLineNo">098</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.98"></a>
<span class="sourceLineNo">099</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.99"></a>
<span class="sourceLineNo">100</span> }<a name="line.100"></a>
<span class="sourceLineNo">101</span><a name="line.101"></a>
<span class="sourceLineNo">102</span> /**<a name="line.102"></a>
<span class="sourceLineNo">103</span> * Register a static list of command completions that will never change.<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * &lt;p&gt;<a name="line.105"></a>
<span class="sourceLineNo">106</span> * Example: foo|bar|baz<a name="line.106"></a>
<span class="sourceLineNo">107</span> *<a name="line.107"></a>
<span class="sourceLineNo">108</span> * @param id<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param list<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @return<a name="line.110"></a>
<span class="sourceLineNo">111</span> */<a name="line.111"></a>
<span class="sourceLineNo">112</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.112"></a>
<span class="sourceLineNo">113</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.113"></a>
<span class="sourceLineNo">114</span> }<a name="line.114"></a>
<span class="sourceLineNo">115</span><a name="line.115"></a>
<span class="sourceLineNo">116</span> /**<a name="line.116"></a>
<span class="sourceLineNo">117</span> * Register a static list of command completions that will never change<a name="line.117"></a>
<span class="sourceLineNo">118</span> *<a name="line.118"></a>
<span class="sourceLineNo">119</span> * @param id<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param completions<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @return<a name="line.121"></a>
<span class="sourceLineNo">122</span> */<a name="line.122"></a>
<span class="sourceLineNo">123</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.123"></a>
<span class="sourceLineNo">124</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.124"></a>
<span class="sourceLineNo">125</span> }<a name="line.125"></a>
<span class="sourceLineNo">126</span><a name="line.126"></a>
<span class="sourceLineNo">127</span> /**<a name="line.127"></a>
<span class="sourceLineNo">128</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.128"></a>
<span class="sourceLineNo">129</span> * immediately as part of this method call.<a name="line.129"></a>
<span class="sourceLineNo">130</span> *<a name="line.130"></a>
<span class="sourceLineNo">131</span> * @param id<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param supplier<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @return<a name="line.133"></a>
<span class="sourceLineNo">134</span> */<a name="line.134"></a>
<span class="sourceLineNo">135</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.135"></a>
<span class="sourceLineNo">136</span> return registerStaticCompletion(id, supplier.get());<a name="line.136"></a>
<span class="sourceLineNo">137</span> }<a name="line.137"></a>
<span class="sourceLineNo">138</span><a name="line.138"></a>
<span class="sourceLineNo">139</span> /**<a name="line.139"></a>
<span class="sourceLineNo">140</span> * Register a static list of command completions that will never change<a name="line.140"></a>
<span class="sourceLineNo">141</span> *<a name="line.141"></a>
<span class="sourceLineNo">142</span> * @param id<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param completions<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @return<a name="line.144"></a>
<span class="sourceLineNo">145</span> */<a name="line.145"></a>
<span class="sourceLineNo">146</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.146"></a>
<span class="sourceLineNo">147</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.147"></a>
<span class="sourceLineNo">148</span> }<a name="line.148"></a>
<span class="sourceLineNo">149</span><a name="line.149"></a>
<span class="sourceLineNo">150</span> /**<a name="line.150"></a>
<span class="sourceLineNo">151</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.151"></a>
<span class="sourceLineNo">152</span> * &lt;p&gt;<a name="line.152"></a>
<span class="sourceLineNo">153</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.153"></a>
<span class="sourceLineNo">154</span> *<a name="line.154"></a>
<span class="sourceLineNo">155</span> * @param id<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param classes<a name="line.156"></a>
<span class="sourceLineNo">157</span> */<a name="line.157"></a>
<span class="sourceLineNo">158</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.158"></a>
<span class="sourceLineNo">159</span> // get completion with specified id<a name="line.159"></a>
<span class="sourceLineNo">160</span> id = prepareCompletionId(id);<a name="line.160"></a>
<span class="sourceLineNo">161</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span><a name="line.162"></a>
<span class="sourceLineNo">163</span> if (completion == null) {<a name="line.163"></a>
<span class="sourceLineNo">164</span> // Throw something because no completion with specified id<a name="line.164"></a>
<span class="sourceLineNo">165</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.165"></a>
<span class="sourceLineNo">166</span> }<a name="line.166"></a>
<span class="sourceLineNo">167</span><a name="line.167"></a>
<span class="sourceLineNo">168</span> for (Class clazz : classes) {<a name="line.168"></a>
<span class="sourceLineNo">169</span> defaultCompletions.put(clazz, id);<a name="line.169"></a>
<span class="sourceLineNo">170</span> }<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span><a name="line.172"></a>
<span class="sourceLineNo">173</span> @NotNull<a name="line.173"></a>
<span class="sourceLineNo">174</span> private static String prepareCompletionId(String id) {<a name="line.174"></a>
<span class="sourceLineNo">175</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.175"></a>
<span class="sourceLineNo">176</span> }<a name="line.176"></a>
<span class="sourceLineNo">177</span><a name="line.177"></a>
<span class="sourceLineNo">178</span> @NotNull<a name="line.178"></a>
<span class="sourceLineNo">179</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.179"></a>
<span class="sourceLineNo">180</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.180"></a>
<span class="sourceLineNo">181</span> final int argIndex = args.length - 1;<a name="line.181"></a>
<span class="sourceLineNo">182</span><a name="line.182"></a>
<span class="sourceLineNo">183</span> String input = args[argIndex];<a name="line.183"></a>
<span class="sourceLineNo">184</span><a name="line.184"></a>
<span class="sourceLineNo">185</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.185"></a>
<span class="sourceLineNo">186</span> if (completion == null || "*".equals(completion)) {<a name="line.186"></a>
<span class="sourceLineNo">187</span> completion = findDefaultCompletion(cmd, args);<a name="line.187"></a>
<span class="sourceLineNo">188</span> }<a name="line.188"></a>
<span class="sourceLineNo">189</span><a name="line.189"></a>
<span class="sourceLineNo">190</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.190"></a>
<span class="sourceLineNo">191</span> String last = completions[completions.length - 1];<a name="line.191"></a>
<span class="sourceLineNo">192</span> if (last.startsWith("repeat@")) {<a name="line.192"></a>
<span class="sourceLineNo">193</span> completion = last;<a name="line.193"></a>
<span class="sourceLineNo">194</span> }<a name="line.194"></a>
<span class="sourceLineNo">195</span> }<a name="line.195"></a>
<span class="sourceLineNo">196</span><a name="line.196"></a>
<span class="sourceLineNo">197</span> if (completion == null) {<a name="line.197"></a>
<span class="sourceLineNo">198</span> return Collections.singletonList(input);<a name="line.198"></a>
<span class="sourceLineNo">199</span> }<a name="line.199"></a>
<span class="sourceLineNo">200</span><a name="line.200"></a>
<span class="sourceLineNo">201</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">040</span><a name="line.40"></a>
<span class="sourceLineNo">041</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.41"></a>
<span class="sourceLineNo">042</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.42"></a>
<span class="sourceLineNo">043</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.43"></a>
<span class="sourceLineNo">044</span> private final CommandManager manager;<a name="line.44"></a>
<span class="sourceLineNo">045</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.47"></a>
<span class="sourceLineNo">048</span><a name="line.48"></a>
<span class="sourceLineNo">049</span> public CommandCompletions(CommandManager manager) {<a name="line.49"></a>
<span class="sourceLineNo">050</span> this.manager = manager;<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.53"></a>
<span class="sourceLineNo">054</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.54"></a>
<span class="sourceLineNo">055</span> String config = c.getConfig();<a name="line.55"></a>
<span class="sourceLineNo">056</span> if (config == null) {<a name="line.56"></a>
<span class="sourceLineNo">057</span> return Collections.emptyList();<a name="line.57"></a>
<span class="sourceLineNo">058</span> }<a name="line.58"></a>
<span class="sourceLineNo">059</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.59"></a>
<span class="sourceLineNo">060</span> int start;<a name="line.60"></a>
<span class="sourceLineNo">061</span> int end;<a name="line.61"></a>
<span class="sourceLineNo">062</span> if (ranges.length != 2) {<a name="line.62"></a>
<span class="sourceLineNo">063</span> start = 0;<a name="line.63"></a>
<span class="sourceLineNo">064</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.64"></a>
<span class="sourceLineNo">065</span> } else {<a name="line.65"></a>
<span class="sourceLineNo">066</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.67"></a>
<span class="sourceLineNo">068</span> }<a name="line.68"></a>
<span class="sourceLineNo">069</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.69"></a>
<span class="sourceLineNo">070</span> });<a name="line.70"></a>
<span class="sourceLineNo">071</span> }<a name="line.71"></a>
<span class="sourceLineNo">072</span><a name="line.72"></a>
<span class="sourceLineNo">073</span> /**<a name="line.73"></a>
<span class="sourceLineNo">074</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.74"></a>
<span class="sourceLineNo">075</span> *<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param id<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @param handler<a name="line.77"></a>
<span class="sourceLineNo">078</span> * @return<a name="line.78"></a>
<span class="sourceLineNo">079</span> */<a name="line.79"></a>
<span class="sourceLineNo">080</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.80"></a>
<span class="sourceLineNo">081</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.81"></a>
<span class="sourceLineNo">082</span> }<a name="line.82"></a>
<span class="sourceLineNo">083</span><a name="line.83"></a>
<span class="sourceLineNo">084</span> /**<a name="line.84"></a>
<span class="sourceLineNo">085</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.86"></a>
<span class="sourceLineNo">087</span> * &lt;p&gt;<a name="line.87"></a>
<span class="sourceLineNo">088</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.88"></a>
<span class="sourceLineNo">089</span> * your handler will be executed on the main thread.<a name="line.89"></a>
<span class="sourceLineNo">090</span> * &lt;p&gt;<a name="line.90"></a>
<span class="sourceLineNo">091</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.91"></a>
<span class="sourceLineNo">092</span> * &lt;p&gt;<a name="line.92"></a>
<span class="sourceLineNo">093</span> * Use context.isAsync() to determine if you are async or not.<a name="line.93"></a>
<span class="sourceLineNo">094</span> *<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param id<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @param handler<a name="line.96"></a>
<span class="sourceLineNo">097</span> * @return<a name="line.97"></a>
<span class="sourceLineNo">098</span> */<a name="line.98"></a>
<span class="sourceLineNo">099</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.99"></a>
<span class="sourceLineNo">100</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.100"></a>
<span class="sourceLineNo">101</span> }<a name="line.101"></a>
<span class="sourceLineNo">102</span><a name="line.102"></a>
<span class="sourceLineNo">103</span> /**<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Register a static list of command completions that will never change.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.105"></a>
<span class="sourceLineNo">106</span> * &lt;p&gt;<a name="line.106"></a>
<span class="sourceLineNo">107</span> * Example: foo|bar|baz<a name="line.107"></a>
<span class="sourceLineNo">108</span> *<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param id<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @param list<a name="line.110"></a>
<span class="sourceLineNo">111</span> * @return<a name="line.111"></a>
<span class="sourceLineNo">112</span> */<a name="line.112"></a>
<span class="sourceLineNo">113</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.113"></a>
<span class="sourceLineNo">114</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.114"></a>
<span class="sourceLineNo">115</span> }<a name="line.115"></a>
<span class="sourceLineNo">116</span><a name="line.116"></a>
<span class="sourceLineNo">117</span> /**<a name="line.117"></a>
<span class="sourceLineNo">118</span> * Register a static list of command completions that will never change<a name="line.118"></a>
<span class="sourceLineNo">119</span> *<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param id<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @param completions<a name="line.121"></a>
<span class="sourceLineNo">122</span> * @return<a name="line.122"></a>
<span class="sourceLineNo">123</span> */<a name="line.123"></a>
<span class="sourceLineNo">124</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.124"></a>
<span class="sourceLineNo">125</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.125"></a>
<span class="sourceLineNo">126</span> }<a name="line.126"></a>
<span class="sourceLineNo">127</span><a name="line.127"></a>
<span class="sourceLineNo">128</span> /**<a name="line.128"></a>
<span class="sourceLineNo">129</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.129"></a>
<span class="sourceLineNo">130</span> * immediately as part of this method call.<a name="line.130"></a>
<span class="sourceLineNo">131</span> *<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param id<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @param supplier<a name="line.133"></a>
<span class="sourceLineNo">134</span> * @return<a name="line.134"></a>
<span class="sourceLineNo">135</span> */<a name="line.135"></a>
<span class="sourceLineNo">136</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.136"></a>
<span class="sourceLineNo">137</span> return registerStaticCompletion(id, supplier.get());<a name="line.137"></a>
<span class="sourceLineNo">138</span> }<a name="line.138"></a>
<span class="sourceLineNo">139</span><a name="line.139"></a>
<span class="sourceLineNo">140</span> /**<a name="line.140"></a>
<span class="sourceLineNo">141</span> * Register a static list of command completions that will never change<a name="line.141"></a>
<span class="sourceLineNo">142</span> *<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param id<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @param completions<a name="line.144"></a>
<span class="sourceLineNo">145</span> * @return<a name="line.145"></a>
<span class="sourceLineNo">146</span> */<a name="line.146"></a>
<span class="sourceLineNo">147</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.147"></a>
<span class="sourceLineNo">148</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.148"></a>
<span class="sourceLineNo">149</span> }<a name="line.149"></a>
<span class="sourceLineNo">150</span><a name="line.150"></a>
<span class="sourceLineNo">151</span> /**<a name="line.151"></a>
<span class="sourceLineNo">152</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.152"></a>
<span class="sourceLineNo">153</span> * &lt;p&gt;<a name="line.153"></a>
<span class="sourceLineNo">154</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.154"></a>
<span class="sourceLineNo">155</span> *<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param id<a name="line.156"></a>
<span class="sourceLineNo">157</span> * @param classes<a name="line.157"></a>
<span class="sourceLineNo">158</span> */<a name="line.158"></a>
<span class="sourceLineNo">159</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.159"></a>
<span class="sourceLineNo">160</span> // get completion with specified id<a name="line.160"></a>
<span class="sourceLineNo">161</span> id = prepareCompletionId(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.162"></a>
<span class="sourceLineNo">163</span><a name="line.163"></a>
<span class="sourceLineNo">164</span> if (completion == null) {<a name="line.164"></a>
<span class="sourceLineNo">165</span> // Throw something because no completion with specified id<a name="line.165"></a>
<span class="sourceLineNo">166</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.166"></a>
<span class="sourceLineNo">167</span> }<a name="line.167"></a>
<span class="sourceLineNo">168</span><a name="line.168"></a>
<span class="sourceLineNo">169</span> for (Class clazz : classes) {<a name="line.169"></a>
<span class="sourceLineNo">170</span> defaultCompletions.put(clazz, id);<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span> }<a name="line.172"></a>
<span class="sourceLineNo">173</span><a name="line.173"></a>
<span class="sourceLineNo">174</span> @NotNull<a name="line.174"></a>
<span class="sourceLineNo">175</span> private static String prepareCompletionId(String id) {<a name="line.175"></a>
<span class="sourceLineNo">176</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.176"></a>
<span class="sourceLineNo">177</span> }<a name="line.177"></a>
<span class="sourceLineNo">178</span><a name="line.178"></a>
<span class="sourceLineNo">179</span> @NotNull<a name="line.179"></a>
<span class="sourceLineNo">180</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.180"></a>
<span class="sourceLineNo">181</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.181"></a>
<span class="sourceLineNo">182</span> final int argIndex = args.length - 1;<a name="line.182"></a>
<span class="sourceLineNo">183</span><a name="line.183"></a>
<span class="sourceLineNo">184</span> String input = args[argIndex];<a name="line.184"></a>
<span class="sourceLineNo">185</span><a name="line.185"></a>
<span class="sourceLineNo">186</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.186"></a>
<span class="sourceLineNo">187</span> if (completion == null || "*".equals(completion)) {<a name="line.187"></a>
<span class="sourceLineNo">188</span> completion = findDefaultCompletion(cmd, args);<a name="line.188"></a>
<span class="sourceLineNo">189</span> }<a name="line.189"></a>
<span class="sourceLineNo">190</span><a name="line.190"></a>
<span class="sourceLineNo">191</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.191"></a>
<span class="sourceLineNo">192</span> String last = completions[completions.length - 1];<a name="line.192"></a>
<span class="sourceLineNo">193</span> if (last.startsWith("repeat@")) {<a name="line.193"></a>
<span class="sourceLineNo">194</span> completion = last;<a name="line.194"></a>
<span class="sourceLineNo">195</span> } else if (argIndex &gt;= completions.length &amp;&amp; cmd.parameters[cmd.parameters.length - 1].consumesRest) {<a name="line.195"></a>
<span class="sourceLineNo">196</span> completion = last;<a name="line.196"></a>
<span class="sourceLineNo">197</span> }<a name="line.197"></a>
<span class="sourceLineNo">198</span> }<a name="line.198"></a>
<span class="sourceLineNo">199</span><a name="line.199"></a>
<span class="sourceLineNo">200</span> if (completion == null) {<a name="line.200"></a>
<span class="sourceLineNo">201</span> return Collections.singletonList(input);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">203</span><a name="line.203"></a>
<span class="sourceLineNo">204</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.204"></a>
<span class="sourceLineNo">205</span> int i = 0;<a name="line.205"></a>
<span class="sourceLineNo">206</span> for (CommandParameter param : cmd.parameters) {<a name="line.206"></a>
<span class="sourceLineNo">207</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> Class type = param.getType();<a name="line.208"></a>
<span class="sourceLineNo">209</span> while (type != null) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> String completion = this.defaultCompletions.get(type);<a name="line.210"></a>
<span class="sourceLineNo">211</span> if (completion != null) {<a name="line.211"></a>
<span class="sourceLineNo">212</span> return completion;<a name="line.212"></a>
<span class="sourceLineNo">213</span> }<a name="line.213"></a>
<span class="sourceLineNo">214</span> type = type.getSuperclass();<a name="line.214"></a>
<span class="sourceLineNo">215</span> }<a name="line.215"></a>
<span class="sourceLineNo">216</span> if (param.getType().isEnum()) {<a name="line.216"></a>
<span class="sourceLineNo">217</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.217"></a>
<span class="sourceLineNo">218</span> //noinspection unchecked<a name="line.218"></a>
<span class="sourceLineNo">219</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.219"></a>
<span class="sourceLineNo">220</span> return DEFAULT_ENUM_ID;<a name="line.220"></a>
<span class="sourceLineNo">221</span> }<a name="line.221"></a>
<span class="sourceLineNo">222</span> break;<a name="line.222"></a>
<span class="sourceLineNo">223</span> }<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> return null;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span><a name="line.227"></a>
<span class="sourceLineNo">228</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.228"></a>
<span class="sourceLineNo">229</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.229"></a>
<span class="sourceLineNo">230</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.230"></a>
<span class="sourceLineNo">231</span> return ctx.enumCompletionValues;<a name="line.231"></a>
<span class="sourceLineNo">232</span> }<a name="line.232"></a>
<span class="sourceLineNo">233</span> if (completion.startsWith("repeat@")) {<a name="line.233"></a>
<span class="sourceLineNo">234</span> completion = completion.substring(6);<a name="line.234"></a>
<span class="sourceLineNo">204</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.204"></a>
<span class="sourceLineNo">205</span> }<a name="line.205"></a>
<span class="sourceLineNo">206</span><a name="line.206"></a>
<span class="sourceLineNo">207</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> int i = 0;<a name="line.208"></a>
<span class="sourceLineNo">209</span> for (CommandParameter param : cmd.parameters) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.210"></a>
<span class="sourceLineNo">211</span> Class type = param.getType();<a name="line.211"></a>
<span class="sourceLineNo">212</span> while (type != null) {<a name="line.212"></a>
<span class="sourceLineNo">213</span> String completion = this.defaultCompletions.get(type);<a name="line.213"></a>
<span class="sourceLineNo">214</span> if (completion != null) {<a name="line.214"></a>
<span class="sourceLineNo">215</span> return completion;<a name="line.215"></a>
<span class="sourceLineNo">216</span> }<a name="line.216"></a>
<span class="sourceLineNo">217</span> type = type.getSuperclass();<a name="line.217"></a>
<span class="sourceLineNo">218</span> }<a name="line.218"></a>
<span class="sourceLineNo">219</span> if (param.getType().isEnum()) {<a name="line.219"></a>
<span class="sourceLineNo">220</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.220"></a>
<span class="sourceLineNo">221</span> //noinspection unchecked<a name="line.221"></a>
<span class="sourceLineNo">222</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.222"></a>
<span class="sourceLineNo">223</span> return DEFAULT_ENUM_ID;<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> break;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span> }<a name="line.227"></a>
<span class="sourceLineNo">228</span> return null;<a name="line.228"></a>
<span class="sourceLineNo">229</span> }<a name="line.229"></a>
<span class="sourceLineNo">230</span><a name="line.230"></a>
<span class="sourceLineNo">231</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.231"></a>
<span class="sourceLineNo">232</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.232"></a>
<span class="sourceLineNo">233</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.233"></a>
<span class="sourceLineNo">234</span> return ctx.enumCompletionValues;<a name="line.234"></a>
<span class="sourceLineNo">235</span> }<a name="line.235"></a>
<span class="sourceLineNo">236</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.236"></a>
<span class="sourceLineNo">237</span><a name="line.237"></a>
<span class="sourceLineNo">238</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.238"></a>
<span class="sourceLineNo">239</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.239"></a>
<span class="sourceLineNo">240</span><a name="line.240"></a>
<span class="sourceLineNo">241</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.241"></a>
<span class="sourceLineNo">242</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.242"></a>
<span class="sourceLineNo">243</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.243"></a>
<span class="sourceLineNo">244</span> if (handler != null) {<a name="line.244"></a>
<span class="sourceLineNo">245</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.246"></a>
<span class="sourceLineNo">247</span> return null;<a name="line.247"></a>
<span class="sourceLineNo">248</span> }<a name="line.248"></a>
<span class="sourceLineNo">249</span> String config = complete.length == 1 ? null : complete[1];<a name="line.249"></a>
<span class="sourceLineNo">250</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.250"></a>
<span class="sourceLineNo">251</span><a name="line.251"></a>
<span class="sourceLineNo">252</span> try {<a name="line.252"></a>
<span class="sourceLineNo">253</span> //noinspection unchecked<a name="line.253"></a>
<span class="sourceLineNo">254</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.254"></a>
<span class="sourceLineNo">255</span> if (completions != null) {<a name="line.255"></a>
<span class="sourceLineNo">256</span> allCompletions.addAll(completions);<a name="line.256"></a>
<span class="sourceLineNo">257</span> continue;<a name="line.257"></a>
<span class="sourceLineNo">258</span> }<a name="line.258"></a>
<span class="sourceLineNo">259</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.259"></a>
<span class="sourceLineNo">260</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.260"></a>
<span class="sourceLineNo">261</span> throw new CommandCompletionTextLookupException();<a name="line.261"></a>
<span class="sourceLineNo">262</span> }<a name="line.262"></a>
<span class="sourceLineNo">263</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> // This should only happen if some other feedback error occured.<a name="line.264"></a>
<span class="sourceLineNo">265</span> } catch (Exception e) {<a name="line.265"></a>
<span class="sourceLineNo">266</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.266"></a>
<span class="sourceLineNo">267</span> }<a name="line.267"></a>
<span class="sourceLineNo">268</span> // Something went wrong in lookup, fall back to input<a name="line.268"></a>
<span class="sourceLineNo">269</span> return Collections.singletonList(input);<a name="line.269"></a>
<span class="sourceLineNo">270</span> } else {<a name="line.270"></a>
<span class="sourceLineNo">271</span> // Plaintext value<a name="line.271"></a>
<span class="sourceLineNo">272</span> allCompletions.add(value);<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span> }<a name="line.274"></a>
<span class="sourceLineNo">275</span> return allCompletions;<a name="line.275"></a>
<span class="sourceLineNo">276</span> }<a name="line.276"></a>
<span class="sourceLineNo">277</span><a name="line.277"></a>
<span class="sourceLineNo">278</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.278"></a>
<span class="sourceLineNo">279</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.279"></a>
<span class="sourceLineNo">280</span> }<a name="line.280"></a>
<span class="sourceLineNo">281</span><a name="line.281"></a>
<span class="sourceLineNo">282</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.282"></a>
<span class="sourceLineNo">283</span> }<a name="line.283"></a>
<span class="sourceLineNo">284</span><a name="line.284"></a>
<span class="sourceLineNo">285</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.285"></a>
<span class="sourceLineNo">286</span> }<a name="line.286"></a>
<span class="sourceLineNo">287</span><a name="line.287"></a>
<span class="sourceLineNo">288</span>}<a name="line.288"></a>
<span class="sourceLineNo">236</span> boolean repeat = completion.startsWith("repeat@");<a name="line.236"></a>
<span class="sourceLineNo">237</span> if (repeat) {<a name="line.237"></a>
<span class="sourceLineNo">238</span> completion = completion.substring(6);<a name="line.238"></a>
<span class="sourceLineNo">239</span> }<a name="line.239"></a>
<span class="sourceLineNo">240</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.240"></a>
<span class="sourceLineNo">241</span><a name="line.241"></a>
<span class="sourceLineNo">242</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.242"></a>
<span class="sourceLineNo">243</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.243"></a>
<span class="sourceLineNo">244</span><a name="line.244"></a>
<span class="sourceLineNo">245</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.246"></a>
<span class="sourceLineNo">247</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.247"></a>
<span class="sourceLineNo">248</span> if (handler != null) {<a name="line.248"></a>
<span class="sourceLineNo">249</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.249"></a>
<span class="sourceLineNo">250</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.250"></a>
<span class="sourceLineNo">251</span> return null;<a name="line.251"></a>
<span class="sourceLineNo">252</span> }<a name="line.252"></a>
<span class="sourceLineNo">253</span> String config = complete.length == 1 ? null : complete[1];<a name="line.253"></a>
<span class="sourceLineNo">254</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.254"></a>
<span class="sourceLineNo">255</span><a name="line.255"></a>
<span class="sourceLineNo">256</span> try {<a name="line.256"></a>
<span class="sourceLineNo">257</span> //noinspection unchecked<a name="line.257"></a>
<span class="sourceLineNo">258</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.258"></a>
<span class="sourceLineNo">259</span><a name="line.259"></a>
<span class="sourceLineNo">260</span> //Handle completions with more than one word:<a name="line.260"></a>
<span class="sourceLineNo">261</span> if (!repeat &amp;&amp;<a name="line.261"></a>
<span class="sourceLineNo">262</span> command.parameters[command.parameters.length - 1].consumesRest<a name="line.262"></a>
<span class="sourceLineNo">263</span> &amp;&amp; args.length &gt; ACFPatterns.SPACE.split(command.complete).length) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> String start = String.join(" ", args);<a name="line.264"></a>
<span class="sourceLineNo">265</span> completions = completions.stream()<a name="line.265"></a>
<span class="sourceLineNo">266</span> .filter(s -&gt; s.split(" ").length &gt;= args.length)<a name="line.266"></a>
<span class="sourceLineNo">267</span> .filter(s -&gt; ApacheCommonsLangUtil.startsWithIgnoreCase(s, start))<a name="line.267"></a>
<span class="sourceLineNo">268</span> .map(s -&gt; {<a name="line.268"></a>
<span class="sourceLineNo">269</span> String[] completionArgs = s.split(" ");<a name="line.269"></a>
<span class="sourceLineNo">270</span> return String.join(" ",<a name="line.270"></a>
<span class="sourceLineNo">271</span> Arrays.copyOfRange(completionArgs, args.length - 1, completionArgs.length));<a name="line.271"></a>
<span class="sourceLineNo">272</span> }).collect(Collectors.toList());<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span><a name="line.274"></a>
<span class="sourceLineNo">275</span> if (completions != null) {<a name="line.275"></a>
<span class="sourceLineNo">276</span> allCompletions.addAll(completions);<a name="line.276"></a>
<span class="sourceLineNo">277</span> continue;<a name="line.277"></a>
<span class="sourceLineNo">278</span> }<a name="line.278"></a>
<span class="sourceLineNo">279</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.279"></a>
<span class="sourceLineNo">280</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.280"></a>
<span class="sourceLineNo">281</span> throw new CommandCompletionTextLookupException();<a name="line.281"></a>
<span class="sourceLineNo">282</span> }<a name="line.282"></a>
<span class="sourceLineNo">283</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.283"></a>
<span class="sourceLineNo">284</span> // This should only happen if some other feedback error occured.<a name="line.284"></a>
<span class="sourceLineNo">285</span> } catch (Exception e) {<a name="line.285"></a>
<span class="sourceLineNo">286</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.286"></a>
<span class="sourceLineNo">287</span> }<a name="line.287"></a>
<span class="sourceLineNo">288</span> // Something went wrong in lookup, fall back to input<a name="line.288"></a>
<span class="sourceLineNo">289</span> return Collections.singletonList(input);<a name="line.289"></a>
<span class="sourceLineNo">290</span> } else {<a name="line.290"></a>
<span class="sourceLineNo">291</span> // Plaintext value<a name="line.291"></a>
<span class="sourceLineNo">292</span> allCompletions.add(value);<a name="line.292"></a>
<span class="sourceLineNo">293</span> }<a name="line.293"></a>
<span class="sourceLineNo">294</span> }<a name="line.294"></a>
<span class="sourceLineNo">295</span> return allCompletions;<a name="line.295"></a>
<span class="sourceLineNo">296</span> }<a name="line.296"></a>
<span class="sourceLineNo">297</span><a name="line.297"></a>
<span class="sourceLineNo">298</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.298"></a>
<span class="sourceLineNo">299</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.299"></a>
<span class="sourceLineNo">300</span> }<a name="line.300"></a>
<span class="sourceLineNo">301</span><a name="line.301"></a>
<span class="sourceLineNo">302</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.302"></a>
<span class="sourceLineNo">303</span> }<a name="line.303"></a>
<span class="sourceLineNo">304</span><a name="line.304"></a>
<span class="sourceLineNo">305</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.305"></a>
<span class="sourceLineNo">306</span> }<a name="line.306"></a>
<span class="sourceLineNo">307</span><a name="line.307"></a>
<span class="sourceLineNo">308</span>}<a name="line.308"></a>
@@ -31,269 +31,289 @@
<span class="sourceLineNo">023</span><a name="line.23"></a>
<span class="sourceLineNo">024</span>package co.aikar.commands;<a name="line.24"></a>
<span class="sourceLineNo">025</span><a name="line.25"></a>
<span class="sourceLineNo">026</span>import org.jetbrains.annotations.NotNull;<a name="line.26"></a>
<span class="sourceLineNo">027</span><a name="line.27"></a>
<span class="sourceLineNo">028</span>import java.util.ArrayList;<a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.Arrays;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Collection;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collections;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.HashMap;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.List;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.Map;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.function.Supplier;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.stream.Collectors;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.IntStream;<a name="line.37"></a>
<span class="sourceLineNo">038</span><a name="line.38"></a>
<span class="sourceLineNo">026</span>import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;<a name="line.26"></a>
<span class="sourceLineNo">027</span>import org.jetbrains.annotations.NotNull;<a name="line.27"></a>
<span class="sourceLineNo">028</span><a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.ArrayList;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Arrays;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collection;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.Collections;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.HashMap;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.List;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.Map;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.function.Supplier;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.Collectors;<a name="line.37"></a>
<span class="sourceLineNo">038</span>import java.util.stream.IntStream;<a name="line.38"></a>
<span class="sourceLineNo">039</span><a name="line.39"></a>
<span class="sourceLineNo">040</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.40"></a>
<span class="sourceLineNo">041</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.41"></a>
<span class="sourceLineNo">042</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.42"></a>
<span class="sourceLineNo">043</span> private final CommandManager manager;<a name="line.43"></a>
<span class="sourceLineNo">044</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.44"></a>
<span class="sourceLineNo">045</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span><a name="line.47"></a>
<span class="sourceLineNo">048</span> public CommandCompletions(CommandManager manager) {<a name="line.48"></a>
<span class="sourceLineNo">049</span> this.manager = manager;<a name="line.49"></a>
<span class="sourceLineNo">050</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.53"></a>
<span class="sourceLineNo">054</span> String config = c.getConfig();<a name="line.54"></a>
<span class="sourceLineNo">055</span> if (config == null) {<a name="line.55"></a>
<span class="sourceLineNo">056</span> return Collections.emptyList();<a name="line.56"></a>
<span class="sourceLineNo">057</span> }<a name="line.57"></a>
<span class="sourceLineNo">058</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.58"></a>
<span class="sourceLineNo">059</span> int start;<a name="line.59"></a>
<span class="sourceLineNo">060</span> int end;<a name="line.60"></a>
<span class="sourceLineNo">061</span> if (ranges.length != 2) {<a name="line.61"></a>
<span class="sourceLineNo">062</span> start = 0;<a name="line.62"></a>
<span class="sourceLineNo">063</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.63"></a>
<span class="sourceLineNo">064</span> } else {<a name="line.64"></a>
<span class="sourceLineNo">065</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.65"></a>
<span class="sourceLineNo">066</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> }<a name="line.67"></a>
<span class="sourceLineNo">068</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.68"></a>
<span class="sourceLineNo">069</span> });<a name="line.69"></a>
<span class="sourceLineNo">070</span> }<a name="line.70"></a>
<span class="sourceLineNo">071</span><a name="line.71"></a>
<span class="sourceLineNo">072</span> /**<a name="line.72"></a>
<span class="sourceLineNo">073</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.73"></a>
<span class="sourceLineNo">074</span> *<a name="line.74"></a>
<span class="sourceLineNo">075</span> * @param id<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param handler<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @return<a name="line.77"></a>
<span class="sourceLineNo">078</span> */<a name="line.78"></a>
<span class="sourceLineNo">079</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.79"></a>
<span class="sourceLineNo">080</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.80"></a>
<span class="sourceLineNo">081</span> }<a name="line.81"></a>
<span class="sourceLineNo">082</span><a name="line.82"></a>
<span class="sourceLineNo">083</span> /**<a name="line.83"></a>
<span class="sourceLineNo">084</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.84"></a>
<span class="sourceLineNo">085</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * &lt;p&gt;<a name="line.86"></a>
<span class="sourceLineNo">087</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.87"></a>
<span class="sourceLineNo">088</span> * your handler will be executed on the main thread.<a name="line.88"></a>
<span class="sourceLineNo">089</span> * &lt;p&gt;<a name="line.89"></a>
<span class="sourceLineNo">090</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.90"></a>
<span class="sourceLineNo">091</span> * &lt;p&gt;<a name="line.91"></a>
<span class="sourceLineNo">092</span> * Use context.isAsync() to determine if you are async or not.<a name="line.92"></a>
<span class="sourceLineNo">093</span> *<a name="line.93"></a>
<span class="sourceLineNo">094</span> * @param id<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param handler<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @return<a name="line.96"></a>
<span class="sourceLineNo">097</span> */<a name="line.97"></a>
<span class="sourceLineNo">098</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.98"></a>
<span class="sourceLineNo">099</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.99"></a>
<span class="sourceLineNo">100</span> }<a name="line.100"></a>
<span class="sourceLineNo">101</span><a name="line.101"></a>
<span class="sourceLineNo">102</span> /**<a name="line.102"></a>
<span class="sourceLineNo">103</span> * Register a static list of command completions that will never change.<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * &lt;p&gt;<a name="line.105"></a>
<span class="sourceLineNo">106</span> * Example: foo|bar|baz<a name="line.106"></a>
<span class="sourceLineNo">107</span> *<a name="line.107"></a>
<span class="sourceLineNo">108</span> * @param id<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param list<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @return<a name="line.110"></a>
<span class="sourceLineNo">111</span> */<a name="line.111"></a>
<span class="sourceLineNo">112</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.112"></a>
<span class="sourceLineNo">113</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.113"></a>
<span class="sourceLineNo">114</span> }<a name="line.114"></a>
<span class="sourceLineNo">115</span><a name="line.115"></a>
<span class="sourceLineNo">116</span> /**<a name="line.116"></a>
<span class="sourceLineNo">117</span> * Register a static list of command completions that will never change<a name="line.117"></a>
<span class="sourceLineNo">118</span> *<a name="line.118"></a>
<span class="sourceLineNo">119</span> * @param id<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param completions<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @return<a name="line.121"></a>
<span class="sourceLineNo">122</span> */<a name="line.122"></a>
<span class="sourceLineNo">123</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.123"></a>
<span class="sourceLineNo">124</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.124"></a>
<span class="sourceLineNo">125</span> }<a name="line.125"></a>
<span class="sourceLineNo">126</span><a name="line.126"></a>
<span class="sourceLineNo">127</span> /**<a name="line.127"></a>
<span class="sourceLineNo">128</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.128"></a>
<span class="sourceLineNo">129</span> * immediately as part of this method call.<a name="line.129"></a>
<span class="sourceLineNo">130</span> *<a name="line.130"></a>
<span class="sourceLineNo">131</span> * @param id<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param supplier<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @return<a name="line.133"></a>
<span class="sourceLineNo">134</span> */<a name="line.134"></a>
<span class="sourceLineNo">135</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.135"></a>
<span class="sourceLineNo">136</span> return registerStaticCompletion(id, supplier.get());<a name="line.136"></a>
<span class="sourceLineNo">137</span> }<a name="line.137"></a>
<span class="sourceLineNo">138</span><a name="line.138"></a>
<span class="sourceLineNo">139</span> /**<a name="line.139"></a>
<span class="sourceLineNo">140</span> * Register a static list of command completions that will never change<a name="line.140"></a>
<span class="sourceLineNo">141</span> *<a name="line.141"></a>
<span class="sourceLineNo">142</span> * @param id<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param completions<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @return<a name="line.144"></a>
<span class="sourceLineNo">145</span> */<a name="line.145"></a>
<span class="sourceLineNo">146</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.146"></a>
<span class="sourceLineNo">147</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.147"></a>
<span class="sourceLineNo">148</span> }<a name="line.148"></a>
<span class="sourceLineNo">149</span><a name="line.149"></a>
<span class="sourceLineNo">150</span> /**<a name="line.150"></a>
<span class="sourceLineNo">151</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.151"></a>
<span class="sourceLineNo">152</span> * &lt;p&gt;<a name="line.152"></a>
<span class="sourceLineNo">153</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.153"></a>
<span class="sourceLineNo">154</span> *<a name="line.154"></a>
<span class="sourceLineNo">155</span> * @param id<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param classes<a name="line.156"></a>
<span class="sourceLineNo">157</span> */<a name="line.157"></a>
<span class="sourceLineNo">158</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.158"></a>
<span class="sourceLineNo">159</span> // get completion with specified id<a name="line.159"></a>
<span class="sourceLineNo">160</span> id = prepareCompletionId(id);<a name="line.160"></a>
<span class="sourceLineNo">161</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span><a name="line.162"></a>
<span class="sourceLineNo">163</span> if (completion == null) {<a name="line.163"></a>
<span class="sourceLineNo">164</span> // Throw something because no completion with specified id<a name="line.164"></a>
<span class="sourceLineNo">165</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.165"></a>
<span class="sourceLineNo">166</span> }<a name="line.166"></a>
<span class="sourceLineNo">167</span><a name="line.167"></a>
<span class="sourceLineNo">168</span> for (Class clazz : classes) {<a name="line.168"></a>
<span class="sourceLineNo">169</span> defaultCompletions.put(clazz, id);<a name="line.169"></a>
<span class="sourceLineNo">170</span> }<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span><a name="line.172"></a>
<span class="sourceLineNo">173</span> @NotNull<a name="line.173"></a>
<span class="sourceLineNo">174</span> private static String prepareCompletionId(String id) {<a name="line.174"></a>
<span class="sourceLineNo">175</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.175"></a>
<span class="sourceLineNo">176</span> }<a name="line.176"></a>
<span class="sourceLineNo">177</span><a name="line.177"></a>
<span class="sourceLineNo">178</span> @NotNull<a name="line.178"></a>
<span class="sourceLineNo">179</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.179"></a>
<span class="sourceLineNo">180</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.180"></a>
<span class="sourceLineNo">181</span> final int argIndex = args.length - 1;<a name="line.181"></a>
<span class="sourceLineNo">182</span><a name="line.182"></a>
<span class="sourceLineNo">183</span> String input = args[argIndex];<a name="line.183"></a>
<span class="sourceLineNo">184</span><a name="line.184"></a>
<span class="sourceLineNo">185</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.185"></a>
<span class="sourceLineNo">186</span> if (completion == null || "*".equals(completion)) {<a name="line.186"></a>
<span class="sourceLineNo">187</span> completion = findDefaultCompletion(cmd, args);<a name="line.187"></a>
<span class="sourceLineNo">188</span> }<a name="line.188"></a>
<span class="sourceLineNo">189</span><a name="line.189"></a>
<span class="sourceLineNo">190</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.190"></a>
<span class="sourceLineNo">191</span> String last = completions[completions.length - 1];<a name="line.191"></a>
<span class="sourceLineNo">192</span> if (last.startsWith("repeat@")) {<a name="line.192"></a>
<span class="sourceLineNo">193</span> completion = last;<a name="line.193"></a>
<span class="sourceLineNo">194</span> }<a name="line.194"></a>
<span class="sourceLineNo">195</span> }<a name="line.195"></a>
<span class="sourceLineNo">196</span><a name="line.196"></a>
<span class="sourceLineNo">197</span> if (completion == null) {<a name="line.197"></a>
<span class="sourceLineNo">198</span> return Collections.singletonList(input);<a name="line.198"></a>
<span class="sourceLineNo">199</span> }<a name="line.199"></a>
<span class="sourceLineNo">200</span><a name="line.200"></a>
<span class="sourceLineNo">201</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">040</span><a name="line.40"></a>
<span class="sourceLineNo">041</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.41"></a>
<span class="sourceLineNo">042</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.42"></a>
<span class="sourceLineNo">043</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.43"></a>
<span class="sourceLineNo">044</span> private final CommandManager manager;<a name="line.44"></a>
<span class="sourceLineNo">045</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.47"></a>
<span class="sourceLineNo">048</span><a name="line.48"></a>
<span class="sourceLineNo">049</span> public CommandCompletions(CommandManager manager) {<a name="line.49"></a>
<span class="sourceLineNo">050</span> this.manager = manager;<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.53"></a>
<span class="sourceLineNo">054</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.54"></a>
<span class="sourceLineNo">055</span> String config = c.getConfig();<a name="line.55"></a>
<span class="sourceLineNo">056</span> if (config == null) {<a name="line.56"></a>
<span class="sourceLineNo">057</span> return Collections.emptyList();<a name="line.57"></a>
<span class="sourceLineNo">058</span> }<a name="line.58"></a>
<span class="sourceLineNo">059</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.59"></a>
<span class="sourceLineNo">060</span> int start;<a name="line.60"></a>
<span class="sourceLineNo">061</span> int end;<a name="line.61"></a>
<span class="sourceLineNo">062</span> if (ranges.length != 2) {<a name="line.62"></a>
<span class="sourceLineNo">063</span> start = 0;<a name="line.63"></a>
<span class="sourceLineNo">064</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.64"></a>
<span class="sourceLineNo">065</span> } else {<a name="line.65"></a>
<span class="sourceLineNo">066</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.67"></a>
<span class="sourceLineNo">068</span> }<a name="line.68"></a>
<span class="sourceLineNo">069</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.69"></a>
<span class="sourceLineNo">070</span> });<a name="line.70"></a>
<span class="sourceLineNo">071</span> }<a name="line.71"></a>
<span class="sourceLineNo">072</span><a name="line.72"></a>
<span class="sourceLineNo">073</span> /**<a name="line.73"></a>
<span class="sourceLineNo">074</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.74"></a>
<span class="sourceLineNo">075</span> *<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param id<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @param handler<a name="line.77"></a>
<span class="sourceLineNo">078</span> * @return<a name="line.78"></a>
<span class="sourceLineNo">079</span> */<a name="line.79"></a>
<span class="sourceLineNo">080</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.80"></a>
<span class="sourceLineNo">081</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.81"></a>
<span class="sourceLineNo">082</span> }<a name="line.82"></a>
<span class="sourceLineNo">083</span><a name="line.83"></a>
<span class="sourceLineNo">084</span> /**<a name="line.84"></a>
<span class="sourceLineNo">085</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.86"></a>
<span class="sourceLineNo">087</span> * &lt;p&gt;<a name="line.87"></a>
<span class="sourceLineNo">088</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.88"></a>
<span class="sourceLineNo">089</span> * your handler will be executed on the main thread.<a name="line.89"></a>
<span class="sourceLineNo">090</span> * &lt;p&gt;<a name="line.90"></a>
<span class="sourceLineNo">091</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.91"></a>
<span class="sourceLineNo">092</span> * &lt;p&gt;<a name="line.92"></a>
<span class="sourceLineNo">093</span> * Use context.isAsync() to determine if you are async or not.<a name="line.93"></a>
<span class="sourceLineNo">094</span> *<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param id<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @param handler<a name="line.96"></a>
<span class="sourceLineNo">097</span> * @return<a name="line.97"></a>
<span class="sourceLineNo">098</span> */<a name="line.98"></a>
<span class="sourceLineNo">099</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.99"></a>
<span class="sourceLineNo">100</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.100"></a>
<span class="sourceLineNo">101</span> }<a name="line.101"></a>
<span class="sourceLineNo">102</span><a name="line.102"></a>
<span class="sourceLineNo">103</span> /**<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Register a static list of command completions that will never change.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.105"></a>
<span class="sourceLineNo">106</span> * &lt;p&gt;<a name="line.106"></a>
<span class="sourceLineNo">107</span> * Example: foo|bar|baz<a name="line.107"></a>
<span class="sourceLineNo">108</span> *<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param id<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @param list<a name="line.110"></a>
<span class="sourceLineNo">111</span> * @return<a name="line.111"></a>
<span class="sourceLineNo">112</span> */<a name="line.112"></a>
<span class="sourceLineNo">113</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.113"></a>
<span class="sourceLineNo">114</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.114"></a>
<span class="sourceLineNo">115</span> }<a name="line.115"></a>
<span class="sourceLineNo">116</span><a name="line.116"></a>
<span class="sourceLineNo">117</span> /**<a name="line.117"></a>
<span class="sourceLineNo">118</span> * Register a static list of command completions that will never change<a name="line.118"></a>
<span class="sourceLineNo">119</span> *<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param id<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @param completions<a name="line.121"></a>
<span class="sourceLineNo">122</span> * @return<a name="line.122"></a>
<span class="sourceLineNo">123</span> */<a name="line.123"></a>
<span class="sourceLineNo">124</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.124"></a>
<span class="sourceLineNo">125</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.125"></a>
<span class="sourceLineNo">126</span> }<a name="line.126"></a>
<span class="sourceLineNo">127</span><a name="line.127"></a>
<span class="sourceLineNo">128</span> /**<a name="line.128"></a>
<span class="sourceLineNo">129</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.129"></a>
<span class="sourceLineNo">130</span> * immediately as part of this method call.<a name="line.130"></a>
<span class="sourceLineNo">131</span> *<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param id<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @param supplier<a name="line.133"></a>
<span class="sourceLineNo">134</span> * @return<a name="line.134"></a>
<span class="sourceLineNo">135</span> */<a name="line.135"></a>
<span class="sourceLineNo">136</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.136"></a>
<span class="sourceLineNo">137</span> return registerStaticCompletion(id, supplier.get());<a name="line.137"></a>
<span class="sourceLineNo">138</span> }<a name="line.138"></a>
<span class="sourceLineNo">139</span><a name="line.139"></a>
<span class="sourceLineNo">140</span> /**<a name="line.140"></a>
<span class="sourceLineNo">141</span> * Register a static list of command completions that will never change<a name="line.141"></a>
<span class="sourceLineNo">142</span> *<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param id<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @param completions<a name="line.144"></a>
<span class="sourceLineNo">145</span> * @return<a name="line.145"></a>
<span class="sourceLineNo">146</span> */<a name="line.146"></a>
<span class="sourceLineNo">147</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.147"></a>
<span class="sourceLineNo">148</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.148"></a>
<span class="sourceLineNo">149</span> }<a name="line.149"></a>
<span class="sourceLineNo">150</span><a name="line.150"></a>
<span class="sourceLineNo">151</span> /**<a name="line.151"></a>
<span class="sourceLineNo">152</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.152"></a>
<span class="sourceLineNo">153</span> * &lt;p&gt;<a name="line.153"></a>
<span class="sourceLineNo">154</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.154"></a>
<span class="sourceLineNo">155</span> *<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param id<a name="line.156"></a>
<span class="sourceLineNo">157</span> * @param classes<a name="line.157"></a>
<span class="sourceLineNo">158</span> */<a name="line.158"></a>
<span class="sourceLineNo">159</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.159"></a>
<span class="sourceLineNo">160</span> // get completion with specified id<a name="line.160"></a>
<span class="sourceLineNo">161</span> id = prepareCompletionId(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.162"></a>
<span class="sourceLineNo">163</span><a name="line.163"></a>
<span class="sourceLineNo">164</span> if (completion == null) {<a name="line.164"></a>
<span class="sourceLineNo">165</span> // Throw something because no completion with specified id<a name="line.165"></a>
<span class="sourceLineNo">166</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.166"></a>
<span class="sourceLineNo">167</span> }<a name="line.167"></a>
<span class="sourceLineNo">168</span><a name="line.168"></a>
<span class="sourceLineNo">169</span> for (Class clazz : classes) {<a name="line.169"></a>
<span class="sourceLineNo">170</span> defaultCompletions.put(clazz, id);<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span> }<a name="line.172"></a>
<span class="sourceLineNo">173</span><a name="line.173"></a>
<span class="sourceLineNo">174</span> @NotNull<a name="line.174"></a>
<span class="sourceLineNo">175</span> private static String prepareCompletionId(String id) {<a name="line.175"></a>
<span class="sourceLineNo">176</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.176"></a>
<span class="sourceLineNo">177</span> }<a name="line.177"></a>
<span class="sourceLineNo">178</span><a name="line.178"></a>
<span class="sourceLineNo">179</span> @NotNull<a name="line.179"></a>
<span class="sourceLineNo">180</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.180"></a>
<span class="sourceLineNo">181</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.181"></a>
<span class="sourceLineNo">182</span> final int argIndex = args.length - 1;<a name="line.182"></a>
<span class="sourceLineNo">183</span><a name="line.183"></a>
<span class="sourceLineNo">184</span> String input = args[argIndex];<a name="line.184"></a>
<span class="sourceLineNo">185</span><a name="line.185"></a>
<span class="sourceLineNo">186</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.186"></a>
<span class="sourceLineNo">187</span> if (completion == null || "*".equals(completion)) {<a name="line.187"></a>
<span class="sourceLineNo">188</span> completion = findDefaultCompletion(cmd, args);<a name="line.188"></a>
<span class="sourceLineNo">189</span> }<a name="line.189"></a>
<span class="sourceLineNo">190</span><a name="line.190"></a>
<span class="sourceLineNo">191</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.191"></a>
<span class="sourceLineNo">192</span> String last = completions[completions.length - 1];<a name="line.192"></a>
<span class="sourceLineNo">193</span> if (last.startsWith("repeat@")) {<a name="line.193"></a>
<span class="sourceLineNo">194</span> completion = last;<a name="line.194"></a>
<span class="sourceLineNo">195</span> } else if (argIndex &gt;= completions.length &amp;&amp; cmd.parameters[cmd.parameters.length - 1].consumesRest) {<a name="line.195"></a>
<span class="sourceLineNo">196</span> completion = last;<a name="line.196"></a>
<span class="sourceLineNo">197</span> }<a name="line.197"></a>
<span class="sourceLineNo">198</span> }<a name="line.198"></a>
<span class="sourceLineNo">199</span><a name="line.199"></a>
<span class="sourceLineNo">200</span> if (completion == null) {<a name="line.200"></a>
<span class="sourceLineNo">201</span> return Collections.singletonList(input);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">203</span><a name="line.203"></a>
<span class="sourceLineNo">204</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.204"></a>
<span class="sourceLineNo">205</span> int i = 0;<a name="line.205"></a>
<span class="sourceLineNo">206</span> for (CommandParameter param : cmd.parameters) {<a name="line.206"></a>
<span class="sourceLineNo">207</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> Class type = param.getType();<a name="line.208"></a>
<span class="sourceLineNo">209</span> while (type != null) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> String completion = this.defaultCompletions.get(type);<a name="line.210"></a>
<span class="sourceLineNo">211</span> if (completion != null) {<a name="line.211"></a>
<span class="sourceLineNo">212</span> return completion;<a name="line.212"></a>
<span class="sourceLineNo">213</span> }<a name="line.213"></a>
<span class="sourceLineNo">214</span> type = type.getSuperclass();<a name="line.214"></a>
<span class="sourceLineNo">215</span> }<a name="line.215"></a>
<span class="sourceLineNo">216</span> if (param.getType().isEnum()) {<a name="line.216"></a>
<span class="sourceLineNo">217</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.217"></a>
<span class="sourceLineNo">218</span> //noinspection unchecked<a name="line.218"></a>
<span class="sourceLineNo">219</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.219"></a>
<span class="sourceLineNo">220</span> return DEFAULT_ENUM_ID;<a name="line.220"></a>
<span class="sourceLineNo">221</span> }<a name="line.221"></a>
<span class="sourceLineNo">222</span> break;<a name="line.222"></a>
<span class="sourceLineNo">223</span> }<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> return null;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span><a name="line.227"></a>
<span class="sourceLineNo">228</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.228"></a>
<span class="sourceLineNo">229</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.229"></a>
<span class="sourceLineNo">230</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.230"></a>
<span class="sourceLineNo">231</span> return ctx.enumCompletionValues;<a name="line.231"></a>
<span class="sourceLineNo">232</span> }<a name="line.232"></a>
<span class="sourceLineNo">233</span> if (completion.startsWith("repeat@")) {<a name="line.233"></a>
<span class="sourceLineNo">234</span> completion = completion.substring(6);<a name="line.234"></a>
<span class="sourceLineNo">204</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.204"></a>
<span class="sourceLineNo">205</span> }<a name="line.205"></a>
<span class="sourceLineNo">206</span><a name="line.206"></a>
<span class="sourceLineNo">207</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> int i = 0;<a name="line.208"></a>
<span class="sourceLineNo">209</span> for (CommandParameter param : cmd.parameters) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.210"></a>
<span class="sourceLineNo">211</span> Class type = param.getType();<a name="line.211"></a>
<span class="sourceLineNo">212</span> while (type != null) {<a name="line.212"></a>
<span class="sourceLineNo">213</span> String completion = this.defaultCompletions.get(type);<a name="line.213"></a>
<span class="sourceLineNo">214</span> if (completion != null) {<a name="line.214"></a>
<span class="sourceLineNo">215</span> return completion;<a name="line.215"></a>
<span class="sourceLineNo">216</span> }<a name="line.216"></a>
<span class="sourceLineNo">217</span> type = type.getSuperclass();<a name="line.217"></a>
<span class="sourceLineNo">218</span> }<a name="line.218"></a>
<span class="sourceLineNo">219</span> if (param.getType().isEnum()) {<a name="line.219"></a>
<span class="sourceLineNo">220</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.220"></a>
<span class="sourceLineNo">221</span> //noinspection unchecked<a name="line.221"></a>
<span class="sourceLineNo">222</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.222"></a>
<span class="sourceLineNo">223</span> return DEFAULT_ENUM_ID;<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> break;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span> }<a name="line.227"></a>
<span class="sourceLineNo">228</span> return null;<a name="line.228"></a>
<span class="sourceLineNo">229</span> }<a name="line.229"></a>
<span class="sourceLineNo">230</span><a name="line.230"></a>
<span class="sourceLineNo">231</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.231"></a>
<span class="sourceLineNo">232</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.232"></a>
<span class="sourceLineNo">233</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.233"></a>
<span class="sourceLineNo">234</span> return ctx.enumCompletionValues;<a name="line.234"></a>
<span class="sourceLineNo">235</span> }<a name="line.235"></a>
<span class="sourceLineNo">236</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.236"></a>
<span class="sourceLineNo">237</span><a name="line.237"></a>
<span class="sourceLineNo">238</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.238"></a>
<span class="sourceLineNo">239</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.239"></a>
<span class="sourceLineNo">240</span><a name="line.240"></a>
<span class="sourceLineNo">241</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.241"></a>
<span class="sourceLineNo">242</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.242"></a>
<span class="sourceLineNo">243</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.243"></a>
<span class="sourceLineNo">244</span> if (handler != null) {<a name="line.244"></a>
<span class="sourceLineNo">245</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.246"></a>
<span class="sourceLineNo">247</span> return null;<a name="line.247"></a>
<span class="sourceLineNo">248</span> }<a name="line.248"></a>
<span class="sourceLineNo">249</span> String config = complete.length == 1 ? null : complete[1];<a name="line.249"></a>
<span class="sourceLineNo">250</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.250"></a>
<span class="sourceLineNo">251</span><a name="line.251"></a>
<span class="sourceLineNo">252</span> try {<a name="line.252"></a>
<span class="sourceLineNo">253</span> //noinspection unchecked<a name="line.253"></a>
<span class="sourceLineNo">254</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.254"></a>
<span class="sourceLineNo">255</span> if (completions != null) {<a name="line.255"></a>
<span class="sourceLineNo">256</span> allCompletions.addAll(completions);<a name="line.256"></a>
<span class="sourceLineNo">257</span> continue;<a name="line.257"></a>
<span class="sourceLineNo">258</span> }<a name="line.258"></a>
<span class="sourceLineNo">259</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.259"></a>
<span class="sourceLineNo">260</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.260"></a>
<span class="sourceLineNo">261</span> throw new CommandCompletionTextLookupException();<a name="line.261"></a>
<span class="sourceLineNo">262</span> }<a name="line.262"></a>
<span class="sourceLineNo">263</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> // This should only happen if some other feedback error occured.<a name="line.264"></a>
<span class="sourceLineNo">265</span> } catch (Exception e) {<a name="line.265"></a>
<span class="sourceLineNo">266</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.266"></a>
<span class="sourceLineNo">267</span> }<a name="line.267"></a>
<span class="sourceLineNo">268</span> // Something went wrong in lookup, fall back to input<a name="line.268"></a>
<span class="sourceLineNo">269</span> return Collections.singletonList(input);<a name="line.269"></a>
<span class="sourceLineNo">270</span> } else {<a name="line.270"></a>
<span class="sourceLineNo">271</span> // Plaintext value<a name="line.271"></a>
<span class="sourceLineNo">272</span> allCompletions.add(value);<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span> }<a name="line.274"></a>
<span class="sourceLineNo">275</span> return allCompletions;<a name="line.275"></a>
<span class="sourceLineNo">276</span> }<a name="line.276"></a>
<span class="sourceLineNo">277</span><a name="line.277"></a>
<span class="sourceLineNo">278</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.278"></a>
<span class="sourceLineNo">279</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.279"></a>
<span class="sourceLineNo">280</span> }<a name="line.280"></a>
<span class="sourceLineNo">281</span><a name="line.281"></a>
<span class="sourceLineNo">282</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.282"></a>
<span class="sourceLineNo">283</span> }<a name="line.283"></a>
<span class="sourceLineNo">284</span><a name="line.284"></a>
<span class="sourceLineNo">285</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.285"></a>
<span class="sourceLineNo">286</span> }<a name="line.286"></a>
<span class="sourceLineNo">287</span><a name="line.287"></a>
<span class="sourceLineNo">288</span>}<a name="line.288"></a>
<span class="sourceLineNo">236</span> boolean repeat = completion.startsWith("repeat@");<a name="line.236"></a>
<span class="sourceLineNo">237</span> if (repeat) {<a name="line.237"></a>
<span class="sourceLineNo">238</span> completion = completion.substring(6);<a name="line.238"></a>
<span class="sourceLineNo">239</span> }<a name="line.239"></a>
<span class="sourceLineNo">240</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.240"></a>
<span class="sourceLineNo">241</span><a name="line.241"></a>
<span class="sourceLineNo">242</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.242"></a>
<span class="sourceLineNo">243</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.243"></a>
<span class="sourceLineNo">244</span><a name="line.244"></a>
<span class="sourceLineNo">245</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.246"></a>
<span class="sourceLineNo">247</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.247"></a>
<span class="sourceLineNo">248</span> if (handler != null) {<a name="line.248"></a>
<span class="sourceLineNo">249</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.249"></a>
<span class="sourceLineNo">250</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.250"></a>
<span class="sourceLineNo">251</span> return null;<a name="line.251"></a>
<span class="sourceLineNo">252</span> }<a name="line.252"></a>
<span class="sourceLineNo">253</span> String config = complete.length == 1 ? null : complete[1];<a name="line.253"></a>
<span class="sourceLineNo">254</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.254"></a>
<span class="sourceLineNo">255</span><a name="line.255"></a>
<span class="sourceLineNo">256</span> try {<a name="line.256"></a>
<span class="sourceLineNo">257</span> //noinspection unchecked<a name="line.257"></a>
<span class="sourceLineNo">258</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.258"></a>
<span class="sourceLineNo">259</span><a name="line.259"></a>
<span class="sourceLineNo">260</span> //Handle completions with more than one word:<a name="line.260"></a>
<span class="sourceLineNo">261</span> if (!repeat &amp;&amp;<a name="line.261"></a>
<span class="sourceLineNo">262</span> command.parameters[command.parameters.length - 1].consumesRest<a name="line.262"></a>
<span class="sourceLineNo">263</span> &amp;&amp; args.length &gt; ACFPatterns.SPACE.split(command.complete).length) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> String start = String.join(" ", args);<a name="line.264"></a>
<span class="sourceLineNo">265</span> completions = completions.stream()<a name="line.265"></a>
<span class="sourceLineNo">266</span> .filter(s -&gt; s.split(" ").length &gt;= args.length)<a name="line.266"></a>
<span class="sourceLineNo">267</span> .filter(s -&gt; ApacheCommonsLangUtil.startsWithIgnoreCase(s, start))<a name="line.267"></a>
<span class="sourceLineNo">268</span> .map(s -&gt; {<a name="line.268"></a>
<span class="sourceLineNo">269</span> String[] completionArgs = s.split(" ");<a name="line.269"></a>
<span class="sourceLineNo">270</span> return String.join(" ",<a name="line.270"></a>
<span class="sourceLineNo">271</span> Arrays.copyOfRange(completionArgs, args.length - 1, completionArgs.length));<a name="line.271"></a>
<span class="sourceLineNo">272</span> }).collect(Collectors.toList());<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span><a name="line.274"></a>
<span class="sourceLineNo">275</span> if (completions != null) {<a name="line.275"></a>
<span class="sourceLineNo">276</span> allCompletions.addAll(completions);<a name="line.276"></a>
<span class="sourceLineNo">277</span> continue;<a name="line.277"></a>
<span class="sourceLineNo">278</span> }<a name="line.278"></a>
<span class="sourceLineNo">279</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.279"></a>
<span class="sourceLineNo">280</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.280"></a>
<span class="sourceLineNo">281</span> throw new CommandCompletionTextLookupException();<a name="line.281"></a>
<span class="sourceLineNo">282</span> }<a name="line.282"></a>
<span class="sourceLineNo">283</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.283"></a>
<span class="sourceLineNo">284</span> // This should only happen if some other feedback error occured.<a name="line.284"></a>
<span class="sourceLineNo">285</span> } catch (Exception e) {<a name="line.285"></a>
<span class="sourceLineNo">286</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.286"></a>
<span class="sourceLineNo">287</span> }<a name="line.287"></a>
<span class="sourceLineNo">288</span> // Something went wrong in lookup, fall back to input<a name="line.288"></a>
<span class="sourceLineNo">289</span> return Collections.singletonList(input);<a name="line.289"></a>
<span class="sourceLineNo">290</span> } else {<a name="line.290"></a>
<span class="sourceLineNo">291</span> // Plaintext value<a name="line.291"></a>
<span class="sourceLineNo">292</span> allCompletions.add(value);<a name="line.292"></a>
<span class="sourceLineNo">293</span> }<a name="line.293"></a>
<span class="sourceLineNo">294</span> }<a name="line.294"></a>
<span class="sourceLineNo">295</span> return allCompletions;<a name="line.295"></a>
<span class="sourceLineNo">296</span> }<a name="line.296"></a>
<span class="sourceLineNo">297</span><a name="line.297"></a>
<span class="sourceLineNo">298</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.298"></a>
<span class="sourceLineNo">299</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.299"></a>
<span class="sourceLineNo">300</span> }<a name="line.300"></a>
<span class="sourceLineNo">301</span><a name="line.301"></a>
<span class="sourceLineNo">302</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.302"></a>
<span class="sourceLineNo">303</span> }<a name="line.303"></a>
<span class="sourceLineNo">304</span><a name="line.304"></a>
<span class="sourceLineNo">305</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.305"></a>
<span class="sourceLineNo">306</span> }<a name="line.306"></a>
<span class="sourceLineNo">307</span><a name="line.307"></a>
<span class="sourceLineNo">308</span>}<a name="line.308"></a>
@@ -31,269 +31,289 @@
<span class="sourceLineNo">023</span><a name="line.23"></a>
<span class="sourceLineNo">024</span>package co.aikar.commands;<a name="line.24"></a>
<span class="sourceLineNo">025</span><a name="line.25"></a>
<span class="sourceLineNo">026</span>import org.jetbrains.annotations.NotNull;<a name="line.26"></a>
<span class="sourceLineNo">027</span><a name="line.27"></a>
<span class="sourceLineNo">028</span>import java.util.ArrayList;<a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.Arrays;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Collection;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collections;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.HashMap;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.List;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.Map;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.function.Supplier;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.stream.Collectors;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.IntStream;<a name="line.37"></a>
<span class="sourceLineNo">038</span><a name="line.38"></a>
<span class="sourceLineNo">026</span>import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil;<a name="line.26"></a>
<span class="sourceLineNo">027</span>import org.jetbrains.annotations.NotNull;<a name="line.27"></a>
<span class="sourceLineNo">028</span><a name="line.28"></a>
<span class="sourceLineNo">029</span>import java.util.ArrayList;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import java.util.Arrays;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import java.util.Collection;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import java.util.Collections;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import java.util.HashMap;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import java.util.List;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import java.util.Map;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import java.util.function.Supplier;<a name="line.36"></a>
<span class="sourceLineNo">037</span>import java.util.stream.Collectors;<a name="line.37"></a>
<span class="sourceLineNo">038</span>import java.util.stream.IntStream;<a name="line.38"></a>
<span class="sourceLineNo">039</span><a name="line.39"></a>
<span class="sourceLineNo">040</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.40"></a>
<span class="sourceLineNo">041</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.41"></a>
<span class="sourceLineNo">042</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.42"></a>
<span class="sourceLineNo">043</span> private final CommandManager manager;<a name="line.43"></a>
<span class="sourceLineNo">044</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.44"></a>
<span class="sourceLineNo">045</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span><a name="line.47"></a>
<span class="sourceLineNo">048</span> public CommandCompletions(CommandManager manager) {<a name="line.48"></a>
<span class="sourceLineNo">049</span> this.manager = manager;<a name="line.49"></a>
<span class="sourceLineNo">050</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.53"></a>
<span class="sourceLineNo">054</span> String config = c.getConfig();<a name="line.54"></a>
<span class="sourceLineNo">055</span> if (config == null) {<a name="line.55"></a>
<span class="sourceLineNo">056</span> return Collections.emptyList();<a name="line.56"></a>
<span class="sourceLineNo">057</span> }<a name="line.57"></a>
<span class="sourceLineNo">058</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.58"></a>
<span class="sourceLineNo">059</span> int start;<a name="line.59"></a>
<span class="sourceLineNo">060</span> int end;<a name="line.60"></a>
<span class="sourceLineNo">061</span> if (ranges.length != 2) {<a name="line.61"></a>
<span class="sourceLineNo">062</span> start = 0;<a name="line.62"></a>
<span class="sourceLineNo">063</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.63"></a>
<span class="sourceLineNo">064</span> } else {<a name="line.64"></a>
<span class="sourceLineNo">065</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.65"></a>
<span class="sourceLineNo">066</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> }<a name="line.67"></a>
<span class="sourceLineNo">068</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.68"></a>
<span class="sourceLineNo">069</span> });<a name="line.69"></a>
<span class="sourceLineNo">070</span> }<a name="line.70"></a>
<span class="sourceLineNo">071</span><a name="line.71"></a>
<span class="sourceLineNo">072</span> /**<a name="line.72"></a>
<span class="sourceLineNo">073</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.73"></a>
<span class="sourceLineNo">074</span> *<a name="line.74"></a>
<span class="sourceLineNo">075</span> * @param id<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param handler<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @return<a name="line.77"></a>
<span class="sourceLineNo">078</span> */<a name="line.78"></a>
<span class="sourceLineNo">079</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.79"></a>
<span class="sourceLineNo">080</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.80"></a>
<span class="sourceLineNo">081</span> }<a name="line.81"></a>
<span class="sourceLineNo">082</span><a name="line.82"></a>
<span class="sourceLineNo">083</span> /**<a name="line.83"></a>
<span class="sourceLineNo">084</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.84"></a>
<span class="sourceLineNo">085</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * &lt;p&gt;<a name="line.86"></a>
<span class="sourceLineNo">087</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.87"></a>
<span class="sourceLineNo">088</span> * your handler will be executed on the main thread.<a name="line.88"></a>
<span class="sourceLineNo">089</span> * &lt;p&gt;<a name="line.89"></a>
<span class="sourceLineNo">090</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.90"></a>
<span class="sourceLineNo">091</span> * &lt;p&gt;<a name="line.91"></a>
<span class="sourceLineNo">092</span> * Use context.isAsync() to determine if you are async or not.<a name="line.92"></a>
<span class="sourceLineNo">093</span> *<a name="line.93"></a>
<span class="sourceLineNo">094</span> * @param id<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param handler<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @return<a name="line.96"></a>
<span class="sourceLineNo">097</span> */<a name="line.97"></a>
<span class="sourceLineNo">098</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.98"></a>
<span class="sourceLineNo">099</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.99"></a>
<span class="sourceLineNo">100</span> }<a name="line.100"></a>
<span class="sourceLineNo">101</span><a name="line.101"></a>
<span class="sourceLineNo">102</span> /**<a name="line.102"></a>
<span class="sourceLineNo">103</span> * Register a static list of command completions that will never change.<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * &lt;p&gt;<a name="line.105"></a>
<span class="sourceLineNo">106</span> * Example: foo|bar|baz<a name="line.106"></a>
<span class="sourceLineNo">107</span> *<a name="line.107"></a>
<span class="sourceLineNo">108</span> * @param id<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param list<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @return<a name="line.110"></a>
<span class="sourceLineNo">111</span> */<a name="line.111"></a>
<span class="sourceLineNo">112</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.112"></a>
<span class="sourceLineNo">113</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.113"></a>
<span class="sourceLineNo">114</span> }<a name="line.114"></a>
<span class="sourceLineNo">115</span><a name="line.115"></a>
<span class="sourceLineNo">116</span> /**<a name="line.116"></a>
<span class="sourceLineNo">117</span> * Register a static list of command completions that will never change<a name="line.117"></a>
<span class="sourceLineNo">118</span> *<a name="line.118"></a>
<span class="sourceLineNo">119</span> * @param id<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param completions<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @return<a name="line.121"></a>
<span class="sourceLineNo">122</span> */<a name="line.122"></a>
<span class="sourceLineNo">123</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.123"></a>
<span class="sourceLineNo">124</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.124"></a>
<span class="sourceLineNo">125</span> }<a name="line.125"></a>
<span class="sourceLineNo">126</span><a name="line.126"></a>
<span class="sourceLineNo">127</span> /**<a name="line.127"></a>
<span class="sourceLineNo">128</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.128"></a>
<span class="sourceLineNo">129</span> * immediately as part of this method call.<a name="line.129"></a>
<span class="sourceLineNo">130</span> *<a name="line.130"></a>
<span class="sourceLineNo">131</span> * @param id<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param supplier<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @return<a name="line.133"></a>
<span class="sourceLineNo">134</span> */<a name="line.134"></a>
<span class="sourceLineNo">135</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.135"></a>
<span class="sourceLineNo">136</span> return registerStaticCompletion(id, supplier.get());<a name="line.136"></a>
<span class="sourceLineNo">137</span> }<a name="line.137"></a>
<span class="sourceLineNo">138</span><a name="line.138"></a>
<span class="sourceLineNo">139</span> /**<a name="line.139"></a>
<span class="sourceLineNo">140</span> * Register a static list of command completions that will never change<a name="line.140"></a>
<span class="sourceLineNo">141</span> *<a name="line.141"></a>
<span class="sourceLineNo">142</span> * @param id<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param completions<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @return<a name="line.144"></a>
<span class="sourceLineNo">145</span> */<a name="line.145"></a>
<span class="sourceLineNo">146</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.146"></a>
<span class="sourceLineNo">147</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.147"></a>
<span class="sourceLineNo">148</span> }<a name="line.148"></a>
<span class="sourceLineNo">149</span><a name="line.149"></a>
<span class="sourceLineNo">150</span> /**<a name="line.150"></a>
<span class="sourceLineNo">151</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.151"></a>
<span class="sourceLineNo">152</span> * &lt;p&gt;<a name="line.152"></a>
<span class="sourceLineNo">153</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.153"></a>
<span class="sourceLineNo">154</span> *<a name="line.154"></a>
<span class="sourceLineNo">155</span> * @param id<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param classes<a name="line.156"></a>
<span class="sourceLineNo">157</span> */<a name="line.157"></a>
<span class="sourceLineNo">158</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.158"></a>
<span class="sourceLineNo">159</span> // get completion with specified id<a name="line.159"></a>
<span class="sourceLineNo">160</span> id = prepareCompletionId(id);<a name="line.160"></a>
<span class="sourceLineNo">161</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span><a name="line.162"></a>
<span class="sourceLineNo">163</span> if (completion == null) {<a name="line.163"></a>
<span class="sourceLineNo">164</span> // Throw something because no completion with specified id<a name="line.164"></a>
<span class="sourceLineNo">165</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.165"></a>
<span class="sourceLineNo">166</span> }<a name="line.166"></a>
<span class="sourceLineNo">167</span><a name="line.167"></a>
<span class="sourceLineNo">168</span> for (Class clazz : classes) {<a name="line.168"></a>
<span class="sourceLineNo">169</span> defaultCompletions.put(clazz, id);<a name="line.169"></a>
<span class="sourceLineNo">170</span> }<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span><a name="line.172"></a>
<span class="sourceLineNo">173</span> @NotNull<a name="line.173"></a>
<span class="sourceLineNo">174</span> private static String prepareCompletionId(String id) {<a name="line.174"></a>
<span class="sourceLineNo">175</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.175"></a>
<span class="sourceLineNo">176</span> }<a name="line.176"></a>
<span class="sourceLineNo">177</span><a name="line.177"></a>
<span class="sourceLineNo">178</span> @NotNull<a name="line.178"></a>
<span class="sourceLineNo">179</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.179"></a>
<span class="sourceLineNo">180</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.180"></a>
<span class="sourceLineNo">181</span> final int argIndex = args.length - 1;<a name="line.181"></a>
<span class="sourceLineNo">182</span><a name="line.182"></a>
<span class="sourceLineNo">183</span> String input = args[argIndex];<a name="line.183"></a>
<span class="sourceLineNo">184</span><a name="line.184"></a>
<span class="sourceLineNo">185</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.185"></a>
<span class="sourceLineNo">186</span> if (completion == null || "*".equals(completion)) {<a name="line.186"></a>
<span class="sourceLineNo">187</span> completion = findDefaultCompletion(cmd, args);<a name="line.187"></a>
<span class="sourceLineNo">188</span> }<a name="line.188"></a>
<span class="sourceLineNo">189</span><a name="line.189"></a>
<span class="sourceLineNo">190</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.190"></a>
<span class="sourceLineNo">191</span> String last = completions[completions.length - 1];<a name="line.191"></a>
<span class="sourceLineNo">192</span> if (last.startsWith("repeat@")) {<a name="line.192"></a>
<span class="sourceLineNo">193</span> completion = last;<a name="line.193"></a>
<span class="sourceLineNo">194</span> }<a name="line.194"></a>
<span class="sourceLineNo">195</span> }<a name="line.195"></a>
<span class="sourceLineNo">196</span><a name="line.196"></a>
<span class="sourceLineNo">197</span> if (completion == null) {<a name="line.197"></a>
<span class="sourceLineNo">198</span> return Collections.singletonList(input);<a name="line.198"></a>
<span class="sourceLineNo">199</span> }<a name="line.199"></a>
<span class="sourceLineNo">200</span><a name="line.200"></a>
<span class="sourceLineNo">201</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">040</span><a name="line.40"></a>
<span class="sourceLineNo">041</span>@SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})<a name="line.41"></a>
<span class="sourceLineNo">042</span>public class CommandCompletions&lt;C extends CommandCompletionContext&gt; {<a name="line.42"></a>
<span class="sourceLineNo">043</span> private static final String DEFAULT_ENUM_ID = "@__defaultenum__";<a name="line.43"></a>
<span class="sourceLineNo">044</span> private final CommandManager manager;<a name="line.44"></a>
<span class="sourceLineNo">045</span> // TODO: use a CompletionProvider that can return a delegated Id or provide values such as enum support<a name="line.45"></a>
<span class="sourceLineNo">046</span> private Map&lt;String, CommandCompletionHandler&gt; completionMap = new HashMap&lt;&gt;();<a name="line.46"></a>
<span class="sourceLineNo">047</span> private Map&lt;Class, String&gt; defaultCompletions = new HashMap&lt;&gt;();<a name="line.47"></a>
<span class="sourceLineNo">048</span><a name="line.48"></a>
<span class="sourceLineNo">049</span> public CommandCompletions(CommandManager manager) {<a name="line.49"></a>
<span class="sourceLineNo">050</span> this.manager = manager;<a name="line.50"></a>
<span class="sourceLineNo">051</span> registerStaticCompletion("empty", Collections.emptyList());<a name="line.51"></a>
<span class="sourceLineNo">052</span> registerStaticCompletion("nothing", Collections.emptyList());<a name="line.52"></a>
<span class="sourceLineNo">053</span> registerStaticCompletion("timeunits", Arrays.asList("minutes", "hours", "days", "weeks", "months", "years"));<a name="line.53"></a>
<span class="sourceLineNo">054</span> registerAsyncCompletion("range", (c) -&gt; {<a name="line.54"></a>
<span class="sourceLineNo">055</span> String config = c.getConfig();<a name="line.55"></a>
<span class="sourceLineNo">056</span> if (config == null) {<a name="line.56"></a>
<span class="sourceLineNo">057</span> return Collections.emptyList();<a name="line.57"></a>
<span class="sourceLineNo">058</span> }<a name="line.58"></a>
<span class="sourceLineNo">059</span> final String[] ranges = ACFPatterns.DASH.split(config);<a name="line.59"></a>
<span class="sourceLineNo">060</span> int start;<a name="line.60"></a>
<span class="sourceLineNo">061</span> int end;<a name="line.61"></a>
<span class="sourceLineNo">062</span> if (ranges.length != 2) {<a name="line.62"></a>
<span class="sourceLineNo">063</span> start = 0;<a name="line.63"></a>
<span class="sourceLineNo">064</span> end = ACFUtil.parseInt(ranges[0], 0);<a name="line.64"></a>
<span class="sourceLineNo">065</span> } else {<a name="line.65"></a>
<span class="sourceLineNo">066</span> start = ACFUtil.parseInt(ranges[0], 0);<a name="line.66"></a>
<span class="sourceLineNo">067</span> end = ACFUtil.parseInt(ranges[1], 0);<a name="line.67"></a>
<span class="sourceLineNo">068</span> }<a name="line.68"></a>
<span class="sourceLineNo">069</span> return IntStream.rangeClosed(start, end).mapToObj(Integer::toString).collect(Collectors.toList());<a name="line.69"></a>
<span class="sourceLineNo">070</span> });<a name="line.70"></a>
<span class="sourceLineNo">071</span> }<a name="line.71"></a>
<span class="sourceLineNo">072</span><a name="line.72"></a>
<span class="sourceLineNo">073</span> /**<a name="line.73"></a>
<span class="sourceLineNo">074</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.74"></a>
<span class="sourceLineNo">075</span> *<a name="line.75"></a>
<span class="sourceLineNo">076</span> * @param id<a name="line.76"></a>
<span class="sourceLineNo">077</span> * @param handler<a name="line.77"></a>
<span class="sourceLineNo">078</span> * @return<a name="line.78"></a>
<span class="sourceLineNo">079</span> */<a name="line.79"></a>
<span class="sourceLineNo">080</span> public CommandCompletionHandler registerCompletion(String id, CommandCompletionHandler&lt;C&gt; handler) {<a name="line.80"></a>
<span class="sourceLineNo">081</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.81"></a>
<span class="sourceLineNo">082</span> }<a name="line.82"></a>
<span class="sourceLineNo">083</span><a name="line.83"></a>
<span class="sourceLineNo">084</span> /**<a name="line.84"></a>
<span class="sourceLineNo">085</span> * Registr a completion handler to provide command completions based on the user input.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * This handler is declared to be safe to be executed asynchronously.<a name="line.86"></a>
<span class="sourceLineNo">087</span> * &lt;p&gt;<a name="line.87"></a>
<span class="sourceLineNo">088</span> * Not all platforms support this, so if the platform does not support asynchronous execution,<a name="line.88"></a>
<span class="sourceLineNo">089</span> * your handler will be executed on the main thread.<a name="line.89"></a>
<span class="sourceLineNo">090</span> * &lt;p&gt;<a name="line.90"></a>
<span class="sourceLineNo">091</span> * Use this anytime your handler does not need to access state that is not considered thread safe.<a name="line.91"></a>
<span class="sourceLineNo">092</span> * &lt;p&gt;<a name="line.92"></a>
<span class="sourceLineNo">093</span> * Use context.isAsync() to determine if you are async or not.<a name="line.93"></a>
<span class="sourceLineNo">094</span> *<a name="line.94"></a>
<span class="sourceLineNo">095</span> * @param id<a name="line.95"></a>
<span class="sourceLineNo">096</span> * @param handler<a name="line.96"></a>
<span class="sourceLineNo">097</span> * @return<a name="line.97"></a>
<span class="sourceLineNo">098</span> */<a name="line.98"></a>
<span class="sourceLineNo">099</span> public CommandCompletionHandler registerAsyncCompletion(String id, AsyncCommandCompletionHandler&lt;C&gt; handler) {<a name="line.99"></a>
<span class="sourceLineNo">100</span> return this.completionMap.put(prepareCompletionId(id), handler);<a name="line.100"></a>
<span class="sourceLineNo">101</span> }<a name="line.101"></a>
<span class="sourceLineNo">102</span><a name="line.102"></a>
<span class="sourceLineNo">103</span> /**<a name="line.103"></a>
<span class="sourceLineNo">104</span> * Register a static list of command completions that will never change.<a name="line.104"></a>
<span class="sourceLineNo">105</span> * Like @CommandCompletion, values are | (PIPE) separated.<a name="line.105"></a>
<span class="sourceLineNo">106</span> * &lt;p&gt;<a name="line.106"></a>
<span class="sourceLineNo">107</span> * Example: foo|bar|baz<a name="line.107"></a>
<span class="sourceLineNo">108</span> *<a name="line.108"></a>
<span class="sourceLineNo">109</span> * @param id<a name="line.109"></a>
<span class="sourceLineNo">110</span> * @param list<a name="line.110"></a>
<span class="sourceLineNo">111</span> * @return<a name="line.111"></a>
<span class="sourceLineNo">112</span> */<a name="line.112"></a>
<span class="sourceLineNo">113</span> public CommandCompletionHandler registerStaticCompletion(String id, String list) {<a name="line.113"></a>
<span class="sourceLineNo">114</span> return registerStaticCompletion(id, ACFPatterns.PIPE.split(list));<a name="line.114"></a>
<span class="sourceLineNo">115</span> }<a name="line.115"></a>
<span class="sourceLineNo">116</span><a name="line.116"></a>
<span class="sourceLineNo">117</span> /**<a name="line.117"></a>
<span class="sourceLineNo">118</span> * Register a static list of command completions that will never change<a name="line.118"></a>
<span class="sourceLineNo">119</span> *<a name="line.119"></a>
<span class="sourceLineNo">120</span> * @param id<a name="line.120"></a>
<span class="sourceLineNo">121</span> * @param completions<a name="line.121"></a>
<span class="sourceLineNo">122</span> * @return<a name="line.122"></a>
<span class="sourceLineNo">123</span> */<a name="line.123"></a>
<span class="sourceLineNo">124</span> public CommandCompletionHandler registerStaticCompletion(String id, String[] completions) {<a name="line.124"></a>
<span class="sourceLineNo">125</span> return registerStaticCompletion(id, Arrays.asList(completions));<a name="line.125"></a>
<span class="sourceLineNo">126</span> }<a name="line.126"></a>
<span class="sourceLineNo">127</span><a name="line.127"></a>
<span class="sourceLineNo">128</span> /**<a name="line.128"></a>
<span class="sourceLineNo">129</span> * Register a static list of command completions that will never change. The list is obtained from the supplier<a name="line.129"></a>
<span class="sourceLineNo">130</span> * immediately as part of this method call.<a name="line.130"></a>
<span class="sourceLineNo">131</span> *<a name="line.131"></a>
<span class="sourceLineNo">132</span> * @param id<a name="line.132"></a>
<span class="sourceLineNo">133</span> * @param supplier<a name="line.133"></a>
<span class="sourceLineNo">134</span> * @return<a name="line.134"></a>
<span class="sourceLineNo">135</span> */<a name="line.135"></a>
<span class="sourceLineNo">136</span> public CommandCompletionHandler registerStaticCompletion(String id, Supplier&lt;Collection&lt;String&gt;&gt; supplier) {<a name="line.136"></a>
<span class="sourceLineNo">137</span> return registerStaticCompletion(id, supplier.get());<a name="line.137"></a>
<span class="sourceLineNo">138</span> }<a name="line.138"></a>
<span class="sourceLineNo">139</span><a name="line.139"></a>
<span class="sourceLineNo">140</span> /**<a name="line.140"></a>
<span class="sourceLineNo">141</span> * Register a static list of command completions that will never change<a name="line.141"></a>
<span class="sourceLineNo">142</span> *<a name="line.142"></a>
<span class="sourceLineNo">143</span> * @param id<a name="line.143"></a>
<span class="sourceLineNo">144</span> * @param completions<a name="line.144"></a>
<span class="sourceLineNo">145</span> * @return<a name="line.145"></a>
<span class="sourceLineNo">146</span> */<a name="line.146"></a>
<span class="sourceLineNo">147</span> public CommandCompletionHandler registerStaticCompletion(String id, Collection&lt;String&gt; completions) {<a name="line.147"></a>
<span class="sourceLineNo">148</span> return registerAsyncCompletion(id, x -&gt; completions);<a name="line.148"></a>
<span class="sourceLineNo">149</span> }<a name="line.149"></a>
<span class="sourceLineNo">150</span><a name="line.150"></a>
<span class="sourceLineNo">151</span> /**<a name="line.151"></a>
<span class="sourceLineNo">152</span> * Registers a completion handler such as @players to default apply to all command parameters of the specified types<a name="line.152"></a>
<span class="sourceLineNo">153</span> * &lt;p&gt;<a name="line.153"></a>
<span class="sourceLineNo">154</span> * This enables automatic completion support for parameters without manually defining it for custom objects<a name="line.154"></a>
<span class="sourceLineNo">155</span> *<a name="line.155"></a>
<span class="sourceLineNo">156</span> * @param id<a name="line.156"></a>
<span class="sourceLineNo">157</span> * @param classes<a name="line.157"></a>
<span class="sourceLineNo">158</span> */<a name="line.158"></a>
<span class="sourceLineNo">159</span> public void setDefaultCompletion(String id, Class... classes) {<a name="line.159"></a>
<span class="sourceLineNo">160</span> // get completion with specified id<a name="line.160"></a>
<span class="sourceLineNo">161</span> id = prepareCompletionId(id);<a name="line.161"></a>
<span class="sourceLineNo">162</span> CommandCompletionHandler completion = completionMap.get(id);<a name="line.162"></a>
<span class="sourceLineNo">163</span><a name="line.163"></a>
<span class="sourceLineNo">164</span> if (completion == null) {<a name="line.164"></a>
<span class="sourceLineNo">165</span> // Throw something because no completion with specified id<a name="line.165"></a>
<span class="sourceLineNo">166</span> throw new IllegalStateException("Completion not registered for " + id);<a name="line.166"></a>
<span class="sourceLineNo">167</span> }<a name="line.167"></a>
<span class="sourceLineNo">168</span><a name="line.168"></a>
<span class="sourceLineNo">169</span> for (Class clazz : classes) {<a name="line.169"></a>
<span class="sourceLineNo">170</span> defaultCompletions.put(clazz, id);<a name="line.170"></a>
<span class="sourceLineNo">171</span> }<a name="line.171"></a>
<span class="sourceLineNo">172</span> }<a name="line.172"></a>
<span class="sourceLineNo">173</span><a name="line.173"></a>
<span class="sourceLineNo">174</span> @NotNull<a name="line.174"></a>
<span class="sourceLineNo">175</span> private static String prepareCompletionId(String id) {<a name="line.175"></a>
<span class="sourceLineNo">176</span> return (id.startsWith("@") ? "" : "@") + id.toLowerCase();<a name="line.176"></a>
<span class="sourceLineNo">177</span> }<a name="line.177"></a>
<span class="sourceLineNo">178</span><a name="line.178"></a>
<span class="sourceLineNo">179</span> @NotNull<a name="line.179"></a>
<span class="sourceLineNo">180</span> List&lt;String&gt; of(RegisteredCommand cmd, CommandIssuer sender, String[] args, boolean isAsync) {<a name="line.180"></a>
<span class="sourceLineNo">181</span> String[] completions = ACFPatterns.SPACE.split(cmd.complete);<a name="line.181"></a>
<span class="sourceLineNo">182</span> final int argIndex = args.length - 1;<a name="line.182"></a>
<span class="sourceLineNo">183</span><a name="line.183"></a>
<span class="sourceLineNo">184</span> String input = args[argIndex];<a name="line.184"></a>
<span class="sourceLineNo">185</span><a name="line.185"></a>
<span class="sourceLineNo">186</span> String completion = argIndex &lt; completions.length ? completions[argIndex] : null;<a name="line.186"></a>
<span class="sourceLineNo">187</span> if (completion == null || "*".equals(completion)) {<a name="line.187"></a>
<span class="sourceLineNo">188</span> completion = findDefaultCompletion(cmd, args);<a name="line.188"></a>
<span class="sourceLineNo">189</span> }<a name="line.189"></a>
<span class="sourceLineNo">190</span><a name="line.190"></a>
<span class="sourceLineNo">191</span> if (completion == null &amp;&amp; completions.length &gt; 0) {<a name="line.191"></a>
<span class="sourceLineNo">192</span> String last = completions[completions.length - 1];<a name="line.192"></a>
<span class="sourceLineNo">193</span> if (last.startsWith("repeat@")) {<a name="line.193"></a>
<span class="sourceLineNo">194</span> completion = last;<a name="line.194"></a>
<span class="sourceLineNo">195</span> } else if (argIndex &gt;= completions.length &amp;&amp; cmd.parameters[cmd.parameters.length - 1].consumesRest) {<a name="line.195"></a>
<span class="sourceLineNo">196</span> completion = last;<a name="line.196"></a>
<span class="sourceLineNo">197</span> }<a name="line.197"></a>
<span class="sourceLineNo">198</span> }<a name="line.198"></a>
<span class="sourceLineNo">199</span><a name="line.199"></a>
<span class="sourceLineNo">200</span> if (completion == null) {<a name="line.200"></a>
<span class="sourceLineNo">201</span> return Collections.singletonList(input);<a name="line.201"></a>
<span class="sourceLineNo">202</span> }<a name="line.202"></a>
<span class="sourceLineNo">203</span><a name="line.203"></a>
<span class="sourceLineNo">204</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.204"></a>
<span class="sourceLineNo">205</span> int i = 0;<a name="line.205"></a>
<span class="sourceLineNo">206</span> for (CommandParameter param : cmd.parameters) {<a name="line.206"></a>
<span class="sourceLineNo">207</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> Class type = param.getType();<a name="line.208"></a>
<span class="sourceLineNo">209</span> while (type != null) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> String completion = this.defaultCompletions.get(type);<a name="line.210"></a>
<span class="sourceLineNo">211</span> if (completion != null) {<a name="line.211"></a>
<span class="sourceLineNo">212</span> return completion;<a name="line.212"></a>
<span class="sourceLineNo">213</span> }<a name="line.213"></a>
<span class="sourceLineNo">214</span> type = type.getSuperclass();<a name="line.214"></a>
<span class="sourceLineNo">215</span> }<a name="line.215"></a>
<span class="sourceLineNo">216</span> if (param.getType().isEnum()) {<a name="line.216"></a>
<span class="sourceLineNo">217</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.217"></a>
<span class="sourceLineNo">218</span> //noinspection unchecked<a name="line.218"></a>
<span class="sourceLineNo">219</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.219"></a>
<span class="sourceLineNo">220</span> return DEFAULT_ENUM_ID;<a name="line.220"></a>
<span class="sourceLineNo">221</span> }<a name="line.221"></a>
<span class="sourceLineNo">222</span> break;<a name="line.222"></a>
<span class="sourceLineNo">223</span> }<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> return null;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span><a name="line.227"></a>
<span class="sourceLineNo">228</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.228"></a>
<span class="sourceLineNo">229</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.229"></a>
<span class="sourceLineNo">230</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.230"></a>
<span class="sourceLineNo">231</span> return ctx.enumCompletionValues;<a name="line.231"></a>
<span class="sourceLineNo">232</span> }<a name="line.232"></a>
<span class="sourceLineNo">233</span> if (completion.startsWith("repeat@")) {<a name="line.233"></a>
<span class="sourceLineNo">234</span> completion = completion.substring(6);<a name="line.234"></a>
<span class="sourceLineNo">204</span> return getCompletionValues(cmd, sender, completion, args, isAsync);<a name="line.204"></a>
<span class="sourceLineNo">205</span> }<a name="line.205"></a>
<span class="sourceLineNo">206</span><a name="line.206"></a>
<span class="sourceLineNo">207</span> String findDefaultCompletion(RegisteredCommand cmd, String[] args) {<a name="line.207"></a>
<span class="sourceLineNo">208</span> int i = 0;<a name="line.208"></a>
<span class="sourceLineNo">209</span> for (CommandParameter param : cmd.parameters) {<a name="line.209"></a>
<span class="sourceLineNo">210</span> if (param.canConsumeInput() &amp;&amp; ++i == args.length) {<a name="line.210"></a>
<span class="sourceLineNo">211</span> Class type = param.getType();<a name="line.211"></a>
<span class="sourceLineNo">212</span> while (type != null) {<a name="line.212"></a>
<span class="sourceLineNo">213</span> String completion = this.defaultCompletions.get(type);<a name="line.213"></a>
<span class="sourceLineNo">214</span> if (completion != null) {<a name="line.214"></a>
<span class="sourceLineNo">215</span> return completion;<a name="line.215"></a>
<span class="sourceLineNo">216</span> }<a name="line.216"></a>
<span class="sourceLineNo">217</span> type = type.getSuperclass();<a name="line.217"></a>
<span class="sourceLineNo">218</span> }<a name="line.218"></a>
<span class="sourceLineNo">219</span> if (param.getType().isEnum()) {<a name="line.219"></a>
<span class="sourceLineNo">220</span> CommandOperationContext ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.220"></a>
<span class="sourceLineNo">221</span> //noinspection unchecked<a name="line.221"></a>
<span class="sourceLineNo">222</span> ctx.enumCompletionValues = ACFUtil.enumNames((Class&lt;? extends Enum&lt;?&gt;&gt;) param.getType());<a name="line.222"></a>
<span class="sourceLineNo">223</span> return DEFAULT_ENUM_ID;<a name="line.223"></a>
<span class="sourceLineNo">224</span> }<a name="line.224"></a>
<span class="sourceLineNo">225</span> break;<a name="line.225"></a>
<span class="sourceLineNo">226</span> }<a name="line.226"></a>
<span class="sourceLineNo">227</span> }<a name="line.227"></a>
<span class="sourceLineNo">228</span> return null;<a name="line.228"></a>
<span class="sourceLineNo">229</span> }<a name="line.229"></a>
<span class="sourceLineNo">230</span><a name="line.230"></a>
<span class="sourceLineNo">231</span> List&lt;String&gt; getCompletionValues(RegisteredCommand command, CommandIssuer sender, String completion, String[] args, boolean isAsync) {<a name="line.231"></a>
<span class="sourceLineNo">232</span> if (DEFAULT_ENUM_ID.equals(completion)) {<a name="line.232"></a>
<span class="sourceLineNo">233</span> CommandOperationContext&lt;?&gt; ctx = CommandManager.getCurrentCommandOperationContext();<a name="line.233"></a>
<span class="sourceLineNo">234</span> return ctx.enumCompletionValues;<a name="line.234"></a>
<span class="sourceLineNo">235</span> }<a name="line.235"></a>
<span class="sourceLineNo">236</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.236"></a>
<span class="sourceLineNo">237</span><a name="line.237"></a>
<span class="sourceLineNo">238</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.238"></a>
<span class="sourceLineNo">239</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.239"></a>
<span class="sourceLineNo">240</span><a name="line.240"></a>
<span class="sourceLineNo">241</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.241"></a>
<span class="sourceLineNo">242</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.242"></a>
<span class="sourceLineNo">243</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.243"></a>
<span class="sourceLineNo">244</span> if (handler != null) {<a name="line.244"></a>
<span class="sourceLineNo">245</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.246"></a>
<span class="sourceLineNo">247</span> return null;<a name="line.247"></a>
<span class="sourceLineNo">248</span> }<a name="line.248"></a>
<span class="sourceLineNo">249</span> String config = complete.length == 1 ? null : complete[1];<a name="line.249"></a>
<span class="sourceLineNo">250</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.250"></a>
<span class="sourceLineNo">251</span><a name="line.251"></a>
<span class="sourceLineNo">252</span> try {<a name="line.252"></a>
<span class="sourceLineNo">253</span> //noinspection unchecked<a name="line.253"></a>
<span class="sourceLineNo">254</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.254"></a>
<span class="sourceLineNo">255</span> if (completions != null) {<a name="line.255"></a>
<span class="sourceLineNo">256</span> allCompletions.addAll(completions);<a name="line.256"></a>
<span class="sourceLineNo">257</span> continue;<a name="line.257"></a>
<span class="sourceLineNo">258</span> }<a name="line.258"></a>
<span class="sourceLineNo">259</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.259"></a>
<span class="sourceLineNo">260</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.260"></a>
<span class="sourceLineNo">261</span> throw new CommandCompletionTextLookupException();<a name="line.261"></a>
<span class="sourceLineNo">262</span> }<a name="line.262"></a>
<span class="sourceLineNo">263</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> // This should only happen if some other feedback error occured.<a name="line.264"></a>
<span class="sourceLineNo">265</span> } catch (Exception e) {<a name="line.265"></a>
<span class="sourceLineNo">266</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.266"></a>
<span class="sourceLineNo">267</span> }<a name="line.267"></a>
<span class="sourceLineNo">268</span> // Something went wrong in lookup, fall back to input<a name="line.268"></a>
<span class="sourceLineNo">269</span> return Collections.singletonList(input);<a name="line.269"></a>
<span class="sourceLineNo">270</span> } else {<a name="line.270"></a>
<span class="sourceLineNo">271</span> // Plaintext value<a name="line.271"></a>
<span class="sourceLineNo">272</span> allCompletions.add(value);<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span> }<a name="line.274"></a>
<span class="sourceLineNo">275</span> return allCompletions;<a name="line.275"></a>
<span class="sourceLineNo">276</span> }<a name="line.276"></a>
<span class="sourceLineNo">277</span><a name="line.277"></a>
<span class="sourceLineNo">278</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.278"></a>
<span class="sourceLineNo">279</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.279"></a>
<span class="sourceLineNo">280</span> }<a name="line.280"></a>
<span class="sourceLineNo">281</span><a name="line.281"></a>
<span class="sourceLineNo">282</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.282"></a>
<span class="sourceLineNo">283</span> }<a name="line.283"></a>
<span class="sourceLineNo">284</span><a name="line.284"></a>
<span class="sourceLineNo">285</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.285"></a>
<span class="sourceLineNo">286</span> }<a name="line.286"></a>
<span class="sourceLineNo">287</span><a name="line.287"></a>
<span class="sourceLineNo">288</span>}<a name="line.288"></a>
<span class="sourceLineNo">236</span> boolean repeat = completion.startsWith("repeat@");<a name="line.236"></a>
<span class="sourceLineNo">237</span> if (repeat) {<a name="line.237"></a>
<span class="sourceLineNo">238</span> completion = completion.substring(6);<a name="line.238"></a>
<span class="sourceLineNo">239</span> }<a name="line.239"></a>
<span class="sourceLineNo">240</span> completion = manager.getCommandReplacements().replace(completion);<a name="line.240"></a>
<span class="sourceLineNo">241</span><a name="line.241"></a>
<span class="sourceLineNo">242</span> List&lt;String&gt; allCompletions = new ArrayList&lt;&gt;();<a name="line.242"></a>
<span class="sourceLineNo">243</span> String input = args.length &gt; 0 ? args[args.length - 1] : "";<a name="line.243"></a>
<span class="sourceLineNo">244</span><a name="line.244"></a>
<span class="sourceLineNo">245</span> for (String value : ACFPatterns.PIPE.split(completion)) {<a name="line.245"></a>
<span class="sourceLineNo">246</span> String[] complete = ACFPatterns.COLONEQUALS.split(value, 2);<a name="line.246"></a>
<span class="sourceLineNo">247</span> CommandCompletionHandler handler = this.completionMap.get(complete[0].toLowerCase());<a name="line.247"></a>
<span class="sourceLineNo">248</span> if (handler != null) {<a name="line.248"></a>
<span class="sourceLineNo">249</span> if (isAsync &amp;&amp; !(handler instanceof AsyncCommandCompletionHandler)) {<a name="line.249"></a>
<span class="sourceLineNo">250</span> ACFUtil.sneaky(new SyncCompletionRequired());<a name="line.250"></a>
<span class="sourceLineNo">251</span> return null;<a name="line.251"></a>
<span class="sourceLineNo">252</span> }<a name="line.252"></a>
<span class="sourceLineNo">253</span> String config = complete.length == 1 ? null : complete[1];<a name="line.253"></a>
<span class="sourceLineNo">254</span> CommandCompletionContext context = manager.createCompletionContext(command, sender, input, config, args);<a name="line.254"></a>
<span class="sourceLineNo">255</span><a name="line.255"></a>
<span class="sourceLineNo">256</span> try {<a name="line.256"></a>
<span class="sourceLineNo">257</span> //noinspection unchecked<a name="line.257"></a>
<span class="sourceLineNo">258</span> Collection&lt;String&gt; completions = handler.getCompletions(context);<a name="line.258"></a>
<span class="sourceLineNo">259</span><a name="line.259"></a>
<span class="sourceLineNo">260</span> //Handle completions with more than one word:<a name="line.260"></a>
<span class="sourceLineNo">261</span> if (!repeat &amp;&amp;<a name="line.261"></a>
<span class="sourceLineNo">262</span> command.parameters[command.parameters.length - 1].consumesRest<a name="line.262"></a>
<span class="sourceLineNo">263</span> &amp;&amp; args.length &gt; ACFPatterns.SPACE.split(command.complete).length) {<a name="line.263"></a>
<span class="sourceLineNo">264</span> String start = String.join(" ", args);<a name="line.264"></a>
<span class="sourceLineNo">265</span> completions = completions.stream()<a name="line.265"></a>
<span class="sourceLineNo">266</span> .filter(s -&gt; s.split(" ").length &gt;= args.length)<a name="line.266"></a>
<span class="sourceLineNo">267</span> .filter(s -&gt; ApacheCommonsLangUtil.startsWithIgnoreCase(s, start))<a name="line.267"></a>
<span class="sourceLineNo">268</span> .map(s -&gt; {<a name="line.268"></a>
<span class="sourceLineNo">269</span> String[] completionArgs = s.split(" ");<a name="line.269"></a>
<span class="sourceLineNo">270</span> return String.join(" ",<a name="line.270"></a>
<span class="sourceLineNo">271</span> Arrays.copyOfRange(completionArgs, args.length - 1, completionArgs.length));<a name="line.271"></a>
<span class="sourceLineNo">272</span> }).collect(Collectors.toList());<a name="line.272"></a>
<span class="sourceLineNo">273</span> }<a name="line.273"></a>
<span class="sourceLineNo">274</span><a name="line.274"></a>
<span class="sourceLineNo">275</span> if (completions != null) {<a name="line.275"></a>
<span class="sourceLineNo">276</span> allCompletions.addAll(completions);<a name="line.276"></a>
<span class="sourceLineNo">277</span> continue;<a name="line.277"></a>
<span class="sourceLineNo">278</span> }<a name="line.278"></a>
<span class="sourceLineNo">279</span> //noinspection ConstantIfStatement,ConstantConditions<a name="line.279"></a>
<span class="sourceLineNo">280</span> if (false) { // Hack to fool compiler. since its sneakily thrown.<a name="line.280"></a>
<span class="sourceLineNo">281</span> throw new CommandCompletionTextLookupException();<a name="line.281"></a>
<span class="sourceLineNo">282</span> }<a name="line.282"></a>
<span class="sourceLineNo">283</span> } catch (CommandCompletionTextLookupException ignored) {<a name="line.283"></a>
<span class="sourceLineNo">284</span> // This should only happen if some other feedback error occured.<a name="line.284"></a>
<span class="sourceLineNo">285</span> } catch (Exception e) {<a name="line.285"></a>
<span class="sourceLineNo">286</span> command.handleException(sender, Arrays.asList(args), e);<a name="line.286"></a>
<span class="sourceLineNo">287</span> }<a name="line.287"></a>
<span class="sourceLineNo">288</span> // Something went wrong in lookup, fall back to input<a name="line.288"></a>
<span class="sourceLineNo">289</span> return Collections.singletonList(input);<a name="line.289"></a>
<span class="sourceLineNo">290</span> } else {<a name="line.290"></a>
<span class="sourceLineNo">291</span> // Plaintext value<a name="line.291"></a>
<span class="sourceLineNo">292</span> allCompletions.add(value);<a name="line.292"></a>
<span class="sourceLineNo">293</span> }<a name="line.293"></a>
<span class="sourceLineNo">294</span> }<a name="line.294"></a>
<span class="sourceLineNo">295</span> return allCompletions;<a name="line.295"></a>
<span class="sourceLineNo">296</span> }<a name="line.296"></a>
<span class="sourceLineNo">297</span><a name="line.297"></a>
<span class="sourceLineNo">298</span> public interface CommandCompletionHandler&lt;C extends CommandCompletionContext&gt; {<a name="line.298"></a>
<span class="sourceLineNo">299</span> Collection&lt;String&gt; getCompletions(C context) throws InvalidCommandArgument;<a name="line.299"></a>
<span class="sourceLineNo">300</span> }<a name="line.300"></a>
<span class="sourceLineNo">301</span><a name="line.301"></a>
<span class="sourceLineNo">302</span> public interface AsyncCommandCompletionHandler&lt;C extends CommandCompletionContext&gt; extends CommandCompletionHandler&lt;C&gt; {<a name="line.302"></a>
<span class="sourceLineNo">303</span> }<a name="line.303"></a>
<span class="sourceLineNo">304</span><a name="line.304"></a>
<span class="sourceLineNo">305</span> public static class SyncCompletionRequired extends RuntimeException {<a name="line.305"></a>
<span class="sourceLineNo">306</span> }<a name="line.306"></a>
<span class="sourceLineNo">307</span><a name="line.307"></a>
<span class="sourceLineNo">308</span>}<a name="line.308"></a>