diff options
author | Alexander Sulfrian <alexander.sulfrian@fu-berlin.de> | 2016-02-03 21:25:46 +0100 |
---|---|---|
committer | Alexander Sulfrian <alexander.sulfrian@fu-berlin.de> | 2016-02-03 21:25:46 +0100 |
commit | 3f5edbfe13f4bca10274e0999376502fa9ed346d (patch) | |
tree | 8c9d9300fa3f2378a052970ac5dd10fc01a4933d /init.d | |
parent | a759d4eb0b3465707f9e4aba2fa5a25bf0836aa9 (diff) | |
download | emacs-3f5edbfe13f4bca10274e0999376502fa9ed346d.tar.gz emacs-3f5edbfe13f4bca10274e0999376502fa9ed346d.tar.xz emacs-3f5edbfe13f4bca10274e0999376502fa9ed346d.zip |
Some org-bable config
Diffstat (limited to '')
-rw-r--r-- | init.d/.gitignore | 1 | ||||
-rw-r--r-- | init.d/main.org | 2715 |
2 files changed, 2716 insertions, 0 deletions
diff --git a/init.d/.gitignore b/init.d/.gitignore new file mode 100644 index 0000000..abf136d --- /dev/null +++ b/init.d/.gitignore @@ -0,0 +1 @@ +*.el diff --git a/init.d/main.org b/init.d/main.org new file mode 100644 index 0000000..db999ab --- /dev/null +++ b/init.d/main.org @@ -0,0 +1,2715 @@ +#+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))) +#+end_src + +** Remove some annoyances +*** No startup message + +#+begin_src emacs-lisp + (setq inhibit-startup-message t) +#+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 + +** 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 <F10>). 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 =<home>= 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 "<home>" '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 "<f12>" '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 | <S-tab> | +| <select> | <S-up> | +| M-[ b | <S-down> | +| M-[ c | <S-right> | +| M-[ d | <S-left> | +| M-O a | <C-up> | +| M-O b | <C-down> | +| M-O c | <C-right> | +| M-O d | <C-left> | +| ESC M-O a | <C-M-up> | +| ESC M-O b | <C-M-down> | +| ESC M-O c | <C-M-right> | +| ESC M-O d | <C-M-left> | +| ESC M-O A | <M-up> | +| ESC M-O B | <M-down> | +| ESC M-O C | <M-right> | +| ESC M-O D | <M-left> | +| ESC M-[ a | <M-S-up> | +| ESC M-[ b | <M-S-down> | +| ESC M-[ c | <M-S-right> | +| ESC M-[ d | <M-S-left> | +| <clearline> | <C-end> | + +The tables is converted into the real key mappings with the following +function. It uses the org-babel stuff to convert the org-table into an +emacs-lisp variable. + +#+begin_src emacs-lisp :var mappings=key-mappings + (if (not window-system) + (mapc (lambda (row) + (define-key function-key-map + (read-kbd-macro (car row)) + (read-kbd-macro (cadr row)))) + mappings)) +#+end_src + +*** Scroll speed + +The scroll speed of emacs (at least 24.1) was very slow (esp. in +wanderlust summary buffers). The problem was, that for each line the +paragraph direction was checked. Because I do not use right-to-left +languages, I disable the auto detection + +#+begin_src emacs-lisp + (when (boundp 'bidi-paragraph-direction) + (setq-default bidi-paragraph-direction 'left-to-right)) +#+end_src + +*** Sit-for + +=sit-for= seems to modify the current-buffer and causes error message +during find-file (if a backup file exists). This fixes the problem +providing =sit-for= with a temporary buffer, that is destroyed +afterwards. + +#+begin_src emacs-lisp + (defun alex/save-current-buffer (orig-fun &rest args) + "Do not allow the advised function to change the current-buffer." + (with-temp-buffer + (apply orig-fun args))) + (advice-add 'sit-for :around #'alex/save-current-buffer) +#+end_src +* Modes +** Core modes + +These modes are part of the core and the auto-mode-alist is set up +automatically. So the mode should not be required. + +*** cc-mode + +Here I only add a hook for the configuration and a key-binding for the +mode key-map. + +#+begin_src emacs-lisp + (defun alex/c-mode-setup () + ;; auto fill at column 80 + (setq fill-column 80) + (turn-on-auto-fill) + + ;; semantic as for auto-complete + (add-to-list 'ac-sources ac-source-semantic) + + ;; now '_' is not considered a word-delimiter + (modify-syntax-entry ?_ "w") + + ;; indentation style + (c-set-style "linux") + (setq indent-tabs-mode t + c-basic-offset 4 + tab-width 4) + + (bind-key "C-c o" 'ff-find-other-file 'c-mode-map)) + + (add-hook 'c-mode-common-hook 'alex/c-mode-setup) +#+end_src + +*** text-mode + +I only activate =auto-fill-mode= for =text-mode= here. Additionally I +activate =text-mode= automatically for all files called only with +capital letters and without extension (like README or INSTALL). + +#+begin_src emacs-lisp +(setq text-mode-hook 'turn-on-auto-fill) +(add-to-list 'auto-mode-alist '("\\`[A-Z]+\\'" . text-mode)) +#+end_src + +** Additional modes + +Some additional modes for editing of special files types. Most of +them do not requires special configuration only =:mode= or +=:interpreter= from use-package to enable auto loading. + +*** apache-mode + +#+begin_src emacs-lisp + (use-package apache-mode + :mode ("\.htaccess$" "htpd\\.conf$" "srm\\.conf$" "access\\.conf$" + "apache[12]\?\\.conf$" "commonapache[12]\?\\.conf$" + "\/sites-enabled\/.*\.conf$")) +#+end_src + +*** arduino-mode + +#+begin_src emacs-lisp + (use-package arduino-mode + :mode "\\.pde\\'") +#+end_src + +*** auctex + +#+begin_src emacs-lisp + (use-package auctex + :mode ("\\.tex\\'" . latex-mode) + :commands (latex-mode LaTeX-mode plain-tex-mode) + :config + (setq TeX-view-program-list '(("Zathura" "zathura %o")) + TeX-view-program-selection '((output-pdf "Zathura")))) +#+end_src + +*** autoconf-mode + +#+begin_src emacs-lisp + (use-package autoconf-mode + :mode ("\\.ac\\'" "configure\\.in\\'" + ("\\.at\\'" . autotest-mode))) +#+end_src + +*** bibtex + +#+begin_src emacs-lisp + (use-package bibtex + :mode ("\\.bib" . bibtex-mode)) +#+end_src + +*** crontab-mode + +#+begin_src emacs-lisp + (use-package crontab-mode + :commands (crontab-mode)) +#+end_src + +*** css-mode + +The css-mode requires a few adjustments for the indentation style. + +#+begin_src emacs-lisp + (use-package css-mode + :mode "\\.css\\'" + :functions (cssm-c-style-indenter) + :config + (setq cssm-indent-level 4 + cssm-newline-before-closing-bracket t + cssm-indent-function #'cssm-c-style-indenter)) +#+end_src + +*** csv-mode + +#+begin_src emacs-lisp + (use-package csv-mode + :mode "\\.[Cc][Ss][Vv]\\'") +#+end_src + +*** ebuild-mode + +#+begin_src emacs-lisp + (use-package ebuild-mode + :mode ("\\.ebuild\\'" "\\.eclass\\'" "\\.eblit\\'" + ("/[0-9]\\{4\\}-[01][0-9]-[0-3][0-9]-.+\\.[a-z]\\{2\\}\\.txt\\'" + . gentoo-newsitem-mode)) + :interpreter ("runscript" . sh-mode)) +#+end_src + +*** eselect-mode + +#+begin_src emacs-lisp + (use-package eselct-mode + :mode "\\.eselect\\'") +#+end_src + +*** graphviz-dot-mode + +#+begin_src emacs-lisp + (use-package graphviz-dot-mode + :mode ("\\.dot\\'" "\\.gv\\'")) +#+end_src + +*** haskell-mode + +I need haskell-mode and it is required to initialize the indentation +scheme on activation (else a pop-up will ask you to do so, if you press +=<TAB>= inside a haskell buffer). + +#+begin_src emacs-lisp + (use-package haskell-mode + :mode ("\\.hs\\'" "\\.gs\\'" "\\.hi\\'" + ("\\.l[gh]s\\'" . literate-haskell-mode) + ("\\.cabal\\'" . haskell-cabal-mode)) + :interpreter ("runghc" "runhaskell") + :config + (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)) +#+end_src + +*** javascript + +#+begin_src emacs-lisp + (use-package javascript + :mode ("\\.js\\'" . javascript-mode)) +#+end_src + +*** lua-mode + +#+begin_src emacs-lisp + (use-package lua-mode + :mode "\\.lua\\'") +#+end_src + +*** php-mode + +#+begin_src emacs-lisp + (use-package php-mode + :mode ("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'")) +#+end_src + +*** po-mode + +#+begin_src emacs-lisp + (use-package po-mode + :mode "\\.po\\'\\|\\.po\\.") +#+end_src + +*** promela-mode + +Simple mode for promela files. The file extension is not standardized, +so I add a few different extensions. + +#+begin_src emacs-lisp + (use-package promela-mode + :mode ("\\.promela\\'" "\\.spin\\'" "\\.pml\\'" "\\.prm\\'" "\\.porm\\'") + :config + (setq promela-block-indent 2 + promela-selection-indent 0 + promela-selection-option-indent 3)) +#+end_src + +*** protobuf-mode + +#+begin_src emacs-lisp + (use-package protobuf-mode + :mode "\\.proto\\'") +#+end_src + +*** python + +#+begin_src emacs-lisp + (use-package python + :mode ("\\.py\\'" . python-mode) + :interpreter ("python" . python-mode) + :functions (python-continuation-line-p) + :config + <<python>>) +#+end_src + +**** Fix indentation of closing brackets + +This fixes the indentation of the closing brackets for line +continuations in python. The opening and closing brackets should be +lined up in the same column. + +#+begin_src emacs-lisp :noweb-ref python :tangle no + (defun alex/python-indent-closing-brackets (func &rest args) + "Handle lines beginning with a closing bracket and indent them so that + they line up with the line containing the corresponding opening bracket." + (save-excursion + (beginning-of-line) + (let ((syntax (syntax-ppss))) + (if (and (not (eq 'string (syntax-ppss-context syntax))) + (python-continuation-line-p) + (cadr syntax) + (skip-syntax-forward "-") + (looking-at "\\s)")) + (progn + (forward-char 1) + (ignore-errors (backward-sexp)) + (current-indentation)) + (apply func args))))) + + (advice-add 'python-calculate-indentation :around + #'alex/python-indent-closing-brackets) +#+end_src + +*** xrdb-mode + +#+begin_src emacs-lisp + (use-package xrdb-mode + :mode ("\\.Xdefaults\\'" "\\.Xenvironment\\'" "\\.Xresources\'" + "\\.Xdefaults.d/")) +#+end_src + +* Packages +** ace-window + +ace-window is a replacement for =C-x o= that let you switch to a +specific window. It displays a marker in all windows and switch to the +select one. It is also possible execute some actions on the window +(swap, split or delete) by pressing a dispatch key before selecting +the window. It is not optimal, because it does not display the +possibility. Maybe I will replace it with a custom hydra. + +#+begin_src emacs-lisp + (use-package ace-window + :bind (("C-x o" . ace-window) + ("C-x C-o" . aw-flip-window)) + :config + (setq aw-scope 'frame + aw-dispatch-always t + aw-dispatch-alist '((?x aw-delete-window " Ace - Delete Window") + (?m aw-swap-window " Ace - Swap Window") + (?n aw-flip-window) + (?v aw-split-window-vert " Ace - Split Vert Window") + (?h aw-split-window-horz " Ace - Split Horz Window") + (?i delete-other-windows " Ace - Maximize Window") + (?o delete-other-windows)))) +#+end_src + +** auto-complete + +auto-complete uses a popup to display possible completions of the +input. The popup is displayed automatically after some idle time or +when pressing the shortcut (but the auto-complete-mode has to be +enabled before). + +#+begin_src emacs-lisp + (use-package auto-complete + :bind ("M-<tab>" . auto-complete) + :demand t + :diminish auto-complete-mode + :config + (require 'auto-complete-config) + (ac-config-default) + + (setq ac-comphist-file (alex/cache-file "ac-comphist.dat") + ac-quick-help-delay 1.0) + + (global-auto-complete-mode t)) +#+end_src + +** TODO company-mode + +Should be better than auto-complete-mode and the code should be more +modern. + +** cursor-chg + +I want to change the cursor if the buffer is readonly or if I enabled +overwrite. =cursor-chg= can change the shape of the cursor. The color +of the cursor could not be changed, because the cursor-color is a +frame parameter and could be set for a single buffer. + +#+begin_src emacs-lisp + (use-package cursor-chg + :config + (toggle-cursor-type-when-idle 1) + (change-cursor-mode 1)) +#+end_src + +** deft + +#+begin_src emacs-lisp + (use-package deft + :bind ("<f9>" . deft) + :config + (setq deft-extension "org" + deft-directory "~/.org/deft/" + deft-text-mode 'org-mode)) +#+end_src + +** dired-x + +I use dired-x mostly for the features for omitting files. I customize +the arguments for the listing to add a trailing slash for directories +(that way I can omit files like =*.d= but keep directories matching +the same regexp). I enable =dired-omit-mode= per default in all dired +buffers. + +#+begin_src emacs-lisp + (use-package dired-x + :config + (setq dired-omit-files "^\\.?#\\|~$\\|^\\.svn/$\\|^\\.git\$" + dired-omit-extensions (append completion-ignored-extensions + dired-latex-unclean-extensions + dired-bibtex-unclean-extensions + dired-texinfo-unclean-extensions) + dired-listing-switches "-pal --group-directories-first") + + (add-hook 'dired-mode-hook (lambda () (dired-omit-mode 1)))) +#+end_src +** doxymacs + +Currently I use doxymacs only to add font-lock for doxymacs tags. + +#+begin_src emacs-lisp + (defun alex/doxymacs-font-lock () + (when (member major-mode '(c-mode c++-mode)) + (when (not (fboundp 'doxymacs-font-lock)) + (use-package doxymacs + :load-path "/usr/share/emacs/site-lisp/doxymacs/") + (when (not (fboundp 'doxymacs-font-lock)) + (fset 'doxymacs-font-lock 'ignore))) + (doxymacs-font-lock))) + + (add-hook 'font-lock-mode-hook 'alex/doxymacs-font-lock) +#+end_src + +** edit-server + +Allow to exit text areas from a browser with emacs. Open the buffers +in a new frame in org-mode. + +#+begin_src emacs-lisp + (use-package edit-server + :config + (setq edit-server-new-frame t + edit-server-default-major-mode 'org-mode + edit-server-new-frame-alist '((name . "EDIT with Emacs"))) + + (edit-server-start)) +#+end_src + +** expand-region + +This will create a region around semantic elements and let you expand +and contract it around larger/smaller semantic units. + +#+begin_src emacs-lisp + (use-package expand-region + :bind (("C-<return>" . er/expand-region) + ("M-<return>" . er/contract-region))) +#+end_src + +** filladapt + +Indent a filled line (manual or with auto-fill-mode) according to some +heuristics with spaces, comments or citation marks. This is not +available on ELPA so we need to load it from the local =lisp/= folder +in the =user-emacs-directory=. + +#+begin_src emacs-lisp + (use-package filladapt + :load-path "lisp/" + :diminish filladapt-mode + :config + (setq-default filladapt-mode t) + (add-hook 'org-mode-hook #'turn-off-filladapt-mode) + (add-hook 'compilation-mode-hook #'turn-off-filladapt-mode)) +#+end_src +** flymake-jshint + +When entering a javascript buffer, try to load flymake-jshint and +activate flymake-mode when it could be loaded successfully. This is a +possibility to defer the loading of the flymake-jshint library until +it is really required. + +#+begin_src emacs-lisp + (defun alex/jshint-init () + "Try to load `flymake-jshint' if not already loaded and activate + flymake-mode if it could be loaded successfully." + (if (fboundp 'flymake-jshint-init) + (flymake-mode 1) + (use-package flymake-jshint) + (when (fboundp 'flymake-jshint-init) + (flymake-mode 1)))) + + (add-hook 'js-mode-hook 'alex/jshint-init) +#+end_src + +** git-gutter-fringe + +If running under X11 I want to have little git marker on the right +side in the fringe. Therefore I use git-gutter-fringe and I override +the modification function from =fringe-helper= because it does +something strange with the beg and end parameters. + +To make space for the git-gutter signs, I extend the width of the +right fringe a bit (left side is kept at the default width). + +#+begin_src emacs-lisp + (use-package git-gutter-fringe + :if window-system + :config + (setq git-gutter-fr:side 'right-fringe) + (fringe-mode '(nil . 15)) + (global-git-gutter-mode +1) + + ;; fix the helper function (does something strange with beg and end) + (defun fringe-helper-modification-func (ov after-p beg end &optional len) + ;; Sometimes this hook is called with a deleted overlay. + (when (overlay-start ov) + (let ((ov-beg (overlay-start ov)) + (ov-end (overlay-end ov))) + (if after-p + (if (eq beg end) + ;; evaporate overlay + (delete-overlay ov) + ;; if new lines are inserted, add new bitmaps + (let ((before-string (overlay-get ov 'before-string)) + fringe-ov) + (save-excursion + (goto-char ov-beg) + (while (search-forward "\n" ov-end t) + (setq fringe-ov (make-overlay (point) (point))) + (overlay-put fringe-ov 'before-string before-string) + (overlay-put fringe-ov 'fringe-helper-parent ov))))) + ;; if a \n is removed, remove the fringe overlay + (save-excursion + (goto-char ov-beg) + (while (search-forward "\n" ov-end t) + (let ((overlays (overlays-in (point) (1+ (point))))) + (while overlays + (when (eq (overlay-get (car overlays) 'fringe-helper-parent) ov) + (delete-overlay (car overlays)) + (setq overlays nil)) + (pop overlays))))))))) + :diminish + git-gutter-mode) +#+end_src +** helm + +I use helm completion everywhere and I do /not/ autoload helm, because +it would slow down the first completions and I am sure I will use helm +every time I start emacs. + +#+begin_src emacs-lisp + (use-package helm + :bind (("M-x" . helm-M-x) + ("M-X" . execute-extended-command) + ("C-x f" . helm-mini) + ("C-x b" . helm-buffers-list) + ("C-x C-b" . helm-buffers-list) + ("M-y" . helm-show-kill-ring)) + :demand t + :ensure t + :diminish helm-mode + :config + <<helm-config>> + (helm-mode 1)) +#+end_src + +The basic configuration for helm is provided by helm-config. + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (use-package helm-config) +#+end_src + +Customize the prefix key and setup =<tab>= as convenient execute the +persistent-action without quitting helm. + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (bind-key "<tab>" 'helm-execute-persistent-action helm-map) + (setq helm-command-prefix-key "C-c h") +#+end_src + +*** configuration + +Now I customize the helm configuration: + +**** visual + +I want to split the current window to display the helm completion +window and want to cycle through the results. + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (setq helm-split-window-in-side-p t + helm-move-to-line-cycle-in-source t) +#+end_src + +**** scroll other window + +I do not want to scroll the other window by pages, but by 10 +lines. This is useful, if I preview a file or a buffer with the +persistent action and want to scoll around a bit. + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (setq helm-scroll-amount 10) +#+end_src + +**** history + +I want to use =recentf-list= instead of the normal =file-name-history=, +because it is more configurable and more complete. + +I /always/ want to save the history for executed commands, even if the +command has failed. + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (setq helm-ff-file-name-history-use-recentf t + helm-M-x-always-save-history t) +#+end_src + +**** fuzzy matching + +Enable fuzzy matching on some helm modes. There is also +=helm-mode-fuzzy-match= that would enable fuzzy match in every helm +mode, that would also modify sorting. + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (setq helm-apropos-fuzzy-match t + helm-buffers-fuzzy-matching t + helm-ff-fuzzy-matching t + helm-projectile-fuzzy-match t + helm-recentf-fuzzy-match t + helm-M-x-fuzzy-match t) +#+end_src + +**** recursive minibuffers + +Recursive minibuffers allow to execute a minibuffer command while +currently in the minibuffer. With this enabled, I could use the +/completion at point/ from the minibuffer (maybe from +=eval-expression=). + +#+begin_src emacs-lisp :noweb-ref helm-config :tangle no + (setq enable-recursive-minibuffers t) +#+end_src + +*** helm-projectile + +Enable helm support for projectile and replace many projectile +commands with helm completion. + +#+begin_src emacs-lisp + (use-package helm-projectile + :ensure t + :after (helm) + :init + ; This needs to be set before loading helm-projectile + (setq helm-projectile-fuzzy-match t) + :config + (helm-projectile-on)) +#+end_src +** hydra + +With hydra I can build easy groups of commands that (maybe) can +repeated and share a common prefix. The advantage over other +mechanisms is, that hydra will show a overview of the available keys +after pressing the prefix. It is very flexible and maybe I should +create more hydras. + +#+begin_src emacs-lisp + (use-package hydra + :bind (("C-M-s" . alex/hydra-splitter/body) + ("<f2>" . alex/hydra-zoom/body) + ("C-t" . alex/hydra-toggle/body)) + :config + <<helm>>) +#+end_src + +*** move splitter + +With this hydra I can move the splitter between frames using the +cursor keys. + +#+begin_src emacs-lisp :noweb-ref helm :tangle no + (require 'hydra-examples) + (defhydra alex/hydra-splitter () + "Move window spitter" + ("<left>" hydra-move-splitter-left) + ("<right>" hydra-move-splitter-right) + ("<up>" hydra-move-splitter-up) + ("<down>" hydra-move-splitter-down)) +#+end_src + +*** zoom + +With this hydra I can change font site on demand, by repeatedly +pressing + or - until the desired font-size is reached. + +#+begin_src emacs-lisp :noweb-ref helm :tangle no + (defhydra alex/hydra-zoom () + "Change font size" + ("+" text-scale-increase "zoom in") + ("-" text-scale-decrease "zoom out")) +#+end_src + +*** toggle + +With this hydra I can toggle various common settings (or minor-modes) +using some shortcuts. + +Because the keys are already documented in the docstring, hydra should +not show all the keys again in the mode line and we globally set the +hint to nil. + +#+begin_src emacs-lisp :noweb-ref helm :tangle no + (defhydra alex/hydra-toggle (:hint nil) + " + + Toggle common settings/minor-modes: + + \[_d_\] debug-on-error: %`debug-on-error + \[_f_\] auto-fill-mode: %`auto-fill-function + \[_l_\] truncate-lines: %`truncate-lines + \[_w_\] whitespace-mode: %`whitespace-mode + \[_t_\] trailing-whitespaces: %`alex/tw-mode + \[_s_\] flyspell-mode: %`flyspell-mode + + \[_q_\] quit + " + ("d" toggle-debug-on-error) + ("f" auto-fill-mode) + ("l" toggle-truncate-lines) + ("w" whitespace-mode) + ("t" alex/tw-mode) + ("s" flyspell-mode) + ("q" nil)) +#+end_src + +** imenu + +=imenu= is part of core and does not need to be required. + +#+begin_src emacs-lisp + (bind-key [mouse-3] 'imenu) +#+end_src + +** ispell + +I want to use aspell to check the spelling. It correctly supports +Unicode and can have a very good quality of the suggestions. + +#+begin_src emacs-lisp + (setq ispell-program-name "aspell" + ispell-extra-args '("--sug-mode=slow")) +#+end_src + +Normally I do not want to enable flyspell-mode automatically. I only +want to enable it, if I specify a dictionary with =flyspell-dict= as +file-local variable. + +Here I define a buffer-local variable and allow the setting of all +strings as local variable without question. + +#+begin_src emacs-lisp + (defvar flyspell-dict nil + "Dictionary name, that should be set during `find-file' for + `flyspell-mode'. Set this as file-local or dir-local variable to + enable `flyspell-mode' automaticaly.") + (make-variable-buffer-local 'flyspell-dict) + (put 'flyspell-dict 'safe-local-variable #'stringp) +#+end_src + +Enable ispell (if available) and iterate with =F8= over the list of +preferred dictionaries. + +#+begin_src emacs-lisp + (use-package ispell + :config + (defvar alex/dictionaries '("english" "german") + "List of available dictionaries for ispell.") + + (defun alex/switch-dictionary() + (interactive) + (let ((new (alex/get-next ispell-current-dictionary alex/dictionaries))) + (ispell-change-dictionary new) + (message "Dictionary switched to %s" new))) + (global-set-key (kbd "<f8>") 'switch-dictionary) + + (use-package flyspell + :config + <<flyspell-config>>)) +#+end_src + +Update the flyspell status on various changes to the spell checking +(selecting a different dictionary or adding a word to the personal +dictionary). + +#+begin_src emacs-lisp :noweb-ref flyspell-config :tangle no + (defun alex/flyspell-update (&rest args) + (when flyspell-mode + (flyspell-buffer))) + + (add-hook 'flyspell-mode-hook 'alex/flyspell-update) + (advice-add 'ispell-change-dictionary :after #'alex/flyspell-update) + (advice-add 'ispell-pdict-save :after #'alex/flyspell-update) +#+end_src + +If =flyspell-dict= is set for the current buffer, set the value as +current ispell dictionary and enable flyspell-mode. =flyspell-dict= +should be set as local variable (file-local or dir-local). + +#+begin_src emacs-lisp :noweb-ref flyspell-config :tangle no + (defun alex/auto-flyspell-mode () + "Automatically set `flyspell-dict' as dictionary for ispell and + enable `flyspell-mode'." + (when flyspell-dict + (ispell-change-dictionary flyspell-dict) + (flyspell-mode 1))) + (add-hook 'find-file-hook 'alex/auto-flyspell-mode) +#+end_src + +This ignores all incorrect words in lines starting with +=#include=. =flyspell-prog-mode= only checks strings and comments, but +the include files could look like strings. + +#+begin_src emacs-lisp :noweb-ref flyspell-config :tangle no + (defun alex/flyspell-ignore-include (start end sug) + "Ignores all spelling errors in lines starting with #include." + (save-excursion + (goto-char start) + (beginning-of-line) + (if (looking-at "#include") + t + nil))) + + (add-hook 'flyspell-incorrect-hook 'alex/flyspell-ignore-include) +#+end_src + +** magit + +magit is a great mode for managing git repositories. I generally use +=magit-status= as entry point for viewing repository status, staging +and committing. For writing good commit messages, I activate +=flyspell-mode= in the =magit-log-edit-mode=. + +#+begin_src emacs-lisp + (use-package magit + :bind ("<f5>" . magit-status) + :config + (add-hook 'magit-log-edit-mode-hook (lambda () (flyspell-mode 1)))) +#+end_src +** multi-term + +multi-term supports much more terminal applications than similar modes +and can automatically toggle a dedicated window. The only disadvantage +is, that it does not work in combination with tramp. + +#+begin_src emacs-lisp + (use-package multi-term + :bind (("C-c t" . multi-term-dedicated-toggle) + ("C-c T" . multi-term)) + :config + ;;(setq multi-term-dedicated-select-after-open-p t) + ) +#+end_src +** neotree + +I rarely use a files browser in parallel to the main window. Usually I +simply use =find-file= or a dired buffer. But if I really need it, +neotree is a nice replacement for speedbar and simply work out of the +box. I only added projectile support, so that the neotree open per +default the project root (aka. the root of the git repository). + +#+begin_src emacs-lisp + (use-package neotree + :commands (neotree-dir neotree-find neotree-show) + :bind ("C-<tab>" . neotree-project-dir) + :init + (defun alex/neotree-find-file (dir file) + (neotree-dir dir) + (if file + (neotree-find (file-relative-name file dir)))) + + (defun neotree-project-dir () + "Open NeoTree using the git root." + (interactive) + (if (and (fboundp 'neo-global--window-exists-p) + (neo-global--window-exists-p)) + (neotree-hide) + (if (fboundp 'projectile-project-root) + (let ((projectile-require-project-root nil)) + (let ((project-dir (projectile-project-root)) + (file-name (projectile-file-truename (buffer-file-name)))) + (if project-dir + (alex/neotree-find-file project-dir file-name))))) + (neotree-show)))) +#+end_src + +** nlinum + +I generally want to have line numbers. nlinum works best with folding, +so I use that. + +#+begin_src emacs-lisp + (use-package nlinum + :config + <<nlinum-config>>) +#+end_src + +*** global mode + +I use my global-excluding-minor-mode stuff an define some exceptions, +where I do not want to have line numbers. + +#+begin_src emacs-lisp :noweb-ref nlinum-config :tangle no + (alex/define-global-excluding-minor-mode 'nlinum-mode) + + (setq nlinum-mode-exclude-list + '(:minibuffer + :mode + Custom-mode + Man-mode + compilation-mode + dired-mode + doc-view-mode + eshell-mode + helm--mode + helm--remap-mouse-mode + image-mode + magit-mode + magit-status-mode + neotree-mode + term-mode + text-mode + weechat-mode + wl-folder-mode + wl-summary-mode)) + + (alex/global-nlinum-mode t) +#+end_src + +*** number format + +I want to have some spacing around the numbers and calculate the +width, so that the width does not change during scrolling. + +#+begin_src emacs-lisp :noweb-ref nlinum-config :tangle no + (setq nlinum-format " %d ") + + (defun alex/nlinum-max-width () + "Calculate maximum width of line numbers" + (setq nlinum--width + (length (format nlinum-format + (count-lines (point-min) (point-max))))) + (nlinum--flush)) + (add-hook 'nlinum-mode-hook 'alex/nlinum-max-width) +#+end_src + +*** fix make-frame + +linum/nlinum currently triggers a bug in emacs: [[https://lists.gnu.org/archive/html/emacs-devel/2014-09/msg00022.html][Trunk emacs infelicity +with linum mode]] that make it impossible to create a new frame while +linum mode is active in at least on buffer. To fix this I +around-advice =make-frame= and deactivate nlinum before and reactivate +it again after creating the frame. + +#+begin_src emacs-lisp :noweb-ref nlinum-config :tangle no + (defun alex/deactivate-nlinum (buffer) + "Deactivates nlinum in the given BUFFER" + (with-current-buffer buffer + (nlinum-mode 0))) + + (defun alex/activate-nlinum (buffer) + "Activates nlinum in the given BUFFER" + (with-current-buffer buffer + (let ((res (nlinum-mode 1))) + (nlinum--flush) + res))) + + (defun alex/fix-nlinum (func &rest args) + "nlinum currently (emacs-24) triggers a bug, that makes it + impossible to create new frames because the linum face is not + defined. This is a fix, that deactivates nlinum in all buffers and + activate it again after creating the new frame." + (let ((nlinum-buffers (alex/get-buffers-with 'nlinum-mode))) + (mapc 'alex/deactivate-nlinum nlinum-buffers) + (alex/safe-call + (apply func args) + (mapc 'alex/activate-nlinum nlinum-buffers)))) + (advice-add 'make-frame :around #'alex/fix-nlinum) +#+end_src + +** org + +I use org-mode for my emacs config, taking notes, scheduling tasks and +maybe more. + +#+begin_src emacs-lisp + (use-package org + :mode ("\\.org\\'" . org-mode) + :demand t + :config + <<org>>) +#+end_src + +*** visual + +I want to have a nice display. + +On opening a org file, I want to see the outline but not the content +of all nodes. This is useful to get an overview. + +The nested org nodes should be intended, so that it is easy to see the +level, but I do not want to see the repeated stars in front of the +nodes. (The nodes may even got more fancy, if org-bullets is +available. See below.) + +If some parts are hidden, I want to prevent editing. If an edit action +is started the hidden region will be unfolded and the action has to be +confirmed. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (setq org-startup-folded 'content + org-startup-indented t + org-catch-invisible-edits t) +#+end_src + +Hide =org-indent-mode= from modeline. + +#+begin_src emacs-lisp + (alex/rm-add-blacklist " Ind") +#+end_src + +*** modules + +Setup some default modules to load. Some other modules might get +loaded on demand (see below). + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (setq org-modules '(org-annotate-file org-bbdb + org-checklist org-collector org-eval org-expiry + org-habit org-info org-man org-mouse org-protocol + org-toc org-wl)) + + (org-load-modules-maybe t) +#+end_src + +*** todo keywords + +Define some default TODO keywords and corresponding faces, that match +my theme with a dark background. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (setq org-todo-keywords + '((sequence "TODO" "STARTED(s)" "WAITING(w)" "DELEGATED(l)" "|" + "DONE(d)" "DEFERRED(f)" "CANCELLED(x)")) + + org-todo-keyword-faces + '(("TODO" . (:inherit org-warning)) + ("STARTED" . (:foreground "yellow" :weight bold)) + ("DELEGATED" . (:foreground "darkred" :weight bold)) + ("DEFERRED" . (:foreground "gray" :weight bold)) + ("CANCELLED" . (:foreground "gray" :weight normal)) + ("DONE" . (:foreground "cyan" :weight bold)))) +#+end_src + +*** bullets + +Automatically use org-bullets-mode if available and add the +possibility to disable it on a per-file basis with +=#+STARTUP: nobullets=. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (defvar alex/org-startup-with-bullets t + "Not-nil means entering Org-mode will enable org-bullets. This can + also be configured on a per-file basis adding on of the following + lines anywhere in the buffer: + + ,#+STARTUP: bullets + ,#+STARTUP: nobullets") + + (defun alex/org-bullets-setup () + "Enable org-bullets if `alex/org-startup-with-bullets' is not-nil." + (when alex/org-startup-with-bullets + (org-bullets-mode 1))) + (add-hook 'org-mode-hook 'alex/org-bullets-setup) + + (setq org-startup-options + (append org-startup-options + '(("bullets" org-startup-with-bullets t) + ("nobullets" org-startup-with-bullets nil)))) + + (use-package org-bullets + :commands (org-bullets-mode)) +#+end_src + +*** agenda + +The agenda view should be generated only from the =todo.org= file. +This file is the central place where I manage all TODO entries used +for the agenda view and the daily schedule. The agenda view should +always display 7 days from today, even if there are no scheduled tasks +for a day. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (use-package org-agenda + :bind ("C-c a" . org-agenda) + :config + (setq org-agenda-files '("~/doc/org/todo.org") + org-agenda-span 'week + org-deadline-warning-days 14 + org-agenda-show-all-dates t + org-agenda-skip-deadline-if-done t + org-agenda-skip-scheduled-if-done t + org-agenda-start-on-weekday nil + org-reverse-note-order t + org-fast-tag-selection-single-key 'expert)) +#+end_src + +*** capture + +Org-capture can quickly create notes or todo entries. It can also used +in combination with org-protocol to receive information from other +programs (like a web browser). + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (use-package org-capture + :commands (org-capture) + :bind ("C-c o" . org-capture) + :config + (setq org-default-notes-file "~/doc/org/notes.org" + org-capture-templates + '(("t" "Tasks" entry + (file "~/doc/org/todo.org") + "* TODO %?\n%u") + ("n" "Notes" entry + (file+headline "~/doc/org/notes.org" "Notes") + "* %u %?") + ("c" "Capture" entry + (file+headline "~/doc/org/notes.org" "Links") + "* %^{Title}\n\nSource: %u, %c\n\n%i")))) +#+end_src + +*** protocol + +Set default org-capture-template for org-protocol. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (setq org-protocol-default-template-key "c") +#+end_src + +When I start an org-capture in an org-protocol popup, I want to show +only the org-capture buffer (default behaviour would be to split the +current buffer) and I want to close the popup after finishing the +capture. + +When using org-capture with placeholders, we need to delete the other +windows just before starting to filling out the placeholders. The +advice after org-capture is too late, it would delete the other +windows after filling the placeholders. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (defun alex/org-capture-single-window (&rest args) + "Make the org-capture the only window when used as a popup" + (when (equal "emacs-capture" (frame-parameter nil 'name)) + (delete-other-windows))) + (advice-add 'org-capture :after #'alex/org-capture-single-window) + (advice-add 'org-completing-read-no-i :before #'alex/org-capture-single-window) + + (defun alex/org-capture-delete-frame (&rest args) + "Close the frame after finishing the capture, when used org-capture + as a popup" + (when (equal "emacs-capture" (frame-parameter nil 'name)) + (delete-frame))) + (advice-add 'org-capture-finalize :after #'alex/org-capture-delete-frame) +#+end_src + +*** journal + +#+begin_src emacs-lisp :noweb org-config :tangle no + (use-package org-journal + :bind ("C-c C-j" . org-journal-new-entry) + :config + (setq org-journal-dir "~/doc/org/journal/" + org-agenda-file-regexp "\\`\\([^.].*\\.org\\|[0-9]+\\)\\'")) +#+end_src + +*** org without helm + +org has a function, that requests input without ido completion. For +this function I disable helm. + +#+begin_src emacs-lisp :noweb-ref org :tangle no + (defun alex/run-without-helm (orig-func &rest args) + "Run a function without helm completion." + (if (boundp 'helm-mode) + (let ((orig-helm-mode helm-mode)) + (helm-mode 0) + (alex/safe-call + (apply orig-func args) + (when orig-helm-mode + (helm-mode 1)))) + (apply orig-func args))) + + (advice-add 'org-completing-read-no-i :around #'alex/run-without-helm) +#+end_src +** origami + +Sometimes I want to fold some code sections. There are several mode +available, but only origami supports insertion of new regions without +reopening or parsing the whole buffer. But I do not want to use the +semantic expression feature of origami and my markers should support a +title in the first line after the marker. + +I define my own parser for origami and modify the behaviour for my +needs. + +#+begin_src emacs-lisp + (use-package origami + :demand t + :bind (("C-c C-f" . origami-toggle-node) + ("C-c M-f" . origami-close-all-nodes) + ("C-c f" . origami-open-all-nodes)) + + :config + <<origami-config>>) +#+end_src + +*** custom format for folded display + +Per default origami is used to fold semantic expressions and only +shows the marker at the front and end of the region. I want to use +explicit marker inside comments and want to add a description (title) +for the region after the opening marker. So I want to keep the whole +first line visible while the region is folded. + +#+begin_src emacs-lisp :noweb-ref origami-config :tangle no + (defun alex/origami-build-pair-tree (create open close positions) + "This is like `origami-build-pair-tree' and now keeps the whole + first line visible while folded." + (cl-labels ((build (positions) + ;; this is so horrible, but fast + (let (acc beg (should-continue t)) + (while (and should-continue positions) + (cond ((equal (caar positions) open) + (if beg ;go down a level + (let* ((res (build positions)) + (new-pos (car res)) + (children (cdr res)) + (beg-end (save-excursion + (goto-char beg) + (line-end-position))) + (end (cdar new-pos))) + (setq positions (cdr new-pos)) + (setq acc (cons (funcall create beg (+ end (length close)) (- beg-end beg) children) + acc)) + (setq beg nil)) + ;; begin a new pair + (setq beg (cdar positions)) + (setq positions (cdr positions)))) + ((equal (caar positions) close) + (if beg + (let ((beg-end (save-excursion + (goto-char beg) + (line-end-position))) + (end (cdar positions))) + (if (< beg-end end) + ;;close with no children + (setq acc (cons (funcall create beg (+ end (length close)) (- beg-end beg) nil) + acc))) + (setq positions (cdr positions)) + (setq beg nil)) + (setq should-continue nil))))) + (cons positions (reverse acc))))) + (cdr (build positions)))) +#+end_src + +*** respect derived modes + +I manually specify the parser for the origami markers. For more +flexibility I want to support derived modes (f.e. if I assign a value +for emacs-list-mode, this parser should also support the +lisp-interaction-mode). + +Therefore I advice the =origami-get-parser= function and temporarily +overwrite the =origami-parser-alist= and change all definitions with a +compatible mode to the exact major mode of the requested buffer. + +#+begin_src emacs-lisp :noweb-ref origami-config :tangle no + (defun alex/origami-is-derived-mode (buffer parser-elem) + "Helper for `alex/origami-parser-derived-modes' to check if the + current major-mdoe in BUFFER is a dreived mode of the mode part of + an element from the `origami-parser-alist'." + (let ((mode (car parser-elem)) + (parser (cdr parser-elem))) + (with-current-buffer buffer + (if (derived-mode-p mode) + (cons major-mode parser) + nil)))) + + (defun alex/origami-parser-derived-modes (func buffer &rest args) + "Modify the origami-parser-alist on demand to respect the derived + major-modes of the defined modes." + (let* ((check (apply-partially 'alex/origami-is-derived-mode buffer)) + (origami-parser-alist (delq nil (mapcar check origami-parser-alist)))) + (apply func buffer args))) + + (advice-add 'origami-get-parser :around #'alex/origami-parser-derived-modes) +#+end_src + +*** define simple marker for different modes + +#+begin_src emacs-lisp :noweb-ref origami-config :tangle no + (defun alex/origami-markers-parser (begin end create) + "Create a origami parser for regions between BEGIN and END + markers. The folded region will show the complete first line after the + marker but not the END marker." + (lexical-let ((create-tmp create) + (begin-tmp begin) + (end-tmp end) + (regexp (rx-to-string `(or ,begin ,end)))) + (lambda (content) + (let ((positions (origami-get-positions content regexp))) + (alex/origami-build-pair-tree create-tmp begin-tmp end-tmp positions))))) + + (defun alex/origami-marker (mode start end) + "Define a cons with MODE and the marker-parser for origmai, that + could be used directly as element for `origami-parser-alist'." + `(,mode . ,(apply-partially 'alex/origami-markers-parser start end))) + + (setq origami-parser-alist + `(,(alex/origami-marker 'emacs-lisp-mode ";;{{{" ";;}}}") + ,(alex/origami-marker 'lisp-mode ";;{{{" ";;}}}") + ,(alex/origami-marker 'sh-mode "#{{{" "#}}}") + ,(alex/origami-marker 'php-mode "//{{{" "//}}}") + ,(alex/origami-marker 'haskell-mode "--{{{" "--}}}"))) +#+end_src + +*** global-minor-mode + +I want to use origami-mode everywhere, so I create a global minor-mode +and activate it. + +#+begin_src emacs-lisp :noweb-ref origami-config :tangle no + (alex/define-global-excluding-minor-mode 'origami-mode) + (alex/global-origami-mode t) +#+end_src +** powerline + +I use powerline to get a nicer modeline, but I change some aspects to +enhance it even more. + +#+begin_src emacs-lisp + (use-package powerline + :config + <<powerline-config>>) +#+end_src + +*** display utf8 glyphs + +Currently powerline only displays the nice utf-8 glyphs (f.e. for git +branches) if =window-system= is nil. So we simply wrap =powerline-vc= +and temporarily unset =window-system=. + +#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no + (defun alex/fix-powerline-vc (orig-fun &rest args) + "Fix utf8 glyphs display." + (let ((window-system nil)) + (apply orig-fun args))) + (advice-add 'powerline-vc :around #'alex/fix-powerline-vc) +#+end_src + +*** smart-mode-line + +I only use smart-mode-line for the file paths feature. I need to call +=sml/setup=, but I do not want to load a theme because it is +incompatible with powerline. So I simply overwrite =sml/-setup-theme= +with =ignore=. + +#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no + (use-package smart-mode-line + :config + (advice-add 'sml/-setup-theme :around #'ignore) + (sml/setup)) +#+end_src + +*** rich-minority + +I use rich-minority-mode, that has no support for powerline out of the +box. So I advice the =powerline-minor-modes= function and let +rich-minority temporarily overwrite the minor-mode-alist. + +#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no + (defun alex/powerline-rm-setup () + (defun alex/powerline-rm (orig-fun &rest args) + "Applies the rich-minority-mode on the powerline display of the + minor-modes." + (let ((minor-mode-alist (if rich-minority-mode + (rm--mode-list-as-string-list) + minor-mode-alist))) + (apply orig-fun args))) + (advice-add 'powerline-minor-modes :around #'alex/powerline-rm)) + + (eval-after-load 'rich-minority #'alex/powerline-rm-setup) +#+end_src + +*** powerline theme + +Setup the powerline theme. Currently I only change the separator and +make it a little bit higher. + +#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no + (setq powerline-default-separator 'wave + powerline-height 25) + + (powerline-default-theme) +#+end_src + +** projectile + +Projectile allows fast search for files in project directories. I want +to use it everywhere but do not want to see the minor-mode. It +automatically recognize git repositories as projects. + +#+begin_src emacs-lisp + (use-package projectile + :diminish " Projectile.*" + :config + (projectile-global-mode) + (setq projectile-enable-caching t + projectile-cache-file (alex/cache-file "projectile") + projectile-known-projects-file (alex/cache-file "projectile-bookmarks"))) +#+end_src + +** semantic + +semantic is an emacs mode, that parses the source code of the current +buffer. It has support for many languages out of the box (C/C++, +Python, elisp, Erlang...). I want to enable it in all buffers. The +only disadvantage is, that opening a file could trigger the parsing +and will block emacs for a while (depending on how many files are in +the including hierarchy). + +#+begin_src emacs-lisp + (use-package semantic + :config + (use-package semantic/ia) + (setq semanticdb-default-save-directory (alex/cache-file "semantic")) + + (semantic-mode 1) + (global-semantic-idle-summary-mode 1)) +#+end_src + +** server + +Start server (if not running) to edit files with emacsclient and +rebind =C-x k= in server buffers to close it. + +#+begin_src emacs-lisp + (use-package server + :config + (when (and (fboundp 'server-running-p) + (not (server-running-p))) + (server-start)) + + (defun alex/server-swtich-hook () + (when (current-local-map) + (use-local-map (copy-keymap (current-local-map)))) + (when server-buffer-clients + (local-set-key (kbd "C-x k") 'server-edit))) + + (add-hook 'server-switch-hook 'alex/server-swtich-hook)) + +#+end_src + +** smartparens + +smartparens-mode has various features. I only want to have the +highlighting of matching parens and the automatic wrapping of the +region, but I do not want that it inserts, deletes or skips some +parens. + +#+begin_src emacs-lisp + (use-package smartparens-config + :config + (setq-default sp-autoinsert-pair nil + sp-autodelete-pair nil + sp-autodelete-opening-pair nil + sp-autodelete-closing-pair nil + sp-autoskip-closing-pair nil) + + (smartparens-global-mode t) + (show-smartparens-global-mode t) + :diminish + " SP") +#+end_src + +** template + +I want to insert template automatically in new empty files with the +correct extension. But I only want to search for global templates by +default and not in a sub directory of the new file. I also do not want +to update the content of a file after saving (f.e. when saving under a +different name). + +#+begin_src emacs-lisp + (use-package template + :config + (setq template-auto-insert t + template-auto-update nil + template-confirm-insecure nil + + template-date-format "%Y-%m-%d" + template-time-format "%T" + + template-subdirectories nil + template-default-directories (list (concat user-emacs-directory + "templates/"))) + (template-initialize)) +#+end_src +** tramp + +I usually have very heavy shell customization on remote hosts. I do +not want to depend, that tramp can parse my custom prompt format. So I +set =sshx= as default tramp method, that explicit invoke =/bin/sh= as +shell on the remote host. + +#+begin_src emacs-lisp + (use-package tramp + :config + (setq tramp-default-method "sshx" + tramp-persistency-file-name (alex/cache-file "tramp"))) +#+end_src + +*** dir-locals + +Support dir-locals also via tramp. This leads to a additional delay +while opening a file via tramp (because it has to check for the +dir-locals file over ssh) but usually I do not want to clutter single +files with file-local variables. + +#+begin_src emacs-lisp + (setq enable-remote-dir-locals t) +#+end_src +** uniquify + +Use a better approach to make unique buffer names. The default +algorithm just adds a count after the filename if you opened two files +with the same name. =uniquify= adds the path to the buffer name, so +that the right buffer is easier to identify. + +#+begin_src emacs-lisp + (use-package uniquify + :config + (setq uniquify-buffer-name-style 'reverse)) +#+end_src + +** uptimes + +I want to measure the uptime of emacs. This should not be deferred +loaded, because it captures the start time of in the moment it gets +loaded. + +#+begin_src emacs-lisp + (use-package uptimes + :demand t + :config + (setq uptimes-database (alex/cache-file "uptimes"))) +#+end_src + +** weechat + +#+begin_src emacs-lisp + (use-package weechat + :commands (weechat-connect) + :functions (weechat-channel-names + weechat-monitor-buffer + weechat--find-buffer + weechat-buffer-hash) + + :init + (defun weechat () + "Start weechat with `weechat-connect' and automatically switch to + the first buffer in `weechat-auto-monitor-buffers'." + (interactive) + (weechat-connect) + (when weechat-auto-monitor-buffers + (switch-to-buffer + (car weechat-auto-monitor-buffers)))) + + :config + <<weechat-config>>) +#+end_src + +*** config + +I connect to weechat running on the host called =island= via ssh +tunneling, monitor only a few buffers by default and close the buffers +on disconnect. + +#+begin_src emacs-lisp :noweb-ref weechat-config :tangle no + (setq weechat-buffer-kill-buffers-on-disconnect t + + weechat-host-default "is.zedat.fu-berlin.de" + weechat-port-default 58224 + weechat-mode-default "ssh -W localhost:%p %h" + + weechat-text-column 25 + weechat-header-line-format "%c/%s: %t" + + weechat-auto-monitor-buffers '("freenode.#spline" + "ircnet.&ZEDAT-IS" + "oftc.#vserver")) + + (defun alex/weechat-mode-hook () + "Activate `visual-line-mode'." + (visual-line-mode 1)) + (add-hook 'weechat-mode-hook 'alex/weechat-mode-hook) +#+end_src + +*** helm support + +#+begin_src emacs-lisp :noweb-ref weechat-config :tangle no + (defun alex/helm-weechat-support () + + (defun alex/weechat-new-buffers () + (let ((current (weechat-channel-names t)) + (all (weechat-channel-names nil))) + (mapc (lambda (cur) (setq all (delete cur all))) current) + (sort all 'string-lessp))) + + (defun alex/weechat-add-buffer (name) + (weechat-monitor-buffer (weechat--find-buffer name) t)) + + (defun alex/weechat-get-count (channel type) + (let ((hash (gethash type channel))) + (if (not (not hash)) + (gethash :count hash) + 0))) + + (defun alex/weechat-show-topic (channels) + (mapcar + (lambda (channel) + (let* ((hash (weechat-buffer-hash (weechat--find-buffer channel))) + (hlight (alex/weechat-get-count hash :background-highlight)) + (message (alex/weechat-get-count hash :background-message)) + (chan-name (if (> (string-width channel) helm-buffer-max-length) + (helm-substring-by-width + channel helm-buffer-max-length) + (concat channel (make-string + (- (+ helm-buffer-max-length 3) + (string-width channel)) ? )))) + (chan (cond + ((> hlight 0) + (propertize chan-name 'face 'helm-buffer-saved-out)) + ((> message 0) + (propertize chan-name 'face 'helm-buffer-not-saved)) + (t chan-name))) + (hlight-count (if (> hlight 0) + (propertize (format "%-3d" hlight) + 'face 'helm-buffer-saved-out) + " ")) + (message-count (if (> message 0) + (format "%3d" message) " ")) + (count-sep (if (and (> message 0) (> hlight 0)) + "," " ")) + (topic (propertize + (gethash "title" hash) + 'face 'helm-ff-symlink))) + (cons (format "%s\t%s%s%s\t%s" chan message-count count-sep + hlight-count topic) + channel))) + channels)) + + (defun alex/weechat-ignore-buffer (channels) + (delq nil + (mapcar + (lambda (channel) + (let* ((hash (weechat-buffer-hash (weechat--find-buffer channel))) + (plugin (cdr (assoc "plugin" (gethash "local_variables" hash)))) + (type (cdr (assoc "type" (gethash "local_variables" hash))))) + (when (and (string= "irc" plugin) (string= "channel" type)) + channel))) + channels))) + + (defun alex/helm-weechat-buffer-toggle-ignore () + (interactive) + (with-helm-alive-p + (let ((filter-attrs (helm-attr 'candidate-transformer + alex/weechat-new-buffers-source))) + (if (memq 'alex/weechat-ignore-buffer filter-attrs) + (helm-attrset 'candidate-transformer + (remove 'alex/weechat-ignore-buffer + filter-attrs) + alex/weechat-new-buffers-source t) + (helm-attrset 'candidate-transformer + (cons 'alex/weechat-ignore-buffer + filter-attrs) + alex/weechat-new-buffers-source t)) + (helm-force-update)))) + + (setq alex/helm-weechat-buffer-map (copy-keymap helm-map)) + (bind-key "C-c C-c" 'alex/helm-weechat-buffer-toggle-ignore + alex/helm-weechat-buffer-map) + + (setq alex/weechat-new-buffers-source nil) + (defun alex/helm-weechat-buffer () + (interactive) + (setq alex/weechat-new-buffers-source + (helm-build-sync-source "Available channel" + :candidates (alex/weechat-new-buffers) + :action '(("Monitor channel" . alex/weechat-add-buffer)) + :candidate-transformer '(alex/weechat-ignore-buffer + alex/weechat-show-topic))) + (let ((helm-truncate-lines t)) + (helm + :sources (list + (helm-build-sync-source "Buffers" + :candidates (weechat-channel-names t) + :action '(("Open buffer" . switch-to-buffer)) + :candidate-transformer '(alex/weechat-show-topic)) + alex/weechat-new-buffers-source) + :buffer "*weechat*" + :keymap alex/helm-weechat-buffer-map))) + + (bind-key "C-c C-b" 'alex/helm-weechat-buffer weechat-mode-map) + + (defun alex/mark-read () + "Mark buffer as read up to current line." + (interactive) + (let ((inhibit-read-only t)) + (put-text-property + (point-min) (line-beginning-position) + 'face 'font-lock-comment-face))) + (bind-key "<escape>" 'alex/mark-read weechat-mode-map)) + + (eval-after-load 'helm #'alex/helm-weechat-support) +#+end_src +** which-key + +I cannot remember all the key combinations. which-key will show a +hint for possible completions, if I start a key combo and wait longer +than 1s before continue with the next key. + +#+begin_src emacs-lisp + (use-package which-key + :config + (setq which-key-idle-delay 1.0) + (which-key-mode t) + :diminish + which-key-mode) +#+end_src + +** winner + +I use winner to quickly restore a previous window configuration after +it was changed by something. I demand it here, because winner mode +need to be active to keep track of the changes and helm will notice it +and will insert the helm buffer names into =winner-boring-buffers=. + +#+begin_src emacs-lisp + (use-package winner + :bind (("C-c <left>" . winner-undo) + ("C-c <right>" . winner-redo)) + :demand t + :config + (winner-mode 1)) +#+end_src + +** winring + +With winring it is possible to manage different window configurations +and switching between. This could be useful if working with +specialized window configurations (f.e. for debugging) and activating +it when needed. + +#+begin_src emacs-lisp + (use-package winring + :bind (("C-x j" . winring-jump-to-configuration) + ("C-x n" . winring-new-configuration) + ("C-x K" . winring-delete-configuration)) + :functions (winring-initialize) + :config + (winring-initialize) + + (defun alex/confirm-winring-deletion (&rest args) + (y-or-n-p (format "Delete winring configuration %s? " winring-name))) + + (advice-add 'winring-delete-configuration + :before-while + #'alex/confirm-winring-deletion)) +#+end_src + +** wl + +Here are only the functions for auto-loading. I customize wanderlust, +to load the profile from the org-babel file =init.d/wl.org= during +start-up of wanderlust. + +I use a separate frame for wanderlust with a custom name, so that +XMonad can shift it to a different desktop. Additionally I create +a function, that should be called with emacsclient to compose a new +message from a mailto link. This function also creates a new frame +with a custom name and closes it after sending the mail. + +#+begin_src emacs-lisp + (use-package wl + :commands (wl-other-frame wl-draft) + :init + (defun wl-start () + "Start wanderlust in a seperate frame and set the name of the new + frame to `wanderlust'." + (interactive) + (let ((default-frame-alist + (cons '(name . "wanderlust") default-frame-alist))) + (wl-other-frame))) + + (defun alex/wl-mailto-compose-new-frame (mailto-url) + "Compose a new mail from a mailto link with wanderlust in a new + frame and customize the name of the new frame to + `wanderlust-draft'." + (let ((default-frame-alist + (cons '(name . "wanderlust-draft") default-frame-alist)) + (wl-draft-use-frame t)) + (alex/wl-mailto-compose mailto-url) + (set-window-dedicated-p (selected-window) t) + + (make-local-variable 'wl-draft-force-delete-frame) + (setq wl-draft-force-delete-frame t) + (run-hooks 'wl-mail-setup-hook))) + + (require 'rfc2368) + (defun alex/wl-mailto-compose (mailto-url) + "Parse a rfc2368 mailto links and call `wl-draft' with the + information for the headers and the body." + (when (and (stringp mailto-url) (string-match "\\`mailto:" mailto-url)) + (let* ((headers (mapcar (lambda (h) (cons (intern (car h)) (cdr h))) + (rfc2368-parse-mailto-url mailto-url))) + (good-headers (assq-delete-all 'Body (copy-alist headers))) + (body (cdr (assoc 'Body headers)))) + (wl-draft good-headers nil nil body)))) + + (defvar wl-draft-force-delete-frame nil + "If this variable is t `alex/wl-draft-force-hide' always delete + the frame after closing the draft. You may want to make this + variable buffer-local whenever you use it. This variable is used by + `alex/wl-mailto-compose-new-frame' to close the created frame after + composing the mail.") + + (defun alex/wl-draft-force-hide (func &rest args) + "This advice removes the draft-frame even if no other frame is + visible if `alex/wl-draft-force-delete-frame' is non-nil." + (let ((force-delete (and (boundp 'wl-draft-force-delete-frame) + wl-draft-force-delete-frame))) + (apply func args) + (if force-delete + (delete-frame)))) + (advice-add 'wl-draft-hide :around #'alex/wl-draft-force-hide) + + :config + (defun alex/wl-babel-load-profile () + "Load `wl-init-file' with `org-babel-load-file'." + (org-babel-load-file wl-init-file)) + + (setq wl-init-file (locate-user-emacs-file "init.d/wl.org") + wl-load-profile-function 'alex/wl-babel-load-profile)) +#+end_src + +** yasnippet + +I want to use yasnippets everywhere, so I enable the global mode. In +addition to the default snippets I have some in my personal dir. It +does not load the all snippets during startup, but only if the first +buffer switches to the corresponding mode (only the directories are +searched during activation of the global mode). + +#+begin_src emacs-lisp + (use-package yasnippet + :config + (setq yas-snippet-dirs `("~/.emacs.d/snippets/" + ,yas-installed-snippets-dir)) + (yas-global-mode 1) + :diminish yas-minor-mode) +#+end_src + |