From a6add57664c28130659cdfea5ec1fcf27ed473a1 Mon Sep 17 00:00:00 2001
From: dgelessus <dgelessus@users.noreply.github.com>
Date: Tue, 5 May 2020 18:01:46 +0200
Subject: [PATCH] Add positional parameter types for repeated/multiple-value
 parameters

---
 .../de/prob2/jupyter/PositionalParameter.java | 47 +++++++++++++++++++
 .../jupyter/commands/LoadCellCommand.java     |  6 +--
 .../jupyter/commands/LoadFileCommand.java     | 10 +---
 .../prob2/jupyter/commands/PrefCommand.java   |  6 +--
 4 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/src/main/java/de/prob2/jupyter/PositionalParameter.java b/src/main/java/de/prob2/jupyter/PositionalParameter.java
index f127f49..35c8988 100644
--- a/src/main/java/de/prob2/jupyter/PositionalParameter.java
+++ b/src/main/java/de/prob2/jupyter/PositionalParameter.java
@@ -1,5 +1,8 @@
 package de.prob2.jupyter;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Optional;
 
 import org.jetbrains.annotations.NotNull;
@@ -49,6 +52,50 @@ public abstract class PositionalParameter<T> extends Parameter<T> {
 		}
 	}
 	
+	public static final class RequiredMultiple extends PositionalParameter<@NotNull List<@NotNull String>> {
+		public RequiredMultiple(final @NotNull String identifier) {
+			super(identifier);
+		}
+		
+		@Override
+		public boolean isOptional() {
+			return false;
+		}
+		
+		@Override
+		public @NotNull List<@NotNull String> getDefaultValue() {
+			throw new UnsupportedOperationException("Not an optional parameter");
+		}
+		
+		@Override
+		public @NotNull Parameter.ParseResult<@NotNull List<@NotNull String>> parse(final @NotNull String argString) {
+			final String[] split = CommandUtils.ARG_SPLIT_PATTERN.split(argString);
+			return new Parameter.ParseResult<>(Arrays.asList(split), "");
+		}
+	}
+	
+	public static final class OptionalMultiple extends PositionalParameter<@NotNull List<@NotNull String>> {
+		public OptionalMultiple(final @NotNull String identifier) {
+			super(identifier);
+		}
+		
+		@Override
+		public boolean isOptional() {
+			return true;
+		}
+		
+		@Override
+		public @NotNull List<@NotNull String> getDefaultValue() {
+			return Collections.emptyList();
+		}
+		
+		@Override
+		public @NotNull Parameter.ParseResult<@NotNull List<@NotNull String>> parse(final @NotNull String argString) {
+			final String[] split = CommandUtils.ARG_SPLIT_PATTERN.split(argString);
+			return new Parameter.ParseResult<>(Arrays.asList(split), "");
+		}
+	}
+	
 	public static final class RequiredRemainder extends PositionalParameter<@NotNull String> {
 		public RequiredRemainder(final @NotNull String identifier) {
 			super(identifier);
diff --git a/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java b/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java
index ac34682..cdb7b21 100644
--- a/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/LoadCellCommand.java
@@ -2,7 +2,6 @@ package de.prob2.jupyter.commands;
 
 import java.nio.file.Paths;
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
 import com.google.inject.Inject;
@@ -25,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public final class LoadCellCommand implements Command {
-	private static final @NotNull PositionalParameter.OptionalRemainder PREFS_PARAM = new PositionalParameter.OptionalRemainder("prefs");
+	private static final @NotNull PositionalParameter.OptionalMultiple PREFS_PARAM = new PositionalParameter.OptionalMultiple("prefs");
 	private static final @NotNull PositionalParameter.RequiredRemainder CODE_PARAM = new PositionalParameter.RequiredRemainder("code");
 	
 	private final @NotNull ClassicalBFactory classicalBFactory;
@@ -75,8 +74,7 @@ public final class LoadCellCommand implements Command {
 	@Override
 	public @NotNull DisplayData run(final @NotNull ParsedArguments args) {
 		final String body = args.get(CODE_PARAM);
-		final List<String> prefsSplit = args.get(PREFS_PARAM).map(CommandUtils::splitArgs).orElse(Collections.emptyList());
-		final Map<String, String> preferences = CommandUtils.parsePreferences(prefsSplit);
+		final Map<String, String> preferences = CommandUtils.parsePreferences(args.get(PREFS_PARAM));
 		
 		this.animationSelector.changeCurrentAnimation(new Trace(CommandUtils.withSourceCode(body, () ->
 			this.classicalBFactory.create("(machine from Jupyter cell)", body).load(preferences)
diff --git a/src/main/java/de/prob2/jupyter/commands/LoadFileCommand.java b/src/main/java/de/prob2/jupyter/commands/LoadFileCommand.java
index 4d2155e..f3e5dd3 100644
--- a/src/main/java/de/prob2/jupyter/commands/LoadFileCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/LoadFileCommand.java
@@ -5,7 +5,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -40,7 +39,7 @@ public final class LoadFileCommand implements Command {
 	private static final @NotNull Logger LOGGER = LoggerFactory.getLogger(LoadFileCommand.class);
 	
 	private static final @NotNull PositionalParameter.RequiredSingle FILE_NAME_PARAM = new PositionalParameter.RequiredSingle("fileName");
-	private static final @NotNull PositionalParameter.OptionalRemainder PREFS_PARAM = new PositionalParameter.OptionalRemainder("prefs");
+	private static final @NotNull PositionalParameter.OptionalMultiple PREFS_PARAM = new PositionalParameter.OptionalMultiple("prefs");
 	
 	private final @NotNull Injector injector;
 	private final @NotNull AnimationSelector animationSelector;
@@ -98,12 +97,7 @@ public final class LoadFileCommand implements Command {
 		if (!FactoryProvider.isExtensionKnown(extension)) {
 			throw new UserErrorException("Unsupported file type: ." + extension);
 		}
-		final Map<String, String> preferences;
-		if (args.get(PREFS_PARAM).isPresent()) {
-			preferences = CommandUtils.parsePreferences(CommandUtils.splitArgs(args.get(PREFS_PARAM).get()));
-		} else {
-			preferences = Collections.emptyMap();
-		}
+		final Map<String, String> preferences = CommandUtils.parsePreferences(args.get(PREFS_PARAM));
 		
 		try {
 			final ModelFactory<?> factory = this.injector.getInstance(FactoryProvider.factoryClassFromExtension(extension));
diff --git a/src/main/java/de/prob2/jupyter/commands/PrefCommand.java b/src/main/java/de/prob2/jupyter/commands/PrefCommand.java
index 89df593..c416a83 100644
--- a/src/main/java/de/prob2/jupyter/commands/PrefCommand.java
+++ b/src/main/java/de/prob2/jupyter/commands/PrefCommand.java
@@ -27,7 +27,7 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public final class PrefCommand implements Command {
-	private static final @NotNull PositionalParameter.OptionalRemainder PREFS_PARAM = new PositionalParameter.OptionalRemainder("prefs");
+	private static final @NotNull PositionalParameter.OptionalMultiple PREFS_PARAM = new PositionalParameter.OptionalMultiple("prefs");
 	
 	private final @NotNull AnimationSelector animationSelector;
 	
@@ -67,7 +67,7 @@ public final class PrefCommand implements Command {
 	@Override
 	public @NotNull DisplayData run(final @NotNull ParsedArguments args) {
 		final StringBuilder sb = new StringBuilder();
-		if (!args.get(PREFS_PARAM).isPresent()) {
+		if (args.get(PREFS_PARAM).isEmpty()) {
 			final GetCurrentPreferencesCommand cmd = new GetCurrentPreferencesCommand();
 			this.animationSelector.getCurrentTrace().getStateSpace().execute(cmd);
 			// TreeMap is used to sort the preferences by name.
@@ -78,7 +78,7 @@ public final class PrefCommand implements Command {
 				sb.append('\n');
 			});
 		} else {
-			final List<String> prefsSplit = CommandUtils.splitArgs(args.get(PREFS_PARAM).get());
+			final List<String> prefsSplit = args.get(PREFS_PARAM);
 			if (prefsSplit.get(0).contains("=")) {
 				final List<SetPreferenceCommand> cmds = new ArrayList<>();
 				CommandUtils.parsePreferences(prefsSplit).forEach((pref, value) -> {
-- 
GitLab