fix: dir-locals bookmarks mu4e project-agenda (user+gemini)
This commit is contained in:
@@ -2287,60 +2287,68 @@ Cordialement,
|
|||||||
(defconst gortium/project-mu4e-keys '(?I ?S ?D ?T ?A)
|
(defconst gortium/project-mu4e-keys '(?I ?S ?D ?T ?A)
|
||||||
"Character keys used for project mu4e maildir shortcuts (uppercase avoids conflicts).")
|
"Character keys used for project mu4e maildir shortcuts (uppercase avoids conflicts).")
|
||||||
|
|
||||||
(defvar gortium/project-mu4e-bookmarks nil
|
|
||||||
"Cached project mu4e maildir shortcuts for re-injection when mu4e loads.")
|
|
||||||
|
|
||||||
(defun gortium/inject-project-mu4e-bookmarks ()
|
(defun gortium/inject-project-mu4e-bookmarks ()
|
||||||
"Inject project mu4e maildirs into mu4e-maildir-shortcuts.
|
"Inject project mu4e maildirs into mu4e-maildir-shortcuts.
|
||||||
Keys [PI]/[PS]/[PD]/[PT]/[PA] (uppercase). Filters by context-tag:
|
Keys [I]/[S]/[D]/[T]/[A] (uppercase). Filters by context-tag:
|
||||||
only injects when the project's context-tag matches current mu4e context."
|
only injects when the project's context-tag matches current mu4e context."
|
||||||
(let* ((proj-root (and (projectile-project-p) (projectile-project-root)))
|
(interactive)
|
||||||
(proj-tag (when proj-root
|
(when (boundp 'mu4e-maildir-shortcuts)
|
||||||
(let ((default-directory proj-root))
|
(let* ((proj-root (and (projectile-project-p) (projectile-project-root)))
|
||||||
(gortium/read-dir-local 'gortium/project-tag))))
|
(proj-tag (when proj-root
|
||||||
(context-tag (when proj-root
|
(let ((default-directory proj-root))
|
||||||
(let ((default-directory proj-root))
|
(gortium/read-dir-local 'gortium/project-tag))))
|
||||||
(gortium/read-dir-local 'gortium/context-tag))))
|
(context-tag (when proj-root
|
||||||
(cur-context (and (boundp 'mu4e-context-current)
|
(let ((default-directory proj-root))
|
||||||
(car-safe mu4e-context-current)))
|
(gortium/read-dir-local 'gortium/context-tag))))
|
||||||
(project-bm '()))
|
;; Extract the context name safely
|
||||||
;; Only inject if context-tag matches current mu4e context
|
(cur-context-name (and (boundp 'mu4e-context-current)
|
||||||
;; (if no context-tag set, always inject)
|
mu4e-context-current
|
||||||
(when (and proj-tag
|
(mu4e-context-name mu4e-context-current)))
|
||||||
(or (null context-tag)
|
(project-shortcuts '()))
|
||||||
(and cur-context
|
|
||||||
(string= context-tag
|
|
||||||
(mu4e-context-name cur-context)))))
|
|
||||||
(dolist (folder '(("Inbox" . ?I)
|
|
||||||
("Sent" . ?S)
|
|
||||||
("Drafts" . ?D)
|
|
||||||
("Trash" . ?T)
|
|
||||||
("Archive" . ?A)))
|
|
||||||
(push (cons (format "maildir:/%s.%s" (car folder) proj-tag)
|
|
||||||
(cdr folder))
|
|
||||||
project-bm)))
|
|
||||||
;; Inject into mu4e-maildir-shortcuts
|
|
||||||
(setq gortium/project-mu4e-bookmarks project-bm)
|
|
||||||
(when (and (boundp 'mu4e-maildir-shortcuts) project-bm)
|
|
||||||
;; Remove stale project entries
|
|
||||||
(setq mu4e-maildir-shortcuts
|
|
||||||
(seq-filter (lambda (s)
|
|
||||||
(not (and (consp s) (stringp (car s))
|
|
||||||
(string-match "^\\[[A-Z]+\\]" (car s)))))
|
|
||||||
mu4e-maildir-shortcuts))
|
|
||||||
;; Add current project entries
|
|
||||||
(setq mu4e-maildir-shortcuts
|
|
||||||
(append mu4e-maildir-shortcuts project-bm))
|
|
||||||
;; Refresh
|
|
||||||
(setq mu4e--bookmark-items-cached nil)
|
|
||||||
(when (get-buffer "*mu4e-main*")
|
|
||||||
(with-current-buffer "*mu4e-main*"
|
|
||||||
(mu4e--main-redraw))))))
|
|
||||||
|
|
||||||
(add-hook 'projectile-after-switch-project-hook
|
;; 1. Always strip out previous project shortcuts safely
|
||||||
#'gortium/inject-project-mu4e-bookmarks)
|
(setq mu4e-maildir-shortcuts
|
||||||
|
(seq-filter (lambda (shortcut)
|
||||||
|
(let ((key (if (listp (cdr shortcut))
|
||||||
|
(plist-get shortcut :key)
|
||||||
|
(cdr shortcut))))
|
||||||
|
(not (memq key gortium/project-mu4e-keys))))
|
||||||
|
mu4e-maildir-shortcuts))
|
||||||
|
|
||||||
|
;; 2. Determine whether to inject and log the reason to *Messages*
|
||||||
|
(cond
|
||||||
|
((not proj-tag)
|
||||||
|
;; No tag found, do nothing silently (prevents spam on non-project files)
|
||||||
|
nil)
|
||||||
|
|
||||||
|
((and context-tag cur-context-name (not (string= context-tag cur-context-name)))
|
||||||
|
(message "[mu4e Project] Skipped: .dir-locals context '%s' does not match active mu4e context '%s'."
|
||||||
|
context-tag cur-context-name))
|
||||||
|
|
||||||
|
(t
|
||||||
|
;; 3. Build and inject the shortcuts
|
||||||
|
(dolist (folder '(("Inbox" . ?I)
|
||||||
|
("Sent" . ?S)
|
||||||
|
("Drafts" . ?D)
|
||||||
|
("Trash" . ?T)
|
||||||
|
("Archive" . ?A)))
|
||||||
|
(push `(:maildir ,(format "/%s.%s" (car folder) proj-tag)
|
||||||
|
:key ,(cdr folder)
|
||||||
|
:name ,(format "[%s] %s" proj-tag (car folder)))
|
||||||
|
project-shortcuts))
|
||||||
|
|
||||||
|
(setq mu4e-maildir-shortcuts
|
||||||
|
(append mu4e-maildir-shortcuts (nreverse project-shortcuts)))
|
||||||
|
(message "[mu4e Project] Successfully injected maildirs for project tag: %s" proj-tag))))))
|
||||||
|
|
||||||
|
;; Apply the hooks
|
||||||
|
(add-hook 'projectile-after-switch-project-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
(add-hook 'find-file-hook #'gortium/inject-project-mu4e-bookmarks)
|
(add-hook 'find-file-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
(add-hook 'mu4e-main-mode-hook #'gortium/inject-project-mu4e-bookmarks)
|
(add-hook 'mu4e-main-mode-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
|
|
||||||
|
;; CRITICAL: Re-inject AFTER mu4e applies its context variables
|
||||||
|
(add-hook 'mu4e-context-changed-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
|
|
||||||
(after! mu4e
|
(after! mu4e
|
||||||
(gortium/inject-project-mu4e-bookmarks))
|
(gortium/inject-project-mu4e-bookmarks))
|
||||||
#+end_src
|
#+end_src
|
||||||
@@ -3590,6 +3598,7 @@ Saves only project bookmarks without contaminating global list."
|
|||||||
;; Restore globals
|
;; Restore globals
|
||||||
(setq bookmark-alist saved-alist)
|
(setq bookmark-alist saved-alist)
|
||||||
(message "Bookmark added to .bookmarks"))))
|
(message "Bookmark added to .bookmarks"))))
|
||||||
|
|
||||||
(defun gortium/remove-bookmark-from-plan (name)
|
(defun gortium/remove-bookmark-from-plan (name)
|
||||||
"Remove a bookmark entry from * Bookmarks in the Plan file."
|
"Remove a bookmark entry from * Bookmarks in the Plan file."
|
||||||
(when-let* ((plan-file (gortium/project-plan-file)))
|
(when-let* ((plan-file (gortium/project-plan-file)))
|
||||||
@@ -3637,6 +3646,34 @@ Project bookmarks go to .bookmarks file in project root."
|
|||||||
(message "Project bookmark \"%s\" saved to .bookmarks" name))
|
(message "Project bookmark \"%s\" saved to .bookmarks" name))
|
||||||
(user-error "Not in a Projectile project"))))))
|
(user-error "Not in a Projectile project"))))))
|
||||||
|
|
||||||
|
(defun gortium/bookmark-delete ()
|
||||||
|
"Delete a bookmark. Prompts: (g)lobal or (p)roject.
|
||||||
|
Project bookmarks are deleted from the .bookmarks file in the project root."
|
||||||
|
(interactive)
|
||||||
|
(let ((choice (read-char-choice "Delete: (g)lobal / (p)roject? " '(?g ?p))))
|
||||||
|
(pcase choice
|
||||||
|
(?g (call-interactively 'bookmark-delete))
|
||||||
|
(?p
|
||||||
|
(if (not (projectile-project-p))
|
||||||
|
(user-error "Not in a Projectile project")
|
||||||
|
(let ((proj-file (expand-file-name ".bookmarks" (projectile-project-root))))
|
||||||
|
(if (not (file-exists-p proj-file))
|
||||||
|
(message "No project bookmarks found.")
|
||||||
|
|
||||||
|
;; Dynamically bind the project bookmarks
|
||||||
|
(let* ((bookmark-alist (with-temp-buffer
|
||||||
|
(insert-file-contents proj-file)
|
||||||
|
(read (current-buffer))))
|
||||||
|
(names (bookmark-all-names)))
|
||||||
|
|
||||||
|
(if (not names)
|
||||||
|
(message "No bookmarks in project.")
|
||||||
|
(let ((bm-name (completing-read "Delete Project Bookmark: " names nil t)))
|
||||||
|
(when (and bm-name (not (string-empty-p bm-name)))
|
||||||
|
;; Delete from the temporarily bound alist and save
|
||||||
|
(bookmark-delete bm-name nil)
|
||||||
|
(bookmark-save nil proj-file t)
|
||||||
|
(message "Deleted project bookmark: %s" bm-name))))))))))))
|
||||||
|
|
||||||
(defun gortium/sync-plan-to-bookmark-file (bookmarks)
|
(defun gortium/sync-plan-to-bookmark-file (bookmarks)
|
||||||
"Write BOOKMARKS alist back to the Plan file under * Bookmarks."
|
"Write BOOKMARKS alist back to the Plan file under * Bookmarks."
|
||||||
@@ -3700,34 +3737,48 @@ Project bookmarks go to .bookmarks file in project root."
|
|||||||
(message "Transferred '%s' to global" name)))))))
|
(message "Transferred '%s' to global" name)))))))
|
||||||
|
|
||||||
(defun gortium/list-project-bookmarks ()
|
(defun gortium/list-project-bookmarks ()
|
||||||
"Show project bookmarks menu — restores globals after RET jump and on q."
|
"Jump to a project bookmark using standard completion.
|
||||||
|
Keeps global bookmarks completely uncontaminated."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if (not (projectile-project-p))
|
(if (not (projectile-project-p))
|
||||||
(user-error "Not in a project")
|
(user-error "Not in a project")
|
||||||
(let* ((proj-file (expand-file-name ".bookmarks" (projectile-project-root)))
|
(let ((proj-file (expand-file-name ".bookmarks" (projectile-project-root))))
|
||||||
(saved-alist (copy-tree bookmark-alist))
|
|
||||||
(saved-file bookmark-default-file))
|
|
||||||
(if (not (file-exists-p proj-file))
|
(if (not (file-exists-p proj-file))
|
||||||
(message "No .bookmarks file in this project.")
|
(message "No .bookmarks file in this project.")
|
||||||
;; Read project bookmarks directly (read, not bookmark-load)
|
|
||||||
(setq bookmark-alist
|
;; 1. Dynamically bind bookmark-alist.
|
||||||
(with-temp-buffer
|
;; Emacs will ONLY see these bookmarks inside this let block.
|
||||||
(insert-file-contents proj-file)
|
(let* ((bookmark-alist (with-temp-buffer
|
||||||
(read (current-buffer))))
|
(insert-file-contents proj-file)
|
||||||
(bookmark-bmenu-list)
|
(read (current-buffer))))
|
||||||
;; Restore globals after each RET jump AND on q
|
|
||||||
(with-current-buffer "*Bookmark List*"
|
;; 2. Fetch names based on the temporary project alist
|
||||||
(local-set-key (kbd "RET")
|
(names (bookmark-all-names))
|
||||||
(lambda ()
|
|
||||||
(interactive)
|
;; 3. Prompt the user for a selection
|
||||||
(bookmark-bmenu-this-window)
|
(bm-name (when names
|
||||||
(setq bookmark-alist saved-alist)
|
(completing-read "Project Bookmark: " names nil t))))
|
||||||
(setq bookmark-default-file saved-file)))
|
|
||||||
(add-hook 'kill-buffer-hook
|
;; 4. Jump to it. Once this let block ends, global bookmarks instantly return.
|
||||||
(lambda ()
|
(if bm-name
|
||||||
(setq bookmark-alist saved-alist)
|
(bookmark-jump bm-name)
|
||||||
(setq bookmark-default-file saved-file))
|
(message "No bookmarks found in project.")))))))
|
||||||
nil t))))))
|
|
||||||
|
(map! :leader
|
||||||
|
:desc "Set global/project bookmark"
|
||||||
|
"b m" #'gortium/bookmark-set
|
||||||
|
|
||||||
|
:desc "Delete global/project bookmark"
|
||||||
|
"b M" #'gortium/bookmark-delete)
|
||||||
|
|
||||||
|
;; Example using General.el / Doom Emacs map! macro
|
||||||
|
(map! :leader
|
||||||
|
:desc "List project bookmarks" "p RET" #'gortium/list-project-bookmarks)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Refile done task
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(defun gortium/refile-to-today-daily ()
|
(defun gortium/refile-to-today-daily ()
|
||||||
"Refile the current subtree under the 'Journal' headline in today's daily note.
|
"Refile the current subtree under the 'Journal' headline in today's daily note.
|
||||||
This version uses `org-roam-dailies-capture-today` to ensure the daily note
|
This version uses `org-roam-dailies-capture-today` to ensure the daily note
|
||||||
@@ -3966,6 +4017,5 @@ Need chrome... :(
|
|||||||
:desc "Edit Edna rules" "E" #'org-edna-edit))
|
:desc "Edit Edna rules" "E" #'org-edna-edit))
|
||||||
|
|
||||||
|
|
||||||
** Project-Aware Agenda
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1441,60 +1441,68 @@ Cordialement,
|
|||||||
(defconst gortium/project-mu4e-keys '(?I ?S ?D ?T ?A)
|
(defconst gortium/project-mu4e-keys '(?I ?S ?D ?T ?A)
|
||||||
"Character keys used for project mu4e maildir shortcuts (uppercase avoids conflicts).")
|
"Character keys used for project mu4e maildir shortcuts (uppercase avoids conflicts).")
|
||||||
|
|
||||||
(defvar gortium/project-mu4e-bookmarks nil
|
|
||||||
"Cached project mu4e maildir shortcuts for re-injection when mu4e loads.")
|
|
||||||
|
|
||||||
(defun gortium/inject-project-mu4e-bookmarks ()
|
(defun gortium/inject-project-mu4e-bookmarks ()
|
||||||
"Inject project mu4e maildirs into mu4e-maildir-shortcuts.
|
"Inject project mu4e maildirs into mu4e-maildir-shortcuts.
|
||||||
Keys [PI]/[PS]/[PD]/[PT]/[PA] (uppercase). Filters by context-tag:
|
Keys [I]/[S]/[D]/[T]/[A] (uppercase). Filters by context-tag:
|
||||||
only injects when the project's context-tag matches current mu4e context."
|
only injects when the project's context-tag matches current mu4e context."
|
||||||
(let* ((proj-root (and (projectile-project-p) (projectile-project-root)))
|
(interactive)
|
||||||
(proj-tag (when proj-root
|
(when (boundp 'mu4e-maildir-shortcuts)
|
||||||
(let ((default-directory proj-root))
|
(let* ((proj-root (and (projectile-project-p) (projectile-project-root)))
|
||||||
(gortium/read-dir-local 'gortium/project-tag))))
|
(proj-tag (when proj-root
|
||||||
(context-tag (when proj-root
|
(let ((default-directory proj-root))
|
||||||
(let ((default-directory proj-root))
|
(gortium/read-dir-local 'gortium/project-tag))))
|
||||||
(gortium/read-dir-local 'gortium/context-tag))))
|
(context-tag (when proj-root
|
||||||
(cur-context (and (boundp 'mu4e-context-current)
|
(let ((default-directory proj-root))
|
||||||
(car-safe mu4e-context-current)))
|
(gortium/read-dir-local 'gortium/context-tag))))
|
||||||
(project-bm '()))
|
;; Extract the context name safely
|
||||||
;; Only inject if context-tag matches current mu4e context
|
(cur-context-name (and (boundp 'mu4e-context-current)
|
||||||
;; (if no context-tag set, always inject)
|
mu4e-context-current
|
||||||
(when (and proj-tag
|
(mu4e-context-name mu4e-context-current)))
|
||||||
(or (null context-tag)
|
(project-shortcuts '()))
|
||||||
(and cur-context
|
|
||||||
(string= context-tag
|
|
||||||
(mu4e-context-name cur-context)))))
|
|
||||||
(dolist (folder '(("Inbox" . ?I)
|
|
||||||
("Sent" . ?S)
|
|
||||||
("Drafts" . ?D)
|
|
||||||
("Trash" . ?T)
|
|
||||||
("Archive" . ?A)))
|
|
||||||
(push (cons (format "maildir:/%s.%s" (car folder) proj-tag)
|
|
||||||
(cdr folder))
|
|
||||||
project-bm)))
|
|
||||||
;; Inject into mu4e-maildir-shortcuts
|
|
||||||
(setq gortium/project-mu4e-bookmarks project-bm)
|
|
||||||
(when (and (boundp 'mu4e-maildir-shortcuts) project-bm)
|
|
||||||
;; Remove stale project entries
|
|
||||||
(setq mu4e-maildir-shortcuts
|
|
||||||
(seq-filter (lambda (s)
|
|
||||||
(not (and (consp s) (stringp (car s))
|
|
||||||
(string-match "^\\[[A-Z]+\\]" (car s)))))
|
|
||||||
mu4e-maildir-shortcuts))
|
|
||||||
;; Add current project entries
|
|
||||||
(setq mu4e-maildir-shortcuts
|
|
||||||
(append mu4e-maildir-shortcuts project-bm))
|
|
||||||
;; Refresh
|
|
||||||
(setq mu4e--bookmark-items-cached nil)
|
|
||||||
(when (get-buffer "*mu4e-main*")
|
|
||||||
(with-current-buffer "*mu4e-main*"
|
|
||||||
(mu4e--main-redraw))))))
|
|
||||||
|
|
||||||
(add-hook 'projectile-after-switch-project-hook
|
;; 1. Always strip out previous project shortcuts safely
|
||||||
#'gortium/inject-project-mu4e-bookmarks)
|
(setq mu4e-maildir-shortcuts
|
||||||
|
(seq-filter (lambda (shortcut)
|
||||||
|
(let ((key (if (listp (cdr shortcut))
|
||||||
|
(plist-get shortcut :key)
|
||||||
|
(cdr shortcut))))
|
||||||
|
(not (memq key gortium/project-mu4e-keys))))
|
||||||
|
mu4e-maildir-shortcuts))
|
||||||
|
|
||||||
|
;; 2. Determine whether to inject and log the reason to *Messages*
|
||||||
|
(cond
|
||||||
|
((not proj-tag)
|
||||||
|
;; No tag found, do nothing silently (prevents spam on non-project files)
|
||||||
|
nil)
|
||||||
|
|
||||||
|
((and context-tag cur-context-name (not (string= context-tag cur-context-name)))
|
||||||
|
(message "[mu4e Project] Skipped: .dir-locals context '%s' does not match active mu4e context '%s'."
|
||||||
|
context-tag cur-context-name))
|
||||||
|
|
||||||
|
(t
|
||||||
|
;; 3. Build and inject the shortcuts
|
||||||
|
(dolist (folder '(("Inbox" . ?I)
|
||||||
|
("Sent" . ?S)
|
||||||
|
("Drafts" . ?D)
|
||||||
|
("Trash" . ?T)
|
||||||
|
("Archive" . ?A)))
|
||||||
|
(push `(:maildir ,(format "/%s.%s" (car folder) proj-tag)
|
||||||
|
:key ,(cdr folder)
|
||||||
|
:name ,(format "[%s] %s" proj-tag (car folder)))
|
||||||
|
project-shortcuts))
|
||||||
|
|
||||||
|
(setq mu4e-maildir-shortcuts
|
||||||
|
(append mu4e-maildir-shortcuts (nreverse project-shortcuts)))
|
||||||
|
(message "[mu4e Project] Successfully injected maildirs for project tag: %s" proj-tag))))))
|
||||||
|
|
||||||
|
;; Apply the hooks
|
||||||
|
(add-hook 'projectile-after-switch-project-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
(add-hook 'find-file-hook #'gortium/inject-project-mu4e-bookmarks)
|
(add-hook 'find-file-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
(add-hook 'mu4e-main-mode-hook #'gortium/inject-project-mu4e-bookmarks)
|
(add-hook 'mu4e-main-mode-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
|
|
||||||
|
;; CRITICAL: Re-inject AFTER mu4e applies its context variables
|
||||||
|
(add-hook 'mu4e-context-changed-hook #'gortium/inject-project-mu4e-bookmarks)
|
||||||
|
|
||||||
(after! mu4e
|
(after! mu4e
|
||||||
(gortium/inject-project-mu4e-bookmarks))
|
(gortium/inject-project-mu4e-bookmarks))
|
||||||
|
|
||||||
@@ -2657,6 +2665,7 @@ Saves only project bookmarks without contaminating global list."
|
|||||||
;; Restore globals
|
;; Restore globals
|
||||||
(setq bookmark-alist saved-alist)
|
(setq bookmark-alist saved-alist)
|
||||||
(message "Bookmark added to .bookmarks"))))
|
(message "Bookmark added to .bookmarks"))))
|
||||||
|
|
||||||
(defun gortium/remove-bookmark-from-plan (name)
|
(defun gortium/remove-bookmark-from-plan (name)
|
||||||
"Remove a bookmark entry from * Bookmarks in the Plan file."
|
"Remove a bookmark entry from * Bookmarks in the Plan file."
|
||||||
(when-let* ((plan-file (gortium/project-plan-file)))
|
(when-let* ((plan-file (gortium/project-plan-file)))
|
||||||
@@ -2704,6 +2713,34 @@ Project bookmarks go to .bookmarks file in project root."
|
|||||||
(message "Project bookmark \"%s\" saved to .bookmarks" name))
|
(message "Project bookmark \"%s\" saved to .bookmarks" name))
|
||||||
(user-error "Not in a Projectile project"))))))
|
(user-error "Not in a Projectile project"))))))
|
||||||
|
|
||||||
|
(defun gortium/bookmark-delete ()
|
||||||
|
"Delete a bookmark. Prompts: (g)lobal or (p)roject.
|
||||||
|
Project bookmarks are deleted from the .bookmarks file in the project root."
|
||||||
|
(interactive)
|
||||||
|
(let ((choice (read-char-choice "Delete: (g)lobal / (p)roject? " '(?g ?p))))
|
||||||
|
(pcase choice
|
||||||
|
(?g (call-interactively 'bookmark-delete))
|
||||||
|
(?p
|
||||||
|
(if (not (projectile-project-p))
|
||||||
|
(user-error "Not in a Projectile project")
|
||||||
|
(let ((proj-file (expand-file-name ".bookmarks" (projectile-project-root))))
|
||||||
|
(if (not (file-exists-p proj-file))
|
||||||
|
(message "No project bookmarks found.")
|
||||||
|
|
||||||
|
;; Dynamically bind the project bookmarks
|
||||||
|
(let* ((bookmark-alist (with-temp-buffer
|
||||||
|
(insert-file-contents proj-file)
|
||||||
|
(read (current-buffer))))
|
||||||
|
(names (bookmark-all-names)))
|
||||||
|
|
||||||
|
(if (not names)
|
||||||
|
(message "No bookmarks in project.")
|
||||||
|
(let ((bm-name (completing-read "Delete Project Bookmark: " names nil t)))
|
||||||
|
(when (and bm-name (not (string-empty-p bm-name)))
|
||||||
|
;; Delete from the temporarily bound alist and save
|
||||||
|
(bookmark-delete bm-name nil)
|
||||||
|
(bookmark-save nil proj-file t)
|
||||||
|
(message "Deleted project bookmark: %s" bm-name))))))))))))
|
||||||
|
|
||||||
(defun gortium/sync-plan-to-bookmark-file (bookmarks)
|
(defun gortium/sync-plan-to-bookmark-file (bookmarks)
|
||||||
"Write BOOKMARKS alist back to the Plan file under * Bookmarks."
|
"Write BOOKMARKS alist back to the Plan file under * Bookmarks."
|
||||||
@@ -2767,34 +2804,44 @@ Project bookmarks go to .bookmarks file in project root."
|
|||||||
(message "Transferred '%s' to global" name)))))))
|
(message "Transferred '%s' to global" name)))))))
|
||||||
|
|
||||||
(defun gortium/list-project-bookmarks ()
|
(defun gortium/list-project-bookmarks ()
|
||||||
"Show project bookmarks menu — restores globals after RET jump and on q."
|
"Jump to a project bookmark using standard completion.
|
||||||
|
Keeps global bookmarks completely uncontaminated."
|
||||||
(interactive)
|
(interactive)
|
||||||
(if (not (projectile-project-p))
|
(if (not (projectile-project-p))
|
||||||
(user-error "Not in a project")
|
(user-error "Not in a project")
|
||||||
(let* ((proj-file (expand-file-name ".bookmarks" (projectile-project-root)))
|
(let ((proj-file (expand-file-name ".bookmarks" (projectile-project-root))))
|
||||||
(saved-alist (copy-tree bookmark-alist))
|
|
||||||
(saved-file bookmark-default-file))
|
|
||||||
(if (not (file-exists-p proj-file))
|
(if (not (file-exists-p proj-file))
|
||||||
(message "No .bookmarks file in this project.")
|
(message "No .bookmarks file in this project.")
|
||||||
;; Read project bookmarks directly (read, not bookmark-load)
|
|
||||||
(setq bookmark-alist
|
;; 1. Dynamically bind bookmark-alist.
|
||||||
(with-temp-buffer
|
;; Emacs will ONLY see these bookmarks inside this let block.
|
||||||
(insert-file-contents proj-file)
|
(let* ((bookmark-alist (with-temp-buffer
|
||||||
(read (current-buffer))))
|
(insert-file-contents proj-file)
|
||||||
(bookmark-bmenu-list)
|
(read (current-buffer))))
|
||||||
;; Restore globals after each RET jump AND on q
|
|
||||||
(with-current-buffer "*Bookmark List*"
|
;; 2. Fetch names based on the temporary project alist
|
||||||
(local-set-key (kbd "RET")
|
(names (bookmark-all-names))
|
||||||
(lambda ()
|
|
||||||
(interactive)
|
;; 3. Prompt the user for a selection
|
||||||
(bookmark-bmenu-this-window)
|
(bm-name (when names
|
||||||
(setq bookmark-alist saved-alist)
|
(completing-read "Project Bookmark: " names nil t))))
|
||||||
(setq bookmark-default-file saved-file)))
|
|
||||||
(add-hook 'kill-buffer-hook
|
;; 4. Jump to it. Once this let block ends, global bookmarks instantly return.
|
||||||
(lambda ()
|
(if bm-name
|
||||||
(setq bookmark-alist saved-alist)
|
(bookmark-jump bm-name)
|
||||||
(setq bookmark-default-file saved-file))
|
(message "No bookmarks found in project.")))))))
|
||||||
nil t))))))
|
|
||||||
|
(map! :leader
|
||||||
|
:desc "Set global/project bookmark"
|
||||||
|
"b m" #'gortium/bookmark-set
|
||||||
|
|
||||||
|
:desc "Delete global/project bookmark"
|
||||||
|
"b M" #'gortium/bookmark-delete)
|
||||||
|
|
||||||
|
;; Example using General.el / Doom Emacs map! macro
|
||||||
|
(map! :leader
|
||||||
|
:desc "List project bookmarks" "p RET" #'gortium/list-project-bookmarks)
|
||||||
|
|
||||||
(defun gortium/refile-to-today-daily ()
|
(defun gortium/refile-to-today-daily ()
|
||||||
"Refile the current subtree under the 'Journal' headline in today's daily note.
|
"Refile the current subtree under the 'Journal' headline in today's daily note.
|
||||||
This version uses `org-roam-dailies-capture-today` to ensure the daily note
|
This version uses `org-roam-dailies-capture-today` to ensure the daily note
|
||||||
|
|||||||
Reference in New Issue
Block a user