fix: transfer-to-global uses .bookmarks, remove old Plan file fns

This commit is contained in:
2026-07-17 18:16:03 -04:00
parent bcdb6e8120
commit 3aa486d819

View File

@@ -1,170 +0,0 @@
;;; gortium-bookmarks.el — ExoKortex Project Bookmarks
;;; Loaded from README.org via (require 'gortium-bookmarks nil t)
(defvar gortium/project-bookmark-names nil
"Bookmark names currently in the Plan file for the active project.")
(defun gortium//project-plan-file ()
"Return the first .org file under 1-Plan/ at the project root, or nil."
(when-let* ((root (projectile-project-root)))
(car (directory-files (expand-file-name "1-Plan" root) t "\\.org\\'" t))))
(defun gortium//project-tag ()
"Read the project tag from .dir-locals.el in the current project."
(when (projectile-project-p)
(let ((default-directory (projectile-project-root)))
(gortium/read-dir-local 'gortium/project-tag))))
(defun gortium//read-plan-bookmarks ()
"Parse * Bookmarks from the Plan file.
Returns alist ((NAME . URL) ...) where URL is the link target."
(when-let* ((plan-file (gortium//project-plan-file))
(_ (file-exists-p plan-file)))
(with-temp-buffer
(insert-file-contents plan-file)
(goto-char (point-min))
(when (re-search-forward "^\\* Bookmarks" nil t)
(forward-line 1)
(let ((bookmarks '()))
(while (not (or (eobp) (looking-at "^\\* ")))
(cond
((looking-at "^\\*\\* \\(.+\\)\n\\[\\[file:\\(.+\\)\\]\\[\\(.+\\)\\]\\]")
(push (cons (match-string 1) (match-string 2)) bookmarks)
(forward-line 2))
((looking-at "\\[\\[\\(.+\\)\\]\\[\\(.+\\)\\]\\]")
(unless (string-prefix-p "mu4e:" (match-string 1))
(push (cons (match-string 2) (match-string 1)) bookmarks))
(forward-line 1))
(t (forward-line 1))))
(setq gortium/project-bookmark-names (mapcar #'car bookmarks))
(nreverse bookmarks))))))
(defun gortium//append-bookmark-to-plan (name url)
"Append a bookmark as [[url][name]] under * Bookmarks in the Plan file.
NAME is the display name, URL is the link target (file path or web URL)."
(when-let* ((plan-file (gortium//project-plan-file)))
(with-temp-buffer
(insert-file-contents plan-file)
(goto-char (point-min))
(if (re-search-forward "^\\* Bookmarks" nil t)
(forward-line 1)
(goto-char (point-max))
(insert "\n* Bookmarks\n"))
(insert (format "[[%s][%s]]\n" url name))
(write-region (point-min) (point-max) plan-file nil 'silent)
(message "Bookmark added to %s" (file-name-nondirectory plan-file))
(push name gortium/project-bookmark-names))))
(defun gortium//remove-bookmark-from-plan (name)
"Remove a bookmark entry from * Bookmarks in the Plan file."
(when-let* ((plan-file (gortium//project-plan-file)))
(with-temp-buffer
(insert-file-contents plan-file)
(goto-char (point-min))
(when (re-search-forward (format "^\\*\\* %s\n" (regexp-quote name)) nil t)
(forward-line -1)
(let ((start (point)))
(forward-line 2)
(delete-region start (point)))
(write-region (point-min) (point-max) plan-file nil 'silent)
(message "Bookmark '%s' removed from Plan file" name)
(setq gortium/project-bookmark-names
(delete name gortium/project-bookmark-names))))))
(defun gortium/bookmark-set ()
"Save a bookmark. Prompts: (g)lobal or (p)roject.
Project bookmarks go to * Bookmarks in the Plan file.
The prompt shows the project tag so you can verify the target."
(interactive)
(let ((choice (read-char-choice "Save: (g)lobal / (p)roject? " '(?g ?p))))
(pcase choice
(?g (call-interactively 'bookmark-set))
(?p
(if (projectile-project-p)
(let* ((tag (or (gortium//project-tag) "project"))
(name (read-string (format "[%s] Bookmark name: " tag)))
(file (buffer-file-name)))
(gortium//append-bookmark-to-plan name file)
(message "Project bookmark saved to Plan file."))
(user-error "Not in a Projectile project"))))))
(defun gortium/list-project-bookmarks ()
"Show project bookmarks in the bookmark menu (with categories).
Temporarily replaces bookmark-alist so the menu shows project bookmarks
in their native categories. On quit, restores global bookmarks."
(interactive)
(let* ((bookmarks (gortium//read-plan-bookmarks))
(names (mapcar #'car bookmarks)))
(if (not names)
(message "No bookmarks found in this project's Plan file.")
(let ((saved-alist (copy-tree bookmark-alist)))
(setq bookmark-alist nil)
(dolist (bm (nreverse (copy-tree bookmarks)))
(bookmark-store (car bm) `((filename . ,(cdr bm))) nil))
(bookmark-bmenu-list)
(with-current-buffer "*Bookmark List*"
(add-hook 'kill-buffer-hook
(lambda ()
(setq bookmark-alist saved-alist)
(when-let* ((plan-file (gortium//project-plan-file))
(entries (bookmark-maybe-sort-alist bookmark-alist)))
(gortium//sync-plan-to-bookmark-file
(mapcar (lambda (e)
(cons (car e)
(alist-get 'filename (cdr e))))
entries))))
nil t))))))
(defun gortium//sync-plan-to-bookmark-file (bookmarks)
"Write BOOKMARKS alist back to the Plan file under * Bookmarks."
(when-let* ((plan-file (gortium//project-plan-file)))
(with-temp-buffer
(insert-file-contents plan-file)
(when (re-search-forward "^\\* Bookmarks" nil t)
(forward-line 1)
(let ((start (point)))
(if (re-search-forward "^\\* " nil t)
(forward-line -1)
(goto-char (point-max)))
(delete-region start (point)))
(dolist (bm (nreverse (copy-tree bookmarks)))
(insert (format "[[%s][%s]]\n" (cdr bm) (car bm))))
(write-region (point-min) (point-max) plan-file nil 'silent)))))
(defun gortium/transfer-to-project ()
"Transfer a global bookmark to the current project's Plan file."
(interactive)
(if (projectile-project-p)
(let* ((name (completing-read "Transfer to project: " (bookmark-all-names) nil t))
(file (bookmark-location name)))
(when (and name file (y-or-n-p (format "Transfer '%s' to project? " name)))
(gortium//append-bookmark-to-plan name file)
(bookmark-delete name)
(bookmark-save)
(message "Transferred '%s' to project %s" name
(or (gortium//project-tag) ""))))
(user-error "Not in a Projectile project")))
(defun gortium/transfer-to-global ()
"Transfer a project bookmark to the global bookmarks list."
(interactive)
(let* ((bookmarks (gortium//read-plan-bookmarks))
(names (mapcar #'car bookmarks)))
(if names
(let* ((name (completing-read "Transfer to global: " names nil t))
(url (cdr (assoc name bookmarks))))
(when (and name url (y-or-n-p (format "Transfer '%s' to global? " name)))
(bookmark-store name `((filename . ,url)) t)
(bookmark-save)
(gortium//remove-bookmark-from-plan name)
(message "Transferred '%s' to global" name)))
(message "No project bookmarks to transfer."))))
;; Bindings
(map! :leader
:desc "Set bookmark (global/project)"
"b m" #'gortium/bookmark-set
:desc "Jump to project bookmark"
"p RET" #'gortium/list-project-bookmarks)
(provide 'gortium-bookmarks)