aboutsummaryrefslogtreecommitdiff
path: root/pearl.el
diff options
context:
space:
mode:
Diffstat (limited to 'pearl.el')
-rw-r--r--pearl.el76
1 files changed, 75 insertions, 1 deletions
diff --git a/pearl.el b/pearl.el
index fc7667e..2ec5497 100644
--- a/pearl.el
+++ b/pearl.el
@@ -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'.")