fix: restore bookmark fns, require from separate file
This commit is contained in:
@@ -89,7 +89,7 @@ available. You can either set ~doom-theme~ or manually load a theme with the
|
||||
~load-theme~ function. This is the default:
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq doom-theme 'doom-gruvbox)
|
||||
(setq doom-theme 'sanityinc-tomorrow-night)
|
||||
#+end_src
|
||||
|
||||
** Projectile (ExoKortex)
|
||||
@@ -99,9 +99,9 @@ No more auto-discovery of random =.git= repos.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! projectile
|
||||
;; Only .projectile files define a project root
|
||||
(setq projectile-project-root-files '(".projectile"))
|
||||
;; Stop auto-scanning everything — only explicit .projectile markers count
|
||||
(setq projectile-project-root-files-bottom-up nil)
|
||||
(setq projectile-project-root-files-top-down-recurring nil)
|
||||
(setq projectile-auto-discover nil))
|
||||
#+end_src
|
||||
|
||||
@@ -240,48 +240,32 @@ org-agenda-files (seq-uniq org-agenda-files)
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! org
|
||||
;; Header size
|
||||
(custom-set-faces!
|
||||
'(org-document-title :height 2.0 :weight bold)
|
||||
'(org-level-1 :foreground "#b8bb26" :weight semi-bold :height 1.45) ; green
|
||||
'(org-level-2 :foreground "#83a598" :weight semi-bold :height 1.35) ; blue
|
||||
'(org-level-3 :foreground "#d3869b" :weight semi-bold :height 1.25) ; purple
|
||||
'(org-level-4 :foreground "#8ec07c" :weight semi-bold :height 1.15) ; aqua
|
||||
'(org-level-5 :foreground "#fabd2f" :weight normal :height 1.10) ; yellow
|
||||
'(org-level-6 :foreground "#fe8019" :weight normal :height 1.05) ; orange
|
||||
'(org-level-7 :foreground "#cc241d" :weight normal :height 1.02) ; red
|
||||
'(org-level-8 :foreground "#a89984" :weight normal :height 1.00)) ; grey-brown
|
||||
;; '(org-level-1 :weight semi-bold :height 1.45)
|
||||
;; '(org-level-2 :weight semi-bold :height 1.35)
|
||||
;; '(org-level-3 :weight semi-bold :height 1.25)
|
||||
;; '(org-level-4 :weight semi-bold :height 1.15)
|
||||
;; '(org-level-5 :weight normal :height 1.10)
|
||||
;; '(org-level-6 :weight normal :height 1.05)
|
||||
;; '(org-level-7 :weight normal :height 1.02)
|
||||
;; '(org-level-8 :weight normal :height 1.00))
|
||||
;; 1. Update existing faces (Org defines 1-8 by default)
|
||||
(set-face-attribute 'org-document-title nil :height 2.0 :weight 'bold)
|
||||
(set-face-attribute 'org-level-1 nil :weight 'semi-bold :height 1.45)
|
||||
(set-face-attribute 'org-level-2 nil :weight 'semi-bold :height 1.35)
|
||||
(set-face-attribute 'org-level-3 nil :weight 'semi-bold :height 1.25)
|
||||
(set-face-attribute 'org-level-4 nil :weight 'semi-bold :height 1.15)
|
||||
(set-face-attribute 'org-level-5 nil :weight 'normal :height 1.10)
|
||||
(set-face-attribute 'org-level-6 nil :weight 'normal :height 1.05)
|
||||
(set-face-attribute 'org-level-7 nil :weight 'normal :height 1.02)
|
||||
(set-face-attribute 'org-level-8 nil :weight 'normal :height 1.00)
|
||||
|
||||
;; Clamp all levels beyond 8 to use org-level-8 face
|
||||
(defvar gortium/org-level-8-face
|
||||
'((t :foreground "#a89984" :weight normal :height 1.00)))
|
||||
;; '((t :weight normal :height 1.00)))
|
||||
|
||||
;; Définir org-level-9 à org-level-20 avec la même face que org-level-8
|
||||
;; 2. Create missing faces (9-20) and inherit them directly from org-level-8
|
||||
(cl-loop for lvl from 9 to 20
|
||||
do (eval
|
||||
`(defface ,(intern (format "org-level-%d" lvl))
|
||||
',gortium/org-level-8-face
|
||||
,(format "Face pour org heading level %d (cloné du niveau 8)." lvl)
|
||||
:group 'org-faces)))
|
||||
do (let ((face-name (intern (format "org-level-%d" lvl))))
|
||||
(custom-declare-face face-name
|
||||
'((t :inherit org-level-8))
|
||||
(format "Face for org heading level %d." lvl)
|
||||
:group 'org-faces)))
|
||||
|
||||
;; Ajout des nouvelles faces dans org-level-faces
|
||||
;; 3. Add the newly created faces to Org's level list
|
||||
(setq org-level-faces
|
||||
(append org-level-faces
|
||||
(mapcar (lambda (lvl) (intern (format "org-level-%d" lvl)))
|
||||
(number-sequence 9 20))))
|
||||
|
||||
;; Mise à jour du nombre total de niveaux
|
||||
(setq org-n-level-faces (length org-level-faces))
|
||||
)
|
||||
(setq org-n-level-faces (length org-level-faces)))
|
||||
#+end_src
|
||||
|
||||
** Clock-in
|
||||
@@ -2182,7 +2166,7 @@ Useful for the user, but also when you have someone over your shoulder trying to
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(after! mu4e
|
||||
(setq mu4e-maildir-shortcuts mu4e-maildir-list mu4e-maildir-initial-input mu4e-maildir-info-delimiter)
|
||||
(setq mu4e-maildir-initial-input mu4e-maildir-info-delimiter)
|
||||
(setq mu4e-update-interval 300)
|
||||
(setq mu4e-headers-auto-update t)
|
||||
(setq mu4e-contexts
|
||||
@@ -2203,12 +2187,12 @@ Useful for the user, but also when you have someone over your shoulder trying to
|
||||
(mu4e-trash-folder . "/TDNDE/Trash")
|
||||
(mu4e-refile-folder . "/TDNDE/Archive")
|
||||
|
||||
;; Shortcuts
|
||||
(mu4e-maildir-shortcuts . (("/TDNDE/Inbox" . ?i)
|
||||
("/TDNDE/Sent" . ?s)
|
||||
("/TDNDE/Drafts" . ?d)
|
||||
("/TDNDE/Trash" . ?t)
|
||||
("/TDNDE/Archive" . ?a)))
|
||||
;; Shortcuts (Updated to modern Plist format)
|
||||
(mu4e-maildir-shortcuts . ((:maildir "/TDNDE/Inbox" :key ?i)
|
||||
(:maildir "/TDNDE/Sent" :key ?s)
|
||||
(:maildir "/TDNDE/Drafts" :key ?d)
|
||||
(:maildir "/TDNDE/Trash" :key ?t)
|
||||
(:maildir "/TDNDE/Archive" :key ?a)))
|
||||
|
||||
;; SMTP
|
||||
(smtpmail-smtp-user . "tpouplier@tdnde.com")
|
||||
@@ -2221,10 +2205,10 @@ Useful for the user, but also when you have someone over your shoulder trying to
|
||||
(org-msg-signature . "
|
||||
Cdlt,
|
||||
|
||||
,#+begin_signature
|
||||
#+begin_signature
|
||||
--
|
||||
|
||||
,*Thierry Pouplier*
|
||||
*Thierry Pouplier*
|
||||
|
||||
1319 rue Bergar, Laval, Qc, Canada \\\\
|
||||
H7L 4Z7 \\\\
|
||||
@@ -2232,7 +2216,7 @@ Tél. : +1 (450) 667-1884 \\\\
|
||||
Cell. : +1 (514) 887-1674 \\\\
|
||||
tpouplier@tdnde.com \\\\
|
||||
www.tdnde.com \\\\
|
||||
,#+end_signature")))
|
||||
#+end_signature")))
|
||||
|
||||
;; --- CONTEXT: Perso ---
|
||||
(make-mu4e-context
|
||||
@@ -2240,18 +2224,20 @@ www.tdnde.com \\\\
|
||||
:match-func (lambda (msg)
|
||||
(when msg
|
||||
(string-prefix-p "/Perso/" (mu4e-message-field msg :maildir))))
|
||||
:vars `((user-mail-address . "thierrypouplier@gmail.com")
|
||||
(user-full-name . "Thierry Pouplier")
|
||||
(mu4e-sent-folder . "/Perso/Sent")
|
||||
(mu4e-drafts-folder . "/Perso/Drafts")
|
||||
(mu4e-trash-folder . "/Perso/Trash")
|
||||
(mu4e-refile-folder . "/Perso/Archive")
|
||||
;; Fixed standard single quote evaluation alignment
|
||||
:vars '((user-mail-address . "thierrypouplier@gmail.com")
|
||||
(user-full-name . "Thierry Pouplier")
|
||||
(mu4e-sent-folder . "/Perso/Sent")
|
||||
(mu4e-drafts-folder . "/Perso/Drafts")
|
||||
(mu4e-trash-folder . "/Perso/Trash")
|
||||
(mu4e-refile-folder . "/Perso/Archive")
|
||||
|
||||
(mu4e-maildir-shortcuts . (("/Perso/Inbox" . ?i)
|
||||
("/Perso/Sent" . ?s)
|
||||
("/Perso/Trash" . ?t)
|
||||
("/Perso/Drafts" . ?d)
|
||||
("/Perso/Archive" . ?a)))
|
||||
;; Shortcuts (Updated to modern Plist format)
|
||||
(mu4e-maildir-shortcuts . ((:maildir "/Perso/Inbox" :key ?i)
|
||||
(:maildir "/Perso/Sent" :key ?s)
|
||||
(:maildir "/Perso/Trash" :key ?t)
|
||||
(:maildir "/Perso/Drafts" :key ?d)
|
||||
(:maildir "/Perso/Archive" :key ?a)))
|
||||
|
||||
(smtpmail-smtp-user . "thierrypouplier@gmail.com")
|
||||
(smtpmail-smtp-server . "smtp.gmail.com")
|
||||
@@ -2261,11 +2247,11 @@ www.tdnde.com \\\\
|
||||
(org-msg-signature . "
|
||||
Cordialement,
|
||||
|
||||
,#+begin_signature
|
||||
--
|
||||
,*Thierry Pouplier* \\
|
||||
#+begin_signature
|
||||
-r
|
||||
*Thierry Pouplier* \\
|
||||
(514) 887-1674 | thierrypouplier@gmail.com
|
||||
,#+end_signature"))))) ;; End of mu4e-contexts list
|
||||
#+end_signature")))))
|
||||
|
||||
(setq mu4e-context-policy 'pick-first
|
||||
mu4e-compose-context-policy 'ask)
|
||||
@@ -3560,6 +3546,9 @@ to .org files under the project root."
|
||||
(map! :leader
|
||||
:desc "Project-aware agenda"
|
||||
"o P" #'gortium/project-aware-agenda)
|
||||
|
||||
;; Load project bookmark functions
|
||||
(require 'gortium-bookmarks nil t)
|
||||
#+end_src
|
||||
|
||||
#+RESULTS:
|
||||
@@ -3741,14 +3730,11 @@ Need chrome... :(
|
||||
(map! :map org-mode-map
|
||||
:localleader
|
||||
:desc "Edit Edna rules" "E" #'org-edna-edit))
|
||||
#+end_src
|
||||
|
||||
|
||||
|
||||
|
||||
** Project-Aware Agenda
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
#+begin_src emacs-lisp :tangle no
|
||||
;; Remove stale project entries and inject current project's agenda
|
||||
(defvar gortium/project-agenda-commands nil
|
||||
"Cached project agenda commands.")
|
||||
@@ -3778,11 +3764,13 @@ Need chrome... :(
|
||||
#'gortium/inject-project-agenda)
|
||||
;; Also inject at startup and on file open in a project
|
||||
(add-hook 'find-file-hook #'gortium/inject-project-agenda)
|
||||
#+end_src
|
||||
|
||||
** Project Bookmarks
|
||||
;; Load project bookmark functions
|
||||
(require 'gortium-bookmarks nil t)
|
||||
|
||||
;; Load project bookmark functions
|
||||
(require 'gortium-bookmarks nil t)
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(defvar gortium/project-bookmark-names nil
|
||||
"Bookmark names currently in the Plan file for the active project.")
|
||||
|
||||
@@ -3834,9 +3822,7 @@ NAME is the display name, URL is the link target (file path or web URL)."
|
||||
(if (re-search-forward "^\* Bookmarks" nil t)
|
||||
(forward-line 1)
|
||||
(goto-char (point-max))
|
||||
(insert "
|
||||
* Bookmarks
|
||||
"))
|
||||
(insert "\n* Bookmarks\n"))
|
||||
(insert (format "[[%s][%s]]
|
||||
" url name))
|
||||
(write-region (point-min) (point-max) plan-file nil 'silent)
|
||||
@@ -3957,4 +3943,5 @@ in their native categories. On quit restores global bookmarks."
|
||||
"b m" #'gortium/bookmark-set
|
||||
:desc "Jump to project bookmark"
|
||||
"p RET" #'gortium/list-project-bookmarks)
|
||||
|
||||
#+end_src
|
||||
@@ -10,12 +10,12 @@
|
||||
(after! doom-big-font-mode
|
||||
(setq doom-big-font-increment 8))
|
||||
|
||||
(setq doom-theme 'doom-gruvbox)
|
||||
(setq doom-theme 'sanityinc-tomorrow-night)
|
||||
|
||||
(after! projectile
|
||||
;; Only .projectile files define a project root
|
||||
(setq projectile-project-root-files '(".projectile"))
|
||||
;; Stop auto-scanning everything — only explicit .projectile markers count
|
||||
(setq projectile-project-root-files-bottom-up nil)
|
||||
(setq projectile-project-root-files-top-down-recurring nil)
|
||||
(setq projectile-auto-discover nil))
|
||||
|
||||
(setq bookmark-save-flag 1)
|
||||
@@ -105,48 +105,32 @@ org-agenda-files (seq-uniq org-agenda-files)
|
||||
)
|
||||
|
||||
(after! org
|
||||
;; Header size
|
||||
(custom-set-faces!
|
||||
'(org-document-title :height 2.0 :weight bold)
|
||||
'(org-level-1 :foreground "#b8bb26" :weight semi-bold :height 1.45) ; green
|
||||
'(org-level-2 :foreground "#83a598" :weight semi-bold :height 1.35) ; blue
|
||||
'(org-level-3 :foreground "#d3869b" :weight semi-bold :height 1.25) ; purple
|
||||
'(org-level-4 :foreground "#8ec07c" :weight semi-bold :height 1.15) ; aqua
|
||||
'(org-level-5 :foreground "#fabd2f" :weight normal :height 1.10) ; yellow
|
||||
'(org-level-6 :foreground "#fe8019" :weight normal :height 1.05) ; orange
|
||||
'(org-level-7 :foreground "#cc241d" :weight normal :height 1.02) ; red
|
||||
'(org-level-8 :foreground "#a89984" :weight normal :height 1.00)) ; grey-brown
|
||||
;; '(org-level-1 :weight semi-bold :height 1.45)
|
||||
;; '(org-level-2 :weight semi-bold :height 1.35)
|
||||
;; '(org-level-3 :weight semi-bold :height 1.25)
|
||||
;; '(org-level-4 :weight semi-bold :height 1.15)
|
||||
;; '(org-level-5 :weight normal :height 1.10)
|
||||
;; '(org-level-6 :weight normal :height 1.05)
|
||||
;; '(org-level-7 :weight normal :height 1.02)
|
||||
;; '(org-level-8 :weight normal :height 1.00))
|
||||
;; 1. Update existing faces (Org defines 1-8 by default)
|
||||
(set-face-attribute 'org-document-title nil :height 2.0 :weight 'bold)
|
||||
(set-face-attribute 'org-level-1 nil :weight 'semi-bold :height 1.45)
|
||||
(set-face-attribute 'org-level-2 nil :weight 'semi-bold :height 1.35)
|
||||
(set-face-attribute 'org-level-3 nil :weight 'semi-bold :height 1.25)
|
||||
(set-face-attribute 'org-level-4 nil :weight 'semi-bold :height 1.15)
|
||||
(set-face-attribute 'org-level-5 nil :weight 'normal :height 1.10)
|
||||
(set-face-attribute 'org-level-6 nil :weight 'normal :height 1.05)
|
||||
(set-face-attribute 'org-level-7 nil :weight 'normal :height 1.02)
|
||||
(set-face-attribute 'org-level-8 nil :weight 'normal :height 1.00)
|
||||
|
||||
;; Clamp all levels beyond 8 to use org-level-8 face
|
||||
(defvar gortium/org-level-8-face
|
||||
'((t :foreground "#a89984" :weight normal :height 1.00)))
|
||||
;; '((t :weight normal :height 1.00)))
|
||||
|
||||
;; Définir org-level-9 à org-level-20 avec la même face que org-level-8
|
||||
;; 2. Create missing faces (9-20) and inherit them directly from org-level-8
|
||||
(cl-loop for lvl from 9 to 20
|
||||
do (eval
|
||||
`(defface ,(intern (format "org-level-%d" lvl))
|
||||
',gortium/org-level-8-face
|
||||
,(format "Face pour org heading level %d (cloné du niveau 8)." lvl)
|
||||
:group 'org-faces)))
|
||||
do (let ((face-name (intern (format "org-level-%d" lvl))))
|
||||
(custom-declare-face face-name
|
||||
'((t :inherit org-level-8))
|
||||
(format "Face for org heading level %d." lvl)
|
||||
:group 'org-faces)))
|
||||
|
||||
;; Ajout des nouvelles faces dans org-level-faces
|
||||
;; 3. Add the newly created faces to Org's level list
|
||||
(setq org-level-faces
|
||||
(append org-level-faces
|
||||
(mapcar (lambda (lvl) (intern (format "org-level-%d" lvl)))
|
||||
(number-sequence 9 20))))
|
||||
|
||||
;; Mise à jour du nombre total de niveaux
|
||||
(setq org-n-level-faces (length org-level-faces))
|
||||
)
|
||||
(setq org-n-level-faces (length org-level-faces)))
|
||||
|
||||
(after! org
|
||||
;; Automatically clock in when switching to STRT
|
||||
@@ -1340,7 +1324,7 @@ DIFF:
|
||||
)
|
||||
|
||||
(after! mu4e
|
||||
(setq mu4e-maildir-shortcuts mu4e-maildir-list mu4e-maildir-initial-input mu4e-maildir-info-delimiter)
|
||||
(setq mu4e-maildir-initial-input mu4e-maildir-info-delimiter)
|
||||
(setq mu4e-update-interval 300)
|
||||
(setq mu4e-headers-auto-update t)
|
||||
(setq mu4e-contexts
|
||||
@@ -1361,12 +1345,12 @@ DIFF:
|
||||
(mu4e-trash-folder . "/TDNDE/Trash")
|
||||
(mu4e-refile-folder . "/TDNDE/Archive")
|
||||
|
||||
;; Shortcuts
|
||||
(mu4e-maildir-shortcuts . (("/TDNDE/Inbox" . ?i)
|
||||
("/TDNDE/Sent" . ?s)
|
||||
("/TDNDE/Drafts" . ?d)
|
||||
("/TDNDE/Trash" . ?t)
|
||||
("/TDNDE/Archive" . ?a)))
|
||||
;; Shortcuts (Updated to modern Plist format)
|
||||
(mu4e-maildir-shortcuts . ((:maildir "/TDNDE/Inbox" :key ?i)
|
||||
(:maildir "/TDNDE/Sent" :key ?s)
|
||||
(:maildir "/TDNDE/Drafts" :key ?d)
|
||||
(:maildir "/TDNDE/Trash" :key ?t)
|
||||
(:maildir "/TDNDE/Archive" :key ?a)))
|
||||
|
||||
;; SMTP
|
||||
(smtpmail-smtp-user . "tpouplier@tdnde.com")
|
||||
@@ -1398,18 +1382,20 @@ www.tdnde.com \\\\
|
||||
:match-func (lambda (msg)
|
||||
(when msg
|
||||
(string-prefix-p "/Perso/" (mu4e-message-field msg :maildir))))
|
||||
:vars `((user-mail-address . "thierrypouplier@gmail.com")
|
||||
(user-full-name . "Thierry Pouplier")
|
||||
(mu4e-sent-folder . "/Perso/Sent")
|
||||
(mu4e-drafts-folder . "/Perso/Drafts")
|
||||
(mu4e-trash-folder . "/Perso/Trash")
|
||||
(mu4e-refile-folder . "/Perso/Archive")
|
||||
;; Fixed standard single quote evaluation alignment
|
||||
:vars '((user-mail-address . "thierrypouplier@gmail.com")
|
||||
(user-full-name . "Thierry Pouplier")
|
||||
(mu4e-sent-folder . "/Perso/Sent")
|
||||
(mu4e-drafts-folder . "/Perso/Drafts")
|
||||
(mu4e-trash-folder . "/Perso/Trash")
|
||||
(mu4e-refile-folder . "/Perso/Archive")
|
||||
|
||||
(mu4e-maildir-shortcuts . (("/Perso/Inbox" . ?i)
|
||||
("/Perso/Sent" . ?s)
|
||||
("/Perso/Trash" . ?t)
|
||||
("/Perso/Drafts" . ?d)
|
||||
("/Perso/Archive" . ?a)))
|
||||
;; Shortcuts (Updated to modern Plist format)
|
||||
(mu4e-maildir-shortcuts . ((:maildir "/Perso/Inbox" :key ?i)
|
||||
(:maildir "/Perso/Sent" :key ?s)
|
||||
(:maildir "/Perso/Trash" :key ?t)
|
||||
(:maildir "/Perso/Drafts" :key ?d)
|
||||
(:maildir "/Perso/Archive" :key ?a)))
|
||||
|
||||
(smtpmail-smtp-user . "thierrypouplier@gmail.com")
|
||||
(smtpmail-smtp-server . "smtp.gmail.com")
|
||||
@@ -1420,10 +1406,10 @@ www.tdnde.com \\\\
|
||||
Cordialement,
|
||||
|
||||
#+begin_signature
|
||||
--
|
||||
-r
|
||||
*Thierry Pouplier* \\
|
||||
(514) 887-1674 | thierrypouplier@gmail.com
|
||||
#+end_signature"))))) ;; End of mu4e-contexts list
|
||||
#+end_signature")))))
|
||||
|
||||
(setq mu4e-context-policy 'pick-first
|
||||
mu4e-compose-context-policy 'ask)
|
||||
@@ -2626,6 +2612,9 @@ to .org files under the project root."
|
||||
:desc "Project-aware agenda"
|
||||
"o P" #'gortium/project-aware-agenda)
|
||||
|
||||
;; Load project bookmark functions
|
||||
(require 'gortium-bookmarks nil t)
|
||||
|
||||
;; Like Emacs everywhere, but work in hyprland
|
||||
(defun thanos/wtype-text (text)
|
||||
"Process TEXT for wtype, handling newlines properly."
|
||||
@@ -2679,33 +2668,3 @@ to .org files under the project root."
|
||||
;; Make the frame more temporary-like
|
||||
(set-frame-parameter frame 'delete-before-kill-buffer t)
|
||||
(set-window-dedicated-p (selected-window) t))))
|
||||
|
||||
;; Remove stale project entries and inject current project's agenda
|
||||
(defvar gortium/project-agenda-commands nil
|
||||
"Cached project agenda commands.")
|
||||
|
||||
(defun gortium/inject-project-agenda ()
|
||||
"Inject the current project's custom agenda commands into
|
||||
`org-agenda-custom-commands', or remove them if no project."
|
||||
(let* ((proj-root (and (projectile-project-p) (projectile-project-root)))
|
||||
(project-commands nil))
|
||||
(when proj-root
|
||||
(let ((default-directory proj-root))
|
||||
(setq project-commands
|
||||
(gortium/read-dir-local 'gortium/project-agenda-entry))))
|
||||
;; Remove stale project entries (key "P")
|
||||
(setq org-agenda-custom-commands
|
||||
(seq-filter (lambda (entry)
|
||||
(not (and (stringp (car entry))
|
||||
(string= "P" (car entry)))))
|
||||
org-agenda-custom-commands))
|
||||
;; Add current project commands
|
||||
(when project-commands
|
||||
(setq org-agenda-custom-commands
|
||||
(append org-agenda-custom-commands project-commands)))))
|
||||
|
||||
;; Hook into project switching
|
||||
(add-hook 'projectile-after-switch-project-hook
|
||||
#'gortium/inject-project-agenda)
|
||||
;; Also inject at startup and on file open in a project
|
||||
(add-hook 'find-file-hook #'gortium/inject-project-agenda)
|
||||
|
||||
170
doom/.config/doom/gortium-bookmarks.el
Normal file
170
doom/.config/doom/gortium-bookmarks.el
Normal file
@@ -0,0 +1,170 @@
|
||||
;;; 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)
|
||||
Reference in New Issue
Block a user