;;; init.el --- Main configuration file -*- lexical-binding: t; -*- ;; Author: Yann Herklotz ;;; Commentary: ;; This is the main configuration for my Emacs configuration. ;;; Code: (setq user-full-name "Yann Herklotz") (setq user-mail-address "yann@yannherklotz.com") (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) (unless (file-exists-p custom-file) (with-temp-buffer (write-file custom-file))) (load custom-file) (setq gc-cons-threshold (* 1024 1024 1024)) ;; Set some global key rebindings, mainly trying to use `*-dwim' functions ;; whenever possible and making other common functions more convenient. The ;; main keybinding that conflicts with other modes is `C-.' or `C-,'. (global-set-key (kbd "M-u") #'upcase-dwim) (global-set-key (kbd "M-l") #'downcase-dwim) (global-set-key (kbd "M-c") #'capitalize-dwim) (global-set-key (kbd "C-c z") #'quick-calc) (global-set-key (kbd "") #'revert-buffer) (global-set-key (kbd "C-.") #'other-window) (global-set-key (kbd "C-,") #'ymh/prev-window) (global-set-key (kbd "C-\\") #'undo-only) (global-set-key (kbd "C-") #'tab-bar-switch-to-recent-tab) (global-set-key (kbd "C-c l") #'org-store-link) (global-set-key (kbd "C-c c") #'org-capture) (global-set-key [remap dabbrev-expand] 'hippie-expand) (global-set-key [remap zap-to-char] 'zap-up-to-char) (define-key global-map (kbd "M-Q") #'ymh/unfill-paragraph) ;; Create my own keymap for other, less important but still useful commands ;; which I want to have quick access to. This can be quite flexible, and it ;; might change depending on what I need or how the configuration changes. (define-prefix-command 'ymh-map) (global-set-key (kbd "C-c y") 'ymh-map) (define-key ymh-map (kbd "o") #'ymh/reset-coq-windows) (define-key ymh-map (kbd "c") #'calendar) (define-key ymh-map (kbd "C-l") #'org-agenda-open-link) (define-key ymh-map (kbd "C-p") #'org-previous-link) (define-key ymh-map (kbd "C-n") #'org-next-link) ;; Create variables which hold default locations for various things like my Org ;; directory or the directory containing the bibliography. This makes it much ;; easier to migrate the configuration. (defvar ymh/org-base-dir "~/Dropbox/org" "Contains the base directory for Org files.") (defvar ymh/keyboard :default "Define which keyboard is being used. Should be one of `:white-split', `:modified' or `:default'") (defvar ymh/bib-base-dir "~/Dropbox/bibliography" "Contains the base directory for the bibliography related files.") ;; Define functions using the previous variables and `expand-file-name' to ;; calculate the full path for any file correctly. (defun ymh/expand-org-file (file) "Expand FILE name relative to `ymh/org-base-dir'." (expand-file-name file ymh/org-base-dir)) (defun ymh/expand-bib-file (file) "Expand FILE name relative to `ymh/bib-base-dir'." (expand-file-name file ymh/bib-base-dir)) ;; Set registers for commonly accessed files, especially org-mode files that ;; will be edited a lot. In general, I use `org-capture' to edit the Org files ;; in particular though. (set-register ?l (cons 'file (expand-file-name "init.el" user-emacs-directory))) (set-register ?m (cons 'file (ymh/expand-org-file "meetings.org"))) (set-register ?i (cons 'file (ymh/expand-org-file "inbox.org"))) (set-register ?p (cons 'file (ymh/expand-org-file "projects.org"))) (set-register ?c (cons 'file (ymh/expand-org-file (format-time-string "%Y-%m.org")))) ;; Emacs 29 contains some packages that otherwise need to be downloaded from ;; Melpa, and in addition to that it also allows for the installation of ;; packages using git. (defvar ymh/emacs-29-p (version<= "29" emacs-version) "Checks if the current Emacs version is 29 or not.") ;; There are also some changes that are means for MacOS only, so it's useful to ;; have a flag for that as well. (defvar ymh/macos-p (eq system-type 'darwin) "Checks if the current operating system is MacOS.") ;; Add linker arguments when compiling for macos. (when ymh/macos-p (customize-set-variable 'native-comp-driver-options '("-Wl,-w"))) ;; Load package for general package management. (require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) (package-initialize) ;; For emacs 28 and below install use-package. Use-package allows for neat ;; organisation and loading of packages, allowing you to easily set variables ;; before a package is loaded (in the `:init' section), and allowing you to ;; customise the package after it has been loaded (in the `:config' section). ;; ;; There are many more benefits of using `use-package', but the separation of ;; init and config is important to properly trigger any hooks on customisable ;; variables. If you set variables after the package has been loaded, they may ;; not be properly set using the customisation interface, whereas if they were ;; changed before the load it is as if they had been customised using the ;; interface. (unless (package-installed-p 'use-package) (package-install 'use-package)) (eval-when-compile (require 'use-package)) (require 'bind-key) ;; if you use any :bind variant ;; Load my local library of common emacs functions. (use-package ymh-emacs :load-path "ymh-emacs" :config (define-key ebib-index-mode-map "D" #'ymh-ebib-download-pdf-from-doi)) ;; This is the main configuration block for vanilla emacs. (use-package emacs :custom (blink-matching-paren nil) (completion-category-defaults nil) (completion-ignore-case t) (completion-styles '(substring partial-completion)) (read-buffer-completion-ignore-case t) (read-file-name-completion-ignore-case t) (frame-resize-pixelwise t) :init ;; Remove any warnings from the async compilation. This was bothersome ;; because it would make the warning buffer appear whenever there were any. (setq native-comp-async-report-warnings-errors nil) ;; Customise `isearch' so that it works accross new lines, which is especially ;; useful for searching in documents with hard line breaks. This fixes my one ;; reason for not having hard line breaks as it becomes harder to edit. (setq isearch-lax-whitespace t) (setq isearch-regexp-lax-whitespace t) (setq search-whitespace-regexp "[ \t\r\n]+") (setq isearch-lazy-count t) ;; Set the initial gnus file. (setq gnus-init-file (expand-file-name "gnus.el" user-emacs-directory)) ;; I currently use 80 as the default fill column width as it works on low-res ;; displays as well. (setq-default fill-column 80) (setq completion-cycle-threshold 3) (setq tab-always-indent 'complete) ;; Some simple configurations which make using the interface a bit nicer. (setq use-short-answers t) (setq inhibit-startup-message t) (setq confirm-nonexistent-file-or-buffer nil) (setq ring-bell-function 'ignore) ;; I always end sentences in two spaces so that emacs can detect them easier. (setq sentence-end-double-space t) ;; Follow symlinks when opening a file. (setq find-file-visit-truename t) (setq vc-follow-symlinks t) ;; When you have two dired buffers open, it will copy them from one to the ;; other automatically. (setq dired-dwim-target t) (setq wdired-allow-to-change-permissions t) ;; Some performance improvements because I do not use right-to-left text. (setq truncate-partial-width-windows nil) (setq-default bidi-paragraph-direction 'left-to-right) (if (version<= "27.1" emacs-version) (setq bidi-inhibit-bpa t)) (setq read-extended-command-predicate #'command-completion-default-include-p) (setq enable-recursive-minibuffers t) ;; Clean up backup directories. (defvar --backup-directory) (setq --backup-directory (expand-file-name "backups" user-emacs-directory)) (if (not (file-exists-p --backup-directory)) (make-directory --backup-directory t)) (setq backup-directory-alist `(("^/dev/shm/" . nil) ("^/tmp/" . nil) ("." . ,--backup-directory))) (setq make-backup-files t) (setq backup-by-copying t) (setq version-control t) (setq delete-old-versions t) (setq delete-by-moving-to-trash t) (setq kept-old-versions 6) (setq kept-new-versions 9) (setq auto-save-default t) (setq auto-save-timeout 20) (setq auto-save-interval 200) ;; Setup some options to be able to use changelog mode. (setq add-log-full-name user-full-name) (setq add-log-mailing-address "git@yannherklotz.com") (setq change-log-default-name "CHANGELOG") (add-hook 'change-log-mode-hook (lambda () (make-local-variable 'tab-width) (make-local-variable 'left-margin) (setq tab-width 2 left-margin 2))) ;; Set indentation settings for various languages. (setq-default indent-tabs-mode nil) (setq-default tab-width 4) (setq-default python-indent-offset 4) (setq-default c-basic-offset 4) (setq line-number-display-limit 2000000) ;; Remove the emacs border when on Linux. (unless ymh/macos-p (setq default-frame-alist '((undecorated . t) (drag-internal-border . 1) (internal-border-width . 5)))) (setq auth-sources '("~/.authinfo" "~/.authinfo.gpg" "~/.netrc")) ;; Set visual new line indicators when using `visual-line-mode'. (setq visual-line-fringe-indicators '(left-curly-arrow nil)) :config (unless ymh/macos-p (menu-bar-mode -1)) (tool-bar-mode -1) (scroll-bar-mode -1) (column-number-mode 1) (electric-indent-mode -1) (pixel-scroll-precision-mode +1) (global-hl-line-mode +1) (global-display-fill-column-indicator-mode) (add-hook 'text-mode-hook #'visual-line-mode) (add-hook 'text-mode-hook #'auto-fill-mode) ;; Enable those (dolist (c '(overwrite-mode narrow-to-region narrow-to-page upcase-region downcase-region)) (put c 'disabled nil)) (if ymh/macos-p (progn (set-face-attribute 'default nil :family "Iosevka YMHG" :weight 'semi-bold :height 140) (set-face-attribute 'variable-pitch nil :family "Iosevka YMHG" :weight 'semi-bold :height 140) (set-face-attribute 'fixed-pitch nil :family "Iosevka YMHG" :weight 'semi-bold :height 140)) (set-face-attribute 'default nil :family "Iosevka YMHG" :weight 'semi-bold) (set-face-attribute 'variable-pitch nil :family "Iosevka YMHG" :weight 'semi-bold) (set-face-attribute 'fixed-pitch nil :family "Iosevka YMHG" :weight 'semi-bold)) (add-to-list 'mode-line-misc-info '(t ("[" (:eval (alist-get 'name (tab-bar--current-tab))) "] "))) ;; Mac configuration (when ymh/macos-p (cl-case ymh/keyboard (:white-split (setq mac-right-option-modifier 'hyper mac-command-modifier 'meta mac-option-modifier 'super)) (:modified (setq mac-right-option-modifier 'meta mac-command-modifier 'super mac-option-modifier 'hyper)) (:default (setq mac-right-option-modifier 'hyper mac-command-modifier 'meta mac-option-modifier 'super))) (add-hook 'ns-system-appearance-change-functions #'ymh/apply-theme))) ;; Display the time in the mode line (use-package time :custom (display-time-24hr-format t) (display-time-default-load-average nil) (display-time-day-and-date nil) :init (display-time-mode +1)) (use-package whitespace :config (defun ymh/add-hook-before-save-hook () "Add a before-save hook for whitespace cleanup." (add-hook 'before-save-hook #'whitespace-cleanup 0 :local)) (add-hook 'text-mode-hook #'ymh/add-hook-before-save-hook) (add-hook 'dafny-mode-hook #'ymh/add-hook-before-save-hook)) (use-package company :ensure t :bind (:map company-mode-map ("M-n" . company-complete-common-or-cycle)) :hook scala-mode :custom (company-idle-delay nil)) (use-package shr :custom (shr-use-fonts nil) (shr-max-image-proportion 0.5)) (use-package exec-path-from-shell :ensure t :custom (exec-path-from-shell-arguments '("-l")) :config (when (memq window-system '(mac ns x pgtk)) (dolist (var '("SSH_AUTH_SOCK" "SSH_AGENT_PID" "GPG_AGENT_INFO" "LANG" "LC_CTYPE" "NIX_SSL_CERT_FILE" "NIX_PATH")) (add-to-list 'exec-path-from-shell-variables var)) (exec-path-from-shell-initialize))) (use-package browse-url :custom (browse-url-handlers '(("wikipedia\\.org" . eww-browse-url) ("yannherklotz\\.com" . eww-browse-url) ("ymhg\\.org" . eww-browse-url) ("archlinux\\.org" . eww-browse-url) ("sachachua\\.com" . eww-browse-url) ("comonad\\.com" . eww-browse-url) ("drewdevault\\.com" . eww-browse-url) ("wordpress\\.com" . eww-browse-url) ("mathbabe\\.org" . eww-browse-url) ("ethz\\.ch" . eww-browse-url) ("pragmaticemacs\\.com" . eww-browse-url)))) (use-package message :custom (message-send-mail-function 'message-send-mail-with-sendmail) (message-fill-column 80) (message-signature "Yann Herklotz Imperial College London https://yannherklotz.com")) (use-package ispell :custom (ispell-dictionary "en_GB")) (use-package delight :ensure t :config (delight 'auto-revert-mode nil "autorevert") (delight 'eldoc-mode nil "eldoc")) (use-package project :demand t :bind (:map project-prefix-map ("m" . magit-project-status)) :custom (project-switch-commands '((project-find-file "Find file") (project-find-regexp "Find regexp") (project-find-dir "Find directory") (project-vc-dir "VC-Dir") (magit-project-status "Magit") (project-eshell "Eshell")))) (use-package tab-bar :demand t :after project :bind (:map tab-prefix-map ("D" . toggle-frame-tab-bar) ("p" . ymh-tabs-switch-project)) :custom (tab-bar-show nil) (tab-bar-select-tab-modifiers '(meta)) (tab-bar-new-tab-choice "*scratch*") :init (tab-bar-mode 1)) (use-package flyspell :config (unbind-key "C-." flyspell-mode-map) (unbind-key "C-," flyspell-mode-map) (setq flyspell-mouse-map (make-sparse-keymap))) (use-package calc-forms :config (add-to-list 'math-tzone-names '("AOE" 12 0)) (add-to-list 'math-tzone-names '("IST" (float -55 -1) 0))) (use-package calendar :custom (calendar-mark-diary-entries-flag t) (calendar-mark-holidays-flag t) (calendar-mode-line-format nil) (calendar-time-display-form '(24-hours ":" minutes (when time-zone (format "(%s)" time-zone)))) (calendar-week-start-day 1) ; Monday (calendar-date-style 'iso) (calendar-date-display-form calendar-iso-date-display-form) (calendar-time-zone-style 'numeric) ; Emacs 28.1 :config (add-hook 'calendar-today-visible-hook #'calendar-mark-today) (remove-hook 'calendar-mode-hook #'org--setup-calendar-bindings) (let ((map calendar-mode-map)) (define-key map (kbd "s") #'calendar-sunrise-sunset) (define-key map (kbd "l") #'lunar-phases) (define-key map (kbd "i") nil) (define-key map (kbd "i a") #'diary-insert-anniversary-entry) (define-key map (kbd "i c") #'diary-insert-cyclic-entry) (define-key map (kbd "i d") #'diary-insert-entry) ; for current "day" (define-key map (kbd "i m") #'diary-insert-monthly-entry) (define-key map (kbd "i w") #'diary-insert-weekly-entry) (define-key map (kbd "i y") #'diary-insert-yearly-entry) (define-key map (kbd "M-n") #'calendar-forward-month) (define-key map (kbd "M-p") #'calendar-backward-month))) (use-package cal-dst :custom (calendar-standard-time-zone-name "+0000") (calendar-daylight-time-zone-name "+0100")) (use-package diary-lib :custom (diary-file (ymh/expand-org-file "archive/diary")) (diary-date-forms diary-iso-date-forms) (diary-comment-start ";;") (diary-comment-end "") (diary-nonmarking-symbol "!") (diary-show-holidays-flag t) (diary-display-function #'diary-fancy-display) (diary-header-line-format nil) (diary-list-include-blanks nil) (diary-number-of-entries 2) (diary-mail-days 2) (diary-abbreviated-year-flag nil) ;;(add-hook 'diary-list-entries-hook #'diary-fix-timezone t) :config (add-hook 'diary-list-entries-hook #'diary-sort-entries t) (add-hook 'diary-list-entries-hook 'diary-include-other-diary-files) (add-hook 'diary-mark-entries-hook 'diary-mark-included-diary-files)) (use-package appt :custom (appt-display-diary nil) (appt-disp-window-function #'appt-disp-window) ;; 'window (appt-display-mode-line t) (appt-display-interval 5) (appt-audible nil) (appt-warning-time-regexp "appt \\([0-9]+\\)") (appt-message-warning-time 15) :config ;; (defun ymh/org-agenda-to-appt () ;; (org-agenda-to-appt t '((category "meeting"))) ;; (appt-check)) ;; (appt-activate t) ;; (ymh/org-agenda-to-appt) ;; (run-at-time "00:01" nil #'ymh/org-agenda-to-appt) ;; (setq appt-disp-window-function (function my-appt-disp-window)) ;;(defun my-appt-disp-window (min-to-app new-time msg) ;; (save-window-excursion (shell-command (concat ;; "/usr/bin/zenity --info --title='Appointment' --text='" ;; msg ;; "' &" ;; ) nil nil) ;; )) ) (use-package savehist :init (savehist-mode)) (use-package ef-themes :ensure t :config ;;(load-theme 'ef-dark t) ) (use-package modus-themes :ensure t :bind (("" . modus-themes-toggle)) :demand t :custom (modus-themes-common-palette-overrides '((bg-mode-line-active bg-green-subtle) (border-mode-line-active bg-green-subtle) (bg-mode-line-inactive bg-green-nuanced) (border-mode-line-inactive bg-green-nuanced) (fg-region unspecified) (bg-region bg-green-subtle) (fringe unspecified) (bg-line-number-active bg-hl-line) (bg-line-number-inactive unspecified) (fg-line-number-active fg-main) (bg-hl-line bg-dim) (cursor magenta-intense))) (modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted)) (modus-themes-italic-constructs t) (defface modus-themes-variable-pitch) :config (defun ymh-modus-theme-apply-customisations () (modus-themes-with-colors (custom-set-faces `(proof-locked-face ((,c :background ,bg-green-nuanced :extend t))) `(proof-queue-face ((,c :background ,bg-magenta-nuanced :extend t))) `(proof-warning-face ((,c :inherit modus-themes-subtle-yellow))) `(coq-solve-tactics-face ((,c :inherit modus-themes-fg-red))) `(coq-cheat-face ((,c :inherit modus-themes-intense-red :box (:line-width -1 :color ,bg-red-intense :style nil)))) `(fill-column-indicator ((,c :background unspecified :height unspecified)))))) (add-hook 'modus-themes-after-load-theme-hook #'ymh-modus-theme-apply-customisations) (modus-themes-load-theme 'modus-operandi-tinted) (ymh-modus-theme-apply-customisations)) (use-package catppuccin-theme :ensure t :custom (catppuccin-flavor 'mocha) :init (defun ymh/catppuccin-fix-colours () (let ((c '((class color) (min-colors 256))) (mod-col (if (eq catppuccin-flavor 'latte) #'catppuccin-lighten #'catppuccin-darken))) (custom-set-faces `(proof-locked-face ((,c :background ,(funcall mod-col (catppuccin-get-color 'teal) 80) :extend t))) `(proof-queue-face ((,c :background ,(funcall mod-col (catppuccin-get-color 'maroon) 80) :extend t))) `(proof-warning-face ((,c :foreground ,(catppuccin-get-color 'yellow)))) `(coq-solve-tactics-face ((,c :foreground ,(catppuccin-get-color 'red)))) `(coq-cheat-face ((,c :foreground ,(catppuccin-get-color 'red) :box (:line-width -1 :color ,(catppuccin-get-color 'red) :style nil))))))) (defun ymh/catppuccin-toggle () (interactive) (if (eq catppuccin-flavor 'latte) (setq catppuccin-flavor 'mocha) (setq catppuccin-flavor 'latte)) (ymh/catppuccin-fix-colours) (catppuccin-reload))) (use-package pass :ensure t :bind (:map ymh-map ("q" . password-store-otp-token-copy) ("p" . password-store-copy) ("i" . password-store-insert) ("g" . password-store-generate))) (use-package magit :ensure t :custom (magit-diff-refine-hunk t)) (use-package org :custom (org-reverse-note-order t) (org-adapt-indentation nil) (org-attach-auto-tag "attach") (org-confirm-babel-evaluate nil) (org-cycle-separator-lines 2) (org-export-with-broken-links t) (org-fast-tag-selection-single-key 'expert) (org-hide-emphasis-markers nil) (org-html-container-element "section") (org-html-doctype "html5") (org-html-head-include-default-style nil) (org-html-head-include-scripts nil) (org-html-html5-fancy t) (org-html-postamble t) (org-html-postamble-format '(("en" ""))) (org-icalendar-include-bbdb-anniversaries t) (org-icalendar-include-todo t) (org-log-done 'time) (org-log-into-drawer t) (org-return-follows-link t) (org-reverse-note-order t) (org-src-window-setup 'current-window) (org-startup-folded 'content) (org-startup-indented nil) (org-use-speed-commands t) (org-html-divs '((preamble "header" "header") (content "article" "content") (postamble "footer" "postamble"))) (org-structure-template-alist '(("a" . "export ascii") ("c" . "center") ("C" . "comment") ("e" . "example") ("E" . "export") ("h" . "export html") ("l" . "export latex") ("q" . "quote") ("s" . "src") ("v" . "verse") ("el" . "src emacs-lisp") ("d" . "definition") ("t" . "theorem"))) (org-refile-targets `((,(ymh/expand-org-file "main.org") :level . 1) (,(ymh/expand-org-file "someday.org") :level . 1) (,(ymh/expand-org-file "projects.org") :maxlevel . 2) (,(ymh/expand-org-file (format-time-string "%Y-%m.org")) :level . 1))) (org-todo-keywords '((sequence "TODO(t)" "PROJ(p)" "STRT(s)" "WAIT(w)" "HOLD(h)" "DELG(l)" "SMDY(m)" "|" "DONE(d!)" "KILL(k)") (sequence "[ ](T)" "[-](S)" "[?](W)" "|" "[X](D)"))) (org-todo-keyword-faces '(("[-]" . "yellow") ("STRT" . (:background "aquamarine")) ("[?]" . (:weight bold)) ("WAIT" . "yellow") ("HOLD" . "yellow") ("DELG" . "goldenrod") ("SMDY" . "cadet blue") ("PROJ" . (:background "sea green" :weight bold)) ("NO" . (:background "dark salmon")) ("KILL" . "pale green"))) (org-export-allow-bind-keywords t) (org-cite-global-bibliography (list (ymh/expand-bib-file "references.bib"))) :config (unbind-key "C-," org-mode-map)) (use-package org-agenda :bind ("C-c a" . org-agenda) :custom (org-agenda-files (mapcar #'ymh/expand-org-file (list "inbox.org" "main.org" "tickler.org" "projects.org" "diary.org" (format-time-string "%Y-%m.org")))) (org-agenda-custom-commands '(("w" "At work" tags-todo "@work" ((org-agenda-overriding-header "Work"))) ("h" "At home" tags-todo "@home" ((org-agenda-overriding-header "Home"))) ("u" "At uni" tags-todo "@uni" ((org-agenda-overriding-header "University"))))) (org-agenda-include-diary nil) ;; Do not use diary anymore (org-agenda-show-all-dates t) (org-agenda-skip-deadline-if-done t) (org-agenda-skip-scheduled-if-done t) (org-agenda-span 'week) (org-agenda-start-day ".") (org-agenda-start-on-weekday nil) (org-agenda-tag-filter '("-backed"))) (use-package org-capture :bind ("C-c c" . org-capture) :custom (org-capture-templates `(("t" "Todo" entry (file ,(ymh/expand-org-file "inbox.org")) "* TODO %? :PROPERTIES: :ID: %(org-id-uuid) :END: :LOGBOOK: - State \"TODO\" from \"\" %U :END:" :empty-lines 1) ("l" "Link Todo" entry (file ,(ymh/expand-org-file "inbox.org")) "* TODO %? :PROPERTIES: :ID: %(org-id-uuid) :END: :LOGBOOK: - State \"TODO\" from \"\" %U :END: %a" :empty-lines 1) ("c" "Contacts" entry (file ,(ymh/expand-org-file "contacts.org")) "* %(org-contacts-template-name) :PROPERTIES: :EMAIL: %(org-contacts-template-email) :END:" :empty-lines 1) ("m" "Meeting" entry (id "3d358b7c-e192-42f1-97ec-fd99cf8256b0") "* %? :meeting: %^{Meeting}T " :empty-lines 1) ("b" "Bookmarks for links") ("bl" "Bookmark interesting items" item (file+headline ,(ymh/expand-org-file "links.org") "Interesting links") "- %? ") ("br" "Bookmark for future reading" item (file+headline ,(ymh/expand-org-file "links.org") "To read") "- %? ")))) (use-package org-habit :after org) (use-package org-crypt :after org :custom (org-tags-exclude-from-inheritance '("crypt")) (org-crypt-key "8CEF4104683551E8") :config (org-crypt-use-before-save-magic)) (use-package org-id :after org :custom (org-id-link-to-org-use-id 'use-existing) (org-id-track-globally t)) (use-package org-transclusion :ensure t :after org :bind (("C-c t i" . org-transclusion-add) ("C-c t r" . org-transclusion-remove) ("C-c t R" . org-transclusion-remove-all) ("C-c t " . org-transclusion-refresh) ("C-c t m" . org-transclusion-mode)) :custom (org-transclusion-exclude-elements nil)) (use-package org-zettelkasten :after org :ensure t :custom (org-zettelkasten-directory "~/Dropbox/zk") :config (org-zettelkasten-setup)) (use-package pdf-tools :ensure t :config (pdf-tools-install)) (use-package flycheck :ensure t :delight flycheck-mode) (use-package rst :ensure t) (use-package boogie-friends :ensure t :custom ;; (setq flycheck-inferior-dafny-executable "/Users/ymh/.local/dafny-4.0/DafnyServer") (dafny-verification-backend nil) (boogie-friends-symbols-alist nil) :config (add-hook 'dafny-mode-hook (lambda () (prettify-symbols-mode -1))) (add-hook 'dafny-mode-hook (lambda () ;;(add-hook 'before-save-hook #'eglot-format 0 :local) (setq fill-column 120)))) (use-package direnv :if (executable-find "direnv") :ensure t :init (direnv-mode 1)) (use-package vertico :ensure t :init (vertico-mode 1)) (use-package consult :ensure t :bind (("M-s r" . consult-ripgrep) ("M-s g" . consult-git-grep) ("C-h a" . consult-apropos) ("M-s m" . consult-man) ("M-s h" . consult-org-heading))) (use-package dabbrev ;; Swap M-/ and C-M-/ :bind (("M-/" . dabbrev-completion) ("C-M-/" . dabbrev-expand)) ;; Other useful Dabbrev configurations. :custom (dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'"))) (use-package sendmail :ensure t :custom (mail-specify-envelope-from t) (message-sendmail-envelope-from 'header) (mail-envelope-from 'header) :config (if ymh/macos-p (setq sendmail-program "/usr/local/bin/msmtp") (setq sendmail-program "/usr/bin/msmtp"))) (use-package notmuch :ensure t :demand t :bind (("C-x m" . notmuch-mua-new-mail)) :config (defun ymh/notmuch-search-delete-mail (&optional beg end) "Delete a message." (interactive (notmuch-interactive-region)) (if (member "deleted" (notmuch-search-get-tags)) (notmuch-search-tag (list "-deleted")) (progn (notmuch-search-tag (list "+deleted" "-unread") beg end) (notmuch-search-next-thread)))) (defun ymh/notmuch () "Delete a message." (interactive) (let ((tab (tab-bar--tab-index-by-name "*MAIL*"))) (if tab (tab-bar-select-tab (1+ tab)) (progn (tab-bar-new-tab-to) (tab-bar-rename-tab "*MAIL*") (notmuch))))) (defun ymh/notmuch-show-delete-mail (&optional beg end) "Delete a message." (interactive (notmuch-interactive-region)) (if (member "deleted" (notmuch-show-get-tags)) (notmuch-show-tag (list "-deleted")) (progn (notmuch-show-tag (list "+deleted" "-unread") beg end) (notmuch-show-next-thread)))) (setq-default notmuch-search-oldest-first nil) (define-key notmuch-show-mode-map (kbd "d") #'ymh/notmuch-show-delete-mail) (define-key notmuch-search-mode-map (kbd "d") #'ymh/notmuch-search-delete-mail) (global-set-key (kbd "C-c o m") #'ymh/notmuch) (defun ymh/and-search (&rest rest) (apply #'concat (-interpose " and " rest))) (setq notmuch-archive-tags '("-inbox" "-unread" "+archive")) (setq notmuch-saved-searches `((:name "inbox" :key "n" :query ,(ymh/and-search "date:last_month..this_month" "tag:inbox" "not tag:deleted" "tag:unread")) (:name "flagged" :query "tag:flagged" :key "f") (:name "sent" :query "tag:sent" :key "s") (:name "drafts" :query "tag:draft" :key "d") (:name "mailbox" :key ,(kbd "m i") :query ,(ymh/and-search "date:last_month..this_month" "(tag:mailbox and tag:inbox)" "not tag:deleted" "not tag:sent")) (:name "mailbox-unread" :key ,(kbd "m u") :query ,(ymh/and-search "date:last_month..this_month" "(tag:mailbox and tag:inbox)" "not tag:deleted" "not tag:sent" "tag:unread")) (:name "imperial" :key ,(kbd "i i") :query ,(ymh/and-search "date:last_month..this_month" "(tag:imperial and tag:inbox)" "not tag:deleted" "not tag:sent")) (:name "imperial-unread" :key ,(kbd "i u") :query ,(ymh/and-search "date:last_month..this_month" "(tag:imperial and tag:inbox)" "not tag:deleted" "not tag:sent" "tag:unread")) (:name "mailbox-archive" :key ,(kbd "m a") :query ,(ymh/and-search "date:last_month..this_month" "(tag:mailbox and tag:archive)" "not tag:deleted" "not tag:sent")) (:name "imperial-archive" :key ,(kbd "i a") :query ,(ymh/and-search "date:last_month..this_month" "(tag:imperial and tag:archive)" "not tag:deleted" "not tag:sent")) (:name "all recent" :query "date:last_month..this_month" :key "r"))) (setq notmuch-fcc-dirs '(("yann@yannherklotz.com" . "mailbox/Sent -inbox +sent -unread +mailbox -new") ("git@yannherklotz.com" . "mailbox/Sent -inbox +sent -unread +mailbox -new") ("yann.herklotz15@imperial.ac.uk" . "\"imperial/Sent Items\" -inbox +sent -unread +imperial -new"))) (setq +notmuch-home-function (lambda () (notmuch-search "tag:inbox")))) (use-package ol-notmuch :ensure t) (use-package ebib :ensure t :bind (("C-c y b" . ebib) ("C-c i" . ebib-insert-citation)) :custom (ebib-preload-bib-files (list (ymh/expand-bib-file "references.bib"))) (ebib-notes-default-file (ymh/expand-bib-file "bibliography.org")) (ebib-notes-template "* %T\n:PROPERTIES:\n%K\n:NOTER_DOCUMENT: papers/%k.pdf\n:END:\n\n[%C]\n\n%%?\n") (ebib-keywords (ymh/expand-bib-file "keywords.txt")) (ebib-reading-list-file (ymh/expand-bib-file "reading_list.org")) (ebib-notes-storage 'multiple-notes-per-file) :config (defun ymh/ebib-create-identifier (key _) key) (add-to-list 'ebib-notes-template-specifiers '(?k . ymh/ebib-create-identifier)) (add-to-list 'ebib-file-search-dirs (ymh/expand-bib-file "papers")) (if ymh/macos-p (add-to-list 'ebib-file-associations '("pdf" . "open")) (add-to-list 'ebib-file-associations '("pdf" . nil))) (add-to-list 'ebib-citation-commands '(org-mode (("ref" "[cite:@%(%K%,)]") ("text" "[cite/text:@%(%K%,)]")))) (add-to-list 'ebib-citation-commands '(context-mode (("cite" "\\cite[%(%K%,)]") ("authoryear" "\\cite[authoryear][%(%K%,)]") ("authoryears" "\\cite[authoryears][%(%K%,)]") ("entry" "\\cite[entry][%(%K%,)]") ("author" "\\cite[author][%(%K%,)]")))) (advice-add 'bibtex-generate-autokey :around (lambda (orig-func &rest args) (replace-regexp-in-string ":" "" (apply orig-func args)))) ;;(remove-hook 'ebib-notes-new-note-hook #'org-narrow-to-subtree) ) (use-package spell-fu :ensure t :hook (text-mode . spell-fu-mode) :config (add-hook 'spell-fu-mode-hook (lambda () (spell-fu-dictionary-add (spell-fu-get-ispell-dictionary "en_GB")) (spell-fu-dictionary-add (spell-fu-get-ispell-dictionary "de_DE")) (spell-fu-dictionary-add (spell-fu-get-ispell-dictionary "fr_FR")) (spell-fu-dictionary-add (spell-fu-get-personal-dictionary "fr-personal" "~/.aspell.en_GB.pws")) (spell-fu-dictionary-add (spell-fu-get-personal-dictionary "de-personal" "~/.aspell.de_DE.pws")) (spell-fu-dictionary-add (spell-fu-get-personal-dictionary "fr-personal" "~/.aspell.fr_FR.pws"))))) (use-package ledger-mode :ensure t) (use-package geiser :ensure t :config ;;(unbind-key "C-." geiser-mode-map) ;;(unbind-key "C-." geiser-repl-mode-map) ) (use-package geiser-chicken :ensure t :custom (geiser-chicken-binary "chicken-csi")) (use-package haskell-mode :ensure t) (use-package tuareg :ensure t) (use-package proof-general :ensure t :mode ("\\.v\\'" . coq-mode) :custom (proof-splash-enable nil) (proof-auto-action-when-deactivating-scripting 'retract) (proof-delete-empty-windows nil) (proof-multiple-frames-enable nil) (proof-three-window-enable nil) (proof-auto-raise-buffers nil) (coq-compile-before-require nil) (coq-compile-vos t) (coq-compile-parallel-in-background t) (coq-compile-keep-going nil) (coq-compile-quick 'no-quick) (coq-max-background-compilation-jobs 4) (coq-indent-modulestart 0) :config (defun ymh--reset-coq-indentation () "Reset slow indentation." (setq-local indent-line-function #'indent-relative)) (add-hook 'coq-mode-hook #'ymh--reset-coq-indentation t) (define-key coq-mode-map (kbd "C-c TAB") #'smie-indent-line)) (use-package alectryon :ensure t :hook (coq-mode . alectryon-mode) :delight alectryon-mode :config (defun ymh/alectryon-preview () "Display an HTML preview of the current buffer." (interactive) (let* ((html-fname (make-temp-file "alectryon" nil ".html")) (args `("-r" "5" "-" ,html-fname))) (apply #'call-process-region nil nil "rst2html5" nil nil nil args) (message "Compilation complete") (browse-url html-fname))) (define-key alectryon-mode-map (kbd "C-c u t") #'alectryon-toggle) (define-key alectryon-mode-map (kbd "C-c u p") #'ymh/alectryon-preview)) (use-package tex :ensure auctex :mode (("\\.mkiv\\'" . context-mode) ("\\.mkii\\'" . context-mode) ("\\.mkxl\\'" . context-mode)) :custom (TeX-auto-save t) (TeX-parse-self t) (TeX-view-program-selection '((output-pdf "PDF Tools"))) (TeX-source-correlate-start-server t) (TeX-source-correlate-mode t) (TeX-source-correlate-method 'synctex) (reftex-plug-into-AUCTeX t) :init (setq-default TeX-master nil) (setq-default TeX-command-extra-options "-shell-escape") :config (add-hook 'TeX-after-compilation-finished-functions #'TeX-revert-document-buffer) (add-hook 'TeX-mode-hook #'reftex-mode) (add-hook 'TeX-mode-hook #'outline-minor-mode) (add-hook 'LaTeX-mode-hook (lambda () (setq reftex-ref-style-default-list '("Default" "Cleveref")) (define-key LaTeX-mode-map (kbd "$") 'self-insert-command))) ;;(with-eval-after-load 'latex ;; (define-key LaTeX-mode-map ;; " " ;; #'ymh/electric-space)) ) (use-package outline :bind-keymap ("C-c C-'" . outline-mode-prefix-map)) (use-package ox-hugo :ensure t) (use-package ox-gfm :ensure t) (use-package ox-man) (use-package verilog-mode :defer t :mode "\\.sv\\'" :no-require t :config (setq auto-mode-alist (delete '("\\.v\\'" . verilog-mode) auto-mode-alist))) (use-package scala-mode :ensure t :defer t :interpreter ("scala" . scala-mode) :config (add-hook 'scala-mode-hook (lambda () (add-hook 'before-save-hook #'eglot-format 0 :local) (setq fill-column 120)))) (use-package sbt-mode :if (executable-find "sbt") :ensure t :defer t :commands sbt-start sbt-command :config ;; WORKAROUND: https://github.com/ensime/emacs-sbt-mode/issues/31 ;; allows using SPACE when in the minibuffer (substitute-key-definition 'minibuffer-complete-word 'self-insert-command minibuffer-local-completion-map) ;; sbt-supershell kills sbt-mode: https://github.com/hvesalai/emacs-sbt-mode/issues/152 (setq sbt:program-options '("-Dsbt.supershell=false"))) (use-package eglot :if (not ymh/emacs-29-p) :ensure t) (use-package eglot :hook ((scala-mode . eglot-ensure) (dafny-mode . eglot-ensure)) :bind (:map eglot-mode-map ("C-c f d" . eglot-format)) :config (when (executable-find "swipl") (add-to-list 'eglot-server-programs '(prolog-mode . ("swipl" "-g" "use_module(library(lsp_server))." "-g" "lsp_server:main" "-t" "halt" "--" "stdio")))) (when (executable-find "dafny") (add-to-list 'eglot-server-programs '(dafny-mode . ("dafny" "server" "--manual-lemma-induction" "--warn-missing-constructor-parentheses" "--warn-shadowing")))) (when (executable-find "haskell-language-server-wrapper") (add-to-list 'eglot-server-programs '(haskell-mode . ("haskell-language-server-wrapper" "--lsp"))))) (use-package elec-pair :init (electric-pair-mode 1)) (use-package markdown-mode :ensure t) (use-package yaml-mode :ensure t) (use-package ox-texinfo :after org) (use-package ox-beamer :after org) (use-package elfeed :ensure t :custom (elfeed-feeds '(("https://archlinux.org/feeds/news/" linux news) ("https://haskellweekly.news/haskell-weekly.atom" haskell news) ("https://planet.emacsen.org/atom.xml" emacs news) ("https://feeds.feedburner.com/XahsEmacsBlog" blog emacs) ("https://pragmaticemacs.com/feed" blog emacs) ("https://sachachua.com/blog/feed" blog emacs) ("http://comonad.com/reader/feed/" blog haskell) ("https://blog.sumtypeofway.com/rss/" blog haskell) ("https://drewdevault.com/blog/index.xml" blog opensource) ("https://citizen428.net/index.xml" blog opensource) ("https://dataswamp.org/~solene/rss.xml" blog opensource) ("https://yannherklotz.com/index.xml" blog yann) ("https://www.math.columbia.edu/~woit/wordpress/?feed=atom" blog math) ("https://terrytao.wordpress.com/feed/" blog math) ("https://mathbabe.org/feed/" blog math) ("https://lamington.wordpress.com/feed/atom/" blog math) ("https://totallydisconnected.wordpress.com/feed/atom/" blog math) ("https://blogs.ethz.ch/kowalski/category/blogroll/feed/" blog math) ("https://sbseminar.wordpress.com/feed/" blog math) ("https://krystalguo.com/?feed=rss2" blog math) ("https://scottaaronson.blog/?feed=rss2" blog math) ("https://hnrss.org/frontpage" news) ("https://lawrencecpaulson.github.io/feed" blog math logic))) :init (setq-default elfeed-search-filter "@1-month-ago +unread ")) (use-package markdown-mode :ensure t) (use-package darkroom :ensure t :bind (:map ymh-map ("d" . darkroom-mode)) ;; :hook (text-mode . darkroom-tentative-mode) :custom (darkroom-text-scale-increase 1 "Increase the size of the text less.")) (use-package org-ql :ensure t) (use-package agda2-mode :if (executable-find "agda-mode") :init (load-file (let ((coding-system-for-read 'utf-8)) (shell-command-to-string "agda-mode locate")))) (use-package zig-mode :ensure t) (use-package rust-mode :ensure t) (use-package org-pdftools :ensure t :hook (org-mode . org-pdftools-setup-link)) (use-package circe :ensure t :custom (circe-network-options `(("Sourcehut Chat" :host "chat.sr.ht" :port 6697 :use-tls t :user "ymherklotz/irc.libera.chat" :nick "ymherklotz" :sasl-username "ymherklotz" :sasl-password ,(ymh/pass "sr.ht/chat.sr.ht") ))) (circe-color-nicks-everywhere t) (circe-reduce-lurker-spam t) (circe-active-users-timeout 300) :config (enable-circe-color-nicks)) (use-package flymake :bind (:map flymake-mode-map ("C-c f n" . flymake-goto-next-error) ("C-c f p" . flymake-goto-prev-error) ("C-c f b" . flymake-show-buffer-diagnostics) ("C-c f f" . flymake-mode) ("C-c f l" . flymake-switch-to-log-buffer) ("C-c f s" . flymake-start))) (use-package server :config (server-start)) (use-package nix-mode :ensure t) (use-package merlin :ensure t :hook (tuareg-mode . merlin-mode) :custom (merlin-command "ocamlmerlin")) (use-package citeproc :ensure t :custom (org-cite-csl-styles-dir (expand-file-name "styles" "~/projects"))) (use-package org-super-agenda :ensure t :custom (org-super-agenda-groups '(;; Each group has an implicit boolean OR operator between its selectors. (:name "Today" ; Optionally specify section name :time-grid t ; Items that appear on the time grid :todo "TODAY") ; Items that have this TODO keyword (:name "Important" ;; Single arguments given alone :tag "bills" :priority "A") ;; Set order of multiple groups at once (:order-multi (2 (:name "Shopping in town" ;; Boolean AND group matches items that match all subgroups :and (:tag "shopping" :tag "@town")) (:name "Food-related" ;; Multiple args given in list with implicit OR :tag ("food" "dinner")) (:name "Personal" :habit t :tag "personal") (:name "Space-related (non-moon-or-planet-related)" ;; Regexps match case-insensitively on the entire entry :and (:regexp ("space" "NASA") ;; Boolean NOT also has implicit OR between selectors :not (:regexp "moon" :tag "planet"))))) ;; Groups supply their own section names when none are given (:todo "WAITING" :order 8) ; Set order of this section (:todo ("SOMEDAY" "TO-READ" "CHECK" "TO-WATCH" "WATCHING") ;; Show this group at the end of the agenda (since it has the ;; highest number). If you specified this group last, items ;; with these todo keywords that e.g. have priority A would be ;; displayed in that group instead, because items are grouped ;; out in the order the groups are listed. :order 9) (:priority<= "B" ;; Show this section after "Today" and "Important", because ;; their order is unspecified, defaulting to 0. Sections ;; are displayed lowest-number-first. :order 1) ;; After the last group, the agenda will display items that didn't ;; match any of these groups, with the default order position of 99 )) :init (org-super-agenda-mode 1)) (use-package bbdb :ensure t :custom (bbdb-phone-style 'none "Remove American style for phone numbers.") (bbdb-file (ymh/expand-org-file "bbdb") "Sync bbdb file in org repository.")) (use-package bbdb-vcard :ensure t) (use-package lua-mode :ensure t) (use-package ox-context :ensure t :vc (:url "https://github.com/Jason-S-Ross/ox-context" :rev "main") :config (add-to-list 'org-context-snippets-alist '("ymh-abstract" . "\\definestartstop [abstract] [before={\\midaligned{\\bf Abstract} \\startnarrower[2*middle]}, after={\\stopnarrower \\blank[big]}]")) (add-to-list 'org-context-snippets-alist '("ymh-colours" . "\\definecolor[red] [darkred] \\definecolor[green] [darkgreen] \\definecolor[blue] [darkblue] \\definecolor[yellow] [darkyellow] \\definecolor[magenta][darkmagenta] \\definecolor[cyan] [darkcyan] \\definecolor[maincolor] [darkcyan] \\definecolor[extracolor][darkmagenta] \\setuptyping [color=extracolor] \\setuptype [color=extracolor] \\setuphead [chapter] [color=maincolor] \\setuphead [section] [color=maincolor] \\setuphead [subsection] [color=maincolor] \\setuphead [subsubsection][color=maincolor]")) (add-to-list 'org-context-snippets-alist '("ymh-fonts" . "\\definefontfeature[default] [mode=node,kern=yes, liga=yes,tlig=yes,dlig=yes,hlig=no,calt=yes, ccmp=yes,language=dflt, protrusion=quality, expansion=quality] %\\definefontfeature[default][default][protrusion=quality,expansion=quality] \\setupalign[hz,hanging,lesshyphenation,verytolerant] \\setupbodyfont[libertinus,12pt]")) (add-to-list 'org-context-snippets-alist '("ymh-bib" . "\\usebtxdefinitions[aps] \\setupbtx[default:cite][alternative=authoryear]")) (add-to-list 'org-context-snippets-alist '("ymh-interaction" . "\\setupinteraction[ color=maincolor, contrastcolor=maincolor, openaction=ToggleViewer, focus=height, click=yes, style=\\rm, ]")) (add-to-list 'org-context-snippets-alist '("ymh-titleframed" . "\\defineframed [titlepageframed] [frame=off,align=middle]")) (add-to-list 'org-context-snippets-alist '("ymh-first-noheader" . "\\definelayout[1][header=0px] \\definelayout[2][reset]")) (add-to-list 'org-context-inner-templates-alist '("ymh-article" . "\\startalignment[middle] \\dontleavehmode \\titlepageframed[foregroundstyle=\\ss\\bfd\\setupinterlinespace] {\\documentvariable{metadata:title}} \\par \\dontleavehmode \\titlepageframed[foregroundstyle=\\ss\\rmb\\setupinterlinespace] {\\documentvariable{metadata:author}} \\par \\stopalignment %t %f %c %a %i %b %o")) (add-to-list 'org-context-presets-alist '("ymh-article" . (:literal "\\usemodule[art-01]" :template "ymh-article" :snippets ("ymh-abstract" "ymh-colours" "ymh-fonts" "ymh-bib" "ymh-interaction" "ymh-titleframed" "ymh-first-noheader"))))) (use-package dune :ensure t) (use-package spacious-padding :ensure t :config (spacious-padding-mode 1)) (use-package avy :ensure t :bind (;; The char-timer is a useful command that lets you type as many ;; prefixes for the place that you want to jump to as you want, and ;; after a timeout will either go to that place if it is unique, or ;; give avy characters for each duplicate location. ("M-o" . avy-goto-char-timer)) :custom ;; Add colemak friendly keys for avy to use. (avy-keys '(97 114 115 116 100 104 110 101 105 111))) (setq gc-cons-threshold (* 1024 1024 10)) (provide 'init) ;;; init.el ends here