From 1288c2af084fb9ce09bd8807a30291821b39f7b3 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 28 May 2026 00:03:26 -0500 Subject: feat(filter): show "[ None. ]" as the topmost option in builder prompts The builder's state / project / team / labels / assignee prompts each relied on the "empty input means no constraint" convention, with a parenthetical hint in the prompt label ("Team (empty for any):"). The convention is invisible, has to be remembered, and reads as a non-choice rather than a choice. Now every prompt carries `pearl--filter-none` ("[ None. ]") as the first candidate and uses `require-match` so the user picks from the list. Selecting the sentinel is the same logical opt-out as empty input was, but the choice is on screen rather than in the user's head. Two small helpers (`pearl--with-none`, `pearl--filter-none-value-p`) and one defconst keep the sentinel string in one place. The prompt labels lost their parenthetical hints since the affordance is now in the candidate list. Five unit tests cover the sentinel predicate and the list helper across the normal / boundary / "real value" cases. The pattern generalizes well past the builder: any time pearl prompts the user to pick between a value and "no value," the no-value option belongs in the list, not hidden behind empty input. --- tests/test-pearl-adhoc.el | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'tests') diff --git a/tests/test-pearl-adhoc.el b/tests/test-pearl-adhoc.el index 23aad79..d8c7231 100644 --- a/tests/test-pearl-adhoc.el +++ b/tests/test-pearl-adhoc.el @@ -28,6 +28,35 @@ (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) (require 'cl-lib) +;;; --filter-none sentinel helpers + +(ert-deftest test-pearl-filter-none-value-p-recognizes-sentinel () + "The sentinel string reads as a `no constraint' value." + (should (pearl--filter-none-value-p pearl--filter-none))) + +(ert-deftest test-pearl-filter-none-value-p-recognizes-empty-and-nil () + "Empty input and nil also read as `no constraint' (for back-compat)." + (should (pearl--filter-none-value-p "")) + (should (pearl--filter-none-value-p nil))) + +(ert-deftest test-pearl-filter-none-value-p-rejects-real-values () + "An actual picked value does not read as `no constraint'." + (should-not (pearl--filter-none-value-p "In Progress")) + (should-not (pearl--filter-none-value-p "Platform")) + (should-not (pearl--filter-none-value-p "bug"))) + +(ert-deftest test-pearl-with-none-prepends-sentinel () + "`pearl--with-none' puts the sentinel first so it sits at the top of the +completing-read candidate list." + (let ((wrapped (pearl--with-none '("alpha" "beta")))) + (should (string= pearl--filter-none (car wrapped))) + (should (equal '("alpha" "beta") (cdr wrapped))))) + +(ert-deftest test-pearl-with-none-empty-list-yields-just-the-sentinel () + "An empty candidate list still yields a one-element list with the sentinel." + (let ((wrapped (pearl--with-none '()))) + (should (equal (list pearl--filter-none) wrapped)))) + ;;; --assemble-filter (ert-deftest test-pearl-assemble-filter-only-set-keys () -- cgit v1.2.3