aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pearl.el175
1 files changed, 95 insertions, 80 deletions
diff --git a/pearl.el b/pearl.el
index f48c39e..ce56cf7 100644
--- a/pearl.el
+++ b/pearl.el
@@ -2055,6 +2055,48 @@ 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"))))
+(defun pearl--commit-sync-decision (decision spec)
+ "Carry out DECISION for a gated text-field sync, per the SPEC plist.
+DECISION is a `pearl--sync-decision' result. The description, title, and
+comment syncs share this dispatch; they differ only in the SPEC values:
+
+ :local local text being synced
+ :remote remote text just fetched
+ :marker marker at the entry whose drawer holds the hash
+ :prop SHA256 provenance property name
+ :label label for the conflict prompt
+ :apply FN (reconciled-text) writing it into the buffer
+ :push FN (text result-callback) performing the API push
+ :noop-message shown on `:noop'
+ :success-message shown after a successful `:push'
+ :fail-message shown on a failed `:push'
+ :after-push optional FN (result marker) for extra success bookkeeping
+
+The conflict path reuses `:push', adapting its result-callback to the
+success-boolean `pearl--resolve-conflict' expects."
+ (let ((push (plist-get spec :push))
+ (marker (plist-get spec :marker)))
+ (pcase decision
+ (:noop (message "%s" (plist-get spec :noop-message)))
+ (:conflict
+ (pearl--resolve-conflict
+ (plist-get spec :label) (plist-get spec :local) (plist-get spec :remote)
+ marker (plist-get spec :prop) (plist-get spec :apply)
+ (lambda (text cb)
+ (funcall push text (lambda (r) (funcall cb (plist-get r :success)))))))
+ (:push
+ (funcall push (plist-get spec :local)
+ (lambda (result)
+ (if (plist-get result :success)
+ (progn
+ (org-entry-put marker (plist-get spec :prop)
+ (secure-hash 'sha256 (plist-get spec :local)))
+ (when (plist-get spec :after-push)
+ (funcall (plist-get spec :after-push) result marker))
+ (message "%s" (plist-get spec :success-message))
+ (pearl--surface-buffer (marker-buffer marker)))
+ (message "%s" (plist-get spec :fail-message)))))))))
+
;;;###autoload
(defun pearl-sync-current-issue ()
"Push the description edited in the Org body of the issue at point to Linear.
@@ -2080,35 +2122,26 @@ refused and the conflict reported (refresh to reconcile)."
(lambda (remote)
(if (null remote)
(message "Could not fetch %s from Linear; not syncing" issue-id)
- (pcase (pearl--sync-decision
- local-md stored (plist-get remote :description))
- (:noop (message "%s already matches Linear" issue-id))
- (:conflict
- (pearl--resolve-conflict
- (format "%s description" issue-id)
- local-md (plist-get remote :description)
- marker "LINEAR-DESC-SHA256"
- (lambda (md)
- (org-with-point-at marker
- (pearl--set-entry-body-at-point (pearl--md-to-org md))))
- (lambda (md cb)
- (pearl--update-issue-description-async
- issue-id md
- (lambda (r) (funcall cb (plist-get r :success)))))))
- (:push
- (pearl--update-issue-description-async
- issue-id local-md
- (lambda (result)
- (if (plist-get result :success)
- (progn
- (org-entry-put marker "LINEAR-DESC-SHA256"
- (secure-hash 'sha256 local-md))
- (when (plist-get result :updated-at)
- (org-entry-put marker "LINEAR-DESC-UPDATED-AT"
- (plist-get result :updated-at)))
- (message "Synced description for %s to Linear" issue-id)
- (pearl--surface-buffer (marker-buffer marker)))
- (message "Failed to sync description for %s" issue-id))))))))))))))
+ (pearl--commit-sync-decision
+ (pearl--sync-decision local-md stored (plist-get remote :description))
+ (list
+ :local local-md
+ :remote (plist-get remote :description)
+ :marker marker
+ :prop "LINEAR-DESC-SHA256"
+ :label (format "%s description" issue-id)
+ :apply (lambda (md)
+ (org-with-point-at marker
+ (pearl--set-entry-body-at-point (pearl--md-to-org md))))
+ :push (lambda (text cb)
+ (pearl--update-issue-description-async issue-id text cb))
+ :noop-message (format "%s already matches Linear" issue-id)
+ :success-message (format "Synced description for %s to Linear" issue-id)
+ :fail-message (format "Failed to sync description for %s" issue-id)
+ :after-push (lambda (result m)
+ (when (plist-get result :updated-at)
+ (org-entry-put m "LINEAR-DESC-UPDATED-AT"
+ (plist-get result :updated-at))))))))))))))
;;;###autoload
(defun pearl-sync-current-issue-title ()
@@ -2136,33 +2169,23 @@ advances the title provenance; both-changed refuses and reports the conflict."
(lambda (remote)
(if (null remote)
(message "Could not fetch %s from Linear; not syncing" issue-id)
- (pcase (pearl--sync-decision
- local-title stored (plist-get remote :title))
- (:noop (message "%s title already matches Linear" issue-id))
- (:conflict
- (pearl--resolve-conflict
- (format "%s title" issue-id)
- local-title (plist-get remote :title)
- marker "LINEAR-TITLE-SHA256"
- (lambda (md)
- (org-with-point-at marker
- (org-back-to-heading t)
- (org-edit-headline md)))
- (lambda (md cb)
- (pearl--update-issue-title-async
- issue-id md
- (lambda (r) (funcall cb (plist-get r :success)))))))
- (:push
- (pearl--update-issue-title-async
- issue-id local-title
- (lambda (result)
- (if (plist-get result :success)
- (progn
- (org-entry-put marker "LINEAR-TITLE-SHA256"
- (secure-hash 'sha256 local-title))
- (message "Synced title for %s to Linear" issue-id)
- (pearl--surface-buffer (marker-buffer marker)))
- (message "Failed to sync title for %s" issue-id))))))))))))))
+ (pearl--commit-sync-decision
+ (pearl--sync-decision local-title stored (plist-get remote :title))
+ (list
+ :local local-title
+ :remote (plist-get remote :title)
+ :marker marker
+ :prop "LINEAR-TITLE-SHA256"
+ :label (format "%s title" issue-id)
+ :apply (lambda (md)
+ (org-with-point-at marker
+ (org-back-to-heading t)
+ (org-edit-headline md)))
+ :push (lambda (text cb)
+ (pearl--update-issue-title-async issue-id text cb))
+ :noop-message (format "%s title already matches Linear" issue-id)
+ :success-message (format "Synced title for %s to Linear" issue-id)
+ :fail-message (format "Failed to sync title for %s" issue-id)))))))))))
(defun pearl--replace-issue-subtree-at-point (issue)
"Replace the issue subtree at point with a freshly formatted ISSUE entry.
@@ -3455,30 +3478,22 @@ reported (refresh to reconcile)."
(lambda (remote-md)
(if (null remote-md)
(message "Could not fetch the comment from Linear; not syncing")
- (pcase (pearl--sync-decision local-md stored remote-md)
- (:noop (message "Comment already matches Linear"))
- (:conflict
- (pearl--resolve-conflict
- "comment"
- local-md remote-md marker "LINEAR-COMMENT-SHA256"
- (lambda (md)
- (org-with-point-at marker
- (pearl--set-entry-body-at-point (pearl--md-to-org md))))
- (lambda (md cb)
- (pearl--update-comment-async
- comment-id md
- (lambda (r) (funcall cb (plist-get r :success)))))))
- (:push
- (pearl--update-comment-async
- comment-id local-md
- (lambda (result)
- (if (plist-get result :success)
- (progn
- (org-entry-put marker "LINEAR-COMMENT-SHA256"
- (secure-hash 'sha256 local-md))
- (message "Synced comment to Linear")
- (pearl--surface-buffer (marker-buffer marker)))
- (message "Failed to sync comment"))))))))))))))))))
+ (pearl--commit-sync-decision
+ (pearl--sync-decision local-md stored remote-md)
+ (list
+ :local local-md
+ :remote remote-md
+ :marker marker
+ :prop "LINEAR-COMMENT-SHA256"
+ :label "comment"
+ :apply (lambda (md)
+ (org-with-point-at marker
+ (pearl--set-entry-body-at-point (pearl--md-to-org md))))
+ :push (lambda (text cb)
+ (pearl--update-comment-async comment-id text cb))
+ :noop-message "Comment already matches Linear"
+ :success-message "Synced comment to Linear"
+ :fail-message "Failed to sync comment"))))))))))))))
;;; Transient Menu