From 0999c0684f945eb81293e0c56f8e7a506614e699 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 24 May 2026 14:25:09 -0500 Subject: refactor: extract the issue-at-point guard into a helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The guard `(unless (ignore-errors (org-back-to-heading t) t) (user-error ...))` was copy-pasted across ten issue-at-point commands. I pulled it into pearl--goto-heading-or-error, which takes an optional message so the one comment-specific variant ("Not on a Linear comment") still reads right. Same point move, same user-error type and text — no behavior change; 353 tests green. --- pearl.el | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/pearl.el b/pearl.el index 849046d..f48c39e 100644 --- a/pearl.el +++ b/pearl.el @@ -2047,6 +2047,14 @@ text (which is the bracket-stripped form the renderer wrote)." (org-back-to-heading t) (org-get-heading t t t t))) +(defun pearl--goto-heading-or-error (&optional message) + "Move point to the enclosing heading, or signal a `user-error'. +The shared guard for the issue-at-point commands. MESSAGE overrides the +default \"Not on a Linear issue heading\" (e.g. for a comment subtree). +Callers wrap this in `save-excursion' when they must not move point." + (unless (ignore-errors (org-back-to-heading t) t) + (user-error "%s" (or message "Not on a Linear issue heading")))) + ;;;###autoload (defun pearl-sync-current-issue () "Push the description edited in the Org body of the issue at point to Linear. @@ -2057,8 +2065,7 @@ if both the body and the remote changed since the last fetch the push is refused and the conflict reported (refresh to reconcile)." (interactive) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let ((issue-id (org-entry-get nil "LINEAR-ID")) (stored (org-entry-get nil "LINEAR-DESC-SHA256")) (marker (point-marker))) @@ -2114,8 +2121,7 @@ title sends nothing; a local edit against an unchanged remote pushes and advances the title provenance; both-changed refuses and reports the conflict." (interactive) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let ((issue-id (org-entry-get nil "LINEAR-ID")) (stored (org-entry-get nil "LINEAR-TITLE-SHA256")) (marker (point-marker))) @@ -2189,8 +2195,7 @@ buffer) so the refresh can't silently lose them (decision 4), then the refresh proceeds and the subtree is replaced with Linear's version." (interactive) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let ((issue-id (org-entry-get nil "LINEAR-ID")) (stored (org-entry-get nil "LINEAR-DESC-SHA256")) (marker (point-marker))) @@ -2274,8 +2279,7 @@ own, so it renders editable; edit it later with `pearl-edit-current-comment'." (interactive "sComment: ") (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let ((issue-id (org-entry-get nil "LINEAR-ID")) (marker (point-marker))) (unless issue-id @@ -2300,8 +2304,7 @@ Reads the `LINEAR-URL' property of the enclosing issue heading and hands it to `browse-url'. Works from anywhere inside the issue subtree." (interactive) (let ((url (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (org-entry-get nil "LINEAR-URL")))) (unless (and url (not (string-empty-p url))) (user-error "No LINEAR-URL on the issue at point")) @@ -2407,8 +2410,7 @@ anywhere inside an issue subtree." (interactive (list (completing-read "Priority: " pearl--priority-choices nil t))) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let ((issue-id (org-entry-get nil "LINEAR-ID")) (priority-num (cdr (assoc priority-name pearl--priority-choices))) (marker (point-marker))) @@ -2457,8 +2459,7 @@ success. Works from anywhere inside an issue subtree." (and team-id (pearl--team-states team-id))) nil t)))) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let* ((issue-id (org-entry-get nil "LINEAR-ID")) (team-id (org-entry-get nil "LINEAR-TEAM-ID")) (marker (point-marker)) @@ -2501,8 +2502,7 @@ anywhere inside an issue subtree." (pearl--team-collection-names 'members team-id) nil t)))) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let* ((issue-id (org-entry-get nil "LINEAR-ID")) (team-id (org-entry-get nil "LINEAR-TEAM-ID")) (marker (point-marker)) @@ -2540,8 +2540,7 @@ issue subtree." "Labels (comma-separated, empty to clear): " (pearl--team-collection-names 'labels team-id))))) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear issue heading")) + (pearl--goto-heading-or-error) (let* ((issue-id (org-entry-get nil "LINEAR-ID")) (team-id (org-entry-get nil "LINEAR-TEAM-ID")) (marker (point-marker)) @@ -3429,8 +3428,7 @@ an unchanged remote pushes, and a both-sides-changed case is refused and reported (refresh to reconcile)." (interactive) (save-excursion - (unless (ignore-errors (org-back-to-heading t) t) - (user-error "Not on a Linear comment")) + (pearl--goto-heading-or-error "Not on a Linear comment") (let ((comment-id (org-entry-get nil "LINEAR-COMMENT-ID")) (author-id (org-entry-get nil "LINEAR-COMMENT-AUTHOR-ID")) (stored (org-entry-get nil "LINEAR-COMMENT-SHA256")) -- cgit v1.2.3