aboutsummaryrefslogtreecommitdiff
path: root/pearl.el
diff options
context:
space:
mode:
Diffstat (limited to 'pearl.el')
-rw-r--r--pearl.el62
1 files changed, 35 insertions, 27 deletions
diff --git a/pearl.el b/pearl.el
index 18c65c2..3ade6dc 100644
--- a/pearl.el
+++ b/pearl.el
@@ -1762,6 +1762,7 @@ A null author renders as `(unknown)'."
(format ":LINEAR-COMMENT-ID: %s\n" (or (plist-get comment :id) ""))
(format ":LINEAR-COMMENT-AUTHOR-ID: %s\n" (or (plist-get comment :author-id) ""))
(format ":LINEAR-COMMENT-SHA256: %s\n" (secure-hash 'sha256 raw-body))
+ (format ":LINEAR-COMMENT-ORG-SHA256: %s\n" (secure-hash 'sha256 (string-trim body)))
":END:\n"
(if (string-empty-p body) "" (concat body "\n")))))
@@ -3283,28 +3284,37 @@ track correctly across the in-place inserts and deletes the merge performs."
;;; Dirty detection (the save model's local scanners)
+(defun pearl--comment-dirty-p ()
+ "Return non-nil when the comment body at point differs from its last fetch.
+An Org-to-Org comparison against `LINEAR-COMMENT-ORG-SHA256' (the rendered body
+as fetched), so a comment whose markdown does not survive md->org->md (a heading
+or single-asterisk emphasis) is not mistaken for a local edit -- the same fix
+`pearl--subtree-dirty-p' applies to descriptions. Comments rendered before that
+baseline existed fall back to the older markdown-round-trip comparison against
+`LINEAR-COMMENT-SHA256'; they migrate on the next re-render."
+ (let ((org-hash (org-entry-get nil "LINEAR-COMMENT-ORG-SHA256")))
+ (if org-hash
+ (not (string= (secure-hash 'sha256 (pearl--entry-body-at-point)) org-hash))
+ (let ((stored (or (org-entry-get nil "LINEAR-COMMENT-SHA256") "")))
+ (not (string= (secure-hash 'sha256 (pearl--org-to-md (pearl--entry-body-at-point)))
+ stored))))))
+
(defun pearl--changed-comment-candidates ()
"Return comments under the issue at point whose body changed since fetch.
-Each is a plist (:comment-id :author-id :marker). Local only: compares
-`secure-hash' of `pearl--org-to-md' of each comment body to its stored
-`LINEAR-COMMENT-SHA256' (taken over the markdown Linear stored, so the
-comparison must round-trip through markdown, as `pearl-edit-current-comment'
-does). A candidate only means the body differs; ownership is decided later."
+Each is a plist (:comment-id :author-id :marker). Local only, via
+`pearl--comment-dirty-p'. A candidate only means the body differs; ownership is
+decided later."
(let (candidates)
(save-excursion
(pearl--goto-heading-or-error)
(let ((issue-end (save-excursion (org-end-of-subtree t t) (point))))
(while (and (outline-next-heading) (< (point) issue-end))
(let ((cid (org-entry-get nil "LINEAR-COMMENT-ID")))
- (when (and cid (not (string-empty-p cid)))
- (let ((stored (or (org-entry-get nil "LINEAR-COMMENT-SHA256") ""))
- (local (secure-hash 'sha256
- (pearl--org-to-md (pearl--entry-body-at-point)))))
- (unless (string= local stored)
- (push (list :comment-id cid
- :author-id (org-entry-get nil "LINEAR-COMMENT-AUTHOR-ID")
- :marker (point-marker))
- candidates))))))))
+ (when (and cid (not (string-empty-p cid)) (pearl--comment-dirty-p))
+ (push (list :comment-id cid
+ :author-id (org-entry-get nil "LINEAR-COMMENT-AUTHOR-ID")
+ :marker (point-marker))
+ candidates))))))
(nreverse candidates)))
(defun pearl--priority-number-at-point ()
@@ -4728,23 +4738,21 @@ reported (refresh to reconcile)."
(save-excursion
(pearl--goto-heading-or-error "Not on a Linear comment")
(let ((comment-id (org-entry-get nil "LINEAR-COMMENT-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"))
- ;; No-op fast path before resolving the viewer: an unchanged comment
- ;; costs no viewer lookup. `pearl--entry-body-at-point' reads the text
- ;; after the drawer and before the first child heading -- a comment
- ;; subtree has that shape, so it serves the comment body unchanged.
- (let ((local-md (pearl--org-to-md (pearl--entry-body-at-point))))
- (if (string= (secure-hash 'sha256 local-md) (or stored ""))
- (message "No comment changes to sync")
- (pearl--viewer-async
- (lambda (viewer)
- (pearl--save-comment-field
- marker (and viewer (plist-get viewer :id))
- (lambda (outcome) (pearl--report-save-outcome outcome buf))))))))))
+ ;; No-op fast path before resolving the viewer: an unchanged comment costs
+ ;; no viewer lookup. The dirty check is Org-to-Org (see
+ ;; `pearl--comment-dirty-p'), so a comment whose markdown does not survive
+ ;; the round-trip is not falsely seen as edited.
+ (if (not (pearl--comment-dirty-p))
+ (message "No comment changes to sync")
+ (pearl--viewer-async
+ (lambda (viewer)
+ (pearl--save-comment-field
+ marker (and viewer (plist-get viewer :id))
+ (lambda (outcome) (pearl--report-save-outcome outcome buf)))))))))
;;;###autoload
(defun pearl-delete-current-comment ()