diff --git a/Bot_Usage.md b/Bot_Usage.md index fd8cd59..5c1b761 100644 --- a/Bot_Usage.md +++ b/Bot_Usage.md @@ -919,6 +919,8 @@ in one reply. Arguments: - An explicit path string (comma-separated hex hops) -- reports on that path instead of your message's path. Hops must be uniform 1/2/3-byte hex (e.g. `d690,abcd,4f3d`). +- A `#` ends argument parsing: it and everything after it is ignored (so a + pasted channel tag or trailing comment isn't misread as a path string). ``` !path → @[Alice] [4h] d690,da1c,34de,81bb route: ~8.5mi, direct: ~6.5mi, https://da.gd/abcd diff --git a/commands/path.py b/commands/path.py index b5b88f9..75ba3a8 100644 --- a/commands/path.py +++ b/commands/path.py @@ -234,8 +234,9 @@ def _parse_path_arg(path_arg): async def handle(ctx): # args: 'k' switches distances to kilometers. anything else is treated - # as a comma-separated path string. - parts = ctx.message_text.split() + # as a comma-separated path string. a '#' ends argument parsing — it and + # everything after it (e.g. a pasted channel tag or comment) is ignored. + parts = ctx.message_text.split("#", 1)[0].split() args = parts[1:] unit = "km" if any(t.lower() == "k" for t in args) else "mi" u = "mi" if unit == "mi" else "km" diff --git a/tests/test_path_resolve.py b/tests/test_path_resolve.py index 56b255d..a5a51bb 100644 --- a/tests/test_path_resolve.py +++ b/tests/test_path_resolve.py @@ -149,6 +149,30 @@ async def test_neighbour_hop_anchors_without_bot_or_sender(bot_factory): "neighbouring located hop anchors the collision (no bot/sender loc)" +def full_ctx(bot, text): + # handle()-level ctx: no inbound path, so without a path argument the + # command answers the no-path reply. + return SimpleNamespace( + bot=bot, message_text=text, sender_name="bob", + sender_pubkey=None, sender_pubkey_prefix=None, + path=None, path_len=None, path_hash_mode=None, + ) + + +async def test_hash_ends_argument_parsing(bot_factory): + bot = bot_factory() + # '#…' must not be read as a path argument (it used to reply with a + # hex-format error); with no own path this falls through to no-path. + r = await pathcmd.handle(full_ctx(bot, "!path #general and stuff")) + assert r == "@[bob] direct (no path)" + # 'k' before the '#' is still honored + r = await pathcmd.handle(full_ctx(bot, "!path k #general")) + assert r == "@[bob] direct (no path)" + # a real argument before the '#' is still parsed as a path string + r = await pathcmd.handle(full_ctx(bot, "!path zzzz #general")) + assert "invalid hex hop" in r + + async def test_radius_zero_still_disambiguates_two_located(bot_factory): bot = bot_factory() await set_bot_location(bot, 32.0, -96.0)