renamed modules dir

This commit is contained in:
2022-07-20 13:28:01 +02:00
parent 7dcd92f72d
commit d2ca501203
205 changed files with 12 additions and 12 deletions

1
pandalib-cli/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target/

54
pandalib-cli/pom.xml Normal file
View File

@@ -0,0 +1,54 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.pandacube.lib</groupId>
<artifactId>pandalib-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>pandalib-cli</artifactId>
<packaging>jar</packaging>
<repositories>
<repository>
<id>minecraft-libraries</id>
<name>Minecraft Libraries</name>
<url>https://libraries.minecraft.net</url>
</repository>
<repository>
<id>bungeecord-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>fr.pandacube.lib</groupId>
<artifactId>pandalib-core</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-log</artifactId>
<version>${bungeecord.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId>
<version>${bungeecord.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>brigadier</artifactId>
<version>1.0.17</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,139 @@
package fr.pandacube.lib.cli;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.ParsedCommandNode;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import fr.pandacube.lib.chat.ChatStatic;
import fr.pandacube.lib.core.commands.SuggestionsSupplier;
import fr.pandacube.lib.util.Log;
import fr.pandacube.lib.reflect.Reflect;
public abstract class BrigadierCommand extends ChatStatic {
public BrigadierCommand() {
LiteralArgumentBuilder<Object> builder = buildCommand();
String[] aliases = getAliases();
if (aliases == null)
aliases = new String[0];
LiteralCommandNode<Object> commandNode = BrigadierDispatcher.instance.register(builder);
for (String alias : aliases) {
BrigadierDispatcher.instance.register(literal(alias)
.requires(commandNode.getRequirement())
.executes(commandNode.getCommand())
.redirect(commandNode)
);
}
}
protected abstract LiteralArgumentBuilder<Object> buildCommand();
protected String[] getAliases() {
return new String[0];
}
public static LiteralArgumentBuilder<Object> literal(String name) {
return LiteralArgumentBuilder.literal(name);
}
public static <T> RequiredArgumentBuilder<Object, T> argument(String name, ArgumentType<T> type) {
return RequiredArgumentBuilder.argument(name, type);
}
public static boolean isLiteralParsed(CommandContext<Object> context, String literal) {
for (ParsedCommandNode<Object> node : context.getNodes()) {
if (!(node.getNode() instanceof LiteralCommandNode))
continue;
if (((LiteralCommandNode<Object>)node.getNode()).getLiteral().equals(literal))
return true;
}
return false;
}
public static <T> T tryGetArgument(CommandContext<Object> context, String argument, Class<T> type) {
return tryGetArgument(context, argument, type, null);
}
public static <T> T tryGetArgument(CommandContext<Object> context, String argument, Class<T> type, T deflt) {
try {
return context.getArgument(argument, type);
} catch (IllegalArgumentException e) {
return deflt;
}
}
protected static SuggestionProvider<Object> wrapSuggestions(SuggestionsSupplier<Object> suggestions) {
return (context, builder) -> {
Object sender = context.getSource();
String message = builder.getInput();
try {
int tokenStartPos = builder.getStart();
int firstSpacePos = message.indexOf(" ");
String[] args = (firstSpacePos + 1 > tokenStartPos - 1) ? new String[0]
: message.substring(firstSpacePos + 1, tokenStartPos - 1).split(" ", -1);
args = Arrays.copyOf(args, args.length + 1);
args[args.length - 1] = message.substring(tokenStartPos);
List<String> results = suggestions.getSuggestions(sender, args.length - 1, args[args.length - 1], args);
for (String s : results) {
if (s != null)
builder.suggest(s);
}
} catch (Throwable e) {
Log.severe("Error while tab-completing '" + message/* + "' for " + sender.getName()*/, e);
}
return completableFutureSuggestionsKeepsOriginalOrdering(builder);
};
}
public static CompletableFuture<Suggestions> completableFutureSuggestionsKeepsOriginalOrdering(SuggestionsBuilder builder) {
return CompletableFuture.completedFuture(
BrigadierDispatcher.createSuggestionsOriginalOrdering(builder.getInput(), getSuggestionsFromSuggestionsBuilder(builder))
);
}
@SuppressWarnings("unchecked")
private static List<Suggestion> getSuggestionsFromSuggestionsBuilder(SuggestionsBuilder builder) {
try {
return (List<Suggestion>) Reflect.ofClass(SuggestionsBuilder.class).field("result").getValue(builder);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,158 @@
package fr.pandacube.lib.cli;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.context.SuggestionContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import fr.pandacube.lib.util.Log;
import jline.console.completer.Completer;
public class BrigadierDispatcher implements Completer {
public static final BrigadierDispatcher instance = new BrigadierDispatcher();
private final CommandDispatcher<Object> dispatcher;
private final Object sender = new Object();
public BrigadierDispatcher() {
dispatcher = new CommandDispatcher<>();
}
/* package */ LiteralCommandNode<Object> register(LiteralArgumentBuilder<Object> node) {
return dispatcher.register(node);
}
public int execute(String commandWithoutSlash) {
ParseResults<Object> parsed = dispatcher.parse(commandWithoutSlash, sender);
try {
return dispatcher.execute(parsed);
} catch (CommandSyntaxException e) {
Log.severe("Erreur dutilisation de la commande : " + e.getMessage());
return 0;
} catch (Throwable e) {
Log.severe("Erreur lors de lexécution de la commande : ", e);
return 0;
}
}
@Override
public int complete(String buffer, int cursor, List<CharSequence> candidates) {
String bufferBeforeCursor = buffer.substring(0, cursor);
Suggestions completeResult = getSuggestions(bufferBeforeCursor);
completeResult.getList().stream()
.map(Suggestion::getText)
.forEach(candidates::add);
return completeResult.getRange().getStart();
}
/* package */ Suggestions getSuggestions(String buffer) {
ParseResults<Object> parsed = dispatcher.parse(buffer, sender);
try {
CompletableFuture<Suggestions> futureSuggestions = buildSuggestionBrigadier(parsed);
return futureSuggestions.join();
} catch (Throwable e) {
Log.severe("Erreur dexécution des suggestions :\n" + e.getMessage(), e);
return Suggestions.empty().join();
}
}
CompletableFuture<Suggestions> buildSuggestionBrigadier(ParseResults<Object> parsed) {
int cursor = parsed.getReader().getTotalLength();
final CommandContextBuilder<Object> context = parsed.getContext();
final SuggestionContext<Object> nodeBeforeCursor = context.findSuggestionContext(cursor);
final CommandNode<Object> parent = nodeBeforeCursor.parent;
final int start = Math.min(nodeBeforeCursor.startPos, cursor);
final String fullInput = parsed.getReader().getString();
final String truncatedInput = fullInput.substring(0, cursor);
@SuppressWarnings("unchecked") final CompletableFuture<Suggestions>[] futures = new CompletableFuture[parent.getChildren().size()];
int i = 0;
for (final CommandNode<Object> node : parent.getChildren()) {
CompletableFuture<Suggestions> future = Suggestions.empty();
try {
future = node.listSuggestions(context.build(truncatedInput), new SuggestionsBuilder(truncatedInput, start));
} catch (final CommandSyntaxException ignored) {
}
futures[i++] = future;
}
final CompletableFuture<Suggestions> result = new CompletableFuture<>();
CompletableFuture.allOf(futures).thenRun(() -> {
final List<Suggestions> suggestions = new ArrayList<>();
for (final CompletableFuture<Suggestions> future : futures) {
suggestions.add(future.join());
}
result.complete(mergeSuggestionsOriginalOrdering(fullInput, suggestions));
});
return result;
}
// inspired from com.mojang.brigadier.suggestion.Suggestions#merge, but without the sorting part
public static Suggestions mergeSuggestionsOriginalOrdering(String input, Collection<Suggestions> suggestions) {
if (suggestions.isEmpty()) {
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
} else if (suggestions.size() == 1) {
return suggestions.iterator().next();
}
final List<Suggestion> texts = new ArrayList<>();
for (final Suggestions suggestions1 : suggestions) {
texts.addAll(suggestions1.getList());
}
return createSuggestionsOriginalOrdering(input, texts);
}
// inspired from com.mojang.brigadier.suggestion.Suggestions#create, but without the sorting part
public static Suggestions createSuggestionsOriginalOrdering(String command, Collection<Suggestion> suggestions) {
if (suggestions.isEmpty()) {
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
}
int start = Integer.MAX_VALUE;
int end = Integer.MIN_VALUE;
for (final Suggestion suggestion : suggestions) {
start = Math.min(suggestion.getRange().getStart(), start);
end = Math.max(suggestion.getRange().getEnd(), end);
}
final StringRange range = new StringRange(start, end);
final List<Suggestion> texts = new ArrayList<>(suggestions.size());
for (final Suggestion suggestion : suggestions) {
texts.add(suggestion.expand(command, range));
}
return new Suggestions(range, texts);
}
}

View File

@@ -0,0 +1,92 @@
package fr.pandacube.lib.cli;
import java.io.IOException;
import java.util.logging.Logger;
import jline.console.ConsoleReader;
import org.fusesource.jansi.AnsiConsole;
import fr.pandacube.lib.util.Log;
public class CLI {
public static final String ANSI_RESET = "\u001B[0m";
public static final String ANSI_BLACK = "\u001B[30m";
public static final String ANSI_DARK_RED = "\u001B[31m";
public static final String ANSI_DARK_GREEN = "\u001B[32m";
public static final String ANSI_GOLD = "\u001B[33m";
public static final String ANSI_DARK_BLUE = "\u001B[34m";
public static final String ANSI_DARK_PURPLE = "\u001B[35m";
public static final String ANSI_DARK_AQUA = "\u001B[36m";
public static final String ANSI_GRAY = "\u001B[37m";
public static final String ANSI_DARK_GRAY = "\u001B[30;1m";
public static final String ANSI_RED = "\u001B[31;1m";
public static final String ANSI_GREEN = "\u001B[32;1m";
public static final String ANSI_YELLOW = "\u001B[33;1m";
public static final String ANSI_BLUE = "\u001B[34;1m";
public static final String ANSI_LIGHT_PURPLE = "\u001B[35;1m";
public static final String ANSI_AQUA = "\u001B[36;1m";
public static final String ANSI_WHITE = "\u001B[37;1m";
public static final String ANSI_BOLD = "\u001B[1m";
public static final String ANSI_CLEAR_SCREEN = "\u001B[2J\u001B[1;1H";
private final ConsoleReader reader;
private final Logger logger;
public CLI() throws IOException {
AnsiConsole.systemInstall();
reader = new ConsoleReader();
reader.setBellEnabled(false);
reader.setPrompt("\r>");
reader.addCompleter(BrigadierDispatcher.instance);
// configuration du formatteur pour le logger
System.setProperty("net.md_5.bungee.log-date-format", "yyyy-MM-dd HH:mm:ss");
logger = CLILogger.getLogger(this);
}
public ConsoleReader getConsoleReader() {
return reader;
}
public Logger getLogger() {
return logger;
}
public void loop() {
int i = 0;
String line;
try {
while((line = reader.readLine()) != null) {
if (line.trim().equals(""))
continue;
String cmdLine = line;
new Thread(() -> BrigadierDispatcher.instance.execute(cmdLine), "CLICmdThread #"+(i++)).start();
}
} catch (IOException e) {
Log.severe(e);
}
}
}

View File

@@ -0,0 +1,38 @@
package fr.pandacube.lib.cli;
import java.io.PrintStream;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.md_5.bungee.log.ColouredWriter;
import net.md_5.bungee.log.ConciseFormatter;
import net.md_5.bungee.log.LoggingOutputStream;
public class CLILogger {
private static Logger logger = null;
/* package */ static synchronized Logger getLogger(CLI cli) {
if (logger == null) {
logger = Logger.getGlobal();
logger.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
Handler cliLogHandler = new ColouredWriter(cli.getConsoleReader());
cliLogHandler.setFormatter(new ConciseFormatter(true));
logger.addHandler(cliLogHandler);
Handler fileHandler = new DailyLogRotateFileHandler();
fileHandler.setLevel(Level.INFO);
fileHandler.setFormatter(new ConciseFormatter(false));
logger.addHandler(fileHandler);
System.setErr(new PrintStream(new LoggingOutputStream(logger, Level.SEVERE), true));
System.setOut(new PrintStream(new LoggingOutputStream(logger, Level.INFO), true));
}
return logger;
}
}

View File

@@ -0,0 +1,90 @@
package fr.pandacube.lib.cli;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
class DailyLogRotateFileHandler extends Handler {
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
private BufferedWriter currentFile = null;
private String currentFileDate = getCurrentDay();
private boolean closed = false;
@Override
public synchronized void close() throws SecurityException {
closed = true;
if (currentFile != null) try {
currentFile.close();
} catch (IOException ignored) {}
}
@Override
public synchronized void flush() {
if (closed) return;
if (currentFile == null) return;
try {
currentFile.flush();
} catch (IOException ignored) {}
}
@Override
public synchronized void publish(LogRecord record) {
if (closed) return;
if (!isLoggable(record)) return;
if (currentFile == null || !currentFileDate.equals(getCurrentDay())) changeFile();
if (currentFile == null) return;
String formattedMessage;
try {
formattedMessage = getFormatter().format(record);
} catch (Exception ex) {
reportError(null, ex, ErrorManager.FORMAT_FAILURE);
return;
}
try {
currentFile.write(formattedMessage);
currentFile.flush();
} catch (Exception ex) {
reportError(null, ex, ErrorManager.WRITE_FAILURE);
}
}
private void changeFile() {
if (currentFile != null) {
try {
currentFile.flush();
currentFile.close();
} catch (IOException ignored) {}
new File("logs/latest.log").renameTo(new File("logs/" + currentFileDate + ".log"));
}
currentFileDate = getCurrentDay();
try {
File logDir = new File("logs");
logDir.mkdir();
currentFile = new BufferedWriter(new FileWriter("logs/latest.log", true));
} catch (SecurityException | IOException e) {
reportError("Erreur lors de l'initialisation d'un fichier log", e, ErrorManager.OPEN_FAILURE);
currentFile = null;
}
}
private String getCurrentDay() {
return dateFormat.format(new Date());
}
}