From b49f0d63e62ab265f30b69ec39a536a59a72d469 Mon Sep 17 00:00:00 2001 From: AratakiLeo <83653555+aratakileo@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:03:17 +0300 Subject: [PATCH] Refactor code --- README.md | 2 +- gradle.properties | 2 +- .../suggestionsapi/SuggestionsAPI.java | 1 + .../core/SuggestionsProcessor.java | 69 ++++++++++++------- .../injector/AsyncInjector.java | 12 ++++ .../{suggestion => injector}/Injector.java | 53 +++----------- .../SuggestionsInjector.java | 3 +- .../suggestion/AsyncInjector.java | 38 ---------- 8 files changed, 72 insertions(+), 108 deletions(-) create mode 100644 src/main/java/io/github/aratakileo/suggestionsapi/injector/AsyncInjector.java rename src/main/java/io/github/aratakileo/suggestionsapi/{suggestion => injector}/Injector.java (66%) rename src/main/java/io/github/aratakileo/suggestionsapi/{suggestion => injector}/SuggestionsInjector.java (67%) delete mode 100644 src/main/java/io/github/aratakileo/suggestionsapi/suggestion/AsyncInjector.java diff --git a/README.md b/README.md index 09e4571..2c5dd8b 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ SuggestionsAPI.registerResourceDependedInjector( ``` ### How to dynamically inject suggestions? -The `Injector` interface is located in the directory `io.github.aratakileo.suggestionsapi.suggestion`. +The `Injector` interface is located in the directory `io.github.aratakileo.suggestionsapi.injector`. There are two types of injectors: simple and asynchronous. To initialize them, the library also provides functions. The first argument of which will be a regex pattern. diff --git a/gradle.properties b/gradle.properties index 68a989d..f2be7f8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ loader_version=0.14.22 # Mod Properties support_minecraft_version = 1.20.x -mod_version = 1.0.0 +mod_version = 1.0.1 prev_mod_version = 1.0.0 maven_group = io.github.aratakileo archives_base_name = suggestions-api diff --git a/src/main/java/io/github/aratakileo/suggestionsapi/SuggestionsAPI.java b/src/main/java/io/github/aratakileo/suggestionsapi/SuggestionsAPI.java index ba5da34..c3665b9 100644 --- a/src/main/java/io/github/aratakileo/suggestionsapi/SuggestionsAPI.java +++ b/src/main/java/io/github/aratakileo/suggestionsapi/SuggestionsAPI.java @@ -1,5 +1,6 @@ package io.github.aratakileo.suggestionsapi; +import io.github.aratakileo.suggestionsapi.injector.Injector; import io.github.aratakileo.suggestionsapi.suggestion.*; import io.github.aratakileo.suggestionsapi.core.SuggestionsProcessor; import net.fabricmc.api.ClientModInitializer; diff --git a/src/main/java/io/github/aratakileo/suggestionsapi/core/SuggestionsProcessor.java b/src/main/java/io/github/aratakileo/suggestionsapi/core/SuggestionsProcessor.java index 58221e2..7866fbf 100644 --- a/src/main/java/io/github/aratakileo/suggestionsapi/core/SuggestionsProcessor.java +++ b/src/main/java/io/github/aratakileo/suggestionsapi/core/SuggestionsProcessor.java @@ -1,10 +1,10 @@ package io.github.aratakileo.suggestionsapi.core; import com.mojang.brigadier.context.StringRange; -import io.github.aratakileo.suggestionsapi.suggestion.AsyncInjector; -import io.github.aratakileo.suggestionsapi.suggestion.Injector; +import io.github.aratakileo.suggestionsapi.injector.AsyncInjector; +import io.github.aratakileo.suggestionsapi.injector.Injector; import io.github.aratakileo.suggestionsapi.suggestion.Suggestion; -import io.github.aratakileo.suggestionsapi.suggestion.SuggestionsInjector; +import io.github.aratakileo.suggestionsapi.injector.SuggestionsInjector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -14,7 +14,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; -import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.regex.Pattern; @@ -22,6 +22,7 @@ public class SuggestionsProcessor { private static final Pattern WHITESPACE_PATTERN = Pattern.compile("(\\s+)"); private static final Logger LOGGER = LoggerFactory.getLogger(SuggestionsProcessor.class); + private static final HashMap<AsyncInjector, CompletableFuture<Void>> asyncProcessors = new HashMap<>(); private final String textUptoCursor; private final int wordStart; @@ -51,7 +52,7 @@ public boolean process() { final var currentExpression = textUptoCursor.substring(wordStart); final var suggestionsInjectorsBuffer = new HashMap<SuggestionsInjector, Collection<Suggestion>>(); - final var asyncInjectorsBuffer = new ArrayList<AsyncInjector>(); + final var asyncInjectorsBuffer = new HashMap<AsyncInjector, Runnable>(); for (final var injector: injectors) { var isActiveInjector = false; @@ -71,31 +72,38 @@ public boolean process() { if (injector instanceof AsyncInjector asyncInjector) { isValidInjector = true; - final var willApplySuggestions = asyncInjector.initAsyncApplier( - currentExpression, - suggestionList -> { - if (suggestionList == null || suggestionList.isEmpty()) return; + final var asyncApplier = asyncInjector.getAsyncApplier(currentExpression); - final var mojangSuggestions = new ArrayList<com.mojang.brigadier.suggestion.Suggestion>(); - final var offset = injector.getStartOffset(); + if (asyncApplier != null) { + asyncInjectorsBuffer.put(asyncInjector, () -> { + final var suggestionList = asyncApplier.get(); - suggestionList.forEach(suggestion -> { - if (suggestion.shouldShowFor(currentExpression.substring(offset))) - mojangSuggestions.add(new com.mojang.brigadier.suggestion.Suggestion( - StringRange.between(wordStart + offset, textUptoCursor.length()), - suggestion.getSuggestionText() - )); - }); + if (suggestionList == null || suggestionList.isEmpty()) { + asyncProcessors.remove(asyncInjector); + return; + } + + final var mojangSuggestions = new ArrayList<com.mojang.brigadier.suggestion.Suggestion>(); + final var offset = injector.getStartOffset(); - if (mojangSuggestions.isEmpty()) return; + suggestionList.forEach(suggestion -> { + if (suggestion.shouldShowFor(currentExpression.substring(offset))) + mojangSuggestions.add(new com.mojang.brigadier.suggestion.Suggestion( + StringRange.between(wordStart + offset, textUptoCursor.length()), + suggestion.getSuggestionText() + )); + }); - newSuggestionsApplier.accept(textUptoCursor, mojangSuggestions); + if (mojangSuggestions.isEmpty()) { + asyncProcessors.remove(asyncInjector); + return; } - ); - if (willApplySuggestions) { - asyncInjectorsBuffer.add(asyncInjector); + newSuggestionsApplier.accept(textUptoCursor, mojangSuggestions); + }); + isActiveInjector = true; + asyncProcessors.remove(asyncInjector); } } @@ -158,12 +166,23 @@ public boolean process() { var hasUsedAsyncInjector = false; - for (final var injector: asyncInjectorsBuffer) { + for (final var injectorEntry: asyncInjectorsBuffer.entrySet()) { + final var injector = injectorEntry.getKey(); + if (minOffset != -1 && injector.isIsolated() && injector.getStartOffset() > minOffset) continue; hasUsedAsyncInjector = true; - injector.runAsyncApplier(); + CompletableFuture<Void> currentCompletableFuture; + + if ( + asyncProcessors.containsKey(injector) && !( + currentCompletableFuture = asyncProcessors.get(injector) + ).isDone() + ) + currentCompletableFuture.cancel(true); + + asyncProcessors.put(injector, CompletableFuture.runAsync(injectorEntry.getValue())); } if (applicableMojangSuggestions.isEmpty() && !hasUsedAsyncInjector) return false; diff --git a/src/main/java/io/github/aratakileo/suggestionsapi/injector/AsyncInjector.java b/src/main/java/io/github/aratakileo/suggestionsapi/injector/AsyncInjector.java new file mode 100644 index 0000000..8e6b516 --- /dev/null +++ b/src/main/java/io/github/aratakileo/suggestionsapi/injector/AsyncInjector.java @@ -0,0 +1,12 @@ +package io.github.aratakileo.suggestionsapi.injector; + +import io.github.aratakileo.suggestionsapi.suggestion.Suggestion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Supplier; + +public interface AsyncInjector extends Injector { + @Nullable Supplier<@Nullable List<Suggestion>> getAsyncApplier(@NotNull String currentExpression); +} diff --git a/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/Injector.java b/src/main/java/io/github/aratakileo/suggestionsapi/injector/Injector.java similarity index 66% rename from src/main/java/io/github/aratakileo/suggestionsapi/suggestion/Injector.java rename to src/main/java/io/github/aratakileo/suggestionsapi/injector/Injector.java index 9aa72a4..a9adb4a 100644 --- a/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/Injector.java +++ b/src/main/java/io/github/aratakileo/suggestionsapi/injector/Injector.java @@ -1,13 +1,12 @@ -package io.github.aratakileo.suggestionsapi.suggestion; +package io.github.aratakileo.suggestionsapi.injector; -import io.github.aratakileo.suggestionsapi.util.TripleFunction; +import io.github.aratakileo.suggestionsapi.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; -import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.regex.Pattern; public interface Injector { @@ -60,11 +59,10 @@ public boolean isIsolated() { static @NotNull AsyncInjector async( @NotNull Pattern pattern, - TripleFunction< + BiFunction< @NotNull String, @NotNull Integer, - @NotNull Consumer<@Nullable List<Suggestion>>, - @Nullable Runnable + @Nullable List<Suggestion> > uncheckedSupplierGetter ) { return async(pattern, uncheckedSupplierGetter, false); @@ -72,58 +70,29 @@ public boolean isIsolated() { static @NotNull AsyncInjector async( @NotNull Pattern pattern, - TripleFunction< + BiFunction< @NotNull String, @NotNull Integer, - @NotNull Consumer<@Nullable List<Suggestion>>, - @Nullable Runnable + @Nullable List<Suggestion> > uncheckedSupplierGetter, boolean isIsolated ) { return new AsyncInjector() { private int startOffset = 0; - private CompletableFuture<Void> currentProcess = null; - private Runnable applier = null; @Override @Nullable - public CompletableFuture<Void> getCurrentProcess() { - return currentProcess; - } - - @Override - public void setCurrentProcess(@Nullable CompletableFuture<Void> currentProcess) { - this.currentProcess = currentProcess; - } - - @Override - public @Nullable Runnable getApplier() { - return applier; - } - - @Override - public void setApplier(@Nullable Runnable applier) { - this.applier = applier; - } - - @Override - public boolean initAsyncApplier( - @NotNull String currentExpression, - @NotNull Consumer<@Nullable List<Suggestion>> applier + public Supplier<@Nullable List<Suggestion>> getAsyncApplier( + @NotNull String currentExpression ) { final var lastMatchedStart = getLastMatchedStart(pattern, currentExpression); if (lastMatchedStart == -1) - return false; - - AsyncInjector.setApplier( - this, - uncheckedSupplierGetter.apply(currentExpression, lastMatchedStart, applier) - ); + return null; startOffset = lastMatchedStart; - return this.applier != null; + return () -> uncheckedSupplierGetter.apply(currentExpression, lastMatchedStart); } @Override diff --git a/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/SuggestionsInjector.java b/src/main/java/io/github/aratakileo/suggestionsapi/injector/SuggestionsInjector.java similarity index 67% rename from src/main/java/io/github/aratakileo/suggestionsapi/suggestion/SuggestionsInjector.java rename to src/main/java/io/github/aratakileo/suggestionsapi/injector/SuggestionsInjector.java index ca33ef8..00bb057 100644 --- a/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/SuggestionsInjector.java +++ b/src/main/java/io/github/aratakileo/suggestionsapi/injector/SuggestionsInjector.java @@ -1,5 +1,6 @@ -package io.github.aratakileo.suggestionsapi.suggestion; +package io.github.aratakileo.suggestionsapi.injector; +import io.github.aratakileo.suggestionsapi.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/AsyncInjector.java b/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/AsyncInjector.java deleted file mode 100644 index dad2b8f..0000000 --- a/src/main/java/io/github/aratakileo/suggestionsapi/suggestion/AsyncInjector.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.github.aratakileo.suggestionsapi.suggestion; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -public interface AsyncInjector extends Injector { - @Nullable CompletableFuture<Void> getCurrentProcess(); - - void setCurrentProcess(@Nullable CompletableFuture<Void> currentProcess); - - @Nullable Runnable getApplier(); - - void setApplier(@Nullable Runnable applier); - - default void runAsyncApplier() { - if (getApplier() == null) return; - - setCurrentProcess(CompletableFuture.runAsync(getApplier())); - } - - boolean initAsyncApplier( - @NotNull String currentExpression, - @NotNull Consumer<@Nullable List<Suggestion>> applier - ); - - static void setApplier(@NotNull AsyncInjector asyncInjector, @Nullable Runnable applier) { - final var currentProcess = asyncInjector.getCurrentProcess(); - - if (currentProcess != null && !currentProcess.isDone()) - currentProcess.cancel(true); - - asyncInjector.setApplier(applier); - } -}