From 451d04a72b63e68671f4a02da1595f63fe5beb9d Mon Sep 17 00:00:00 2001 From: Junhyung Im Date: Wed, 25 May 2022 06:39:05 +0900 Subject: [PATCH] feat: support eager execution --- build.gradle | 2 +- .../java/io/typecraft/command/Command.java | 70 +++++++------------ .../io/typecraft/command/i18n/MessageId.java | 9 ++- .../io/typecraft/command/CommandTest.java | 7 +- 4 files changed, 39 insertions(+), 49 deletions(-) diff --git a/build.gradle b/build.gradle index 4babe0a..b2f72aa 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { allprojects { group 'io.typecraft' - version '0.1.1' + version '0.2.0' def moduleName = name.substring(name.indexOf('-') + 1) ext.registerPublish = { publishing { diff --git a/core/src/main/java/io/typecraft/command/Command.java b/core/src/main/java/io/typecraft/command/Command.java index 403a964..3a6affd 100644 --- a/core/src/main/java/io/typecraft/command/Command.java +++ b/core/src/main/java/io/typecraft/command/Command.java @@ -3,6 +3,7 @@ import io.typecraft.command.i18n.MessageId; import io.vavr.*; import io.vavr.control.Either; +import io.vavr.control.Option; import lombok.Data; import lombok.With; import org.jetbrains.annotations.Nullable; @@ -42,36 +43,15 @@ public Optional> getFallback() { } } - @Data - @With - class Present implements Command { - private final A value; - private final MessageId descriptionId; - - private Present(A value, MessageId descriptionId) { - this.value = value; - this.descriptionId = descriptionId; - } - - public Present withDescription(String description) { - return withDescriptionId(MessageId.of("").withMessage(description)); - } - - @Override - public Present map(Function f) { - return new Present<>(f.apply(value), getDescriptionId()); - } - } - @Data @With class Parser implements Command { - private final Function, Tuple2, List>> parser; + private final Function, Tuple2, List>> parser; private final List>> tabCompleters; private final List names; private final MessageId descriptionId; - private Parser(Function, Tuple2, List>> parser, List>> tabCompleters, List names, MessageId descriptionId) { + private Parser(Function, Tuple2, List>> parser, List>> tabCompleters, List names, MessageId descriptionId) { this.parser = parser; this.tabCompleters = tabCompleters; this.names = names; @@ -103,13 +83,22 @@ static Mapping mapping(Tuple2>... entries) { return new Mapping<>(map, null); } - static Present present(A value) { - return new Present<>(value, MessageId.of("")); + static Parser present(A value) { + return argument(() -> value); + } + + static Parser argument(Supplier f) { + return new Parser<>( + args -> new Tuple2<>(Option.some(f.get()), args), + Collections.emptyList(), + Collections.singletonList(MessageId.of("")), + MessageId.ofEmpty() + ); } static Parser argument(Function f, Argument argument) { return new Parser<>( - args -> argument.getParser().apply(args).map1(aO -> aO.map(f)), + args -> argument.getParser().apply(args).map1(aO -> Option.ofOptional(aO).map(f)), argument.getTabCompleters(), argument.getIds(), MessageId.of("") @@ -167,15 +156,18 @@ static Either, CommandSuccess> parseWithIndex(int index ? parseWithIndex(index + 1, args, subCommand) : Either.left(new CommandFailure.UnknownSubCommand<>(args, index, mapCommand)); } - } else if (command instanceof Present) { - Present present = (Present) command; - return Either.right(new CommandSuccess<>(args, index, present.getValue())); } else if (command instanceof Parser) { Parser parser = (Parser) command; - List list = new ArrayList<>(Arrays.asList(Arrays.copyOfRange(args, index, args.length))); - A a = parser.getParser().apply(list)._1.orElse(null); - return a != null - ? Either.right(new CommandSuccess<>(new String[0], args.length, a)) + List list = index <= args.length + ? new ArrayList<>(Arrays.asList(Arrays.copyOfRange(args, index, args.length))) + : Collections.emptyList(); + Tuple2, List> result = parser.getParser().apply(list); + Option aO = result._1; + List remainList = result._2; + A a = aO.getOrNull(); + int currentIndex = index + list.size() - remainList.size(); + return aO.isDefined() + ? Either.right(new CommandSuccess<>(args, currentIndex, a)) : Either.left(new CommandFailure.ParsingFailure<>(parser.getNames(), parser)); } throw new UnsupportedOperationException(); @@ -202,10 +194,6 @@ static CommandTabResult tabCompleteWithIndex(int index, String[] args, Co ? tabCompleteWithIndex(index + 1, args, subCommand) : CommandTabResult.suggestion(Collections.emptyList()); } - } else if (command instanceof Present) { - Present present = (Present) command; - String[] newArgs = Arrays.copyOfRange(args, index, args.length); - return CommandTabResult.present(newArgs, present.getValue()); } else if (command instanceof Parser) { Parser parser = (Parser) command; int pos = args.length - index - 1; @@ -247,13 +235,7 @@ static List, Command>> getEntries(Command cmd) } static CommandSpec getSpec(Command cmd) { - if (cmd instanceof Command.Present) { - Present present = (Present) cmd; - return CommandSpec.of( - Collections.emptyList(), - present.getDescriptionId() - ); - } else if (cmd instanceof Command.Parser) { + if (cmd instanceof Command.Parser) { Parser parser = (Parser) cmd; return CommandSpec.of( parser.getNames(), diff --git a/core/src/main/java/io/typecraft/command/i18n/MessageId.java b/core/src/main/java/io/typecraft/command/i18n/MessageId.java index 162aa75..09f7fb0 100644 --- a/core/src/main/java/io/typecraft/command/i18n/MessageId.java +++ b/core/src/main/java/io/typecraft/command/i18n/MessageId.java @@ -3,7 +3,10 @@ import lombok.Data; import lombok.With; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; @With @Data @@ -30,6 +33,10 @@ public static MessageId of(String id) { return new MessageId(id, ""); } + public static MessageId ofEmpty() { + return new MessageId("", ""); + } + public String getMessage(Map messages) { return messages.getOrDefault(getId(), getMessage().isEmpty() ? getId() : getMessage()); } diff --git a/core/src/test/java/io/typecraft/command/CommandTest.java b/core/src/test/java/io/typecraft/command/CommandTest.java index 1b30026..85cbca0 100644 --- a/core/src/test/java/io/typecraft/command/CommandTest.java +++ b/core/src/test/java/io/typecraft/command/CommandTest.java @@ -23,7 +23,8 @@ public class CommandTest { // strArg: Argument pair("add", Command.argument(AddItem::new, intArg, strArg)), pair("remove", Command.argument(RemoveItem::new, intArg)), - pair("page", Command.argument(PageItem::new, intTabArg)) + pair("page", Command.argument(PageItem::new, intTabArg)), + pair("lazy", Command.argument(() -> null)) ); private static final Command.Mapping itemCommandWithFallback = itemCommand.withFallback(Command.present(new FallbackItem())); @@ -145,7 +146,7 @@ public void argument() { String name = "someName"; String[] args = new String[]{"item", "add", String.valueOf(index), name}; assertEquals( - Either.right(new CommandSuccess<>(new String[0], args.length, new AddItem(index, name))), + Either.right(new CommandSuccess<>(args, args.length, new AddItem(index, name))), Command.parse(args, rootCommand) ); } @@ -210,7 +211,7 @@ public void tabUnit() { public void tabSub() { String[] args = new String[]{"item", ""}; assertEquals( - CommandTabResult.suggestion(Arrays.asList("open", "add", "remove", "page")), + CommandTabResult.suggestion(Arrays.asList("open", "add", "remove", "page", "lazy")), Command.tabComplete(args, rootCommand) ); }