aboutsummaryrefslogtreecommitdiff
path: root/pearl.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-25 21:30:34 -0500
committerCraig Jennings <c@cjennings.net>2026-05-25 21:30:34 -0500
commit1de0623168d13c51fb9a7c8a87f89030642ae4d0 (patch)
treea4edf8b91ebafe8590145488f88b47a887ca716c /pearl.el
parent60b51e1c996f1c8f152696946b9440f26ea9a956 (diff)
downloadpearl-1de0623168d13c51fb9a7c8a87f89030642ae4d0.tar.gz
pearl-1de0623168d13c51fb9a7c8a87f89030642ae4d0.zip
refactor(save): remove the immediate-state-push org-sync machinery
The opt-in org-sync mode pushed Linear state immediately — on every TODO-keyword cycle (the org-after-todo-state-change hook) and on every buffer save (the after-save hook scanning the whole file). That's the last immediate-push path, and it contradicts the one-write-path model the rest of v2 builds, so I removed it: pearl-enable-org-sync / -disable-org-sync, pearl-org-hook-function, pearl-sync-org-to-linear, pearl-sync-current-heading-to-linear, and the now-orphaned pearl--process-heading-at-point, pearl--map-org-state-to-linear, and pearl--update-issue-state-async. This finishes the "make org-sync private" task — there was nothing left to make private. Cycling a TODO keyword now marks state dirty (reconciled at the next save) instead of pushing. Saving the buffer pushes nothing. Re-introducing an auto-push on save is the separate "Automatic sync on save" task, which would call the save engine rather than this whole-file scanner. I kept pearl--extract-org-heading-properties and pearl--get-todo-states-pattern. They're general heading/keyword readers, not org-sync-specific, and the keyword-cycle save (the keyword-derivation follow-up) needs exactly them. The obsolete sync tests are replaced by two that assert the contract: the sync commands are gone, and a keyword cycle pushes nothing.
Diffstat (limited to 'pearl.el')
-rw-r--r--pearl.el126
1 files changed, 1 insertions, 125 deletions
diff --git a/pearl.el b/pearl.el
index 370ccb2..3b53556 100644
--- a/pearl.el
+++ b/pearl.el
@@ -1403,49 +1403,6 @@ Use after renaming things in Linear, or to force the next lookup to refetch."
(message "Failed to update issue %s state" issue-id)))
(message "Failed to update issue %s state: API error" issue-id))))))
-(defun pearl--update-issue-state-async (issue-id state-name team-id)
- "Asynchronously update a Linear issue's state.
-ISSUE-ID is the Linear issue ID.
-STATE-NAME is the target state name to set.
-TEAM-ID is the team ID of the issue.
-Gives immediate feedback and performs the API update in the background."
- (pearl--log "Asynchronously updating issue %s state to %s for team %s" issue-id state-name team-id)
-
- ;; Resolve the state name to an ID first; bail out clearly if the team has
- ;; no such state rather than firing a mutation with a null stateId.
- (let ((state-id (pearl--get-state-id-by-name state-name team-id)))
- (if (null state-id)
- (message "Cannot update issue %s: no Linear state named %s in team %s"
- issue-id state-name team-id)
- (message "Updating issue state to %s... (in background)" state-name)
- (let* ((query "mutation UpdateIssueState($issueId: String!, $stateId: String!) {
- issueUpdate(id: $issueId, input: {stateId: $stateId}) {
- success
- issue {
- id
- identifier
- state {
- id
- name
- }
- }
- }
- }")
- (variables `(("issueId" . ,issue-id)
- ("stateId" . ,state-id)))
- (success-handler (lambda (data)
- (let ((success (and (assoc 'data data)
- (assoc 'issueUpdate (assoc 'data data))
- (cdr (assoc 'success (assoc 'issueUpdate (assoc 'data data)))))))
- (if success
- (message "Successfully updated issue %s state to %s" issue-id state-name)
- (pearl--log "Failed to update issue state asynchronously: %s" (prin1-to-string data))
- (message "Failed to update issue %s state in Linear" issue-id)))))
- (error-handler (lambda (error-thrown _response _data)
- (message "Error updating issue %s state in Linear: %s" issue-id error-thrown))))
-
- (pearl--graphql-request-async query variables success-handler error-handler)))))
-
;;; Team Member and Project Management
(defun pearl-get-team-members (team-id)
@@ -1552,17 +1509,6 @@ Gives immediate feedback and performs the API update in the background."
;;; Org Mode Integration
-(defun pearl-org-hook-function ()
- "Sync to Linear when the configured Linear org file is saved.
-Fires only for the buffer visiting `pearl-org-file-path', so a
-custom output path is honored instead of a hardcoded \"linear.org\" name."
- (when (and buffer-file-name
- pearl-org-file-path
- (string-equal (file-truename buffer-file-name)
- (file-truename pearl-org-file-path)))
- (pearl--log "Linear org file saved, syncing changes to Linear API")
- (pearl-sync-org-to-linear)))
-
(defun pearl--extract-org-heading-properties ()
"Extract Linear issue properties from the org entry at point.
Returns a plist with :todo-state, :issue-id, :issue-identifier, and :team-id,
@@ -1580,49 +1526,6 @@ there is no network lookup here."
:team-id (org-entry-get nil "LINEAR-TEAM-ID")))))
-(defun pearl--process-heading-at-point ()
- "Process the Linear issue at the current org heading."
- (let* ((props (pearl--extract-org-heading-properties))
- (todo-state (plist-get props :todo-state))
- (issue-id (plist-get props :issue-id))
- (issue-identifier (plist-get props :issue-identifier))
- (team-id (plist-get props :team-id)))
-
- ;; Only sync when this heading is a Linear issue (has id, identifier, team).
- (when (and issue-id issue-identifier team-id)
- (let ((linear-state (pearl--map-org-state-to-linear todo-state)))
- (when linear-state
- (pearl--update-issue-state-async issue-id linear-state team-id))))))
-
-(defun pearl-sync-org-to-linear ()
- "Syncs change from linear.org to Linear API."
- (interactive)
- ;; If called from org-after-todo-state-change-hook, just process the current heading
- (if (eq this-command 'org-todo)
- (pearl-sync-current-heading-to-linear)
- ;; Otherwise, scan the entire file
- (save-excursion
- (goto-char (point-min))
- (let ((todo-states-pattern (pearl--get-todo-states-pattern)))
- (while (re-search-forward (format "^\\*+ \\(%s\\)" todo-states-pattern) nil t)
- ;; Process at the heading start, but keep the outer point at the end
- ;; of this match so the next search advances past it. Without the
- ;; save-excursion, `beginning-of-line' rewinds point and the search
- ;; re-matches the same heading forever.
- (save-excursion
- (beginning-of-line)
- (pearl--process-heading-at-point)))))))
-
-(defun pearl-sync-current-heading-to-linear ()
- "Sync the current org heading's TODO state to the Linear API.
-Used when directly changing a TODO state in the org buffer."
- (save-excursion
- ;; Move up to the enclosing heading. `org-back-to-heading' signals
- ;; "before first heading" in the preamble; guard so the sync entry point
- ;; degrades to a no-op there instead of erroring.
- (when (ignore-errors (org-back-to-heading t) t)
- (pearl--process-heading-at-point))))
-
;;; Mapping Functions
(defun pearl--map-linear-state-to-org (state)
@@ -1631,13 +1534,6 @@ STATE is the Linear state string."
(or (cdr (assoc state pearl-state-to-todo-mapping))
"TODO")) ; Default fallback
-(defun pearl--map-org-state-to-linear (todo-state)
- "Map an Org TODO-STATE keyword to a Linear state name.
-TODO-STATE is the Org keyword string."
- (or (car (rassoc todo-state pearl-state-to-todo-mapping))
- nil))
-
-
(defun pearl--get-todo-states-pattern ()
"Return the regex pattern matching the Org TODO states.
Built from the org keywords in `pearl-state-to-todo-mapping' and
@@ -4395,25 +4291,6 @@ resolves to a single label."
(message "Loaded Linear API key from LINEAR_API_KEY environment variable"))
(message "LINEAR_API_KEY environment variable not found or empty"))))
-;;; Org Mode Sync Hooks
-
-;;;###autoload
-(defun pearl-enable-org-sync ()
- "Enable synchronization between org mode and Linear."
- (interactive)
- (add-hook 'after-save-hook #'pearl-org-hook-function nil t)
- (add-hook 'org-after-todo-state-change-hook #'pearl-sync-org-to-linear nil t)
- (pearl-highlight-comments)
- (message "Linear-org synchronization enabled"))
-
-;;;###autoload
-(defun pearl-disable-org-sync ()
- "Disable synchronization between org mode and Linear."
- (interactive)
- (remove-hook 'after-save-hook #'pearl-org-hook-function t)
- (remove-hook 'org-after-todo-state-change-hook #'pearl-sync-org-to-linear t)
- (message "Linear-org synchronization disabled"))
-
;;; Comment Editing
(defface pearl-editable-comment
@@ -4522,8 +4399,7 @@ The viewer's own comments get `pearl-editable-comment'; all others get
(defun pearl-highlight-comments ()
"Color comment headings in the current buffer by who can edit them.
The viewer's own comments render green (editable); others render greyed. Runs
-after a fetch/refresh and from `pearl-enable-org-sync', and is safe to
-invoke by hand."
+after a fetch/refresh, and is safe to invoke by hand."
(interactive)
(let ((buffer (current-buffer)))
;; Best-effort: highlighting is a display nicety and must never abort the