mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 14:07:43 +01:00
A simple Completer for MinestomTerminal & Fix LineReader visual issue (#1091)
This commit is contained in:
parent
8ce43ca40c
commit
025cdab7e6
@ -2,6 +2,7 @@ package net.minestom.server.listener;
|
|||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
import net.minestom.server.command.CommandManager;
|
import net.minestom.server.command.CommandManager;
|
||||||
|
import net.minestom.server.command.CommandSender;
|
||||||
import net.minestom.server.command.builder.CommandSyntax;
|
import net.minestom.server.command.builder.CommandSyntax;
|
||||||
import net.minestom.server.command.builder.arguments.Argument;
|
import net.minestom.server.command.builder.arguments.Argument;
|
||||||
import net.minestom.server.command.builder.parser.ArgumentQueryResult;
|
import net.minestom.server.command.builder.parser.ArgumentQueryResult;
|
||||||
@ -13,6 +14,7 @@ import net.minestom.server.entity.Player;
|
|||||||
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
|
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
|
||||||
import net.minestom.server.network.packet.server.play.TabCompletePacket;
|
import net.minestom.server.network.packet.server.play.TabCompletePacket;
|
||||||
import net.minestom.server.utils.StringUtils;
|
import net.minestom.server.utils.StringUtils;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -21,7 +23,20 @@ public class TabCompleteListener {
|
|||||||
|
|
||||||
public static void listener(ClientTabCompletePacket packet, Player player) {
|
public static void listener(ClientTabCompletePacket packet, Player player) {
|
||||||
final String text = packet.text();
|
final String text = packet.text();
|
||||||
|
final Suggestion suggestion = getSuggestion(player, text);
|
||||||
|
if (suggestion != null) {
|
||||||
|
player.sendPacket(new TabCompletePacket(
|
||||||
|
packet.transactionId(),
|
||||||
|
suggestion.getStart(),
|
||||||
|
suggestion.getLength(),
|
||||||
|
suggestion.getEntries().stream()
|
||||||
|
.map(suggestionEntry -> new TabCompletePacket.Match(suggestionEntry.getEntry(), suggestionEntry.getTooltip()))
|
||||||
|
.toList())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable Suggestion getSuggestion(CommandSender commandSender, String text) {
|
||||||
String commandString = text.replaceFirst(CommandManager.COMMAND_PREFIX, "");
|
String commandString = text.replaceFirst(CommandManager.COMMAND_PREFIX, "");
|
||||||
String[] split = commandString.split(StringUtils.SPACE);
|
String[] split = commandString.split(StringUtils.SPACE);
|
||||||
String commandName = split[0];
|
String commandName = split[0];
|
||||||
@ -30,7 +45,7 @@ public class TabCompleteListener {
|
|||||||
final CommandQueryResult commandQueryResult = CommandParser.findCommand(MinecraftServer.getCommandManager().getDispatcher(), commandString);
|
final CommandQueryResult commandQueryResult = CommandParser.findCommand(MinecraftServer.getCommandManager().getDispatcher(), commandString);
|
||||||
if (commandQueryResult == null) {
|
if (commandQueryResult == null) {
|
||||||
// Command not found
|
// Command not found
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult.command(),
|
final ArgumentQueryResult queryResult = CommandParser.findEligibleArgument(commandQueryResult.command(),
|
||||||
@ -38,7 +53,7 @@ public class TabCompleteListener {
|
|||||||
CommandSyntax::hasSuggestion, Argument::hasSuggestion);
|
CommandSyntax::hasSuggestion, Argument::hasSuggestion);
|
||||||
if (queryResult == null) {
|
if (queryResult == null) {
|
||||||
// Suggestible argument not found
|
// Suggestible argument not found
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Argument<?> argument = queryResult.argument();
|
final Argument<?> argument = queryResult.argument();
|
||||||
@ -55,11 +70,10 @@ public class TabCompleteListener {
|
|||||||
final int start = commandLength - inputLength + 1 - trailingSpaces;
|
final int start = commandLength - inputLength + 1 - trailingSpaces;
|
||||||
|
|
||||||
Suggestion suggestion = new Suggestion(input, start, inputLength);
|
Suggestion suggestion = new Suggestion(input, start, inputLength);
|
||||||
suggestionCallback.apply(player, queryResult.context(), suggestion);
|
suggestionCallback.apply(commandSender, queryResult.context(), suggestion);
|
||||||
|
|
||||||
player.sendPacket(new TabCompletePacket(packet.transactionId(), suggestion.getStart(), suggestion.getLength(),
|
return suggestion;
|
||||||
suggestion.getEntries().stream()
|
|
||||||
.map(suggestionEntry -> new TabCompletePacket.Match(suggestionEntry.getEntry(), suggestionEntry.getTooltip())).toList()));
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package net.minestom.server.terminal;
|
||||||
|
|
||||||
|
import org.tinylog.core.LogEntry;
|
||||||
|
import org.tinylog.writers.AbstractFormatPatternWriter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static net.minestom.server.terminal.MinestomTerminal.reader;
|
||||||
|
|
||||||
|
public final class MinestomConsoleWriter extends AbstractFormatPatternWriter {
|
||||||
|
public MinestomConsoleWriter(Map<String, String> properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(LogEntry logEntry) throws Exception {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.printAbove(render(logEntry));
|
||||||
|
} else {
|
||||||
|
System.out.print(render(logEntry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,28 @@
|
|||||||
package net.minestom.server.terminal;
|
package net.minestom.server.terminal;
|
||||||
|
|
||||||
import net.minestom.server.MinecraftServer;
|
import net.minestom.server.MinecraftServer;
|
||||||
|
import net.minestom.server.command.builder.Command;
|
||||||
|
import net.minestom.server.command.builder.suggestion.Suggestion;
|
||||||
|
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
|
||||||
|
import net.minestom.server.listener.TabCompleteListener;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jline.reader.Candidate;
|
||||||
|
import org.jline.reader.Completer;
|
||||||
import org.jline.reader.EndOfFileException;
|
import org.jline.reader.EndOfFileException;
|
||||||
import org.jline.reader.LineReader;
|
import org.jline.reader.LineReader;
|
||||||
import org.jline.reader.LineReaderBuilder;
|
import org.jline.reader.LineReaderBuilder;
|
||||||
|
import org.jline.reader.ParsedLine;
|
||||||
import org.jline.reader.UserInterruptException;
|
import org.jline.reader.UserInterruptException;
|
||||||
import org.jline.terminal.Terminal;
|
import org.jline.terminal.Terminal;
|
||||||
import org.jline.terminal.TerminalBuilder;
|
import org.jline.terminal.TerminalBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class MinestomTerminal {
|
public class MinestomTerminal {
|
||||||
private static final String PROMPT = "> ";
|
private static final String PROMPT = "> ";
|
||||||
|
|
||||||
private static volatile Terminal terminal;
|
private static volatile Terminal terminal;
|
||||||
|
static volatile LineReader reader;
|
||||||
private static volatile boolean running = false;
|
private static volatile boolean running = false;
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
@ -25,7 +33,8 @@ public class MinestomTerminal {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
LineReader reader = LineReaderBuilder.builder()
|
reader = LineReaderBuilder.builder()
|
||||||
|
.completer(new MinestomCompleter())
|
||||||
.terminal(terminal)
|
.terminal(terminal)
|
||||||
.build();
|
.build();
|
||||||
running = true;
|
running = true;
|
||||||
@ -58,7 +67,34 @@ public class MinestomTerminal {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
reader = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class MinestomCompleter implements Completer {
|
||||||
|
@Override
|
||||||
|
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||||
|
final var commandManager = MinecraftServer.getCommandManager();
|
||||||
|
final var consoleSender = commandManager.getConsoleSender();
|
||||||
|
if (line.wordIndex() == 0) {
|
||||||
|
final String commandString = line.word().toLowerCase();
|
||||||
|
candidates.addAll(
|
||||||
|
commandManager.getDispatcher().getCommands().stream()
|
||||||
|
.map(Command::getName)
|
||||||
|
.filter(name -> commandString.isBlank() || name.toLowerCase().startsWith(commandString))
|
||||||
|
.map(Candidate::new)
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final String text = line.line();
|
||||||
|
final Suggestion suggestion = TabCompleteListener.getSuggestion(consoleSender, text);
|
||||||
|
if (suggestion != null) {
|
||||||
|
suggestion.getEntries().stream()
|
||||||
|
.map(SuggestionEntry::getEntry)
|
||||||
|
.map(Candidate::new)
|
||||||
|
.forEach(candidates::add);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
net.minestom.server.terminal.MinestomConsoleWriter
|
@ -1,4 +1,4 @@
|
|||||||
autoshutdown=true
|
autoshutdown=true
|
||||||
writer=console
|
writer=minestom console
|
||||||
writer.level=info
|
writer.level=info
|
||||||
writer.format=[{thread}] [{date: HH:mm:ss}] ({class-name}.{method}) - {level} - {message}
|
writer.format=[{thread}] [{date: HH:mm:ss}] ({class-name}.{method}) - {level} - {message}
|
Loading…
Reference in New Issue
Block a user