Fork 0
My Doom Emacs configuration.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Florian Posdziech 68a0f10557 [doom] Comment comments about auto-saving 4 weeks ago
lisp [keychain] Make ssh-agent available inside Emacs 7 months ago
snippets/org-mode [abc] Add abc-mode and snippet 4 weeks ago
themes [org] Make links less shiny 5 months ago
LICENSE Initial commit 7 months ago
README.org [doom] Comment comments about auto-saving 4 weeks ago
config.el [org] Update thundertalks category 4 weeks ago
init.el [restclient] Enable restclient and json mode 4 months ago
packages.el [org] Add abc-mode for music engraving 2 months ago


Doom Emacs Configuration


Make local packages available.

(add-load-path! "lisp")

Set user info.

(setq user-full-name "Florian Posdziech"
      user-mail-address "hallo@flowfx.de")

Set fonts depending on their availability. Cf. https://github.com/hlissner/doom-emacs/issues/5948#issuecomment-1004253858. TODO: Somehow, doom-font-exists-p is not available at startup.

(setq doom-font (font-spec :family "InconsolataLGC Nerd Font" :size 19)
      doom-variable-pitch-font (font-spec :family "iA Writer Duo V" :size 19)
;; (setq doom-font
;;   (cl-find-if #'doom-font-exists-p
;;     '("InconsolataLGC Nerd Font:pixelsize=19"
;;       "iA Writer Mono V:pixelsize=19")))

;; (setq doom-variable-pitch-font
;;   (cl-find-if #'doom-font-exists-p
;;     '("iA Writer Duo V:pixelsize=19")))

Enable mixed-pitch mode in orgmode.

(add-hook 'org-mode-hook 'mixed-pitch-mode)


Custom theme based on the Smyck color scheme.

(setq doom-theme 'doom-smyck)

Let me have nice todo headings

(setq org-fontify-todo-headline t)


General configurations.

(after! org
  ;; TODO: extract org-directory into noweb reference so it can be used in all the places
  (setq org-directory "~/Things"
        org-agenda-files '(
        +org-capture-todo-file "~/Things/inbox.org"
        org-log-done 'time)

TODO keywords.

  (setq org-todo-keywords '((sequence "TODO(t)" "WAIT(w)" "HOLD(h)" "|" "DONE(d)" "CANCELLED(c)")
                            (type     "PROJ(p)" "ISSUE(i)" "BUG(b)" "REVIEW(r)" "|" "SOLVED(s)")))

Define archive and refile targets.

  (setq org-archive-location "~/Things/archive/%s_archive::"
        org-refile-targets '(("~/Things/private.org" :maxlevel . 3)
                             ("~/Things/work.org" :maxlevel . 2)
                             ("~/Things/someday.org" :maxlevel . 2)
                             ("~/Things/misc.org" :maxlevel . 2)
                             ("~/Things/bookmarks.org" :level . 0))
  (setq org-capture-templates
          ("t" "todo" entry (file +org-capture-todo-file) "* TODO %?")
          ("i" "idea" entry (file +org-capture-todo-file) "* %?")
          ("l" "literature note" plain (file my/generate-literature-note-name)
               "%(format \"#+TITLE: %s\n#+FILETAGS: :literature:book|post|video:\n\n\" my-literature-note--name)")
          ("b" "Bookmark" entry (file "~/Things/bookmarks.org")
               "* %(org-cliplink-capture) :%?:\n")
          ("p" "process email" entry (file +org-capture-todo-file)
               "* TODO %? %:fromname: %a")

One function to archive them all (https://stackoverflow.com/a/27043756)

(defun org-archive-done-tasks ()
   (lambda ()
     (setq org-map-continue-from (org-element-property :begin (org-element-at-point))))
   "/DONE" 'tree))

Fix a conflict between IVY and Org-Goto https://github.com/hlissner/doom-emacs/issues/3254

  (setq org-goto-interface 'outline-path-completion
        org-outline-path-complete-in-steps nil)
;; (advice-add 'org-archive-subtree :after 'org-save-all-org-buffers)
   ;; (remove-hook 'org-trigger-hook 'save-buffer)
   ;; (remove-hook 'org-trigger-hook 'basic-save-buffer)
   ;; (add-hook 'org-trigger-hook 'org-save-all-org-buffers)

Custom link types

(defun make-link-to-pull-request (pull_no)
  (browse-url (concat "https://github.com/dbdrive/triebwerk/pull/" pull_no)))

(defun make-link-to-issue (issue_no)
  (browse-url (concat "https://github.com/dbdrive/triebwerk/issues/" issue_no)))

(org-add-link-type "pr" #'make-link-to-pull-request)
(org-add-link-type "issue" #'make-link-to-issue)

Tables and calculations

(setq org-table-duration-hour-zero-padding nil)

General agenda settings.

  (setq org-agenda-start-day nil                ;; start today
        org-agenda-span 'day                    ;; and show only today
        org-agenda-dim-blocked-tasks 'invisible ;; Don't show me any blocked todos. Next actions only - doesn't work for tags searches
        ;; org-agenda-todo-ignore-scheduled 'future
        ;; org-agenda-todo-ignore-deadlines 'near
        org-agenda-sorting-strategy '((agenda habit-down time-up priority-down category-keep)
                (todo priority-down category-keep)
                (search category-keep))
        org-deadline-warning-days 3

Sort todo items alphabetically - eventually.

(setq org-agenda-sorting-strategy '((agenda habit-down time-up priority-down alpha-up)
                                    (todo priority-down alpha-up)
                                    (tags todo-state-down alpha-up)
                                    (search alpha-up)))

Custom agenda commands

  (setq org-agenda-custom-commands
          ("w" "Today at work"
           ((agenda ""
                   ((org-agenda-skip-function '(my-org-agenda-skip-tag "private")))

          ;; lalibela is my private machine.
          (tags-todo "work|misc"
                      ;; These will appear in the agenda on the day they're scheduled
                      (org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled))
                      ;; Removes the "tags search items" header
                      (org-agenda-overriding-header "")
          (tags "CATEGORY=\"inbox\""
                ((org-agenda-overriding-header "\n\n 📥 INBOX\n")))
        ("q" "Today at home"
          (agenda "" (
                   (org-agenda-skip-function '(my-org-agenda-skip-tag "work"))
          ;; hotmilk and bababoom are my work computers.
          (tags-todo "private|misc"
                        (org-agenda-skip-function '(org-agenda-skip-entry-if 'scheduled))
                        (org-agenda-overriding-header "")

        org-agenda-prefix-format '((agenda . " %?-12t% s")
                                   (todo .   "")
                                   (tags .   " ")
                                   (search . "%i %-12:c"))

  (setq org-agenda-hide-tags-regexp ".*") ;; Hide all tags in agenda view
  (setq org-agenda-block-separator 9472)     ;; Separate agenda and todos by a straight line
  (setq org-agenda-skip-scheduled-if-done t) ;; Don't show done items
  (setq org-agenda-skip-deadline-if-done t) ;; Don't show done items

Custom function to skip entries by tag (https://stackoverflow.com/a/10091330).

(defun my-org-agenda-skip-tag (tag &optional others)
  " Skip all entries that correspond to TAG.

    If OTHERS is true, skip all entries that do not correspond to TAG."
  (let ((next-headline (save-excursion (or (outline-next-heading) (point-max))))
        (current-headline (or (and (org-at-heading-p)
                              (save-excursion (org-back-to-heading)))))
    (if others
        (if (not (member tag (org-get-tags-at current-headline)))
      (if (member tag (org-get-tags-at current-headline))


Disable the super agenda header map to fix something: https://github.com/alphapapa/org-super-agenda/issues/112#issuecomment-548224512

(setq org-super-agenda-header-map nil)

This is applied to all custom agenda views.

(setq org-super-agenda-groups
        ;; (:name "⏰ Calendar" :time-grid t)
        (:name "➡ Today" :scheduled today)
        (:discard (:todo "HOLD"))
        (:name "🏃 Current Sprint"
                :and (:category "sprint" :not (:tag "agenda"))
        (:name "😀 Agenda" :tag "agenda")
        (:name "⚡ THUNDER!" :and (:category "thundertalks" :not (:todo("WAIT"))))
        (:name "🔭 R&D + 20%" :category "20pct")
        (:name "🏡 Zuhause" :and (:tag "@home" :not (:tag "@city")))
        (:name "🛍 City" :tag "@city")
        (:name "💸 Finanzen" :and (:category "finanzen" :not (:todo("WAIT"))))
        (:name "🏋 & 🏃" :and (:category "training" :not (:todo("WAIT"))))
        (:name "🎶 Musik" :and (:category "music" :not (:todo("WAIT"))))
        (:name "" :category "inbox")
        ;; (:name "🛠" :auto-category)
        (:name "🛠" :not (:todo ("WAIT")))
        (:name "😴" :todo ("WAIT"))


(setq org-roam-directory (file-truename "~/Things/notes"))

Add a custom template for literature notes.

(setq org-roam-capture-templates
  '(("d" "default" plain "%?" :target
     (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n")
     :unnarrowed t
     :jump-to-captured t)
    ("l" "literature note" plain "%?" :target
     (file+head "literature/${title}.org" "#+title: ${title}\n")
     :unnarrowed t
     :jump-to-captured t)))


Minimal configuration (Mu4e 1.6.0 user manual)

Use mu4e for email in Emacs.

(setq mail-user-agent 'mu4e-user-agent
    mu4e-sent-folder   "/Sent"
    mu4e-drafts-folder "/Drafts"
    mu4e-refile-folder "/Archive"
    mu4e-spam-folder   "/Junk"
    mu4e-trash-folder  "/Trash")

Don't run anything for getting new mails, but mails are still indexed.

(setq mu4e-get-mail-command "true")

Handle html emails.

(setq mu4e-html2text-command "w3m -T text/html")

Prefer plain text, always. (Disable MU4E 'HTML over plain text' heuristic)

(setq mu4e-view-html-plaintext-ratio-heuristic most-positive-fixnum)

TODO: Mark as read and move to spam.

SMTP settings.

    message-send-mail-function   'smtpmail-send-it
    smtpmail-smtp-server         "smtp.mailbox.org"
    smtpmail-smtp-service        587
    smtpmail-smtp-stream-type    'starttls)

Keyboard macro to jump to inbox.

(defun my-mu4e-inbox ()
  "jump to mu4e inbox"
  (mu4e~headers-jump-to-maildir "/Inbox"))

(map! :leader
      :desc "Jump to mu4e inbox"
      "oi" 'my-mu4e-inbox)

Keyboard bindings

Use Vim keys to move around windows without hitting C-w first (https://github.com/syl20bnr/spacemacs/issues/5933).

(define-key evil-motion-state-map (kbd "C-h") #'evil-window-left)
(define-key evil-motion-state-map (kbd "C-j") #'evil-window-down)
(define-key evil-motion-state-map (kbd "C-k") #'evil-window-up)
(define-key evil-motion-state-map (kbd "C-l") #'evil-window-right)

Run last macro on F5 (https://sites.google.com/site/steveyegge2/effective-emacs).

(global-set-key [f5] 'call-last-kbd-macro)

Open agenda views with SPC W and SPC Q, all things with SPC T and the inbox with SPC I.

(defun my-org-work-agenda ()
  (org-agenda nil "w"))

(defun my-org-private-agenda ()
  (org-agenda nil "q"))

(defun my-org-inbox-file ()
  (find-file "~/Things/inbox.org" ))

(map! :leader
      :desc "Open work agenda"
      "W" #'my-org-work-agenda)

(map! :leader
      :desc "Open private agenda"
      "Q" #'my-org-private-agenda)

(map! :leader
      :desc "Open my inbox"
      "I" #'my-org-inbox-file)

Exit insert mode by pressing jj quickly

(key-chord-define evil-insert-state-map "jj" 'evil-normal-state)

(key-chord-mode 1)


Show absolute line number in current row. Show relative everywhere else.

(setq display-line-numbers 'relative)
(setq projectile-project-search-path '("~/Things/"))

Reload buffer if file on disk has changed (unless local changes exist)

(setq global-auto-revert-mode t)

Don't ask. Just quit.

(setq confirm-kill-emacs t)

keychain-environment.el gets SSH_AGENT_PID and SSH_AUTH_SOCK from the shell outside of Emacs (https://www.emacswiki.org/emacs/keychain-environment.el).

(require 'keychain-environment)

I don't want to check my org-caldav configuration into the Git repository. It's synced together with all other org files.

(load-file "~/Things/calendars/org-caldav-config.el")

When connecting with emacsclient -nc, don't open a new workspace. Simply connect to "main" (https://github.com/hlissner/doom-emacs/issues/1949).

(after! persp-mode
  (setq persp-emacsclient-init-frame-behaviour-override "main"))

Show current workspace in modeline.

(setq doom-modeline-persp-name t)
(setq auth-sources '("~/.authinfo"))

Automatic tangle on save (https://leanpub.com/lit-config/read#leanpub-auto-automatic-tangle-on-save).

(add-hook 'org-mode-hook
  (lambda () (add-hook 'after-save-hook 'org-babel-tangle :append :local)))



(setq anki-editor-ignored-org-tags '("literature"))
; TODO: load anki-editor-mode when in an org file


When entering olivetti-mode, turn of

  • line numbers
  • git gutter
  • vi tildes at the end of the document
(defun my-toggle-git-gutter-mode ()
  "toggle git-gutter-mode"
  (git-gutter-mode 'toggle))

(defun my-toggle-vi-tilde-fringe-mode ()
  "toggle vi-tilde-fringe-mode"
  (vi-tilde-fringe-mode 'toggle))

; TODO: Define one function that does all 3 so we only need 2 hooks.
(add-hook 'olivetti-mode-on-hook (lambda () (setq display-line-numbers nil)))
(add-hook 'olivetti-mode-on-hook 'my-toggle-git-gutter-mode)
(add-hook 'olivetti-mode-on-hook 'my-toggle-vi-tilde-fringe-mode)
(add-hook 'olivetti-mode-off-hook (lambda () (setq display-line-numbers 'relative)))
(add-hook 'olivetti-mode-off-hook 'my-toggle-git-gutter-mode)
(add-hook 'olivetti-mode-off-hook 'my-toggle-vi-tilde-fringe-mode)