#+PROPERTY: header-args :comments link :tangle yes :noweb no-export :results silent #+STARTUP: overview * About this file This is my main emacs init file. It can be loaded by the init.el with org-babel or can be tangled and compiled to =main.elc= and loaded directly. If you're viewing this file in an org-mode buffer, you can open source code blocks (those are the ones in begin_src) in a separate buffer by moving your point inside them and typing C-c ' (org-edit-special). This opens another buffer in emacs-lisp-mode, so you can use M-x eval-buffer to load the changes. * Personal information #+begin_src emacs-lisp (setq user-full-name "Alexander Sulfrian" user-mail-address "alexander@sulfrian.net") #+end_src * Initialization ** packages Add some more package repositories. #+begin_src emacs-lisp (nconc package-archives '(("melpa-stable" . "http://stable.melpa.org/packages/") ("melpa" . "http://melpa.org/packages/") ("org" . "http://orgmode.org/elpa/") ("marmalade" . "http://marmalade-repo.org/packages/"))) #+end_src By default the package system is initialized after evaluating the user-init-file (this file) and I could not customize packages in this file. So I initialize the package system right here and disable the automatic initialization. #+begin_src emacs-lisp (setq package-enable-at-startup nil package-user-dir (locate-user-emacs-file "cache/elpa/")) (package-initialize nil) #+end_src ** use-package I require use-package to simplify the configuration. This is a requirement for this configuration, so I install it here. #+begin_src emacs-lisp (eval-when-compile (unless (package-installed-p 'use-package) (package-install 'use-package)) (setq use-package-verbose t) (require 'use-package)) #+end_src ** auto-compile For faster start-up times, this init file should be compiled into byte code. I use auto-compile mode for this. It will recompile files on load if the byte compiled file exists but is outdated. #+begin_src emacs-lisp (use-package auto-compile :ensure t :config (auto-compile-on-load-mode)) #+end_src For safety reasons emacs should prefer the newer file, if the =*.el= and =*.elc= file exists. #+begin_src emacs-lisp (setq load-prefer-newer t) #+end_src ** dash #+begin_src emacs-lisp (use-package dash :demand t :ensure t) #+end_src emacs-lisp * General Setup ** Encoding Set all the encoding stuff to utf-8 (but to latin-1 on ZEDAT hosts). #+begin_src emacs-lisp (let ((encoding (if (string-match "\\.zedat.fu-berlin.de\\'" system-name) 'latin-1 'utf-8))) (setq locale-coding-system encoding) (set-terminal-coding-system encoding) (set-keyboard-coding-system encoding) (set-selection-coding-system encoding) (prefer-coding-system encoding)) #+end_src ** Customizing Emacs should not edit the init.el file when saving stuff from customize. So I set a separate custom-file and load it. #+begin_src emacs-lisp (setq custom-file "~/.emacs.d/emacs-custom.el") (load custom-file) #+end_src ** Helper for configuration I need some functions to simplify the configuration below. They are defined here. *** Get buffers with specific minor-mode Simply get a list of all buffers, where the specified minor-mode is active. #+begin_src emacs-lisp (defun alex/get-buffers-with (mode) "Get a list of buffers where the given MODE is active. It is done by evaluating the given symbol in all buffers and return a list with all buffers where it evaluates to t. So actually MODE could be any buffer-local variable." (let ((state (mapcar (lambda (buf) (with-current-buffer buf (when (and (boundp mode) (symbol-value mode)) buf))) (buffer-list)))) (delq nil state))) #+end_src *** Ignore errors of a function This macro first tries to execute the given fun and evaluate the body afterwards, even if fun raised an error. After evaluation of body the original return value (or error) of fun is returned. This is useful for around advices, that should be reset something after calling the adviced function, even if it raises an error. #+begin_src emacs-lisp (defmacro alex/safe-call (fun &rest body) "Evaluate FUN and catch all errors, evaluates BODY afterwards (regardless whether an error was raised or not) and finally returns the result of FUN captured earlier or re-throw the error." `(let* ((tmp (condition-case err (list (,@fun) nil) (error (list nil err)))) (err (cadr tmp)) (result (car tmp))) ,@body (when err (signal (car err) (cdr err))) result)) #+end_src *** Get next element from list This lisp function returns the next element from a list. It is useful if you want to switch a setting between multiple values. #+begin_src emacs-lisp (defun alex/get-next (old list) "Returns the element after OLD in LIST or the first element if OLD is the last element or is not in LIST." (let ((index (or (cl-position old list) -1)) (len (length list))) (nth (% (+ 1 index) len) list))) #+end_src *** Exclude list for globalized minor-modes I want to define some global-minor-modes, but keep them disabled in certain modes, buffers or in the minibuffer. So I declare some helper to define exclude lists for custom global-minor-modes. #+begin_src emacs-lisp (defun alex/parse-exclude-list (exclude-list) "Convert a free from exlude list (with multiple keywords) in a propper assoc list with the keywords as key and the values in between as values." (let ((keyword nil) (res '()) (args '())) (dolist (elem exclude-list) (if (keywordp elem) (progn (when keyword (setq res (nconc res (list keyword (or args 'empty))))) (setq keyword elem args '())) (setq args (nconc args (list elem))))) (nconc res (list keyword (or args 'empty))))) (defmacro alex/check-list (list var &rest body) "Simple macro to check if body returns non-nil for any element in the list." `(if (eq ,list 'empty) nil (delq nil (mapcar (lambda (,var) ,@body) ,list)))) (defun alex/safe-get-value (var) "Get the value of the variable of nil if the given variable does not exists." (if (boundp var) (symbol-value var) nil)) (defun alex/minor-mode-exclude (mode) "Check the exclude list for the given mode. Returns t if the mode should be excluded, else nil." (let* ((exclude-list (intern (concat (symbol-name mode) "-exclude-list"))) (excludes (alex/parse-exclude-list (symbol-value exclude-list)))) (cond ((and (plist-get excludes :minibuffer) (minibufferp)) t) ((alex/check-list (plist-get excludes :mode) mode (cond ((derived-mode-p mode) t) ((alex/safe-get-value mode) t))) t) ((alex/check-list (plist-get excludes :buffer) buf (cond ((and (symbolp buf) (eq (current-buffer) (alex/safe-get-value buf))) t) ((and buf (eq (current-buffer) buf)) t))) t) (t nil)))) #+end_src Last I define a macro for defining a globalized minor-mode with the exclude list feature. #+begin_src emacs-lisp (defmacro alex/global-excluding-minor-mode (global mode &rest body) "Define a global-minor-mode that can be disabled on some modes or buffers. BODY is executed each time when the mode should be activated (it passed the exclude list at this position). If BODY is empty the mode will be simply activated." (if `(not ,body) `(define-globalized-minor-mode ,global ,mode (lambda () (unless (alex/minor-mode-exclude ',mode) (,mode 1)))) `(define-globalized-minor-mode ,global ,mode (lambda () (unless (alex/minor-mode-exclude ',mode) ,@body))))) (defmacro alex/minor-mode-exclude-list (mode) `(defvar ,(intern (concat (symbol-name mode) "-exclude-list")) () (concat "Exclude list for " (symbol-name ',mode) ". " "Can contain :minibuffer, :modeq and :buffer."))) (defun alex/build-global-name (mode) "Build the symbol for the global mode by inserting 'global-' after 'alex/' or prepending 'alex/gloabl-' if MODE does not start with the personal prefix." (let ((name (symbol-name mode))) (intern (if (string-match "^alex/" name) (replace-regexp-in-string "^alex/" "\\&global-" name) (concat "alex/global-" name))))) (defun alex/define-global-excluding-minor-mode (mode &rest body) (let ((global (alex/build-global-name mode))) (eval `(alex/global-excluding-minor-mode ,global ,mode ,body)) (eval `(alex/minor-mode-exclude-list ,mode)))) #+end_src ** Cache directory I want to keep all the changing files in one place, so I create =~/.emacs.d/cache/= for this purpose. #+begin_src emacs-lisp (let ((cache (locate-user-emacs-file "cache/"))) (unless (file-directory-p cache) (make-directory cache))) #+end_src Additionally I define a helper function to create a file name inside this cache directory. #+begin_src emacs-lisp (defun alex/cache-file (filename) (locate-user-emacs-file (concat "cache/" filename))) #+end_src *** recentf Save the history of the last 1000 visited files. #+begin_src emacs-lisp (setq recentf-save-file (alex/cache-file "recentf") recentf-max-saved-items 1000) (recentf-mode 1) #+end_src *** save-place Save the last position in a file and raise the limit to 10k elements. #+begin_src emacs-lisp (use-package saveplace :config (setq save-place-file (alex/cache-file "saveplace") save-place-limit 10000) (setq-default save-place t)) #+end_src *** savehist Save a lot of history between emacs restarts. Save everything, but do not keep duplicates. #+begin_src emacs-lisp (setq savehist-file (alex/cache-file "savehist") history-length t history-delete-duplicates t savehist-save-minibuffer-history t savehist-additional-variables '(kill-ring search-ring regexp-search-ring)) #+end_src Enable the =savehist-mode=. This has to be below the configuration, because the history is loaded when this mode is activated the first time. So the =savehist-file= has to be configured when activating. #+begin_src emacs-lisp (savehist-mode 1) #+end_src *** bookmarks Bookmarks are great to remember various positions in files. Save the bookmark file every time I make a modification (so that I do not loose a change, even if emacs or my laptop crashes). #+begin_src emacs-lisp (setq bookmark-default-file (alex/cache-file "bookmarks") bookmark-save-flag 1) #+end_src *** backups Do not save backup files into the directory of the original file. #+begin_src emacs-lisp (setq backup-directory-alist '(("." . "~/.emacs.d/backups"))) #+end_src Do not delete old backup files. #+begin_src emacs-lisp (setq delete-old-versions -1 version-control t) #+end_src Make backups even for files under version control. #+begin_src emacs-lisp (setq vc-make-backup-files t) #+end_src *** auto-save Do not save auto-save files into the directory of the original file (especially important for editing files via tramp). #+begin_src emacs-lisp (setq auto-save-file-name-transforms `((".*" ,(alex/cache-file "auto-save-list/") t)) auto-save-list-file-prefix (alex/cache-file "auto-save-list/.saves-")) #+end_src ** Remove some annoyances *** No startup message Remove the startup screen. #+begin_src emacs-lisp (setq inhibit-startup-message t) #+end_src Remote the message in the message area: For information about GNU Emacs and the GNU system, type C-h C-a =inhibit-startup-echo-area-message= could be used, but it has to be set to the username (as elisp literal), So =(user-login-name)= does not work. To generalize the config, this simply overwrites the config printing the message. #+begin_src emacs-lisp (defun display-startup-echo-area-message ()) #+end_src *** Newline at end of file Require a newline at end of file, but do not insert newlines automatically just by moving the cursor down. #+begin_src emacs-lisp (setq require-final-newline t next-line-add-newlines nil) #+end_src *** Yes or No I do not want to have to type =yes= and =no=. =y= or =n= should be sufficient. #+begin_src emacs-lisp (fset 'yes-or-no-p 'y-or-n-p) #+end_src *** Symbolic links and version control Visit the real file (without question), if editing a symbolic links that points to a file under version control. #+begin_src emacs-lisp (setq vc-follow-symlinks t) #+end_src *** Unbind C-z, if not running in terminal C-z is a relict from terminal programms to suspend the currently running programm. It is not needed under X11 and the gui will freeze, if you press it by accident. #+begin_src emacs-lisp (when window-system (global-unset-key (kbd "C-z"))) #+end_src ** Visual *** Window configuration Clean up the UI. No toolbar, but use scrollbars and tooltips to keep the minibuffer clean. #+begin_src emacs-lisp (tool-bar-mode -1) (tooltip-mode 1) (scroll-bar-mode 1) #+end_src Use extremely small scroll-bars on the right. #+begin_src emacs-lisp (set-scroll-bar-mode 'right) (set-frame-parameter nil 'scroll-bar-width 10) (nconc default-frame-alist '((scroll-bar-width . 10))) #+end_src The menu-bar is helpful in the terminal (under X you can get a menu on demand with ). So I enable the menu-bar if no window-system is available. To show the menu also in an emacsclient in the terminal, I have to add a hook in the =after-make-frame-function=. #+begin_src emacs-lisp (defun alex/update-menu-bar (&optional frame) "This displays the menu bar if the given FRAME (default: selected frame) is in a terminal" (let ((status (if (display-graphic-p frame) 0 1))) (set-frame-parameter frame 'menu-bar-lines status))) (alex/update-menu-bar) (add-hook 'after-make-frame-functions 'alex/update-menu-bar) #+end_src *** Color-theme Use own color theme and switch it depending whether the frame is on terminal or under X11. #+begin_src emacs-lisp (use-package color-theme :demand t :config (setq color-theme-directory "~/.emacs.d/lisp/themes/" color-theme-load-all-themes nil) (color-theme-initialize) (color-theme-monokai-alex) (defun alex/update-color-theme (&optional frame) (let ((color-theme-is-global nil)) (if (display-graphic-p frame) (color-theme-monokai-alex) (color-theme-alex-console)))) (add-hook 'after-make-frame-functions 'alex/update-color-theme)) #+end_src I always want to have as much as possible syntax highlighting. #+begin_src emacs-lisp (global-font-lock-mode t) (setq font-lock-maximum-decoration t) #+end_src *** Cleanup minor-modes in modeline I want to hide some minor-modes, if they are activated in nearly all buffers or it is irrelevant if they are activated. To be compatible with powerline I use rich-minority, but I add some custom stuff to fake the interface of diminish so that I can use the diminish feature of use-package. I can use :diminish in use-package with either a mode name or e regexp to hide matching modes. #+begin_src emacs-lisp (use-package rich-minority :ensure t :config (defvar alex/minor-mode-blacklist () "List of regexp that is matched against the lighter of all minor-modes. All matching minor-modes are hidden in the mode line.") (defun alex/rm-add-blacklist (regexp) "Add the given REGEXP to alex/minor-modes-blacklist and updates the combined regexp in rm-blacklist afterwards." (unless (member regexp alex/minor-mode-blacklist) (setq alex/minor-mode-blacklist (nconc alex/minor-mode-blacklist (list regexp))) (alex/update-rm-blacklist)) alex/minor-mode-blacklist) (defun alex/update-rm-blacklist () "Update rm-blacklist and build a regexp from the multiple values in alex/minor-modes-blacklist." (setq rm-blacklist (format "^\\(%s\\)$" (mapconcat #'identity alex/minor-mode-blacklist "\\|")))) (defun alex/get-lighter (mode) "Get the lighter for the given minor-mode." (let ((value (assoc mode minor-mode-alist))) (if value (let ((lighter (cadr value))) (if (symbolp lighter) (when (boundp lighter) (eval lighter)) lighter)) nil))) (defun diminish (mode &optional regexp) "This is a fake diminish with rich-minority-mode. It accepts uses either the MODE or if given the REGEXP to hide the mode." (if (and regexp (> (length regexp) 0)) (alex/rm-add-blacklist regexp) (let ((lighter (alex/get-lighter mode))) (when lighter (alex/rm-add-blacklist lighter))))) (rich-minority-mode 1)) #+end_src *** Trailing whitespaces I generally want to show trailing whitespaces, but there are several exceptions. Per default there is only a buffer local variable to control this feature. I create a simple minor-mode, so that I could simply activate or deactivate this feature. #+begin_src emacs-lisp (define-minor-mode alex/tw-mode "trailing-whitespace-mode" :lighter " TW" (setq show-trailing-whitespace alex/tw-mode)) (alex/define-global-excluding-minor-mode 'alex/tw-mode) #+end_src I want to disable trailing whitespaces in the minibuffer, in weechat, helm and term-mode and in the which-key buffer. So I define here the exclude list. #+begin_src emacs-lisp (setq alex/tw-mode-exclude-list '(:minibuffer :mode helm--remap-mouse-mode weechat-mode term-mode Custom-mode :buffer which-key--buffer)) #+end_src And now activate the new global mode and hide it from the mode line. #+begin_src emacs-lisp (alex/global-tw-mode t) (diminish 'alex/tw-mode) #+end_src *** Visual-wrap-column Sometimes I want to force =visual-line-wrap= at a specific column (in contrast to the window width). This is especially useful for emails, that are badly formatted with long lines. =visual-line-wrap= will split long lines at the word-break before the specified column. #+begin_src emacs-lisp (defvar alex/visual-wrap-column nil "Column to force visual line wrap. Use `alex/set-visual-wrap-column' to change the value.") (defun alex/set-visual-wrap-column (new-wrap-column &optional buffer) "Force visual line wrap at NEW-WRAP-COLUMN in BUFFER (defaults to current buffer) by setting the right-hand margin on every window that displays BUFFER. A value of NIL or 0 for NEW-WRAP-COLUMN disables this behavior." (interactive (list (read-number "New visual wrap column, 0 to disable: " (or alex/visual-wrap-column fill-column 0)))) (when (and (numberp new-wrap-column) (zerop new-wrap-column)) (setq new-wrap-column nil)) (with-current-buffer (or buffer (current-buffer)) (visual-line-mode t) (set (make-local-variable 'alex/visual-wrap-column) new-wrap-column) (add-hook 'window-configuration-change-hook 'alex/update-visual-wrap-column nil t) (let ((windows (get-buffer-window-list))) (dolist (win windows) (when (window-live-p win) (with-selected-window win (alex/update-visual-wrap-column))))))) (defun alex/update-visual-wrap-column () "Update the right margin of the current window, to match the available space to `alex/visual-wrap-column'." (if (not alex/visual-wrap-column) (set-window-margins nil nil) (let* ((current-margins (window-margins)) (right-margin (or (cdr current-margins) 0)) (current-width (window-width)) (current-available (+ current-width right-margin))) (if (<= current-available alex/visual-wrap-column) (set-window-margins nil (car current-margins)) (set-window-margins nil (car current-margins) (- current-available alex/visual-wrap-column)))))) #+end_src ** Localization I want to use german names for month and weekdays. #+begin_src emacs-lisp (setq calendar-week-start-day 1 calendar-day-name-array ["Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag"] calendar-month-name-array ["Januar" "Februar" "März" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember"]) #+end_src ** Browser I have a simple wrapper script to be able to easily switch to a different browser. So I only have to configure to use this wrapper script. #+begin_src emacs-lisp (setq browse-url-browser-function 'browse-url-generic browse-url-generic-program "browser") #+end_src ** Movement The defaults for the cursor movement and scrolling are not very good, so I need to customize the settings to match the expectations. *** Scrolling If I move the cursor out of screen, I do not want to jump to recenter the cursor, but scroll just as far to display the cursor again. #+begin_src emacs-lisp (setq scroll-conservatively 10000 auto-window-vscroll nil) #+end_src Do not accelerate mouse scrolling. #+begin_src emacs-lisp (setq mouse-wheel-progressive-speed nil) #+end_src Automatic scroll the compilation output to the bottom (or the first error). #+begin_src emacs-lisp (setq compilation-scroll-output t) #+end_src *** Automatic indentation Automatic indent new lines. #+begin_src emacs-lisp (bind-key "RET" 'newline-and-indent) #+end_src But clean whitespaces, if the indentation is abandoned. #+begin_src emacs-lisp (use-package clean-aindent-mode :config (clean-aindent-mode t)) #+end_src *** Back to indentation I want to have a better handling for the == key. Per default I want to move the cursor to the end of the indentation (first non-whitespace character). Only if the cursor is already at that position, I want to move to the beginning of the line. #+begin_src emacs-lisp (defun alex/back-to-indentation-or-beginning () "Move the point to the first non-whitespace character on the line, of if it is already there, to the beginning of the line." (interactive) (if (= (point) (save-excursion (back-to-indentation) (point))) (beginning-of-line) (back-to-indentation))) (bind-key "" 'alex/back-to-indentation-or-beginning) #+end_src *** Ungreedy kill-word The default =kill-word= (and =backward-kill-word=) is a bit greedy. I want to replace =forward-word= in the original definition with =forward-same-syntax=. This could not be done with an advice because =forward-word= is a byte code primitive and could not be replaced with =flet= or something like that. So I have to copy the original definition of kill-word here and simple do the replacement in the source. #+begin_src emacs-lisp (defun kill-word (arg) "Kill characters forward until encountering the end of a word. With argument ARG, do this that many times." (interactive "p") (kill-region (point) (progn (forward-same-syntax arg) (point)))) #+end_src ** Selection The selection is the region between the mark and the point. But I want to see the active region, so I want to ensure, that transient-mark-mode is enabled globally. #+begin_src emacs-lisp (transient-mark-mode 1) #+end_src Additionally I have some enhancements to the default behaviour of some commands. *** Kill or copy whole line If no region is active, I want to kill/copy the current line. #+begin_src emacs-lisp (defun alex/whole-line (func beg end &rest region) (interactive (if mark-active (list (region-beginning) (region-end)) (list (line-beginning-position) (line-beginning-position 2)))) (apply func beg end region)) (advice-add 'kill-ring-save :around #'alex/whole-line) (advice-add 'kill-region :around #'alex/whole-line) #+end_src *** Rectangle selection The rectangle selection of cua mode works very well, but I only want the rectangle selection mode and not the C-z/C-x/C-c/C-v bindings. #+begin_src emacs-lisp (setq cua-rectangle-mark-key (kbd "M-SPC") cua-delete-selection nil) (cua-selection-mode t) #+end_src *** X11 clipboard Use the X11 clipboard in addition to the primary selection, because some other X11 apps can only use the X11 clipboard. #+begin_src emacs-lisp (setq x-select-enable-clipboard t) (setq interprogram-paste-function 'x-selection-value) #+end_src ** Custom commands Here I define some global custom commands. These commands are bind in the =global-map= and are not associated with any other package. *** Open terminal Open an external terminal in the default directory of the current buffer. In most cases this is the directory containing the file of the current buffer. #+begin_src emacs-lisp (defun alex/open-buffer-shell () "Open a terminal in the default directory of the current buffer." (interactive) (if default-directory (start-process-shell-command "urxvt" nil (concat "DIR=" default-directory " urxvt")) (message "Buffer does not contain a file."))) (bind-key "" 'alex/open-buffer-shell) #+end_src ** Bug fixes A few workarounds about some strange emacs behaviour. *** Key mapping Some versions of urxvt send some strange key codes for some key combinations. The following table contains the mappings from the key codes send by urxvt and the real keys. #+tblname: key-mappings | Keycode | Key | |-------------+-------------| | M-[ Z | | |