Skip to content

Commit

Permalink
enhance: Further improve on ValueMapArgumentType
Browse files Browse the repository at this point in the history
  • Loading branch information
MATRIX-feather committed Dec 30, 2024
1 parent 288184e commit 2a9cabb
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 26 deletions.
26 changes: 26 additions & 0 deletions src/main/java/xyz/nifeather/morph/commands/MorphCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
Expand Down Expand Up @@ -54,6 +55,10 @@ public boolean register(Commands dispatcher)
//.then(
// Commands.argument("properties", new ValueMapArgumentType())
// .executes(this::execExperimental)
// .then(
// Commands.argument("extra", IntegerArgumentType.integer())
// .executes(this::execExperimentala)
// )
//)
)
.build());
Expand All @@ -73,6 +78,27 @@ private int execExperimental(CommandContext<CommandSourceStack> context)
return 1;
}

private int execExperimentala(CommandContext<CommandSourceStack> context)
{
var input = ValueMapArgumentType.get("properties", context);

input.forEach((k, v) ->
{
context.getSource().getSender().sendMessage("Key '%s', Value '%s'".formatted(k, v));
});

try
{
context.getSource().getSender().sendPlainMessage("Extra is " + IntegerArgumentType.getInteger(context, "extra"));
}
catch (Throwable t)
{
context.getSource().getSender().sendPlainMessage("No extra: " + t.getMessage());
}

return 1;
}

public @NotNull CompletableFuture<Suggestions> suggestID(CommandContext<CommandSourceStack> context, SuggestionsBuilder suggestionsBuilder)
{
var source = context.getSource().getExecutor();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,83 +31,176 @@ public static Map<String, String> get(String name, CommandContext<CommandSourceS
return context.getArgument(name, defaultMap.getClass());
}

private static final Component ERR_NO_BRACKET = Component.translatableWithFallback(
"morphclient.parsing.bracket.start",
"Expected square bracket (\"[\") to start a string"
);

private static final Component ERR_EMPTY_KEY = Component.translatableWithFallback(
"morphclient.parsing.key.empty",
"May not have a empty key"
);

private static SimpleCommandExceptionType forKeyNoValue(String key)
{
return new SimpleCommandExceptionType(Component.translatableWithFallback(
"morphclient.parsing.value_map.no_value",
"Missing value for key '%s'",
key
));
}

private static SimpleCommandExceptionType forDuplicateKey(String key)
{
return new SimpleCommandExceptionType(Component.translatableWithFallback(
"morphclient.parsing.value_map.duplicate_key",
"Duplicate key '%s'",
key
));
}

private static final String[] EMPTY_STRING_ARRAY = new String[]{};

@Override
public Map<String, String> parse(StringReader reader) throws CommandSyntaxException
{
if (reader.peek() != '[')
throw new SimpleCommandExceptionType(Component.translatable("Expected square bracket to start a string")).createWithContext(reader);

if (!reader.getString().endsWith("]"))
throw new SimpleCommandExceptionType(Component.literal("Unclosed bracket string")).createWithContext(reader);
throw new SimpleCommandExceptionType(ERR_NO_BRACKET).createWithContext(reader);

reader.skip();

Map<String, String> map = new Object2ObjectOpenHashMap<>();

boolean closeBracketMet = false;
while (reader.canRead())
{
var subString = readStringQuotableUntil(reader, ',');
if (reader.peek() == ']')
{
closeBracketMet = true;
break;
}

int beginCursor = reader.getCursor();
var parseResult = parseOnce(reader, ',', ']');

if (parseResult.key == null)
{
reader.setCursor(beginCursor);
throw new SimpleCommandExceptionType(ERR_EMPTY_KEY).createWithContext(reader);
}

if (parseResult.value != null)
{
if (map.containsKey(parseResult.key))
{
var index = reader.getString().substring(beginCursor).indexOf(parseResult.key);
reader.setCursor(beginCursor + index);

if (subString == null) continue;
throw forDuplicateKey(parseResult.key).createWithContext(reader);
}

String[] split = subString.split("=", 2);
String key = split[0];
String value = split.length > 1 ? split[1] : null;
map.put(parseResult.key, parseResult.value);
}
else
{
var index = reader.getString().substring(beginCursor).indexOf(parseResult.key);
reader.setCursor(beginCursor + index);

if (value != null)
map.put(key, value);
throw forKeyNoValue(parseResult.key).createWithContext(reader);
}
}

if (closeBracketMet)
reader.skip();
else
throw new SimpleCommandExceptionType(Component.translatable("parsing.expected", "]")).createWithContext(reader);

return map;
}

public record KeyValuePair(@Nullable String key, @Nullable String value)
{
}

/**
* @return A string, NULL if the input equals 'terminator'
* @throws CommandSyntaxException
*/
@Nullable
public String readStringQuotableUntil(StringReader reader, char terminator) throws CommandSyntaxException
@NotNull
public KeyValuePair parseOnce(StringReader reader, char terminator, char endOfString) throws CommandSyntaxException
{
//log.info("Starting read... Peek is '%s'".formatted(reader.peek()));
StringBuilder builder = new StringBuilder();
StringBuilder keyStringBuilder = new StringBuilder();
@Nullable StringBuilder valueStringBuilder = null;

boolean isKey = true;

String key = null;
String value = null;

while (true)
{
if (!reader.canRead())
break;

char current = reader.read();
//log.info("Current: '%s'".formatted(current));
char next = reader.peek();

// 如果遇到了闭合括号,break;
if (next == endOfString)
break;

// Next变Current
reader.skip();

//log.info("Current: '%s'".formatted(next));

// 遇到了结束符
if (current == terminator)
if (next == terminator)
break;

//region 识别Key

var builder = isKey ? keyStringBuilder : valueStringBuilder;

// 遇到等于号,切换至Value
if (next == '=' && isKey)
{
isKey = false;
continue;
}

if (!isKey && builder == null)
builder = valueStringBuilder = new StringBuilder();

//endregion 识别Key

// 遇到引号了
if (StringReader.isQuotedStringStart(current))
if (StringReader.isQuotedStringStart(next))
{
var str = reader.readStringUntil(current);
var str = reader.readStringUntil(next);

//log.info("APPENDING QUOTE STRING [%s]".formatted(str));
builder.append(str);
continue;
}

// 如果遇到了闭合括号,break;
if (current == ']')
break;

// 是空格
if (Character.isWhitespace(current))
if (Character.isWhitespace(next))
continue;

// 其他情况
//log.info("APPENDING [%s]".formatted(current));
builder.append(current);
builder.append(next);
}

if (!keyStringBuilder.isEmpty())
key = keyStringBuilder.toString();

if (valueStringBuilder != null)
value = valueStringBuilder.toString();

//log.info("DONE! result is [%s]".formatted(builder.toString()));
return builder.isEmpty() ? null : builder.toString();
return new KeyValuePair(key, value);
}

@Override
Expand Down

0 comments on commit 2a9cabb

Please sign in to comment.