commit a8abb8dab6d3eda3f0efd49a91b8d9e6e5abf8ba Author: Max Schlueter Date: Fri Aug 19 23:17:05 2022 +0200 Initial commit diff --git a/config.el b/config.el new file mode 100644 index 0000000..caec038 --- /dev/null +++ b/config.el @@ -0,0 +1,721 @@ +;;; $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-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 + "" #'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 + "" #'org-clock-convenience-timestamp-up + "" #'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! "" #'=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! "" #'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! "" #'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")) + diff --git a/init.el b/init.el new file mode 100644 index 0000000..2e5a0cf --- /dev/null +++ b/init.el @@ -0,0 +1,190 @@ +;;; init.el -*- lexical-binding: t; -*- + +;; This file controls what Doom modules are enabled and what order they load in. +;; Remember to run 'doom sync' after modifying it! + +;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's +;; documentation. There you'll find information about all of Doom's modules +;; and what flags they support. + +;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or +;; 'C-c g k' for non-vim users) to view its documentation. This works on +;; flags as well (those symbols that start with a plus). +;; +;; Alternatively, press 'gd' (or 'C-c g d') on a module to browse its +;; directory (for easy access to its source code). + +(doom! :input + ;;chinese + ;;japanese + ;;layout ; auie,ctsrnm is the superior home row + + :completion + company ; the ultimate code completion backend + ;;helm ; the *other* search engine for love and life + ;;ido ; the other *other* search engine... + ;; (ivy +fuzzy) ; a search engine for love and life + (vertico +icons) ; the search engine of the future + + :ui + ;;deft ; notational velocity for Emacs + doom ; what makes DOOM look the way it does + doom-dashboard ; a nifty splash screen for Emacs + ;; doom-quit ; DOOM quit-message prompts when you quit Emacs + ;;(emoji +unicode) ; 🙂 + hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW + ;;hydra + ;;indent-guides ; highlighted indent columns + ;;ligatures ; ligatures and symbols to make your code pretty again + ;;minimap ; show a map of the code on the side + modeline ; snazzy, Atom-inspired modeline, plus API + ;; nav-flash ; blink the current line after jumping + ;;neotree ; a project drawer, like NERDTree for vim + ophints ; highlight the region an operation acts on + (popup +defaults +all) ; tame sudden yet inevitable temporary windows + ;;tabs ; an tab bar for Emacs + ;;treemacs ; a project drawer, like neotree but cooler + ;;unicode ; extended unicode support for various languages + vc-gutter ; vcs diff in the fringe + vi-tilde-fringe ; fringe tildes to mark beyond EOB + window-select ; visually switch windows + workspaces ; tab emulation, persistence & separate workspaces + zen ; distraction-free coding or writing + + :editor + (evil +everywhere); come to the dark side, we have cookies + file-templates ; auto-snippets for empty files + fold ; (nigh) universal code folding + ;;(format +onsave) ; automated prettiness + ;;god ; run Emacs commands without modifier keys + ;;lispy ; vim for lisp, for people who don't like vim + multiple-cursors ; editing in many places at once + ;;objed ; text object editing for the innocent + ;;parinfer ; turn lisp into python, sort of + ;;rotate-text ; cycle region at point between text candidates + snippets ; my elves. They type so I don't have to + word-wrap ; soft wrapping with language-aware indent + + :emacs + dired ; making dired pretty [functional] + electric ; smarter, keyword-based electric-indent + ;;ibuffer ; interactive buffer management + undo ; persistent, smarter undo for your inevitable mistakes + vc ; version-control and Emacs, sitting in a tree + + :term + ;;eshell ; a consistent, cross-platform shell (WIP) + ;; shell ; a terminal REPL for Emacs + ;;term ; terminals in Emacs + vterm ; another terminals in Emacs + + :checkers + syntax ; tasing you for every semicolon you forget + (spell +flyspell) ; tasing you for misspelling mispelling + ;;grammar ; tasing grammar mistake every you make + + :tools + ;;ansible + biblio ; Writes a PhD for you (citation needed) + ;;debugger ; FIXME stepping through code, to help you add bugs + direnv + ;;docker + ;;editorconfig ; let someone else argue about tabs vs spaces + ;;ein ; tame Jupyter notebooks with emacs + (eval +overlay) ; run code, run (also, repls) + ;;gist ; interacting with github gists + lookup ; navigate your code and its documentation + ;;lsp ; M-x vscode + (magit +forge) ; a git porcelain for Emacs + ;;make ; run make tasks from Emacs + pass ; password manager for nerds + pdf ; pdf enhancements + ;;prodigy ; FIXME managing external services & code builders + ;;rgb ; creating color strings + ;;taskrunner ; taskrunner for all your projects + ;;terraform ; infrastructure as code + ;;tmux ; an API for interacting with tmux + ;;upload ; map local to remote projects via ssh/ftp + + :os + (:if IS-MAC macos) ; improve compatibility with macOS + ;;tty ; improve the terminal Emacs experience + + :lang + ;;agda ; types of types of types of types... + ;;beancount ; mind the GAAP + ;;assembly ; assembly for fun or debugging + ;;cc ; C/C++/Obj-C madness + ;;clojure ; java with a lisp + ;;common-lisp ; if you've seen one lisp, you've seen them all + ;;coq ; proofs-as-programs + ;;crystal ; ruby at the speed of c + ;;csharp ; unity, .NET, and mono shenanigans + data ; config/data formats + ;;(dart +flutter) ; paint ui and not much else + ;;dhall + ;;elixir ; erlang done right + ;;elm ; care for a cup of TEA? + emacs-lisp ; drown in parentheses + ;;erlang ; an elegant language for a more civilized age + ;;ess ; emacs speaks statistics + ;;faust ; dsp, but you get to keep your soul + ;;fsharp ; ML stands for Microsoft's Language + ;;fstar ; (dependent) types and (monadic) effects and Z3 + ;;gdscript ; the language you waited for + ;;(go +lsp) ; the hipster dialect + ;;(haskell +lsp) ; a language that's lazier than I am + ;;hy ; readability of scheme w/ speed of python + ;;idris ; + ;;json ; At least it ain't XML + (java +meghanada) ; the poster child for carpal tunnel syndrome + (javascript +lsp) ; all(hope(abandon(ye(who(enter(here)))))) + ;;julia ; a better, faster MATLAB + ;;kotlin ; a better, slicker Java(Script) + (latex +latexmk) ; writing papers in Emacs has never been so fun + ;;lean + ;;ledger ; be audit you can be + ;;lua ; one-based indices? one-based indices + markdown ; writing docs for people to ignore + ;;nim ; python + lisp at the speed of c + nix ; I hereby declare "nix geht mehr!" + ;;ocaml ; an objective camel + (org +noter +roam2 +dragndrop +pomodoro) ; organize your plain life in plain text + ;;php ; perl's insecure younger brother + ;;plantuml ; diagrams for confusing people more + ;;purescript ; javascript, but functional + ;;python ; beautiful is better than ugly + ;;qt ; the 'cutest' gui framework ever + ;;racket ; a DSL for DSLs + ;;raku ; the artist formerly known as perl6 + ;;rest ; Emacs as a REST client + ;;rst ; ReST in peace + ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} + ;;rust ; Fe2O3.unwrap().unwrap().unwrap().unwrap() + ;; (scala +lsp) ; java, but good + ;;(scheme +guile) ; a fully conniving family of lisps + sh ; she sells {ba,z,fi}sh shells on the C xor + ;;sml + ;;solidity ; do you need a blockchain? No. + ;;swift ; who asked for emoji variables? + ;;terra ; Earth and Moon in alignment for performance. + ;;web ; the tubes + ;;yaml ; JSON, but readable + ;;zig ; C, but simpler + + :email + mu4e + ;; notmuch + ;;(wanderlust +gmail) + + :app + calendar + ;;emms + everywhere ; *leave* Emacs!? You must be joking + irc ; how neckbeards socialize + ;;(rss +org) ; emacs as an RSS reader + ;;twitter ; twitter client https://twitter.com/vnought + + :config + ;;literate + (default +bindings +smartparens)) diff --git a/packages.el b/packages.el new file mode 100644 index 0000000..e3499e5 --- /dev/null +++ b/packages.el @@ -0,0 +1,71 @@ +;; -*- no-byte-compile: t; -*- +;;; $DOOMDIR/packages.el + +;; To install a package with Doom you must declare them here, run 'doom sync' on +;; the command line, then restart Emacs for the changes to take effect. +;; Alternatively, use M-x doom/reload. +;; +;; WARNING: Disabling core packages listed in ~/.emacs.d/core/packages.el may +;; have nasty side-effects and is not recommended. + + +;; All of Doom's packages are pinned to a specific commit, and updated from +;; release to release. To un-pin all packages and live on the edge, do: +;(unpin! t) + +;; ...but to unpin a single package: +;(unpin! pinned-package) +;; Use it to unpin multiple packages +;(unpin! pinned-package another-pinned-package) + + +;; To install SOME-PACKAGE from MELPA, ELPA or emacsmirror: +;(package! some-package) + +;; To install a package directly from a particular repo, you'll need to specify +;; a `:recipe'. You'll find documentation on what `:recipe' accepts here: +;; https://github.com/raxod502/straight.el#the-recipe-format +;(package! another-package +; :recipe (:host github :repo "username/repo")) + +;; If the package you are trying to install does not contain a PACKAGENAME.el +;; file, or is located in a subdirectory of the repo, you'll need to specify +;; `:files' in the `:recipe': +;(package! this-package +; :recipe (:host github :repo "username/repo" +; :files ("some-file.el" "src/lisp/*.el"))) + +;; If you'd like to disable a package included with Doom, for whatever reason, +;; you can do so here with the `:disable' property: +;(package! builtin-package :disable t) + +;; You can override the recipe of a built in package without having to specify +;; all the properties for `:recipe'. These will inherit the rest of its recipe +;; from Doom or MELPA/ELPA/Emacsmirror: +;(package! builtin-package :recipe (:nonrecursive t)) +;(package! builtin-package-2 :recipe (:repo "myfork/package")) + +;; Specify a `:branch' to install a package from a particular branch or tag. +;; This is required for some packages whose default branch isn't 'master' (which +;; our package manager can't deal with; see raxod502/straight.el#279) +;(package! builtin-package :recipe (:branch "develop")) + +(package! org-inline-pdf :pin "b2dfbf41efac55edacde8a8a6bd0275418de6454") +(package! org-clock-convenience :pin "efc9773a8dedf834cf4a78fb6f5f8fffe55ef8eb") +(package! org-roam-bibtex :pin "3ac2445f431bc39aa0ca5abfc80e28c0c06f0738") +;; (package! org-super-agenda) +;; (package! mu4e-alert) +;; (package! clip2org) +(package! centered-cursor-mode) +;; (package! counsel-tramp) +;; (package! org-capture-pop-frame) +(package! org-caldav) +(package! ob-typescript) +(package! indium) +;; (package! mac-pseudo-daemon) +;; (package! nix-docbook-mode) +(package! base16-theme) +(package! citar-org-roam + :recipe (:host github :repo "emacs-citar/citar-org-roam")) +(package! pdf-tools :built-in 'prefer) +;; (package! weblorg) diff --git a/snippets/mu4e-compose-mode/all b/snippets/mu4e-compose-mode/all new file mode 100644 index 0000000..c85d200 --- /dev/null +++ b/snippets/mu4e-compose-mode/all @@ -0,0 +1,10 @@ +# -*- mode: snippet -*- +# name: hi all +# key: all +# -- +Hi all, + +$0 + +Cheers, +Max \ No newline at end of file diff --git a/snippets/mu4e-compose-mode/best b/snippets/mu4e-compose-mode/best new file mode 100644 index 0000000..b7d09fa --- /dev/null +++ b/snippets/mu4e-compose-mode/best @@ -0,0 +1,6 @@ +# -*- mode: snippet -*- +# name: Best regards +# key: best, +# -- +Best regards, +Max${ Schlüter} \ No newline at end of file diff --git a/snippets/mu4e-compose-mode/cordialement b/snippets/mu4e-compose-mode/cordialement new file mode 100644 index 0000000..13233d7 --- /dev/null +++ b/snippets/mu4e-compose-mode/cordialement @@ -0,0 +1,6 @@ +# -*- mode: snippet -*- +# name: Cordialement +# key: cord, +# -- +Cordialement, +Max${ Schlüter} diff --git a/snippets/mu4e-compose-mode/dear b/snippets/mu4e-compose-mode/dear new file mode 100644 index 0000000..c51750f --- /dev/null +++ b/snippets/mu4e-compose-mode/dear @@ -0,0 +1,10 @@ +# -*- mode: snippet -*- +# name: dear name +# key: dear +# -- +Dear ${1:`(bjm/mu4e-get-names-for-yasnippet)`}, + +$0 + +Best regards, +Max Schlueter diff --git a/snippets/mu4e-compose-mode/hallo b/snippets/mu4e-compose-mode/hallo new file mode 100644 index 0000000..982699e --- /dev/null +++ b/snippets/mu4e-compose-mode/hallo @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: hallo name +# key: hallo, +# -- +Hallo ${1:`(bjm/mu4e-get-names-for-yasnippet)`}, + +$0 diff --git a/snippets/mu4e-compose-mode/hi b/snippets/mu4e-compose-mode/hi new file mode 100644 index 0000000..b8c8a1b --- /dev/null +++ b/snippets/mu4e-compose-mode/hi @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: hi name +# key: hi, +# -- +Hi ${1:`(bjm/mu4e-get-names-for-yasnippet)`}, + +$0 diff --git a/snippets/mu4e-compose-mode/lg b/snippets/mu4e-compose-mode/lg new file mode 100644 index 0000000..fa52222 --- /dev/null +++ b/snippets/mu4e-compose-mode/lg @@ -0,0 +1,6 @@ +# -*- mode: snippet -*- +# name: Liele Grüße +# key: lg, +# -- +Liebe Grüße, +Max diff --git a/snippets/mu4e-compose-mode/liebe b/snippets/mu4e-compose-mode/liebe new file mode 100644 index 0000000..a6141ab --- /dev/null +++ b/snippets/mu4e-compose-mode/liebe @@ -0,0 +1,10 @@ +# -*- mode: snippet -*- +# name: liebe titel name +# key: liebe, +# -- +Liebe${1:$(when (string-prefix-p "Herr" yas-text) "r")} ${1:$$(yas-completing-read "Titel? " '("Herr" "Frau"))}, + +$0 + +Viele Grüße, +Max Schlüter \ No newline at end of file diff --git a/snippets/mu4e-compose-mode/mfg b/snippets/mu4e-compose-mode/mfg new file mode 100644 index 0000000..5d6868f --- /dev/null +++ b/snippets/mu4e-compose-mode/mfg @@ -0,0 +1,6 @@ +# -*- mode: snippet -*- +# name: Liele Grüße +# key: lg, +# -- +Mit freundlichen Grüßen, +Max Schlüter diff --git a/snippets/mu4e-compose-mode/salut b/snippets/mu4e-compose-mode/salut new file mode 100644 index 0000000..77ca6fa --- /dev/null +++ b/snippets/mu4e-compose-mode/salut @@ -0,0 +1,7 @@ +# -*- mode: snippet -*- +# name: Salut +# key: salut, +# -- +Salut ${1:`(bjm/mu4e-get-names-for-yasnippet)`}, + +$0 diff --git a/snippets/mu4e-compose-mode/sehr b/snippets/mu4e-compose-mode/sehr new file mode 100644 index 0000000..e238b97 --- /dev/null +++ b/snippets/mu4e-compose-mode/sehr @@ -0,0 +1,10 @@ +# -*- mode: snippet -*- +# name: Sehr geehrte... +# key: sehr, +# -- +Sehr geehrte${1:$(when (string-prefix-p "Herr" yas-text) "r")} ${1:$$(yas-completing-read "Titel? " '("Herr" "Frau" "Damen und Herren"))}, + +$0 + +Mit freundlichen Grüßen, +Max Schlüter diff --git a/snippets/mu4e-compose-mode/vg b/snippets/mu4e-compose-mode/vg new file mode 100644 index 0000000..23515a3 --- /dev/null +++ b/snippets/mu4e-compose-mode/vg @@ -0,0 +1,6 @@ +# -*- mode: snippet -*- +# name: Viele Grüße +# key: vg, +# -- +Viele Grüße, +Max${ Schlüter} diff --git a/snippets/mu4e-compose-mode/zusammen b/snippets/mu4e-compose-mode/zusammen new file mode 100644 index 0000000..48102e9 --- /dev/null +++ b/snippets/mu4e-compose-mode/zusammen @@ -0,0 +1,10 @@ +# -*- mode: snippet -*- +# name: hallo zusammen +# key: zusammen +# -- +Hallo zusammen, + +$0 + +Viele Grüße, +Max \ No newline at end of file diff --git a/snippets/text-mode/letter b/snippets/text-mode/letter new file mode 100644 index 0000000..2556335 --- /dev/null +++ b/snippets/text-mode/letter @@ -0,0 +1,38 @@ +# -*- mode: snippet -*- +# name:myExampleLetter +# key:,ltr +# -- + #+LCO: mySN + #+OPTIONS: backaddress:t email:nil + #+OPTIONS: after-closing-order:(after_closing ps encl cc) + #+OPTIONS: after-letter-order:(after_letter) + #+OPTIONS: foldmarks:nil phone:nil place:t special-headings:nil subject:t + #+OPTIONS: title-subject:nil url:nil location:t title:nil + + #+LATEX_CLASS: default-koma-letter + #+LATEX_HEADER: \setkomavar{signature}{\includegraphics[height=1cm]{/home/ra/Downloads/signature.pdf}\\\\\usekomavar{fromname}} + #+LaTeX_HEADER: \usepackage{pdfpages} + #+AUTHOR: Sender Name + #+FROM_ADDRESS: Acmestreet 1, 5555 Footown + #+PHONE_NUMBER: 0123456789 + #+URL: example.org + #+EMAIL: foo@bar.com + #+TO_ADDRESS: ${1:ReceiverInc}\\\ ${2:JohnDoe}\\\ ${3:SomeStreet}\\\ ${4:ZipTown}\\\Mittelerde + #+PLACE: MyTown + #+SUBJECT: ${5:MySubject} + #+OPENING: ${6:Dear John} + #+CLOSING: With best regards + ${0:MyText} +*** PS :ps:noexport: + PS: I must remove the :noexport: tag to display this line in the exported pdf +*** CC :cc: + Jane & Alice +*** ENCL :encl: + - A map + - Another map +*** Included files :after_letter: + #+BEGIN_EXPORT latex + % Uncomment line below to include other pdf files + %\includepdf[pages=-]{/home/ra/Downloads/Map.pdf} %must use absolute path + %\includepdf[pages=-]{/home/ra/Downloads/OtherMap.pdf} %must use absolute path + #+END_EXPORT