Class TabCompletionManager
- Since:
- 6.2.0
- Version:
- 1.0.0
- Author:
- wisdomme
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final classOne key's registration: the completer and the owner it was attributed to, replaced and removed as a unit. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final StringBuilt-in completer prefix for blocks.static final StringBuilt-in completer prefix for boolean values.private final Map<String, TabCompletionManager.Registration> Key -> its registration: the completer together with the owner name and owner instance the registration was attributed to (05-06 / D-08, T-05-24; #506).private final ThreadLocal<String> The owner currently attributed to registrations made viaregister(String, TabCompleter)-- set bybeginRegistrationScope(String), cleared byendRegistrationScope().private final ThreadLocal<UltiToolsPlugin> The module instance attributed to registrations in the current scope, if the scope names one (#506).private static TabCompletionManagerstatic final StringBuilt-in completer prefix for items.private static final Loggerstatic final StringBuilt-in completer prefix for materials.private final MethodInvocationCompleterstatic final StringBuilt-in completer prefix for players.static final StringBuilt-in completer prefix for toggle values.static final StringBuilt-in completer prefix for worlds. -
Constructor Summary
ConstructorsModifierConstructorDescriptionprivatePrivate constructor - use getInstance(). -
Method Summary
Modifier and TypeMethodDescriptionvoidbeginRegistrationScope(String owner) Marks the beginning of a registration scope attributed toowner-- every completer key registered viaregister(String, TabCompleter)while this scope is active is recorded as owned byowner, sounregisterByOwner(String)can sweep it later without requiring caller code to pass an owner explicitly (05-06 / D-08's "explicit owner parameter on an internal registration path" -- the parameter is ambient rather than a new argument on the publishedregister(String, TabCompleter)signature, which stays frozen).voidbeginRegistrationScope(String owner, UltiToolsPlugin ownerInstance) Same asbeginRegistrationScope(String), and additionally attributes every key registered in the scope toownerInstance, sounregisterByOwnerInstance(UltiToolsPlugin)can release exactly that module instance's completers (#506).private TabCompletercompleterFor(String key) createContext(org.bukkit.entity.Player player, org.bukkit.command.Command command, String[] args) Creates a context for tab completion with common defaults.voidEnds the current registration scope started bybeginRegistrationScope(String).filterByInput(List<String> suggestions, String input) Helper method to filter suggestions by current input.getCompleter(String key) Gets a registered completer by key.static TabCompletionManagerGets the singleton instance.voidregister(String key, TabCompleter completer) Registers a custom completer with a key.private voidRegisters all built-in completers.releaseForSupersede(UltiToolsPlugin ownerInstance) Releases every completer key registered in a scope that namedownerInstanceand returns the action that gives them back (#562).static StringresolveSuggestValue(Method matchedMethod, String parameterName) ResolvesmatchedMethod's@CmdParam.suggest()value for the parameter whose@CmdParam.value()equalsparameterName-- i.e.private voidrestore(Map<String, TabCompletionManager.Registration> released) suggest(TabCompletionContext context) Generates suggestions using the given context.suggest(TabCompletionContext context, String resolvedSuggest) Resolves suggestions using an explicitly-resolved@CmdParam.suggest()value, rather thancontext'sTabCompletionContext.parameterName-- which carries@CmdParam.value(), the parameter's DISPLAY NAME, not its suggestion (05-06 / D-07 Pitfall 2, T-05-28).Generates suggestions using the appropriate completer.suggestFirstArgs(Map<String, Method> mappings, TabCompletionContext context) Suggests command format first arguments from mappings.suggestWith(TabCompletionContext context, String completerKey) Suggests completions for a specific parameter type.voidunregister(String key) Unregisters a completer.intunregisterByOwner(String owner) Bulk-unregisters every completer key currently attributed toownerby an earlierbeginRegistrationScope(String)/endRegistrationScope()window.intunregisterByOwnerInstance(UltiToolsPlugin ownerInstance) Unregisters every completer key registered in a scope that namedownerInstance(#506), whatever name the scope carried.
-
Field Details
-
PLAYERS
Built-in completer prefix for players.- See Also:
-
WORLDS
Built-in completer prefix for worlds.- See Also:
-
MATERIALS
Built-in completer prefix for materials.- See Also:
-
BLOCKS
Built-in completer prefix for blocks.- See Also:
-
ITEMS
Built-in completer prefix for items.- See Also:
-
BOOLEAN
Built-in completer prefix for boolean values.- See Also:
-
TOGGLE
Built-in completer prefix for toggle values.- See Also:
-
LOGGER
-
instance
-
completers
Key -> its registration: the completer together with the owner name and owner instance the registration was attributed to (05-06 / D-08, T-05-24; #506). One immutable entry per key, replaced as a whole byregister(String, TabCompleter)and removed by the owner sweeps only while it is still the exact entry they matched, so a key registered again meanwhile -- from another thread, or by anything the sweep triggers -- keeps its new completer (Codex review of #564, round 4). The owner fields are recorded only while abeginRegistrationScope(String)/endRegistrationScope()window is active; a completer registered outside one is "unowned" and never swept. Keyed by the completer KEY (aString), not by the completer'sClass-- Phase 1 D-35/D-38 forbids staticClass-keyed maps because they pin a plugin's ClassLoader. An owner instance is held only until that module is unloaded, exactly as the completer object itself is. -
methodCompleter
-
currentOwner
The owner currently attributed to registrations made viaregister(String, TabCompleter)-- set bybeginRegistrationScope(String), cleared byendRegistrationScope().ThreadLocalrather than a plain field becausegetInstance()is one process-wide singleton and PluginManager's own module loading, while sequential today, should not silently corrupt ownership if that ever changes. -
currentOwnerInstance
The module instance attributed to registrations in the current scope, if the scope names one (#506). Two copies of one module share a name, so only the instance tells a superseded copy's completers from its replacement's;unregisterByOwnerInstance(UltiToolsPlugin)releases by it.
-
-
Constructor Details
-
TabCompletionManager
private TabCompletionManager()Private constructor - use getInstance().
-
-
Method Details
-
getInstance
Gets the singleton instance.- Returns:
- the tab completion manager instance
-
registerBuiltInCompleters
private void registerBuiltInCompleters()Registers all built-in completers. -
register
Registers a custom completer with a key.- Parameters:
key- the key to register with (e.g., "@custom")completer- the completer to register
-
unregister
Unregisters a completer.- Parameters:
key- the key to unregister
-
beginRegistrationScope
Marks the beginning of a registration scope attributed toowner-- every completer key registered viaregister(String, TabCompleter)while this scope is active is recorded as owned byowner, sounregisterByOwner(String)can sweep it later without requiring caller code to pass an owner explicitly (05-06 / D-08's "explicit owner parameter on an internal registration path" -- the parameter is ambient rather than a new argument on the publishedregister(String, TabCompleter)signature, which stays frozen).ClassLoader-derived ownership was considered and rejected for this codebase. Every internal
UltiToolsPluginmodule is loaded through ONE sharedURLClassLoadercovering the wholeplugins/folder (seePluginManager.init(ClassLoader)) -- the identical structural finding already recorded atPluginManager.validateAdditionalEntity's javadoc for D-19 -- so a completer instance'sgetClass().getClassLoader()cannot distinguish between two different modules here. An explicit scope is the only mechanism reachable from a module's only registration entry point (the publicregister(String, TabCompleter)) that still correctly separates two modules' completers.Not part of the frozen 6.2.5 singleton shape (
getInstance(),register(String, TabCompleter),unregister(String)) -- new in 6.3.0, intended forPluginManager's own module load/unload sequence, not for module authors.Scopes do not nest: a second
beginRegistrationScopecall while one is already active simply replaces the current owner.UltiTools' own module loading is sequential -- one module's container is fully assembled (including itspluginContext.refresh(), where@PostConstructruns) before the next module's load begins -- so nesting has never been required; this is a stated assumption, not an enforced invariant.- Parameters:
owner- the identifier (the framework uses the plugin's name) to attribute subsequent registrations to- Since:
- 6.3.0
-
beginRegistrationScope
Same asbeginRegistrationScope(String), and additionally attributes every key registered in the scope toownerInstance, sounregisterByOwnerInstance(UltiToolsPlugin)can release exactly that module instance's completers (#506).PluginManageropens this form for every module it loads: when a newer copy of a module replaces an older one, both copies share a name, and only the instance tells their completers apart.- Parameters:
owner- the name to attribute subsequent registrations to, as inbeginRegistrationScope(String)ownerInstance- the module instance to attribute them to;nullrecords none, which is exactlybeginRegistrationScope(String)- Since:
- 6.3.0
-
endRegistrationScope
public void endRegistrationScope()Ends the current registration scope started bybeginRegistrationScope(String). Registrations made after this call (and before another scope begins) are unowned and never swept byunregisterByOwner(String)-- the same as every registration made before this mechanism existed.- Since:
- 6.3.0
-
unregisterByOwner
Bulk-unregisters every completer key currently attributed toownerby an earlierbeginRegistrationScope(String)/endRegistrationScope()window. Each key is removed only while it still holds the registration the sweep matched, so a key registered again meanwhile keeps its new completer (Codex review of #564, round 4). A key registered outside any scope (core built-ins, or any caller that never callsbeginRegistrationScope(String)) has no recorded owner and is never matched here, regardless ofowner's value.- Parameters:
owner- the owner identifier to sweep;nullmatches nothing and is a no-op- Returns:
- the number of keys unregistered
- Since:
- 6.3.0
-
unregisterByOwnerInstance
Unregisters every completer key registered in a scope that namedownerInstance(#506), whatever name the scope carried. A key another module or another copy of the same module registered afterwards belongs to that registrant and is not touched, and a key registered without an instance is never matched here --unregisterByOwner(String)still releases those by name.- Parameters:
ownerInstance- the module instance being unloaded;nullmatches nothing- Returns:
- the number of keys unregistered
- Since:
- 6.3.0
-
releaseForSupersede
Releases every completer key registered in a scope that namedownerInstanceand returns the action that gives them back (#562).PluginManagercalls this for a loaded copy of a module just before a newer copy of the same module builds its container and runsregisterSelf(), so the newer copy registers its keys into a registry that holds none of the older copy's. When the newer copy fails to load, the framework first releases what the failed copy registered and then runs the returned action, which puts each released completer back under its key, unchanged; when the newer copy loads, the action is dropped and the older copy is unloaded. Running the action more than once restores nothing more.As in the owner sweeps, a key is removed only while it still holds the registration this call matched, and put back only while it is free: a key registered again in between keeps its new completer, and one WARNING names the key -- a copy never takes over another copy's key. Intended for
PluginManager, not for module authors.- Parameters:
ownerInstance- the loaded copy being superseded;nullreleases nothing- Returns:
- the action that restores what this call released
- Since:
- 6.3.0
-
restore
-
getCompleter
Gets a registered completer by key.- Parameters:
key- the completer key- Returns:
- the completer or null if not found
-
completerFor
-
suggest
public List<String> suggest(org.bukkit.entity.Player player, org.bukkit.command.Command command, String[] args) Generates suggestions using the appropriate completer.- Parameters:
player- the player requesting completioncommand- the commandargs- the current arguments- Returns:
- list of suggestions
-
suggest
Generates suggestions using the given context.- Parameters:
context- the completion context- Returns:
- list of suggestions
-
suggest
Resolves suggestions using an explicitly-resolved@CmdParam.suggest()value, rather thancontext'sTabCompletionContext.parameterName-- which carries@CmdParam.value(), the parameter's DISPLAY NAME, not its suggestion (05-06 / D-07 Pitfall 2, T-05-28).suggest(TabCompletionContext)above is left untouched for existing callers; this overload is the dual-notation entry point a caller that has already resolved the realsuggest()value (seeresolveSuggestValue(Method, String)) should use instead.A
resolvedSuggestbeginning with@resolves as a built-in or registered completer key. Any other value -- includingnullor empty -- falls through to the existing method-invocation completer (and its i18n hint-text fallback), unchanged.- Parameters:
context- the completion contextresolvedSuggest- the already-resolved@CmdParam.suggest()string for the parameter being completed; may benullor empty- Returns:
- the suggestions; never null
- Since:
- 6.3.0
-
resolveSuggestValue
ResolvesmatchedMethod's@CmdParam.suggest()value for the parameter whose@CmdParam.value()equalsparameterName-- i.e. it keys the lookup off the parameter's DISPLAY NAME to find the right parameter, then returns that parameter's suggestion, never the display name itself (05-06 / D-07). This mirrorsMethodInvocationCompleter.getSuggestName's existing lookup shape so the two stay consistent, without depending on that private method directly.- Parameters:
matchedMethod- the matched@CmdMappingmethod, ornullparameterName- the parameter's display name (@CmdParam.value()) to look up- Returns:
- the resolved
suggest()value, ornullifmatchedMethodisnullor no parameter'svalue()matchesparameterName - Since:
- 6.3.0
-
suggestWith
Suggests completions for a specific parameter type.- Parameters:
context- the completion contextcompleterKey- the key of the completer to use- Returns:
- list of suggestions
-
createContext
public TabCompletionContext createContext(org.bukkit.entity.Player player, org.bukkit.command.Command command, String[] args) Creates a context for tab completion with common defaults.- Parameters:
player- the playercommand- the commandargs- the arguments- Returns:
- a tab completion context
-
filterByInput
Helper method to filter suggestions by current input.- Parameters:
suggestions- the suggestions to filterinput- the current input- Returns:
- filtered suggestions
-
suggestFirstArgs
Suggests command format first arguments from mappings.- Parameters:
mappings- the command mappings (format -> method)context- the completion context- Returns:
- list of first argument suggestions
-