#+TITLE:emacs configuration #+AUTHOR: Marco Thomas #+PROPERTY: header-args :tangle "~/.emacs.d/init.el" * Meta ** init.el vs init.org All changes to the configuration should be done in =init.org=, *not* in =init.el=. This is what the initial =init.el= should look like. #+BEGIN_SRC emacs-lisp :tangle no (require 'org) (find-file (concat (getenv "HOME") "/.dots/files/emacs/init.org")) (org-babel-tangle) (load-file (concat (getenv "HOME") "/.emacs.d/init.el")) #+END_SRC ** Startup =lexical-binding= can improve speed. #+BEGIN_SRC emacs-lisp ;;; -*- lexical-binding: t -*- #+END_SRC ** Tangle The =init.el= should (after the first run) mirror the source blocks in the =init.org=. We can use =C-c C-v t= to run =org-babel-tangle=, which extracts the code blocks from the current file into a source-specific file (in this case a =.el=-file). To avoid doing this each time a change is made we can add a function to the =after-save-hook= ensuring to always tangle and byte-compile the =org=-document after changes. #+BEGIN_SRC emacs-lisp (defun tangle-init () (when (equal (buffer-file-name) (expand-file-name (concat (getenv "HOME") "/.dots/files/emacs/init.org"))) ;; Avoid running hooks when tangling. (let ((prog-mode-hook nil)) (org-babel-tangle)))) (add-hook 'after-save-hook 'tangle-init) #+END_SRC ** Performance for start-up A common optimization is to temporarily disable garbage collection during initialization. Here, we set the =gc-cons-threshold= to a ridiculously large number, and restore the default value after initialization. #+BEGIN_SRC emacs-lisp (setq gc-cons-threshold most-positive-fixnum) (add-hook 'emacs-startup-hook (lambda () (setq gc-cons-threshold (* 32 1024 1024)))) #+END_SRC * Configuration ** Performance *** lsp-mode Some optimization for =lsp-mode= #+begin_src emacs-lisp (setq read-process-output-max (* 3 1024 1024)) #+end_src *** Scrolling Disable bidirectional text scanning for a modest performance boost. I've set this to =nil= in the past, but the =bidi-display-reordering='s docs say that is an undefined state and suggest this to be just as good: #+begin_src emacs-lisp (setq-default bidi-display-reordering 'left-to-right bidi-paragraph-direction 'left-to-right) #+end_src Disabling the BPA makes redisplay faster, but might produce incorrect display reordering of bidirectional text with embedded parentheses and other bracket characters whose =paired-bracket= Unicode property is non-nil. Emacs 27+ only. #+begin_src emacs-lisp (setq bidi-inhibit-bpa t) #+end_src Reduce rendering/line scan work for Emacs by not rendering cursors or regions in non-focused windows. #+begin_src emacs-lisp (setq-default cursor-in-non-selected-windows nil) (setq highlight-nonselected-windows nil) #+end_src Emacs "updates" its ui more often than it needs to, so slow it down slightly. Default is 0.5. #+begin_src emacs-lisp (setq idle-update-delay 1.0) #+end_src Introduced in Emacs HEAD (b2f8c9f), this inhibits fontification while receiving input, which should help a little with scrolling performance. #+begin_src emacs-lisp (setq redisplay-skip-fontification-on-input t) #+end_src ** General *** Super general Some defaults, which i forget the reason of using them. #+begin_src emacs-lisp (setq make-backup-files nil auto-mode-case-fold nil auto-save-default nil inhibit-startup-screen t tramp-default-method "ssh" initial-major-mode 'fundamental-mode initial-scratch-message nil fast-but-imprecise-scrolling t) #+end_src *** Short yes/no Answering /yes/ and /no/ to each question from Emacs can be tedious, a single /y/ or /n/ will suffice. #+BEGIN_SRC emacs-lisp (fset 'yes-or-no-p 'y-or-n-p) #+END_SRC *** Quit prompts Make ESC quit prompts. #+begin_src emacs-lisp (global-set-key (kbd "") 'keyboard-escape-quit) #+end_src *** Soft wrap #+begin_src emacs-lisp :tangle no (global-visual-line-mode t) #+end_src ** straight.el (Packages) #+begin_src emacs-lisp (setq straight-check-for-modifications 'live) (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) #+end_src Inhibit =package.el= from loading, as we don't need it. #+begin_src emacs-lisp (setq package-enable-at-startup nil) (straight-use-package 'use-package) #+end_src ** Keybindings *** leader key =general= allows me to use key-binds with a leader key, just like =vim=. #+begin_src emacs-lisp (use-package general :straight t :init (general-create-definer vim-leader-def :prefix "SPC")) #+end_src *** which-key Show me a cool completion bar at the bottom of the screen, with all possible keybindings. #+begin_src emacs-lisp (use-package which-key :straight t :init (which-key-mode) :diminish (which-key-mode) :config (setq which-key-idle-delay 1)) #+end_src *** evil-mode Forgive me, but I'm =evil=. #+begin_src emacs-lisp (use-package evil :straight t :bind (:map evil-motion-state-map ("C-y" . nil)) (:map evil-insert-state-map ("C-y" . nil)) :init ;; so C-z works for background (setq evil-toggle-key "C-~" evil-want-C-d-scroll t evil-want-C-u-scroll t evil-want-integration t evil-want-keybinding nil) :config (evil-mode)) (use-package evil-collection :straight t :after evil :config (evil-collection-init)) (use-package evil-matchit :straight t :after evil :config (global-evil-matchit-mode 1)) #+end_src ** Appearance *** Fonts I mainly use these fonts: + =SFMono Nerd Font Mono= as main mono-spaced (+ Icons) + =JuliaMono= for all other characters + =Noto Emoji= to show emojis in emacs + =Noto JP= for japanese characters #+begin_src emacs-lisp (set-face-attribute 'default nil :font "SFMono Nerd Font" :height 110 :weight 'medium) (set-fontset-font t 'unicode "JuliaMono" nil 'prepend) (set-fontset-font t 'unicode "Noto Color Emoji" nil 'prepend) (set-fontset-font t 'unicode "Noto Sans Mono CJK JP" nil 'append) #+end_src *** Bars I don't need ugly bars. #+begin_src emacs-lisp (menu-bar-mode -1) (tool-bar-mode -1) (scroll-bar-mode -1) #+end_src *** Parenthesis Show me the friend of my parenthesis. #+begin_src emacs-lisp (show-paren-mode t) (setq show-paren-style 'paranthesis) #+end_src *** Line numbers Show me relative line numbers, when in =normal= mode and absolute ones, when in =insert= mode. #+begin_src emacs-lisp (setq-default display-line-numbers 'relative display-line-numbers-widen t ;; this is the default display-line-numbers-current-absolute t) ;; Display absolute numbers, when in normal mode (defun noct:relative () (setq-local display-line-numbers 'relative)) (defun noct:absolute () (setq-local display-line-numbers t)) (add-hook 'evil-insert-state-entry-hook #'noct:absolute) (add-hook 'evil-insert-state-exit-hook #'noct:relative) #+end_src Show me both line and column counter in my bar. #+begin_src emacs-lisp (line-number-mode) (column-number-mode) #+end_src *** Theme Setting my beloved light theme with some icons. #+begin_src emacs-lisp (use-package doom-themes :straight (doom-themes :type git :host github :repo "hlissner/emacs-doom-themes") :config (setq doom-themes-enable-bold t doom-themes-enable-italic t doom-solarized-light-padded-modeline nil) (load-theme 'doom-solarized-light t) (doom-themes-org-config)) #+end_src *** Modeline Use =doom-modeline= as a bar... together with icons and nyan cat! #+begin_src emacs-lisp (use-package doom-modeline :straight t :config (doom-modeline-mode 1) (setq doom-modeline-indent-info t doom-modeline-buffer-file-name-style 'file-name doom-modeline-height 1)) (use-package all-the-icons :straight t) (use-package nyan-mode :straight t :init (nyan-mode) :config (setq nyan-cat-face-number 4 nyan-minimum-window-width 120)) #+end_src *** Inline colors Show me color codes as colors! #+begin_src emacs-lisp (use-package rainbow-mode :straight t :hook (prog-mode . rainbow-mode) (org-mode . rainbow-mode) (c-mode . (lambda() (rainbow-mode -1)))) #+end_src *** Whitespaces Show me trailing white-spaces. #+begin_src emacs-lisp (global-whitespace-mode t) (setq whitespace-style '(face trailing tabs tab-mark)) #+end_src *** ivy Ivy - a generic completion frontend for Emacs. Swiper - isearch with an overview, and more. Oh, man! #+begin_src emacs-lisp (use-package ivy :straight t :diminish :bind (("C-s" . swiper) :map ivy-minibuffer-map ("TAB" . ivy-alt-done) ("C-l" . ivy-alt-done) ("C-j" . ivy-next-line) ("C-k" . ivy-previous-line) :map ivy-switch-buffer-map ("C-k" . ivy-previous-line) ("C-l" . ivy-done) ("C-d" . ivy-switch-buffer-kill) :map ivy-reverse-i-search-map ("C-k" . ivy-previous-line) ("C-d" . ivy-reverse-i-search-kill)) :config (ivy-mode 1)) #+end_src *** counsel Spice up some of those old mini buffers. #+begin_src emacs-lisp (use-package counsel :straight t :bind (("M-x" . counsel-M-x) ("C-x b" . counsel-ibuffer) ("C-x C-f" . counsel-find-file) ("C-x C-g" . counsel-git) :map minibuffer-local-map ("C-r" . 'counsel-minibuffer-history))) #+end_src ** ORG MODE <3 *** Setup and keys Bootstrap =org-mode= together with keybindings. =C-c C-t= for =org-todo=. #+begin_src emacs-lisp (use-package org :straight t :general (vim-leader-def 'normal 'global "oci" 'org-clock-in "oco" 'org-clock-out "ocd" 'org-clock-display "oa" 'org-agenda "oca" 'org-capture "oes" 'org-edit-src-code "oti" 'org-toggle-inline-images "odi" 'org-display-inline-images) :hook (org-mode . (lambda () (electric-indent-local-mode -1))) ;; dont make real spaces at the start of a line (org-mode . org-indent-mode)) ;; add virtual spaces (only visual) #+end_src *** Misc #+begin_src emacs-lisp (setq org-startup-with-inline-images nil ;; start with inline images disabled org-image-actual-width nil ;; rescale inline images org-directory "~/org" ;; set org file directory org-edit-src-content-indentation 0 ;; don't indent stupidly in org-edit-src-code org-log-done nil ;; just mark DONE without a time stamp org-log-repeat nil ;; don't set a time after marking sth DONE org-descriptive-links t ;; Always show links ) #+end_src *** org-todo faces Which =org-todo= keywords should be used and how they look. #+begin_src emacs-lisp (setq org-todo-keywords '((sequence "TODO" "PROGRESS" "REVIEW" "|" "DONE")) org-todo-keyword-faces '(("TODO" . "#cc241d") ("PROGRESS" . "#a6cc70") ("REVIEW" . "#b16286") ("DONE" . "#abb0b6"))) #+end_src *** org-babel Executing code inline is just a breeze. Firstly tho, they must be enabled here. Also be *careful* with =haskell= recursion, it can lead to system crashes (at least for me). #+begin_src emacs-lisp (org-babel-do-load-languages 'org-babel-load-languages '((python . t) (shell . t) (haskell . t) (C . t) (dot . t) (octave . t))) #+end_src *** org-agenda The default =agenda= looks a bit messy. #+begin_src emacs-lisp (use-package org-super-agenda :straight t :after org :config (setq org-super-agenda-groups '((:auto-outline-path t))) (org-super-agenda-mode)) #+end_src Setup some stuff for =agenda= #+begin_src emacs-lisp (setq org-agenda-files (quote ("~/org")) ;; indexed files by org agenda org-agenda-start-on-weekday nil ;; my week starts on a monday calendar-week-start-day 1 ;; my week starts on a monday ) #+end_src I need my =hjkl= :( #+begin_src emacs-lisp (define-key org-agenda-mode-map (kbd "h") 'org-agenda-earlier) (define-key org-agenda-mode-map (kbd "l") 'org-agenda-later) (define-key org-agenda-mode-map (kbd "j") 'org-agenda-next-line) (define-key org-agenda-mode-map (kbd "k") 'org-agenda-previous-line) (define-key org-agenda-mode-map (kbd "t") 'org-agenda-goto-today) (define-key org-super-agenda-header-map (kbd "h") 'org-agenda-earlier) (define-key org-super-agenda-header-map (kbd "l") 'org-agenda-later) (define-key org-super-agenda-header-map (kbd "j") 'org-agenda-next-line) (define-key org-super-agenda-header-map (kbd "k") 'org-agenda-previous-line) (define-key org-super-agenda-header-map (kbd "t") 'org-agenda-goto-today) #+end_src *** org-ref #+begin_src emacs-lisp (use-package org-ref :straight t :after org :init (setq org-ref-completion-library 'org-ref-ivy-cite)) #+end_src *** org-alert #+begin_src emacs-lisp (use-package org-alert :straight t :config (setq alert-default-style 'libnotify) (org-alert-enable)) #+end_src *** LaTeX Export Enable LaTeX export with =pdflatex= and use =minted= for code highlighting. Also fix math =utf8= chars. #+begin_src emacs-lisp (setq org-latex-listings 'minted org-latex-minted-options '(("breaklines" "true") ("breakanywhere" "true") ("bgcolor" "bg")) org-latex-pdf-process '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" "bibtex %b" "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f") org-latex-inputenc-alist '(("utf8" . "utf8x")) org-latex-default-packages-alist (cons '("mathletters" "ucs" nil) org-latex-default-packages-alist) org-format-latex-options (plist-put org-format-latex-options :scale 1)) #+end_src For some reason =\alert= is misinterpreted in LaTeX. #+begin_src emacs-lisp (defun mth/beamer-bold (contents backend info) (when (eq backend 'beamer) (replace-regexp-in-string "\\`\\\\[A-Za-z0-9]+" "\\\\textbf" contents))) #+end_src Use the above fix and disable creating of =.tex= files. #+begin_src emacs-lisp (use-package ox :after org :config (add-to-list 'org-export-filter-bold-functions 'mth/beamer-bold) (add-to-list 'org-latex-logfiles-extensions "tex") (add-to-list 'org-latex-logfiles-extensions "bbl")) #+end_src Use graphivz to draw graphs. #+begin_src emacs-lisp (use-package graphviz-dot-mode :straight t :hook (graphviz-dot-mode . (lambda () (set-input-method "math"))) :config (setq graphviz-dot-indent-width 4)) #+end_src *** Fonts and fancy Some custom fonts stuff. #+begin_src emacs-lisp (setq org-ellipsis " ⮷" ;; folding icon ;; org-hide-emphasis-markers t ;; hide markers such as *, =, _ ) #+end_src I want my =org-bullets= to look fancy, so I'm using some UTF8 chars. Use =(setq inhibit-compacting-font-caches t)=, if performance is low. #+begin_src emacs-lisp (use-package org-superstar :straight t :after org :hook (org-mode . org-superstar-mode) :config (setq org-superstar-remove-leading-stars t org-superstar-headline-bullets-list '(9673 10061 10040))) #+end_src ** General programming tools *** Indentation Use some magic heuristics for indentation. #+begin_src emacs-lisp (use-package dtrt-indent :straight t :hook (prog-mode . dtrt-indent-mode) (text-mode . dtrt-indent-mode) (org-mode . dtrt-indent-mode) (markdown-mode . dtrt-indent-mode)) #+end_src #+begin_src emacs-lisp (setq ; c-default-style "bsd" c-basic-offset 4) (setq-default indent-tabs-mode nil) #+end_src *** Auto pairs Auto matching pairs is nice. #+begin_src emacs-lisp (use-package electric-pair :config (setq electric-pair-open-newline-between-pairs nil) :hook (prog-mode . electric-pair-mode) (text-mode . electric-pair-mode) (org-mode . electric-pair-mode) (markdown-mode . electric-pair-mode)) #+end_src *** =git= =magit= aka most convenient git client, I've ever used. #+begin_src emacs-lisp (use-package magit :straight t :general (vim-leader-def 'normal 'global "gb" 'magit-blame "gc" 'magit-checkout "gc" 'magit-commit "gd" 'magit-diff "gg" 'counsel-git-grep "gi" 'magit-gitignore-in-topdir "gl" 'magit-log "gp" 'magit-push "gs" 'magit-status "gu" 'magit-pull)) #+end_src *** Highlight todo's Sometimes, a big red TODO is more intimidating than one with normal text color. #+begin_src emacs-lisp (use-package hl-todo :straight t :hook (prog-mode . hl-todo-mode) :config (defface hl-todo-TODO '((t :background "#cc241d" :foreground "#ffffff")) "TODO Face") (defface hl-todo-UNUSED '((t :background "#B58900" :foreground "#ffffff")) "TODO Face") (setq hl-todo-highlight-punctuation ":" hl-todo-color-background t hl-todo-keyword-faces '(("TODO" . hl-todo-TODO) ("XXX" . hl-todo-TODO) ("FIXME" . hl-todo-TODO) ("UNUSED" . hl-todo-UNUSED)))) #+end_src ** Code suggestions *** company First of all, we need a backend for our completion and analysis. #+begin_src emacs-lisp (use-package company :straight t :hook (lsp-mode . company-mode) (prog-mode . company-mode) (LaTeX-mode . company-mode) (org-mode . company-mode) :custom (company-minimum-prefix-length 3) (conpany-idle-delay 0.5) :bind (:map company-active-map ("C-j" . company-select-next-or-abort) ("C-k" . company-select-previous-or-abort) ("C-l" . company-complete-selection))) #+end_src Then we can sprinkle in a fancy front-end for it. (only works in GUI emacs) #+begin_src emacs-lisp (use-package company-box :straight t :config (setq company-box-doc-delay 1.0 company-box-max-candidates 10) :hook (company-mode . company-box-mode)) #+end_src *** snippets **** completion Here I use =company= to display snippet recommendations. #+begin_src emacs-lisp (defun company-mode/backend-with-yas (backend) (if (and (listp backend) (member 'company-yasnippet backend)) backend (append (if (consp backend) backend (list backend)) '(:with company-yasnippet)))) (defun company-mode/add-yasnippet () (setq company-backends (mapcar #'company-mode/backend-with-yas company-backends))) #+end_src **** yasnippet #+begin_src emacs-lisp (use-package yasnippet :straight t :init :bind (:map yas-minor-mode-map ("C-y" . yas-expand)) :hook (company-mode . yas-minor-mode) (company-mode . company-mode/add-yasnippet)) #+end_src We also need the actual snippets. #+begin_src emacs-lisp (use-package yasnippet-snippets :straight (yasnippet-snippets :type git :host github :repo "AndreaCrotti/yasnippet-snippets" :fork (:host github :repo "marcothms/yasnippet-snippets")) :after yasnippet) #+end_src ** LSP and language specific settings *** lsp-mode =lsp-mode= is feature-richer than =eglot=, so I'm using this one. #+begin_src emacs-lisp (use-package lsp-mode :straight t :commands (lsp lsp-deferred) :init (setq lsp-keymap-prefix "C-l") :config (lsp-enable-which-key-integration t) (setq lsp-auto-guess-root t lsp-idle-delay 1 lsp-enable-file-watchers nil lsp-headerline-breadcrumb-icons-enable t)) #+end_src Code Lens can show error inline. #+begin_src emacs-lisp (use-package lsp-ui :straight t :after lsp) #+end_src In order for =lsp-mode= to work, it needs to compile code on the =fly=. #+begin_src emacs-lisp (use-package flycheck :straight t :after lsp) #+end_src *** tags =tags= can be used to search for =tagged= entities, such as =structs= etc. #+begin_src emacs-lisp (use-package lsp-ivy :straight t :after lsp-mode :bind(:map lsp-mode-map ("C-l g a" . lsp-ivy-workspace-symbol))) #+end_src *** language configurations **** rust Basic =rust-mode= with some fancy characters. #+begin_src emacs-lisp (use-package rust-mode :straight t) #+end_src I want to use =rust-analyzer= and see inlay type hints for variables. Warning: If inlay hints don't work, make sure to use the lastest: + rust version + =rust-analyzer= + =rust-mode= + =lsp-mode= #+begin_src emacs-lisp (setq lsp-rust-server 'rust-analyzer lsp-rust-analyzer-server-display-inlay-hints t) (add-hook 'rust-mode 'lsp-rust-analyzer-inlay-hints-mode) #+end_src **** haskell =ghcup install hls= and =cabal install stylish-haskell= are required. #+begin_src emacs-lisp (use-package haskell-mode :straight t :config (setq haskell-stylish-on-save t) :hook (haskell-mode . interactive-haskell-mode)) (use-package lsp-haskell :straight t :after lsp) #+end_src **** octave #+begin_src emacs-lisp (use-package octave-mode :mode ("\\.m\\'" . octave-mode) :hook (octave-mode . company-mode)) #+end_src ** Input methods *** spelling Sjoe my speling misttakes. #+begin_src emacs-lisp (use-package ispell :straight t :if (executable-find "hunspell") :config (setq ispell-program-name "hunspell" ispell-dictionary "de_DE,en_GB,en_US") (ispell-set-spellchecker-params) (ispell-hunspell-add-multi-dic "de_DE,en_GB,en_US") :hook (org-mode . flyspell-mode) (markdown-mode . flyspell-mode) (text-mode . flyspell-mode)) #+end_src *** math Who needs LaTeX when you can have the power of unicode? #+begin_src emacs-lisp (use-package math-symbol-lists :straight t :config (quail-define-package "math" "UTF-8" "Ω" t) (quail-define-rules ; Equality and order ("<=" ?≤) (">=" ?≥) ("\\prec" ?≺) ("\\preceq" ?≼) ("\\succ" ?≻) ("\\succeq" ?≽) ("/=" ?≠) ("\\neq" ?≠) ("\\=n" ?≠)("\\equiv" ?≡) ("\\nequiv" ?≢) ("\\approx" ?≈) ("\\~~" ?≈) ("\\t=" ?≜) ("\\def=" ?≝) ; Set theory ("\\sub" ?⊆) ("\\subset" ?⊂) ("\\subseteq" ?⊆) ("\\in" ?∈) ("\\inn" ?∉) ("\\:" ?∈) ("\\cap" ?∩) ("\\inter" ?∩) ("\\cup" ?∪) ("\\uni" ?∪) ("\\emptyset" ?∅) ("\\empty" ?∅) ("\\times" ?×) ("\\x" ?×) ; Number stuff ("\\mid" ?∣) ("\\infty" ?∞) ("\\sqrt" ?√) ("\\Im" ?ℑ) ("\\Re" ?ℜ) ; Logic ("\\/" ?∨) ("\\and" ?∧) ("/\\" ?∧) ("\\or" ?∨) ("~" ?¬) ("\neg" ?¬) ("|-" ?⊢) ("|-n" ?⊬) ("\\bot" ?⊥) ("\\top" ?⊤) ("\\r" ?→) ("\\lr" ?↔) ("\\R" ?⇒) ("\\Lr" ?⇔) ("\\qed" ?∎) ; Predicate logic ("\\all" ?∀) ("\\ex" ?∃) ("\\exn" ?∄) ; functions ("\\to" ?→) ("\\mapsto" ?↦) ("\\circ" ?∘) ("\\comp" ?∘) ("\\integral" ?∫) ("\\fun" ?λ) ; Sets of numbers ("\\nat" ?ℕ) ("\\N" ?ℕ) ("\\int" ?ℤ) ("\\Z" ?ℤ) ("\\rat" ?ℚ) ("\\Q" ?ℚ) ("\\real" ?ℝ) ("\\R" ?ℝ) ("\\complex" ?ℂ) ("\\C" ?ℂ) ("\\prime" ?ℙ) ("\\P" ?ℙ) ; Complexity ("\\bigo" ?𝒪) ; Greek ("\\Ga" ?α) ("\\GA" ?Α) ("\\alpha" ?α) ("\\Gb" ?β) ("\\GB" ?Β) ("\\beta" ?β) ("\\Gg" ?γ) ("\\GG" ?Γ) ("\\gamma" ?γ) ("\\Gamma" ?Γ) ("\\Gd" ?δ) ("\\GD" ?Δ) ("\\delta" ?δ) ("\\Delta" ?Δ) ("\\Ge" ?ε) ("\\GE" ?Ε) ("\\epsilon" ?ε) ("\\Gz" ?ζ) ("\\GZ" ?Ζ) ("\\Gh" ?η) ("\\Gh" ?Η) ("\\mu" ?μ) ("\\Gth" ?θ) ("\\GTH" ?Θ) ("\\theta" ?θ) ("\\Theta" ?Θ) ("\\Gi" ?ι) ("\\GI" ?Ι) ("\\iota" ?ι) ("\\Gk" ?κ) ("\\GK" ?Κ) ("\\Gl" ?λ) ("\\GL" ?Λ) ("\\lambda" ?λ) ("\\Gm" ?μ) ("\\GM" Μ) ("\\mu" ?μ) ("\\Gx" ?ξ) ("\\GX" ?Ξ) ("\\xi" ?ξ) ("\\Xi" ?Ξ) ("\\Gp" ?π) ("\\GP" ?Π) ("\\pi" ?π) ("\\Pi" ?Π) ("\\Gr" ?ρ) ("\\GR" ?Ρ) ("\\rho" ?ρ) ("\\Gs" ?σ) ("\\GS" ?Σ) ("\\sigma" ?σ) ("\\Sigma" ?Σ) ("\\Gt" ?τ) ("\\GT" ?Τ) ("\\tau" ?τ) ("\\Gph" ?ϕ) ("\\GPH" ?Φ) ("\\phi" ?ϕ) ("\\Phi" ?Φ) ("\\Gc" ?χ) ("\\GC" ?Χ) ("\\chi" ?χ) ("\\Gp" ?ψ) ("\\GP" ?Ψ) ("\\psi" ?ψ) ("\\Go" ?ω) ("\\GO" ?Ω) ("\\omega" ?ω) ("\\Omega" ?Ω) ) (mapc (lambda (x) (if (cddr x) (quail-defrule (cadr x) (car (cddr x))))) (append math-symbol-list-superscripts math-symbol-list-subscripts))) #+end_src