Skip to content

Commit 451d04a

Browse files
committed
feat: support eager execution
1 parent 35d310e commit 451d04a

File tree

4 files changed

+39
-49
lines changed

4 files changed

+39
-49
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44

55
allprojects {
66
group 'io.typecraft'
7-
version '0.1.1'
7+
version '0.2.0'
88
def moduleName = name.substring(name.indexOf('-') + 1)
99
ext.registerPublish = {
1010
publishing {

core/src/main/java/io/typecraft/command/Command.java

+26-44
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.typecraft.command.i18n.MessageId;
44
import io.vavr.*;
55
import io.vavr.control.Either;
6+
import io.vavr.control.Option;
67
import lombok.Data;
78
import lombok.With;
89
import org.jetbrains.annotations.Nullable;
@@ -42,36 +43,15 @@ public Optional<Command<A>> getFallback() {
4243
}
4344
}
4445

45-
@Data
46-
@With
47-
class Present<A> implements Command<A> {
48-
private final A value;
49-
private final MessageId descriptionId;
50-
51-
private Present(A value, MessageId descriptionId) {
52-
this.value = value;
53-
this.descriptionId = descriptionId;
54-
}
55-
56-
public Present<A> withDescription(String description) {
57-
return withDescriptionId(MessageId.of("").withMessage(description));
58-
}
59-
60-
@Override
61-
public <B> Present<B> map(Function<? super A, ? extends B> f) {
62-
return new Present<>(f.apply(value), getDescriptionId());
63-
}
64-
}
65-
6646
@Data
6747
@With
6848
class Parser<A> implements Command<A> {
69-
private final Function<List<String>, Tuple2<Optional<A>, List<String>>> parser;
49+
private final Function<List<String>, Tuple2<Option<A>, List<String>>> parser;
7050
private final List<Supplier<List<String>>> tabCompleters;
7151
private final List<MessageId> names;
7252
private final MessageId descriptionId;
7353

74-
private Parser(Function<List<String>, Tuple2<Optional<A>, List<String>>> parser, List<Supplier<List<String>>> tabCompleters, List<MessageId> names, MessageId descriptionId) {
54+
private Parser(Function<List<String>, Tuple2<Option<A>, List<String>>> parser, List<Supplier<List<String>>> tabCompleters, List<MessageId> names, MessageId descriptionId) {
7555
this.parser = parser;
7656
this.tabCompleters = tabCompleters;
7757
this.names = names;
@@ -103,13 +83,22 @@ static <A> Mapping<A> mapping(Tuple2<String, Command<? extends A>>... entries) {
10383
return new Mapping<>(map, null);
10484
}
10585

106-
static <A> Present<A> present(A value) {
107-
return new Present<>(value, MessageId.of(""));
86+
static <A> Parser<A> present(A value) {
87+
return argument(() -> value);
88+
}
89+
90+
static <T> Parser<T> argument(Supplier<T> f) {
91+
return new Parser<>(
92+
args -> new Tuple2<>(Option.some(f.get()), args),
93+
Collections.emptyList(),
94+
Collections.singletonList(MessageId.of("")),
95+
MessageId.ofEmpty()
96+
);
10897
}
10998

11099
static <T, A> Parser<T> argument(Function<? super A, ? extends T> f, Argument<A> argument) {
111100
return new Parser<>(
112-
args -> argument.getParser().apply(args).map1(aO -> aO.map(f)),
101+
args -> argument.getParser().apply(args).map1(aO -> Option.ofOptional(aO).map(f)),
113102
argument.getTabCompleters(),
114103
argument.getIds(),
115104
MessageId.of("")
@@ -167,15 +156,18 @@ static <A> Either<CommandFailure<A>, CommandSuccess<A>> parseWithIndex(int index
167156
? parseWithIndex(index + 1, args, subCommand)
168157
: Either.left(new CommandFailure.UnknownSubCommand<>(args, index, mapCommand));
169158
}
170-
} else if (command instanceof Present) {
171-
Present<A> present = (Present<A>) command;
172-
return Either.right(new CommandSuccess<>(args, index, present.getValue()));
173159
} else if (command instanceof Parser) {
174160
Parser<A> parser = (Parser<A>) command;
175-
List<String> list = new ArrayList<>(Arrays.asList(Arrays.copyOfRange(args, index, args.length)));
176-
A a = parser.getParser().apply(list)._1.orElse(null);
177-
return a != null
178-
? Either.right(new CommandSuccess<>(new String[0], args.length, a))
161+
List<String> list = index <= args.length
162+
? new ArrayList<>(Arrays.asList(Arrays.copyOfRange(args, index, args.length)))
163+
: Collections.emptyList();
164+
Tuple2<Option<A>, List<String>> result = parser.getParser().apply(list);
165+
Option<A> aO = result._1;
166+
List<String> remainList = result._2;
167+
A a = aO.getOrNull();
168+
int currentIndex = index + list.size() - remainList.size();
169+
return aO.isDefined()
170+
? Either.right(new CommandSuccess<>(args, currentIndex, a))
179171
: Either.left(new CommandFailure.ParsingFailure<>(parser.getNames(), parser));
180172
}
181173
throw new UnsupportedOperationException();
@@ -202,10 +194,6 @@ static <A> CommandTabResult<A> tabCompleteWithIndex(int index, String[] args, Co
202194
? tabCompleteWithIndex(index + 1, args, subCommand)
203195
: CommandTabResult.suggestion(Collections.emptyList());
204196
}
205-
} else if (command instanceof Present) {
206-
Present<A> present = (Present<A>) command;
207-
String[] newArgs = Arrays.copyOfRange(args, index, args.length);
208-
return CommandTabResult.present(newArgs, present.getValue());
209197
} else if (command instanceof Parser) {
210198
Parser<A> parser = (Parser<A>) command;
211199
int pos = args.length - index - 1;
@@ -247,13 +235,7 @@ static <A> List<Map.Entry<List<String>, Command<A>>> getEntries(Command<A> cmd)
247235
}
248236

249237
static <A> CommandSpec getSpec(Command<A> cmd) {
250-
if (cmd instanceof Command.Present) {
251-
Present<A> present = (Present<A>) cmd;
252-
return CommandSpec.of(
253-
Collections.emptyList(),
254-
present.getDescriptionId()
255-
);
256-
} else if (cmd instanceof Command.Parser) {
238+
if (cmd instanceof Command.Parser) {
257239
Parser<A> parser = (Parser<A>) cmd;
258240
return CommandSpec.of(
259241
parser.getNames(),

core/src/main/java/io/typecraft/command/i18n/MessageId.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import lombok.Data;
44
import lombok.With;
55

6-
import java.util.*;
6+
import java.util.Collections;
7+
import java.util.HashMap;
8+
import java.util.Locale;
9+
import java.util.Map;
710

811
@With
912
@Data
@@ -30,6 +33,10 @@ public static MessageId of(String id) {
3033
return new MessageId(id, "");
3134
}
3235

36+
public static MessageId ofEmpty() {
37+
return new MessageId("", "");
38+
}
39+
3340
public String getMessage(Map<String, String> messages) {
3441
return messages.getOrDefault(getId(), getMessage().isEmpty() ? getId() : getMessage());
3542
}

core/src/test/java/io/typecraft/command/CommandTest.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public class CommandTest {
2323
// strArg: Argument<String>
2424
pair("add", Command.argument(AddItem::new, intArg, strArg)),
2525
pair("remove", Command.argument(RemoveItem::new, intArg)),
26-
pair("page", Command.argument(PageItem::new, intTabArg))
26+
pair("page", Command.argument(PageItem::new, intTabArg)),
27+
pair("lazy", Command.argument(() -> null))
2728
);
2829
private static final Command.Mapping<MyCommand> itemCommandWithFallback =
2930
itemCommand.withFallback(Command.present(new FallbackItem()));
@@ -145,7 +146,7 @@ public void argument() {
145146
String name = "someName";
146147
String[] args = new String[]{"item", "add", String.valueOf(index), name};
147148
assertEquals(
148-
Either.right(new CommandSuccess<>(new String[0], args.length, new AddItem(index, name))),
149+
Either.right(new CommandSuccess<>(args, args.length, new AddItem(index, name))),
149150
Command.parse(args, rootCommand)
150151
);
151152
}
@@ -210,7 +211,7 @@ public void tabUnit() {
210211
public void tabSub() {
211212
String[] args = new String[]{"item", ""};
212213
assertEquals(
213-
CommandTabResult.suggestion(Arrays.asList("open", "add", "remove", "page")),
214+
CommandTabResult.suggestion(Arrays.asList("open", "add", "remove", "page", "lazy")),
214215
Command.tabComplete(args, rootCommand)
215216
);
216217
}

0 commit comments

Comments
 (0)