Support spaces within command option values

Command options can now include space-containing strings if they are
enclosed in double quotes. This enhancement allows for dynamic
assignment of complex configurations, such as setting a custom system
prompt through the `gptSystemPrompt` option of the `/configure` command.

Change-Id: I749a7de39c8e9f92e3f3fcb1cea20692f0d49890
Signed-off-by: Patrizio <patrizio.gelosi@amarulasolutions.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/commands/ClientCommands.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/commands/ClientCommands.java
index f3ad30f..ebd2200 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/commands/ClientCommands.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/mode/common/client/commands/ClientCommands.java
@@ -13,6 +13,7 @@
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Map;
+import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -47,9 +48,11 @@
     private static final List<COMMAND_SET> HISTORY_COMMANDS = new ArrayList<>(List.of(
             COMMAND_SET.DIRECTIVE
     ));
+    // Option values can be either a sequence of chars enclosed in double quotes or a sequence of non-space chars.
+    private static final String OPTION_VALUES = "\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"|\\S+";
     private static final Pattern COMMAND_PATTERN = Pattern.compile("/(" + String.join("|",
-            COMMAND_MAP.keySet()) + ")\\b((?:\\s+--\\w+(?:=\\S+)?)+)?");
-    private static final Pattern OPTIONS_PATTERN = Pattern.compile("--(\\w+)(?:=(\\S+))?");
+            COMMAND_MAP.keySet()) + ")\\b((?:\\s+--\\w+(?:=(?:" + OPTION_VALUES + "))?)+)?");
+    private static final Pattern OPTIONS_PATTERN = Pattern.compile("--(\\w+)(?:=(" + OPTION_VALUES + "))?");
 
     private final ChangeSetData changeSetData;
     private final Directives directives;
@@ -145,7 +148,9 @@
 
     private void parseSingleOption(COMMAND_SET command, Matcher reviewOptionsMatcher) {
         String optionKey = reviewOptionsMatcher.group(1);
-        String optionValue = reviewOptionsMatcher.group(2);
+        String optionValue = Optional.ofNullable(reviewOptionsMatcher.group(2))
+                .map(val -> val.replaceAll("^\"(.*)\"$", "$1"))
+                .orElse("");
         if (REVIEW_COMMANDS.contains(command)) {
             switch (REVIEW_OPTION_MAP.get(optionKey)) {
                 case FILTER: