diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-26 15:06:42 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-26 15:06:42 -0500 |
| commit | 02d1c7b009f109a83a6c62ae56f4a3a9ba2d21e3 (patch) | |
| tree | 40e2d12dfede9e93423a3fc163229a8d453fe265 | |
| parent | 41a33964c6b97858a17fd12288592b03d5df68d9 (diff) | |
| download | pearl-02d1c7b009f109a83a6c62ae56f4a3a9ba2d21e3.tar.gz pearl-02d1c7b009f109a83a6c62ae56f4a3a9ba2d21e3.zip | |
refactor: remove the dead state-to-todo mapping subsystem
`pearl-state-to-todo-mapping` and its derived regex stopped doing real work once keyword rendering moved to slugifying the Linear state name (`pearl--state-name-to-keyword`) and the keyword-to-state direction moved to resolving through the team's workflow states. The defcustom fed only `pearl--get-todo-states-pattern`, which had no caller left, and the two cache vars existed only to serve that dead function. State extraction reads `org-get-todo-state` off the buffer's `#+TODO` line, so nothing live touched the mapping.
I removed the defcustom, both cache vars, and the dead function, and dropped the three pattern tests that exercised it. Removing the defcustom orphaned the mapping bindings that ~12 test setup macros still carried. They were passing through slugification rather than the map, so I stripped them too and kept the `org-todo-keywords` bindings the temp buffers actually need. Also dropped the stale README config row.
| -rw-r--r-- | README.org | 1 | ||||
| -rw-r--r-- | pearl.el | 47 | ||||
| -rw-r--r-- | tests/test-pearl-bugfixes.el | 1 | ||||
| -rw-r--r-- | tests/test-pearl-comments.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-compose.el | 2 | ||||
| -rw-r--r-- | tests/test-pearl-conflict.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-fields.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-format.el | 11 | ||||
| -rw-r--r-- | tests/test-pearl-list-comments.el | 3 | ||||
| -rw-r--r-- | tests/test-pearl-mapping.el | 51 | ||||
| -rw-r--r-- | tests/test-pearl-merge.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-org-parse.el | 13 | ||||
| -rw-r--r-- | tests/test-pearl-org-write.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-refresh.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-save.el | 6 | ||||
| -rw-r--r-- | tests/test-pearl-title-sync.el | 6 |
16 files changed, 32 insertions, 145 deletions
@@ -279,7 +279,6 @@ Most users only need an API key and an output path. The rest are knobs for teams | =pearl-org-file-path= | Active Org output file | | =pearl-default-team-id= | Default team for issue creation | | =pearl-saved-queries= | Named local issue queries | -| =pearl-state-to-todo-mapping= | Linear state to Org keyword mapping | | =pearl-max-issue-pages= | Pagination cap, 100 issues per page | | =pearl-request-timeout= | Synchronous request timeout in seconds | | =pearl-fold-after-update= | Re-fold the active page after fetch/refresh | @@ -101,22 +101,6 @@ Defaults to \\='gtd/linear.org\\=' in your `org-directory'." :type 'file :group 'pearl) -(defcustom pearl-state-to-todo-mapping - '(("Todo" . "TODO") - ("In Progress" . "IN-PROGRESS") - ("In Review" . "IN-REVIEW") - ("Backlog" . "BACKLOG") - ("Blocked" . "BLOCKED") - ("Done" . "DONE")) - "Mapping between Linear state names and Org TODO keywords, for rendering. -Each element is a cons cell (LINEAR-STATE . ORG-STATE). It controls how a -Linear state renders as an Org TODO keyword and how an Org keyword maps back -on sync. It no longer decides which issues appear: inclusion is now a -server-side query concern (see `pearl-list-issues'). A Linear state -not listed here renders with the default TODO keyword." - :type '(alist :key-type string :value-type string) - :group 'pearl) - (defcustom pearl-async-default t "Use async API calls by default. When t, all API calls will be asynchronous unless explicitly overridden. @@ -283,17 +267,6 @@ not sprawl open. A no-op when `pearl-fold-after-update' is nil." 'org-set-startup-visibility)) (pearl--hide-all-drawers))) -(defvar pearl-todo-states-pattern nil - "Cached regex pattern for matching Org TODO states. -This pattern is generated from `pearl-state-to-todo-mapping'. -Use `pearl--get-todo-states-pattern' to get the pattern.") - -(defvar pearl--todo-states-pattern-source nil - "Mapping the cached pattern was built from. -Holds the `pearl-state-to-todo-mapping' value used to build -`pearl-todo-states-pattern', so the cache can be invalidated -when the mapping changes.") - ;; Cache variables (defvar pearl--cache-teams nil @@ -1535,8 +1508,8 @@ there is no network lookup here." Upcased, each run of non-alphanumerics replaced by a single hyphen (alnum is Unicode-aware, so accented and non-Latin letters survive), with leading and trailing hyphens trimmed. An all-symbol name (empty slug) falls back to -\"TODO\". This is the workspace-faithful replacement for the static -`pearl-state-to-todo-mapping' lookup." +\"TODO\". This is the workspace-faithful replacement for the former static +state-name-to-keyword mapping." (let ((slug (string-trim (replace-regexp-in-string "[^[:alnum:]]+" "-" (upcase (or name ""))) "-+" "-+"))) @@ -1565,22 +1538,6 @@ file always has a valid `#+TODO:' line." (concat active-str " |" (if (string-empty-p done-str) "" (concat " " done-str))))))) -(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 -cached in `pearl-todo-states-pattern'. The cache is rebuilt when -the mapping changes, so a mid-session `setq' or customization takes effect." - (unless (and pearl-todo-states-pattern - (eq pearl--todo-states-pattern-source - pearl-state-to-todo-mapping)) - ;; Pattern like "TODO\\|IN-PROGRESS\\|IN-REVIEW\\|BACKLOG\\|BLOCKED\\|DONE". - (setq pearl--todo-states-pattern-source pearl-state-to-todo-mapping - pearl-todo-states-pattern - (mapconcat #'regexp-quote - (mapcar #'cdr pearl-state-to-todo-mapping) - "\\|"))) - pearl-todo-states-pattern) - (defun pearl--map-linear-priority-to-org (priority-num) "Convert Linear PRIORITY-NUM to an Org priority cookie, or \"\" for none. PRIORITY-NUM is 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low. None (0), nil, and diff --git a/tests/test-pearl-bugfixes.el b/tests/test-pearl-bugfixes.el index 7f5c635..9fe2518 100644 --- a/tests/test-pearl-bugfixes.el +++ b/tests/test-pearl-bugfixes.el @@ -35,7 +35,6 @@ "Run BODY in an org-mode temp buffer holding CONTENT at point-min." (declare (indent 1)) `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE"))) - (pearl-state-to-todo-mapping '(("Todo" . "TODO"))) (org-element-use-cache nil)) (with-temp-buffer (insert ,content) diff --git a/tests/test-pearl-comments.el b/tests/test-pearl-comments.el index 591b4ce..ae54f7d 100644 --- a/tests/test-pearl-comments.el +++ b/tests/test-pearl-comments.el @@ -32,11 +32,9 @@ (require 'cl-lib) (defmacro test-pearl--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (with-temp-buffer (insert ,content) (org-mode) diff --git a/tests/test-pearl-compose.el b/tests/test-pearl-compose.el index a96a9ca..7029297 100644 --- a/tests/test-pearl-compose.el +++ b/tests/test-pearl-compose.el @@ -94,7 +94,7 @@ Binds `captured' to the value the on-finish receives (or `:none'). Stubs (defmacro test-pearl--in-issue (&rest body) "Run BODY in an org buffer with point inside a Linear issue subtree." (declare (indent 0)) - `(let ((pearl-state-to-todo-mapping '(("Todo" . "TODO")))) + `(progn (with-temp-buffer (insert "** TODO [#B] ENG-1: Issue\n:PROPERTIES:\n:LINEAR-ID: a\n:END:\nBody.\n") (org-mode) diff --git a/tests/test-pearl-conflict.el b/tests/test-pearl-conflict.el index 56d3c84..5cebc81 100644 --- a/tests/test-pearl-conflict.el +++ b/tests/test-pearl-conflict.el @@ -30,11 +30,9 @@ (require 'cl-lib) (defmacro test-pearl-conflict--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (with-temp-buffer (insert ,content) (org-mode) diff --git a/tests/test-pearl-fields.el b/tests/test-pearl-fields.el index 2ad9679..53e4ac8 100644 --- a/tests/test-pearl-fields.el +++ b/tests/test-pearl-fields.el @@ -31,11 +31,9 @@ (require 'cl-lib) (defmacro test-pearl--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (with-temp-buffer (insert ,content) (org-mode) diff --git a/tests/test-pearl-format.el b/tests/test-pearl-format.el index ece64d3..96ec395 100644 --- a/tests/test-pearl-format.el +++ b/tests/test-pearl-format.el @@ -32,15 +32,10 @@ (require 'testutil-fixtures (expand-file-name "testutil-fixtures.el")) (defmacro test-pearl--with-default-mapping (&rest body) - "Run BODY with the default state mapping and a clean pattern cache." + "Run BODY. Kept as a thin wrapper: the renderer slugifies the state name now, +so these tests no longer need a state mapping bound." (declare (indent 0)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") - ("In Review" . "IN-REVIEW") ("Backlog" . "BACKLOG") - ("Blocked" . "BLOCKED") ("Done" . "DONE"))) - (pearl-todo-states-pattern nil) - (pearl--todo-states-pattern-source nil)) - ,@body)) + `(progn ,@body)) (defun test-pearl--norm-full () "A normalized fully-populated issue." diff --git a/tests/test-pearl-list-comments.el b/tests/test-pearl-list-comments.el index 1e2b009..a9517c9 100644 --- a/tests/test-pearl-list-comments.el +++ b/tests/test-pearl-list-comments.el @@ -116,8 +116,7 @@ (ert-deftest test-pearl-append-finds-marked-comments-heading () "Adding a comment to an issue whose Comments heading carries a marker reuses it." - (let ((pearl-state-to-todo-mapping '(("Todo" . "TODO"))) - (pearl-list-comments-shown 5) (pearl-list-comments-count-cap 25)) + (let ((pearl-list-comments-shown 5) (pearl-list-comments-count-cap 25)) (let ((entry (pearl--format-issue-as-org-entry (pearl--cap-issue-list-comments (list :id "a" :identifier "ENG-1" :title "issue" diff --git a/tests/test-pearl-mapping.el b/tests/test-pearl-mapping.el index b5faa3d..1207bf0 100644 --- a/tests/test-pearl-mapping.el +++ b/tests/test-pearl-mapping.el @@ -20,56 +20,17 @@ ;;; Commentary: ;; Unit tests for the pure mapping helpers in pearl.el: -;; Linear state <-> org keyword, the cached TODO-states regex, and -;; Linear priority -> org cookie / readable name. +;; Linear priority -> org cookie / readable name, and the priority list. ;;; Code: (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) -;; A small, explicit mapping used across the state tests so cases don't -;; depend on the package default. -(defmacro test-pearl--with-mapping (mapping &rest body) - "Run BODY with the state mapping bound to MAPPING and the cache cleared." - (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping ,mapping) - (pearl-todo-states-pattern nil) - (pearl--todo-states-pattern-source nil)) - ,@body)) - -;; pearl--map-linear-state-to-org (the static name->keyword lookup) was removed -;; in the keyword-cycle save: the keyword is now always the slug of the state -;; name (`pearl--state-name-to-keyword'), matching the workspace-derived #+TODO -;; header, and the keyword->state-id direction resolves through the team's -;; states (`pearl--resolve-keyword-to-state'), not a flat mapping. The mapping -;; alist itself survives only as the source for `pearl--get-todo-states-pattern' -;; (tested below). - -;;; pearl--get-todo-states-pattern - -(ert-deftest test-pearl-get-todo-states-pattern-builds-alternation () - "The pattern is the org keywords joined with regex alternation." - (test-pearl--with-mapping '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE")) - (should (string-equal "TODO\\|IN-PROGRESS\\|DONE" - (pearl--get-todo-states-pattern))))) - -(ert-deftest test-pearl-get-todo-states-pattern-empty-mapping () - "An empty mapping yields an empty pattern string." - (test-pearl--with-mapping '() - (should (string-equal "" (pearl--get-todo-states-pattern))))) - -(ert-deftest test-pearl-get-todo-states-pattern-recomputes-after-mapping-change () - "The cached pattern is recomputed when the mapping changes mid-session. - -Regression for the stale-cache bug: a once-populated pattern must not -outlive a change to `pearl-state-to-todo-mapping'." - (test-pearl--with-mapping '(("Todo" . "TODO") ("Done" . "DONE")) - (should (string-equal "TODO\\|DONE" (pearl--get-todo-states-pattern))) - ;; Change the mapping after the pattern has been cached. - (setq pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "DOING") ("Done" . "DONE"))) - (should (string-equal "TODO\\|DOING\\|DONE" - (pearl--get-todo-states-pattern))))) +;; The static Linear-state -> Org-keyword mapping and its derived regex were +;; removed once keyword rendering moved to slugifying the state name +;; (`pearl--state-name-to-keyword'), and the keyword -> state-id direction moved +;; to resolving through the team's states (`pearl--resolve-keyword-to-state'). +;; What remains pure-mapping-shaped is the priority conversion, tested below. ;;; pearl--map-linear-priority-to-org diff --git a/tests/test-pearl-merge.el b/tests/test-pearl-merge.el index ba73cc6..7cb2a34 100644 --- a/tests/test-pearl-merge.el +++ b/tests/test-pearl-merge.el @@ -33,11 +33,9 @@ (require 'cl-lib) (defmacro test-pearl-merge--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) ;; the merge's derived-header rebuild gathers team states synchronously; ;; stub it so the merge tests stay network-free (the header then derives ;; from the displayed issues' own states) diff --git a/tests/test-pearl-org-parse.el b/tests/test-pearl-org-parse.el index e0bb967..731f6ef 100644 --- a/tests/test-pearl-org-parse.el +++ b/tests/test-pearl-org-parse.el @@ -30,15 +30,11 @@ (require 'cl-lib) (defmacro test-pearl--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) ;; Declare the Linear keywords so `org-get-todo-state' recognizes them, the ;; way the generated file's `#+TODO:' line does in real use. - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (pearl-todo-states-pattern nil) - (pearl--todo-states-pattern-source nil) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (with-temp-buffer (insert ,content) (org-mode) @@ -107,10 +103,7 @@ "An issue rendered by build-org-content parses back through the reader. Locks the render/parse contract: the LINEAR-* drawer the renderer writes is exactly what the reader extracts, and the rendered keyword is recognized." - (let ((pearl-state-to-todo-mapping '(("In Progress" . "IN-PROGRESS"))) - (pearl-todo-states-pattern nil) - (pearl--todo-states-pattern-source nil) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + (let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (let ((content (pearl--build-org-content '((:id "i-1" :identifier "ENG-2" :title "round trip" :priority 2 :state (:name "In Progress") :team (:id "t-1")))))) diff --git a/tests/test-pearl-org-write.el b/tests/test-pearl-org-write.el index 6491b54..6c30380 100644 --- a/tests/test-pearl-org-write.el +++ b/tests/test-pearl-org-write.el @@ -33,12 +33,10 @@ "One normalized issue, enough to render a recognizable org entry.") (defmacro test-pearl--with-org-file (var &rest body) - "Bind VAR to a fresh temp .org path and run BODY, cleaning up after. -The state mapping is bound so rendering is deterministic." + "Bind VAR to a fresh temp .org path and run BODY, cleaning up after." (declare (indent 1)) `(let* ((,var (make-temp-file "linear-test-" nil ".org")) - (pearl-org-file-path ,var) - (pearl-state-to-todo-mapping '(("Todo" . "TODO")))) + (pearl-org-file-path ,var)) (unwind-protect (progn ,@body) (let ((b (find-buffer-visiting ,var))) diff --git a/tests/test-pearl-refresh.el b/tests/test-pearl-refresh.el index ba17836..d09c96c 100644 --- a/tests/test-pearl-refresh.el +++ b/tests/test-pearl-refresh.el @@ -31,11 +31,9 @@ (require 'cl-lib) (defmacro test-pearl--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (with-temp-buffer (insert ,content) (org-mode) diff --git a/tests/test-pearl-save.el b/tests/test-pearl-save.el index 22df84e..90e55cd 100644 --- a/tests/test-pearl-save.el +++ b/tests/test-pearl-save.el @@ -43,8 +43,7 @@ ;; `org-entry-put', which in batch makes the cache reconcile pathologically ;; (seconds per call). Disabling it keeps the suite fast and deterministic; ;; production never touches this binding. - `(let ((pearl-state-to-todo-mapping '(("Todo" . "TODO"))) - (pearl-comment-sort-order 'newest-first) + `(let ((pearl-comment-sort-order 'newest-first) (org-element-use-cache nil)) (with-temp-buffer (insert (pearl--format-issue-as-org-entry ,issue)) @@ -734,8 +733,7 @@ description hash is left untouched and the title still saved." (defmacro test-pearl-save--in-two-issues (&rest body) "Render two issues (ENG-1, ENG-2; bodies \"Body.\") and run BODY at point-min." (declare (indent 0)) - `(let ((pearl-state-to-todo-mapping '(("Todo" . "TODO"))) - (pearl-comment-sort-order 'newest-first) + `(let ((pearl-comment-sort-order 'newest-first) (org-element-use-cache nil)) (with-temp-buffer (insert (pearl--format-issue-as-org-entry diff --git a/tests/test-pearl-title-sync.el b/tests/test-pearl-title-sync.el index fc84a15..cd25439 100644 --- a/tests/test-pearl-title-sync.el +++ b/tests/test-pearl-title-sync.el @@ -34,11 +34,9 @@ (require 'cl-lib) (defmacro test-pearl--in-org (content &rest body) - "Run BODY in an org-mode temp buffer holding CONTENT, default mapping bound." + "Run BODY in an org-mode temp buffer holding CONTENT." (declare (indent 1)) - `(let ((pearl-state-to-todo-mapping - '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE"))) - (org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) + `(let ((org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE")))) (with-temp-buffer (insert ,content) (org-mode) |
