#+Title: Emacs Customizations #+Author: Ricardo Wurmus #+PROPERTY: noweb tangle #+PROPERTY: mkdirp t #+OPTIONS: tasks:nil toc:1 * Introduction My Emacs configuration is a mess. As I’m writing this my Emacs configuration stretches across multiple files, each containing various snippets of code that seemed like a good idea to group. Unfortunately, there are a some things that don’t have a “natural” home. Enabling the same minor mode in various major modes is one of these cases—do I duplicate the hook and place it in a file for each major mode? Or do I write a new file for the minor mode in which I add it to the major modes at once? With multiple files I spend too much time trying to find the best place for any bit of configuration I add. This slows me down and sometimes I just append to the main =init.el=, so I often feel that my configuration is in need of reorganisation. But configuring Emacs should be fun! I don’t want it to create an uncomfortable clean-up task as a side-effect. This is why I’m now trying to use a literate approach with =org-mode=. My Emacs configuration should be prose first and code second. In my experience, finding the right spot in prose for a new paragraph requires a lot less effort as the text itself acts as a connection between unrelated bits of code. * How to use this? :PROPERTIES: :noweb-ref: compile-init :END: We take all code blocks in this file and assemble an =init.el= from it if the source file =init.org= is younger. At startup time we check if the =init.el= has to be regenerated. #+BEGIN_SRC elisp (let ((orgfile (expand-file-name (concat user-emacs-directory "init.org"))) (target (expand-file-name (concat user-emacs-directory "init.el")))) (when (not (file-newer-than-file-p target orgfile)) (progn (require 'org) (org-babel-tangle-file orgfile) (byte-compile-file target) (load target)))) #+END_SRC * Initialise packages :PROPERTIES: :noweb-ref: packages :END: Emacs is an operating system and I use it as such (see [[http://elephly.net/posts/2016-02-14-ilovefs-emacs.html][this blog post]]). I rely on quite a few extensions that have been made available on various ELPA repositories. Recently, I have moved to installing and managing Emacs packages like any other software package on my system with the functional package manager [[https://gnu.org/s/guix][GNU Guix]]. I find this more reliable, although at first it is slightly less convenient as I can no longer just use =package.el= but first need to package the Elisp code for Guix. To install all packages via GNU Guix I can either use a manifest file or use the following invocation: #+BEGIN_SRC sh :noweb-ref nil guix package -i \ emacs \ emacs-auctex \ emacs-better-defaults \ emacs-clojure-mode \ emacs-company \ emacs-debbugs \ emacs-emms \ emacs-emms-player-mpv \ emacs-ess \ emacs-expand-region \ emacs-fill-column-indicator \ emacs-god-mode \ emacs-haskell-mode \ emacs-ido-ubiquitous \ emacs-js2-mode \ emacs-lispy \ emacs-markdown-mode \ emacs-mmm-mode \ emacs-multiple-cursors \ emacs-org-bullets \ emacs-page-break-lines \ emacs-paren-face \ emacs-pdf-tools \ emacs-perspective \ emacs-projectile \ emacs-rich-minority \ emacs-shell-switcher \ emacs-solarized-theme \ emacs-skewer-mode \ emacs-smart-mode-line \ emacs-smex \ emacs-tagedit \ emacs-typo \ emacs-undo-tree \ emacs-web-mode \ emacs-wget \ emacs-zenburn-theme \ emacs-znc \ emacs-paredit \ emacs-geiser \ emacs-magit \ emacs-sicp \ mu #+END_SRC There are some packages I use that are not yet packaged for Guix. Here’s a list of them: #+BEGIN_SRC elisp (defvar my/packages '(centered-cursor-mode guide-key ido-vertical-mode scss-mode)) #+END_SRC I want these packages to be installed automatically. First I need to define in what repositories Emacs should look for the packages. I’m using packages from both the “melpa” and “marmalade” repositories. #+BEGIN_SRC elisp (require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/")) (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/")) (package-initialize) #+END_SRC If this is a fresh Emacs installation melpa needs to be initialised first: #+BEGIN_SRC elisp (unless (file-exists-p "~/.emacs.d/elpa/archives/melpa") (package-refresh-contents)) #+END_SRC Now we are ready to install packages if they aren’t yet installed. #+BEGIN_SRC elisp (defun packages-install (packages) (mapc (lambda (package) (when (not (package-installed-p package)) (package-install package))) packages) (delete-other-windows)) (defun init--install-packages () (packages-install my/packages)) #+END_SRC Install packages as soon as this configuration is evaluated. If there’s an error (e.g. because a package by this name cannot be found) ask Emacs to refresh the list of packages and retry. If there’s an error again we just ignore it. It could be that it’s because there’s no Internet connection. #+BEGIN_SRC elisp (condition-case e (init--install-packages) (error (ignore-errors (package-refresh-contents) (init--install-packages)))) #+END_SRC * Default fonts :PROPERTIES: :noweb-ref: default-fonts :END: I like pretty faces. For coding I like to use the DejaVu Sans Mono font. In =org-mode= and in =eww= I like to use a font with variable pitch instead of the default mono-spaced font. I find Linux Biolinum pretty, especially when it’s rendered large. #+BEGIN_SRC elisp (set-frame-font "DejaVu Sans Mono") (set-face-attribute 'variable-pitch nil :height 1.25 :family "Linux Biolinum") #+END_SRC * Manuals :PROPERTIES: :noweb-ref: manuals :END: Also in Info manuals I want to use variable-pitch fonts where possible. Unfortunately, Info manuals don’t contain enough semantic markup, so I cannot selectively use a monospace font for examples or inline code and use a variable pitch font for everything else. So I just use variable pitch in headings. #+BEGIN_SRC elisp (require 'info) (set-face-attribute 'info-title-1 nil :inherit 'variable-pitch :height 1.3) (set-face-attribute 'info-title-2 nil :inherit 'variable-pitch :height 1.3) (set-face-attribute 'info-title-3 nil :inherit 'variable-pitch :height 1.3) (set-face-attribute 'info-menu-header nil :inherit 'variable-pitch :height 1.1) #+END_SRC Since Emacs 25 there is a new face for quoted expressions in Info manuals. By default it uses the “courier” font, which looks terrible. #+BEGIN_SRC elisp (set-face-attribute 'Info-quoted nil :inherit 'fixed-pitch :family "Monospace") #+END_SRC * Org-mode :PROPERTIES: :noweb-ref: org-mode :END: This is my org mode configuration. Document it. #+BEGIN_SRC elisp (require 'org-indent) (setq org-ellipsis "⤵") (setq org-src-fontify-natively t) (global-set-key (kbd "C-c o l") 'org-store-link) (global-set-key (kbd "C-c o a") 'org-agenda) ;; TODO: make these available in org-mode only (global-set-key (kbd "C-c o s") 'org-schedule) (global-set-key (kbd "C-c o c") 'org-capture) (setq org-log-done t) (setq org-return-follows-link t) (setq org-directory "~/Documents/org") (setq org-agenda-files (mapcar (lambda (x) (concat org-directory x)) (list "/master.org" "/work.org" "/study.org" "/home.org"))) (setq org-default-notes-file (concat org-directory "/notes.org")) (setq org-agenda-custom-commands '(("w" todo "WAITING" nil) ("n" todo "NEXT" nil) ("d" "Agenda + Next Actions" ((agenda) (todo "NEXT"))))) (setq org-fontify-done-headline t) (require 'org-bullets) (setq org-bullets-bullet-list '("◉" "○" "◇" "◇")) (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1) (variable-pitch-mode 1) (visual-line-mode 1))) (defun gtd () (interactive) (find-file (concat org-directory "/master.org"))) #+END_SRC I don’t like the way org-mode looks by default. It’s noisy, too colourful and seems old-fashioned to the point of being somewhat unattractive. This is why I find it important to change some of the default faces. Since I enable =variable-pitch-mode= in my org-mode buffers I also need to explicitly make a few faces inherit from the =fixed-width= face to be rendered with a monospaced font. #+BEGIN_SRC elisp (set-face-attribute 'org-done nil :strike-through t) (set-face-attribute 'org-headline-done nil :strike-through t :foreground "light gray") (set-face-attribute 'org-document-title nil :height 1.6 :foreground "#073642") (set-face-attribute 'org-level-1 nil :height 1.0 :foreground "#586e75") (set-face-attribute 'org-level-2 nil :height 0.9 :foreground (face-attribute 'default :foreground)) (set-face-attribute 'org-level-3 nil :height 0.8 :foreground (face-attribute 'default :foreground)) (set-face-attribute 'org-level-4 nil :height 0.8 :foreground (face-attribute 'default :foreground)) (set-face-attribute 'org-block-background nil :background "#efe9d6") (set-face-attribute 'org-verbatim nil :background "#efe9d6") (dolist (face '(org-meta-line org-document-info-keyword org-special-keyword)) (set-face-attribute face nil :foreground "#93a1a1" :weight 'normal)) (dolist (face '(org-block-begin-line org-block-end-line org-block org-table org-meta-line org-document-info-keyword org-special-keyword org-verbatim org-todo org-tag org-done org-hide org-indent org-checkbox org-block-background)) (set-face-attribute face nil :inherit 'fixed-pitch) ;; TODO: this is ugly. When scaling up the variable-pitch face the ;; fixed-pitch face will become even larger. (set-face-attribute face nil :height 0.8)) (set-face-attribute 'org-tag nil :foreground (face-attribute 'default :foreground) :weight 'normal :height (face-attribute 'default :height) :overline nil :underline nil :box '(:line-width -1 :color "#859900")) #+END_SRC To ensure that indented blocks line up with their headings despite using =variable-pitch-mode= we set the indentation character to =*= and hide it by setting the foreground colour to the same as the default background colour. #+BEGIN_SRC elisp (setq org-indent-boundary-char ?*) (set-face-attribute 'org-indent nil :foreground (face-attribute 'default :background)) #+END_SRC =variable-pitch-mode= also makes it impossible to align tags at a fixed column, so I don’t. Instead I just let tags appear right behind the heading. #+BEGIN_SRC elisp (setq org-tags-column 0) #+END_SRC The following snippet is an attempt to prettify the somewhat ugly headers of source code blocks in =org-mode=. The snippet was taken from [[https://pank.eu/blog/pretty-babel-src-blocks.html][the blog of Rasmus Pank]] and slightly modified to suit my needs. #+BEGIN_SRC elisp (defvar-local my/org-at-src-begin -1 "Variable that holds whether last position was an org source code block.") (defvar-local my/org-src-begin-regexp "^[ \t]*#\\+begin_src[ \t]+[^ \f\t\n\r\v]+[ \t]*") (defvar my/ob-header-symbol ?☰ "Symbol used for babel headers") (defun my/org-prettify-src--update () (let ((case-fold-search t) (re my/org-src-begin-regexp) found) (save-excursion (goto-char (point-min)) (while (re-search-forward re nil t) (goto-char (match-end 0)) (let ((args (org-trim (buffer-substring-no-properties (point) (line-end-position))))) (when (org-string-nw-p args) (let ((new-cell (cons args my/ob-header-symbol))) (cl-pushnew new-cell prettify-symbols-alist :test #'equal) (cl-pushnew new-cell found :test #'equal))))) (setq prettify-symbols-alist (cl-set-difference prettify-symbols-alist (cl-set-difference (cl-remove-if-not (lambda (elm) (eq (cdr elm) my/ob-header-symbol)) prettify-symbols-alist) found :test #'equal))) ;; Clean up old font-lock-keywords. (font-lock-remove-keywords nil prettify-symbols--keywords) (setq prettify-symbols--keywords (prettify-symbols--make-keywords)) (font-lock-add-keywords nil prettify-symbols--keywords) (while (re-search-forward re nil t) (font-lock-flush (line-beginning-position) (line-end-position))) ;; Toggle prettify-symbols-mode to restore composition of ;; regions on which the "composition" text-property was deleted. (prettify-symbols-mode -1) (prettify-symbols-mode +1)))) (defun my/org-prettify-src () "Hide src options via `prettify-symbols-mode'. `prettify-symbols-mode' is used because expanding is simple. It’s not very efficient and maybe should be implemented using overlays." (let* ((case-fold-search t) (at-src-block (save-excursion (beginning-of-line) (looking-at my/org-src-begin-regexp)))) ;; Test if we moved out of a block. (cond ((or (and my/org-at-src-begin (not at-src-block)) ;; File was just opened. (eq my/org-at-src-begin -1)) (my/org-prettify-src--update)) ;; Remove composition if at line (at-src-block (with-silent-modifications (remove-text-properties (match-end 0) (1+ (line-end-position)) '(composition))))) (setq my/org-at-src-begin at-src-block))) (defun my/org-prettify-symbols () (mapc (apply-partially 'add-to-list 'prettify-symbols-alist) (cl-reduce 'append (mapcar (lambda (x) (list x (cons (upcase (car x)) (cdr x)))) `(("#+begin_src" . ?✎) ;; ➤ 🖝 ➟ ➤ ✎ ("#+end_src" . ?□) ;; ⏹ ("#+header:" . ,my/ob-header-symbol) ("#+begin_quote" . ?«) ("#+end_quote" . ?»))))) (turn-on-prettify-symbols-mode) (add-hook 'post-command-hook 'my/org-prettify-src t t)) (add-hook 'org-mode-hook #'my/org-prettify-symbols) #+END_SRC All of this should be loaded lazily. #+BEGIN_SRC elisp :noweb-ref org-mode-lazy (provide 'my/init-org) (with-eval-after-load "org" <> ) (require 'org) #+END_SRC * Editing files on remote systems :PROPERTIES: :noweb-ref: tramp :END: TRAMP is a really convenient way to edit files on remote systems from within the comfort of my cozy customised local Emacs session. I use it to edit files at work, to edit things on my server =elephly.net=, and even to edit things as root on the local system. #+BEGIN_SRC elisp (require 'tramp) (setq tramp-default-method "ssh") (setq tramp-default-proxies-alist (list ;; Do not use a proxy on the same system. '((regexp-quote (system-name)) nil nil) ;; For root connections to remote hosts, log in via ssh with normal ;; user account first, then su/sudo to root '("elephly\\.net\\'" "\\`root\\'" "/ssh:%h:") ;; Pass through ssh1 as user ‘rwurmus’ to reach remote hosts on ;; MDC network. '("mdc-berlin\\.net" "\\`rwurmus\\'" "/ssh:rwurmus@ssh1.mdc-berlin.de:"))) ;; ssh1 runs a restricted shell session, so "exec ssh" cannot be used. (add-to-list 'tramp-restricted-shell-hosts-alist "\\`ssh1\\.mdc-berlin\\.de\\'") ;; respect the PATH variable on the remote machine (add-to-list 'tramp-remote-path 'tramp-own-remote-path) (setq tramp-verbose 3) #+END_SRC * Shell :PROPERTIES: :noweb-ref: shell :END: The default prompt face makes it hard to see the prompt. #+BEGIN_SRC elisp (set-face-attribute 'comint-highlight-prompt nil :foreground "#859900" :weight 'bold) #+END_SRC * Magit :PROPERTIES: :noweb-ref: magit :END: #+BEGIN_SRC elisp ;; full screen magit-status (defadvice magit-status (around magit-fullscreen activate) (window-configuration-to-register :magit-fullscreen) ad-do-it (delete-other-windows)) (defun my/magit-quit-session () "Restores the previous window configuration and kills the magit buffer" (interactive) (kill-buffer) (jump-to-register :magit-fullscreen)) (defun my/magit-toggle-whitespace () "Toggles git option -w" (interactive) (if (member "-w" magit-diff-options) (my/magit-dont-ignore-whitespace) (my/magit-ignore-whitespace))) (defun my/magit-ignore-whitespace () "Adds git option -w" (interactive) (add-to-list 'magit-diff-options "-w") (magit-refresh)) (defun my/magit-dont-ignore-whitespace () "Removes git option -w" (interactive) (setq magit-diff-options (remove "-w" magit-diff-options)) (magit-refresh)) (define-key magit-status-mode-map (kbd "q") 'my/magit-quit-session) (define-key magit-status-mode-map (kbd "W") 'my/magit-toggle-whitespace) (setq magit-diff-refine-hunk 'all) #+END_SRC #+BEGIN_SRC elisp :noweb-ref magit-lazy (provide 'my/init-magit) (with-eval-after-load "magit" <> ) (require 'magit) (global-set-key (kbd "C-c m") 'magit-status) #+END_SRC * Ido :PROPERTIES: :noweb-ref: ido :END: #+BEGIN_SRC elisp (require 'ido-vertical-mode) (ido-mode 1) (ido-vertical-mode 1) (setq ido-vertical-define-keys 'C-n-and-C-p-only) (setq ido-ubiquitous-max-items 50000) ;; hit ~ to go straight to the home directory in ido mode (add-hook 'ido-setup-hook (lambda () ;; Go straight home (define-key ido-file-completion-map (kbd "~") (lambda () (interactive) (if (looking-back "/") (insert "~/") (call-interactively 'self-insert-command)))))) ;; Use ido everywhere (require 'ido-ubiquitous) (ido-ubiquitous-mode 1) (fset 'yes-or-no-p 'y-or-n-p) ;; open file at point with C-x C-f (setq ido-use-filename-at-point 'guess) #+END_SRC #+BEGIN_SRC elisp :noweb-ref ido-lazy (with-eval-after-load "ido" <> ) (require 'ido) #+END_SRC * Completion :PROPERTIES: :noweb-ref: completion :END: #+BEGIN_SRC elisp (add-hook 'after-init-hook 'global-company-mode) (setq company-idle-delay 0.5) (define-key company-mode-map (kbd "C-c ") 'company-complete) (require 'color) (let ((bg (face-attribute 'default :background))) (custom-set-faces `(company-tooltip ((t (:inherit default :background ,(color-lighten-name bg 2))))) `(company-scrollbar-bg ((t (:background ,(color-lighten-name bg 10))))) `(company-scrollbar-fg ((t (:background ,(color-lighten-name bg 5))))) `(company-tooltip-selection ((t (:inherit font-lock-function-name-face)))) `(company-tooltip-common ((t (:inherit font-lock-constant-face)))))) #+END_SRC #+BEGIN_SRC elisp :noweb-ref completion-lazy (provide 'my/init-completion) (with-eval-after-load "company" <> ) (require 'company) #+END_SRC * Pretty symbols :PROPERTIES: :noweb-ref: pretty-symbols :END: #+BEGIN_SRC elisp (defun my/pretty-js-symbols () (push '("===" . ?≡) prettify-symbols-alist) (push '("function" . ?𝑓) prettify-symbols-alist)) (defun my/pretty-r-symbols () (push '("%>%" . ?⤚) prettify-symbols-alist) (push '("%$%" . ?⤜) prettify-symbols-alist) (push '("==" . ?≡) prettify-symbols-alist) (push '("function" . ?𝑓) prettify-symbols-alist)) (when (boundp 'global-prettify-symbols-mode) (add-hook 'js2-mode-hook 'my/pretty-js-symbols) (add-hook 'ess-mode-hook 'my/pretty-r-symbols) (add-hook 'inferior-ess-mode-hook 'my/pretty-r-symbols) (global-prettify-symbols-mode +1)) #+END_SRC * Resize buffer margins dynamically :PROPERTIES: :noweb-ref: resize-dynamically :END: I don’t want to have any margins by default. #+BEGIN_SRC elisp (setq-default left-margin-width 0 right-margin-width 0) #+END_SRC When writing Org-mode documents or when browsing the web with Eww I prefer to see shorter lines. The following procedure takes the current window width and adjust the buffer margins dynamically such that the buffer contents are restricted in width. I find this much more readable when editing Org documents or browsing with Eww. #+BEGIN_SRC elisp (defun my/dynamic-margin-window (window) "Get current window width and adjust margins such that the buffer contents are centered and no more than 80 characters wide." (with-current-buffer (window-buffer window) (when (or (eq major-mode 'org-mode) (eq major-mode 'eww-mode)) (let* ((textwidth 80) (margin (max (- (window-size window t) textwidth) 0))) (setq left-margin-width 0 right-margin-width margin) (set-window-buffer window (current-buffer)))))) (defun my/dynamic-margin (frame) "Dynamically adjust margin for all windows of the frame." (walk-windows 'my/dynamic-margin-window 'no-minibuf frame)) #+END_SRC The procedure is added to the list of functions that are to be evaluated whenever the window size changes. As a result the content width is adjusted dynamically. #+BEGIN_SRC elisp (add-to-list 'window-size-change-functions 'my/dynamic-margin) #+END_SRC * Multimedia with EMMS :PROPERTIES: :noweb-ref: emms :END: I like to use EMMS as a music player. Unfortunately, the default players like mpg321 or ogg123 don’t support seeking, so I’m using =mpv= for everything. #+BEGIN_SRC elisp (require 'emms-player-mpv) (setq emms-player-list (list emms-player-mpv)) #+END_SRC * TODO Initial stuff :PROPERTIES: :noweb-ref: initial :END: This is supposed to happen at the very beginning, even before loading packages. I still need to arrange these things nicely. #+BEGIN_SRC elisp ;; No splash screen please ... (setq inhibit-startup-message t) ;; display tool tips in echo area only (tooltip-mode -1) (setq frame-resize-pixelwise t) (defalias 'yes-or-no-p 'y-or-n-p) ;; disable mouse scrolling (mouse-wheel-mode -1) (add-to-list 'load-path (concat user-emacs-directory "lisp")) #+END_SRC * TODO More stuff :PROPERTIES: :noweb-ref: initial-after-packages :END: This is even more stuff to be done after initialising packages. I still need to process all of this and clean it up. #+BEGIN_SRC elisp ;; better defaults, includes hiding the GUI (require 'better-defaults) (require 'paren-face) (global-paren-face-mode 1) (require 'paren) (setq show-paren-delay 0) (show-paren-mode 1) (require 'projectile) (projectile-global-mode) (require 'guide-key) (setq guide-key/guide-key-sequence '("C-x r" "C-x 4" "C-c p")) (guide-key-mode) ;; Keep emacs Custom-settings in separate file (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) (load custom-file) (setq frame-background-mode 'light) (load-theme 'solarized-light t) (add-hook 'haskell-mode-hook (lambda () (turn-on-haskell-indentation) (turn-on-haskell-doc))) #+END_SRC * TODO And even more :PROPERTIES: :noweb-ref: old-init :END: #+BEGIN_SRC elisp (setq backup-directory-alist `(;; Do not backup or auto-save remote files to prevent delays. (,tramp-file-name-regexp . nil) ;; Write backup files to a dedicated directory. ("." . ,(expand-file-name (concat user-emacs-directory "backups"))))) ;; Make backups of files, even when they're in version control (setq vc-make-backup-files t) (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode)) (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)) (setq scss-compile-at-save nil) ;; (setq whitespace-global-modes '(not erc-mode)) ;; (global-whitespace-mode 1) ;; (set-face-attribute 'whitespace-space nil :background nil :foreground "gray20") ;; (set-face-attribute 'whitespace-newline nil :background nil :foreground "gray20") ;; (setq whitespace-style ;; '(face spaces tabs newline space-mark tab-mark newline-mark)) ;; (setq whitespace-display-mappings ;; ;; all numbers are Unicode codepoint in decimal. try ;; ;; (insert-char 182 ) to see it ;; '( ;; (space-mark 32 [183] [46]) ; 32 SPACE, 183 MIDDLE DOT 「·」, ;; ; 46 FULL STOP 「.」 ;; (newline-mark 10 [182 10]) ; 10 LINE FEED ;; (tab-mark 9 [9655 9] [92 9]) ; 9 TAB, 9655 WHITE ;; ; RIGHT-POINTING TRIANGLE 「▷」 ;; )) (desktop-save-mode t) ;; ediff settings (setq ediff-diff-options "-w") ;; cause Emacs to fully redraw the display *before* it processes queued input events. (setq redisplay-dont-pause t) ;; fewer backslashes in regexp builder (require 're-builder) (setq reb-re-syntax 'string) ;; remove prompt on killing process buffer (setq kill-buffer-query-functions (remq 'process-kill-buffer-query-function kill-buffer-query-functions)) ;; enable features that are disabled by default (put 'narrow-to-region 'disabled nil) (put 'erase-buffer 'disabled nil) (put 'narrow-to-page 'disabled nil) (require 'fill-column-indicator) (setq fci-rule-use-dashes t) (setq fci-dash-pattern 0.3) (add-hook 'prog-mode-hook 'fci-mode) ;; keep the cursor centered to avoid sudden scroll jumps (require 'centered-cursor-mode) ;; disable in terminal modes ;; http://stackoverflow.com/a/6849467/519736 ;; also disable in Info mode, because it breaks going back with the backspace key (define-global-minor-mode my-global-centered-cursor-mode centered-cursor-mode (lambda () (when (not (memq major-mode (list 'Info-mode 'term-mode 'eshell-mode 'shell-mode 'erc-mode))) (centered-cursor-mode)))) (my-global-centered-cursor-mode 1) ;; expand region (global-set-key (kbd "M-@") 'er/expand-region) ;; Swap C-t and C-x, so it's easier to type on Dvorak layout ;; `keyboard-translate` does not work when attaching an emacsclient to ;; a running emacs in daemon mode, so instead we define the key in the ;; key-translation-map. ;; http://lists.gnu.org/archive/html/help-gnu-emacs/2009-10/msg00505.html (define-key key-translation-map [?\C-x] [?\C-t]) (define-key key-translation-map [?\C-t] [?\C-x]) ;; Use narrow tab width (set-default 'tab-width 4) (setq tab-width 4) (load "email.el") (require 'my/init-org) (require 'my/init-completion) (load "init-geiser.el") (setq gnus-select-method '(nntp "news.gmane.org")) (require 'my/init-magit) (load "init-eshell.el") (load "init-smex.el") (load "init-modeline.el") (load "init-my-stuff.el") (load "init-paredit.el") (load "init-music.el") (require 'my/init-music) (load "init-god-mode.el") (require 'my/init-god-mode) ;; Revert stale document graphics buffers automatically when the files ;; have changed. (add-hook 'doc-view-mode-hook 'auto-revert-mode) (page-break-lines-mode 1) (global-set-key (kbd "") 'backward-page) (global-set-key (kbd "") 'forward-page) (add-to-list 'auto-mode-alist '("\\.html\\'" . sgml-mode)) (eval-after-load "sgml-mode" '(progn (require 'tagedit) (tagedit-add-paredit-like-keybindings) (tagedit-add-experimental-features) (add-hook 'html-mode-hook (lambda () (tagedit-mode 1))))) (delete-selection-mode 1) ; delete seleted text when typing ;; don't let the cursor go into minibuffer prompt, HT Xah Lee (setq minibuffer-prompt-properties '(read-only t point-entered minibuffer-avoid-prompt face minibuffer-prompt)) (require 'undo-tree) (global-undo-tree-mode 1) (setq debbugs-gnu-default-packages '("emacs" "guix")) (setq erc-join-buffer 'bury) (savehist-mode) ;; PDF view mode (setq pdf-info-epdfinfo-program "~/.guix-profile/bin/epdfinfo") (pdf-tools-install) (add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode)) ;; enable variable-pitch-mode in eww (add-hook 'eww-mode-hook (lambda () (variable-pitch-mode 1))) ;; pretty quotes! (add-hook 'erc-mode-hook (lambda () (require 'typo) (typo-mode 1))) (add-hook 'org-mode-hook (lambda () (require 'typo) (typo-mode 1))) #+END_SRC * Putting it all together Having defined named code blocks in the sections above we can finally put them all together to build the init file #+BEGIN_SRC elisp :noweb yes :tangle "~/.emacs.d/init.el" <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> #+END_SRC # Local Variables: # org-edit-src-content-indentation: 0 # eval: (add-hook 'org-babel-post-tangle-hook (lambda nil (byte-compile-file "~/.emacs.d/init.el"))) # End: