doom-config/config.el

750 lines
29 KiB
EmacsLisp

;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
;; Load extra configuration of Nix-computed paths deifned in programs.emacs.extraConfig
;; (load "default")
;; Place your private configuration here! Remember, you do not need to run 'doom
;; sync' after modifying this file!
;; Some functionality uses this to identify you, e.g. GPG configuration, email
;; clients, file templates and snippets.
(setq user-full-name "Max Schlueter"
user-mail-address "me@maxschlueter.com")
;; Doom exposes five (optional) variables for controlling fonts in Doom. Here
;; are the three important ones:
;;
;; + `doom-font'
;; + `doom-variable-pitch-font'
;; + `doom-big-font' -- used for `doom-big-font-mode'; use this for
;; presentations or streaming.
;;
;; They all accept either a font-spec, font string ("Input Mono-12"), or xlfd
;; font string. You generally only need these two:
(setq doom-font (font-spec :family "Fira Mono" :size 14.0))
;; There are two ways to load a theme. Both assume the theme is installed and
;; available. You can either set `doom-theme' or manually load a theme with the
;; `load-theme' function. This is the default:
(setq doom-theme 'doom-solarized-light)
;; TODO: Restore session at startup
;; (add-hook 'window-setup-hook #'doom-load-session 'append)
;; If you use `org' and don't want your org files in the default location below,
;; change `org-directory'. It must be set before org loads!
;; https://github.com/hlissner/doom-emacs/issues/4832
;; (after! org
;; (defun +org--restart-mode-h ()
;; "Restart `org-mode', but only once."
;; (quiet! (org-mode-restart))
;; (delq! (current-buffer) org-agenda-new-buffers)
;; (remove-hook 'doom-switch-buffer-hook #'+org--restart-mode-h
;; 'local)))
(setq org-directory "~/Nextcloud/org/")
(after! org
(setq org-return-follows-link t
org-agenda-files `(,(expand-file-name "gtd/inbox.org" org-directory)
,(expand-file-name "gtd/projects.org" org-directory)))
(setq org-capture-templates
`(("i" "Inbox" entry (file ,(expand-file-name "gtd/inbox.org" org-directory))
"* TODO %?\nEntered on %U\n" :prepend t)
("x" "Org Protocol" entry (file ,(expand-file-name "gtd/inbox.org" org-directory))
"* TODO %:annotation\nEntered on %U\n" :prepend t :immediate-finish t)))
(setq org-log-done 'time
org-log-into-drawer t)
(setq org-tag-alist '(("@errand" . ?e)
("@office" . ?o)
("@home" . ?h)))
(setq org-refile-allow-creating-parent-nodes 'confirm
org-refile-targets `(("projects.org" . (:level . 1))
(,(expand-file-name "gtd/someday.org" org-directory) . (:level . 0))))
;; https://christiantietze.de/posts/2019/03/sync-emacs-org-files/
(add-hook 'auto-save-hook #'org-save-all-org-buffers)
(add-hook 'kill-emacs-hook #'org-save-all-org-buffers)
(advice-add #'org-save-all-org-buffers :around #'doom-shut-up-a)
(add-to-list 'org-modules 'org-habit t)
(setq org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "HOLD(h)" "WAIT(w)" "|" "DONE(d)" "KILL(k)"))))
(after! org-clock
(setq org-clock-persist t
org-clock-persist-query-resume nil
;; org-clock-out-remove-zero-time-clocks t
org-clock-in-switch-to-state "NEXT"))
;;; Autoload this function for the org-pomodoro polybar module
(autoload #'org-pomodoro-active-p "org-pomodoro" nil t)
(after! org-pomodoro
(defvar +org-pomodoro-length-file "/tmp/org-pomodoro-length"
"Location of the lock file which stores the PID of the process currenty running mu4e")
(defun +org-pomodoro/set-length ()
"Sets the length of pomodoros and breaks. The lengths are stored in a file
so that they may persist between sessions."
(interactive)
(let ((pomodoro-length (read-number "org-pomodoro-length: " org-pomodoro-length))
(pomodoro-short-break-length (read-number "org-pomodoro-short-break-length: " org-pomodoro-short-break-length))
(pomodoro-long-break-length (read-number "org-pomodoro-long-break-length: " org-pomodoro-long-break-length)))
(write-region (format "%d\n%d\n%d\n" pomodoro-length pomodoro-short-break-length pomodoro-long-break-length)
nil
+org-pomodoro-length-file)
(+org-pomodoro/update-length)))
(defun +org-pomodoro/update-length ()
"Update the length of pomodoros and breaks from `+org-pomodoro-length-file'.
If the file does not exist, just return nil."
(when (file-exists-p +org-pomodoro-length-file)
(let ((lengths (mapcar 'string-to-number
(split-string (with-temp-buffer
(setq coding-system-for-read 'utf-8)
(insert-file-contents +org-pomodoro-length-file)
(buffer-string)) "\n" t))))
(setq org-pomodoro-length (nth 0 lengths)
org-pomodoro-short-break-length (nth 1 lengths)
org-pomodoro-long-break-length (nth 2 lengths)))))
(+org-pomodoro/update-length)
(defun +org-pomodoro/restart-last-pomodoro ()
"Starts a new pomodoro on the last clocked-in task. Resets the pomodoro count without prompt when necessary.
This is useful for external scripts as the org-pomodoro function has y-or-n prompts"
(when (and org-pomodoro-last-clock-in
org-pomodoro-expiry-time
(org-pomodoro-expires-p))
(setq org-pomodoro-count 0))
(setq org-pomodoro-last-clock-in (current-time))
(call-interactively 'org-clock-in-last)
(org-pomodoro-start :pomodoro))
(defun +org-pomodoro/start-pomodoro-on-capture ()
"Starts org-pomodoro upon capture if the pomodoro capture template was used"
(when (and (not org-note-abort)
(equal (org-capture-get :pomodoro) t))
(when (and org-pomodoro-last-clock-in
org-pomodoro-expiry-time
(org-pomodoro-expires-p))
(setq org-pomodoro-count 0))
(set-buffer (org-capture-get :buffer))
(goto-char (org-capture-get :insertion-point))
(org-clock-in)
(org-pomodoro-start :pomodoro)))
(add-hook 'org-capture-after-finalize-hook #'+org-pomodoro/start-pomodoro-on-capture))
(defun max/org-gtd--incubate ()
"Process GTD inbox item by incubating it.
Allow the user apply user-defined tags from
`org-tag-persistent-alist', `org-tag-alist' or file-local tags in
the inbox. Refile to any org-gtd incubate target (see manual)."
(interactive)
(org-gtd--decorate-item)
(org-gtd--refile org-gtd-incubated)
(org-gtd-process-inbox))
(use-package! org-gtd
:after org
:config
(org-edna-mode)
(setq org-gtd-directory (concat org-directory "newgtd/")
org-edna-use-inheritance t
org-gtd-refile-to-any-target t )
(advice-add #'org-gtd--incubate :override #'max/org-gtd--incubate)
(map! :leader
(:prefix ("d" . "org-gtd")
:desc "Capture" "c" #'org-gtd-capture
:desc "Engage" "e" #'org-gtd-engage
:desc "Process inbox" "p" #'org-gtd-process-inbox
:desc "Show all next" "n" #'org-gtd-show-all-next
:desc "Stuck projects" "s" #'org-gtd-show-stuck-projects))
(map! :map org-gtd-process-map
:desc "Choose" "C-c c" #'org-gtd-choose))
(defun max/org-agenda-bulk-mark-inbox-items ()
"Bulk mark all inbox items in the org-agenda."
(let ((entries-marked 0))
(save-excursion
(goto-char (point-min))
(while (not (eobp))
(if (and (org-get-at-bol 'org-hd-marker)
(string= "inbox" (funcall 'org-agenda-get-category)))
(progn
(setq entries-marked (1+ entries-marked))
(call-interactively 'org-agenda-bulk-mark))
(beginning-of-line 2))))
(unless entries-marked
(message "No inbox items found."))))
(defun max/org-agenda-process-inbox-item ()
"Process a single item in the org-agenda."
(interactive)
(org-with-wide-buffer
(org-agenda-set-tags)
(org-agenda-priority)
(org-agenda-set-effort)
(org-agenda-refile nil nil t)))
(defun max/org-agenda-bulk-process-entries ()
"Bulk process all marked entries in the org-agenda using `max/org-agenda-process-inbox-item'."
(if (not (null org-agenda-bulk-marked-entries))
(let ((entries (reverse org-agenda-bulk-marked-entries))
(processed 0)
(skipped 0))
(dolist (e entries)
(let ((pos (text-property-any (point-min) (point-max) 'org-hd-marker e)))
(if (not pos)
(progn (message "Skipping removed entry at %s" e)
(cl-incf skipped))
(goto-char pos)
(let (org-loop-over-headlines-in-active-region) (funcall 'max/org-agenda-process-inbox-item))
;; `post-command-hook' is not run yet. We make sure any
;; pending log note is processed.
(when org-log-setup (org-add-log-note))
;; (when (or (memq 'org-add-log-note (default-value 'post-command-hook))
;; (memq 'org-add-log-note post-command-hook))
;; (org-add-log-note))
(cl-incf processed))))
(org-agenda-redo)
(unless org-agenda-persistent-marks (org-agenda-bulk-unmark-all))
(message "Acted on %d entries%s%s"
processed
(if (= skipped 0)
""
(format ", skipped %d (disappeared before their turn)"
skipped))
(if (not org-agenda-persistent-marks) "" " (kept marked)")))))
(defun max/org-agenda-process-inbox ()
"Processes all inbox items in the org-agenda."
(interactive)
(max/org-agenda-bulk-mark-inbox-items)
(max/org-agenda-bulk-process-entries))
(map! :after evil-org-agenda
:map evil-org-agenda-mode-map
:m "P" #'max/org-agenda-process-inbox)
(after! org-agenda
(setq org-agenda-window-setup 'current-window
org-agenda-restore-windows-after-quit t
org-agenda-block-separator nil
org-agenda-compact-blocks t
org-agenda-start-with-log-mode t)
(defun max/switch-to-agenda ()
(interactive)
(org-agenda nil " "))
(map! :map 'override
"<f1>" #'max/switch-to-agenda)
(defun max/skip-habits ()
"Skip trees that are habits."
(save-restriction
(widen)
(let ((next-headline (save-excursion (or (outline-next-heading) (point-max)))))
(cond
((org-is-habit-p)
next-headline)
(t
nil)))))
;; (setq org-columns-default-format "%40ITEM(Task) %Effort(EE){:} %CLOCKSUM(Time Spent) %SCHEDULED(Scheduled) %DEADLINE(Deadline)")
(setq org-agenda-custom-commands `((" " "Agenda"
((alltodo ""
((org-agenda-overriding-header "Inbox")
(org-agenda-files '(,(expand-file-name "gtd/inbox.org" org-directory)))))
(agenda ""
((org-agenda-span 'week)
(org-deadline-warning-days 365)))
(todo "NEXT"
((org-agenda-overriding-header "In Progress")
(org-agenda-files '(,(expand-file-name "gtd/projects.org" org-directory)))))
(todo "TODO"
((org-agenda-overriding-header "Active Projects")
(org-agenda-files '(,(expand-file-name "gtd/projects.org" org-directory)))
(org-agenda-skip-function #'max/skip-habits)))))
("W" "Weekly Review"
((agenda ""
((org-agenda-span 'week)
(org-agenda-start-day "-6d")))
(todo "NEXT"
((org-agenda-overriding-header "In Progress")
(org-agenda-files '(,(expand-file-name "gtd/projects.org" org-directory)))))
(todo "TODO"
((org-agenda-overriding-header "Active Projects")
(org-agenda-files '(,(expand-file-name "gtd/projects.org" org-directory)))
(org-agenda-skip-function #'max/skip-habits))))))))
;; org-agenda-custom-commands
;; '((" " "Agenda"
;; ((agenda ""
;; (
;; (org-agenda-start-day nil)
;; (org-agenda-span 'day)
;; (org-deadline-warning-days 365)))
;; (alltodo ""
;; ((org-agenda-overriding-header "")
;; (org-super-agenda-groups
;; '((:name "To Refile"
;; :category "inbox")
;; (:name "Emails"
;; :category "emails")
;; (:name "In Progress"
;; :todo "NEXT")
;; (:name "Projects"
;; :file-path "projects.org$")
;; (:name "One-off Tasks"
;; :category "next"))
;; ))))))))
(use-package! org-inline-pdf
:hook (org-mode . org-inline-pdf-mode))
(use-package! indium
:hook ((js-mode typescript-mode) . indium-interaction-mode)
:init
(setq indium-chrome-data-dir (concat doom-cache-dir "indium-chrome-profile"))
:config
(map! :localleader
:map indium-interaction-mode-map
"I" #'indium-launch)
)
(use-package! org-clock-convenience
:after org-agenda
:config
;; Fix for macos: https://github.com/dfeich/org-clock-convenience/issues/9#issuecomment-646842338
(when IS-MAC (load "org-clock-convenience"))
(map! :after org-agenda
:map org-agenda-mode-map
"<S-up>" #'org-clock-convenience-timestamp-up
"<S-down>" #'org-clock-convenience-timestamp-down
"o" #'org-clock-convenience-fill-gap
"e" #'org-clock-convenience-fill-gap-both))
(after! info
(map! :map Info-mode-map
:n "g n" #'Info-goto-node))
(setq max/org-calendar-directory (concat org-directory "calendar/"))
(setq max/org-calendar-file (concat max/org-calendar-directory "calendar.org"))
;;; https://www.reddit.com/r/orgmode/comments/8rl8ep/making_orgcaldav_useable/
(use-package! org-caldav
:after org
:init
;; (defun org-caldav-sync-at-close ()
;; (org-caldav-sync)
;; (save-some-buffers))
;; (defvar org-caldav-sync-timer nil
;; "Timer that `org-caldav-push-timer' used to reschedule itself, or nil.")
;; (defun org-caldav-sync-with-delay (secs)
;; (when org-caldav-sync-timer
;; (cancel-timer org-caldav-sync-timer))
;; (setq org-caldav-sync-timer
;; (run-with-idle-timer
;; (* 1 secs) nil 'org-caldav-sync)))
(setq org-icalendar-alarm-time 1)
:config
(setq org-caldav-resume-aborted 'always
org-caldav-save-directory max/org-calendar-directory
org-caldav-backup-file (concat max/org-calendar-directory "org-caldav-backup.org")
org-caldav-url "https://nextcloud.maxschlueter.com/remote.php/dav/calendars/max"
org-caldav-calendar-id "calendar"
org-caldav-files `(,max/org-calendar-file)
org-caldav-inbox max/org-calendar-file)
(after! org-agenda
(add-to-list 'org-agenda-files max/org-calendar-file t)
(setq org-agenda-include-diary t
org-agenda-insert-diary-strategy 'top-level
org-agenda-insert-diary-extract-time t
org-agenda-diary-file max/org-calendar-file))
;; (setq org-caldav-calendars
;; `((:calendar-id "personal"
;; :files (,(concat max/org-calendar-directory "personal.org"))
;; :inbox ,(concat max/org-calendar-directory "personal.org"))
;; (:calendar-id "work"
;; :files (,(concat max/org-calendar-directory "work.org"))
;; :inbox ,(concat max/org-calendar-directory "work.org"))
;; ))
(defun max/org-caldav-get-inbox ()
(let* ((calid (completing-read "Calendar: "
(cl-loop for cal in org-caldav-calendars
collect (plist-get cal :calendar-id))
nil t))
(calinbox (cl-loop for cal in org-caldav-calendars
when (string= (plist-get cal :calendar-id) calid)
return (plist-get cal :inbox))))
calinbox))
;; (add-hook 'after-save-hook
;; (lambda ()
;; (when (eq major-mode 'org-mode)
;; (org-caldav-sync-with-delay 300))))
;; (add-hook 'kill-emacs-hook 'org-caldav-sync-at-close)
)
(setq +org-roam-open-buffer-on-find-file nil)
(after! org-roam
(setq org-roam-dailies-capture-templates
'(("d" "default" entry
"* %?"
:target (file+head "%<%Y-%m-%d>.org"
"#+title: %<%Y-%m-%d>\n"))))
;; ("j" "journal" entry
;; #'org-roam-capture--get-point
;; "* %?"
;; :file-name "daily/%<%Y-%m-%d>"
;; :head "#+title: %<%Y-%m-%d>\n"
;; :olp ("Journal"))))
(map! :leader
:desc "Capture today" "n n" #'org-roam-dailies-capture-today)
(setq org-roam-directory (concat org-directory "roam/")
org-roam-completion-everywhere nil))
(after! org-noter
;; (map! :map pdf-view-mode-map "i" nil)
;; (map! :map pdf-view-mode-map :gn "i" #'org-noter-insert-note)
(setq org-noter-always-create-frame t))
(after! biblio
(map! :map biblio-selection-mode-map
"C-j" #'biblio--selection-next
"C-k" #'biblio--selection-previous)
(setq biblio-crossref-user-email-address user-mail-address))
(after! bibtex-completion
;; (require 'ivy-bibtex)
;; (setq! bibtex-completion-library-path '("~/Nextcloud/Papers/")
;; bibtex-completion-notes-path org-roam-directory
;; bibtex-completion-bibliography '("~/Nextcloud/Papers/library.bib"))
;; TODO: make it a citar action
(defun max/bibtex-completion-org-capture (keys)
(let ((titles (bibtex-completion-format-citation-org-title-link-to-PDF keys)))
(with-current-buffer (find-file-noselect (expand-file-name "gtd/inbox.org" org-directory))
(save-excursion
(goto-char (point-max))
(insert (concat "* TODO Read: " titles
"\n"))))))
(ivy-bibtex-ivify-action max/bibtex-completion-org-capture max/ivy-bibtex-org-capture)
(ivy-add-actions
'ivy-bibtex
'(("x" max/ivy-bibtex-org-capture "Capture PDF to read"))))
(after! citar
(setq! citar-library-paths '("~/Nextcloud/Papers/")
citar-notes-paths `(,org-roam-directory)
citar-bibliography '("~/Nextcloud/Papers/library.bib")))
(use-package citar-org-roam
:after citar org-roam
:no-require
:config (citar-org-roam-mode))
;; Taken from: https://github.com/hlissner/doom-emacs/pull/6077
;; (use-package! org-roam-bibtex
;; ;; :when (featurep! :lang org +roam2)
;; :after org-roam
;; :preface
;; ;; if the user has not set a template mechanism set a reasonable one of them
;; ;; The package already tests for nil itself so we define a dummy tester
;; (defvar orb-preformat-keywords
;; '("title" "url" "file" "author-or-editor" "keywords" "citekey" "pdf"))
;; :hook (org-roam-mode . org-roam-bibtex-mode)
;; :custom
;; (orb-note-actions-interface (cond ((featurep! :completion ivy) 'ivy)
;; ((featurep! :completion helm) 'helm)
;; ((t 'default))))
;; :config
;; (setq orb-insert-interface (cond ((featurep! :completion ivy) 'ivy-bibtex)
;; ((featurep! :completion helm) 'helm-bibtex)
;; ((t 'generic))))
;; (setq orb-process-file-keyword t
;; orb-file-field-extensions '("pdf"))
;; (add-to-list 'org-roam-capture-templates
;; '("b" "Bibliography note" plain
;; "%?
;; - keywords :: %^{keywords}
;; - related ::
;; * %^{title}
;; :PROPERTIES:
;; :Custom_ID: %^{citekey}
;; :URL: %^{url}
;; :AUTHOR: %^{author-or-editor}
;; :NOTER_DOCUMENT: %^{file}
;; :NOTER_PAGE:
;; :END:\n\n"
;; :if-new (file+head "${citekey}.org" ":PROPERTIES:
;; :ROAM_REFS: cite:${citekey}
;; :END:
;; #+TITLE: ${title}\n")
;; :unnarrowed t)))
(after! projectile
(setq projectile-project-search-path '(("~/Projects" . 1))))
;; (setq ns-auto-hide-menu-bar t)
;(defun switch-to-agenda ()
(defun max/org-clock-get-clock-string ()
"Form a clock string that will be shown in polybar."
(require 'org-clock)
(when (org-clocking-p)
(let ((clocked-time (org-clock-get-clocked-time)))
(if org-clock-effort
(let* ((effort-in-minutes (org-duration-to-minutes org-clock-effort))
(work-done-str (org-duration-from-minutes clocked-time))
(effort-str (org-duration-from-minutes effort-in-minutes)))
(format "%s/%s %s"
work-done-str effort-str org-clock-heading))
(format "%s %s"
(org-duration-from-minutes clocked-time)
org-clock-heading)))))
;; (when (org-clocking-p)
;; (org-no-properties (org-clock-get-clock-string))))
;; (when (org-clocking-p)
;; (let* ((clocked-time (org-clock-get-clocked-time))
;; (work-done-str (org-duration-from-minutes clocked-time)))
;; (make-symbol work-done-str))))
;; (defun my/toggle-org-agenda ()
;; "Toggle my custom org agenda view"
;; (interactive)
;; (if (get-buffer-window org-agenda-buffer-name)
;; (org-agenda-quit)
;; (org-agenda nil " ")))
(after! auth-source
(when IS-MAC
(setq auth-sources '(macos-keychain-internet macos-keychain-generic))))
;; (setq mac-right-option-modifier nil)
;; (set-irc-server! "chat.freenode.net"
;; `(:tls t
;; :port 6697
;; :nick "maxsc"
;; :sasl-username ,(+pass-get-user "irc/freenode.net")
;; :sasl-password (lambda (&rest _) (+pass-get-secret "irc/freenode.net"))
;; :channels ("#home-manager")))
;; (map! "<f4>" #'=irc)
;;; https://github.com/alphapapa/org-ql/issues/67
;(after! (org-super-agenda evil-org-agenda)
; (setq org-super-agenda-header-map (copy-keymap evil-org-agenda-mode-map)))
;;; (after! woman
;;; (set-popup-rule! "^\\*WoMan" :side 'left :size 30 :ttl 0)
;;; )
;;; (after! org (set-popup-rule! "^CAPTURE-.*\\.org$" :side 'right :size .50 :select t :vslot 2 :ttl 3))
;;; (after! org-roam
;;; (advice-add #'display-buffer-pop-up-frame :before #'org-roam-protocol-open-ref))
;;; Autoload this command so that the mbsync service can update the index
(autoload #'mu4e-update-index "mu4e" nil t)
(defun max/=mu4e ()
"Start email client and view all inboxes."
(interactive)
(require 'mu4e)
(+workspace-switch +mu4e-workspace-name t)
(mu4e~start (lambda () (mu4e-headers-search (mu4e-get-bookmark-query ?i)))))
(map! "<f2>" #'max/=mu4e)
(after! yasnippet
(setq yas-triggers-in-field t))
;; http://pragmaticemacs.com/emacs/email-templates-in-mu4e-with-yasnippet/
(defun bjm/mu4e-get-names-for-yasnippet ()
"Return comma separated string of names for an email"
(interactive)
(let ((email-name "") str email-string email-list email-name2 tmpname)
(save-excursion
(goto-char (point-min))
;; first line in email could be some hidden line containing NO to field
(setq str (buffer-substring-no-properties (point-min) (point-max))))
;; take name from TO field - match series of names
(when (string-match "^To: \"?\\(.+\\)" str)
(setq email-string (match-string 1 str)))
;;split to list by comma
(setq email-list (split-string email-string " *, *"))
;;loop over emails
(dolist (tmpstr email-list)
;;get first word of email string
(setq tmpname (car (split-string tmpstr " ")))
;;remove whitespace or ""
(setq tmpname (replace-regexp-in-string "[ \"]" "" tmpname))
;;join to string
(setq email-name
(concat email-name ", " tmpname)))
;;remove initial comma
(setq email-name (replace-regexp-in-string "^, " "" email-name))
;;see if we want to use the name in the FROM field
;;get name in FROM field if available, but only if there is only
;;one name in TO field
(if (< (length email-list) 2)
(when (string-match "^\\([^ ,\n]+\\).+writes:$" str)
(progn (setq email-name2 (match-string 1 str))
;;prefer name in FROM field if TO field has "@"
(when (string-match "@" email-name)
(setq email-name email-name2))
)))
email-name))
(setq +org-capture-emails-file (expand-file-name "gtd/projects.org" org-directory))
(after! mu4e
(setq mu4e-maildir "~/Maildir")
;; Recommended msmtp config from doom module documentation
(setq sendmail-program (executable-find "msmtp")
send-mail-function #'smtpmail-send-it
message-sendmail-f-is-evil t
message-sendmail-extra-arguments '("--read-envelope-from")
message-send-mail-function #'message-send-mail-with-sendmail)
;; fix https://github.com/hlissner/doom-emacs/issues/3294
(setq mu4e-attachment-dir "~/Downloads")
(defun max/mu4e-view-import-attachment-calendar (msg attnum)
(let* ((att (mu4e~view-get-attach msg attnum))
(index (plist-get att :index))
(docid (mu4e-message-field msg :docid))
(mtype (plist-get att :mime-type))
(fname (plist-get att :name))
(fpath (concat (mu4e~get-attachment-dir fname mtype) "/" fname)))
(if (string= "text/calendar" mtype)
(progn (mu4e~proc-extract 'save docid index mu4e-decryption-policy fpath)
(let ((org-caldav-inbox (max/org-caldav-get-inbox)))
(org-caldav-import-ics-to-org fpath)))
(mu4e-error "Invalid mime-type for a calendar event: `%s'" mtype))))
(add-to-list 'mu4e-view-attachment-actions
'("cImport in calendar" . max/mu4e-view-import-attachment-calendar) t)
(after! mu4e-alert
(when IS-MAC
(mu4e-alert-set-default-style 'notifier)))
(add-to-list 'mu4e-bookmarks
(make-mu4e-bookmark
:name "All Inboxes"
:query "maildir:/mailbox.org/Inbox OR maildir:/uni-potsdam.de/Inbox"
:key ?i))
)
(set-email-account! "mailbox.org"
'((mu4e-sent-folder . "/mailbox.org/Sent")
(mu4e-drafts-folder . "/mailbox.org/Drafts")
(mu4e-trash-folder . "/mailbox.org/Trash")
(mu4e-refile-folder . "/mailbox.org/Archive")
(smtpmail-smtp-user . "me@maxschlueter.com")
(mu4e-maildir-shortcuts
(:maildir "/mailbox.org/Inbox" :key ?i)
(:maildir "/mailbox.org/Sent" :key ?s)
(:maildir "/mailbox.org/Drafts" :key ?d)
(:maildir "/mailbox.org/Trash" :key ?t)
(:maildir "/mailbox.org/Archive" :key ?a))
(mu4e-compose-signature . nil))
t)
(set-email-account! "uni-potsdam.de"
'((mu4e-sent-folder . "/uni-potsdam.de/Sent")
(mu4e-drafts-folder . "/uni-potsdam.de/Drafts")
(mu4e-trash-folder . "/uni-potsdam.de/Trash")
(mu4e-refile-folder . "/uni-potsdam.de/Archive")
(smtpmail-smtp-user . "mschlueter@uni-potsdam.de")
(mu4e-maildir-shortcuts
(:maildir "/uni-potsdam.de/Inbox" :key ?i)
(:maildir "/uni-potsdam.de/Sent" :key ?s)
(:maildir "/uni-potsdam.de/Drafts" :key ?d)
(:maildir "/uni-potsdam.de/Trash" :key ?t)
(:maildir "/uni-potsdam.de/Archive" :key ?a))
(mu4e-compose-signature . nil)))
(setq +latex-viewers '(pdf-tools))
(setq org-roam-directory (concat org-directory "roam/"))
;; (setq! +biblio-pdf-library-dir "~/Nextcloud/Papers/"
;; +biblio-default-bibliography-files '("~/Nextcloud/Papers/library.bib")
;; +biblio-notes-path org-roam-directory)
(after! org-roam-bibtex
(setq orb-insert-link-description 'citekey))
;; https://tecosaur.github.io/emacs-config/config.html#getting-notified
;; http://cachestocaches.com/2017/3/complete-guide-email-emacs-using-mu-and-/
;; (use-package! mu4e-alert
;; :after mu4e
;; :init
;; (setq mu4e-alert-interesting-mail-query
;; (concat
;; "flag:unread maildir:/mailbox.org/Inbox"
;; " OR "
;; "flag:unread maildir:/uni-potsdam.de/Inbox"
;; ))
;; (setq doom-modeline-mu4e t)
;; :config
;; (mu4e-alert-enable-mode-line-display)
;; (mu4e-alert-set-default-style 'libnotify)
;; (mu4e-alert-enable-notifications))
;;
;;
(after! forge
(setq forge-owned-accounts '(("MaxSchlueter"))))
(setq +workspaces-on-switch-project-behavior t)
(after! evil-snipe
(setq evil-snipe-spillover-scope 'visible))
(map! "<f12>" #'redraw-display)
(after! restart-emacs
(defun max/restart-emacs--get-emacs-binary ()
(let ((invocation-directory (file-truename "~/.nix-profile/Applications/Emacs.app/Contents/MacOS")))
(expand-file-name invocation-name invocation-directory)))
(advice-add #'restart-emacs--get-emacs-binary :override #'max/restart-emacs--get-emacs-binary))
;; (server-start)
;; (use-package! mac-pseudo-daemon
;; :config
;; (mac-pseudo-daemon-mode)
;; )
;; (load! nix-docbook-mode)
;;; (after! calfw-org
;;; (autoload (function cfw:org-create-file-source) "cfw:org-create-file-source" nil t))
;;; (after! calfw-org
;;; (autoload #'cfw:org-create-file-source "cfw:org-create-file-source"))