#+TITLE: Emacs Config #+AUTHOR: Evie Litherland-Smith #+EMAIL: evie@xenia.me.uk #+FILETAGS: :emacs:config:org: * Common defaults #+BEGIN_SRC emacs-lisp :results output silent (setq user-full-name "Evie Litherland-Smith" user-mail-address "evie@xenia.me.uk") (setq custom-file (locate-user-emacs-file "custom.el")) (set-default-coding-systems 'utf-8) (set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) #+END_SRC ** package-archive with priorities #+begin_src emacs-lisp :results output silent (when (require 'package nil :noerror) (add-to-list 'package-archives '("stable" . "https://stable.melpa.org/packages/")) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/")) (setq package-archive-priorities '(("gnu" . 99) ("nongnu" . 80) ("stable" . 70) ("melpa" . 0)))) #+end_src * Org-mode For reference information, see [[https://orgmode.com][Org-mode website]] #+BEGIN_SRC emacs-lisp :results output silent (setq org-directory "~/Org" org-default-notes-file (expand-file-name "notes.org" org-directory) org-pretty-entities-include-sub-superscripts t org-pretty-entities-include-sub-superscripts t org-tags-column 0 org-modern-tag nil org-outline-path-complete-in-steps nil org-refile-use-outline-path t org-refile-allow-creating-parent-nodes t org-refile-use-outline-path 'file org-refile-targets '((nil :maxlevel . 3) (org-agenda-files :maxlevel . 3))) #+END_SRC ** Keymaps #+begin_src emacs-lisp :results output silent (keymap-global-set "C-c o a" #'org-agenda) (keymap-global-set "C-c o n" #'org-capture) (keymap-global-set "C-c o l" #'org-capture-goto-last-stored) (keymap-global-set "C-c o j j" #'org-journal-new-entry) (keymap-global-set "C-c o j n" #'org-journal-new-date-entry) (keymap-global-set "C-c o j s" #'org-journal-new-scheduled-entry) (add-hook 'org-mode-hook #'org-modern-mode) (add-hook 'org-agenda-finalize-hook #'org-modern-agenda) #+end_src ** org-agenda #+begin_src emacs-lisp :results output silent (setq org-agenda-files (list (expand-file-name org-directory) (expand-file-name "journal" org-directory) (expand-file-name "projects" org-directory)) org-agenda-sticky nil org-agenda-window-setup 'current-window org-agenda-prefix-format '((agenda . " %-12:c%?-12t% s") (todo . " %-12:c") (tags . " %-12:c") (search . " %-12:c"))) #+end_src ** org-journal #+BEGIN_SRC emacs-lisp :results output silent (setq org-journal-dir (expand-file-name "journal" org-directory) org-journal-file-type 'monthly org-journal-file-format "%Y-%m.org") #+END_SRC ** Capture templates #+BEGIN_SRC emacs-lisp :results output silent (setq org-capture-templates '(("n" "Note" entry (file+headline "inbox.org" "Note") "* %?" :prepend t :empty-lines 1) ("t" "Task" entry (file+headline "inbox.org" "Task") "* TODO %?" :prepend t :empty-lines 1) )) #+END_SRC ** Citar #+begin_src emacs-lisp :results output silent (setq citar-bibliography '("~/.references/main.bib") citar-library-paths '("~/.references/library") citar-notes-paths '("~/.references/notes") citar-symbols '((file "F" . "󰂺") (note "N" . "󰎞") (link "L" . "󰌹"))) (when (require 'citar nil :noerror) (keymap-global-set "C-c o c o" #'citar-open)) #+end_src ** Khalel #+begin_src emacs-lisp :results output silent (setq khalel-import-org-file (expand-file-name "calendar.org" org-directory) khalel-import-org-file-read-only nil khalel-import-org-file-confirm-overwrite nil khalel-import-start-date "-30d" khalel-import-end-date "+30d") (when (require 'khalel nil :noerror) (add-hook 'org-agenda-mode-hook #'khalel-import-events) (khalel-add-capture-template "e")) #+end_src * Copy (to sort) For now I'll just copy all config into this file, to confirm that it works properly. Will reorganise into separate sections later ** TODO Defaults #+BEGIN_SRC emacs-lisp ;;; Code: (setq load-prefer-newer t indent-tabs-mode nil global-auto-revert-non-file-buffers t dired-auto-revert-buffer t dired-dwim-target t tab-always-indent 'complete completion-cycle-threshold 3 completions-detailed t xref-show-definitions-function #'xref-show-definitions-completing-read kill-do-not-save-duplicates t auto-window-vscroll nil fast-but-imprecise-scrolling t scroll-conservatively 101 scroll-margin 0 scroll-preserve-screen-position 1) (global-auto-revert-mode +1) (delete-selection-mode) ;; Misc useful keymaps (keymap-global-set "M-#" #'dictionary-lookup-definition) (keymap-global-set "C-c r" #'recentf) (keymap-global-set "C-c b" #'ibuffer) (keymap-global-set "C-c p l" #'list-packages) (keymap-global-set "C-c p r" #'package-refresh-contents) (keymap-global-set "C-c p i" #'package-install) (keymap-global-set "C-c p d" #'package-delete) ;; turn on spell checking, if available. (when (and (require 'ispell nil :noerror) (executable-find ispell-program-name)) (add-hook 'text-mode-hook #'flyspell-mode) (add-hook 'prog-mode-hook #'flyspell-prog-mode)) ;; Make shebang (#!) file executable when saved (add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p) #+END_SRC ** TODO UI #+BEGIN_SRC emacs-lisp (setq use-dialog-box nil fill-column 80 truncate-lines nil truncate-partial-width-windows nil) (menu-bar-mode -1) (tab-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) (line-number-mode) (global-display-line-numbers-mode -1) (global-prettify-symbols-mode +1) (global-visual-line-mode +1) ;; (set-frame-font "FiraCode Nerd Font-12") ;; (set-frame-parameter nil 'alpha-background 80) ;; Nerd-Icons modes (when (require 'nerd-icons) (nerd-icons-set-font "Symbols Nerd Font Mono") (when (require 'nerd-icons-dired nil :noerror) (add-hook 'dired-mode-hook #'nerd-icons-dired-mode)) (when (require 'nerd-icons-ibuffer nil :noerror) (add-hook 'ibuffer-mode-hook #'nerd-icons-ibuffer-mode)) (when (require 'nerd-icons-completion nil :noerror) (nerd-icons-completion-mode) (when (require 'marginalia nil :noerror) (add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup)))) ;; Doom-Modeline (setq doom-modeline-icon t doom-modeline-mu4e nil ;; Use mu4e own formatting doom-modeline-modal nil doom-modeline-modal-icon nil doom-modeline-persp-name nil doom-modeline-persp-icon nil) (when (require 'doom-modeline nil :noerror) (doom-modeline-mode +1)) ;; Dashboard (setq initial-buffer-choice 'dashboard-open dashboard-icon-type 'nerd-icons dashboard-set-heading-icons t dashboard-set-file-icons t dashboard-set-navigator t dashboard-set-init-info t dashboard-startup-banner 'ascii dashboard-projects-backend 'project-el dashboard-projects-switch-function 'project-switch-project dashboard-projects-show-base t dashboard-recentf-show-base 'align dashboard-items '((recents . 5) (agenda . 15)) dashboard-heading-icons '((recents . "nf-oct-history") (agenda . "nf-oct-calendar")) dashboard-banner-ascii (concat " .000000. \n" " .0. .0. \n" " .00. .00. \n" " .000cl. .lc000. \n" ".0 0.\n" "0. .o0000o. .0\n" " 00 .0' '0. 00 \n" " 00 .0 0. 00 \n" " HHHHH HHHHHHHHHHHH HHHHH \n" "HHHH HHH HHHHHHHHHHHHHH HHHH\n" " HHHHHH HHHHHHHHH HHHHHHHH \n" " HHH HHHH HHHHHHHHH HHHH \n" " HHH HHHHHH \n" " HHHHH HH \n")) (when (require 'dashboard nil :noerror) (keymap-global-set "C-c d" #'dashboard-open) (add-hook 'dashboard-mode-hook #'khalel-import-events)) ;; Extra minor-modes (when (require 'git-gutter nil :noerror) (global-git-gutter-mode +1)) (when (require 'which-key nil :noerror) (which-key-mode +1)) (when (require 'page-break-lines nil :noerror) (global-page-break-lines-mode +1)) ;;;; Help Buffers ;; Make `describe-*' screens more helpful (when (require 'helpful nil :noerror) (keymap-set helpful-mode-map " " #'helpful-update) (keymap-global-set " " #'helpful-command) (keymap-global-set " " #'helpful-callable) (keymap-global-set " " #'helpful-key) (keymap-global-set " " #'helpful-symbol) (keymap-global-set " " #'helpful-variable) (keymap-global-set "C-h F" #'helpful-function)) ;; Bind extra `describe-*' commands (keymap-global-set "C-h K" #'describe-keymap) ;; add visual pulse when changing focus, like beacon but built-in ;; from from https://karthinks.com/software/batteries-included-with-emacs/ (defun pulse-line (&rest _) "Pulse the current line." (pulse-momentary-highlight-one-line (point))) (dolist (command '(scroll-up-command scroll-down-command recenter-top-bottom other-window)) (advice-add command :after #'pulse-line)) ;;; custom-ui-config.el ends here #+END_SRC ** TODO Email #+BEGIN_SRC emacs-lisp (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 message-kill-buffer-on-exit t mail-user-agent 'mu4e-user-agent read-mail-command 'mu4e mu4e-maildir "~/Mail" mu4e-attachment-dir "~/Downloads" mu4e-get-mail-command "mbsync -a" mu4e-update-interval (* 5 60) ; Every 5 minutes mu4e-sent-messages-behavior 'sent mu4e-change-filenames-when-moving t mu4e-context-policy 'pick-first mu4e-use-fancy-chars t mu4e-headers-thread-single-orphan-prefix '("─>" . "─▶") mu4e-headers-thread-orphan-prefix '("┬>" . "┬▶") mu4e-headers-thread-connection-prefix '("│ " . "│ ") mu4e-headers-thread-first-child-prefix '("├>" . "├▶") mu4e-headers-thread-child-prefix '("├>" . "├▶") mu4e-headers-thread-last-child-prefix '("└>" . "╰▶") mu4e-modeline-all-read '("R:" . "󰑇 ") mu4e-modeline-all-clear '("C:" . "󰚭 ") mu4e-modeline-new-items '("N:" . "󰎔 ") mu4e-modeline-unread-items '("U:" . "󰶊 ") mu4e-search-full-label '("F" . "󱊖 ") mu4e-search-hide-label '("H" . "󰘓 ") mu4e-search-related-label '("R" . "󰌹 ") mu4e-search-skip-duplicates-label '("D" . "󰆑 ") mu4e-search-threaded-label'("T" . "󱇫 ") mu4e-alert-modeline-formatter 'mu4e-alert-default-mode-line-formatter mu4e-headers-fields '((:human-date . 12) (:flags . 6) (:from-or-to . 25) (:subject)) mu4e-headers-actions '(("org capture message" . mu4e-org-store-and-capture) ("capture message" . mu4e-action-capture-message) ("show this thread" . mu4e-action-show-thread)) mu4e-maildir-shortcuts '((:maildir "/Proton/Inbox/" :key ?p) (:maildir "/iCloud/Inbox/" :key ?i) (:maildir "/Outlook/Inbox/" :key ?w))) (when (require 'mu4e nil :noerror) (keymap-global-set "C-c m m" #'mu4e) (keymap-global-set "C-c m u" #'mu4e-update-index) (keymap-global-set "C-c m c" #'mu4e-compose-new) (when (require 'mu4e-alert nil :noerror) (mu4e-alert-set-default-style 'libnotify) (mu4e-alert-enable-notifications) (mu4e-alert-enable-mode-line-display)) (setq mu4e-contexts (list (make-mu4e-context :name "Xenia" :vars '((user-mail-address . "evie@xenia.me.uk") (mu4e-sent-folder . "/Proton/Sent") (mu4e-drafts-folder . "/Proton/Drafts") (mu4e-trash-folder . "/Proton/Trash") (mu4e-refile-folder . "/Proton/Archive"))) (make-mu4e-context :name "Proton" :match-func (lambda (msg) (when msg (string-prefix-p "/Proton" (mu4e-message-field msg :maildir)))) :vars '((user-mail-address . "e.litherlandsmith@proton.me") (mu4e-sent-folder . "/Proton/Sent") (mu4e-drafts-folder . "/Proton/Drafts") (mu4e-trash-folder . "/Proton/Trash") (mu4e-refile-folder . "/Proton/Archive"))) (make-mu4e-context :name "iCloud" :match-func (lambda (msg) (when msg (string-prefix-p "/iCloud" (mu4e-message-field msg :maildir)))) :vars '((user-mail-address . "e.litherlandsmith@icloud.com") (mu4e-sent-folder . "/iCloud/Sent Messages") (mu4e-drafts-folder . "/iCloud/Drafts") (mu4e-trash-folder . "/iCloud/Deleted Messages") (mu4e-refile-folder . "/iCloud/Archive"))) (make-mu4e-context :name "Work" :match-func (lambda (msg) (when msg (string-prefix-p "/Outlook" (mu4e-message-field msg :maildir)))) :vars '((user-mail-address . "evie.litherland-smith@ukaea.uk") (mu4e-sent-folder . "/Outlook/Sent") (mu4e-drafts-folder . "/Outlook/Drafts") (mu4e-trash-folder . "/Outlook/Trash") (mu4e-refile-folder . "/Outlook/Archive")))))) #+END_SRC ** TODO Feeds #+BEGIN_SRC emacs-lisp (let ((elfeed-base-directory "~/.elfeed")) (setq elfeed-db-directory (expand-file-name "db" elfeed-base-directory) elfeed-enclosure-default-dir (expand-file-name "enclosures" elfeed-base-directory) rmh-elfeed-org-files (list (expand-file-name "feeds.org" elfeed-base-directory)))) (when (require 'elfeed nil :noerror) (keymap-global-set "C-c f f" #'elfeed) (add-hook 'elfeed-search-mode-hook #'elfeed-update) (when (require 'elfeed-org nil :noerror) (elfeed-org)) (when (require 'elfeed-tube nil :noerror) (elfeed-tube-setup))) #+END_SRC ** TODO IDE #+BEGIN_SRC emacs-lisp (when (require 'rainbow-delimiters nil :noerror) (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)) (when (require 'treesit-aut nil :noerror) (global-treesit-auto-mode +1)) (setq apheleia-remote-algorithm 'local) (when (require 'apheleia nil :noerror) (keymap-global-set "C-c c f" #'apheleia-format-buffer) (apheleia-global-mode +1)) (when (require 'eglot nil :noerror) (eglot-ensure)) (setq direnv-always-show-summary nil) (when (require 'direnv nil :noerror) (direnv-mode +1)) (when (require 'yasnippet nil :noerror) (require 'yasnippet-snippets nil :noerror) (yas-reload-all) (add-hook 'prog-mode-hook #'yas-minor-mode)) #+END_SRC *** TODO Ligatures #+BEGIN_SRC emacs-lisp (defun fira-code-mode--make-alist (list) "Generate prettify-symbols alist from LIST." (let ((idx -1)) (mapcar (lambda (s) (setq idx (1+ idx)) (let* ((code (+ #Xe100 idx)) (width (string-width s)) (prefix ()) (suffix '(?\s (Br . Br))) (n 1)) (while (< n width) (setq prefix (append prefix '(?\s (Br . Bl)))) (setq n (1+ n))) (cons s (append prefix suffix (list (decode-char 'ucs code)))))) list))) (defconst fira-code-mode--ligatures '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\" "{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}" "--" "---" "-->" "->" "->>" "-<" "-<<" "-~" "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_(" ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*" "/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||=" "|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "==" "===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">=" ">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>" "<$" "<$>" "