diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-24 14:39:01 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-24 14:39:01 -0500 |
| commit | ba58f66332e6a8692d985f4d5478c743fca9bcb7 (patch) | |
| tree | 77e602831da177e866273e491e15820b2d221595 | |
| parent | 049661b4c2f9047b2bf40868a6f327a4eae7075c (diff) | |
| download | pearl-ba58f66332e6a8692d985f4d5478c743fca9bcb7.tar.gz pearl-ba58f66332e6a8692d985f4d5478c743fca9bcb7.zip | |
refactor: extract the label-category picker out of pearl-new-issue
pearl-new-issue was 129 lines — long but linear (a run of creation prompts), and untested since it is eight interactive reads. I pulled out the one intricate, self-contained piece: the issue-type label selection that groups labels by their " - " category prefix and does the two-stage category-then-label pick. It is now pearl--read-issue-label, called for selected-type. Verbatim move, no logic change; new-issue drops to 93 lines. 353 tests green.
| -rw-r--r-- | pearl.el | 81 |
1 files changed, 44 insertions, 37 deletions
@@ -3136,6 +3136,49 @@ Uses async API for better performance." (message "No team selected")))) ;;;###autoload +(defun pearl--read-issue-label (team-id) + "Prompt for an issue-type label in TEAM-ID, returning its label id (or nil). +Labels are grouped by their \" - \" category prefix; the user picks a category +\(or All), then a label, with a fuzzy match used directly when the typed text +resolves to a single label." + (let* ((issue-types (pearl-get-issue-types team-id)) + (label-names (mapcar #'car issue-types)) + ;; Group labels by category (e.g., "Docs", "Feature", etc.) + (label-categories (let ((categories (make-hash-table :test 'equal))) + (dolist (label label-names) + (when-let* ((parts (split-string label " - " t)) + (category (car parts))) + (puthash category + (cons label (gethash category categories nil)) + categories))) + categories)) + (category-names (hash-table-keys label-categories)) + ;; First select a category, then a specific label + (selected-category (completing-read + "Label category: " + (append '("All") category-names) + nil nil nil nil "All")) + (filtered-labels (if (string= selected-category "All") + label-names + (gethash selected-category label-categories nil))) + (label-prompt (completing-read + (if (string= selected-category "All") + "Label (type for fuzzy search): " + (format "Label in %s category: " selected-category)) + filtered-labels + nil nil nil nil "")) + (matching-labels (when (not (string-empty-p label-prompt)) + (cl-remove-if-not + (lambda (label-name) + (string-match-p (regexp-quote label-prompt) label-name)) + filtered-labels))) + (selected-label-name (if (= (length matching-labels) 1) + (car matching-labels) + (when matching-labels + (completing-read "Select specific label: " matching-labels nil t))))) + (when (and selected-label-name (not (string-empty-p selected-label-name))) + (cdr (assoc selected-label-name issue-types))))) + (defun pearl-new-issue () "Create a new Linear issue with additional attributes." (interactive) @@ -3180,43 +3223,7 @@ Uses async API for better performance." (string-to-number estimate))) ;; Issue type (label) - (issue-types (pearl-get-issue-types team-id)) - (label-names (mapcar #'car issue-types)) - ;; Group labels by category (e.g., "Docs", "Feature", etc.) - (label-categories (let ((categories (make-hash-table :test 'equal))) - (dolist (label label-names) - (when-let* ((parts (split-string label " - " t)) - (category (car parts))) - (puthash category - (cons label (gethash category categories nil)) - categories))) - categories)) - (category-names (hash-table-keys label-categories)) - ;; First select a category, then a specific label - (selected-category (completing-read - "Label category: " - (append '("All") category-names) - nil nil nil nil "All")) - (filtered-labels (if (string= selected-category "All") - label-names - (gethash selected-category label-categories nil))) - (label-prompt (completing-read - (if (string= selected-category "All") - "Label (type for fuzzy search): " - (format "Label in %s category: " selected-category)) - filtered-labels - nil nil nil nil "")) - (matching-labels (when (not (string-empty-p label-prompt)) - (cl-remove-if-not - (lambda (label-name) - (string-match-p (regexp-quote label-prompt) label-name)) - filtered-labels))) - (selected-label-name (if (= (length matching-labels) 1) - (car matching-labels) - (when matching-labels - (completing-read "Select specific label: " matching-labels nil t)))) - (selected-type (when (and selected-label-name (not (string-empty-p selected-label-name))) - (cdr (assoc selected-label-name issue-types)))) + (selected-type (pearl--read-issue-label team-id)) ;; Get project (selected-project (pearl-select-project team-id)) |
