Skip to content

Commit

Permalink
GH-3 Add Tabcomplete support. (#3)
Browse files Browse the repository at this point in the history
* Update LiteCommandManager.

* Add tab suggestion system.

* Become independent of some dependencies.

* Fix isLastResolver.

* Rename class in velocity module.

* Update README.md
  • Loading branch information
Rollczi authored Nov 17, 2021
1 parent 25b89f5 commit cd2fbf0
Show file tree
Hide file tree
Showing 33 changed files with 362 additions and 116 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class HelloWorldCommand {
```
Register your first command in plugin main class: (in this case for Velocity)
```java
this.liteCommands = VelocityFactory.builder(proxy)
this.liteCommands = LiteVelocityFactory.builder(proxy)
.command(HelloWorldCommand.class)
.register();
```
Expand Down
9 changes: 3 additions & 6 deletions litecommands-core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
dependencies {

// panda
implementation 'org.panda-lang:expressible:1.1.1'
implementation 'org.panda-lang.utilities:di:1.4.1'

// google & slf4j
implementation 'com.google.guava:guava:31.0.1-jre'
implementation 'org.slf4j:slf4j-api:1.7.32'

// [test] kotlin
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31'
// [test] groovy
testImplementation 'org.codehaus.groovy:groovy-all:2.4.15'
testImplementation 'org.codehaus.groovy:groovy-all:3.0.8'
// [test] junit-jupiter
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@
import dev.rollczi.litecommands.component.ScopeMetaData;
import dev.rollczi.litecommands.valid.ValidationCommandException;

import java.util.List;

public interface LiteCommandManager {

void registerCommand(ScopeMetaData forScope, CommandInvocationExecutor execute);
void registerCommand(ScopeMetaData forScope, Executor execute, Suggester suggester);

void unregisterCommands();

@FunctionalInterface
interface CommandInvocationExecutor {
interface Executor {

void execute(LiteInvocation invocation) throws ValidationCommandException;

}

interface Suggester {

List<String> suggest(LiteInvocation invocation);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import dev.rollczi.litecommands.component.LiteSection;
import dev.rollczi.litecommands.valid.ValidationMessagesService;
import org.panda_lang.utilities.inject.Injector;
import org.slf4j.Logger;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.logging.Logger;

public class LiteCommands {

Expand All @@ -24,8 +25,8 @@ public class LiteCommands {
this.logger = logger;
}

public Set<LiteSection> getResolvers() {
return Collections.unmodifiableSet(resolvers);
public Collection<LiteSection> getResolvers() {
return Collections.unmodifiableCollection(resolvers);
}

public LiteCommandManager getCommandManager() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,21 @@
import dev.rollczi.litecommands.valid.handle.ValidationExceptionHandler;
import org.panda_lang.utilities.inject.DependencyInjection;
import org.panda_lang.utilities.inject.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

public class LiteCommandsBuilder {

private final Set<Class<?>> commandClasses = new HashSet<>();
private final Set<Object> commandInstances = new HashSet<>();
private final Set<Bind> binds = new HashSet<>();
private final Map<Class<?>, SingleArgumentHandler<?>> argumentParsers = new HashMap<>();
private final Map<Class<?>, SingleArgumentHandler<?>> argumentHandlers = new HashMap<>();
private final ValidationMessagesService messagesService = new ValidationMessagesService();
private ValidationExceptionHandler validationExceptionHandler;
private LiteCommandManager commandManager;
Expand Down Expand Up @@ -81,7 +80,7 @@ public <T> LiteCommandsBuilder bind(Class<T> on, Object instance) {
}

public <T> LiteCommandsBuilder argument(Class<T> on, SingleArgumentHandler<T> singleArgumentHandler) {
this.argumentParsers.put(on, singleArgumentHandler);
this.argumentHandlers.put(on, singleArgumentHandler);
return this;
}

Expand All @@ -106,7 +105,7 @@ public LiteCommands register() {
}

if (logger == null) {
logger = LoggerFactory.getLogger("LiteCommands");
logger = Logger.getLogger("LiteCommands");
}

if (validationExceptionHandler == null) {
Expand All @@ -119,7 +118,7 @@ public LiteCommands register() {
InjectContext context = InjectUtils.getContextFromObjects(objects);
LiteInvocation invocation = context.getInvocation();

for (Map.Entry<Class<?>, SingleArgumentHandler<?>> entry : argumentParsers.entrySet()) {
for (Map.Entry<Class<?>, SingleArgumentHandler<?>> entry : argumentHandlers.entrySet()) {
Class<?> on = entry.getKey();
SingleArgumentHandler<?> singleArgumentHandler = entry.getValue();

Expand All @@ -134,7 +133,7 @@ public LiteCommands register() {
});
});

AnnotationParser parser = new LiteAnnotationParser();
AnnotationParser parser = new LiteAnnotationParser(argumentHandlers);
LiteComponentFactory factory = new LiteComponentFactory(logger, injector, parser);
Set<LiteSection> resolvers = new HashSet<>();

Expand All @@ -156,14 +155,14 @@ public LiteCommands register() {
for (LiteSection resolver : resolvers) {
commandManager.registerCommand(resolver.getScope(), invocation -> {
try {
resolver.resolve(LiteComponent.Data.create(invocation));
resolver.resolveExecution(LiteComponent.MetaData.create(invocation));
} catch (ValidationCommandException exception) {
validationExceptionHandler.handle(invocation, exception);
}
});
}, invocation -> resolver.resolveCompletion(LiteComponent.MetaData.create(invocation)));
}

return new LiteCommands(resolvers, commandManager, messagesService, injector, logger);
return new LiteCommands(resolvers, commandManager, messagesService, injector, logger);
}

public static LiteCommandsBuilder builder() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dev.rollczi.litecommands.annotations.IgnoreClass;
import dev.rollczi.litecommands.annotations.IgnoreMethod;
import dev.rollczi.litecommands.component.ScopeMetaData;
import dev.rollczi.litecommands.inject.SingleArgumentHandler;
import panda.std.Option;

import java.lang.reflect.AnnotatedElement;
Expand All @@ -20,4 +21,6 @@ public interface AnnotationParser {
*/
Option<ScopeMetaData> parse(AnnotatedElement annotatedElement);

Option<SingleArgumentHandler<?>> getArgumentHandler(Class<?> argumentClass);

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import dev.rollczi.litecommands.annotations.Section;
import dev.rollczi.litecommands.annotations.UsageMessage;
import dev.rollczi.litecommands.component.ScopeMetaData;
import dev.rollczi.litecommands.inject.SingleArgumentHandler;
import dev.rollczi.litecommands.valid.ValidationInfo;
import dev.rollczi.litecommands.annotations.Execute;
import dev.rollczi.litecommands.annotations.IgnoreMethod;
Expand All @@ -20,9 +21,16 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Map;

public class LiteAnnotationParser implements AnnotationParser {

private final Map<Class<?>, SingleArgumentHandler<?>> argumentHandlers;

public LiteAnnotationParser(Map<Class<?>, SingleArgumentHandler<?>> argumentHandlers) {
this.argumentHandlers = argumentHandlers;
}

@Override
public Option<ScopeMetaData> parse(AnnotatedElement annotatedElement) {
if (!(annotatedElement instanceof Class) && !(annotatedElement instanceof Method)) {
Expand Down Expand Up @@ -106,4 +114,9 @@ public Option<ScopeMetaData> parse(AnnotatedElement annotatedElement) {
return Option.of(builder.build());
}

@Override
public Option<SingleArgumentHandler<?>> getArgumentHandler(Class<?> argumentClass) {
return Option.of(argumentHandlers.get(argumentClass));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,32 @@

public interface LiteComponent {

void resolve(Data data);
void resolveExecution(MetaData data);

List<String> resolveCompletion(MetaData data);

ScopeMetaData getScope();

class Data {
private final LiteInvocation invocation;
private final List<LiteComponent> tracesOfResolvers = new ArrayList<>();
class MetaData {
protected final LiteInvocation invocation;
protected final List<LiteComponent> tracesOfResolvers = new ArrayList<>();

private Data(Data data, LiteComponent resolver) {
private MetaData(MetaData data, LiteComponent resolver) {
this.invocation = data.invocation;
this.tracesOfResolvers.addAll(data.tracesOfResolvers);
this.tracesOfResolvers.add(resolver);
}

private Data(LiteInvocation invocation) {
private MetaData(LiteInvocation invocation) {
this.invocation = invocation;
}

Data resolverNestingTracing(LiteComponent currentResolver) {
MetaData resolverNestingTracing(LiteComponent currentResolver) {
if (this.invocation.arguments().length + 1 < tracesOfResolvers.size()) {
throw new IllegalStateException();
}

return new Data(this, currentResolver);
return new MetaData(this, currentResolver);
}

public int getCurrentArgsCount(LiteComponent context) {
Expand All @@ -40,19 +42,20 @@ public int getCurrentArgsCount(LiteComponent context) {
: invocation.arguments().length - tracesOfResolvers.size();
}

public String getNextPredictedResolverName() {
String[] arguments = this.invocation.arguments();
int size = tracesOfResolvers.size();

if (arguments.length == size) {
public boolean isLastResolver() {
return invocation.arguments().length - 1 <= tracesOfResolvers.size();
}

public String getNextPredictedPartOfSuggestion() {
if (this.isLastResolver()) {
return StringUtils.EMPTY;
}

if (arguments.length < size) {
throw new IllegalStateException();
}
return this.invocation.arguments()[tracesOfResolvers.size()];
}

return arguments[size];
public String getCurrentPartOfCommand() {
return this.invocation.arguments()[tracesOfResolvers.size()];
}

public List<LiteComponent> getTracesOfResolvers() {
Expand All @@ -63,8 +66,8 @@ public LiteInvocation getInvocation() {
return invocation;
}

public static Data create(LiteInvocation invocation) {
return new Data(invocation);
public static MetaData create(LiteInvocation invocation) {
return new MetaData(invocation);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import dev.rollczi.litecommands.annotations.parser.AnnotationParser;
import org.panda_lang.utilities.inject.Injector;
import org.slf4j.Logger;
import panda.std.Option;
import panda.std.Result;
import panda.std.stream.PandaStream;

import java.lang.reflect.Method;
import java.util.Set;
import java.util.logging.Logger;

public class LiteComponentFactory {

Expand Down Expand Up @@ -53,7 +53,7 @@ public Option<LiteSection> createSection(Class<?> sectionClass) throws Throwable

public Option<LiteExecution> createExecution(Object instance, Method executionMethod) {
return parser.parse(executionMethod)
.map((scope) -> new LiteExecution(logger, scope, new MethodExecutor(executionMethod, instance, injector)));
.map((scope) -> new LiteExecution(logger, parser, scope, new MethodExecutor(executionMethod, instance, injector)));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,35 @@

import dev.rollczi.litecommands.LiteInvocation;
import dev.rollczi.litecommands.LiteSender;
import dev.rollczi.litecommands.annotations.parser.AnnotationParser;
import dev.rollczi.litecommands.inject.InjectContext;
import dev.rollczi.litecommands.valid.Valid;
import dev.rollczi.litecommands.valid.ValidationCommandException;
import dev.rollczi.litecommands.valid.ValidationInfo;
import org.slf4j.Logger;
import panda.std.stream.PandaStream;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

public final class LiteExecution extends AbstractComponent {

private final Logger logger;
private final AnnotationParser parser;
private final MethodExecutor executor;

LiteExecution(Logger logger, ScopeMetaData scopeMetaData, MethodExecutor executor) {
LiteExecution(Logger logger, AnnotationParser parser, ScopeMetaData scopeMetaData, MethodExecutor executor) {
super(scopeMetaData);
this.logger = logger;
this.parser = parser;
this.executor = executor;
}

@Override
public void resolve(Data data) {
public void resolveExecution(MetaData data) {
LiteInvocation invocation = data.getInvocation();
LiteSender sender = invocation.sender();

Expand All @@ -48,8 +54,21 @@ public void resolve(Data data) {
throw exception;
}

logger.error(error.getFirst(), error.getSecond());
logger.log(Level.SEVERE, error.getFirst(), error.getSecond());
});
}

@Override
public List<String> resolveCompletion(MetaData data) {
return getExecutorCompletion(data, data.getCurrentArgsCount(this) - 1);
}

public List<String> getExecutorCompletion(MetaData data, int argNumber) {
LiteInvocation invocation = data.getInvocation();

return executor.getParameter(argNumber)
.flatMap(parser::getArgumentHandler)
.map(argumentHandler -> argumentHandler.tabulation(invocation.name(), invocation.arguments()))
.orElseGet(Collections.emptyList());
}
}
Loading

0 comments on commit cd2fbf0

Please sign in to comment.