Repository: nonebot/nonebot2

Issue:
Bug: 命令强制空格无法匹配无参数消息
我开#1743 这个issue的初衷是希望做到可以匹配 "#cmd arg" 和 "#cmd"，但不匹配 "#cmdarg"
目前force_whitespace参数设置为True的时候，"#cmd" 就无法匹配了。
个人觉得，当cmd后面没有跟arg的时候，即使force_whitespace设置为True，也可以匹配比较好（？

_Originally posted by @BiologyHazard in https://github.com/nonebot/nonebot2/issues/1743#issuecomment-1528942065_
            


Discussion:

Resolving patch:
diff --git a/nonebot/rule.py b/nonebot/rule.py
--- a/nonebot/rule.py
+++ b/nonebot/rule.py
@@ -376,11 +376,12 @@ def __hash__(self) -> int:
     async def __call__(
         self,
         cmd: Optional[Tuple[str, ...]] = Command(),
+        cmd_arg: Optional[Message] = CommandArg(),
         cmd_whitespace: Optional[str] = CommandWhitespace(),
     ) -> bool:
         if cmd not in self.cmds:
             return False
-        if self.force_whitespace is None:
+        if self.force_whitespace is None or not cmd_arg:
             return True
         if isinstance(self.force_whitespace, str):
             return self.force_whitespace == cmd_whitespace


Test patch:
diff --git a/tests/test_rule.py b/tests/test_rule.py
--- a/tests/test_rule.py
+++ b/tests/test_rule.py
@@ -273,22 +273,34 @@ async def test_keyword(
 
 @pytest.mark.asyncio
 @pytest.mark.parametrize(
-    "cmds, cmd, force_whitespace, whitespace, expected",
+    "cmds, force_whitespace, cmd, whitespace, arg_text, expected",
     [
-        [(("help",),), ("help",), None, None, True],
-        [(("help",),), ("foo",), None, None, False],
-        [(("help", "foo"),), ("help", "foo"), True, " ", True],
-        [(("help",), ("foo",)), ("help",), " ", " ", True],
-        [(("help",),), ("help",), False, " ", False],
-        [(("help",),), ("help",), True, None, False],
-        [(("help",),), ("help",), "\n", " ", False],
+        # command tests
+        [(("help",),), None, ("help",), None, None, True],
+        [(("help",),), None, ("foo",), None, None, False],
+        [(("help", "foo"),), None, ("help", "foo"), None, None, True],
+        [(("help", "foo"),), None, ("help", "bar"), None, None, False],
+        [(("help",), ("foo",)), None, ("help",), None, None, True],
+        [(("help",), ("foo",)), None, ("bar",), None, None, False],
+        # whitespace tests
+        [(("help",),), True, ("help",), " ", "arg", True],
+        [(("help",),), True, ("help",), None, "arg", False],
+        [(("help",),), True, ("help",), None, None, True],
+        [(("help",),), False, ("help",), " ", "arg", False],
+        [(("help",),), False, ("help",), None, "arg", True],
+        [(("help",),), False, ("help",), None, None, True],
+        [(("help",),), " ", ("help",), " ", "arg", True],
+        [(("help",),), " ", ("help",), "\n", "arg", False],
+        [(("help",),), " ", ("help",), None, "arg", False],
+        [(("help",),), " ", ("help",), None, None, True],
     ],
 )
 async def test_command(
     cmds: Tuple[Tuple[str, ...]],
-    cmd: Tuple[str, ...],
     force_whitespace: Optional[Union[str, bool]],
+    cmd: Tuple[str, ...],
     whitespace: Optional[str],
+    arg_text: Optional[str],
     expected: bool,
 ):
     test_command = command(*cmds, force_whitespace=force_whitespace)
@@ -298,7 +310,10 @@ async def test_command(
     assert isinstance(checker, CommandRule)
     assert checker.cmds == cmds
 
-    state = {PREFIX_KEY: {CMD_KEY: cmd, CMD_WHITESPACE_KEY: whitespace}}
+    arg = arg_text if arg_text is None else make_fake_message()(arg_text)
+    state = {
+        PREFIX_KEY: {CMD_KEY: cmd, CMD_WHITESPACE_KEY: whitespace, CMD_ARG_KEY: arg}
+    }
     assert await dependent(state=state) == expected