;; -*- emacs-lisp -*- ;; (setq debug-on-error t) (require 'package) (setq package-enable-at-startup nil) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) (let ((default-directory "~/.emacs.d/lisp/")) (normal-top-level-add-subdirs-to-load-path)) (package-initialize) ;; Bootstrap `use-package' (unless (package-installed-p 'use-package) (package-refresh-contents) (package-install 'use-package)) (eval-when-compile (require 'use-package)) ;;; General emacs configuration (use-package emacs :init ; executed before package is loaded (fset 'yes-or-no-p 'y-or-n-p) (put 'narrow-to-region 'disabled nil) :hook ; add functions onto hook; only basename needed ((text-mode . turn-on-auto-fill) (before-save . whitespace-cleanup)) :bind ; key bindings (("C-x a r" . align-regexp)) :config ; executed after package is loaded (defadvice ; align-regexp should use spaces. align-regexp (around align-regexp-with-spaces activate) (let ((indent-tabs-mode nil)) ad-do-it)) :custom (inhibit-startup-screen t) (default-input-method "TeX") (user-full-name "Ryan Kavanagh") (user-mail-address "rak@rak.ac") :custom-face (default ((t (:family "Iosevka"))))) (if (string= (system-name) "demeter.rak.ac") (use-package leuven-theme ; nice theme for lecturing / projectors :ensure t :config (load-theme 'leuven t)) (use-package moe-theme :ensure t :after powerline ; must be loaded after for powerline-moe-theme to work :config (moe-dark) (moe-theme-powerline))) (defun single-lines-only () "Replace multiple blank lines with a single one" (interactive) (goto-char (point-min)) (while (re-search-forward "\\(^\\s-*$\\)\n" nil t) (replace-match "\n") (forward-char 1))) (use-package ace-window :ensure t :custom ;; home row keys (aw-keys '(?h ?t ?n ?s ?a ?o ?e ?u ?i ?d)) :bind (("M-o" . ace-window)) :config ;; need to redefine a few of these because the defaults ;; overlap with customized aw-keys (setq aw-dispatch-alist '((?x aw-delete-window "Delete Window") (?m aw-swap-window "Swap Windows") (?M aw-move-window "Move Window") (?c aw-copy-window "Copy Window") (?j aw-switch-buffer-in-window "Select Buffer") (?f aw-flip-window) (?p aw-switch-buffer-other-window "Switch Buffer Other Window") (?c aw-split-window-fair "Split Fair Window") (?v aw-split-window-vert "Split Vert Window") (?b aw-split-window-horz "Split Horz Window") (?1 delete-other-windows "Delete Other Windows") (?? aw-show-dispatch-help)))) (use-package aggressive-indent :ensure t :config (global-aggressive-indent-mode 1)) (use-package autorevert :diminish auto-revert-mode) (use-package avy :ensure t :config (avy-setup-default) :bind (("C-c C-j" . avy-resume) ("C-;" . avy-goto-char))) (use-package beluga-mode :load-path "~/.opam/default/.opam-switch/sources/beluga/tools/" :mode "\\.bel\'") (use-package bibtex :mode ("\\.bib\'" . bibtex-mode) :custom (bibtex-dialect 'biblatex) (bibtex-maintain-sorted-entries 'crossref) ;; Use only the first author name if there are more than 2 authors (bibtex-autokey-names 1) ;; Otherwise use both names (bibtex-autokey-names-stretch 1) (bibtex-autokey-name-separator "_") (bibtex-autokey-name-year-separator "_") (bibtex-autokey-year-length 4) (bibtex-autokey-year-title-separator ":_") (bibtex-autokey-titleword-length 5) (bibtex-autokey-titlewords 3) ;; Make all title words lowercase (bibtex-autokey-preserve-case 1) :bind (:map bibtex-mode-map ("C-c C-c" . org-ref-clean-bibtex-entry) ("C-c s" . bibtex-sort-buffer)) :config (defun my/bibtex-generate-autokey (autogenerated) (let ((key (bibtex-autokey-get-field "_key"))) (if (string= "" key) autogenerated key))) (advice-add 'bibtex-generate-autokey :filter-return #'my/bibtex-generate-autokey) ;; stolen from bibtex.el and modified to handle "Mac Lane" (defun my/bibtex-autokey-demangle-name (fullname) "Get the last part from a well-formed FULLNAME and perform abbreviations." (let* (case-fold-search (name (cond ((string-match "\\(\\(Ma?c\\|De\\) +[[:upper:]][^, ]*\\)[^,]*," fullname) ;; Name is of the form "Mac Last, First" or ;; "Mac Last, Jr, First" or "Mc Last, First" or ;; "Mc Last, Jr, First" ;; --> Take Mac Last or Mc Last, as appropriate ;; and replace spaces by concatenation (let ((mclast (match-string 1 fullname))) (when (string-match split-string-default-separators mclast) (replace-match "" nil nil mclast)))) ((string-match "\\([[:upper:]][^, ]*\\)[^,]*," fullname) ;; Name is of the form "von Last, First" or ;; "von Last, Jr, First" ;; --> Take the first capital part before the comma (match-string 1 fullname)) ((string-match "\\([^, ]*\\)," fullname) ;; Strange name: we have a comma, but nothing capital ;; So we accept even lowercase names (match-string 1 fullname)) ((string-match "\\(\\<[[:lower:]][^ ]* +\\)+\\([[:upper:]][^ ]*\\)" fullname) ;; name is of the form "First von Last", "von Last", ;; "First von von Last", or "d'Last" ;; --> take the first capital part after the "von" parts (match-string 2 fullname)) ((string-match "\\([^ ]+\\) *\\'" fullname) ;; name is of the form "First Middle Last" or "Last" ;; --> take the last token (match-string 1 fullname)) (t (error "Name `%s' is incorrectly formed" fullname))))) (funcall bibtex-autokey-name-case-convert-function (bibtex-autokey-abbrev name bibtex-autokey-name-length)))) (advice-add 'bibtex-autokey-demangle-name :override 'my/bibtex-autokey-demangle-name) ;; Until https://debbugs.gnu.org/cgi/bugreport.cgi?bug=36252 gets fixed (defun bibtex-autokey-get-year () "Return year field contents as a string obeying `bibtex-autokey-year-length'. If the year field is absent, extract the year from a valid ISO8601-2 Extended Format date in the date field and return it as a string obeing `bibtex-autokey-year-length'." (let ((yearfield (bibtex-autokey-get-field "year")) (datefield (bibtex-autokey-get-field "date")) (shortener (lambda (year) (substring year (max 0 (- (length year) bibtex-autokey-year-length)))))) (if (string= "" yearfield) (cond ((string-match "[./]*\\(-?[[:digit:]]+X*\\)\\([-/.[:digit:]:T~?%X]*\\)" datefield) ;; Matches ISO8601-2 Extended Format specification level 1 ;; examples listed in tables 3, 4, and 5 on pp. 38-40 of the ;; biblatex package manual, version 3.12 (funcall shortener (match-string 1 datefield))) (t (error "Date field `%s' is incorrectly formed" datefield))) (funcall shortener yearfield)))) ;; Don't have accented characters in keys (let ((charMap '(;; This list based on Xah Lee's http://ergoemacs.org/emacs/emacs_zap_gremlins.html ;; Case-sensitivity (see bibtex-autokey-name-change-strings) requires us to ;; duplicate everything ("ß" . "ss") ("á\\|à\\|â\\|ä\\|ā\\|ǎ\\|ã\\|å\\|ą\\|ă\\|ạ\\|ả\\|ả\\|ấ\\|ầ\\|ẩ\\|ẫ\\|ậ\\|ắ\\|ằ\\|ẳ\\|ặ" . "a") ("æ" . "ae") ("ç\\|č\\|ć" . "c") ("é\\|è\\|ê\\|ë\\|ē\\|ě\\|ę\\|ẹ\\|ẻ\\|ẽ\\|ế\\|ề\\|ể\\|ễ\\|ệ" . "e") ("í\\|ì\\|î\\|ï\\|ī\\|ǐ\\|ỉ\\|ị" . "i") ("ñ\\|ň\\|ń" . "n") ("ó\\|ò\\|ô\\|ö\\|õ\\|ǒ\\|ø\\|ō\\|ồ\\|ơ\\|ọ\\|ỏ\\|ố\\|ổ\\|ỗ\\|ộ\\|ớ\\|ờ\\|ở\\|ợ" . "o") ("ú\\|ù\\|û\\|ü\\|ū\\|ũ\\|ư\\|ụ\\|ủ\\|ứ\\|ừ\\|ử\\|ữ\\|ự" . "u") ("ý\\|ÿ\\|ỳ\\|ỷ\\|ỹ" . "y") ("þ" . "th") ("ď\\|ð\\|đ" . "d") ("ĩ" . "i") ("ľ\\|ĺ\\|ł" . "l") ("ř\\|ŕ" . "r") ("š\\|ś" . "s") ("ť" . "t") ("ž\\|ź\\|ż" . "z") ("œ" . "oe") (" " . " ") ; thin space etc ("–" . "-") ("—\\|一" . "--")))) ;; For some reason, *-name-* and *-titleword-* get clobbered, even ;; though the original value in decribe-variable clearly shows ;; them having been based on the extended ;; bibtex-autokey-transcriptions. Force them to be the right ;; thing. (progn (seq-do (lambda (pair) (add-to-list 'bibtex-autokey-transcriptions pair)) charMap) (seq-do (lambda (pair) (add-to-list 'bibtex-autokey-name-change-strings pair)) charMap) (seq-do (lambda (pair) (add-to-list 'bibtex-autokey-titleword-change-strings pair)) charMap)))) (use-package bibtex-completion :ensure ivy-bibtex :custom (bibtex-completion-bibliography "~/Documents/papers/library.bib") (bibtex-completion-library-path '("~/Documents/papers/pdfs/")) (bibtex-completion-notes-path "~/Documents/papers/notes/") (bibtex-completion-notes-extension ".org") (bibtex-completion-pdf-extension '(".pdf" ".djvu" ".txt"))) (use-package cc-mode :custom (c-default-style "bsd")) (use-package company :ensure t :diminish :bind ("" . company-indent-or-complete-common) :hook (after-init . global-company-mode)) (use-package company-auctex :ensure t :after latex :config (company-auctex-init)) (use-package company-bibtex :ensure t :hook (bibtex-mode . (lambda () (add-to-list 'company-backends 'company-bibtex)))) (use-package company-box :ensure t :diminish :hook (company-mode . company-box-mode)) (use-package company-coq :ensure t :hook (coq-mode . company-coq-mode)) (use-package company-math :ensure t :config (add-to-list 'company-backends 'company-math-symbols-unicode) (add-to-list 'company-backends 'company-latex-commands)) (use-package company-org-block :ensure t :hook ((org-mode . (lambda () (setq-local company-backends '(company-org-block)) (company-mode +1))))) (use-package counsel :ensure t :bind (("C-x b" . counsel-switch-buffer) ("C-x C-b" . counsel-ibuffer) ("C-x C-f" . counsel-find-file) ("M-x" . counsel-M-x) ("M-y" . counsel-yank-pop) (" i" . counsel-info-lookup-symbol) (" j" . counsel-set-variable) (" u" . counsel-unicode-char)) :config (add-to-list 'ivy-initial-inputs-alist '(counsel-M-x . ""))) (use-package cus-edit :custom (custom-file null-device "Don't store customizations")) (use-package diary :ensure diary-lib :custom (diary-display-function 'diary-fancy-display) :hook ((diary-list-entries . diary-include-other-diary-files) (diary-list-entries . diary-sort-entries))) (use-package dictem) (use-package diminish :ensure t) (use-package doi-utils ;; provided by org-ref :ensure org-ref) (use-package dtrt-indent :ensure t) (use-package dune :ensure t) (use-package dune-format :ensure t) (use-package eldoc :diminish) (use-package elpher :ensure t) (use-package elpy :ensure t :after python :config (elpy-enable) :custom (elpy-rpc-python-command "python3")) (use-package ess :ensure t) (use-package fill-column-indicator :ensure t) (use-package flyspell :bind (("" . flyspell-auto-correct-previous-word)) :config (unbind-key "C-;" flyspell-mode-map)) (use-package flyspell-correct-ivy :ensure t :after flyspell :bind ("C-" . flyspell-correct-wrapper) :config (setq flyspell-correct-interface #'flyspell-correct-ivy)) (use-package gnus :ensure t :defer t :bind ;; (:map gnus-summary-buffer-map ;; ("SPC" . (gnus-summary-goto-next-page) :custom (gnus-select-method '(nntp "news.club.cc.cmu.edu" (nntp-address "news.club.cc.cmu.edu") (nntp-via-address "news-cclub") (nntp-via-rlogin-command "ssh") (nntp-open-connection-function nntp-open-via-rlogin-and-netcat))) (gnus-home-score-file "gnus.SCORE") (gnus-secondary-select-methods '((nntp "news.gmane.io") (nnimap "imap.rak.ac") (nnimap "mail.cs.mcgill.ca"))) (gnus-parameters '(("^nntp+.*" (address . "rak@rak.ac")) ("^nnimap+imap\\.rak\\.ac:.*" (posting-style (address . "rak@rak.ac") (gcc "nnimap+imap.rak.ac:Sent"))) ("^nnimap+mail\\.cs\\.mcgill\\.ca:.*" (posting-style (address . "rkavanagh@cs.mcgill.ca") (gcc "nnimap+mail.cs.mcgill.ca:INBOX.Sent"))))) (gnus-cloud-method "nnimap:imap.rak.ac") (gnus-cloud-storage-method 'base64) (gnus-cloud-synced-files '("~/.newsrc" "~/.newsrc.eld" (:directory "~/News" :match ".*.SCORE\\'"))) (gnus-update-message-archive-method t) (gnus-message-archive-method '(nnfolder "archive" ; this gets included in the server buffer (nnfolder-inhibit-expiry t) (nnfolder-get-new-mail nil) (nnfolder-active-file "~/News/sent/active") (nnfolder-directory "~/News/sent"))) (gnus-check-new-newsgroups nil) (gnus-group-line-format "%M%S%p%P%5y:%B%(%G%) %z\n") (gnus-topic-display-empty-topics nil) (gnus-posting-styles '((".*" (signature-file "~/.signature")))) :hook (message-send . gnus-score-followup-article) (gnus-group-mode . gnus-topic-mode)) (use-package haskell-mode :ensure t :hook ((haskell-mode . turn-on-haskell-doc-mode) (haskell-mode . turn-on-haskell-indentation))) (use-package info-look :ensure t) (use-package ispell :ensure t :defer t :custom (ispell-dictionary "en_CA-w_accents")) (use-package ivy :ensure t :diminish :bind (("C-c v" . ivy-push-view) ("C-c V" . ivy-pop-view) ("C-c C-r" . ivy-resume)) :custom (ivy-use-virtual-buffers t) (ivy-count-format "(%d/%d) ") :config (ivy-mode 1)) (use-package ivy-bibtex :ensure t :bind (("C-c b" . ivy-bibtex))) (use-package ivy-hydra :ensure t) (use-package latex :ensure auctex :after info-look :mode ("\\.tex\\'" . TeX-latex-mode) :init ;; http://www.cs.au.dk/~abizjak/emacs/2016/03/06/latex-fill-paragraph.html (defun ales/fill-paragraph (&optional P) "When called with prefix argument call `fill-paragraph'. Otherwise split the current paragraph into one sentence per line." (interactive "P") (if (not P) (save-excursion (let ((fill-column 12345678)) ;; relies on dynamic binding (fill-paragraph) ;; this will not work correctly if the paragraph is ;; longer than 12345678 characters (in which case the ;; file must be at least 12MB long. This is unlikely.) (let ((end (save-excursion (forward-paragraph 1) (backward-sentence) (point-marker)))) ;; remember where to stop (beginning-of-line) (while (progn (forward-sentence) (<= (point) (marker-position end))) (just-one-space) ;; leaves only one space, point is after it (delete-char -1) ;; delete the space (newline) ;; and insert a newline (LaTeX-indent-line) ;; I only use this in combination with late, so this makes sense )))) ;; otherwise do ordinary fill paragraph (fill-paragraph P))) :hook ((LaTeX-mode . turn-on-reftex) (LaTeX-mode . turn-off-auto-fill) (LaTeX-mode . turn-on-flyspell) (LaTeX-mode . LaTeX-math-mode) (LaTeX-mode . (lambda () (set (make-local-variable 'TeX-electric-math) (cons "\\(" "\\)")))) (LaTeX-mode . (lambda () (LaTeX-add-environments '("axiom" LaTeX-env-label) '("theorem" LaTeX-env-label) '("proposition" LaTeX-env-label) '("definition" LaTeX-env-label) '("corollary" LaTeX-env-label) '("lemma" LaTeX-env-label) '("example" LaTeX-env-label) '("conjecture" LaTeX-env-label) '("figure" LaTeX-env-label)))) (LaTeX-mode . (lambda () ;; This must be a hook. Trying to set it in :config ;; causes the variable to become buffer-local, so ;; it never actually takes effect in all ;; latex-moded buffers. So much time wasted debugging. (add-to-list 'LaTeX-label-alist '("axiom" . "ax:")) (add-to-list 'LaTeX-label-alist '("conjecture" . "conj:")) (add-to-list 'LaTeX-label-alist '("corollary" . "cor:")) (add-to-list 'LaTeX-label-alist '("definition" . "def:")) (add-to-list 'LaTeX-label-alist '("proposition" . "prop:")) (add-to-list 'LaTeX-label-alist '("theorem" . "theorem:")) (add-to-list 'LaTeX-label-alist '("example" . "ex:")) (add-to-list 'LaTeX-label-alist '("lemma" . "lemma:")) (add-to-list 'LaTeX-label-alist '("figure" . "fig:"))))) :config (info-lookup-add-help :mode 'LaTeX-mode :regexp ".*" :parse-rule "\\\\?[a-zA-Z]+\\|\\\\[^a-zA-Z]" :doc-spec '(("(latex2e)Concept Index") ("(latex2e)Command Index"))) :bind (:map LaTeX-mode-map ("M-q" . ales/fill-paragraph))) (use-package libmpdel ;; used by mpdel to connect to mpd :custom (libmpdel-hostname "asteria.home.arpa")) (use-package magit :ensure t :config (put 'magit-clean 'disabled nil) :custom (magit-diff-refine-hunk 'all)) (use-package markdown-mode :ensure t :init (autoload 'markdown-mode "markdown-mode" "Major mode for editing Markdown files" t) :hook ((markdown-mode . (lambda () (setq-default indent-tabs-mode nil) (setq-default whitespace-style nil)))) :mode (("\\.markdown\\'" . markdown-mode) ("\\.mdown\'" . markdown-mode))) (use-package menu-bar :config (menu-bar-mode -1) :bind ([S-f10] . menu-bar-mode)) (use-package merlin ;; ocaml assistant :ensure t) (use-package message :config (defun message-whitespace-cleanup () "Clean whitespace in message-mode Runs whitespace-cleanup on a message body and signature, while also preserving the space at the end of the '-- ' delimiter between body and signature. This function is dumb and implicitly assumes the existence of a delimiter." (interactive) (save-excursion (save-restriction (widen) (let ((body-min (progn (message-goto-body) (point))) (body-max (progn (message-goto-signature) (previous-line) (point))) (signature-min (progn (message-goto-signature) (point))) (whitespace-style '(trailing))) (progn (narrow-to-region body-min body-max) (whitespace-cleanup) (widen) (narrow-to-region signature-min (point-max)) (whitespace-cleanup)))))) :hook ((message-mode . (lambda () (remove-hook 'before-save-hook 'whitespace-cleanup t))) (message-mode . (lambda () (add-hook 'before-save-hook 'message-whitespace-cleanup nil t)))) :custom (message-citation-line-function 'message-insert-formatted-citation-line) (message-send-mail-function 'message-send-mail-with-sendmail)) (use-package mingus ;; mpd client :custom (mingus-mpd-host "asteria.home.arpa")) (use-package minibuffer :config (add-to-list 'completion-styles 'substring) :custom ;; Cycle through tab-completions with tab if there are less than 5 (completion-cycle-threshold 5)) (use-package mpc ;; mpd client :custom (mpc-host "asteria.home.arpa")) (use-package mpdel ;; mpd client ;; host/port customization under libmpdel package :ensure t :diminish :config (mpdel-mode)) (use-package ocp-indent :ensure t) (use-package octave :mode ("\\.m\'" . octave-mode)) (use-package org :bind (:map org-mode-map ("" . org-cycle)) :hook (org-mode . visual-line-mode) :custom (org-link-file-path-type 'relative)) (use-package org-chef :ensure t) (use-package org-noter :ensure t :custom ;; Surely there's an easier way of setting this? (org-noter-notes-search-path '("~/Documents/papers/notes/"))) (use-package org-ref :ensure t :after ivy-bibtex) (use-package org-ref-arxiv :ensure org-ref :custom (arxiv-entry-format-string "@Misc{%s, title = {%s}, author = {%s}, eprinttype = {arxiv}, date = {%s}, eprint = {%s}, eprintclass = {%s}, abstract = {%s}, pagetotal = {MISSING}, _checked = {NOT CHECKED}, _source = {ev}, }") ;; redefine it to use a sensible date and stuff. ;; my version of arxiv-get-bibtex-entry-via-arxiv-api :config (defun my/arxiv-get-bibtex-entry-via-arxiv-api (arxiv-number) "Retrieve meta data for ARXIV-NUMBER. Returns a formatted BibTeX entry." (with-current-buffer (url-retrieve-synchronously (format "http://export.arxiv.org/api/query?id_list=%s" arxiv-number) t) (let* ((parse-tree (libxml-parse-xml-region (progn (goto-char 0) (search-forward "