From 505e7070bfbff9812823c09e94c9c87ed8c9ca0d Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Thu, 28 May 2026 01:55:00 -0500 Subject: feat(prompts): split sentinel + default-yes for safe yes/no Two UX refinements on the just-shipped prompt surface, both following the principle "the prompt should describe what it's doing and the default should be the most-common choice." First, the sentinel that was uniformly "[ None. ]" really meant two different things at two kinds of prompt, and the label only matched one of them. Filter-dimension prompts (team, state, project, labels, assignee) treat picking the sentinel as "no constraint on this dimension." Every value matches, which is *any*, not *none*. The saved-query prompts (delete, run) treat picking the sentinel as "don't act." That one is *cancel*, not *none* or *any*. Renamed accordingly: `pearl--filter-any` ("[ Any. ]") for the five filter dimensions and `pearl--filter-cancel` ("[ Cancel. ]") for the two saved-query prompts. The generic helper became `pearl--with-sentinel SENTINEL CANDIDATES` so each call site picks the label that fits its case. The predicate became `pearl--filter-sentinel-value-p` (recognizes either sentinel or empty/nil) so the cancellation logic is unchanged. Second, three non-destructive yes/no prompts ("Open issues only?", "Save this filter locally...", "Save N fields across M issues?") moved from `y-or-n-p` to a new `pearl--read-yes-no` helper. The helper renders a completing-read over ("yes" "no") with the most-common choice as the default and topmost candidate, so RET takes it without typing. Default is "yes" for all three (each is a do-the-thing-I-asked confirmation), but the helper takes a DEFAULT arg so a future prompt where "no" is more common can opt in. The destructive prompts (delete issue, delete saved query, delete comment) stay as `yes-or-no-p`. Typing "yes" there is a deliberate safety affordance, not friction worth removing. Tests cover the sentinel-value predicate across both sentinels + empty/nil + real values, the `pearl--with-sentinel` helper, the `pearl--read-yes-no` t/nil return and default-ordering behavior, and the three save-test stubs swapped to mock the new helper. --- tests/test-pearl-save.el | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tests/test-pearl-save.el') diff --git a/tests/test-pearl-save.el b/tests/test-pearl-save.el index 47b48c2..b82ca04 100644 --- a/tests/test-pearl-save.el +++ b/tests/test-pearl-save.el @@ -755,7 +755,7 @@ description hash is left untouched and the title still saved." (test-pearl-save--in-two-issues (let ((prompted nil) (fetched nil)) (test-pearl-save--with-net - (cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest _) (setq prompted t) t)) + (cl-letf (((symbol-function 'pearl--read-yes-no) (lambda (&rest _) (setq prompted t) t)) ((symbol-function 'pearl--fetch-issue-description-async) (lambda (&rest _) (setq fetched t)))) (pearl-save-all) @@ -770,7 +770,7 @@ description hash is left untouched and the title still saved." (end-of-line) (insert " EDITED")) (goto-char (point-min)) (test-pearl-save--with-net - (cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest _) t)) + (cl-letf (((symbol-function 'pearl--read-yes-no) (lambda (&rest _) t)) ((symbol-function 'pearl--fetch-issue-description-async) (lambda (_id cb) (funcall cb '(:description "Body." :updated-at "t0"))))) (pearl-save-all) @@ -783,7 +783,7 @@ description hash is left untouched and the title still saved." (end-of-line) (insert " EDITED")) (goto-char (point-min)) (test-pearl-save--with-net - (cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest _) nil)) + (cl-letf (((symbol-function 'pearl--read-yes-no) (lambda (&rest _) nil)) ((symbol-function 'pearl--fetch-issue-description-async) (lambda (_id cb) (funcall cb '(:description "Body." :updated-at "t0"))))) (pearl-save-all) @@ -803,7 +803,7 @@ description hash is left untouched and the title still saved." (end-of-line) (insert " EDITED")) (goto-char (point-min)) (test-pearl-save--with-net - (cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest _) t)) + (cl-letf (((symbol-function 'pearl--read-yes-no) (lambda (&rest _) t)) ((symbol-function 'pearl--fetch-issue-description-async) (lambda (_id cb) (funcall cb '(:description "Body." :updated-at "t0"))))) (pearl-save-all) -- cgit v1.2.3