From 27861ad0edf7b000a0195270db43df6accb5649a Mon Sep 17 00:00:00 2001 From: Hamza Date: Tue, 20 Oct 2026 00:31:05 +0500 Subject: [PATCH] Read a prompt's wording only where the engine wrote it The pick-box heuristic read the message for a leading "Select", and this branch had widened it past leading whitespace so that a routine's own message would be read the same way. That makes a plain point prompt look like a pick: (getpoint "\nSelect a point: ") showed the pick box and lost its point modifiers, since pointmod refuses them wherever picks_objects holds. A routine writes all of its own message (raw), and says through picks_one when it picks an object, so the wording needs reading only where the engine wrote it. Covered for both spellings a routine might use, with and without the leading newline. --- crates/engine/src/lisp/tests.rs | 12 ++++++++---- crates/engine/src/prompt.rs | 7 ++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/crates/engine/src/lisp/tests.rs b/crates/engine/src/lisp/tests.rs index 86cc0b0c..6a1051c1 100644 --- a/crates/engine/src/lisp/tests.rs +++ b/crates/engine/src/lisp/tests.rs @@ -473,10 +473,14 @@ fn an_entsel_prompt_picks_objects_whatever_its_message_says() { assert!(s.current_prompt().unwrap().picks_objects(), "{}", s.prompt_text()); s.cancel(); - // A point prompt is not a pick, and keeps its point modifiers. - s.cmdline("(getpoint \"\nSpecify a point: \")").unwrap(); - assert!(!s.current_prompt().unwrap().picks_objects(), "{}", s.prompt_text()); - s.cancel(); + // A point prompt is not a pick, and keeps its point modifiers -- including one whose own + // message happens to begin with the word the built-in commands are read by. `picks_one` says + // which calls pick, so the wording is only ever read where the engine wrote it (#1635 review). + for point in ["(getpoint \"\nSpecify a point: \")", "(getpoint \"\nSelect a point: \")", "(getpoint \"Select a point: \")"] { + s.cmdline(point).unwrap(); + assert!(!s.current_prompt().unwrap().picks_objects(), "{point}: {}", s.prompt_text()); + s.cancel(); + } } #[test] diff --git a/crates/engine/src/prompt.rs b/crates/engine/src/prompt.rs index 5108af6d..b9c45eae 100644 --- a/crates/engine/src/prompt.rs +++ b/crates/engine/src/prompt.rs @@ -135,10 +135,11 @@ impl Prompt { /// The prompt picks objects: a "Select objects" prompt, one that says it picks a single object /// ([`Prompt::picks_one`]), or a point prompt whose click selects one ("Select object to /// offset", "Select first line"…, the commands that pick a single object themselves). The UI - /// shows the pick box there. A routine's own prompt usually begins with a newline, so the - /// wording is read past the leading whitespace. + /// shows the pick box there. The wording is only read where the engine wrote it: a routine + /// writes its own message (`raw`), which may open with "Select" and still ask for a point, + /// and says through `picks_one` when it picks instead (#1635 review). pub fn picks_objects(&self) -> bool { - self.picks_one || self.accept.select || (self.accept.point && self.message.trim_start().starts_with("Select")) + self.picks_one || self.accept.select || (self.accept.point && !self.raw && self.message.starts_with("Select")) } /// "Specify next point or [Undo/Close] :". pub fn display(&self) -> String {