;;; 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 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 "M-SPC") (lambda () (interactive) (insert " "))) (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) (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)) ;; 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 :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]+") ;; 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) (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)) (set-frame-font "Iosevka YMHG Semibold-14" nil t) (setq auto-mode-alist (append (list ;;'("\\.\\(vcf\\|gpg\\)\\'" . sensitive-minor-mode) '("\\.v\\'" . coq-mode) '("\\.mkiv\\'" . context-mode) '("\\.mkii\\'" . context-mode) '("\\.mkxl\\'" . context-mode)) auto-mode-alist)) (add-to-list 'mode-line-misc-info '(t ("[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 :init (setq display-time-24hr-format t) (setq display-time-default-load-average nil) (setq display-time-day-and-date t) :config (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 :init (setq company-idle-delay nil)) (use-package shr :init (setq shr-use-fonts nil) (setq shr-max-image-proportion 0.5)) (use-package exec-path-from-shell :ensure t :init (setq exec-path-from-shell-arguments '("-l")) :config (when (memq window-system '(mac ns x)) (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 :init (setq 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 :init (setq message-send-mail-function 'message-send-mail-with-sendmail) (setq message-fill-column 80) (setq message-signature "Yann Herklotz Imperial College London https://yannherklotz.com")) (use-package ispell :init (setq ispell-dictionary "en_GB")) (use-package delight :ensure t :config (delight 'auto-revert-mode nil "autorevert") (delight 'eldoc-mode nil "eldoc")) (use-package project :init (setq 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"))) :config (define-key project-prefix-map "m" #'magit-project-status)) (use-package tab-bar :bind (("C-x t D" . toggle-frame-tab-bar)) :demand t :init (setq tab-bar-show nil) (setq tab-bar-select-tab-modifiers '(meta)) (setq tab-bar-new-tab-choice "*scratch*") :config (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 :config (setq calendar-mark-diary-entries-flag t) (setq calendar-mark-holidays-flag t) (setq calendar-mode-line-format nil) (setq calendar-time-display-form '(24-hours ":" minutes (when time-zone (format "(%s)" time-zone)))) (setq calendar-week-start-day 1) ; Monday (setq calendar-date-style 'iso) (setq calendar-date-display-form calendar-iso-date-display-form) (setq calendar-time-zone-style 'numeric) ; Emacs 28.1 (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 :config (setq calendar-standard-time-zone-name "+0000") (setq calendar-daylight-time-zone-name "+0100")) (use-package diary-lib :config (setq diary-file (ymh/expand-org-file "diary")) (setq diary-date-forms diary-iso-date-forms) (setq diary-comment-start ";;") (setq diary-comment-end "") (setq diary-nonmarking-symbol "!") (setq diary-show-holidays-flag t) (setq diary-display-function #'diary-fancy-display) (setq diary-header-line-format nil) (setq diary-list-include-blanks nil) (setq diary-number-of-entries 2) (setq diary-mail-days 2) (setq diary-abbreviated-year-flag nil) ;;(add-hook 'diary-list-entries-hook #'diary-fix-timezone t) (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 :init (setq appt-display-diary nil) (setq appt-disp-window-function #'appt-disp-window) (setq appt-display-mode-line t) (setq appt-display-interval 5) (setq appt-audible nil) (setq appt-warning-time-regexp "appt \\([0-9]+\\)") (setq appt-message-warning-time 15) :config (run-at-time 10 nil #'appt-activate 1)) (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 :init (setq modus-themes-common-palette-overrides '((bg-mode-line-active bg-cyan-subtle) (border-mode-line-active bg-cyan-subtle) (bg-mode-line-inactive bg-cyan-nuanced) (border-mode-line-inactive bg-cyan-nuanced) (fg-region unspecified) (bg-region bg-green-subtle))) (setq modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted)) (setq modus-themes-italic-constructs t) :config (add-hook 'modus-themes-after-load-theme-hook (lambda () (modus-themes-with-colors (custom-set-faces `(proof-locked-face ((,c :background ,bg-cyan-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))))))) (modus-themes-load-theme 'modus-vivendi-tinted)) (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 :init (setq magit-diff-refine-hunk t)) (use-package org :init (setq org-adapt-indentation nil) (setq org-attach-auto-tag "attach") (setq org-confirm-babel-evaluate nil) (setq org-cycle-separator-lines 2) (setq org-export-with-broken-links t) (setq org-fast-tag-selection-single-key 'expert) (setq org-hide-emphasis-markers nil) (setq org-html-container-element "section") (setq org-html-doctype "html5") (setq org-html-head-include-default-style nil) (setq org-html-head-include-scripts nil) (setq org-html-html5-fancy t) (setq org-html-postamble t) (setq org-html-postamble-format '(("en" ""))) (setq org-icalendar-include-bbdb-anniversaries t) (setq org-icalendar-include-todo t) (setq org-log-done 'time) (setq org-log-into-drawer t) (setq org-return-follows-link t) (setq org-reverse-note-order t) (setq org-src-window-setup 'current-window) (setq org-startup-folded 'content) (setq org-startup-indented nil) (setq org-use-speed-commands t) (setq org-html-divs '((preamble "header" "header") (content "article" "content") (postamble "footer" "postamble"))) (setq 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"))) (setq 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))) (setq 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)"))) (setq 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"))) (setq org-export-allow-bind-keywords t) :config (unbind-key "C-," org-mode-map)) (use-package org-agenda :bind ("C-c a" . org-agenda) :init (setq org-agenda-files (cons (ymh/expand-bib-file "reading_list.org") (mapcar #'ymh/expand-org-file (list "inbox.org" "main.org" "tickler.org" "projects.org" (format-time-string "%Y-%m.org"))))) (setq 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"))))) (setq org-agenda-include-diary t) (setq org-agenda-show-all-dates t)) (setq org-agenda-skip-deadline-if-done t) (setq org-agenda-skip-scheduled-if-done t) (setq org-agenda-span 'week) (setq org-agenda-start-day ".") (setq org-agenda-start-on-weekday nil) (setq org-agenda-tag-filter '("-backed")) (use-package org-capture :bind ("C-c c" . org-capture) :init (setq 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)))) (use-package org-habit :after org) (use-package org-crypt :after org :config (org-crypt-use-before-save-magic) (setq org-tags-exclude-from-inheritance '("crypt")) (setq org-crypt-key "8CEF4104683551E8")) (use-package org-id :after org :config (setq org-id-link-to-org-use-id 'use-existing) (setq 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)) :config (setq org-transclusion-exclude-elements nil)) (use-package org-zettelkasten :after org :init (unless (package-installed-p 'org-zettelkasten) (if ymh/emacs-29-p (package-vc-install '(org-zettelkasten . (:url "https://git.sr.ht/~ymherklotz/org-zettelkasten"))) (package-install 'org-zettelkasten))) (setq 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 :init ;; (setq flycheck-inferior-dafny-executable "/Users/ymh/.local/dafny-4.0/DafnyServer") (setq dafny-verification-backend nil) (setq 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 :config (direnv-mode)) (use-package orderless :ensure t :init (setq completion-styles '(substring orderless basic))) (use-package vertico :ensure t :init (setq read-file-name-completion-ignore-case t) (setq read-buffer-completion-ignore-case t) (setq completion-ignore-case t) (setq completion-category-defaults nil) (vertico-mode)) (use-package corfu :ensure t :init (global-corfu-mode)) (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 :init (setq mail-specify-envelope-from t) (setq message-sendmail-envelope-from 'header) (setq 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 :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 notmuch-archive-tags '("-inbox" "-unread" "+archive")) (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-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@ymhg.org" . "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 [" . ebib-insert-citation)) :init (defun ymh/ebib-create-identifier (key _) key) (setq ebib-preload-bib-files (list (ymh/expand-bib-file "references.bib"))) (setq ebib-notes-default-file (ymh/expand-bib-file "notes.org")) (setq ebib-notes-template "* %T\n:PROPERTIES:\n%K\n:NOTER_DOCUMENT: papers/%k.pdf\n:END:\n%%?\n") (setq ebib-keywords (ymh/expand-bib-file "keywords.txt")) (setq ebib-reading-list-file (ymh/expand-bib-file "reading_list.org")) (setq ebib-notes-storage 'multiple-notes-per-file) :config (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%,)]")))) (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 :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 :config (setq geiser-chicken-binary "chicken-csi")) (use-package haskell-mode :ensure t) (use-package tuareg :ensure t) (use-package proof-general :ensure t :config (setq proof-splash-enable nil) (setq proof-auto-action-when-deactivating-scripting 'retract) (setq proof-delete-empty-windows nil) (setq proof-multiple-frames-enable nil) (setq proof-three-window-enable nil) (setq proof-auto-raise-buffers nil) (setq coq-compile-before-require nil) (setq coq-compile-vos t) (setq coq-compile-parallel-in-background t) (setq coq-compile-keep-going nil) (setq coq-compile-quick 'no-quick) (setq coq-max-background-compilation-jobs 4) (setq coq-indent-modulestart 0) (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 :delight alectryon-mode :config (when ymh/macos-p (setq alectryon-executable "/nix/store/bvlk3hyrjdgl0sg93rrdr2z71hgza0m9-python3.9-alectryon-1.4.0/bin/alectryon")) (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 :init (setq TeX-auto-save t) (setq TeX-parse-self t) (setq-default TeX-master nil) (setq TeX-view-program-selection '((output-pdf "PDF Tools"))) (setq TeX-source-correlate-start-server t) (setq-default TeX-command-extra-options "-shell-escape") (setq TeX-source-correlate-mode t) (setq TeX-source-correlate-method 'synctex) (setq reftex-plug-into-AUCTeX t) :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")))) ;;(with-eval-after-load 'latex ;; (define-key LaTeX-mode-map ;; " " ;; #'ymh/electric-space)) ) (use-package ox-hugo :ensure t) (use-package ox-gfm :ensure t) (use-package verilog-mode :defer t :no-require t :config (setq auto-mode-alist (delete '("\\.v\\'" . verilog-mode) auto-mode-alist)) (add-to-list 'auto-mode-alist '("\\.sv\\'" . verilog-mode))) (use-package hungry-delete :ensure t :init (setq hungry-delete-join-reluctantly t) :config (global-hungry-delete-mode)) (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 (add-to-list 'eglot-server-programs '(prolog-mode . ("swipl" "-g" "use_module(library(lsp_server))." "-g" "lsp_server:main" "-t" "halt" "--" "stdio"))) (add-to-list 'eglot-server-programs '(dafny-mode . ("dafny" "server" "--manual-lemma-induction" "--warn-missing-constructor-parentheses" "--warn-shadowing")))) (use-package elec-pair :config (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 visual-fill-column :ensure t) (use-package elfeed :ensure t :init (setq-default elfeed-search-filter "@1-month-ago +unread ") (setq 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)))) (use-package markdown-mode :ensure t) (use-package expand-region :ensure t :bind (("M-o" . er/expand-region))) (use-package chess :ensure t :defer t) (use-package darkroom :ensure t :hook (text-mode . darkroom-tentative-mode) :init (setq darkroom-text-scale-increase 1)) (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 bufferlo :init (unless (package-installed-p 'bufferlo) (if ymh/emacs-29-p (package-vc-install '(bufferlo . (:url "https://github.com/florommel/bufferlo"))) (package-install-file (expand-file-name "packages/bufferlo" user-emacs-directory)))) :bind (("C-x b" . bufferlo-switch-to-buffer) ("C-x C-b" . bufferlo-ibuffer) :map ymh-map ("f" . bufferlo-bury)) :demand t :config (bufferlo-mode 1)) (use-package org-pdftools :ensure t :hook (org-mode . org-pdftools-setup-link)) (use-package circe :ensure t :init (setq 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") ))) (setq circe-color-nicks-everywhere t) (setq circe-reduce-lurker-spam t) (setq 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)) (setq gc-cons-threshold (* 1024 1024 10)) (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) (provide 'init) ;;; init.el ends here