aboutsummaryrefslogtreecommitdiff
path: root/README.org
Commit message (Collapse)AuthorAgeFilesLines
* feat(sources): favorites, views, and filters via pick-sourceCraig Jennings2026-05-271-3/+20
| | | | | | | | | | Pearl now treats Linear sources (favorites, custom views, ad-hoc filters, saved queries) as one surface. `pearl-pick-source` is the unified picker: it lists every Linear favorite alongside every locally saved query, and dispatches by kind. View / project / cycle / label / user favorites resolve to runnable filter or view sources; issue / document / dashboard favorites open in the browser since they aren't lists. The filter compiler grows id-based forms (`:label-id` and `:assignee-id`), so favorites that name a Linear entity (a user, a label) compile to rename-proof queries rather than fragile name matching. The ad-hoc builder gets a matching member-assignee option ("me / member / any"), so a one-off "what's a teammate working on?" doesn't require building a saved query first. Two pre-existing builder bugs surfaced during verify and got fixed in the same pass. The builder previously passed display names straight to the compiler, but `:team` compiles to `team.key.eq` and `:project` to `project.id.eq`, so Linear rejected every builder run that pinned a team or project. Now the builder resolves the picked name to its key / id before assembling. And `pearl-list-issues-by-project` previously injected `:assignee :me` into the filter, hiding every teammate's work in the project. It now returns the whole project. The save prompt on the builder was rewritten so the local-only nature is unambiguous, and the README grew a Sources section plus a keymap-table entry for `f s`.
* refactor: verb-align command names and prefixes, use issue not ticketCraig Jennings2026-05-271-17/+17
| | | | | | The keybinding prefixes now each name an action verb: f fetch, e edit, c create, k delete, o open, y copy. The url group is gone, its actions split into open and copy, and the direct lowercase c (new comment) is dropped so c can head the create group. Two commands carried non-verb names, so I renamed them: pearl-new-issue is now pearl-create-issue and pearl-add-comment is now pearl-create-comment. The old sync helper that already held the pearl-create-issue name moved to the private pearl--create-issue, where it belongs as internal plumbing. I also swept "ticket" to "issue" across the labels, transient, docstrings, and README. Linear's own term is "issue" and the buffer mirrors Linear, so the command names already said "issue" while the labels said "ticket". Now they agree. The transient's per-entry keys still trail the keymap verbs, which stays its own task.
* feat(labels): render Linear labels as Org tags on issue headingsCraig Jennings2026-05-271-1/+1
| | | | | | | | An issue's Linear labels now appear as Org tags on its heading (** TODO [#B] Title :bug:backend:), so the org-native gestures work: filter by tag, build a tag agenda, sparse-tree on :bug:. Before this, labels lived only in the :LINEAR-LABELS: drawer, which Org's tag machinery can't see. pearl--label-name-to-tag slugifies a label name to a tag: downcase, non-[[:alnum:]_] runs become a single underscore, Unicode letters preserved. pearl--label-tags builds the deduplicated set, first occurrence winning on a collision. The renderer appends them, and pearl-edit-labels rewrites them through pearl--set-heading-label-tags after updating the drawer. This is render-only. The :LINEAR-LABELS: drawer stays the source of truth, hand-edited heading tags are ignored by save and the dirty scan and get rewritten from Linear on the next change or fetch, and the way to change labels is still pearl-edit-labels. Bidirectional tag editing (heading tags back to Linear) is out of scope.
* docs: document pearl-mode and the completed keymapCraig Jennings2026-05-271-7/+26
| | | | I replaced the old save/edit/new/delete prefix writeup with pearl-mode, which auto-enables in Linear buffers, and the full scheme: the hot keys directly under the prefix plus the fetch, edit, new, delete, and url groups.
* feat(render): render issue titles and the view name verbatimCraig Jennings2026-05-271-0/+13
| | | | | | The buffer should mirror Linear: a value on the page appears exactly as Linear stores it, so the heading title matches what you'd see opening the issue in Linear itself. I flipped pearl-title-case-headings to default nil so titles render verbatim. I also stopped running the view name in the #+title through the title-caser, which was coupled to the same flag. The smart-title-case path stays as opt-in tidying for anyone who wants it. Two transformations remain, both forced by Org's syntax rather than chosen: state names become TODO keywords (Org keywords can't contain spaces, so the real name stays in the LINEAR-STATE-NAME drawer), and descriptions and comments convert between Markdown and Org. Documented under "Fidelity to Linear" in the README.
* refactor: remove the dead state-to-todo mapping subsystemCraig Jennings2026-05-261-1/+0
| | | | | | `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.
* feat(comments): lead the Comments heading with the 💬 glyphCraig Jennings2026-05-261-1/+1
| | | | | | The Comments heading rendered the count marker as `Comments 💬 5/18`, with the glyph wedged between the word and the count. I moved the 💬 to the front of the heading, rendering `💬 Comments 5/18`, so it reads as an icon for the section rather than part of the number. `pearl--comment-count-marker` now returns just ` 5/18`, and `pearl--format-comments` leads with the glyph. The append locator that finds an issue's Comments subtree now tolerates the leading 💬, and still matches the old `Comments 💬 N/N` layout so a buffer rendered before this change keeps working on the next add-comment.
* feat: resolve a cycled TODO keyword to its Linear state at saveCraig Jennings2026-05-261-11/+4
| | | | | | Cycling a ticket's TODO keyword (C-c C-t) now counts as a state edit. The dirty scan gains a keyword-cycle arm: state is dirty when the explicit id moved off its baseline (the picker arm, as before) or when the keyword diverged from the synced state name's slug. At save, the picker arm pushes the explicit id; the keyword-cycle arm resolves the keyword to a team state id by slug match, first by position, and pushes that. A keyword no team state matches is reported skipped rather than guessed. set-heading-state now slugifies the keyword instead of the static-map lookup, so the picker writes the same keyword the renderer derives. Without that, a picker edit to a non-standard state would read as permanently cycled. That retires pearl--map-linear-state-to-org, whose only caller this was, and its tests.
* docs: rewrite the README editing section for the unified save modelCraig Jennings2026-05-251-29/+35
| | | | | | The README still described the old per-field push commands and the org-sync hook mode, both removed in save-model-v2. I rewrote the editing section around the one write path: you edit in the buffer, save the ticket, and Pearl reconciles each changed field against the remote. It now leads with pearl-save-issue / pearl-save-all, spells out how each field is edited (the cookie for priority, a picker for state/assignee/labels, hand-editing for text), explains that picking a constrained field marks it changed rather than pushing, and describes the conflict gate for both free-text and atomic fields. The old "Org TODO sync" section drops the removed enable/disable hooks and keeps the state-to-keyword mapping as render config, with pearl-edit-state as the way to change state. The intro, the feature list, and the use-package and prefix-key examples lose their stale references. I kept the keyword-cycle-to-state and keyword-derivation work named as planned follow-ups rather than claiming they work, since they're not in yet.
* refactor(save): retire the immediate-push field setters for buffer-editorsCraig Jennings2026-05-251-4/+3
| | | | | | | | The structured fields now reconcile at save (the previous commits), so the immediate-push setters are the duplicate path that made the package feel like it had two save models. I retired them. pearl-set-priority is deleted outright — priority is edited org-natively through the heading cookie. pearl-set-state, pearl-set-assignee, and pearl-set-labels become pearl-edit-state / -assignee / -labels: the same completing-read picker, but it writes the buffer representation (keyword/name/id, the assignee drawer, the labels drawer plus the live LINEAR-LABEL-IDS set) and marks the field dirty instead of pushing. The change goes out at the next pearl-save-issue / pearl-save-all. pearl-compose-current-description is renamed pearl-edit-description (its compose-and-push behavior is unchanged — v2 doesn't touch the compose buffers). The transient, the C-; L e keymap, the affordance preamble, and the README follow the new names, and the priority slots are dropped (no command — it's the org cookie). Deleting the setters left pearl--push-issue-field and pearl--priority-choices with no callers, so both are gone, along with the killed-buffer test that only exercised the removed helper. I filed a follow-up: the atomic savers' async commit callbacks need the same killed-buffer guard that helper carried. The setter command tests are rewritten to assert the buffer-write-and-no-push contract. The reconcile-and-push path they used to cover is exercised in test-pearl-save.
* feat: add pearl-delete-current-commentCraig Jennings2026-05-251-2/+3
| | | | | | | | | | Pearl could render, create, and edit comments but not delete one, so removing your own comment meant leaving Emacs for the web app. I added the delete command and filled the reserved C-; L d c keymap slot. pearl-delete-current-comment runs from inside a comment's subtree. It's own-only, reusing the viewer gate from pearl-edit-current-comment: a comment authored by someone else, a bot, or an integration is refused with no commentDelete call. It confirms before the destructive mutation, and on success removes that comment's Org subtree, leaving sibling comments and the issue body untouched. pearl--delete-comment-async mirrors pearl--delete-issue-async. The delete is permanent. I verified Linear's commentDelete against the live API: the comment is not found immediately after, with no restore path, so unlike issueDelete this isn't a recoverable soft delete. Because of that, a comment with unsaved local edits (or no stored hash) gets a stronger "discard your local edits" confirmation rather than the plain prompt. I surfaced it as K in the transient Delete group and as d c in the prefix keymap, and inverted the keymap test that asserted d c was unbound.
* feat: add the pearl-prefix-map keymap and regroup the transient menuCraig Jennings2026-05-251-2/+14
| | | | | | | | | | The command surface had no muscle-memory path. Everything went through M-x or the transient, and the transient grouped commands by an ad-hoc mix (issue-at-point, create, org-sync) rather than by what you're doing. I added pearl-prefix-map, an opt-in prefix keymap organized as save / edit / new / delete. It isn't bound at load, because a global multi-key prefix isn't reliably free across terminals and GUIs. Each binding is a (label . command) menu item, so which-key shows the label without pearl depending on which-key. The user binds the map to a free prefix (the README suggests C-; L). So C-; L s s saves the ticket at point, s a saves the whole file, e p edits priority, n t creates a ticket, m opens the transient. I regrouped the transient to mirror those categories: Save, Edit, New, Delete for ticket actions, and Fetch, View, Setup for the workspace. I added the two save commands and relabeled every entry to the verb wording. The per-field push entries (edit-desc, edit-title) are gone since the save model subsumes them, though the commands still work from M-x. I pulled the org-sync commands (enable, disable, push-file) from the menu too, since they're plumbing, tracked separately for going private. The keymap binds the existing command names. Aligning those names with the labels (edit-state, new-comment) is a separate task, as is the delete-comment command that will fill the d c slot.
* docs: capitalize PEARL in the README titleCraig Jennings2026-05-241-1/+1
|
* docs: title the README with the PEARL backronym and add an epigraphCraig Jennings2026-05-241-2/+5
| | | | I made the recursive backronym the README title — Pearl Edits and Reflects Linear (P=Pearl, E=Edits, A=and, R=Reflects, L=Linear) — and named it in the opening line, matching the sibling projects' READMEs (Chime, emacs-wttrin). Added an Umberto Eco epigraph, "We like lists because we don't want to die.", in the same quote style they use. The cgit repo description on cjennings.net is set to match.
* docs: restructure the README and repoint URLs to cjennings.netCraig Jennings2026-05-241-235/+271
| | | | I rewrote the README into a sectioned guide — a nav header over Features, Installation, Quick Start, Commands, The Org File, Configuration, Development & Testing, FAQ, Troubleshooting, History, and License — and repointed every repository URL off the deleted github.com/cjennings/pearl onto https://git.cjennings.net/pearl.git. The repoint also covers the URL header in pearl.el, the Eask website-url, and the package-summary repo link. The upstream credit to Gael Blanchemain's linear-emacs is unchanged.
* feat: pearl — manage Linear issues from org-modeCraig Jennings2026-05-241-0/+335
Pearl fetches Linear issues into an org file and syncs edits back. It covers list / custom views / saved queries, per-issue and bulk rendering with comments inline, conflict-aware sync of descriptions, titles, and comments, field commands for priority / state / assignee / labels, and a transient dispatch menu. The render folds to a scannable outline and nests issues under a sortable parent. Based on and inspired by Gael Blanchemain's linear-emacs.