From 3eaec33da0a49729b41ca9166b1e38cadeddd4ed Mon Sep 17 00:00:00 2001 From: Drewry Pope Date: Tue, 27 Oct 2026 14:33:38 -0500 Subject: [PATCH] fix(id): world-line verbs need their word boundary (#1507) /logs used a bare strip_prefix, so /logs5 and /logs55 silently tailed the log for 5/55 seconds, and a tab glued the same way; every other verb requires the exact verb or verb+space+argument. /document and /input only matched with a trailing space, so the bare verbs fell through to unknown command instead of their usage. Pin all of it in a new unit test. --- pkgs/id/src/world_line.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/pkgs/id/src/world_line.rs b/pkgs/id/src/world_line.rs index 7a12a9ce8..d31566cdf 100644 --- a/pkgs/id/src/world_line.rs +++ b/pkgs/id/src/world_line.rs @@ -71,6 +71,9 @@ pub fn parse_line(line: &str) -> Option { prefix: (!prefix.is_empty()).then(|| prefix.to_owned()), }); } + if line == "/document" { + return Some(WorldLine::Message("usage: /document ".to_owned())); + } if let Some(rest) = line.strip_prefix("/document ") { let name = rest.trim(); if !name.is_empty() && name == rest { @@ -78,8 +81,8 @@ pub fn parse_line(line: &str) -> Option { } return Some(WorldLine::Message("usage: /document ".to_owned())); } - if let Some(rest) = line.strip_prefix("/logs") { - let rest = rest.trim(); + if line == "/logs" || line.starts_with("/logs ") { + let rest = line.strip_prefix("/logs").unwrap_or_default().trim(); if rest.is_empty() { return Some(WorldLine::Logs { seconds: None }); } @@ -90,6 +93,9 @@ pub fn parse_line(line: &str) -> Option { } return Some(WorldLine::Message("usage: /logs [seconds]".to_owned())); } + if line == "/input" { + return Some(WorldLine::Message("usage: /input ".to_owned())); + } if let Some(hex) = line.strip_prefix("/input ") { if !hex.is_empty() && hex.len() % 2 == 0 && hex.bytes().all(|b| b.is_ascii_hexdigit()) { return Some(WorldLine::Input(hex.to_ascii_lowercase())); @@ -158,6 +164,34 @@ mod tests { ); } + #[test] + fn glued_and_bare_verbs_do_not_parse_as_commands() { + // #1507: every verb needs its boundary — exact, or the verb, a space, + // and its argument. A glued argument is not the command. + assert_eq!( + parse_line("/logs5"), + Some(WorldLine::Message("unknown command; type /help".into())) + ); + assert_eq!( + parse_line("/logs55"), + Some(WorldLine::Message("unknown command; type /help".into())) + ); + assert_eq!( + parse_line("/logs\t5"), + Some(WorldLine::Message("unknown command; type /help".into())) + ); + // A bare verb that takes an argument answers with its usage, like + // the trailing-space form already did — not "unknown command". + assert_eq!( + parse_line("/document"), + Some(WorldLine::Message("usage: /document ".into())) + ); + assert_eq!( + parse_line("/input"), + Some(WorldLine::Message("usage: /input ".into())) + ); + } + #[test] fn unknown_and_malformed_commands_become_messages() { assert_eq!(