diff options
Diffstat (limited to 'pearl.el')
| -rw-r--r-- | pearl.el | 51 |
1 files changed, 51 insertions, 0 deletions
@@ -3229,6 +3229,57 @@ track correctly across the in-place inserts and deletes the merge performs." (push (cons id (copy-marker (point) t)) markers)))))) (nreverse markers))) +;;; Dirty detection (the save model's local scanners) + +(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." + (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--issue-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)))))))) + (nreverse candidates))) + +(defun pearl--issue-dirty-fields () + "Return the locally-changed fields of the issue subtree at point, no network. +A plist: `:title' and `:description' are booleans; `:comment-candidates' is the +list from `pearl--changed-comment-candidates'. This is Phase A of the two-phase +save scan -- comment ownership (own vs read-only) is classified separately once +the viewer id is known (see `pearl--classify-comment-candidates')." + (save-excursion + (pearl--goto-heading-or-error) + (list :title (not (string= (secure-hash 'sha256 (pearl--issue-title-at-point)) + (or (org-entry-get nil "LINEAR-TITLE-SHA256") ""))) + :description (pearl--subtree-dirty-p) + :comment-candidates (pearl--changed-comment-candidates)))) + +(defun pearl--classify-comment-candidates (candidates viewer-id) + "Split CANDIDATES into own dirty comments and read-only ones, by VIEWER-ID. +Returns a plist (:own (...) :read-only (...)). A candidate is `:own' when its +`:author-id' equals VIEWER-ID (see `pearl--comment-editable-p'); a non-own / +bot / external comment is `:read-only' -- edited locally but not pushable." + (let (own read-only) + (dolist (c candidates) + (if (pearl--comment-editable-p (plist-get c :author-id) viewer-id) + (push c own) + (push c read-only))) + (list :own (nreverse own) :read-only (nreverse read-only)))) + (defun pearl--merge-issues-into-buffer (issues) "Merge normalized ISSUES into the current buffer by `LINEAR-ID'. Same-source refresh semantics: an existing issue still in ISSUES is re-rendered |
