diff options
Diffstat (limited to 'pearl.el')
| -rw-r--r-- | pearl.el | 76 |
1 files changed, 75 insertions, 1 deletions
@@ -4068,6 +4068,23 @@ CALLBACK is called with a plist (:success BOOL)." (funcall callback (list :success success)))) (lambda (_error _response _data) (funcall callback '(:success nil)))))) +(defun pearl--delete-comment-async (comment-id callback) + "Delete COMMENT-ID on Linear via commentDelete. +CALLBACK receives a plist (:success BOOL). Verified live (2026-05-25): +`commentDelete' removes the comment immediately with no API restore path, so +unlike `issueDelete' this is not a recoverable soft delete." + (let ((query "mutation CommentDelete($id: String!) { + commentDelete(id: $id) { success } + }") + (variables `(("id" . ,comment-id)))) + (pearl--graphql-request-async + query variables + (lambda (data) + (let ((payload (cdr (assoc 'commentDelete (assoc 'data data))))) + (funcall callback + (list :success (eq t (cdr (assoc 'success payload))))))) + (lambda (_error _response _data) (funcall callback '(:success nil)))))) + (defun pearl--apply-comment-highlights (viewer-id) "Color every comment heading in the buffer by editability for VIEWER-ID. The viewer's own comments get `pearl-editable-comment'; all others get @@ -4135,6 +4152,61 @@ reported (refresh to reconcile)." marker (and viewer (plist-get viewer :id)) (lambda (outcome) (pearl--report-save-outcome outcome buf)))))))))) +;;;###autoload +(defun pearl-delete-current-comment () + "Delete the comment at point on Linear after confirmation, removing its subtree. +Works from anywhere inside a comment's subtree. Only your own comments are +deletable: a comment authored by anyone else (or a bot/integration) is refused +without a `commentDelete' call. The delete is permanent -- Linear's +`commentDelete' has no API restore path -- so a locally edited comment, or one +with no stored hash, gets a stronger discard-local-edits confirmation. On +success the comment's Org subtree is removed; sibling comments and the issue +body stay." + (interactive) + (save-excursion + (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")) + (marker (point-marker)) + (buf (current-buffer))) + (unless comment-id + (user-error "Not on a Linear comment")) + (pearl--viewer-async + (lambda (viewer) + (cond + ((null viewer) + (message "Could not determine your Linear identity; not deleting")) + ((not (pearl--comment-editable-p author-id (plist-get viewer :id))) + (message "You can only delete your own comments")) + (t + ;; A clean comment (stored hash present and matching the rendered + ;; body) gets the plain prompt; a locally edited body or a missing + ;; hash (unknown provenance) gets the discard wording. The delete + ;; proceeds either way (decision 2). + (let* ((clean (and stored + (string= (secure-hash 'sha256 + (pearl--org-to-md + (org-with-point-at marker + (pearl--issue-body-at-point)))) + stored))) + (prompt (if clean + "Delete this comment from Linear and remove it here? " + "Delete this comment from Linear and discard your local edits here? "))) + (when (yes-or-no-p prompt) + (pearl--delete-comment-async + comment-id + (lambda (result) + (if (plist-get result :success) + (when (buffer-live-p buf) + (org-with-point-at marker + (org-back-to-heading t) + (delete-region (point) + (progn (org-end-of-subtree t t) (point)))) + (message "Deleted comment from Linear") + (pearl--surface-buffer buf)) + (message "Failed to delete comment"))))))))))))) + ;;; Transient Menu ;;;###autoload (autoload 'pearl-menu "pearl" nil t) @@ -4159,7 +4231,8 @@ reported (refresh to reconcile)." ("n" "new ticket" pearl-new-issue) ("c" "new comment" pearl-add-comment)] ["Delete" - ("k" "delete ticket" pearl-delete-current-issue)]] + ("k" "delete ticket" pearl-delete-current-issue) + ("K" "delete comment" pearl-delete-current-comment)]] ["Workspace" ["Fetch" ("l" "my open issues" pearl-list-issues) @@ -4225,6 +4298,7 @@ reported (refresh to reconcile)." (defvar pearl-delete-map (let ((map (make-sparse-keymap))) (define-key map "t" (cons "delete ticket" #'pearl-delete-current-issue)) + (define-key map "c" (cons "delete comment" #'pearl-delete-current-comment)) map) "Pearl delete commands; a sub-keymap of `pearl-prefix-map'.") |
