#+title: Doom Emacs Config * Main #+PROPERTY: header-args :results silent ** Help #+begin_src emacs-lisp :tangle yes ;; Here are some additional functions/macros that could help you configure Doom: ;; - `load!' for loading external *.el files relative to this one ;; - `use-package!' for configuring packages ;; - `after!' for running code after a package has loaded ;; - `add-load-path!' for adding directories to the `load-path', relative to ;; this file. Emacs searches the `load-path' when you load packages with ;; `require' or `use-package'. ;; - `map!' for binding new keys #+end_src ** Overall config *** Doom specific settings #+begin_src emacs-lisp :tangle yes (setq user-full-name "Julian Mutter" user-mail-address "julian.mutter@comumail.de") (setq doom-font (font-spec :family "Source Code Pro" :size 14)) (setq doom-theme 'doom-one) (setq display-line-numbers-type 'relative) #+end_src *** My custom keybindings #+begin_src emacs-lisp :tangle yes ;; Open external terminal (map! :leader :desc "Open external terminal" "o t" (cmd! (call-process-shell-command "alacritty &" nil 0))) ;; Open external file manager (map! :leader :desc "Open external file explorer" "o e" (cmd! (call-process-shell-command "thunar &" nil 0))) ;; Remap font scaling keybindings to make more sense (map! :desc "Increase font size" :n "C-+" #'text-scale-increase) (map! :desc "Decrease font size" :n "C--" #'text-scale-decrease) (map! :desc "Reset font size" :n "C-=" #'doom/reset-font-size) (map! :desc "Flycheck next error" :nv "g n" #'flycheck-next-error) (map! :desc "Flycheck previous error" :nv "g N" #'flycheck-previous-error) (map! :leader "c X" #'flycheck-list-errors) (map! :desc "Format and save" :g "C-s" #'fd-format-and-save) (map! :leader "w 1" #'delete-other-windows) (map! :leader "t p" #'+popup/toggle) (dotimes (counter 9) (let ((command (format "(map! :leader \"%d\" #'winum-select-window-%d)" (1+ counter) (1+ counter)))) (eval (read command)))) (map! :leader "r" #'quickrun) (setq-default evil-escape-key-sequence "kj") (defun fd-format-and-save() (interactive) (company-abort) (evil-force-normal-state) ;; (without-minibuffer '+format/buffer) ; Skip if no formatter is defined (e.g. in text mode) (+format/buffer) ; Skip if no formatter is defined (e.g. in text mode) (save-buffer)) (defmacro without-minibuffer (&rest body) "Like `progn', but stop and return nil if any of BODY forms tries to use the minibuffer. Also disable dialogs while evaluating BODY forms, since dialogs are just an alternative to the minibuffer." `(catch 'tried-to-use-minibuffer (minibuffer-with-setup-hook (lambda (&rest args) (throw 'tried-to-use-minibuffer nil)) (let ((use-dialog-box)) ; No cheating by using dialogs instead of minibuffer ,@body)))) ;; Do not ask before exiting emacs (setq confirm-kill-emacs nil) #+end_src *** Openwith #+begin_src emacs-lisp :tangle yes (openwith-mode t) (setq openwith-associations '(("\\.pdf\\'" "evince" (file)))) #+end_src ** Org #+begin_src emacs-lisp :tangle yes (setq org-directory "~/Nextcloud/org" org-roam-directory "~/Nextcloud/org/roam") ;; Make all org files agenda files (setq org-agenda-files (list org-directory "~/dev/bachelor-thesis/notes")) (setq org-export-allow-bind-keywords t) ;; Insert timestamp when marking task as done (setq org-log-done #'time) (add-hook 'org-clock-in-hook #'save-buffer) (add-hook 'org-clock-out-hook #'save-buffer) (setq org-pomodoro-manual-break t) ;; Max volume is 65536 since player is paplay (let ((volume "--volume=40000")) (setq org-pomodoro-start-sound-args volume) (setq org-pomodoro-killed-sound-args volume) (setq org-pomodoro-ticking-sound-args volume) (setq org-pomodoro-finished-sound-args volume) (setq org-pomodoro-overtime-sound-args volume) (setq org-pomodoro-long-break-sound-args volume) (setq org-pomodoro-short-break-sound-args volume) ) (setq org-agenda-custom-commands '(("." "Clocking today" agenda "" ((org-agenda-span 1) (org-agenda-start-day "today") (org-agenda-start-with-clockreport-mode t) (org-agenda-start-with-log-mode 'clockcheck) )))) (setq org-agenda-clockreport-parameter-plist '(:link t :maxlevel 2 :fileskip0 t)) ;; :stepskip0 t (setq org-clock-mode-line-total 'today) (map! :map org-mode-map :nvi "C-k" #'org-backward-element) (map! :map org-mode-map :nvi "C-j" #'org-forward-element) (map! :map org-mode-map :nvi "C-h" #'org-up-element) (map! :map org-mode-map :nvi "C-l" #'org-down-element) (map! :map org-mode-map :nvi "M-i" #'org-roam-node-insert) (map! :map org-mode-map :nvi "M-@" #'org-cite-insert) (map! :map doom-leader-notes-map "r r" #'org-roam-node-find) (map! :map doom-leader-notes-map "r t" #'org-roam-buffer-toggle) (map! :map doom-leader-notes-map "s" #'fd-org-notes-search-follow-symlinks) (after! org (add-to-list 'org-capture-templates '("b" "Bachelor todo" entry (file+headline "bachelor/todo.org" "Inbox") "* IDEA %?\n%i\n%T\n%a" :prepend t) )) (defun fd-org-notes-search-follow-symlinks (query) "Alternative to +default/org-notes-search which follows symbolic links for better project inlusion" (interactive (list (if (doom-region-active-p) (buffer-substring-no-properties (doom-region-beginning) (doom-region-end)) ""))) (require 'org) (+vertico-file-search :query query :in org-directory :args '("-L"))) (defun fd-org-latex-preview-buffer () "Show latex preview for whole buffer by running org-latex-preview with C-u C-u" (interactive) (let ((current-prefix-arg '(16))) (call-interactively 'org-latex-preview) )) #+end_src ** TeX #+begin_src emacs-lisp :tangle yes ;; Enable org mode like header navigation (map! :map TeX-mode-map :nvi "" #'outline-cycle-buffer) (map! :map TeX-mode-map :nv "C-k" #'outline-backward-same-level) (map! :map TeX-mode-map :nv "C-j" #'outline-forward-same-level) (map! :map TeX-mode-map :nv "C-h" #'outline-up-heading) (map! :map TeX-mode-map :nv "C-l" #'outline-next-heading) ;; Fixes latexindent not finding perl libraries (setenv "PERL5LIB" "~/perl5/lib/perl5") (setq +latex-viewers '(evince)) #+end_src ** Spell Checking #+begin_src emacs-lisp :tangle yes (use-package! lsp-ltex :init (setq lsp-ltex-enabled t) (setq lsp-ltex-language "en-US") (setq lsp-ltex-mother-tongue "de-DE")) ;; Do not automatically enable writegood mode (remove-hook! '(org-mode-hook markdown-mode-hook rst-mode-hook asciidoc-mode-hook latex-mode-hook LaTeX-mode-hook) #'writegood-mode) ;; Removing hooks for automatic spell checking set here: https://github.com/hlissner/doom-emacs/blob/develop/modules/checkers/spell/config.el (remove-hook! '(org-mode-hook markdown-mode-hook TeX-mode-hook rst-mode-hook mu4e-compose-mode-hook message-mode-hook git-commit-mode-hook) #'flyspell-mode) (remove-hook! '(yaml-mode-hook conf-mode-hook prog-mode-hook) #'flyspell-prog-mode) ;; (setq ispell-dictionary "english") (setq ispell-personal-dictionary "~/ispell-personal-dictionary") (map! :map doom-leader-toggle-map :desc "Toggle dictionary" "d" #'fd-switch-dictionary) (defun fd-switch-dictionary() (interactive) (let* ((dic ispell-current-dictionary) (change (if (string= dic "german") "english" "german"))) (ispell-change-dictionary change) (message "Dictionary switched from %s to %s" dic change) )) (set-flyspell-predicate! '(latex-mode) #'+latex-flyspell-word-p) (defun +latex-flyspell-word-p () "Return t if point is on a word that should be spell checked. Return nil if on a link url, markup, html, or references." (let ((faces (ensure-list (get-text-property (point) 'face)))) (or (and (memq 'font-lock-comment-face faces) (memq 'markdown-code-face faces)) (not (cl-loop with unsafe-faces = '(font-lock-comment-face ;; font-latex-math-face ;; font-latex-string-face font-lock-keyword-face font-lock-constant-face font-lock-function-name-face font-lock-variable-name-face font-lock-type-face ;; figure captions ) for face in faces if (memq face unsafe-faces) return t))))) #+end_src ** Flutter #+begin_src emacs-lisp :tangle yes ;; (setq lsp-dart-flutter-sdk-dir "~/snap/flutter/common/flutter") ;; (map! :mode dart-mode :leader "r" #'flutter-run-or-hot-reload) #+end_src ** Evil snipe #+begin_src emacs-lisp :tangle yes ;; Make sniping simpler for german keyboard (setq evil-snipe-scope 'visible) (map! :map evil-snipe-override-mode-map :m "," #'evil-snipe-repeat) (map! :map evil-snipe-override-mode-map :m ";" #'evil-snipe-repeat-reverse) (map! :map evil-snipe-parent-transient-map "," #'evil-snipe-repeat) (map! :map evil-snipe-parent-transient-map ";" #'evil-snipe-repeat-reverse) #+end_src ** Matlab #+begin_src emacs-lisp :tangle yes (add-hook 'matlab-mode-hook (lambda () (add-to-list 'quickrun-file-alist '("\\.m\\'" . "octave")))) ;; (assq-delete-all "objc" quickrun-file-alist) (quickrun-add-command "matlab" '((:command . "octave")) :mode #'matlab-mode ) (quickrun-add-command "octave" '((:command . "octave")) :mode #'octave-mode ) ;; (autoload 'matlab-mode "matlab" "Matlab Editing Mode" t) (add-to-list 'auto-mode-alist '("\\.m$" . matlab-mode)) ;; (setq matlab-indent-function t) ;; (setq matlab-shell-command "/urs/local/bin/matlab") #+end_src ** Features *** Toggle word case #+begin_src elisp :tangle yes (map! :desc "Toggle case of word" :nv "g C" #'toggle-word-case) (defun toggle-word-case () "Toggle the case of current word or text selection." (interactive) (let ( (deactivate-mark nil) $p1 $p2) (if (use-region-p) (setq $p1 (region-beginning) $p2 (region-end)) (save-excursion (skip-chars-backward "[:alpha:]") (setq $p1 (point)) (skip-chars-forward "[:alpha:]") (setq $p2 (point)))) (let ((first-char-prop (get-char-code-property (char-after $p1) 'general-category))) (cond ((string= "Ll" first-char-prop) ; Lower case (upcase-region $p1 (+ $p1 1))) ((string= "Lu" first-char-prop) ; Upper case (downcase-region $p1 (+ $p1 1))) (t (message "Word does not start with a alphabetic character")))))) #+end_src *** Tetris #+begin_src emacs-lisp :tangle yes (add-hook 'tetris-mode-hook #'turn-off-evil-mode) #+end_src ** Projectile #+begin_src emacs-lisp :tangle yes (map! :map 'doom-leader-project-map :desc "Repeat last command" "SPC" #'projectile-repeat-last-command) #+end_src ** More #+begin_src emacs-lisp :tangle yes (defun fd-pretty-print-dirty-json() (interactive) (let ((new-buffer-contents (shell-command-to-string (format "echo '%s' | newliner" (buffer-string))))) (erase-buffer) (insert new-buffer-contents) (evil-indent (buffer-end -1) (buffer-end +1))) ) #+end_src ** Inventory #+begin_src emacs-lisp :tangle yes (defun fd-inventory-transfer() (interactive) (fd-inventory-transfer-check-if-valid-table) (let ((location-from (string-trim (org-table-get 1 2))) (location-to (string-trim (org-table-get 1 3))) (item-name (string-trim (org-table-get-field 1)))) (let (transfer-amount) (setq transfer-amount (read-number (concat "Transfer from " location-from " to " location-to ": "))) (fd-inventory-transfer-log-transfer transfer-amount item-name location-from location-to) (fd-inventory-transfer-do-transfer transfer-amount) (org-table-align) ))) (defun fd-inventory-transfer-check-if-valid-table () (unless (org-at-table-p) (error "You are not inside a table")) (unless (and (string-match-p "^[[:blank:]]*-?[0-9]+[[:blank:]]*$" (org-table-get-field 2)) (string-match-p "^[[:blank:]]*-?[0-9]+[[:blank:]]*$" (org-table-get-field 3))) (error "Amounts in table are not numbers")) (if (or (string= "" (org-table-get 1 2)) (string= "" (org-table-get 1 3))) (error "No valid table header"))) (defun fd-inventory-transfer-do-transfer(amount) (let* ((amount-from-location (string-to-number (org-table-get-field 2))) (amount-to-location (string-to-number (org-table-get-field 3))) (amount-from-location-new (- amount-from-location amount)) (amount-to-location-new (+ amount-to-location amount))) (progn (org-table-get-field 2 (number-to-string amount-from-location-new)) (org-table-get-field 3 (number-to-string amount-to-location-new))))) (defun fd-inventory-transfer-log-transfer(amount item-name from-location to-location) (save-excursion (let* ((log-heading-point (or (org-find-exact-headline-in-buffer "Transfer log" nil t) (progn (goto-char (org-table-end)) (org-insert-heading) (insert "Transfer log") (point))))) (goto-char log-heading-point) (forward-line) (let ((message (concat "- " (format-time-string "%d.%m.%Y") ": *" (number-to-string amount) "* =" item-name "= from " from-location " to " to-location "\n"))) (insert message)) ))) #+end_src ** Python #+begin_src emacs-lisp :tangle yes (defun fd-python-to-latex(regionBegin regionEnd) (interactive (if (use-region-p) (list (region-beginning) (region-end)) (list (point-min) (point-max)))) (shell-command-on-region regionBegin regionEnd "python2latex")) #+end_src ** Haskell #+begin_src emacs-lisp :tangle yes (set-docsets! 'haskell-mode "Haskell") #+end_src ** Citations #+begin_src emacs-lisp :tangle yes (setq! citar-bibliography '("~/Nextcloud/zotero-sources.bib")) #+end_src