personthecat.catlib.command.arguments.FileArgument Maven / Gradle / Ivy
package personthecat.catlib.command.arguments;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import org.jetbrains.annotations.Nullable;
import personthecat.catlib.command.CommandUtils;
import personthecat.catlib.io.FileIO;
import personthecat.catlib.util.LibReference;
import personthecat.catlib.util.McUtils;
import personthecat.catlib.util.PathUtils;
import java.io.File;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import net.minecraft.class_2172;
import net.minecraft.class_2316;
import net.minecraft.class_2319;
import static personthecat.catlib.io.FileIO.fileExists;
import static personthecat.catlib.io.FileIO.listFiles;
import static personthecat.catlib.util.PathUtils.extension;
import static personthecat.catlib.util.PathUtils.noExtension;
/**
* Generates references to files on the fly on the command line.
*/
public class FileArgument implements ArgumentType {
public static void register() {
class_2316.method_10017(LibReference.MOD_ID + ":file_argument", FileArgument.class,
new class_2319<>(() -> new FileArgument(McUtils.getConfigDir())));
}
public final File dir;
@Nullable public final File preferred;
public final boolean recursive;
public FileArgument(final File dir) {
this(dir, null, true);
}
public FileArgument(final File dir, final File preferred) {
this(dir, preferred, true);
}
public FileArgument(final File dir, final boolean recursive) {
this(dir, null, recursive);
}
public FileArgument(final File dir, @Nullable final File preferred, final boolean recursive) {
if (!(dir.exists() || dir.mkdirs())) {
throw new IllegalStateException("Creating directory: " + dir.getAbsolutePath());
} else if (!dir.isDirectory()) {
throw new IllegalArgumentException("FileArgument must be a directory: " + dir.getAbsolutePath());
}
this.dir = dir;
this.preferred = preferred;
this.recursive = recursive;
}
@Override
public File parse(final StringReader reader) throws CommandSyntaxException {
final String path;
if (reader.peek() == '"') {
path = reader.readQuotedString();
} else {
final int start = reader.getCursor();
while (reader.canRead() && inPath(reader.peek())) {
reader.skip();
}
path = reader.getString().substring(start, reader.getCursor());
}
// Todo: recursive search is expensive. Maybe return a FileResult.
return this.lazyFile(path.replace("\\_", " "));
}
public Stream suggestPaths(final CommandContext ctx) {
return this.suggestPaths(ctx, this.dir);
}
public Stream suggestPaths(final CommandContext ctx, final File f) {
final String input = ctx.getInput();
final int space = input.lastIndexOf(" ");
final String path = space > 0 ? input.substring(space) : input;
final boolean simple = !PathUtils.hasExtension(path);
final Stream paths = PathUtils.getContents(this.dir, f, simple);
if (path.startsWith("\"")) {
return paths.map(s -> "\"" + s + "\"");
}
return paths.map(s -> s.replace(" ", "\\_"));
}
@Override
public CompletableFuture listSuggestions(final CommandContext ctx, final SuggestionsBuilder builder) {
final Stream neighbors = CommandUtils.getLastArg(ctx, FileArgument.class, File.class)
.map(file -> this.suggestPaths(ctx, file))
.orElseGet(() -> this.suggestPaths(ctx));
return class_2172.method_9264(neighbors, builder);
}
private static boolean inPath(final char c) {
return c == '/' || c == '\\' || c == '(' || c == ')' || StringReader.isAllowedInUnquotedString(c);
}
/** Retrieves files without needing extensions. */
private File lazyFile(final String path) {
final File test = new File(this.dir, path);
// Prefer files over folders unless extension is provided
if (!extension(test).isEmpty() && fileExists(test)) {
return test;
}
for (final File f : listFiles(test.getParentFile())) {
if (test.getName().equals(noExtension(f))) {
return f;
}
}
if (this.recursive && !path.contains("/")) {
return FileIO.locateFileRecursive(this.dir, this.preferred,
f -> test.getName().equals(noExtension(f))).orElse(test);
}
return test;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy