;; -*-mode:emacs-lisp; coding:utf-8; fill-column:80;-*-

;;; .emacs.el -- Universal Startup File for GNU Emacs
;;    ___ _ __ ___   __ _  ___ ___
;;   / _ \ '_ ` _ \ / _` |/ __/ __|
;;  |  __/ | | | | | (_| | (__\__ \
;; (_)___|_| |_| |_|\__,_|\___|___/

;;; -------- VENUE
;;; ----------------------------------------------------------------------------

;; This is  a UNIVERSAL EMACS  STARTUP FILE for  regular GNU Emacs  and Emacs/NT
;; (Windows).  Requires   at  least  Emacs   21.2+.  It  contains   no  personal
;; information. Customize it to your own taste:

;; (1) This <.emacs> implicitly evaluates <./.emacs.local> and <~/.emacs.local>
;;     if they exists.
;;
;; (2) Directory <~/.emacs.d/lisp> is a good place for user-specific Elisp
;;     packages that are not part of GNU Emacs.

;;; -------- MODES
;;; ----------------------------------------------------------------------------

;;;; Anti-RSI (Repeated Strain Injury):

;; This  .emacs enables  `type-break-mode' for  all buffers.  When this  mode is
;; enabled,  the  user  is  encouraged  to take  typing  breaks  at  appropriate
;; intervals. Consider the command `type-break-statistics'.

;;;; Debugging:
;;
;; - To identify what parts of your `.emacs' consume time to load, start Emacs
;;   with -q and evaluate: `(benchmark-run (require 'package))'
;;
;; - When .emacs.el does not startup because of unbalanced parantheses, go to
;;   the end of the file and type C-u C-M-u. This will move you to the beginning
;;   of the first unbalanced sexp.

(setq debug-on-error nil debug-on-signal nil debug-on-quit nil
      ;; warning-minimum-level :emergency
      )

;;; -------- COPYRIGHT/LICENSE
;;; ----------------------------------------------------------------------------

;; Copyright © 1998-2016  Andreas Spindler. This file is free  software; you can
;; redistribute it  and/or modify it under  the terms of the  GNU General Public
;; License as published by the Free SoftwareFoundation; either version 2, or (at
;; your option) any later version. It is distributed in the hope that it will be
;; useful,  but  WITHOUTANY  WARRANTY;  without even  the  implied  warranty  of
;; MERCHANTABILITY  or FITNESS  FOR A  PARTICULAR PURPOSE.  See the  GNU General
;; Public License for more details.

;; $Author: Andreas Spindler <info@visualco.de>$
;; $Maintained at: http://www.visualco.de$
;; $Writestamp: 2016-08-18 13:43:53$

;;; -------- ENVIRONMENT
;;; ----------------------------------------------------------------------------

;;;; Environemnt:

(defconst --startup-time (float-time (current-time)))
(defconst --xemacs-p (featurep 'xemacs) "XEmacs?")
(defun --is-version (a b) (and (not --xemacs-p)
                                 (>= emacs-major-version a)
                                 (>= emacs-minor-version b)))
(defconst --emacs24p (--is-version 24 4) "Emacs 24.4+?")
(defconst --emacs23p (--is-version 23 1) "Emacs 23.1+?")
(defconst --emacs22p (--is-version 22 0) "Emacs 22.0+?")
(defconst --emacs21p (--is-version 21 0) "Emacs 21.0+?")
(defconst --winnt-p (memq window-system '(w32 win32 windows-nt))
  "Running under Windows NT?")
(defconst --cygwin-p (or (eq system-type 'cygwin)
                         (and --winnt-p (file-accessible-directory-p "C:\\cygwin")))
  "Running under Windows NT with Cygwin installed to C:/cygwin?")
(defconst --xwm-p (memq window-system '(x)) "Running under X")
(defconst --unix-p (memq window-system '(usg-unix-v berkeley-unix))
  "Running under a unixoid OS?")
(defconst --superuser-p (eq 0 (user-uid))
  "Is this Emacs instance run by the super-user (root)?")
(defun --server-p ()
  "Is running as server?"
  ;; http://stackoverflow.com/questions/3704962/how-to-know-if-emacs-server-is-running
  (condition-case nil
      (and (boundp 'server-process)
           (memq (process-status server-process) '(connect listen open run)))
    (error)))

;;;; Startup options:

(defconst --no-desktop (member "--no-desktop" command-line-args)
  "Non-nil if `--no-desktop' command-line switch given.")
(defconst --batch-mode (or noninteractive (member "--batch-mode" command-line-args))
  "Non-nil if -batch-mode command-line switch given.")
(defconst --dark-p (not --batch-mode)
  "Non-nil activates dark color scheme.")
(defun --startup-frame()
  "Return primary frame."
  default-minibuffer-frame)
(defun --startup-directory ()
  "Return primary directory, i.e. the directory from which Emacs was started:
`desktop-dirname', `default-directory' local variable of the *scratch* buffer."
  (if (and (not --no-desktop) );desktop-dirname)
      ;desktop-dirname
    (with-current-buffer "*scratch*" default-directory)))
(defun --startup-buffer ()
  "Return default buffer from \\[--startup-directory] ."
  (let ((buf) (dir (--startup-directory))
        (l '("GNUmakefile" "MAKEFILE" "Makefile" "makefile" "Makefile.PL" "Makefile.in"
             "_config.yml" "sconscript" "sconstruct"
             "_Build.sh" "Build.sh" "Build" "build"
             "_Build.cmd" "Build.cmd" "_build.cmd" "_StartStudio.cmd"
             "README" "README.txt" "README.TXT" "readme.txt"
             "VENUE" "MOTIVATION" "AGENDA" "TODO" "DOXYFILE" "Doxyfile"
             "INSTALL" "INSTALL.txt" "INSTALL.TXT" "install.txt"
             "MANIFEST" "ChangeLog")))
    (while (and (not buf) l)
      (if (not (safe-file-exists-p (setq f (concat dir (car l)))))
          (setq l (cdr l))
        (setq buf (find-file-noselect f))))
    ))

;;;; Tame Emacs:

;; No visible bell, high thresholds. Neutralize the startup fanfare.

(setq visible-bell t
      inhibit-startup-screen t
      inhibit-startup-message t
      auto-revert-verbose nil
      revert-without-query (list ".+")
      large-file-warning-threshold (* 1000 1024 1024))

(when (and --winnt-p --emacs22p)
  (set-message-beep 'silent))
(defun display-startup-echo-area-message ())
(add-hook 'after-init-hook
          '(lambda()
             (when (get-buffer "*Warning s*") ; usually: "Emacs server running"
               (delete-windows-on "*Warnings*"))
             (if --cygwin-p ; Emacs warns when not using cmd.exe under Windows
                 (run-with-idle-timer 0 nil '(lambda()
                                               (when (get-buffer "*Shell Configuration*")
                                                 (delete-windows-on "*Shell Configuration*"))))
               )))

;; In the default configuration BS (ASCII 8) and `C-h' are both
;; `backward-delete-char-untabify'.

(fset 'yes-or-no-p 'y-or-n-p)
(global-set-key "\M-h" 'help-command)
(global-set-key "\C-h" 'help-command)
(setq undo-limit (* 108 undo-limit)
      undo-strong-limit (* 108 undo-strong-limit)
      message-log-max t
      mark-ring-max 8000
      global-mark-ring-max 4000
      echo-keystrokes 0.5)
(if --emacs23p
    (setq major-mode 'text-mode fill-column 80))
(setq comment-column 72)

;;;; `frame-title-format':

;; Run generating the title lazy to speed up starting Emacs.

(add-hook
 'after-init-hook
 '(lambda()
    (run-with-idle-timer
     5 nil
     '(lambda ()
        (setq frame-title-format
              (concat
               (or
                (getenv "USER") (getenv "USERNAME"))
               "@"
               (condition-case nil
                   (replace-regexp-in-string
                    "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" "" ; chomp
                    (if --unix-p
                        (with-output-to-string
                          (call-process "/bin/hostname" nil standard-output nil)))
                    (if --cygwin-p
                        (with-output-to-string
                          (call-process "C:/cygwin/bin/hostname" nil standard-output nil)))
                    )
                 (error))
               ":%f" " " "%F" " "
               "[" (--startup-directory) "]" " "
               ;; (if (--server-p) "[Server]")
               ))))))

;;;; Modeline, Minibuffer, Completion:

(setq resize-minibuffer-mode t
      resize-mini-windows t)
(file-name-shadow-mode 1)
(icomplete-mode t)
(setq read-buffer-completion-ignore-case t
      read-file-name-completion-ignore-case t
      completion-ignore-case t
      completion-ignored-extensions
      (append '(".o" ".elc" ".ps" ".pdf") completion-ignored-extensions))

;;;; Default frame configuration:

(menu-bar-mode 0)
(when --xwm-p
  (tool-bar-mode nil)
  (set-scroll-bar-mode 'left))
(setq icon-title-format "%b %t %f"
      popup-frames t
      line-number-mode t
      column-number-mode t
      frame-background-mode (if --dark-p 'dark 'light))
(cond
 ((eq frame-background-mode 'dark)
  (when --xwm-p (toggle-scroll-bar 0))
  (set-face-foreground 'mode-line "Aquamarine")
  (set-face-background 'mode-line "Black")
  (setq initial-frame-alist             ; standard colors for new frames
        '((foreground-color . "NavajoWhite")
          (background-color . "gray8")))
  )
 (t
  (when --xwm-p (toggle-scroll-bar 1))
  (set-face-background 'mode-line "midnightblue")
  (setq initial-frame-alist '((foreground-color . "black")
                              (background-color . "ghost white"))))
 )

(setq default-frame-alist initial-frame-alist)
(setq display-time-day-and-date t       ; display time in modeline
      display-time-24hr-format t)
(run-with-idle-timer 5 nil '(lambda() (display-time)))
(setq-default left-margin-width  1
              right-margin-width 0)

(if --emacs24p
    (add-to-list 'display-buffer-alist  ; display-buffer-reuse-frames obsolete since 24.3
                 '("." nil (reusable-frames . t)))
  (defvar display-buffer-reuse-frames)  ; https://www.gnu.org/software/emacs/manual/html_node/elisp/Warning-Tips.html
  (setq display-buffer-reuse-frames t))

;;;; Mouse color and scrolling:

(run-with-idle-timer 1 nil
                     '(lambda()
                        (mouse-avoidance-mode 'exile)
                        (if (load "mwheel" t t)
                            (mwheel-install))
                        (setq mouse-scroll-delay 0.0
                              mouse-wheel-scroll-amount '(3 ((shift) . 1) ((control) . nil))
                              mouse-wheel-progressive-speed nil ; don't accelerate scrolling
                              mouse-wheel-follow-mouse t        ; scroll window under mouse
                              scroll-error-top-bottom t)
                        ))
(global-set-key [down-mouse-3] 'imenu)  ; right mouse button -> imenu

;;;; Point color and shape:

(setq cursor-in-non-selected-windows nil)
(add-hook
 'post-command-hook
 '(lambda ()
    "Change cursor color and type according to some minor modes."
    ;; Change cursor color according to mode; inspired by
    ;; http://www.emacswiki.org/emacs/ChangingCursorDynamically.
    (setq read-only-color "Yellow"
          read-only-type '(bar . 3)
          overwrite-color "Gold"
          overwrite-cursor-type 'box
          regular-color (if --dark-p "Yellow" "DarkOrange")
          regular-cursor-type 'box)
    (cond
     (buffer-read-only
      (set-cursor-color read-only-color)
      (setq cursor-type read-only-type)
      (blink-cursor-mode 0))
     (overwrite-mode
      (set-cursor-color overwrite-color)
      (setq cursor-type overwrite-cursor-type)
      (blink-cursor-mode 1))
     (t
      (set-cursor-color regular-color)
      (setq cursor-type regular-cursor-type)
      (blink-cursor-mode 0)))
    ))

;;;; Parentheses:

(when t
  (setq show-paren-ring-bell-on-mismatch nil
        show-paren-style 'mixed
        show-paren-delay .400
        blink-matching-delay .5
        blink-matching-paren t)
  (run-with-idle-timer
   5 nil '(lambda()
            (show-paren-mode t)
            (defadvice show-paren-function (after show-matching-paren-offscreen activate)
              "If the matching paren is offscreen, show the matching line in the
echo area. Has no effect if the character before point is not of the syntax
class ')'."
              (interactive)
              (let* ((cb (char-before (point)))
                     (matching-text (and cb
                                         (char-equal (char-syntax cb) ?\) )
                                         (blink-matching-open))))
                (when matching-text (message matching-text))))
            ))
  )

;;;; IDO-Mode (interactive do)

;; Switches between buffers, files and directories with a minimum of keystrokes,
;; by using a different completion function. Supersedes `iswitchb', which
;; provided that functionality only for buffer switching.

(require 'ido)
(ido-mode 1)
(setq ido-everywhere t
      ido-enable-flex-matching t       ; match any characters in the substring
      ido-confirm-unique-completion t  ; wait for RET on unique TAB completeions
      ido-max-prospects 20)
(global-set-key [(C-next)]  'ido-switch-buffer)
(global-set-key [(C-prior)] 'ido-switch-buffer-other-frame)

(defun --copy-face (face new-face)
  "Define NEW-FACE from existing FACE."
  (copy-face face new-face)
  (eval `(defvar ,new-face nil))
  (set new-face new-face))

(add-hook 'font-lock-mode-hook
          '(lambda()
             (require 'dired)
             (--copy-face 'dired-marked    'ido-first-match)
             (--copy-face 'dired-mark      'ido-only-match)
             (--copy-face 'isearch-fail    'ido-incomplete-regexp)
             (--copy-face 'dired-directory 'ido-subdir)))

;;;; Highlight current line:

(unless (or --no-desktop --batch-mode (not --emacs21p))
  (when (require 'hl-line nil t)
    (setq hl-line-sticky-flag nil)))

;;;; Window margins:

(defvar --default-window-margins (list 3 7))

;;;; Shortcut functions:

(defun main ()
  "Switch to \\[--startup-buffer]."
  (interactive)
  (let ((buf (--startup-buffer)))
    (if buf
        (if current-prefix-arg
            (message buf)
          (switch-to-buffer buf t))
      (message "No startup buffer"))
  ))
(defun msg ()
  "Switch to *Messages* buffer."
  (interactive) (switch-to-buffer "*Messages*") (--end-of-buffer))
(defun lorem ()
  "Insert a lorem ipsum."
  (interactive) (newline)
  (insert "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
          "eiusmod tempor incididunt ut labore et dolore magna aliqua. "
          "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris "
          "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
          "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
          "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
          "culpa qui officia deserunt mollit anim id est laborum.")
  (fill-paragraph))
(defun answer ()
  "Look up the word under cursor in a browser."
  (interactive)
  (browse-url (concat "http://www.answers.com/main/ntquery?s="
                      (thing-at-point 'word))))

;;;; Tramp mode

(setq tramp-default-method "ssh")


;;; -------- LISP/COMPATIBILITY
;;; ----------------------------------------------------------------------------

(require 'package)                      ; use list-packages to manage emacs pac
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))
(when (< emacs-major-version 24)
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))
(package-initialize)

(require 'cl-lib)
(when --winnt-p
  (setq package-user-dir (concat exec-directory "/../site-lisp")))
(add-to-list 'load-path (expand-file-name "~/.emacs.d/lisp"))
(defun recompile-local-lisp ()
  (interactive)
  (byte-recompile-directory "~/.emacs.d/lisp/" 0 t))
(when t
  (add-hook 'after-save-hook
            '(lambda ()
               "Auto-compile .emacs, .emacs.el -> .emacs.elc."
               (let* ((n (buffer-file-name)))
                 (if (or (string= n (expand-file-name ".emacs"))
                         (string= n (expand-file-name ".emacs.el")))
                     (byte-compile-file n))
                 ))))

;;;; Lists and trees:

(when (not (fboundp 'delete-dups))
  (defun delete-dups (list)
    "Destructively remove `equal' duplicates from LIST.
Store the result in LIST and return it. LIST must be a proper list. Of several
`equal' occurrences of an element in LIST, the first one is kept."
    (let ((tail list))
      (while tail
        (setcdr tail (delete (car tail) (cdr tail)))
        (setq tail (cdr tail)))) list))

(defun flatten (list)
  "Flatten LIST, returning a list with the atoms in LIST at any level.
LIST is a flat or a list of list. Also works for a consp whose cdr is non-nil.
Note that this function does not remove `nil' elements.

See also `prune' and `purge'."
  ;; Non-recursive, traditional Lisp
  (cond ((null list) nil)
        ((atom list) list)
        (t (let ((old list) (new ()) item)
             (while old
               (if (atom old)           ; from consp with non-nil cdr
                   (setq item old old nil)
                 (setq item (car old) old (cdr old)))
               (while (consp item)      ; make item atomic
                 (if (cdr item)
                     (setq old (cons (cdr item) old)))
                 (setq item (car item)))
               (setq new (cons item new)))
             (reverse new)))))

(defun prune (tree &optional test)
  "Recursively remove all items from sequence TREE that satisfy TEST.
When TEST is nil (default) remove all nils from TREE."
  ;; Copied from Paul Graham's book "On Lisp", and modified to remove nils.
  ;; http://www.paulgraham.com/onlisp.html
  ;; http://stackoverflow.com/questions/3967320/lisp-function-to-remove-nils
  (if test
      (cl-labels ((rec (tree acc)       ; recurse on TEST
                       (cond ((null tree)
                              (nreverse acc))
                             ((consp (car tree))
                              (rec (cdr tree)
                                   (cons (rec (car tree) nil) acc)))
                             (t (rec (cdr tree)
                                     (if (funcall test (car tree))
                                         acc
                                       (cons (car tree) acc))))
                             )))
        (rec tree nil))
    (if (listp tree)                    ; recurse on nils
        (mapcar #'prune (remove nil tree)) tree)))

(defun purge (tree &optional test)
  "`flatten' and `prune' sequence TREE and finally remove duplicates."
  (delete-dups (prune (flatten tree) test)))

;;;; String functions:

(defun is-empty-str (str)
  "Return t if STR is `nil' or \"\"."
  (or (not str) (string-equal str "")))
(defun join-str (sep &rest sequences)
  "Like Perl's `join'."
  (mapconcat #'(lambda(x)x) (flatten sequences) sep))
(defun join-re (&rest res)
  "Parenthesize (group) Emacs regular expressions."
  (concat "\\(" (join-str "\\|" res) "\\)"))
(defun join-shy-re (&rest res)
  "Like `join-re', but build a shy group."
  (concat "\\(?:" (join-str "\\|" res) "\\)"))
(defun qq (&rest sequences)
  "Wrap string(s) into double-quotes."
  (concat "\"" (join-str "" sequences) "\""))

(defun replace-in-string (what with in)
  ;; `replace-regexp-in-string' is a builtin function, but there's no
  ;; `replace-in-string' (or similar) function in Emacs.
  ;; http://stackoverflow.com/questions/17325713/looking-for-a-replace-in-string-function-in-elisp
  (replace-regexp-in-string (regexp-quote what) with in nil 'literal))

(defun replace-regexp-literally-in-string (str regexp repl &optional first)
  "Replace matches of REGEXP in STR with REPL (literally - \\& and \\1 to \\9 won't work).

If REPL is a function call this function, passing it the match string as an
argument; the replace text is then the function result. If FIRST is true replace
just the first match Returns the replaced string.

Example: Substitute environment variables.

    (replace-regexp-literally-in-string \"$HOME/bin:$PRJDIR/phenotypes\" \"\\$[A-Za-z_]+\"
        '(lambda(s)(getenv (substring s 1))))"
  (let ((safe (match-data)))
    (unwind-protect
        ;; Hints:
        ;;      (string-match "f" "foo") => begin 0, end 1
        ;;      (string-match "foo" "foo") => begin 0, end 3
        ;;      (substring "foo" 0 1) => "f"
        (let ((result "") (start 0) stop mbeg mend)
          (while (and (not stop) (string-match regexp str start))
            (setq mbeg (match-beginning 0) ; 0based index of 1st matched char
                  mend (match-end 0))      ; 0based index of 1st char *beyond* the match
            (setq result (concat result (substring str start mbeg)
                                 (if (functionp repl)
                                     (funcall repl (substring str mbeg mend)) repl)))
            (setq start mend stop first))
          (if (>= start 0) ; if matched at least once result result plus rest,
                           ; otherwise str
              (setq str (concat result (substring str start))))
          str)
      ;; unwindform
      (store-match-data safe)))
  )

(defun translate-strings (str alist)
  "Replace all literal substrings from a list in a string.
Example: x's are translated to y's
    (translate-strings-intrusively str '((\"x\" . \"y\") (\"y\" . \"z\")))"
  ;; http://emacs.stackexchange.com/questions/13708/replace-all-literal-substrings-from-a-list-in-a-string/13725#13725
  (replace-regexp-in-string
   (regexp-opt (mapcar 'car alist))
   (lambda (match) (cdr (assoc match alist))) str))

(defun translate-strings-intrusively (str slist)
  "Like `translate-strings', but entries in the list can affect subsequent entries.
Example: x's are translated to z's
    (translate-strings-intrusively str '((\"x\" . \"y\") (\"y\" . \"z\")))"
  (dolist (cons slist str)
    (setq str (replace-in-string (car cons) (cdr cons) str))))

;;;; Read functions:

(defvar --read-string-history nil)
(defun --read-string (prompt defval &optional initval)
  "Read a string from the minibuffer, prompting with string `prompt'.
INITVAL is a string to insert before reading (after the prompt). PROMPT is
appended with DEFVAL, so the person being prompted which string is charged when
entering the empty string."
  (read-string (format "%s (`%s')? " prompt defval)
               (or initval "") '--read-string-history defval))
(defun --read-pathname (prompt defval &optional initval)
  "Like `--read-string', but use `file-name-history'."
  (read-string (format "%s (`%s')? " prompt defval)
                   (or initval "") 'file-name-history defval))

(defun --wap-region (&optional strict real-word)
  "Return the symbol or word that point is on (or a nearby one) as a cons with
buffer offsets delimiting the beginning/ending point of some word.

The result is nil when there is no word nearby. If STRICT is non-nil return nil
unless point is within or adjacent to a symbol or word. The function finds a
symbol unless REAL-WORD is non-nil, in which case ist finds a word."
  ;; Copied from Emacs 22 simple.el `current-word', then modified to return a
  ;; cons.
  (save-excursion
    (let* ((oldpoint (point)) (start (point)) (end (point))
           (syntaxes (if real-word "w" "w_"))
           (not-syntaxes (concat "^" syntaxes)))
      (skip-syntax-backward syntaxes) (setq start (point))
      (goto-char oldpoint)
      (skip-syntax-forward syntaxes) (setq end (point))
      (when (and (eq start oldpoint) (eq end oldpoint)
                 (not strict)) ; point is neither within nor adjacent to a word
                               ; -> look for preceding word in same line
        (skip-syntax-backward not-syntaxes (save-excursion (beginning-of-line) (point)))
        (if (bolp) ; no preceding word in same line -> look for following word
                   ; in line
            (progn (skip-syntax-forward not-syntaxes (save-excursion (end-of-line) (point)))
                   (setq start (point))
                   (skip-syntax-forward syntaxes)
                   (setq end (point)))
          (setq end (point))
          (skip-syntax-backward syntaxes)
          (setq start (point))))
      (unless (= start end)         ; return as string
        ;;(buffer-substring-no-properties start end)
        (cons start end)))))

(defun --wap (&optional strict real-word)
  "Return symbol or word that point is on (or a nearby one) as a string.
The result has no text properties. See `--wap-region' for parameters STRICT and
REAL-WORD."
  (let ((reg (--wap-region)))
        (condition-case nil
            (buffer-substring-no-properties (car reg) (cdr reg))
          (error))))

;;;; File and directory test functions:

(defun --file-name (&optional f)
  "When F is a buffer get its file-name.
Use `--file-name' to always get a filename. F defaults to `current-buffer'."
  (unless f (setq f (current-buffer)))
  (if (bufferp f)
      (buffer-file-name f)
    f))
(defun --directory-name (&optional f)  (setq f (--file-name f)) (when f (file-name-directory f)))
(defun safe-file-readable-p (&optional f) (setq f (--file-name f)) (when f (file-readable-p f)))
(defun safe-file-exists-p (&optional f)   (setq f (--file-name f)) (when f (file-exists-p f)))
(defun safe-file-size (f)  (nth 7 (file-attributes f)))
(defun safe-file-empty (f) (=   0 (safe-file-size f)))
(defun directory-exists-p (f) (setq f (--directory-name f)) (when f (file-accessible-directory-p f)))

;;;; Expand variables in strings:

(defun --expand-variables (strings)
  "Replace environment variables of the form \"$VARIABLE\" all STRINGS (list or
scalar)."
  ;; In `ff-list-replace-env-vars'; the call to `string-match' can fail on nil.
  (setq wantarray (listp strings))
  (unless wantarray
    (setq strings (list strings)))
  (condition-case nil
      (progn (setq list (ff-list-replace-env-vars strings))
             (if wantarray list (car list)))
    (error)))

;;;; Expand pathnames:

(defun --expand-pathnames (path &optional dirname no-wildcards)
  "PATH is a pathname string or list of pathname strings, DIRNAME is the
directory to start from if a pathname is relative. Relative pathnames do not
start with slash or tilde. Default DIRNAME is `default-directory'.

Steps performed:

    1.) Substitute environment variables of the form \"$FOO\" or \"($FOO)\" in
        PATH and DIRNAME.
    2.) Make an absolute, canonicalized filename from PATH and DIRNAME (see
       `expand-file-name').
    3.) Unless NO-WILDCARDS is non-nil expand shell patterns (globs) in PATH
        into a list of existing filenames.
    4.) Return a list of pathnames.

For example, to get a list of existing directories use:

    (setq existing-dirs
              \(cl-mapcan '(lambda (f) (when (and f (file-directory-p f)) (list f)))
              \(flatten (mapcar '--expand-pathnames path-list))))"
  (if (null path) (setq path ""))
  (if (stringp path)
      (let ((canon (expand-file-name    ; convert to absolute, canonicalize
                    (--expand-variables path)
                    (--expand-variables (or dirname default-directory)))))
        (mapcar
         (lambda(x) (replace-regexp-literally-in-string (replace-regexp-literally-in-string x "\\\\" "/") "//" "/"))
         (if no-wildcards canon (file-expand-wildcards canon))))
    ;; Argument is a list of strings, recurse for each string and return a flat
    ;; list.
    (flatten (mapcar '--expand-pathnames path))))

(defun --expand-pathname (path &optional dirname no-wildcards)
  "Like `--expand-pathnames' but return the first pathname of the resulting
list."
  (car (--expand-pathnames path dirname no-wildcards)))

(defun --expand-directories (path &optional dirname no-wildcards)
  "Like `--expand-pathnames' but expand only existing directories.
Filter out files, non-existing directories and directory names starting with a
dot."
  (flatten (cl-mapcan '(lambda (f)
                         (when (and f (not (string-match "/\\." f)) (file-directory-p f))
                           (list f)))
                      (delete-dups (--expand-pathnames path dirname no-wildcards)))))

;;;; Find existing pathnames:

(defun --ff-existing-pathnames (&optional pattern dirnames stop-at-first nonexisting)
  "Find existing path(s) that match PATTERN in DIRNAMES (string or list,
default: `ff-search-directories'). When STOP-AT-FIRST is non-nil stop after the
first file matching PATTERN. When NONEXISTING is non-nil also canonicalize
PATTERN in all DIRNAMES. For example,

    (setq unavailable-tags-files
    (sort (--ff-existing-pathnames \"TAGS\" cc-search-directories nil t) 'string-lessp))

In PATTERN and DIRNAMES environment variables of the form \"$FOO\" or \"($FOO)\"
get substituted. All paths in DIRNAMES can contain shell patterns too.

When a part of the directory name is \"/*\" its occurence is expanded by all
existing directory-names at that level. Without a \"/*\" find files
non-recursively. For example, \"$HOME/prj/*/mk/gnu\" expands to all
sub-directories in \"~/prj\" that have a \"../mk/gnu\" branch.

Returns a flat, unique list of pathnames."
  ;; This function is based on `ff-get-file-name'. Changes: added environment
  ;; variables, shell patterns and the `stop-at-first' and `nonexisting' flags.
  ;; Return all files, maybe non-existing files, not just the first found file.
  (require 'find-file)
  (or dirnames (setq dirnames ff-search-directories))
  (if (stringp dirnames)
      (--ff-existing-pathnames pattern (list dirnames) stop-at-first nonexisting)
    ;; Search in `dirnames' - which may be something stupid like (nil).
    (let ((dirs (flatten (if (symbolp dirnames)
                             (--expand-variables (symbol-value dirnames))
                           (--expand-variables dirnames))))
          (dir) (rest) (found (list)))
      (setq dir (car dirs))
      (unless ff-quiet-mode
        (message "Find all %s <%s> in <%s>" (if nonexisting "non-existing" "existing") pattern dir))
      (while (and dirs (or (not stop-at-first) (not found)))
        ;; Unless dir contains a "/*" look for pattern in the directory only;
        ;; search recursively in sub-directories otherwise.
        (if (and dir (not (string-match "\\([^*]*\\)/\\\*\\(/.*\\)*" dir)))
            ;; Not contains a "/*".
            (dolist (file (--expand-pathnames pattern dir))
              (when (or nonexisting (file-exists-p file))
                (unless ff-quiet-mode
                  (message "    found <%s>" file))
                (setq found (append found (list file))))
              )
          ;; Else recurse all "/*" sub-dirs.
          (when dir
            (if (match-beginning 2)
                (setq rest (substring dir (match-beginning 2) (match-end 2)))
              (setq rest ""))
            (setq dir (substring dir (match-beginning 1) (match-end 1)))
            (let ((dirlist (ff-all-dirs-under dir '(".svn" "." ".."))) subdir compl-dirs)
              (setq subdir (car dirlist))
              (while dirlist
                (setq compl-dirs (append compl-dirs (list (concat subdir rest))))
                (setq dirlist (cdr dirlist))
                (setq subdir (car dirlist)))
              (when compl-dirs
                (setq found
                      (append found
                              (--ff-existing-pathnames pattern compl-dirs stop-at-first nonexisting))))
              )))
        (setq dirs (cdr dirs))
        (setq dir (car dirs)))
      ;; Return.
      (flatten (mapcar (lambda (a) (expand-file-name a)) (delete-dups found)))
      )))

(defun --ff-existing-pathname (pattern &optional dirnames)
  "Like `--ff-existing-pathnames' but stop after first file.
Example: Find in two known paths
    (--ff-existing-pathname name (list \"h:/\" \"$USERPROFILE\"))"
  (car (--ff-existing-pathnames pattern dirnames t)))

(defun --ff-program (filename &optional dirnames)
  "Like `--ff-existing-pathname', but prepend the paths in the PATH environment
variable to DIRNAMES."
  (setq dirnames (append dirnames (split-string (getenv "PATH") (if --winnt-p ";" ":"))))
  (if --winnt-p
      (setq dirnames (append dirnames '("$USERPROFILE/bin" "$PROGRAMFILES/*" "c:/prog/*")))
    (setq dirnames (append dirnames '("$HOME/bin"))))
  (let ((ff-quiet-mode nil))
    (--ff-existing-pathname filename dirnames)))

;;;; PC Selection Mode (CUA)
;;
;; Enable `pc-selection-mode' to change the mark behavior to emulate Motif, Mac
;; or Windows mark-region and cut and paste style.
;;
;; Limitations: In `transient-mark-mode' C-SPC activates the region and lets you
;;     select text as you see fit. If you want to set the mark (and nothing
;;     else) you have to follow up with another C-SPC (or C-g) to abort the
;;     region selection.
;;
;; CUA is a "consistent and usable" user-interface standard published by IBM in
;; 1987. The standard had strong impact on Microsoft Windows, OSF/Motif, MacOS
;; and Gnome/KDE, but not "character mode" on UNIX terminal. Most relevant for
;; Emacs are SHIFT-DEL (cut), CTRL-INSERT (copy) and SHIFT-INSERT (paste). These
;; key bindings are established here.

(setq transient-mark-mode t
      mark-even-if-inactive t
      set-mark-command-repeat-pop t)
(transient-mark-mode 1)
(delete-selection-mode 1)
(unless --emacs24p                      ; obsolete since 24.1
  (if (fboundp 'pc-selection-mode)
      (pc-selection-mode)
    (require 'pc-select)))

(defun --tune-CUA-mode ()
  "Fine-tune CUA editing for all major modes."
  (require 'outline)
  (setq is-prog-mode (derived-mode-p 'prog-mode))
  (set-mark (point)) ; prevents "The mark is not set now so there is no region"
                     ; with interactive "r" defuns
  (deactivate-mark)
  ;; (local-set-key [(tab)] '--smart-tab)
  (local-set-key [(backtab)] '--unindent)
  (local-set-key [(meta backspace)] 'undo)
  (local-set-key [(home)] '--beginning-of-line)
  (local-set-key [(end)] 'end-of-line)
  (local-set-key [(meta home)] '--beginning-of-buffer)
  (local-set-key [(meta end)] '--end-of-buffer)
  (when is-prog-mode
    (local-set-key [(control home)]
                   '(lambda(&optional arg)
                      (interactive "p") (beginning-of-defun arg) (show-subtree)))
    (local-set-key [(control end)]
                   '(lambda(&optional arg)
                      (interactive "p") (end-of-defun arg) (show-subtree))))
  (local-set-key [(control w)] '--close-buffer-save)
  (local-set-key [(control a)] 'mark-whole-buffer)
  (local-set-key [(control k)] 'kill-whole-line)
  (when is-prog-mode
    (local-set-key [(meta k)] 'kill-line)
    (local-set-key [(control e)] 'kill-sexp)
    (local-set-key [(control left)] 'backward-sexp)
    (local-set-key [(control right)] 'forward-sexp)
    (local-set-key [(control shift left)] '(lambda() (interactive) (show-all) (backward-sexp) (mark-sexp 1)))
    (local-set-key [(control shift right)] 'mark-sexp))
  (local-set-key [(control up)] 'backward-paragraph)
  (local-set-key [(control down)] 'forward-paragraph)
  ;; Comments (CTRL-C K), backslashing (CTRL-C C)
  (local-set-key [(control c)(k)] '(lambda(&optional beg end)
                                     "Uncomment region or kill comment on current line."
                                     (interactive "r") (if (or mark-active)
                                                           (uncomment-region beg end)
                                                         (kill-comment 1) (indent-according-to-mode))))
  (local-set-key [(control c)(c)] '(lambda (&optional beg end)
                                     "Comment out region or `indent-for-comment'."
                                     (interactive "r") (if (or mark-active)
                                                           (comment-region beg end)
                                                         (indent-for-comment))))
  ;; Hilite-mode, META-CURSOR scrolling.
  (when is-prog-mode
    (hl-line-mode))
  (when (not (eq major-mode 'org-mode))
    (local-set-key [(meta up)] '(lambda (&optional arg) (interactive "P")
                                  (scroll-down (case arg ((nil) 1) (t arg)))))
    (local-set-key [(meta down)] '(lambda (&optional arg) (interactive "P")
                                    (scroll-up (case arg ((nil) 1) (t arg)))))
    (local-set-key [(meta left)] '(lambda (&optional num) (interactive "p")
                                    (if (< (scroll-right (or num tab-width)) 0)
                                        (--beginning-of-line))))
    (local-set-key [(meta right)] '(lambda (&optional num) (interactive "p")
                                     (if (<= (current-column) (scroll-left (or num tab-width)))
                                         (end-of-line)))))
  ;; Hideshow minor mode. `hs-minor-mode' implements block hiding and showing.
  (when nil
    (when is-prog-mode
      (hs-minor-mode)
      (define-key hs-minor-mode-map [?\C-c ?\C-\M-h] 'hs-hide-all)
      (define-key hs-minor-mode-map [?\C-c ?\C-\M-s] 'hs-show-all)))
  ;; Flyspell, check comments. Always a buffer-local mode.
  (when nil
    (when is-prog-mode
      (run-with-idle-timer
       30 nil '(lambda ()
                 (ispell-change-dictionary "en_US")
                 (setq flyspell-prog-text-faces
                       '(font-lock-comment-face font-lock-doc-face))
                 (flyspell-prog-mode)))
      ))
  )

(defadvice yank (after indent-region activate)
  "Auto-indent pasted code."
  ;; http://www.mygooglest.com/fni/.emacs
  (if (member major-mode '(emacs-lisp-mode
                           scheme-mode lisp-mode c-mode c++-mode
                           objc-mode latex-mode plain-tex-mode python-mode))
      (indent-region (region-beginning) (region-end) nil)))

(defadvice yank-pop (after indent-region activate)
  (if (member major-mode '(emacs-lisp-mode
                           scheme-mode lisp-mode c-mode c++-mode
                           objc-mode latex-mode plain-tex-mode python-mode))
      (indent-region (region-beginning) (region-end) nil)))

;;;; Allow changing case:

(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)

;;;; Narrowing:

(put 'narrow-to-region 'disabled nil)

;;;; Line endings, trailing spaces, line wrapping and truncation:

(setq-default indicate-empty-lines t)
(setq sentence-end-double-space nil  ; two spaces are wrong in german (DIN 5008)
      truncate-lines nil
      truncate-partial-width-windows t
      track-eol t
      require-final-newline t
      next-line-add-newlines nil)

(add-hook 'prog-mode-hook
          '(lambda()
             (setq show-trailing-whitespace t)))

(defun trunc()
  "Toggle between truncated and wrapped lines."
  ;; From http://www.emacswiki.org/emacs/McMahanEmacsMacros
  (interactive)
  (toggle-truncate-lines nil)
  (message (if truncate-lines "Truncating lines (... $)" "Wrapping lines (...\\)"))
  (redraw-display))

;;;; Indentations, tabs and spaces
;;
;; `tab-width' is buffer-local, but because `tab-stop-list' is not, indentations
;; may mix spaces and tabs when a global `tab-stop-list' interacts with a local
;; `tab-width', and some mode-hook (accidentally) sets `tab-stop-list'.

(defun --tab-stop-list (&optional first)
  "Generate a default list based upon `tab-width'.
Start at number FIRST if non-nil and less then `tab-width'."
  (if (and (numberp first)
           (< first tab-width))
      (let ((seq (--tab-stop-list)))
        (push first seq))
    (number-sequence tab-width (* tab-width (/ 200 tab-width)) tab-width)))

(set-default 'tab-width 4)
(set-default 'indent-tabs-mode nil)
(setq tab-stop-list (--tab-stop-list))
(make-variable-buffer-local 'tab-stop-list)
(when nil                        ; let TAB to insert a literal TAB in every mode
  (global-set-key (kbd "TAB") 'self-insert-command))

;;;; Make *scratch* indestructible

;; http://stackoverflow.com/questions/234963/re-open-scratch-buffer-in-emacs

(defun --scratch-buffer(&optional reset)
  "Get the *scratch* buffer object.
Make new scratch buffer unless it exists. If RESET is non-nil arrange it that it
can't be killed."
  (let ((R (get-buffer "*scratch*")))
    (unless R
      (message "Creating new *scratch* buffer")
      (setq R (get-buffer-create "*scratch*") reset t))
    (when reset
      (with-current-buffer R
        (lisp-interaction-mode)
        (make-local-variable 'kill-buffer-query-functions)
        (add-hook 'kill-buffer-query-functions '(lambda()(bury-buffer) nil)))
      )
    R))
(--scratch-buffer t)
(run-with-idle-timer 3 t '--scratch-buffer)

(defun scratch()
  "Switch to *scratch*. With prefix-arg delete its contents."
  (interactive)
  (switch-to-buffer (--scratch-buffer))
  (if current-prefix-arg
      (delete-region (point-min) (point-max))
    (goto-char (point-max))))

;;;; Local buffer variables, and which are considered safe:

(setq enable-local-variables t
      enable-local-eval 'maybe
      safe-local-variable-values
      (quote ((minor-mode . auto-revert)
              (buffer-file-coding-system . utf-8-unix)
              (buffer-file-coding-system . utf-8-auto)
              (buffer-file-coding-system . utf-8)
              )))

;;;; Setup european display (ISO 8859, Latin-1, Windows-Latin-1)

;; Use UTF-8 by default when no information in the file explicitly says it is.
;; When a file does not use UTF-8, and Emacs does not recognize its coding
;; properly, use `universal-coding-system-argument', bound to C-x RET c, or
;; `set-buffer-file-coding-system' bound to C-x RET f.

(prefer-coding-system 'utf-8)        ; `iso-latin-1-dos' by default for NT/Emacs
(if --emacs23p
    (if (boundp 'buffer-file-coding-system)
        (setq-default buffer-file-coding-system 'utf-8)))
(when (or --cygwin-p --unix-p) ; treat clipboard as UTF-8
  (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)))

;;;; Deletion, Backup and Auto-save

;; http://stackoverflow.com/questions/151945/how-do-i-control-how-emacs-makes-backup-files/18330742#18330742.

(defvar --backup-directory (concat user-emacs-directory "backups"))
(if (not (file-exists-p --backup-directory))
    (make-directory --backup-directory t))
(setq backup-directory-alist `(("." . ,--backup-directory)))
(setq make-backup-files t         ; backup of a file the first time it is saved.
      backup-by-copying t         ; don't clobber symlinks
      version-control t           ; version numbers for backup files
      delete-old-versions t       ; delete excess backup files silently
      delete-by-moving-to-trash t
      kept-old-versions 9
      kept-new-versions 9
      auto-save-default t)

;;;; Anti-RSI (Repeated Strain Injury) mode
;;
;; Use `type-break' to take a break now. The command `type-break-statistics'
;; prints interesting things.
;;
;; - Keep your elbows slightly open, at around 121° (reduced the risk by 84%)
;; - Leave more than 12 cm between the edge of the table and the "J" key (62%)
;; - Don't use your neck to hold the phone (60%)
;; - Avoid keyboard wrist rests (48%)
;; - Don't bend your wrists when holding the mouse. Keep it within 5° (45%)
;; - Strike the keys with a light touch, with less than 48g of pressure (40%)
;; - Raise the screen so that your neck tilt by less than 3° (36%)
;; - Rest your elbows or forearms on the chair armrests, or on the desk itself (35%)
;; - Use a keyboard that is less than 3.5 cm thick (35%)
;; - Keep the keyboard slightly lower than your elbows (23%)
;; - Avoid resting your hands on the leading edge of your desk, or pad the edge (22%)
;;
;; More tipps:
;;
;; - The keyboard should be pretty close to your lap. Like, within two inches or
;;   so. Don't use the feet on the back of the keyboard.
;;
;; - On a side view of your body, joints should be at right angles, roughly.
;;   Feet on the floor, back straight.
;;
;; - Take breaks at least every hour, preferably more.
;;   - Hold your hands at arms length away from your body.
;;   - Spread out your fingers on a horizontal plane. You'll feel stretching. Keep them there for several seconds.
;;   - Stretching.
;;
;; - Stress plays a factor in RSI. Sometimes a HUGE factor.
;;
;; - Don't type with your wrists on the keyboard wrist pad. When typing, your
;;   fingers should be curved and below your wrists, like they would be if you
;;   played the piano. Never force wrists while typing.
;;
;; - Make CAPSLOCK work as an additional CTRL-key
;;   http://www.emacswiki.org/emacs/MovingTheCtrlKey. CTRL gets a more central
;;   position on the keyboard. Which, in Emacs, is quite useful considering ones
;;   frequent use of CTRL commands. However, this cannot be done in Emacs.

(unless --no-desktop
  (setq type-break-mode-line-message-mode t
        type-break-demo-functions '(type-break-demo-boring)
        type-break-time-warning-intervals '()
        type-break-file-name nil)
  (type-break-mode))

;;; -------- LINUM, MINIMAP, FULLSCREEN, DARKROOM (F11)
;;; ----------------------------------------------------------------------------

;;;; Minimap

(setq linum-format "%6d \u2502 ")
(load "minimap" t)

;;;; Fullscreen minor mode (F11)

;; http://emacswiki.org/emacs/FullScreen

(defvar --fullscreen-mode 0)
(defun --fullscreen ()
  (interactive)
  (cond
   ((= --fullscreen-mode 0)             ; restored/maximized => fullscreen
    (if --winnt-p                       ; enable
        (w32-send-sys-command 61488)
      (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 '(1 "_NET_WM_STATE_FULLSCREEN" 0)))
    (message "fullscreen")
    (incf --fullscreen-mode))
   ((= --fullscreen-mode 1)                  ; fullscreen => follow mode for current buffer
    ;; Essentially the `all-over-the-screen' defun from
    ;; http://stackoverflow.com/questions/970292/emacs-multiple-columns-one-buffer
    (delete-other-windows)
    (linum-mode 0)
    (if (fboundp 'minimap-mode) (minimap-mode 0))
    (split-window-horizontally)
    (split-window-horizontally)
    (balance-windows)
    (follow-mode t)
    (message "all-over-the-screen")
    (incf --fullscreen-mode))
   ((= --fullscreen-mode 2)                  ; all over the screen => maximized
    (follow-mode nil)
    (delete-other-windows)
    (if --winnt-p
        (w32-send-sys-command 61728)
      (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 '(2 "_NET_WM_STATE_FULLSCREEN" 0)))
    (message "maximized")
    (setq --fullscreen-mode 0))
   ))
(global-set-key [f11] '--fullscreen)

;;;; Darkroom-mode (M-F11)

;; http://www.martyn.se/code/emacs/darkroom-mode/

(global-set-key [(meta f11)]
                '(lambda()
                   "Toggle distraction free editing mode \\[darkroom-mode]."
                   (interactive)
                   (require 'darkroom)
                   (linum-mode 0)
                   (if (fboundp 'minimap-mode) (minimap-mode 0))
                   (let ((darkroom-mode-left-margin 18)
                         (darkroom-mode-right-margin 18))
                     (set-window-margins nil 0 0)
                     (darkroom-mode))
                   ))

(global-set-key [(shift f11)]
                '(lambda()
                   "Toggle \\[linum-mode], \\[minimap-mode] and (if available)
distraction free editing mode \\[darkroom-mode]."
                   (interactive)
                   (linum-mode 0)
                   ;;(if (fboundp 'minimap-mode) (minimap-mode 0))
                   (if (<= left-margin-width 1)
                       (setq-default left-margin-width 10
                                     right-margin-width 8)
                     (if (= left-margin-width 10)
                         (setq-default left-margin-width 20
                                       right-margin-width 8)
                       (setq-default left-margin-width  1
                                     right-margin-width 0)))
                   (set-window-buffer nil (current-buffer)) ; active margins
                   ))

;;; -------- GLOBAL FONT LOCKING AND FACES
;;; ----------------------------------------------------------------------------

;; Define two static color schemes here for "light" (alias `nil') and "dark"
;; background. This background mode is set by defining the Emacs variable
;; `frame-background-mode'. The below colors will look good on most displays.
;; Try `list-colors-display', `list-faces-display'.
;;
;; Create some faces that `cc-mode' (cc-fonts.el) classifies
;; "future-extensions", and have to be defined defined in advance here.

(add-hook 'after-init-hook
          '(lambda()
             (global-font-lock-mode)
             (font-lock-add-keywords
              nil '(("\\<\\(\\(TODO\\|BUG\\|DISCLAIMER\\|WARNING\\|NOTE\\|ERROR\\):\\)"
                     1 font-lock-warning-face)))))

(add-hook 'font-lock-mode-hook
          '(lambda()
             (custom-set-faces
              ;; Keywords, function-names, type-names
              '(fixed-pitch
                ((((class color) (background dark )) (:bold t :foreground "black")
                  ((class color) (background light)) (:bold t :foreground "dimgrey"))))
              '(font-lock-builtin-face
                ((((class color) (background dark )) (:foreground "gray70"))
                 (((class color) (background light)) (:bold t :foreground "blue4"))))
              '(font-lock-keyword-face
                ((((class color) (background dark )) (:bold t :foreground "LightGoldenrod"))
                 (((class color) (background light)) (:bold t :foreground "blue3"))))
              ;; Labels, case, public, private, proteced, namespace-tags
              '(font-lock-label-face
                ((((class color) (background dark )) (:italic t :foreground "LightGoldenrod"))
                 (((class color) (background light)) (:italic t :foreground "blue3"))))
              '(font-lock-preprocessor-face
                ((((class color) (background dark )) (:bold t :foreground "NavajoWhite4"))
                 (((class color) (background light)) (:bold t :foreground "blue3"))))
              '(font-lock-function-name-face
                ((((class color) (background dark )) (:italic t :foreground "FloralWhite"))
                 (((class color) (background light)) (:foreground "mediumblue"))))
              '(font-lock-type-face
                ((((class color) (background dark )) (:foreground "LightGoldenrod"))
                 (((class color) (background light)) (:foreground "mediumblue"))))
              ;; Variables, constants, strings-literals.
              '(font-lock-variable-name-face
                ((((class color) (background dark )) (:foreground "LightGoldenrod"))
                 (((class color) (background light)) (:foreground "darkslateblue"))))
              '(font-lock-constant-face
                ((((class color) (background dark )) (:foreground "Orange1"))
                 (((class color) (background light)) (:foreground "DarkRed"))))
              '(font-lock-string-face
                ((((class color) (background dark )) (:foreground "Coral"))
                 (((class color) (background light)) (:foreground "PaleVioletRed"))))
              '(sh-heredoc-face
                ((((class color) (background dark )) (:bold t :foreground "Chocolate"))
                 (((class color) (background light)) (:bold t :foreground "Firebrick"))))
              '(sh-quoted-exec
                ((((class color) (background dark )) (:bold t :foreground "Chocolate"))
                 (((class color) (background light)) (:bold t :foreground "DarkOrange"))))
              ;; Comments and embedded documentation.
              '(font-lock-comment-face
                ((((class color) (background dark )) (:foreground "OliveDrab2"))
                 (((class color) (background light)) (:foreground "Forestgreen"))))
              '(font-lock-warning-face
                ((((class color) (background dark )) (:bold t :italic t :underline t :foreground "OliveDrab1"))
                 (((class color) (background light)) (:bold t :italic t :underline t :foreground "Darkred"))))
              '(font-lock-doc-face
                ((((class color) (background dark )) (:foreground "Chartreuse3" :width condensed))
                 (((class color) (background light)) (:underline t :foreground "Chartreuse2" :width condensed))))
              '(which-func              ; which-function-mode
                ((((class color) (background dark )) (:foreground "Chartreuse3" :width condensed))
                 (((class color) (background light)) (:underline t :foreground "Chartreuse2" :width condensed))))
              ;; `cperl-mode'
              '(cperl-array-face
                ((((class color) (background dark )) (:italic t :foreground "NavajoWhite"))
                 (((class color) (background light)) (:italic t :foreground "darkslateblue"))))
              '(cperl-hash-face
                ((((class color) (background dark )) (:italic t :foreground "LightGoldenrod"))
                 (((class color) (background light)) (:italic t :foreground "darkslateblue"))))
              ;; `outline-mode'
              '(outline-1               ; chapter
                ((((class color) (background light))
                  (:height 1.2 :underline t :foreground "dark goldenrod"))
                 (((class color) (background dark))
                  (:height 1.2 :underline t :foreground "dark goldenrod"))))
              '(outline-2               ; section
                ((((class color) (background light)) (:height 1.1 :foreground "goldenrod"))
                 (((class color) (background dark )) (:height 1.1 :foreground "goldenrod"))))
              '(outline-3               ; subsection
                ((((class color) (background light)) (:height 1.0 :foreground "dark khaki"))
                 (((class color) (background dark )) (:height 1.0 :foreground "dark khaki"))))
              '(outline-4               ; subsubsection
                ((((class color) (background light)) (:height 1.0 :foreground "khaki"))
                 (((class color) (background dark )) (:height 1.0 :foreground "khaki"))))
              '(outline-5               ; paragraph
                ((((class color) (background light)) (:height 1.0 :foreground "cornsilk"))
                 (((class color) (background dark )) (:height 1.0 :foreground "cornsilk"))
                 ))
              '(outline-6               ; subparagraph
                ((((class color) (background light)) (:height 1.0 :italic t :foreground "deepskyblue"))
                 (((class color) (background dark )) (:height 1.0 :italic t :foreground "deepskyblue4"))))
              )
             ;; Duplicate faces
             (--copy-face 'font-lock-doc-face 'font-lock-doc-markup-face) ; Javadoc tags
             (--copy-face 'font-lock-comment-face  'font-lock-doc-string-face)
             (--copy-face 'font-lock-warning-face  'cperl-invalid-face        )
             (--copy-face 'font-lock-constant-face 'cperl-nonoverridable-face)
             ;; Minibuffer
             (custom-set-faces
              '(minibuffer-prompt
                ((((class color) (background dark )) (:foreground "Red" :background "Black" :bold t))
                 (((class color) (background light)) (:foreground "midnightblue" :background "whitesmoke" :bold t :italic t)))))
             ;; Search, region, ido.
             (custom-set-faces
              '(lazy-highlight-face     ; highlight isearch "lazy" matches
                ((((class color) (background dark )) (:foreground "black" :background "yellow2"))
                 (((class color) (background light)) (:bold t :foreground "black" :background "lemonchiffon"))))
              '(isearch
                ((((class color) (background dark )) (:foreground "black" :background "yellow2" :bold t :italic nil))
                 (((class color) (background light)) (:foreground "black" :background "yellow" :bold t :italic nil))))
              '(isearch-fail
                ((((class color) (background dark )) (:foreground "black" :background "OrangeRed1" :bold t :italic nil))
                 (((class color) (background light)) (:foreground "black" :background "OrangeRed1" :bold t :italic nil))))
              '(region                  ; selected text (active region)
                ((((class color) (background dark )) (:background "SeaGreen" :bold t))
                 (((class color) (background light)) (:foreground "springgreen" :background "black"))))
              )
             ;; Mismatched parentheses, heading/trailing whitespace and `flyspell'.
             (custom-set-faces
              '(show-paren-match
                ((((class color) (background light)) (:background "honeydew" :bold t))
                 (((class color) (background dark )) (:foreground "White" :background "Black" :bold t))))
              '(show-paren-mismatch
                ((((class color) (background light)) (:foreground "OrangeRed" :italic t :bold t))
                 (((class color) (background dark )) (:foreground "OrangeRed" :background "Black" :italic t :bold t))))
              '(trailing-whitespace
                ((((class color) (background dark )) (:bold t :background "lightpink4"))
                 (((class color) (background light)) (:bold t :background "gray92"))))
              '(escape-glyph                       ; e.g. "..." at EOL in outline-mode
                ((((class color) (background dark )) (:bold t))
                 (((class color) (background light)) (:bold t :foreground "OrangeRed"))))
              '(makefile-space
                ((((class color) (background dark )) (:bold t :background "PaleGreen4"))))
              '(sh-escaped-newline
                ((((class color) (background dark )) (:bold t))
                 (((class color) (background light)) (:bold t :foreground "OrangeRed"))))
              '(flyspell-incorrect
                ((((class color) (background dark )) (:underline t))
                 (((class color) (background light)) (:underline t))))
              '(flyspell-duplicate
                ((((class color) (background dark )) (:underline t))
                 (((class color) (background light)) (:underline t))))
              )
             ;; Minimap
             (when (featurep 'minimap)
               (custom-set-faces
                '(minimap-active-region-background ((t (:background "black"))))
                '(minimap-font-face ((t (:height 50 :family "DejaVu Sans Mono"))))
                ))
             ;; Line-highlighting and -continuation, EOL, Linum
             (custom-set-faces
              '(linum
                ((((class color) (background dark )) (:foreground "gray50"))
                 (((class color) (background light)) (:foreground "blue")))))
             (when (featurep 'hl-line)
               (custom-set-faces
                (if --emacs22p
                    '(hl-line
                      ((((class color) (background dark )) (:background "black"))
                       (((class color) (background light)) (:background "gray92"))))
                  '(highlight                      ; Emacs 21 only
                    ((((class color) (background dark )) (:bold t :background "black"))
                     (((class color) (background light)) (:bold t :background "gray92"))))
                  )))
             (if (>= emacs-major-version 23)
                 ;; http://www.emacswiki.org/emacs/OutlineMode#toc3
                 (set-display-table-slot standard-display-table 'selective-display
                                         (let ((face-offset (* (face-id 'nobreak-space) (lsh 1 22))))
                                           (vconcat (mapcar (lambda (c) (+ face-offset c)) "..."))))
               ;; Else use a different string only.
               (set-display-table-slot standard-display-table 'selective-display (string-to-vector " [...]"))
               )
             )
          )

;;; -------- SEARCH/REPLACE AND ABBREVATIONS
;;; ----------------------------------------------------------------------------

(setq search-highlight t
      case-fold-search nil      ; case-sensitive search/replace
      replace-lax-whitespace t  ; query-replace matches a sequence of wspc chars
      query-replace-highlight t)

;;;; Abbrevations, Hippie-Expand

(defun --abbrev-backward-char ()
  (backward-char) t) ; return non-nil to inhibit insertion of char that
                     ; triggered the expansion
(put '--abbrev-backward-char 'no-self-insert t)
(abbrev-mode 1)
(if --emacs23p
    (setq abbrev-mode t))
(condition-case nil
    (quietly-read-abbrev-file)          ; default: ~/.abbrev_defs
  (error "%s not found" abbrev-file-name))

(define-key read-expression-map [(tab)] 'hippie-expand)     ; TAB in minibuffer
(global-set-key [(control tab)] '--indent-rigidly)          ; C-TAB
(global-set-key [(control x)(tab)] '--indent-rigidly)       ; C-x TAB
(global-set-key [(control shift tab)] '--unindent-rigidly)  ; C-BACKTAB
(global-set-key [(control x)(backtab)] '--unindent-rigidly) ; C-x BACKTAB
(setq dabbrev-case-replace nil)         ; reserve case when expanding

(defun --point-in-string ()
  (nth 3 (syntax-ppss)) ; (eq (get-text-property (point) 'face) 'font-lock-string-face)
  )

(defun --smart-tab ()
  "Implements a cycle of mark-deactivation, indentation, symbol-expansion and marking the sexp.
Smart features:
  - minibuffer compliant, acts as usual in the minibuffer
  - behaves well inside literal strings
Algorithm:
    if in literal string
        jump to first non-white character on the line, stop
    if mark is active
        indent region or deactive mark, stop
    indent line or insert tab
    if point not moved
        if at end of symbol
            expand symbol (`dabbrev-expand') or jump to begin, stop
        mark sexp at point to continue the cycle"
  ;; Replaces `hippie-expand' globally bound to TAB. `--smart-tab' is bound to
  ;; TAB in some mode hooks. It has been modified here: the general symbol
  ;; expansion was in the way most of the time. `unindent' unindents the line,
  ;; i.e. reverses TAB. For the orignal `smart-tab' function see
  ;; http://www.emacswiki.org/emacs/TabCompletion#SmartTab[] and
  ;; https://gist.github.com/188961[].
  (interactive)
  (if (minibufferp)
      (unless (minibuffer-complete)
        (dabbrev-expand nil))
    (let ((start (point)) (noinfo))
      (if (--point-in-string)
          (back-to-indentation)
        (if mark-active                 ; deactivate mark
            (progn (indent-region (region-beginning) (region-end))
                   (if (= start (point))
                       (deactivate-mark)))
          (indent-for-tab-command)      ; no mark active - indent line or insert TAB
          (when (= start (point))       ; point moved?
            (if (looking-at "\\_>")     ; expand symbol at point
                (condition-case nil (dabbrev-expand nil) (error (backward-sexp)))
              (forward-sexp)            ; mark sexp at point
              (backward-sexp) (mark-sexp 1))
            )))
      (unless noinfo
        (cond ((eq major-mode 'sh-mode)
               (sh-show-indent nil))))
      )))

(defun --indent-rigidly (&optional beg end)
  "Insert a physical TAB character at point to the next tab stop (\\[tab-to-tab-stop]).
Use `C-q TAB' to insert insert a literal TAB character.

With active region indent the region `tab-width' columns. When the prefix
argument is a one-base column number, indent each line in the region to that
column."
  (interactive "*r")
  (let ((deactivate-mark nil))
    (if mark-active
        (if current-prefix-arg
            (indent-region beg end current-prefix-arg)
          (indent-rigidly beg end tab-width))
      (tab-to-tab-stop))))

(defun --unindent-rigidly (&optional beg end)
  "Untabify line or region `tab-width' columns."
  (interactive "*r")
  (let ((deactivate-mark nil))
    (if mark-active
        (indent-rigidly beg end (- tab-width))
      (backward-delete-char-untabify tab-width))))

(defun shift-region (numcols)
  ;; The code for `shift-region' and `unindent' was found at Nachopp's Blog
  ;; http://ignaciopp.wordpress.com/2009/06/17/emacs-indentunindent-region-as-a-block-using-the-tab-key/
  (if (< (point) (mark))
      (if (not (bolp))
          (progn (beginning-of-line) (exchange-point-and-mark) (end-of-line)))
    (progn (end-of-line) (exchange-point-and-mark) (beginning-of-line)))
  (save-excursion
    (let ((start (region-beginning))
          (finish (region-end)))
      (if (< (point-max) (mark)) (exchange-point-and-mark))
      (let ((save-mark (mark)))
        (indent-rigidly start finish numcols)))
    ))

(defun --unindent()
  "Unindent line, or block if it's a region selected.
To be assigned to SHIFT+TAB (BACKTAB). Erase words backward (one at a time) up
to the beginning of the line, stop at indentation and do not (unconveniently)
kill white spaces and the last word of the previous line."
  (interactive)
  (if mark-active
      (progn                            ; unindent-block
        (shift-region (- tab-width))
        (setq deactivate-mark nil))
    (progn
      (unless (bolp)
        (if (looking-back "^[ \t]*")
            (progn
              ;; "a" holds how many spaces are there to the beginning of the line
              (let ((a (length (buffer-substring-no-properties (point-at-bol) (point)))))
                (progn
                  ;; Delete backwards progressively in tab-width steps, but
                  ;; without going further of the beginning of line.
                  (if (> a tab-width)
                      (delete-char tab-width) ; `delete-backward-char' is obolete
                    (backward-delete-char a)))))
          ;; Delete tab and spaces first, if at least 2 exist, before removing
          ;; words.
          (progn
            (if (looking-back "[ \t]\\{2,\\}")
                (delete-horizontal-space)
              (backward-kill-word 1))))))
    ))

;;;; I-search symbol at point:

;; I-search with initial contents (symbol at point). Both variants are modified,
;; and based on code from <http://www.emacswiki.org/emacs/SearchAtPoint>.
;; `isearch-forward-at-point' is like `isearch-forward', but bound to <M-s>, and
;; it does not prompt.

(defvar isearch-initial-string nil)
(defun isearch-set-initial-string ()
  (remove-hook 'isearch-mode-hook 'isearch-set-initial-string)
  (setq isearch-string isearch-initial-string)
  (isearch-search-and-update))

(defun isearch-forward-at-point (&optional regexp-p no-recursive-edit)
  "Interactive search forward for the symbol at point."
  (interactive "P\np")
  (if regexp-p
      (isearch-forward regexp-p no-recursive-edit)
    (let* ((end (progn (skip-syntax-forward "w_") (point)))
           (begin (progn (skip-syntax-backward "w_") (point))))
      (if (eq begin end)
          (isearch-forward regexp-p no-recursive-edit) ; no symbol
        (setq isearch-initial-string (buffer-substring begin end))
        (add-hook 'isearch-mode-hook 'isearch-set-initial-string)
        (isearch-forward regexp-p no-recursive-edit)))))

(define-key global-map "\M-s" 'isearch-forward-at-point)
(define-key isearch-mode-map "\M-s" 'isearch-repeat-forward)

;;;; Query/Replace:

;; NOTE: Build regexps with visual feedback by using `re-builder'.

(defun --query-replace-read-args (prompt regexp-flag &optional noerror)
  "Works on active region or current word.
Unlike `query-replace-read-args' it proposes both strings (FROM and TO) and
chooses the defaults of both."
  (unless noerror
    (barf-if-buffer-read-only))
  (let (pos1 pos2)
    (if (region-active-p)
        (setq pos1 (region-beginning) pos2 (region-end))
      (let (bds (--wap-region t))
        (if (consp bds)                 ; otherwise there is no word nearby
            (setq pos1 (car bds) pos2 (cdr bds)))))
    (setq from-str
          (if (and pos1 pos2)
              (buffer-substring-no-properties pos1 pos2)
            (if query-replace-defaults
                (car query-replace-defaults) "")))
    (setq default-to-str (cdr query-replace-defaults))
    (setq query-replace-defaults (cons from-str default-to-str)))
  (let* ((from (query-replace-read-from prompt regexp-flag))
         (to (progn (if (consp from)    ; user accepted the defaults
                        (setq from (car from)))
                    (query-replace-read-to from prompt regexp-flag))))
    (if (and (zerop (length to)) query-replace-defaults) ; empty target string?
        (setq to (query-replace-compile-replacement default-to-str regexp-flag)))
    (list from to current-prefix-arg))
  )

(defun --query-replace-whole-buffer (from to &optional word-flag regexp-flag)
  "Query-replace strings in whole buffer, proposing word at point as the string to be replaced.
Unless third arg WORD-FLAG (prefix arg if interactive) is non-nil match at word
boundaries. Motivation: `query-replace' (incremental) and
`replace-string' (global) replaces those occurrences between `point' and the end
of the buffer."
  (interactive
   (let ((common (--query-replace-read-args "Query replace whole buffer\n" nil)))
     (list (nth 0 common) (nth 1 common) (nth 2 common))))
  (save-excursion
    (let ((case-fold-search nil))
      (if (use-region-p)
          (deactivate-mark))
      (perform-replace from to t regexp-flag (not word-flag) nil nil (point-min) (point-max)))
    )
  )

(global-set-key "\M-r" '--query-replace-whole-buffer) ; default `move-to-window-line'

;;;; Search all buffers for lines matching a regular expression (F3):

(global-set-key
 [f3] (lambda (extension rexp)
        "Run \\[occur] in all buffers for REGEXP whose filename matches
EXTENSION (default: all buffers) and display buffer <*Occur*>.

This is basically a shortcut for \\[multi-occur-in-matching-buffers]."
        (interactive "MBuffer regexp (RETURN for all buffers): \nsRegexp: ")
        (if (and extension (> (length extension) 0))
            (multi-occur-in-matching-buffers (concat ".+\." extension "$") rexp)
          (multi-occur (buffer-list) rexp))))

;;; -------- CTAGS, ECB, CEDET
;;; ----------------------------------------------------------------------------

;;;; etags/ctags:

;; Load a single TAGS file `tags-file-name' generated by some Makefile. Example:
;;     ctags --extra=+q --langmap=c++:+.txx.ixx --if0 --totals
;;           --recurse --exclude='*~' --c++-kinds=+p --fields=+iaS -e

(add-hook 'after-init-hook
          '(lambda()
             (require 'etags)
             (setq tags-revert-without-query t
                   tags-add-tables 'ask-user
                   tags-file-name (expand-file-name "TAGS" (--startup-directory)))
             ))

(defun --find-tag-default ()
  "Specialize `find-tag-default' for C/C++:
- parse to #include file-names and #define macro names
- find scoped names
- ignore keywords"
  ;; http://www.emacswiki.org/emacs/RegularExpression
  (if mark-active                       ; explicit region
      (buffer-substring-no-properties (region-beginning) (region-end))
    (cond
     ((or (equal major-mode 'c-mode)
          (equal major-mode 'c++-mode)) ; language: C/C++
      (let ((case-fold-search t))
        (if (save-excursion             ; preprocessor directive?
              (beginning-of-line)
              (or (looking-at "^\\s-*#\\s-*\\(include\\)\\s-*[<\"]\\([^>\"]+\\)")
                  (looking-at "^\\s-*#\\s-*\\(define\\|undef\\)\\s-*\\(\\(\\sw\\|\\s_\\)+\\)")))
            (match-string 2)
          (let ((done)                  ; hop over keywords
                (keywords (format "\\b\\(%s\\)\\b"
                                  (mapconcat 'identity
                                             '("namespace" "class" "struct" "union" "enum" "typedef"
                                               "virtual" "inline" "static" "const" "volatile"
                                               "if" "else" "try" "catch" "return"
                                               "void" "signed" "unsinged"
                                               "\\w+_cast"
                                               "void" "bool" "long" "float" "double" "char" "short" "int") "\\|"))))
            (while (not done)
              (while (not (looking-at "\\w\\|\\s_"))
                (forward-char))
              (unless (setq done (not (string-match keywords (find-tag-default))))
                (forward-sexp)))
            (if (save-excursion         ; scoped name?
                  (if (and (not (looking-at "\\b\\(\\sw\\|\\s_\\)"))
                           (looking-at "\\sw\\|\\s_\\|:"))
                      (backward-sexp)) ; jump to begin of word if starting within
                  (looking-at "\\(\\(\\sw\\|\\s_\\)+\\(::\\(\\sw\\|\\s_\\)+\\)+\\)"))
                (match-string 1)
              (find-tag-default)))
          )))
     (t                                 ; language: any
      (find-tag-default))
     ))
  )

(defun --find-tag (tagname &optional regexp-p)
  "Like `find-tag' but if TAGNAME isn't defined get a default using `--find-tag-default'.
Interactively, with prefix arg ask user."
  ;; TODO:
  ;; - `--find-tag-default' should rather be an advice for the original `find-tag' function.
  ;; - post to http://stackoverflow.com/questions/23693847/how-can-i-jump-to-definition-without-being-queried-in-emacs
  (interactive
   (list (if current-prefix-arg (--read-string "Find tag" (--find-tag-default))
           (--find-tag-default))))
  (condition-case nil
      (progn (setq mark-active)
             (find-tag tagname nil regexp-p)
             (message tagname))
    (error (message "No tags containing '%s'" tagname))))

(defun --find-tag/ido ()
  "Find a tag using ido."
  ;; http://emacswiki.org/emacs/InteractivelyDoThings#toc11
  (interactive)
  (tags-completion-table)
  (let (tag-names)
    (mapatoms (lambda (x)
                (push (prin1-to-string x t) tag-names))
              tags-completion-table)
    (find-tag (ido-completing-read "Tag: " tag-names))))

(global-set-key [?\M-.] '--find-tag)
(global-set-key [?\C-x ?\M-.] '--find-tag/ido)

(global-set-key [(control kp-divide)] 'tags-search)
(global-set-key [(meta kp-divide)] 'tags-query-replace)
(global-set-key [(control kp-multiply)] 'pop-tag-mark)
(global-set-key [(control kp-enter)]
                '(lambda()
                   "`list-tags' with current filename."
                   ;; tags filename:   /home/andreass/itpgk/TAGS
                   ;; buffer filename: /home/andreass/itpgk/apps/sds/src/LineSaorRelation/LineSaorRelation.cxx
                   ;; list filename:                        apps/sds/src/LineSaorRelation/LineSaorRelation.cxx
                   (interactive)
                   (let* ((d (file-name-directory tags-file-name))
                          (f (replace-regexp-in-string (regexp-quote d) "" (--file-name) nil 'literal)))
                     (list-tags f)
                     (message f)
                     )))

(global-set-key [(control kp-subtract)]
                '(lambda () "Back to first found item."
                   (interactive) (tags-loop-continue t)))

(global-set-key [(control kp-add)]
                '(lambda () "Continue `tags-search', `tags-query-replace' or `find-tag'."
                   (interactive)
                   (condition-case nil (tags-loop-continue)
                     (error (find-tag last-tag t)))))

;;;; Load file explorer in directory of current file:

(cond
 (--winnt-p
  (defun explorer (file)
    "Launch Windows Explorer."
    (interactive "fFile/Folder: ")
    (let ((w32file (substitute ?\\ ?/ (expand-file-name file))))
      (if (file-directory-p w32file)
          (w32-shell-execute "explore" w32file "/e,/select,")
        (w32-shell-execute "open" "explorer" (concat "/e,/select," w32file)))))

  (global-set-key
   [(f1)(x)]
   '(lambda()
      (interactive)
      (explorer (or (--file-name (current-buffer)) default-directory))
      ))
  )
 (t))

;;;; Speedbar:

(require 'speedbar)
(global-set-key [(meta f1)] 'speedbar)
(setq speedbar-show-unknown-files t)
(add-to-list 'speedbar-fetch-etags-parse-list
             '("\\.\\(cxx\\|hxx\\|ixx\\)" . speedbar-parse-c-or-c++tag))

;;; -------- SYSTEM/APPLICATIONS INTERFACE
;;; ----------------------------------------------------------------------------

;; Copy and paste to through the clipboard, with coding system conversion.

(cond (--winnt-p
       (set-selection-coding-system 'compound-text-with-extensions))
      (t
       (set-selection-coding-system 'utf-8)))

;;;; Shell environment (Cygwin/Cmd)

;; F12   : toggle between shell buffer and current window configuration
;; S-F12 : like before, but let shell buffer appear in a dedicated frame
;; M-F12 : inject a pushd to change to directory of current buffer
;; C-F12 : `shell-command'

(defun --dired-garbage (&optional dirname)
  "Run this function interactively, wait until the process terminated, then mark files.
Use in \"%m\" in dired buffer and regexp \".*\" to mark all files."
  (interactive "D")
  (let ((genl-garbage
         '("*.tmp" "*.bak" "*.log" "*.orig" "*.rej"
           "nul" "tags" "*.exe.stackdump"))
        (tex-garbage
         '("*.loc" "*.toc" "*.dvi" "*.aux"))
        (win-garbage
         '("*.jbf" "thumbs.db" "pspbrwse.jbf"))
        (msvc-garbage
         (if current-prefix-arg
             '("*.obj" "*.lib" "*.res" "*.map" "*.exp" "*.sbr" "*.pdb" "*.suo"
               "*.cv4" "*.pch" "*.ncb" "*.map" "*.csm" "*.idb" "*.bcw" "*.mbt"
               "*.obr" "*.mrt" "*.ilk" "*.plg" "*.crf" "*.rsp" "*.bsc")))
        (gcc-garbage
         (if current-prefix-arg
             '("*.o" "*.a" "*.gch"))))
    (let ((xlist (flatten (append win-garbage genl-garbage tex-garbage msvc-garbage gcc-garbage))))
      (find-dired dirname
                  (join-str " -o " (mapcar (lambda (a) (format "-iname '%s'" a)) xlist))))
    )
  )
(setq shell-prompt-pattern "^[^#$%<>\n]* *[#$%>~] *"
      comint-prompt-regexp shell-prompt-pattern)
(defun --shell-command (cmd &optional prompt)
  "Execute CMD (PROMPT non-nil requires the user to acknowledge).
When CMD ends in an ampersand execute asynchronously."
  (when (or (not prompt)
            (yes-or-no-p (format "%s\nExecute this command? " cmd)))
    (let ((result (shell-command cmd))
          (b1 (get-buffer-window "*Async Shell Command*"))
          (b2 (get-buffer-window "*Shell Command Output*")))
      (when b1
        (delete-windows-on b1)
        (delete-frame (window-frame b1)))
      (when b2
        (delete-windows-on b2)
        (delete-frame (window-frame b2)))
      result)))

(global-set-key [(f12)] '--toggle-shell)
(global-set-key [(shift f12)] '(lambda()(interactive)(--toggle-shell 'frame)))
(global-set-key [(meta f12)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(control f12)] 'shell-command) ; alias M-!

(defvar cygwin-mount-cygwin-bin-directory)
(cond
 (--cygwin-p
  ;; Activate Cygwin Bash over COMSPEC.
  ;; http://www.blarg.net/~offby1/cygwin-mount/
  (defun tty ()
    "Launch a shell (mintty) in the buffer's directory."
    (interactive)
    (w32-shell-execute "open" "C:/cygwin/bin/mintty.exe"
                       (concat "-s 132,50 -o ScrollbackLines=10000 "
                               "-o BackgroundColour=50,50,10 -o CursorColour=220,20,60 "
                               "-o Transparency=High -o OpaqueWhenFocused=yes -o Font=Consolas "
                               "-o FontHeight=12 "
                               "/bin/env CHERE_INVOKING=1 /bin/bash -l -i")))
  (condition-case nil
      (let* ((cygwin-root "C:/cygwin")
             (cygwin-bin (concat cygwin-root "/bin")))
        (require 'cygwin-mount)
        (setq cygwin-mount-cygwin-bin-directory cygwin-bin)
        (cygwin-mount-activate)
        (message "Cygwin activated")
        (setenv "PS1" "[\\j] \\w > ")
        (setenv "PID" nil)
        (setenv "MAKE_MODE" "UNIX")
        (setenv "CYGWIN" (concat (getenv "CYGWIN") " nodosfilewarning"))
        (setenv "PATH" (concat cygwin-bin ";" (getenv "PATH")))
        (when --winnt-p
          (setq exec-path (cons cygwin-mount-cygwin-bin-directory exec-path)))
        (unless (getenv "BASH_ENV")
          (setenv "BASH_ENV" (--ff-existing-pathname ".bash_env" (list "$HOME" "$USERPROFILE"))))
        ;; Shell buffer setup (comint)
        (setq shell-file-name "bash"
              shell-command-switch "-c"
              explicit-bash-args '("--noediting" "--login" "-i")
              explicit-shell-file-name shell-file-name
              dired-chmod-program "chmod"
              w32-quote-process-args t
              w32-allow-system-shell t
              w32-system-shells (append '("sh" "bash" "sh.exe" "bash.exe") w32-system-shells))
        (setenv "SHELL" shell-file-name)
        (load "comint")
        (add-hook 'comint-output-filter-functions
                  '(lambda (text)
                     (if (string-match "[[:word:]]*Working directory is ||\\([^|]+\\)||" text)
                         (cd (substring text (match-beginning 1) (match-end 1))))) nil t)
        (fset 'original-comint-exec-1 (symbol-function 'comint-exec-1))
        (defun comint-exec-1 (name buffer command switches)
          (let ((binary-process-input t)
                (binary-process-output nil))
            (original-comint-exec-1 name buffer command switches)))
        )
    (error (message "Cygwin-mount failed!")))
  )
 (--winnt-p
  (defun tty ()
    "Launch the NT Command console in the buffer's directory."
    (interactive)
    (w32-shell-execute "open" "cmd"))
  )
 )

(add-hook 'comint-preoutput-filter-functions
          '(lambda (&optional output)
             ;; Delete completion buffer every time you enter a command.
             ;; http://stackoverflow.com/questions/6458220/automatically-close-emacs-shell-mode-tab-completion-buffer
             (interactive)
             (dolist (win (window-list))
               (when (string= (buffer-name (window-buffer win)) "*Completions*")
                 (delete-window win)
                 (kill-buffer "*Completions*")))
             output))
(add-hook 'comint-output-filter-functions 'shell-strip-ctrl-m nil t) ; no ^M echoing
(add-hook 'comint-output-filter-functions 'comint-watch-for-password-prompt nil t)
(autoload 'comint-add-scroll-to-bottom "comint-scroll-to-bottom" "Activate `comint-scroll-to-bottom'.")

(setq comint-file-name-quote-list '(?\   ?\")
      process-coding-system-alist
      (cons '("bash" . undecided-unix) process-coding-system-alist))

(add-hook 'shell-mode-hook
          '(lambda()
             ;; NOT shell script programming mode. General settings. See also
             ;; <http://www.emacswiki.org/cgi-bin/wiki/ansi-color.el>
             (setq comint-prompt-regexp shell-prompt-pattern
                   comint-completion-addsuffix t
                   comint-scroll-show-maximum-output 'this
                   comint-eol-on-send t)
             (setq shell-dirstack-query "cygpath -w `dirs`")
             (make-variable-buffer-local 'comint-completion-addsuffix)
             (load-library "ansi-color")
             (ansi-color-for-comint-mode-on))
          )

(defvar --toggle-shell-last-window-conf nil "The last window configuration.")
(defvar --toggle-shell-last-buf nil "The last buffer object in case there's no last window configuration.")
(defvar --toggle-shell-last-frame nil "The frame that was selected when opening a shell buffer.")
(defun --toggle-shell-have-conf ()
  (window-configuration-p --toggle-shell-last-window-conf))
(defun --toggle-shell-store-last-conf ()
  (setq --toggle-shell-last-buf (current-buffer)
        --toggle-shell-last-frame (selected-frame)
        --toggle-shell-last-window-conf (current-window-configuration)))
(defun --toggle-shell-restore-last-conf ()
  (if (--toggle-shell-have-conf)
      (progn (raise-frame --toggle-shell-last-frame)
             (set-window-configuration --toggle-shell-last-window-conf))
        (let ((bufnam (if (bufferp --toggle-shell-last-buf)
                          (buffer-name --toggle-shell-last-buf) --toggle-shell-last-buf)))
          (if bufnam
          (if (get-buffer bufnam) (switch-to-buffer bufnam t)
                (message "%s: buffer not available" bufnam))))))

(defun --toggle-shell (&optional display inject-cd)
  "Toggles between current buffers and a system shell buffer.
With prefix-arg close the shell.

When DISPLAY is 'vertical splits the shell as vertical window; when 'frame uses
a dedicated frame (default: single window). When INJECT-CD executes a `pushd' to
the working directory of the buffer from which you toggled the shell."
  (interactive)
  (let* ((shell-buf (get-buffer "*shell*"))
         (shell-window (if shell-buf (get-buffer-window shell-buf t))) ; non-nil when currently displayed
         (shell-frame (if shell-window (window-frame shell-window)))
         (in-shell (eq (current-buffer) shell-buf))
         (vertical (string= display 'vertical))
         (popup-frame (or (string= display 'frame)
                          (and inject-cd (not (bufferp shell-buf)))
                          (and (framep shell-frame)
                               (not (eq shell-frame (selected-frame)))))))
    ;; With prefix-arg close shell, restore windows. Otherwise (no prefix-arg)
    ;; toggle shell window; restore windows when called twice in a row, or the
    ;; current buffer is the shell buffer (`in-shell').
    (if current-prefix-arg
        ;; Kill shell.
        (if (bufferp shell-buf)
            (progn (message "Exiting shell '%s'" (buffer-name shell-buf))
                   (kill-buffer shell-buf)
                   (if in-shell (--toggle-shell-restore-last-conf)))
          (error "No shell buffer to kill."))
      ;; If already in shell-buffer toggle back to stored frame-configuration.
      (if (and in-shell (not inject-cd))
          (progn
            (--toggle-shell-restore-last-conf)
            ;; Recurse to reopen the shell-buffer in a dedicated frame, or
            ;; close the dedicated frame and reopen the buffer in a window.
            (if (and popup-frame (eq shell-frame (selected-frame)))
                (--toggle-shell 'frame inject-cd)
              (when (and popup-frame shell-frame)
                (delete-frame shell-frame)
                (--toggle-shell nil inject-cd))))
        ;; Not in shell buffer. Warp to it or create new one.
        (unless in-shell
          (--toggle-shell-store-last-conf))
        (if popup-frame
            (progn (switch-to-buffer-other-frame (or shell-buf "*shell*"))
                   (raise-frame
                    (or shell-frame (window-frame (get-buffer-window "*shell*" t)))))
          (if (> (count-windows) 1)
              (delete-other-windows)))
        ;; Finally `cd' into the working directory the current buffer.
        (let ((new-shell (not (bufferp shell-buf)))
              (new-dir       ; `default-directory' of `--toggle-shell-last-buf'
               (if --toggle-shell-last-buf
                   (buffer-local-value 'default-directory --toggle-shell-last-buf))))
          ;; (if (buffer-file-name --toggle-shell-last-buf)
          ;;       (file-name-directory (buffer-file-name --toggle-shell-last-buf))
          ;;     (buffer-local-value 'default-directory --toggle-shell-last-buf)))))
          ;; Open shell, move point to end-of-buffer. The new shell-buffer's
          ;; `default-directory' will be that of the buffer the shell was
          ;; launched from.
          (when vertical
            (if (> (count-windows) 1)
                (delete-other-windows))
            (split-window-vertically)
            (other-window 1))
          (funcall 'shell)
          (when new-shell
            (message "New shell %s (%s)" (buffer-name (current-buffer)) new-dir)
            (if inject-cd (sit-for 2))) ; wait for prompt
          (goto-char (point-max))
          ;; If on a command-prompt insert and launch a "cd" command (assume no
          ;; job is running).
          (when (and inject-cd new-dir)
            (save-excursion
              (forward-line -1)
              (end-of-line)
              (unless (setq inject-cd (re-search-forward comint-prompt-regexp (point-max) t))
                (error "Cannot `pushd', shell is busy")))
            (when (and inject-cd
                       ;;(not (string= default-directory new-dir))
                       ;;(not shell-last-dir ...)
                       )
              (let* ((cmd (format "pushd '%s' %s" (comint-quote-filename new-dir)
                                  (if (buffer-file-name --toggle-shell-last-buf)
                                      (format "# '%s'"
                                              (file-name-directory (buffer-file-name --toggle-shell-last-buf)))
                                    ""))))
                ;; `shell-process-cd' set new `default-directory' and set `shell-last-dir' to old.
                ;; (If the pushd command is successful, a dirs is performed as well; >nul discards
                ;; this output.)
                (shell-process-cd new-dir)
                (insert cmd)
                (comint-send-input)
                (message "%s: cd '%s'" (buffer-name --toggle-shell-last-buf) new-dir))
              )
            )
          )
        )
      )))

;;;; Transparent file Compression and Encryption

;; EasyPG is an all-in-one GnuPG interface for Emacs. It has two aspects: tools
;; to use GnuPG from Emacs (EasyPG Assistant), and a functional library to GnuPG
;; (EasyPG Library). The library is implemented in epg.el, the applications in
;; epa-*.el. The most important is epa-file.el, which implements auto-encryption
;; - it will encrypt .gpg-files automatically.
;;
;; To encrypt a file on the command-line (symmetrically, no public-key):
;;      $ gpg --symmetric filename
;; You will be prompted for a passphrase, and then GnuPG creates filename.gpg;
;; it will not overwrite filename. For example, if the filename is notizen.txt
;; then GnuPG creates notizen.txt.gpg
;;
;; To decrypt .gpg-files on the command-line use:
;;     $ gpg -d filename.gpg
;;
;; By default, epa-file will try to use symmetric encryption, aka
;; password-based encryption. Asymmetric Encryption is public-key encryption.
;; With symmetric encryption all that is required to encrypt/decrypt your file
;; is the pass phrase. Using Public Key Encryption, you require both your
;; private key and your pass phrase.
;;
;;     C-S-e : encrypt region or buffer
;;     C-S-d : decrypt
;;
;; http://www.gnu.org/software/emacs/manual/html_mono/epa.html[EasyPG Manual]

(auto-compression-mode t)
(when --emacs24p
  (epa-file-enable)
  (setq epa-file-cache-passphrase-for-symmetric-encryption t) ; default is nil
  )

;;;; Dired:

(add-hook 'dired-mode-hook
          '(lambda()
             (setq dired-listing-switches "-alh --group-directories-first"
                   dired-recursive-deletes t) ; delete non-empty directories
             ))

;;;; GNU spell checker (ispell/aspell):

;;     M-$ : check a region or the whole buffer for spelling errors
;;     M-t : check a region or sexp at point
;;
;; Für aktuelle deutsche Wörterbücher siehe
;; https://www.j3e.de/ispell/igerman98/. Anweisung in INSTALL.aspell befolgen.
;; Das Wörterbuch muss kompiliert werden
;;      make aspell/de_DE.rws
;; Die Wörterbuchdateien liegen nun unter
;;      aspell dump config | grep data-dir

(when t
  (add-hook 'after-init-hook
            '(lambda ()
               (setq-default ispell-program-name
                             (cond (--winnt-p
                                    "C:/cygwin/bin/aspell.exe")
                                   (t
                                    (if (file-executable-p "/usr/bin/hunspell")
                                        "/usr/bin/hunspell" "/usr/bin/aspell"))))

               (when (and ispell-program-name
                          (file-executable-p ispell-program-name))
                 (message "ispell-program-name = %s" ispell-program-name)
                 ;; (autoload 'ispell-minor-mode "ispell" "Check spelling of words interactively." t)
                 ;; (autoload 'ispell-word "ispell" "Check spelling of word at or before point" t)
                 ;; (autoload 'ispell-complete-word "ispell" "Complete word at or before point" t)
                 ;; (autoload 'ispell-region "ispell" "Check spelling of every word in the region" t)
                 ;; (autoload 'ispell-buffer "ispell" "Check spelling of every word in the buffer" t)
                 ;; (autoload 'ispell "ispell" "Run ispell over buffer" t)
                 (eval-after-load "ispell"
                   '(progn
                      (let ((langs '("de_DE" "en_US")))
                        (setq --dictionary-ring (make-ring (length langs)))
                        (dolist (elem langs) (ring-insert --dictionary-ring elem)))
                      (setq ispell-dictionary (ring-ref --dictionary-ring -1) ; default to use if `ispell-local-dictionary' is nil
                            ispell-silently-savep t
                            ispell-really-aspell nil ; `aspell' extensions should not be used
                            ispell-really-hunspell t ; `hunspell' extensions should be used
                            )
                      (defun --toggle-dictionary ()
                        ;; Using code from http://www.emacswiki.org/emacs/FlySpell.
                        (interactive)
                        (let ((lang (ring-ref --dictionary-ring -1)))
                          (ring-insert --dictionary-ring lang)
                          (ispell-change-dictionary lang)
                          (message "Switched to dictionary %S" lang)
                          (sit-for 0.4)
                          (when flyspell-mode
                            (flyspell-delete-all-overlays)
                            (flyspell-buffer)))
                        )
                      (defun --spell-at-point (&optional beg end )
                        "Check region or current word for spelling errors."
                        (interactive "*r") ; unless mark choose sexp at point
                        (if (or mark-active)
                            (ispell-region beg end)
                          (progn (setq deactivate-mark t) (ispell-word)))
                        )
                      (global-set-key "\C-\M-t" ; default: `transpose-sexps'
                                      '(lambda() "Toggle dictionary (with prefix-arg) or run ispell on the current buffer."
                                         (interactive) (if current-prefix-arg (--toggle-dictionary) (ispell))))
                      (global-set-key "\C-t" 'ispell-word)      ; default: `transpose-chars'
                      (global-set-key "\M-t" '--spell-at-point) ; default: `transpose-words'
                      ))
                 )
               ;; `flyspell-auto-correct-word' is bound to `C-.' Keep hitting
               ;; `C-.' to replace the word with the successive suggestions.
               (setq flyspell-mark-duplications-flag nil
                     flyspell-use-meta-tab nil
                     flyspell-sort-corrections nil
                     flyspell-issue-message-flag nil
                     flyspell-consider-dash-as-word-delimiter-flag t)
               )
            )
  (when nil
    (add-hook 'after-init-hook
              '(lambda()
                 (mapc
                  (lambda (hook) (add-hook hook 'flyspell-mode))
                  '(text-mode-hook asciidoc-mode-hook LaTeX-mode-hook)))
              )
    )
  )

;;; -------- FRAMES AND WINDOWS
;;; ----------------------------------------------------------------------------

(load "frame-cmds" t)
(setq split-window-keep-point t
      pop-up-windows t
      even-window-heights nil)

;;;; Window manipulation and navigation (<F2>, <F6>):

;;     F2 s : spawn window to another frame
;;     F2 c : `compare-windows'
;;     F2 1 : `delete-other-windows'
;;     F2 2 : `split-window-vertically'
;;     F2 3 : `split-window-horizontally'
;;     F2 4 : split window and enable follow mode
;;
;;     C-, and C-. : cycle through windows (keys are unbound by default)
;;
;; http://emacs.stackexchange.com/questions/3458/how-to-switch-between-windows-quickly
;;

(global-set-key [f2] (make-keymap))
(global-set-key [(f2)(s)] '(lambda()
                             "Spawn window. Close window and open buffer in a new frame."
                             (interactive)
                             (save-some-buffers t)
                             (setq b (current-buffer))
                             (delete-window)
                             (switch-to-buffer-other-frame b))
                )

(global-set-key [(f2)(c)] 'compare-windows)
(global-set-key [(f2) ?1] 'delete-other-windows)
(global-set-key [(f2) ?2] 'split-window-vertically)
(global-set-key [(f2) ?3] 'split-window-horizontally)
(global-set-key [(f2) ?4] '(lambda()
                             (interactive)
                             (follow-delete-other-windows-and-split)
                             (follow-recenter)))

(global-set-key [?\C-x ?\C-.] 'other-window)
(global-set-key [?\C-x ?\C-,] '(lambda()(interactive)(other-window -1)))

(global-set-key [(f6)] 'next-multiframe-window)
(global-set-key [(control f6)] 'previous-multiframe-window)

;;;; Frames and fonts, clone (<F2>, <C-x 5>):

;;     F2 r    : toggle recent buffer list
;;     F2 f    : set frame font
;;     F2 c    : open twin copy of the current buffer in other frame
;;     C-x 5 c : dto.
;;     C-x 4 c : dto. but in other window
;;
;;     CTRL-+  : enlarge font
;;     CTRL--  : shrink font
;;     CTRL-1  : previous frame
;;     CTRL-2  : next frame
;;     C-x C-b : replace 'list-buffers'

(if --emacs23p
    (global-set-key [(f2)(r)]
                    '(lambda (&optional prefix)
                       "Toggle recent buffer list."
                       (interactive "P")
                       (select-frame (--startup-frame))
                       (let* ((ibuf (get-buffer "*Ibuffer*")))
                         (cond
                          ((or (eq (current-buffer) ibuf))
                           (jump-to-register ?b)) ; restore frames
                          (t                      ; show buffer list
                           (frameset-to-register ?b)
                           (delete-other-windows)
                           (ibuffer)))
                         ))))

(global-set-key [?\C-+] 'text-scale-adjust)
(global-set-key [?\C--] 'text-scale-adjust)

(autoload 'ibuffer "ibuffer" "List buffers." t)
(global-set-key [?\C-x ?\C-b] 'ibuffer)

;; Enable ibuffer-filter-by-filename to filter on directory names too.
(eval-after-load "ibuf-ext"
  '(define-ibuffer-filter filename
       "Toggle current view to buffers with file or directory name matching QUALIFIER."
     (:description "filename"
                   :reader (read-from-minibuffer "Filter by file/directory name (regexp): "))
     (ibuffer-awhen (or (buffer-local-value 'buffer-file-name buf)
                        (buffer-local-value 'dired-directory buf))
                    (string-match qualifier it))))

;; <C-M-Cursor> shrinks/enlarges the selected frame or window

(global-set-key [(control meta up)]
                (lambda() (interactive)
                  (let ((F (selected-frame)))
                        (if (and (one-window-p t) (frame-restored-p F) (> (frame-height F) 5))
                        (set-frame-height F (- (frame-height F) 1))
                          (shrink-window -1)))))
(global-set-key [(control meta down)]
                (lambda() (interactive)
                  (let ((F (selected-frame)))
                        (if (and (one-window-p t) (frame-restored-p F))
                        (set-frame-height F (+ (frame-height F) 1))
                          (enlarge-window 1)))))
(global-set-key [(control meta left)]
                (lambda() (interactive)
                  (let ((F (selected-frame)))
                        (if (and (one-window-p t) (frame-restored-p F) (> (frame-width F) 10))
                        (set-frame-width F (- (frame-width F) 1))
                          (enlarge-window-horizontally -1)))))
(global-set-key [(control meta right)]
                (lambda() (interactive)
                  (let ((F (selected-frame)))
                        (if (and (one-window-p t) (frame-restored-p F))
                                                   (set-frame-width F (+ (frame-width F) 1))
                          (enlarge-window-horizontally 1)))))

;;;; Special display popup frames:

;; Dedicated windows are never split/reused for other buffers, and killing the
;; buffer deletes its frame. Test for dedicated windows:
;;
;;      (if (window-dedicated-p (selected-window))
;;          default-minibuffer-frame (selected-frame))
;;
;; Make some buffers which by default appear in other windows, appear in the
;; same window:
;;
;;      (nconc same-window-buffer-names '("*Help*"))

(when (and (featurep 'frame-cmds) --emacs24p)
  (cond (--winnt-p
         (setq special-display-frame-alist
               '((border-width . 20)
                 (menu-bar-lines . 0)
                 (tool-bar-lines . 0)
                 (modeline . nil)
                 (minibuffer . nil)
                 (unsplittable . t)
                 (vertical-scroll-bars . nil)
                 (horizontal-scroll-bars . nil)))
         )
        (--unix-p
         (setq special-display-frame-alist
               '((user-position . t)
                 (border-width . 20)
                 (menu-bar-lines . 0)
                 (tool-bar-lines . 0)
                 (modeline . nil)
                 (minibuffer . nil)
                 (unsplittable . t)))
         )
        )
  (setq special-display-regexps
        '(("[*]+\\([Dd]iff\\|[Cc]ompilation\\|[Gg]rep\\)"
           --display-compilation-frame)
          ;; ("shell[*]\\|[*][sS]+hell" --display-shell-frame)
          )
        )
  (defun --display-compilation-frame (buf &optional args)
    (let ((W (special-display-popup-frame buf))
          (N (buffer-name buf)))
      (when (setq F (window-frame W))
        (set-window-margins W 0 0)
        (maximize-frame F)
        (redirect-frame-focus F default-minibuffer-frame)
        (select-frame default-minibuffer-frame)
        ) W)
    )
  (defun --display-shell-frame (buf &optional args)
    (let ((W (special-display-popup-frame buf))
          (N (buffer-name buf)))
      (when (setq F (window-frame W))
        (set-window-margins W 0 0)
        (maximize-frame F)
        (redirect-frame-focus F default-minibuffer-frame)
        (select-frame default-minibuffer-frame)
        ) W)
    )
  (defun --display-gud-frame (buf &optional args)
    (let ((W (special-display-popup-frame buf))
          (N (buffer-name buf)))
      (when (setq F (window-frame W))
        (set-window-margins W 0 0)
        (redirect-frame-focus F default-minibuffer-frame)
        (select-frame default-minibuffer-frame)
        ) W)
    )
  )

;;; -------- FILES AND BUFFERS
;;; ----------------------------------------------------------------------------

;; M-n and M-p are not bound by default.

(defun --get-buffer (&optional buffer-or-name)
  "Get editor buffer object from BUFFER-OR-NAME."
  (let ((buffer (current-buffer)))
    (if (and buffer-or-name)
        (setq buffer (get-buffer buffer-or-name)))
    buffer))

(defun --close-buffer (&optional buffer-or-name)
  "Close the buffer BUFFER-OR-NAME."
  (let ((buffer (--get-buffer buffer-or-name)))
    (when buffer
      (unless (--is-transient-buffer buffer t)
        (when (buffer-file-name buffer)
          (recentf-push (buffer-file-name buffer))))
      (condition-case nil           ; throws "Attempt to delete the sole visible or iconified frame"
          (delete-frame (window-frame (get-buffer-window buffer)))
        (error))
      (delete-windows-on buffer)
      (kill-buffer buffer)))
  )

(defun --close-buffer-save (&optional buffer-or-name)
  "Close the buffer BUFFER-OR-NAME.
Similar to `--close-buffer' but prompt user to save if modified, even if buffer
not associated with a file."
  (interactive)
  (let ((buffer (--get-buffer buffer-or-name)))
    (when (buffer-modified-p buffer)
      (if (y-or-n-p (concat "Buffer " (buffer-name buffer) " modified. Save? "))
          (save-buffer) (set-buffer-modified-p nil)))
    (--close-buffer buffer))
  )

(defun --normal-mode-no-gimmicks ()
  "Enable buffer `normal-mode' and refontify.
Disable frame menu, toolbar, scrollbars."
  (interactive)
  (menu-bar-mode 0)
  (tool-bar-mode 0)
  (if (featurep 'minimap) (minimap-mode 0))
  (set-scroll-bar-mode 'left)
  (toggle-scroll-bar (if --dark-p 0 1))
  (linum-mode 0)
  (setq-default left-margin-width  1
                right-margin-width 0)
  (set-window-buffer nil (current-buffer)) ; use margins now
  (normal-mode)
  (font-lock-fontify-buffer)
  )

(global-set-key [pause] 'toggle-read-only)
(global-set-key [(control a)] 'mark-whole-buffer)
(global-set-key [?\C-,] 'previous-buffer)
(global-set-key [?\C-.] 'next-buffer)
(global-set-key [?\M-g ?g] '--normal-mode-no-gimmicks)

;;;; Auto-Insert, Writestamps

(auto-insert-mode 1)
(add-hook 'find-file-hook 'auto-insert)

(setq time-stamp-active t               ; enable writestamps
      time-stamp-line-limit 200         ; find in the first n lines
      time-stamp-format "%:y-%02m-%02d %02H:%02M:%02S"
      time-stamp-start  "\\$[wW]ritestamp[: ]*" ; regexp after which stamp is written
      time-stamp-end    "\\$")

;;;; Transient buffers, kill, nuke buffers

(defvar --transient-buffers-name-list
  '(list) "Absolute list of filenames to remove by `--is-transient-buffer'.")
(defvar --transient-buffers-name-list-strict
  '(list) "Absolute list of filenames to remove by `--is-transient-buffer', strict mode.")

(defvar --transient-buffers-name-regexp
  "\\.\\(reg\\)\\|ChangeLog\\|configure\\|fstab\\|TAGS\\|BROWSE\\|DOXYFILE\\|\\.emacs\\.local"
  "Filenames to remove by `--is-transient-buffer'.")
(defvar --transient-buffers-name-regexp-strict
  "\\.\\(el\\|gpg\\|ahk\\|cmd\\|bat\\)$"
  "Filenames to remove by `--is-transient-buffer', strict mode.")

(defun --is-transient-buffer (&optional buf strict)
  "Test if buffer object BUF (default: current) is transient.
Transient buffers don't visit a file, or the file is temporary/read-only (e.g.,
man-pages, tag-files). If STRICT also matches buffers whose files have gone,
filenames with <.> and GUD/compilation/shell buffers."
  (or buf (setq buf (current-buffer)))
  (or (bufferp buf) (setq buf (get-buffer buf)))
  (condition-case nil
      (let* ((bufn (buffer-name buf))
             (buff (buffer-file-name buf)))
        (if (or (not buff)                                 ; *pseudo-buffers* have no file
                (and bufn (string-match "<[0-9]+>$" bufn)) ; indirect buffer
                (save-excursion                            ; Dired buffers (checking major mode)
                  (set-buffer buf) (equal major-mode 'dired-mode))
                (string-match "\\.\\(sln\\|vcxproj\\)$" buff) ; VS solutions/projects
                (string-match "\\.\\(log\\|te?mp\\)$" buff) ; temporary files
                (string-match "\\.\\(m3u8?\\)$" buff)
                (string-match "\\.\\([1-9]+\\)$" buff)      ; read-only files (man-pages etc.)
                (string-match --transient-buffers-name-regexp bufn) ; known filenames
                (member bufn  --transient-buffers-name-list)
                (and (not (buffer-modified-p buf)) ; empty files, unmodified
                     (= 0 (buffer-size buf)))
                ;; Strict mode.
                (and strict
                     (not (buffer-modified-p buf))
                     (or
                      (member bufn  --transient-buffers-name-list-strict)
                      (string-match --transient-buffers-name-regexp-strict bufn)
                      (string-match "^[._]" buff) ; filenames beginning with '.' or '_'
                      (string-match "\\.\\(html?\\|epub\\|mobi\\|zip\\)$" buff)
                      (= 0 (buffer-size buf))               ; empty files
                      (and buff (not (file-exists-p buff))) ; file moved/renamed
                      )))
            ;; Return buffer. Compilation buffer only in strict mode.
            (if (or strict (not (string-match "compilation" bufn))) buf))
        )
    (error
     (message "ERROR: %s: buffer %s" (buffer-file-name buf) (buffer-name buf))))
    )

(defun --nuke (&optional strict)
  "Kill less interesting buffers, cloned buffers, other frames and windows unless they're modified.
Refontify and `normal-mode' all surviving buffers. With prefix-arg or STRICT
kill harder; see `--is-transient-buffer'."
  (interactive "P")
  (deactivate-mark)
  (clean-buffer-list)
  (if (fboundp 'recentf-cleanup)
      (recentf-cleanup))
  (delete-other-windows)
  (delete-other-frames)
  (save-excursion
    (dolist (b (buffer-list))
      (unless (eq b (get-buffer "*Messages*"))
        (when (--is-transient-buffer b strict)
          (message "Killing '%s' %s" (buffer-name b) (if strict "(strict)" ""))
          (delete-windows-on b)
          (kill-buffer b)))
      )))

(global-set-key [(control f4)]
                '(lambda ()
                   (interactive)
                   (let* ((msgbufn "*Messages*"))
                     (cond
                      ((eq (current-buffer) (get-buffer msgbufn))
                       ;; Remove the *Messages* frame. In strict mode refontify,
                       ;; reset major mode of surviving buffers.
                       (--close-buffer (current-buffer))
                       (if current-prefix-arg
                           (save-excursion
                             (let ((bufl (buffer-list)))
                               (while bufl (setq buf1 (car bufl) bufl (cdr bufl))
                                      (--normal-mode-no-gimmicks)))))
                       )
                      (t
                       ;; Kill transient and old buffers, switch to *Message*
                       ;; frame.
                       (select-frame (--startup-frame))
                       (--nuke current-prefix-arg)
                       (switch-to-buffer-other-frame msgbufn) (end-of-buffer)
                       ))
                     )))

(global-set-key [(meta control f4)]
                '(lambda (&optional strict)
                   "Print \"transient\" buffers that `--nuke' would kill."
                   (interactive "P")
                   (message "\nTransient buffers: %s" (if strict "strict" ""))
                   (dolist (b (buffer-list))
                     (when (--is-transient-buffer b strict)
                       (message "%s\t<%s>" (buffer-name b) (buffer-file-name b))))
                   (switch-to-buffer-other-window "*Messages*")
                   (end-of-buffer)))

;;;; Smart buffer switching (recent and companion files)
;;
;; C-x   b: `switch-to-buffer'
;; C-x 5 b: `switch-to-buffer-other-frame'
;; C-x 5 f: `find-file-other-frame'

(require 'find-file)
(setq ff-case-fold-search nil         ; allows extensions in different cases
      ff-always-try-to-create nil     ; don't create other file if was not found
      ff-quiet-mode nil
      ff-ignore-include nil
      cc-search-directories             ; lists are sequentially searched
      (append '("." ".."         "../.."             "../../.."
                "../src"         "../../src"         "../../../src"
                "../src/*"       "../../src/*"       "../../../src/*"
                "../src/*/*"     "../../src/*/*"     "../../../src/*/*"
                "../include"     "../../include"     "../../../include"
                "../include/*"   "../../include/*"   "../../../include/*"
                "../include/*/*" "../../include/*/*" "../../../include/*/*"
                "../inc"         "../../inc"         "../../../inc"
                "../inc/*"       "../../inc/*"       "../../../inc/*"
                "../inc/*/*"     "../../inc/*/*"     "../../../inc/*/*"
                ) cc-search-directories)
      cc-other-file-alist
      (append '(("\\.c$"   (".h"))
                ("\\.cpp$" (".hpp" ".h" ".hxx" ".ixx" ".txx" ".inl"))
                ("\\.cxx$" (".hpp" ".h" ".hxx" ".ixx" ".txx" ".inl"))
                ("\\.h$"   (".inl" ".l" ".y" ".cpp" ".cxx" ".c"))
                ("\\.hpp$" (       ".cpp" ".cxx"))
                ("\\.ixx$" (".hpp" ".cpp" ".cxx"))
                ("\\.txx$" (".hpp" ".cpp" ".cxx"))
                ) cc-other-file-alist)
      )

(when --unix-p
  (setq cc-search-directories
        (append cc-search-directories
                '("/usr/*/include"
                  "/usr/*/include/*" "/usr/*/include/*/*" "/usr/*/include/*/*/*"
                  "/usr/include/sys" "/usr/include/sys/*" "/usr/include/sys/*/*"))))

(when (getenv "INCLUDE")
  (setq cc-search-directories (append cc-search-directories
                                      (split-string (getenv "INCLUDE") (if --winnt-p ";" ":")))))

(global-set-key [?\C-x ?l] 'goto-line)
(global-set-key [(control x)(control o)] 'revert-buffer)
(global-set-key [(control o)] '--other-buffer)
(global-set-key [(meta o)] '(lambda()   ; other frame
                              (interactive)
                              (let ((pop-up-frames t)
                                    (pop-up-windows nil))
                                (--other-buffer t))))

(defadvice switch-to-buffer (before to-existing-buffer-only activate compile)
  "When interactive, switch to existing buffer only, unless given a prefix argument.
See Glickstein, page 30."
  (interactive
   (list (read-buffer "Switch to buffer? " (--recent-buffer) (null current-prefix-arg)))))

(defun --other-buffer (&optional new-frame)
  "\"Je est un autre.\" --- Arthur Rimbaud.
Finds some other, interesting buffer:
    - #include
    - \"$Companion: FILENAME$\" tag near the head of buffer
      (if GET-COMPANION is non-nil, interactively, with prefix-arg)
    - filename at point
    - `ff-find-other-file', `other-buffer'
Return some buffer object or raise an error."
  (interactive)
  (let (ftype buf (ynp t) (borg (current-buffer)))
    (unless (--is-transient-buffer)
      ;; #include <FILENAME>
      (let ((ff-quite-mode t))
        (save-window-excursion
          (ff-find-other-file)
          (unless (eq (current-buffer) borg)
            (setq buf (current-buffer))))
        )
      ;; $Companion:FILENAME$
      (unless buf
        (save-excursion
          (goto-char (point-min))
          (when (re-search-forward "\\$[Cc]ompanion[ :]+\\(.+?\\)\\$" (point-max) t)
            (setq buf (buffer-substring (match-beginning 1)(match-end 1)))
            (if (file-exists-p buf)
                (setq ynp nil)
              (setq buf nil))
            )))
      ;; filename at point or most recent buffer
      (unless buf
        (if (and (setq buf (ffap-file-at-point)) (> (length buf) 1))
            (unless (yes-or-no-p
                     (concat "    " (buffer-file-name (current-buffer)) "\n"
                             " => " (buffer-file-name buf)))
              (setq buf nil))))
      (unless buf
        (setq buf (other-buffer) ynp nil)))
    ;; `display-buffer'
    (unless buf (error "No companion file found."))
    (unless (bufferp buf)
      (setq buf (find-file-noselect buf)))
    (when (or (not ynp) (yes-or-no-p
                         (concat "    " (buffer-file-name (current-buffer)) "\n"
                                 " => " (buffer-file-name buf))))
      (message (buffer-name buf))
      (if nil
          (if (one-window-p t)
              (pop-to-buffer buf)
            (display-buffer-other-frame buf)))
      (pop-to-buffer buf)
      ))
  )

;;;; Scrolling and mark

;; The `mark-ring' is a list of former marks of the current buffer, most recent
;; first. `--pop-local-mark' (M-PgDn) works like `set-mark-command' with
;; prefix-arg (C-u C-SPC). But `set-mark-command' does not care if the
;; `mark-ring' contains duplicate or closed positions. `--pop-local-mark' will
;; filter such positions out, and additionally makes sure that the jump is at
;; least 132 chars away (some arbitary value).
;;
;; The `global-mark-ring' records buffers in which the mark was recently set.
;; `--pop-global-mark' (M-PgUp) works like `pop-global-mark', but the function
;; makes sure the mark being jumped to is in another buffer, and that this
;; buffer is connected to a real file.
;;
;; Use C-SPC to store a new mark. When `transient-mark-mode' is enabled, the
;; region is highlighted whenever the mark is active, and deactivated by
;; changing the buffer. Press C-SPC twice to record the buffer position but
;; deactive the highlighted region.

(setq redisplay-dont-pause t
      hscroll-step 3
      scroll-margin 5                   ; begin this far from screen top/bottom
      scroll-preserve-screen-position nil
      scroll-conservatively 100000      ; do not jump to screen-center when scrolling
      scroll-preserve-screen-position 1 ; maintain screen-position on PgUp/PgDown etc.
      )

(defun --current-line ()       (1+ (count-lines (point-min) (point)))) ; like current-column
(defun --window-top-line ()    (save-excursion (goto-char (window-start)) (--current-line)))
(defun --window-bottom-line () (save-excursion   (move-to-window-line -1) (--current-line)))

(defun --beginning-of-line ()
  "Toggle point column 0 and first non-blank character.
With prefix-arg nearby set mark."
  (interactive)
  (set-window-hscroll (selected-window) 0)
  (setq n (point))
  (back-to-indentation)
  (if (eq n (point)) (beginning-of-line)))

(defun --beginning-of-buffer ()
  "Approximate the begin of the current buffer."
  (interactive)
  (beginning-of-buffer)
  (and (not (--is-transient-buffer))
       (re-search-forward "^#include" (+ (point-min) 500) t))
  (--beginning-of-line))

(defun --end-of-buffer ()
  "Approximate the end of the current buffer."
  (interactive) (--beginning-of-line) (goto-char (point-max)))

(defun --end-of-line ()
  "Move point to end of line."
  (interactive) (deactivate-mark) (end-of-line))

(defun --pop-local-mark (&optional reccnt beg)
  "Make mark the point, then pop off former buffer-local mark and jump to mark.
Do this while the new buffer position is within 132 chars."
  (interactive)
  (if mark-ring
      (deactivate-mark)
    (error "Local mark ring is empty"))
  (or beg (setq beg (point)))
  (set-mark-command 1)
  (delete-other-windows)
  (let ((dist-max 132) (dist (abs (- beg (point))))
        (reccnt (if (numberp reccnt) (+ reccnt 1) 1)))
    (when (< dist dist-max)
      (when (and (numberp reccnt) (> reccnt 132))
        (goto-char beg)
        (error (format "No mark found within %d chars: point not moved (try C-u C-SPC)" dist-max)))
      (--pop-local-mark reccnt beg)))
  )

(defun --pop-global-mark (&optional reccnt beg begbuf)
  "Pop off `global-mark-ring' and jump to the top location."
  (interactive)
  (unless beg
        (setq beg (point) begbuf (current-buffer)))
  (deactivate-mark)
  (delete-other-windows)
  (pop-global-mark)
  (when (and (numberp reccnt) (> reccnt 132))
        (switch-to-buffer begbuf) (goto-char beg)
        (message "`global-mark-ring' is empty"))
  (if (or (eq begbuf (current-buffer)))
          (--pop-global-mark (if (numberp reccnt) (+ reccnt 1) 1) beg begbuf))
  )

(global-set-key [(M-prior)] '--pop-global-mark) ; recently visited buffers
(global-set-key [(M-next)]  '--pop-local-mark)

;;;; Unscroll

;; Code taken from "Writing GNU Emacs Extensions" by Bob Glickstein, (O'Reilly &
;; Assoc., 1997). This file uses "advice" to modify the scrolling commands such
;; that the screen appearance is preserved at the start of each series of
;; scrolls. After scrolling (intentionally or otherwise), you can restore the
;; display with M-x unscroll RET, which Bob Glickstein likes to bind to C-M-v.
;; Since the KDE WM traps C-M-v, however, we bind it to C-v too.

(defvar unscroll-point (make-marker)
  "Cursor position for next call to \\[unscroll].")
(defvar unscroll-window-start (make-marker)
  "Window start for next call to \\[unscroll].")
(defvar unscroll-hscroll nil
  "Horizontal scroll for next call to \\[unscroll].")

(defun unscroll ()
  "Revert to last position before the start of scrolling."
  (interactive)
  (goto-char unscroll-point) (recenter)
  (set-window-start nil unscroll-window-start)
  (set-window-hscroll nil unscroll-hscroll))

(defun unscroll-maybe-remember ()
  (when (and (symbolp last-command)
         (not (get last-command 'unscrollable)))
    (set-marker unscroll-point (point))
    (set-marker unscroll-window-start (window-start))
    (setq unscroll-hscroll (window-hscroll))))

(put 'scroll-up 'unscrollable t)
(put 'scroll-down 'unscrollable t)
(put 'scroll-left 'unscrollable t)
(put 'scroll-right 'unscrollable t)

(defadvice scroll-up (before remember-for-unscroll activate compile)
  "Remember where we started from, for `unscroll'."
  (unscroll-maybe-remember))
(defadvice scroll-down (before remember-for-unscroll activate compile)
  "Remember where we started from, for `unscroll'."
  (unscroll-maybe-remember))
(defadvice scroll-left (before remember-for-unscroll activate compile)
  "Remember where we started from, for `unscroll'."
  (unscroll-maybe-remember))
(defadvice scroll-right (before remember-for-unscroll activate compile)
  "Remember where we started from, for `unscroll'."
  (unscroll-maybe-remember))

(define-key global-map "\C-\M-v" 'unscroll)
(global-set-key [(control v)] 'unscroll)

;;;; Comments in program code

(require 'newcomment)

(global-set-key [(meta insert)] '--fill-next-column-stop)

(defun --trim-string (string)
  "Remove white spaces in beginning and ending of STRING.
White space here is any of: space, tab, emacs newline (line feed, ASCII 10)."
  (replace-regexp-in-string "\\`[ \t\n]*" "" (replace-regexp-in-string "[ \t\n]*\\'" "" string)))

(defun --fill-next-column-stop ()
  "When the current line defines a comment reindent it and fill up comment-chars
up to the next stop column. Stops at 4, 8, 25, 48, 72, 80, 108 and 132."
  (interactive)
  (let*
      ((fill-char
        ;; Basically use the first character from `comment-start'. Note that
        ;; this variable is defined arbitarily in `newcomment' one or two
        ;; characters wide (";" in ELisp, "# " in Perl and "// " in C++ modes).
        ;; Hence make some distinctions here.
        (cond
         ((or (eq major-mode 'c++-mode)
              (eq major-mode 'c-mode))
          (if current-prefix-arg "/" "*"))
         ((eq major-mode 'asciidoc-mode)
          ;; Examine characters at point. `char-after' w/o argunent returns the
          ;; character at point, `char-before' w/o argument the character before
          ;; point. The point is actually a dubious concept within Emacs: a
          ;; position between two characters.
          ;; http://www.gnu.org/software/emacs/manual/html_node/elisp/Near-Point.html
          (setq c (--trim-string (char-to-string (if (bolp) (char-after) (char-before)))))
          (if current-prefix-arg
              (--read-string "*=note -=listing *=sidebar _=quote .=literal +=backend" (or c "*"))
            (if (or (= (length c) 0))
                (--read-string "*=note -=listing *=sidebar _=quote .=literal +=backend" "*")
              c)))
         (t
          (substring comment-start 0 1))
         )))
    (if (looking-at fill-char)
        (kill-line)
      (if (or (= (length fill-char) 0))
          (error "No filling char.")
        (indent-according-to-mode)
        (end-of-line) (delete-horizontal-space)
        (let ((n
               (cond ((<= (current-column) 3) 3)
                     ((<= (current-column) 7) 7)
                     ((<= (current-column) 24) 24)
                     ((<= (current-column) 47) 47)
                     ((<= (current-column) 71) 71)
                     ((<= (current-column) 78) 78)
                     ((<= (current-column) 107) 107)
                     ((<= (current-column) 131) 131)
                     (t     ; reached max. column, insert new-line and continue
                      (end-of-line) (newline-and-indent)
                      (cond ((<= (current-column) 3) 3)
                            ((<= (current-column) 7) 7)
                            ((<= (current-column) 24) 24)
                            ((<= (current-column) 47) 47)
                            ((<= (current-column) 71) 71)
                            ((<= (current-column) 78) 78)
                            ((<= (current-column) 107) 107)
                            ((<= (current-column) 131) 131)
                            (t -1)
                            )
                      )
                     )))
          (message "'%s': column-stop %d -> %d" fill-char (current-column) (+ n 1))
          (while (<= (current-column) n) (insert fill-char))
          )
        )
      )
    ))

(defconst my-indent-for-comment nil)
(defun --indent-for-comment (&optional beg end)
  ;; The --package cares about indentation, tabs and whitespace. Things that
  ;; can't be seen directly.
  "Comment out region or insert comment to current line.
If the region is active and the mark is active, call `comment-region' (unless it
only consists of comments, in which case it calls `uncomment-region').

Else convert an empty single-line comment or start a new one, according to the
three comment classes:

   A) comment to the right of the code (at the `comment-column')
   B) comment on its own line, indented like code
   C) comment on its own line, beginning at the left-most column.

The idea of this function is, while writing your code, type the comment-char
repeatedly until you are satisfied with the comment.

Basically this function implements a smarter `indent-for-comment'. It was
inspired by `asm-comment': in `asm-mode' your repeatedly press ';' until the
new/present comment is seated right. However, you have to get used to it. To
disable this behavior simply switch to overwrite-mode."
  (interactive "r")
  (let ((comment-char (substring comment-start 0 1)))
    (cond
     (buffer-read-only
      ;; Throw an error.
      (error "Buffer is read-only."))
     (mark-active                       ; un/comment the region
      (comment-or-uncomment-region beg end))
     ((or overwrite-mode (--point-in-string))
      ;; When overwriting or in literal strings just insert `comment-char'. Note
      ;; that `in-string-p' is more accurate but also expensive.
      (insert comment-char)
      ;; (message "Overwrite")
      )
     (t
      (comment-normalize-vars)          ; the mark is inactive
      (let ((commentp (save-excursion
                        (beginning-of-line) (comment-search-forward (line-end-position) t)))
            (point-at-bol (bolp))
            (point-at-eol (or (eolp) (looking-at "[ \t]*$")))
            )
        (if commentp (message "Line comment %d/%d" commentp (point)))
        (cond
         ;; Uncommented line? Start new comment.
         ((null commentp)
          (cond
           ((save-excursion
              (beginning-of-line)
              (looking-at "^[ \t]*$"))
            (recenter)
            (delete-horizontal-space)
            (indent-according-to-mode)
            (comment-indent)
            ;; ;; (insert comment-char ?\ )
            ;; (insert comment-char)
            (indent-for-tab-command)
            (message "New standalone-comment")
            )
           (t
            (comment-indent)
            (message "New inline-comment at %d" (point))
            )
           )
          )
         ;; Line contains a comment. Jump/indent comment if point is before the comment.
         ((<= (point) commentp)         ; sits before or on the `comment-char'
          (cond
           ((save-excursion
             (goto-char commentp)
             (skip-chars-backward " \t") (bolp)) ; standalone?
            (comment-indent)
            ;; (fixup-whitespace)          ; between objects around point - leave one space or none
            (message "Indented standalone-comment %d/%d" (current-column) comment-column)
            )
           (t                           ; inline
            (comment-indent)
            ;; (fixup-whitespace)
            (message "Indented inline-comment %d/%d" (current-column) comment-column)
            )
           )
          )
         ;; Point in comment where `comment-indent' has put it and at EOL?
         ((= (point) (save-excursion (comment-indent) (point)))
          (cond
           ;; At EOL? Kill empty inline/standalone-comment. By pressing the
           ;; comment-char multiple times empty comments are created and removed
           ;; in a circle. Warning: `comment-indent' injects a comment on empty
           ;; lines and thus can't be used to set a variable
           (point-at-eol
            (kill-comment 1)
            (previous-line)
            (if (looking-at "^[ \t]*$") ; standalone?
                (--cleanup-whitespace)
              (end-of-line)
              ;; (fixup-whitespace)
              ;; (indent-according-to-mode)
              ;; (beginning-of-line) (back-to-indentation)
              )
            (message "Empty comment removed")
            )
           (t
            ;; Not at EOL - we have text.
            ;;    inline:     turn into standalone
            ;;    standalone: kill and cleanup all blank lines
            (cond
             ((save-excursion
                (goto-char commentp)
                (skip-chars-backward " \t") (bolp)) ; standalone?
              (recenter)
              (kill-comment 1)
              (previous-line) (indent-according-to-mode)
              (--cleanup-whitespace)
              (message "Killed standalone-comment")
              )
             (t                         ; inline
              (goto-char commentp)
              (newline)
              (insert comment-char)     ; 2nd char
              (comment-indent)
              (message "Upgraded inline-comment")
              )
             )
            )
           )
          )
         ;; Insert `comment-char'.
         (t
          (insert comment-char)
          (message "Insert comment-char")
          )
         )
        )
      ))
    ))

;;;; Reduce whitespace (Cleanup)

(global-set-key [(control delete)] '--cleanup-whitespace)

(defun --cleanup-whitespace ()
  "Reduce blank lines arround point.
With prefix-arg fix the whole buffer."
  (interactive)
  (setq mark-active nil)
  (defun line-comment-position ()
    (let (commentpos)
      (save-excursion
        (beginning-of-line)
        (setq commentpos (comment-search-forward (line-end-position) t)))
      commentpos))
  (save-match-data
    (if current-prefix-arg
        ;; Cleanup whole buffer or region
        (progn (delete-trailing-whitespace)
               (whitespace-cleanup))
      ;; Reduce whitespace arround point
      (let* ((thiscomment (line-comment-position))
             (eolpos (line-end-position))
             thisblank singleblank manyblank)
        (save-excursion
          (beginning-of-line)
          (setq thisblank (looking-at "[ \t]*$")
                singleblank (and thisblank
                                 (not (looking-at "[ \t]*\n[ \t]*$"))
                                 (or (bobp) (progn (forward-line -1) (not (looking-at "[ \t]*$")))))
                manyblank (and thisblank (not singleblank)))
          )
        (if singleblank                 ; delete some isolated blank line
            (progn (delete-blank-lines)
                   (indent-according-to-mode))
          (if manyblank                 ; delete all surrounding blank lines
              (progn (delete-blank-lines)
                     (indent-according-to-mode))
            (if (looking-at "^")        ; at BOL
                (if (looking-at "[ \t]+")
                    (delete-horizontal-space)
                  (delete-indentation)  ; join to previous line
                  (indent-according-to-mode)
                  (when (looking-at comment-start-skip)
                    (save-excursion (indent-for-comment)) (fixup-whitespace))
                  )
              (if (looking-at "$")      ; at EOL
                  (progn
                    (if thiscomment     ; this line has a comment
                        (progn (delete-indentation t)
                               (if (looking-at comment-start-skip)
                                   (progn (kill-region (point) (match-end 0))
                                          (fixup-whitespace))))
                      (delete-indentation t) ; this line has no comment
                      (if (looking-at comment-start-skip)
                          (progn (kill-region (point) (match-end 0))
                                 (insert comment-start)
                                 (fixup-whitespace)
                                 (indent-for-comment))
                        (fixup-whitespace))
                      )
                    )
                (if (looking-at "[ \t]+") ; at middle of line
                    (delete-horizontal-space)
                  (fixup-whitespace))
                )))))
      )
    ))

;;;; Markup text

(global-set-key [(control <)] '--wap-markup)

(defvar --wap-markup-qs) (make-variable-buffer-local '--wap-markup-qs)
(defvar --wap-markup-qe) (make-variable-buffer-local '--wap-markup-qe)
(defvar --wap-markup-es) (make-variable-buffer-local '--wap-markup-es)
(defvar --wap-markup-ee) (make-variable-buffer-local '--wap-markup-ee)

(defun --wap-markup-enable (&optional s1 e1 s2 e2)
  (if (not s1)
      (--wap-markup-enable "'" "'" "*" "*")
    (setq --wap-markup-qs s1) (setq --wap-markup-qe e1)
    (setq --wap-markup-es s2) (setq --wap-markup-ee e2)))

(defun --wap-markup (&optional beg end)
  "Quote or emphasize (prefix-arg) the current region. Without region get word
at point, according to the current syntax (`--wap-region').
        Quotation: quote/mark substrings, quote, citation (Notierung, Zitat)
        Emphasis: emphasize filenames and URLs, the accentuation (Betonung)
The default markup is `quoting' and \"emphasizing\". Programming modes can
refine these character using the `--wap-markup-enable' function. The
programming-mode only defines how the text is edited; how it will appear,
however, depends on the text is typeset/visualized/spoken)."
  (interactive "*r")
  ;; TODO: With prefix arg remove all markups
  ;; TODO: Without prefix arg cycle through all markups --wap-markup-list
  (if (or (not mark-active) (not beg) (not end))
          (let ((reg (--wap-region)))
        (setq beg (car reg) end (cdr reg))))
  (setq s (if current-prefix-arg --wap-markup-es --wap-markup-qs)
        e (if current-prefix-arg --wap-markup-ee --wap-markup-qe))
  (goto-char beg)(insert s)
  (goto-char (+ end (length s)))(insert e)
  (if (eq beg end) (goto-char (+ beg 1)))
  )

;;;; Fill paragraphs
;;
;; M-q fills paragraphs, C-x M-q allows varying indentation of paragraphs in a
;; region. Both justify with prefix-arg.

(global-set-key [(control return)] 'newline-and-indent)
(global-set-key [(control meta return)] '--unwrap-lines)
(global-set-key [(meta q)] '--fill-thing)
(global-set-key [(meta control q)] '--unfill-thing)
(global-set-key [(control x)(meta q)] 'fill-nonuniform-paragraphs) ; fill with varying indentation

(defun --count-words ()
   "Print number of words in the region."
   ;; http://www.gnu.org/software/emacs/emacs-lisp-intro/html_mono/emacs-lisp-intro.html#Counting-Words
   (interactive)
   (let (start end bds)
     (cond
      ((use-region-p)
       (setq start (region-beginning) end (region-end)))
      (t
       (setq bds (bounds-of-thing-at-point 'paragraph))
       (setq start (car bds) end (cdr bds)))
      )
     (save-excursion
       (let ((count 0))
         (goto-char start)
         (while (and (< (point) end)     ; loop!
                     (re-search-forward "\\w+\\W*" end t))
           (setq count (1+ count)))
         (cond ((zerop count) (message "The region does not have any words."))
               ((= 1 count)   (message "The region has 1 word."))
               (t             (message "The region has %d words." count))
               )
         ))
     ))

(defun --fill-thing (&optional justify region)
  "Smart filling function for paragraph at point or paragraphs in region.

If JUSTIFY is non-nil (interactively, with prefix argument), justify as well.

The REGION argument is non-nil if called interactively, and the mark is active,
use `fill-individual-paragraphs'. The function fills each of the paragraphs in
the active region, treating every change in indentation level OR prefix as a
paragraph boundary, then fills each paragraph using its indentation level as the
fill prefix."
  (interactive
   (progn (barf-if-buffer-read-only)
          (list (if current-prefix-arg 'full) t)))
  (cond
   ((use-region-p)
    (fill-individual-paragraphs (region-beginning) (region-end) justify)
    (--count-words (region-beginning) (region-end)))
   (t
    (fill-paragraph justify)
    (--count-words))
   )
  )

(defun --unfill-thing ()
  "Takes a multi-line paragraph, or a region of such, and makes single line(s)
from each paragraph."
  (interactive
   (progn (barf-if-buffer-read-only)))
  (cond
   ((use-region-p)
    (let ((fill-column (point-max)))
      (fill-individual-paragraphs (region-beginning) (region-end)))
    (--count-words (region-beginning) (region-end))
    )
   (t
    (let ((fill-column (point-max)))
      (fill-paragraph nil))
    (--count-words))
   )
  )

(defun --unwrap-lines()
  "Remove all newlines until we get to two consecutive ones, reach the end of
the buffer. Useful for unwrapping quotes before sending them on IRC."
  ;; http://www.emacswiki.org/emacs/UnwrapLine
  (interactive)
  (let ((start (point))
        (end (copy-marker (or (search-forward "\n\n" nil t) (point-max))))
        (fill-column (point-max)))
    (fill-region start end)
    (goto-char end)
    (goto-char start)))

;;;; Whitespace-mode, Selective display, Tabify (F10)
;;
;; F10:   white-space-mode to auto-tabify
;; M-F10: reserved by X (full-screen)
;; M-F10: auto-tabify-region or
;; C-F10: selective display
;;
;; See
;; - http://www.emacswiki.org/emacs/ShowWhiteSpace
;; - http://www.emacswiki.org/SmartTabs

(when --emacs23p
  (require 'whitespace)
  (defun tabify (start end)
    "\"Tabs for indentation, spaces for alignment.\".
When a region is selected for each line:
  - tabify before 1st character
  - untabify after 1st character to end-of-line
WARNING: converts TABs in strings"
    (interactive "r")
    (save-window-excursion
      (save-excursion
        (save-restriction
          (goto-char start)
          (beginning-of-line)
          (let ((modified (buffer-modified-p))
                (lnno 0) (lnspc 0) (lntab 0) (lnutab 0)
                (bol (point)) (iol 0))
            (while (and (< bol end)
                        (< bol (point-max)))
              (save-excursion
                (back-to-indentation)
                (setq iol (point)))
              ;; Tabify from BOL to 1st char.
              (skip-chars-forward "\t")
              (when (looking-at " ")
                (setq lnspc (1+ lnspc))
                (set-buffer-modified-p nil)
                (tabify bol iol)
                (if (buffer-modified-p)
                    (setq modified t lntab (1+ lntab))))
              ;; Untabify from 1st char to EOL.
              (set-buffer-modified-p nil)
              (end-of-line)
              (untabify iol (point))
              (if (buffer-modified-p)
                  (setq modified t lnutab (1+ lnutab)))
              (forward-line)
              (setq bol (point) lnno (1+ lnno))
              (message "Tabified line %d (%d, %d-%d)" lnno bol start end)
              )
            (set-buffer-modified-p modified)
            (message "Lines in region: %d   Changed: %d+%d/%d (tab-width %d)\n"
                     lnno lntab lnutab lnspc tab-width))
          ))
      )
    (if (not whitespace-mode)
        (whitespace-mode t))
    )

  (global-set-key
   [f10]
   (lambda()
     "Toggle \\[whitespace-mode]."
     (interactive)
     (if (not whitespace-mode)
         (whitespace-mode t)
       (message "Disabling whitespace-mode")
       (whitespace-mode nil)
       (normal-mode))
     (font-lock-fontify-buffer))
   )

  (global-set-key
   [(control f10)]
   (lambda()
     "Hide lines indented more than a given number of
columns (\\[set-selective-display]). Lines with at least n columns of
indentation disappear from the screen. Pass column as prefix-arg (default:
current column)."
     (interactive "r")
     (set-selective-display
      (if current-prefix-arg current-prefix-arg
        (unless selective-display (1+ (current-column)))))))
  )

;;;; Browse URLs
;;

(global-set-key "\C-c\C-zu" 'browse-url)
(global-set-key "\C-c\C-z." 'browse-url-at-point)
(global-set-key "\C-c\C-zb" 'browse-url-of-buffer)
(global-set-key "\C-c\C-zr" 'browse-url-of-region)
(global-set-key "\C-c\C-zv" 'browse-url-of-file)
(add-hook 'dired-mode-hook
          '(lambda () (local-set-key "\C-c\C-zf" 'browse-url-of-dired-file)))
(setq browse-url-save-file t)   ; always save modified buffers before displaying
                                ; the file in a browser

;;;; Buttonize buffers
;;
;; http://stackoverflow.com/questions/3472092/how-to-get-emacs-to-highlight-and-link-file-paths

(define-button-type 'find-file-button 'follow-link t 'action #'find-file-button)
(defun find-file-button (button)
  (find-file (buffer-substring (button-start button) (button-end button))))

(defun buttonize-current-buffer-on-idle (&optional secs repeat)
  "Idle-timer (see \\[run-with-idle-timer]) that buttonizes filenames and URLs.
Use \\[cancel-timer] to cancel it. SECS defaults to 60 seconds idle time."
  (interactive)
  (run-with-idle-timer (or secs 30) t 'buttonize-buffer))
;; (add-hook 'after-init-hook 'buttonize-current-buffer-on-idle)

(defun buttonize-buffer ()
  "Turn all file paths and URLs of the current buffer into buttons."
  (interactive)
  (require 'ffap)
  (deactivate-mark)
  (let (token guess beg end reached bound len)
    (save-excursion
      (setq reached (point-min))
      (goto-char (point-min))
      (while (re-search-forward ffap-next-regexp nil t)
        ;; Bug in ffap, Emacs 23.3.1: `ffap-file-at-point' enters endless loop
        ;; when the string at point is "//".
        (setq token (ffap-string-at-point))
        (unless (string= "//" (substring token 0 2))
          ;; Note that `ffap-next-regexp' only finds some "indicator string" for
          ;; a file or URL. `ffap-string-at-point' blows this up into a token.
          (save-excursion
            (beginning-of-line)
            (when (search-forward token (point-at-eol) t)
              (setq beg (match-beginning 0)
                    end (match-end 0)
                    reached end))
            )
          (message "Found token %s at (%d-%d)" token beg (- end 1))
          ;; Now let `ffap-guesser' identify the actual file path or URL at
          ;; point.
          (when (setq guess (ffap-guesser))
            (message "  Guessing %s" guess)
            (save-excursion
              (beginning-of-line)
              (when (search-forward guess (point-at-eol) t)
                (setq len (length guess) end (point) beg (- end len))
                ;; Finally we found something worth buttonizing. It shall have
                ;; at least 2 chars, however.
                (message "    Matched at (%d-%d]" beg (- end 1))
                (unless (or (< (length guess) 2))
                  (message "      Buttonize!")
                  (make-button beg end :type 'find-file-button))
                )
              )
            )
          ;; Continue one character after the guess, or the original token.
          (goto-char (max reached end))
          (message "Continuing at %d" (point))
          )))
    ))

;;; -------- GIT
;;; ----------------------------------------------------------------------------

(defun git-grep (dir regexp)
  "Like \\[rgrep] (aka \\[grep-find]) but for the given regexp using `git grep'."
  ;; http://stackoverflow.com/questions/25633490/how-can-i-use-m-x-rgrep-with-the-git-grep-command-in-emacs
  (interactive (list (read-directory-name "Directory: " (--startup-directory))
                     (read-string "Regexp: ")))
  (unless (boundp 'grep-find-template) (grep-compute-defaults))
  (let ((old grep-find-template))
    (grep-apply-setting 'grep-find-template "git --no-pager grep --color=auto --line-number <C> <R>")
    (rgrep regexp "*" dir)
    (grep-apply-setting 'grep-find-template old)
    ))
(defalias 'ggrep 'git-grep)

;;; -------- COMPILE, GREP, DEBUG
;;; ----------------------------------------------------------------------------

(global-set-key [(f7)] '--compile)                            ; compile
(global-set-key [(f8)] '(lambda()(interactive)(--compile t))) ; clean
(global-set-key [(shift f7)] 'find-grep-dired)                ; consider also M-x rgrep
(global-set-key [(shift f8)] '--toggle-output-buffer)
(global-set-key (kbd "C-<pause>") 'kill-compilation) ; common IDE shortcut to stop make/find/grep
(global-set-key [(f4)] 'next-error)
(global-set-key [(shift f4)] 'previous-error)

(require 'compile)
(defvar compile-all-command nil)

(ignore-errors
  (require 'ansi-color)
  (add-hook 'compilation-filter-hook
            '(lambda () ; http://stackoverflow.com/questions/3072648/cucumbers-ansi-colors-messing-up-emacs-compilation-buffer
               (when (eq major-mode 'compilation-mode)
                 (ansi-color-apply-on-region compilation-filter-start (point-max))))
            ))

(setq compilation-read-command t
      compilation-scroll-output t
      compilation-ask-about-save nil
      compilation-window-height 25
      compilation-error-regexp-alist
      ;; WARNING: do not use a leading ^
      (append
       ;; Borland
       '(("\\(Error\\|Fehler\\|Fatal\\|Warn[iu]ng\\) [EW0-9]+ \\([a-zA-Z]?:?.+\\) \\([0-9]+\\):" 2 3))
       ;; MSC
       '(("\\([1-9]+>\\)\\([^\t\n\r]+\\)(\\([0-9]+\\)) *: +\\(fatal\\|error\\|warning\\)" 2 3))
       '(("\\([1-9]+>\\)[\t ]+\\([^\t\n\r]+\\)(\\([0-9]+\\)) *:" 2 3))
       '(("\\([^\t\n\r]+\\)(\\([0-9]+\\)) *: +\\(fatal\\|error\\|warning\\)" 1 2))
       ;; Perl
       '(("\\(.+\\) at \\([^ ]+\\) line \\([0-9]+\\)" 2 3))
       ;; ./script.sh: Zeile 1375: rc_set_file: Kommando nicht gefunden.
       '(("\\(.+\\): Zeile \\([0-9]+\\):" 1 2))
       ;; asciidoc: FAILED: X.tmp line 99: block macro cannot occur here: pass::[</div>]
       '(("\\(ERROR\\|FAILED\\|WARNING\\|DEPRECATED\\): \\([^ ]+\\): line \\([0-9]+\\):" 2 3))
       ;; cstor/Rlist
       '(("\\(ERROR\\|FEHLER\\|FATAL\\|WARN[IU]NG\\): *\\([a-zA-Z]?:?.+\\) *(\\([0-9]+\\))" 2 3))
       compilation-error-regexp-alist)
      compilation-parse-errors-filename-function
      '(lambda (filename)
         ;; Function called from `next-error' to post-process filenames while
         ;; parsing error messages. Normally `next-error' fails when the path of
         ;; the error filename is not relative to the compilation directory.
         (let ((f filename) (g) (case-fold-search t) (ff-quiet-mode t))
           (when --winnt-p
             (setq f (replace-regexp-in-string "\\\\"    "/" f))  ; backslash -> slash
             (setq f (replace-regexp-in-string "^[1-9]>"  "" f))) ; remove "N>" at begin of line (MSVC)
           (setq g f)
           (unless (file-exists-p f) ; find in `cc-search-directories'
             (setq f (--ff-existing-pathname g)))
           ;; return f or filename
           (cond ((and f (file-exists-p f))
                  (message "next-error: %s (found)" f) f)
                 (t
                  (message "next-error: %s (not found)" filename) filename))
           )))

(defadvice compilation-goto-locus (after echo-error-message activate)
  "Echo the last error message from the most recent compilation buffer.
Useful when the compilation displays in some other frame."
  (if compilation-last-buffer
      (save-excursion
        (set-buffer compilation-last-buffer)
        (goto-char (window-point (get-buffer-window (current-buffer) t)))
        (message (buffer-substring (line-beginning-position) (line-end-position))))
    (error "No compilation started")))

(defun --read-compile-command (prompt &optional cmd)
  "Prompts the user for a command, using PROMPT as the prompt, CMD as the value
and proposes `compile-history' with alternate values (default:
`compile-command')."
  (if (not cmd)
      (progn (setq cmd (or compile-command ""))
             (setq prompt (concat prompt " (compile-command): ")))
    (setq prompt (concat prompt ": ")))
  (read-from-minibuffer prompt (eval cmd) nil nil '(compile-history . 1)))

(defun --compile (&optional clean prompt)
  "Switch to directory of the makefile, then run `compile'. At the head of the
current buffer look for
    $Compile: COMMAND$
or (when CLEAN is non-nil)
    $Clean: COMMAND$
Tags are first looked up in current buffer, then the makefile buffer."
  (interactive)
  (setq prompt current-prefix-arg)
  (if (fboundp 'mk)
      ;; Shortcut function defined in desktops' .emacs.local
      (mk current-prefix-arg)
    ;; Run `compile' or interprete $Compile: COMMAND$.
    (let ((mkbuf (--startup-buffer))
          (mkdir (--startup-directory)))
      (if (not mkbuf)
          ;; Default: run `compile' in scratch buffer.
          (progn
            (message "No startup buffer.")
            (unless mkdir (error "No startup directory"))
            (let ((default-directory mkdir))
              (call-interactively #'compile))
            )
        ;; Search for impilicit compile command.
        (let ((compile-buf)
              (hysteresis 10000)
              (prompt-tag (if clean "Clean" "Compile")))
          (save-excursion
            ;; Search for implicit command in the current buffer. If CLEAN set
            ;; `compile-all-command', else `compile-command'. TODO: put multiple
            ;; tags into a history list.
            (goto-char (point-min))
            (if (and clean (re-search-forward "\\$ *[Cc]lean: *\\(.+\\) *\\$" hysteresis t))
                (setq compile-all-command (buffer-substring (match-beginning 1) (match-end 1))
                      compile-buf (current-buffer))
              (if (re-search-forward "\\$ *[Cc]ompile: *\\(.+\\) *\\$" hysteresis t)
                  (setq compile-command (buffer-substring (match-beginning 1) (match-end 1))
                        compile-buf (current-buffer))))
            ;; Start compilation when we have `compile-buf'.
            (cond
             ((bufferp compile-buf)
              ;; Prompt for command, proposing the implicit one.
              (setq prompt-tag (format "%s (%s)" prompt-tag (buffer-name compile-buf)))
              (if (or prompt ;;(eq compile-buf mkbuf)
                      )
                  (if clean
                      (setq compile-all-command (--read-compile-command prompt-tag compile-all-command))
                    (setq compile-command (--read-compile-command prompt-tag compile-command))))
              ;; Start async. compilation. `compile' uses plus "-c" and the command
              ;; string. Raise the compilation buffer.
              (if clean
                  (if (is-empty-str compile-all-command)
                      (progn (compile "make clean")
                             (message "%s: make clean" prompt-tag))
                    (compile compile-all-command)
                    (message "%s: %s" prompt compile-all-command))
                (if (is-empty-str compile-command)
                    (progn (compile "make")
                           (message "%s: make" prompt-tag))
                  (compile compile-command)
                  (message "%s: %s" prompt-tag compile-command))
                )
              ;; Jump to 1st error.
              (save-excursion
                (when nil
                  (display-buffer (compilation-find-buffer) t t)
                  (set-buffer (compilation-find-buffer))
                  (set-buffer-file-coding-system 'utf-8))
                )
              )
             (t
              ;; The current buffer normally defines no $Compile:$ command. Switch to
              ;; makefile-buffer and `--compile' again, or "make all".
              (message "The buffer '%s' defines no compile command" (buffer-name))
              (cond
               ((eq (current-buffer) mkbuf)
                (setq compile-command "make all")
                (compile compile-command)
                (message "%s: %s" prompt compile-command)
                (when prompt
                  (save-excursion
                    (display-buffer-reuse-frames (compilation-find-buffer) t t)
                    (set-buffer (compilation-find-buffer))
                    (set-buffer-file-coding-system 'utf-8))
                  ))
               ((bufferp mkbuf)
                (set-buffer mkbuf)
                (--compile clean))
               (t
                (error "No makefile found"))
               )
              )
             ))
          nil)
        )))
  )

(defun --toggle-output-buffer (&optional kill)
  "Display or hide compilation/grep/find/message buffer.
With KILL non-nil (interactively, with prefix-arg) kill. Call multiple times to
switch between compilaton buffer, *grep*, *Find* and *Messages*."
  (interactive "P")
  (let (B W)
    (condition-case nil
        (setq B (compilation-find-buffer))
      (error
       (unless (setq B (get-buffer "*grep*"))
         (unless (setq B (get-buffer "*Find*"))
           (unless (setq B (get-buffer "*Occur*"))
             (setq B (get-buffer "*Messages*")))))
       ))
    (setq W (get-buffer-window B t))
    (if (and kill B)
        (progn
          (condition-case nil
              (kill-compilation)
            (error))
          (delete-windows-on B) (kill-buffer B)
          (select-frame default-minibuffer-frame))
      ;; Show or hide
      (let ((F0 default-minibuffer-frame)
            (F1 (window-frame W)))
        (if (eq (current-buffer) B)
            (delete-windows-on B)       ; hide - will close special popup frames
          (pop-to-buffer B)             ; show
          )
        )
      )))

;;; -------- BUFFER MODES
;;; ----------------------------------------------------------------------------
;;

(local-set-key [?\C-c] (make-keymap))

(autoload 'ffap-file-at-point "ffap")
(autoload 'sensitive-minor-mode "sensitive-minor-mode"
  "Disable backups and autosave." t)

(setq auto-mode-alist
      (append
       (list
        '("\\.\\([hH]\\|inl\\|[io]dl\\|dox\\|ixx\\|txx\\)$" . c++-mode)
        '("\\.bash.*" . sh-mode)
        '("/etc/\\(.*profile\\|.*fstab\\)" . sh-mode)
        '("\\.ahk" . ahk-mode)
        '("\\.inputrc" . conf-mode)
        '("\\.rls$" . cperl-mode)
        '("\\.conf" . conf-mode)
        '("\\.htt" . html-mode)
        '("\\.[Pp][Yy]$" . python-mode)
        '("[Ss][Cc]onscript" . python-mode)
        '("[Ss][Cc]onstruct" . python-mode)
        '("\\.java?$" . java-mode)
        '("\\.m$" . objc-mode)
        '("\\.\\(frm\\|bas\\|rws\\|vb[as]\\|dsm\\|cls\\)$" . visual-basic-mode)
        '("\\.\\(css\\|csspp\\)$" . css-mode)
        '("[Mm]akefile\\.nt$" . makefile-bsdmake-mode)
        '("\\(DOXYFILE\\|Doxyfile\\)$" . makefile-mode)
        '("\\(.l\\.lex\\)$" . flex-mode)
        '("\\(.y\\.yacc\\)$" . bison-mode)
        '("/[_A-Z]+$" . text-mode)
        '("\\.\\(vcf\\|gpg\\)$" . sensitive-minor-mode)
        '("\\.\\(xsd\\|vcxproj\\)" . xml-mode)
        '("\\.\\(adoc\\)" . asciidoc-mode)
        ) auto-mode-alist)
      )

;;;; HTML, CSS, SASS, YAML

(autoload 'css-mode "css-mode" "CSS Stylesheet editing mode" t)
(add-to-list 'auto-mode-alist '("\\.css\\'" . scss-mode))

(autoload 'scss-mode "scss-mode")
(add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode))

(autoload 'yaml-mode "yaml-mode")       ; https://github.com/yoshiki/yaml-mode
(add-to-list 'auto-mode-alist '("\\.ya?ml$" . yaml-mode))

;;;; Generic modes

;; For various other file types. For a list of generic modes see the constants
;; `generic-default-modes', `generic-mswindows-modes', `generic-unix-modes'.

(require 'generic-x)

;;;; C/C++, ObjectiveC, Java modes (cc-mode)

(require 'cc-mode)
(require 'cc-styles)

(autoload 'c-comment "c-fill" "Formatting for multiline C comments" t)
(autoload 'hide-ifdef-mode "hideif" "Hide code within preprocessor conditionals" t)

(setq c-doc-comment-style '((java-mode . javadoc)
                            (pike-mode . autodoc)
                            (c-mode. javadoc)
                            (c++-mode. javadoc)))

(c-add-style "compact-k&r"
             '("k&r"
               (c-tab-always-indent . t)
               (c-backslash-column . 72)
               (c-basic-offset . 4)
               (c-echo-syntactic-information-p . t)
               ;; Auto-cleanup certain constructs,such als "} else {". Most of
               ;; them take place only when auto-newline has been turned on.
               (c-cleanup-list . (brace-else-brace
                                  brace-elseif-brace
                                  brace-catch-brace
                                  empty-defun-braces
                                  defun-close-semi
                                  list-close-comma
                                  scope-operator))
               ;; Map syntactic symbols to indentation offsets. See the
               ;; `c-offsets-alist' documentation syntactic symbols.
               (c-offsets-alist . ((inline-open . +)
                                   (inline-close . 0)
                                   (knr-argdecl-intro . +)
                                   (knr-argdecl . 0)
                                   (label . 0)
                                   (access-label . -)
                                   (case-label . 0)
                                   (statement-case-intro . +)
                                   (statement-case-open . +)
                                   (substatement . +)
                                   (substatement-open . 0)
                                   (inclass . 4) (friend . 0)))
               ;; Leave the comment starter/terminator on separate lines.
               (c-hanging-comment-starter-p . nil)
               (c-hanging-comment-ender-p . nil)
               ;; Control insertion of newlines after braces and commas.
               ;;(c-hanging-brace-alist . ())
               (c-hanging-semi&comma-criteria
                . ((lambda ()
                     ;; Prevent newlines from being inserted after semicolons
                     ;; when there is a non-blank following line. Based on code
                     ;; from the CC mode manual.
                     (save-excursion
                       (if (and (eq last-command-char ?\;)
                                (zerop (forward-line 1))
                                (not (looking-at "^[ \t]*$"))) 'stop nil)))
                   ;; Stop if a comma/semicolon was inserted in a parentheses
                   ;; list.
                   c-semi&comma-inside-parenlist))))

(defun --c-mode-font-lock-if0 (limit)
  ;; http://stackoverflow.com/questions/4549015/in-c-c-mode-in-emacs-change-face-of-code-in-if-0-endif-block-to-comment-f
  (save-restriction
    (widen)
    (save-excursion
      (goto-char (point-min))
      (let ((depth 0) str start start-depth)
        (while (re-search-forward "^\\s-*#\\s-*\\(if\\|else\\|endif\\)" limit 'move)
          (setq str (match-string 1))
          (if (string= str "if")
              (progn
                (setq depth (1+ depth))
                (when (and (null start) (looking-at "\\s-+0"))
                  (setq start (match-end 0)
                        start-depth depth)))
            (when (and start (= depth start-depth))
              (c-put-font-lock-face start (match-beginning 0) 'font-lock-comment-face)
              (setq start nil))
            (when (string= str "endif")
              (setq depth (1- depth)))))
        (when (and start (> depth 0))
          (c-put-font-lock-face start (point) 'font-lock-comment-face)))))
  nil)

(add-hook 'c-mode-common-hook
          '(lambda()
             (c-set-style "compact-k&r")
             (which-function-mode)
             (--tune-CUA-mode)
             (--wap-markup-enable "_" "_" "`" "`")
             (setq tags-case-fold-search nil)
             ;; Fill paragraphs. This only affects `fill-paragraph' and not
             ;; `fill-region'
             (setq fill-paragraph-function 'c-fill-paragraph
                   fill-column 80)
             (local-set-key [(meta q)] '--fill-thing)
             (local-set-key [(meta control q)] '--unfill-thing)
             ;; Javadoc comment style. Also let "- " begin paragraphs (item
             ;; lists). The regular `c-paragraph-start' is just "$".
             (when --emacs22p
               (setq c-paragraph-start "\\(@[a-zA-Z]+\\>\\|$\\|- \\)") ; for Javadoc
               (c-setup-paragraph-variables))
             ;; Enable auto-newline insertion (evident by "/a" on the modeline).
             ;; Electrifies certain keys such as the left and right braces,
             ;; colons, semi-colons, etc.
             (when nil
               (if --emacs22p
                   (c-toggle-auto-newline 1)
                 (c-toggle-auto-state 1)))
             ;; Enable hungry-deletion of whitespace (evident by "/h" on the
             ;; modeline). Electrifies backspace/delete keys by consuming all
             ;; preceding/forward whitespace, including newlines and tabs.
             (when nil
               (c-toggle-hungry-state 1)
               (local-set-key [(delete)] 'c-electric-delete-forward))
             ;; Change the insertion behavior of line continuation backslash for
             ;; `c-indent-line'. The original function inserts also if on
             ;; #include, or on a macro without backslashes. This has been
             ;; fixed.
             (local-set-key [(return)] '(lambda()
                                          (interactive)
                                          (let ((has-backslash)
                                                (macro-start (c-query-macro-start)))
                                            (save-excursion
                                              (end-of-line)
                                              (if (eq (char-before) ?\\)
                                                  (setq has-backslash t)))
                                            ;; Indent.
                                            (if (and (not has-backslash) macro-start)
                                                (newline-and-indent)
                                              (c-newline-and-indent)))))
             ;; Define C-HOME and C-END for C modes.
             (local-set-key [?\C-c ?\\] 'c-backslash-region)
             (local-set-key [(control home)] 'c-beginning-of-defun)
             (local-set-key [(control end)] 'c-end-of-defun)
             (local-set-key [?\C-x ?\C-a] 'c-mark-function)
             ;; Change face of #if0..#endif to comment face.
             (font-lock-add-keywords
              nil
              '((--c-mode-font-lock-if0 (0 font-lock-comment-face prepend))) 'add-to-end)
             )
          t)

;; In the implementation of user-defined strings literals the delimiter tags are
;; marked up separately as `font-lock-keyword-face'; another option would be
;; `font-lock-constant-face'. This implementation is not as efficient as it good
;; be; but it works and does not slow down Emacs. If you like to fontify the
;; whole literal string as `font-lock-string-face' - including the delimiters -
;; replace the three regexp by one:
;;
;;     ("\\([uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(.*?)[^\\s-\\\\()]\\{0,16\\}\"\\)" 1 font-lock-string-face t)
;;
;; http://stackoverflow.com/questions/8549351/c11-mode-or-settings-for-emacs/12934513#12934513

(add-hook
 'c++-mode-hook
 '(lambda()
    ;; We could place some regexes into `c-mode-common-hook', but note that their evaluation order matters.
    (font-lock-add-keywords
     nil '(;; complete some fundamental keywords
           ("\\<\\(void\\|unsigned\\|signed\\|char\\|short\\|bool\\|int\\|long\\|float\\|double\\)\\>" . font-lock-keyword-face)
           ;; namespace names and tags - these are rendered as constants by cc-mode
           ("\\<\\(\\w+::\\)" . font-lock-function-name-face)
           ;; new C++11 keywords
           ("\\<\\(alignof\\|alignas\\|constexpr\\|decltype\\|noexcept\\|nullptr\\|static_assert\\|thread_local\\|override\\|final\\)\\>" . font-lock-keyword-face)
           ("\\<\\(char16_t\\|char32_t\\)\\>" . font-lock-keyword-face)
           ;; PREPROCESSOR_CONSTANT, PREPROCESSORCONSTANT
           ("\\<[A-Z]*_[A-Z_]+\\>" . font-lock-constant-face)
           ("\\<[A-Z]\\{2,\\}\\>"  . font-lock-constant-face)
           ;; hexadecimal numbers
           ("\\<0[xX][0-9A-Fa-f]+\\>" . font-lock-constant-face)
           ;; integer/float/scientific numbers
           ("\\<[\\-+]*[0-9]*\\.?[0-9]+\\([ulUL]+\\|[eE][\\-+]?[0-9]+\\)?\\>" . font-lock-constant-face)
           ;; c++11 string literals
           ;;       L"wide string"
           ;;       L"wide string with UNICODE codepoint: \u2018"
           ;;       u8"UTF-8 string", u"UTF-16 string", U"UTF-32 string"
           ("\\<\\([LuU8]+\\)\".*?\"" 1 font-lock-keyword-face)
           ;;       R"(user-defined literal)"
           ;;       R"( a "quot'd" string )"
           ;;       R"delimiter(The String Data" )delimiter"
           ;;       R"delimiter((a-z))delimiter" is equivalent to "(a-z)"
           ("\\(\\<[uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(\\)" 1 font-lock-keyword-face t) ; start delimiter
           (   "\\<[uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(\\(.*?\\))[^\\s-\\\\()]\\{0,16\\}\"" 1 font-lock-string-face t)  ; actual string
           (   "\\<[uU8]*R\"[^\\s-\\\\()]\\{0,16\\}(.*?\\()[^\\s-\\\\()]\\{0,16\\}\"\\)" 1 font-lock-keyword-face t) ; end delimiter
           ;; user-defined types (rather project-specific)
           ("\\<[A-Za-z_]+[A-Za-z_0-9]*_\\(type\\|ptr\\)\\>" . font-lock-type-face)
           ("\\<\\(xstring\\|xchar\\)\\>" . font-lock-type-face)
           ))
    ) t)

(add-hook 'java-mode-hook
          '(lambda()
             (setq c-comment-start-regexp "\\(@\\|/\\(/\\|[*][*]?\\)\\)")) t)

(define-derived-mode nonelectric-c-mode c-mode "Nonelectric-C"
  "Enable C-mode with all electricity turned off. Useful for C-like files."
  (setq left-margin 8 fill-column 80)
  ;;(c-toggle-auto-newline nil)
  ;;(c-toggle-hungry-state nil)
  (c-toggle-electric-state 0))

;;;; Sh, Bash, AHK, Perl, Python

;; See also the micro-docs `cperl-tips-faces', `cperl-problems', `list-colors-display'.

(autoload 'ahk-mode "ahk-mode" "AutoHotkey mode" t)
(autoload 'python-mode "python" "Python programming language mode" t)

(defalias 'perl-mode 'cperl-mode)
(eval-after-load "cperl-mode"
  '(progn
     (font-lock-add-keywords
      'cperl-mode
      '(("\\<\\(map\\|split\\|exists\\|basename\\|defined\\|undef\\|scalar\\|delete\\|print\\|push\\|pop\\|keys\\|values\\|shift\\|unshift\\|qw\\|qq\\|confess\\|croak\\|length\\|reverse\\|sort\\)[^A-Za-z0-9_]+" .
         font-lock-keyword-face))))
  )

(add-hook 'cperl-mode-hook
          (lambda()
            (--tune-CUA-mode)
            (--wap-markup-enable "I<" ">" "C<" ">")
            (which-function-mode)
            (setq case-fold-search nil)
            (setq cperl-font-lock t
                  cperl-hairy nil
                  ;;cperl-syntaxify-by-font-lock nil
                  cperl-comment-columns 72
                  cperl-indent-level 4
                  cperl-continued-statement-offset 0
                  cperl-label-offset 0
                  cperl-min-label-indent 4
                  ;; Electric braces, colons, semicolons.
                  cperl-auto-newline-after-colon nil
                  cperl-auto-newline nil
                  cperl-extra-newline-before-brace nil
                  cperl-extra-newline-before-brace-multiline nil
                  cperl-electric-parens nil
                  cperl-electric-linefeed nil
                  ;; Syntax formatting.
                  cperl-fix-hanging-brace-when-indent t
                  cperl-break-one-line-blocks-when-indent nil
                  cperl-merge-trailing-else t
                  cperl-indent-left-aligned-comments nil)

            (local-set-key [?\C-x ?\C-a] 'c-mark-function)

            ;; Outline minor mode and `outline-level' function.

            (--enable-outline-minor-mode
             (join-shy-re (join-re "#!.+" "package\\b" "__DATA__" "__END__")
                     (join-re "=head[1-2]\\b") ; \1
                     (join-re "=head[3-4]\\b") ; \2
                     (join-shy-re "=item\\b")       ; \3
                     ;;(join-shy-re "=item\\b" "sub\\b" "BEGIN\\b" "INIT\\b") ; \3
                     ;;(join-shy-re "use vars\\b" "if ([01])" "for\\b" "foreach\\b" "while\\b") ; \4
                     ;;(join-shy-re "if\\b" "unless\\b" "open\\b") ; \5
                     ))
            (--enable-outline-minor-mode-bindings)
            (setq outline-level '(lambda ()
                                   (save-excursion
                                     (let ((case-fold-search nil))
                                       (if (looking-at outline-regexp)
                                           ;; Else parse the `outline-regexp'.
                                           (cond ((match-beginning 1) 1)
                                                 ((match-beginning 2) 2)
                                                 ((match-beginning 3) 3)
                                                 ((match-beginning 4) 4)
                                                 ((match-beginning 5) 5) (t 6))
                                         ;; Return 0 for "before first heading".
                                         (if (bobp) 0 1000))))))
            )
          1)

(add-hook 'python-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (which-function-mode)
             ;; Place or move comment when '#' is pressed.
             (if my-indent-for-comment
                 (local-set-key (vector ?\#) '--indent-for-comment))
             ))

(add-hook 'sh-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (which-function-mode)
             (local-set-key [?\C-c ?\\] 'sh-backslash-region)
             (if my-indent-for-comment
                 (local-set-key (vector ?\#) '--indent-for-comment)) ; place or move comment when '#' is pressed
             (setq sh-indent-comment t)
             ))

;;;; LUA
;;

(autoload 'lua-mode "lua-mode" "Lua editing mode." t)
(add-to-list 'auto-mode-alist '("\\.tdef$" . lua-mode))
(add-to-list 'auto-mode-alist '("\\.tmod$" . lua-mode))
(add-to-list 'auto-mode-alist '("\\.lua$" . lua-mode))
(add-to-list 'interpreter-mode-alist '("lua" . lua-mode))

(add-hook 'lua-mode-hook
          (lambda()
            (--tune-CUA-mode)
            (--wap-markup-enable "--[[" "]]" "assert(" ")")
            (which-function-mode)
            (setq case-fold-search nil)
            (set-fill-column 80)
            (setq lua-indent-level tab-width)
            )
          1)

;;;; Windows-Batch, Powershell, Visual Basic
;;
;; Refine `bat-generic-mode' from <generic-x.el> for more keywords as
;; `cmd-generic-mode'. Code has been copied straight from <generic-x.el>, then
;; modified. Note C-c C-c still runs `bat-generic-mode-compile'.

(autoload 'visual-basic-mode "visual-basic-mode"
  "Visual Basic programming language mode" t)

(add-hook 'cmd-generic-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (setq tab-width 8 tab-stop-list (--tab-stop-list 1))
             (local-set-key [(tab)] 'tab-to-tab-stop))
          )

(define-generic-mode cmd-generic-mode
  nil nil
  (eval-when-compile
    (list
     ;; Make this one first in the list, otherwise comments will be
     ;; over-written by other variables
     '("^[@ \t]*\\([rR][eE][mM][^\n\r]*\\)" 1 font-lock-comment-face t)
     '("[ \t]+\\(&[rR][eE][mM][^\n\r]*\\)"  1 font-lock-comment-face t)
     '("^[ \t]*\\(::.*\\)"                  1 font-lock-comment-face t)
     '("[ \t]+\\(::.*\\)"                   1 font-lock-comment-face t)
     '("^[@ \t]*\\([bB][rR][eE][aA][kK]\\|[vV][eE][rR][iI][fF][yY]\\)[ \t]+\\([oO]\\([nN]\\|[fF][fF]\\)\\)"
       (1 font-lock-builtin-face)
       (2 font-lock-constant-face t t))
     ;; Any text (except ON/OFF) following ECHO or ECHO. is a string.
     '("^[@ \t]*\\([eE][cC][hH][oO]\\.?\\)[ \t]+\\(\\([oO]\\([nN]\\|[fF][fF]\\)\\)\\|\\([^>|\r\n]+\\)\\)"
       (1 font-lock-builtin-face)
       (3 font-lock-constant-face t t)
       (5 font-lock-string-face t t))
     ;; These keywords appear as the first word on a line. (Actually, they can
     ;; also appear after "if ..." or "for ..." clause, but since they are
     ;; frequently used in simple text, we punt.)
     ;;
     ;; In `generic-bat-mode-setup-function' we make the keywords case-insensitive
     (generic-make-keywords-list
      '("exit" "for" "if" "setlocal" "endlocal" "mode" "set" "chcp" "color")
      font-lock-keyword-face "^[@ \t]*")
     ;; These keywords can be anywhere on a line.
     (generic-make-keywords-list
      '("do" "eq" "exist" "else" "errorlevel" "goto" "set" "in" "neq" "not"
        "use" "con" "enableextensions" "enabledelayedexpansion")
      font-lock-keyword-face)
     ;; These are built-in DOS/Windows commands or external commands frequently
     ;; used in batch files.
     (generic-make-keywords-list
      '("call" "cd" "choice" "cls" "copy" "date" "del" "dir" "echo" "find"
        "md" "net" "notepad" "path" "pause" "ping" "pushd" "popd" "prompt"
        "rd" "ren" "start" "shift" "subst" "title" "type" "ver" "vol" "xcopy")
      font-lock-builtin-face "[ \t|\n]")
     ;; Labels, pipes.
     '("^[ \t]*\\(:\\sw+\\)"         1 font-lock-function-name-face t)
     '("\\(>[A-Za-z ]+\\)"           1 font-lock-function-name-face t)
     ;; Variables.
     '("\\(!\\sw+!\\)"               1 font-lock-variable-name-face t)
     '("\\(%\\sw+%\\)"               1 font-lock-variable-name-face t)
     '("\\(%%\\sw+\\)"               1 font-lock-variable-name-face t)
     '("\\(%[0-9]\\)"                1 font-lock-variable-name-face t)
     '("[\t ]+\\([+-/][^\t\n\" ]+\\)" 1 font-lock-type-face)
     '("[ \t\n|]\\<\\([gG][oO][tT][oO]\\)\\>[ \t]*\\(\\sw+\\)?"
       (1 font-lock-keyword-face)
       (2 font-lock-function-name-face nil t))
     '("[ \t\n|]\\<\\([sS][eE][tT]\\)\\>[ \t]*\\(\\sw+\\)?[ \t]*=?"
       (1 font-lock-builtin-face)
       (2 font-lock-variable-name-face t t))))
  '("\\.[bB][aA][tT]\\'"
    "\\.[cC][mM][dD]\\'"
    "\\`[cC][oO][nN][fF][iI][gG]\\."
    "\\`[aA][uU][tT][oO][eE][xX][eE][cC]\\.")
  '(generic-bat-mode-setup-function)
  "Revisited generic mode for MS-Windows batch files.  Replaces `bat-generic-mode'."
  )

(autoload 'powershell "powershell"
  "Start powershell within Emacs with M-x \\[powershell].
Continue to use the regular Windows shell within emacs via M-x \\[shell]. " t)

(autoload 'powershell-mode "powershell-mode") ; editing mode
;; (add-to-list 'auto-mode-alist '("\\.ps1" . powershell-mode))
(add-hook 'powershell-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             ;; M-q is not working, as `fill-comment-paragraph' adds blanks into the fill-prefix.
             ;; By commenting out the line
             ;;     (set (make-local-variable 'comment-start-skip) "#+\\s*")
             ;; in powershell-mode.el it works.
             ))

(add-hook 'visual-basic-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (setq visual-basic-capitalize-keywords-p t
                   visual-basic-wildcards "*.frm *.bas *.cls *.rws *.vbs *.dsm")))

;;;; Lisp
;;

(add-hook 'emacs-lisp-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (which-function-mode)
             (--wap-markup-enable "`" "'" "\"" "\"")
             (global-set-key [?\C-x ?\C-e] 'eval-region)
             (global-set-key [?\C-x ?\M-e] 'eval-defun)
             (when --emacs22p (setq emacs-lisp-docstring-fill-column nil))
             ;; Define outline regex with a prefix of ';;;' (the lowest sublevel is 3).
             (--enable-outline-minor-mode "\\(;;;+\\|(defun\\)")
             (--enable-outline-minor-mode-bindings)
             (if my-indent-for-comment
                 (local-set-key (vector ?\;) '--indent-for-comment))
             )
          )

;;;; Yacc, Byacc, Bison, Lex, Flex, JSON
;
;; [Bison and JSON](https://github.com/Wilfred/bison-mode) are autoloaded.
;;
;; [Flex mode](http://www.emacswiki.org/emacs/FlexMode)
;;
;; Byacc mode (Yacc for Perl) was written by me as a quick solution (aka hack).

(autoload 'flex-mode "flex-mode" "flex programming languages mode" t)

(add-to-list 'auto-mode-alist '("\\.lex\\'" . flex-mode))

(defun byacc-mode()
  "Enable YACC file editing with Perl action code (assumes C mode as the base)."
  (interactive)
  (setq c-font-lock-extra-types
        (append c-font-lock-extra-types
                '("__[a-z0-9_]+"        ; identifiers beginning with '__'
                  "\\$."                ; yacc vars: $$, $1, $2...
                  "^ *\\| "             ; rules separator
                  )))
  (c-mode)
  (if --emacs22p                        ; disable auto-newline on : , ; { }
      (c-toggle-auto-newline 1)
    (c-toggle-auto-state 1))
  )

;;;; Makefile, Change-Log
;;

(if --emacs22p
    (setq auto-mode-alist
          (append (list '("\\(GNU\\)?[Mm]akefile$" . makefile-gmake-mode)
                        '("\\.mak$" . makefile-gmake-mode))
                  auto-mode-alist)))

(add-hook 'makefile-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (setq indent-tabs-mode t tab-width 4)
             (setq comment-column 72)
             (local-set-key [?\C-c ?\\] 'makefile-backslash-region))
          )

(add-hook 'change-log-mode-hook
          '(lambda () ; note that the "^" is *implicit* at the beginning of the regexp
             (set (make-local-variable 'outline-regexp) "[[:digit:]]+")))

;;;; Template Mode (Perl Template Toolkit)

;; Download template-mode.el at http://www.visualco.de

(autoload 'template-mode "template-mode" "Major mode for editing Template-Toolkit files" t)
(autoload 'template-minor-mode "template-mode" "Minor mode for editing Template-Toolkit files" t)
(autoload 'outline-template-mode "template-mode" "Combines `outline-mode' (major) with `template-minor-mode'" t)
(autoload 'htmlize-buffer "htmlize" "Convert BUFFER to HTML, preserving colors and decorations" t)

;;;; Asciidoc, Markdown, Text

;; `asciidoc-mode' (download from http://www.visualco.de) runs, in that order,
;; `outline-minor-mode-hook', `text-mode-hook', `asciidoc-mode-hook'.

(add-hook 'text-mode-hook
          '(lambda()
             (turn-on-auto-fill)
             ;; Put _ into word constituent class (see "Syntax Tables" in "GNU
             ;; Emacs Lisp Reference Manual").
             (modify-syntax-entry ?_ "w")
             ;; Rebind keys for text modes. rather is for programming-modes.
             (local-set-key [(control e)] 'kill-word)
             (local-set-key [(control up)] 'backward-paragraph)
             (local-set-key [(control down)] 'forward-paragraph)
             (local-set-key [(control left)] 'backward-word)
             (local-set-key [(control right)] 'forward-word)
             (local-set-key [(control shift up)] '(lambda()(interactive)(backward-paragraph)(forward-paragraph-mark)))
             (local-set-key [(control shift down)] '(lambda()(interactive)(forward-paragraph)(backward-paragraph-mark)))
             (local-set-key [(control shift left)] '(lambda()(interactive)(mark-word -1)))
             (local-set-key [(control shift right)] 'mark-word)
             (--tune-CUA-mode)
             (if (not (eq major-mode 'org-mode))
                 (--enable-outline-minor-mode-bindings))
             )
          )

(autoload 'markdown-mode "markdown-mode"
  "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))
(add-hook 'markdown-mode-hook
          '(lambda()
             (--wap-markup-enable "*" "*" "`" "`")
             (set-fill-column 80)))

(autoload 'asciidoc-mode "asciidoc-mode" "" t)
(add-hook 'asciidoc-mode-hook
          '(lambda() (--wap-markup-enable "'" "'" "$$`" "`$$")))

;;;; Org-mode, Outline-mode, Outline-minor-mode

;; A derived mode runs all the hooks from the parent modes. `outline-mode'
;; derives from `text-mode', `org-mode' from `outline-mode'.

(eval-after-load "outline" '(require 'foldout))
(add-hook 'outline-mode-hook
          '(lambda()
             ;; (hide-body)
             ;; (outline-next-visible-heading 1)
             ))
(add-hook 'outline-minor-mode-hook '--enable-outline-minor-mode-bindings)

(defun --enable-outline-minor-mode (&optional regexp level)
  "Enable `outline-minor-mode' and set `outline-regexp' and `outline-level'.
In text files, outline mode searches for matches of `outline-regexp' and then
calls the function `outline-level' on each to determine the depth at which a
statement is nested in the outline, e.g.

    (defun outline-level () ; very simple approach
        (- (match-end 0) (match-beginning 0)))"
  (when regexp
    (outline-minor-mode t)
    (set (make-local-variable 'outline-regexp) regexp)
    ;; This function is called from a major-mode hook, so`outline-level' is
    ;; maybe `lisp-outline-level', `latex-outline-level' etc. and must be reset
    ;; because it is incompatible with the new REGEXP.
    (setq outline-level (if level level 'outline-level)))
  )

(defun --enable-outline-minor-mode-bindings ()
  "Bind the regular `outline-mode' C-c keymap.
Although this may interfere with some major mode, since the C-c @ map
established by `outline-minor-mode' is unhandy."
  ;; Bind keys `C-HOME' and `C-END'.
  (local-set-key [(control home)]
                 '(lambda() "Show previous entry."
                   (interactive)
                   (unless (or (and (not (bolp)) (outline-back-to-heading)) (outline-get-last-sibling))
                     (outline-previous-visible-heading 1))
                   (show-entry)(recenter)))
  (local-set-key [(control end)]
                 '(lambda() "Show next entry."
                    (interactive) (hide-entry)
                    (outline-next-visible-heading 1)
                    (show-entry) (recenter)))
  ;; Map the safe `C-c @' prefix of `outline-minor-mode' to `C-c' as with
  ;; `outline-mode'.
  (local-set-key [(control c)(control n)] 'outline-next-visible-heading)
  (local-set-key [(control c)(control p)] 'outline-previous-visible-heading)
  (local-set-key [(control c)(control f)] 'outline-forward-same-level)
  (local-set-key [(control c)(control b)] 'outline-backward-same-level)
  (local-set-key [(control c)(control u)] 'outline-up-heading)
  (local-set-key [(control c)(control a)] 'show-all)
  (local-set-key [(control c)(control e)] 'show-entry)
  (local-set-key [(control c)(control k)] 'show-branches)
  (local-set-key [(control c)(tab)] 'show-children)
  (local-set-key [(control c)(control s)] 'show-subtree)
  (local-set-key [(control c)(control t)] 'hide-body)
  (local-set-key [(control c)(control c)] 'hide-entry)
  (local-set-key [(control c)(control d)] 'hide-subtree)
  (local-set-key [(control c)(control q)] 'hide-sublevels)
  (local-set-key [(control c)(control o)] 'hide-other)
  (local-set-key [(control c)(control l)] 'hide-leaves)
  )

(add-to-list 'load-path (expand-file-name "~/git/org-mode/lisp"))
(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\)$" . org-mode))

(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cb" 'org-iswitchb)

(add-hook 'org-mode-hook
          '(lambda()
             (linum-mode 0)            ; large files will become uneditable slow
             (setq org-catch-invisible-edits t ; prevent inadvertently editing an invisible part of the buffer
                   org-support-shift-select  t ; make shift-cursor commands select text
                   org-export-run-in-background t
                   ;;org-export-publishing-directory "out" ; does not affect all
                   org-return-follows-link t
                   fill-column 80
                   )))

;;;; (La)TeX mode

;; `latex-mode' is the major mode for editing files of input for LaTeX, and
;; implemented in <tex-mode.el>. `LaTeX-mode' is the major AUCTeX mode for
;; editing LaTeX. `font-latex' (not part of Emacs) implements better syntax
;; coloring.

(add-hook 'latex-mode-hook
          '(lambda()
             (--tune-CUA-mode)
             (imenu-add-menubar-index)
             (make-variable-buffer-local 'time-stamp-line-limit)
             (setq time-stamp-line-limit 200)
             (if --winnt-p (setq tex-dvi-print-command "bash -c \"dvips -f *\""))
             (--wap-markup-enable"``" "''" "\\emph{" "}")
             (local-set-key [(control return)] 'latex-insert-item) ; default is M-RETURN
             (if nil
                 (--enable-outline-minor-mode
                  (join-re "\\\\subparagrap" ; 12: \subparagraph
                           "\\\\paragraph."  ; 11: \paragraph
                           "\\\\subsubsec"   ; 10: \subsubsection
                           "\\\\begin{ab"
                           "\\\\subsecti" ; 9: \subsection \begin{abstract}
                           "\\\\section"  ; 8: \section
                           "\\\\title{""\\\\docume" ; 7: \documentclass
                           ))
               (--enable-outline-minor-mode-bindings))
             (when (load "font-latex" t)
               (setq font-lock-maximum-decoration t
                     font-latex-do-multi-line nil)
               (custom-set-variables
                '(font-latex-match-reference-keywords
                  (quote                ; defaults with \footnote... removed
                   ("nocite" "cite" "label"
                    "pageref" "vref" "eqref" "ref"
                    "include" "input" "bibliography"
                    "index" "glossary"
                    "sectref" "longref"
                    "tabref" "tablongref"
                    "figref" "figlongref"))))
               (custom-set-faces
                '(font-latex-bold-face ((t (:foreground "darkslategrey" :bold t :weight bold))))
                '(font-latex-italic-face ((t (:foreground "darkslategrey" :italic t :slant italic))))
                '(font-latex-math-face ((t (:foreground "darkorange3" :background "white smoke"))))
                '(font-latex-sedate-face ((t (:foreground "mediumblue")))) ; own macros, minor keywords
                '(font-latex-string-face ((t (:foreground "violetred" :family "arial"))))
                '(font-latex-subscript-face ((t (:height 0.8))))
                '(font-latex-superscript-face ((t (:height 0.8))))
                '(font-latex-title-1-face ; section
                  ((((type tty pc) (class color)))
                   (t (:height 1.3 :inherit font-latex-title-2-face))))
                '(font-latex-title-2-face ; subsection
                  ((((type tty pc) (class color)))
                   (t (:height 1.2 :inherit font-latex-title-3-face))))
                '(font-latex-title-3-face ; subsubsection
                  ((((type tty pc) (class color)) (:weight bold))
                   (t (:height 1.1 :inherit font-latex-title-4-face))))
                '(font-latex-title-4-face ; paragraph
                  ((((type tty pc) (class color)) (:weight bold))
                   (((class color) (background light)) (:weight bold :inherit variable-pitch :foreground "blue"))
                   (((class color) (background  dark)) (:weight bold :inherit variable-pitch :foreground "yellow"))
                   (t (:weight bold :inherit variable-pitch))))
                '(font-latex-warning-face
                  ((t (:foreground "black" :background "greenyellow" :weight normal)))))
               )
             )
          )

(when (and (load "auctex.el" t)
           (load "preview-latex.el" t))
  ;; AUCTeX is an advanced mode to edit (La)TeX files which must be installed
  ;; separately.
  (message "AUCTeX found")
  (require 'tex-mik)                    ; more appropriate values for MiKTeX
  (setq TeX-default-mode 'LaTeX-mode)
  (setq-default TeX-master nil)         ; the name of the master file
  (setq TeX-quote-after-quote t         ; type " twice to get TeX-quotes
        TeX-parse-self t
        TeX-auto-save t)
  (setq auto-mode-alist (append (list '("\\.\\(tex\\|cl[so]\\)$" . LaTeX-mode)) auto-mode-alist))
  (custom-set-variables
   ;;'(LaTeX-enable-toolbar nil); turn off AUCTeX toolbar
   '(TeX-electric-sub-and-superscript t))
  (add-hook 'LaTeX-mode-hook            ; also runs `latex-mode-hook'
                '(lambda()
                   (auto-fill-mode t)
                   (outline-minor-mode t)
                   (LaTeX-math-mode)
                   (TeX-fold-mode 1)
                   (setq ispell-extra-args '("--mode=tex"))
                   (local-set-key [(shift tab)] 'TeX-complete-symbol)
                   (local-set-key [(f4)] 'TeX-next-error)
                   (local-set-key [(f5)] 'TeX-command-master) ; normally runs gdb (debug program)
                   (local-set-key [?\M-g ?g] 'TeX-normal-mode)

                   ;; From version 11.82 on, handling of verbatim constructs
                   ;; was consolidated across AUCTeX. This resulted in the
                   ;; font-latex-specific variables
                   ;; `font-latex-verb-like-commands',
                   ;; `font-latex-verbatim-macros', and
                   ;; `font-latex-verbatim-environments' being removed and the
                   ;; more general variables
                   ;; `LaTeX-verbatim-macros-with-delims',
                   ;; `LaTeX-verbatim-macros-with-braces', and
                   ;; `LaTeX-verbatim-environments' being added.

                   (setq LaTeX-verbatim-macros-with-braces (list "code")
                         LaTeX-verbatim-environments (list "verbatim" "clang" "Clang" "Shlang" "Rlistlang"))
                   )
                )
  )

;;;; Picture-mode
;;

(add-hook 'picture-mode-hook
          (lambda()
            (local-set-key [(meta backspace)] 'undo)))

;;;; HTML mode

(add-hook 'html-mode-hook
          '(lambda()
             (turn-off-auto-fill)))

;;; -------- LOAD DESKTOP
;;; ----------------------------------------------------------------------------

;; For Emacssen 22.1+ `desktop-read' is implicitly added to the
;; `after-init-hook', and unless `desktop-save-mode' is nil it'll loads the
;; desktop from a file named by `desktop-base-file-name', in directories listed
;; by `desktop-path'.
;;
;; Which desktops are loaded are defined by `desktop-path'.  Default value:
;;     ("." "~/.emacs.d/" "~")
;; To limit to the current directory use:
;;     desktop-path (list ".")

(unless (or --no-desktop (not --emacs22p))
  (require 'desktop)
  (desktop-save-mode t)
  (setq desktop-save 'if-exists
        desktop-load-locked-desktop t
        desktop-path (list ".")
        desktop-buffers-not-to-save (concat "\\("
                                            "^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS"
                                            "\\|\\.emacs.*"
                                            "\\)$")
        desktop-globals-to-save '(desktop-globals-to-save
                                  file-name-history
                                  shell-command-history
                                  compile-command compile-all-command
                                  regexp-history
                                  )
        desktop-locals-to-save '(desktop-locals-to-save
                                 truncate-lines fill-column tab-width
                                 case-fold-search
                                 change-log-default-name
                                 line-number-mode column-number-mode size-indication-mode
                                 indicate-buffer-boundaries
                                 ))
  (add-to-list 'desktop-modes-not-to-save 'dired-mode)
  (add-to-list 'desktop-modes-not-to-save 'Info-mode)
  (add-to-list 'desktop-modes-not-to-save 'info-lookup-mode)
  (add-to-list 'desktop-modes-not-to-save 'fundamental-mode)
  (if --emacs24p
      (setq desktop-auto-save-timeout nil))
  (add-hook 'desktop-save-hook
            '(lambda()
               (when (featurep 'compile)
                 (desktop-truncate compile-history 6)
                 (desktop-truncate grep-history 6))
               (desktop-truncate minibuffer-history 20)
               (desktop-truncate file-name-history 20)
               (desktop-truncate search-ring 10)
               (desktop-truncate regexp-search-ring 10))
            ))

;;; -------- START EMACS SERVER
;;; ----------------------------------------------------------------------------
;;
;; When some instance of GNU Emacs plays the role of the server we can use the
;; emacsclient program.
;;
;; http://stackoverflow.com/questions/885793/emacs-error-when-calling-server-start/7009934#7009934

(unless (or --batch-mode)
  (require 'server)
  (when (and --emacs23p (= emacs-major-version 23)
             (= emacs-minor-version 1)
             (equal window-system 'w32))
    ;; Windows: suppress error "directory ~/.emacs.d/server is unsafe"
    (defun server-ensure-safe-dir (dir) "Noop" t))
  (condition-case nil
      (server-start)
    (error
     (message "Catched exception from `server-start'")
     (let* ((server-dir
             (if server-use-tcp server-auth-dir server-socket-dir)))
       (when (and server-use-tcp
                  (not (file-accessible-directory-p server-dir)))
         (display-warning
          'server "Unable to start the Emacs server: server-directory not accessible." :warning)
         (display-warning
          'server (format "Creating %S" server-dir) :warning)
         (make-directory server-dir t)
         (server-start))))
    ))

;;; -------- AFTER-INIT
;;; ----------------------------------------------------------------------------

;; This code is directly run after <~/.emacs.el> and <default.el> (`add-hook' by
;; default pushes to front of the list). At this point the desktop hasn't been
;; loaded. We load <~/.emacs.local> and <./.emacs.local>. These files are
;; "private" companions to some "~/.emacs".

(defun --eval-file-of-lisp (elfile)
  (setq elfile (--expand-variables elfile))
  (if (safe-file-exists-p elfile)
      (progn
        (let ((ff-quiet-mode nil))
          (condition-case nil
              (progn (load-file elfile))
            (error "Evaluating <%s>: load error!" elfile))))
    (message "<%s> not found" elfile)))

(unless --batch-mode
  (add-hook 'after-init-hook
            '(lambda()
               (menu-bar-mode 0)
               (tool-bar-mode 0)
               (let ((ff-quiet-mode t) (startdir (--startup-directory)))
                 (message "After-init: startup directory <%s>" startdir)
                 (let ((globaldirs (list "$HOME"))
                       (localdirs (list startdir
                                        (concat startdir "/..")
                                        (concat startdir "/res")
                                        (concat startdir "/mk"))))
                   ;; Set frame title and icon.
                   (when --winnt-p
                     (setq --makefile-icon
                           (or (--ff-existing-pathname "makefile.ico" localdirs)
                               (--ff-existing-pathname "_makefile.ico" localdirs)
                               (--ff-existing-pathname "favicon.ico" localdirs)
                               ))
                     (let ((found (mapcar
                                   (lambda (cons)
                                     (--ff-existing-pathname cons (append localdirs globaldirs)))
                                   (list "build.ico" "shell.ico"))))
                       (setq --compile-icon (nth 0 found)
                             --shell-icon (nth 1 found)))
                     )
                   (when (featurep 'frame-utils)
                     (fru-set-frame-icon (if --winnt-p --makefile-icon) nil
                                         (concat (if (<= (length startdir) 50) startdir
                                                   (concat "..." (substring startdir (-(length startdir) 12))))
                                                 " -- " frame-title-format
                                                 (if (daemonp) "--- server"))))
                   ;; Evaluate .emacs.local
                   (--eval-file-of-lisp "~/.emacs.local")
                   (--eval-file-of-lisp (concat startdir "/.emacs.local"))
                   )
                 t)
               )))

(add-hook 'after-init-hook
          '(lambda()
             (message (format "%s | %fs" (--startup-buffer)
                              (- (float-time (current-time)) --startup-time)))
             t) t)

;;; -------- KILLING EMACS
;;; ----------------------------------------------------------------------------

(add-hook 'write-file-hooks
          '(lambda()              ; WARNING: must return nil or Emacs won't exit
             (unless (or (eq major-mode 'makefile-mode)
                         (eq major-mode 'makefile-gmake-mode)
                         (eq major-mode 'makefile-automake-mode))
               (copyright-update))
             (time-stamp)))

;;; -------- AUTO-INSERT, SKELETONS AND ABBREVS
;;; ----------------------------------------------------------------------------

(define-auto-insert
  (cons "\\.\\(org\\)\\'" "Org text")
  '("Title: "
    "# -*-mode:org; fill-column:80; coding:utf-8-unix-*-\n"
    "#\n"
    "# " (file-name-nondirectory buffer-file-name) "\n"
    "#\n"
    "# $Companion: " "$\n"
    "# $Writestamp: $\n"
    "\n"
    "#+TITLE:    " str "\n"
    "#+AUTHOR:   " user-full-name "\n"
    "#+EMAIL:    " user-mail-address "\n"
    "#+OPTIONS:  H:6\n"
    "#+OPTIONS:  toc:4\n"
    "#+LANGUAGE: de\n"
    "\n"
    "### EOF\n"))

(define-auto-insert
  (cons "\\(\\.\\(txt\\|text\\|asciidoc\\)\\|README\\)\\'" "AsciiDoc")
  '("Title: "
    "// -*-mode:asciidoc; coding:utf-8; fill-column:80-*-\n"
    "//\n"
    "// " (file-name-nondirectory buffer-file-name) " --- " str "\n"
    "//\n"
    "// Copyright (C) " (format-time-string "%Y") " " (getenv "USERNAME") "\n"
    "//\n"
    "// $Compile: asciidoctool --start --html  " (file-name-nondirectory buffer-file-name) "$\n"
    "// $Clean:   asciidoctool --clean --clean " (file-name-nondirectory buffer-file-name) "$\n"
    "// $Writestamp: $\n"
    "\n\n" str "\n"
    (make-string (length str) ?=) "\n"
    (getenv "USERNAME") "\n"
    "Version 1.0, " (format-time-string "%B %Y") "\n"
    "\n"
    ":data-uri:\n"
    ":numbered!:\n"
    "\n"
    "PREAMBLE. End of preamble.\n"
    "\n"
    "== First section\n"
    "\nLorem\n\n"
    ":numbered!:\n"
    "== Bibliography\n\n"
    "[bibliography]\n"
    "- [[[Shortname]]] Author. 'Title'. Publisher. ISBN isbn.\n"
    "\n\n"
    "// " (file-name-nondirectory buffer-file-name) "\n"
    "// EOF"
    '(normal-mode)
    )
  )

(define-auto-insert
  (cons "\\.\\(sh\\)\\'" "Shell script")
  '(nil
    "#!bash\n"
    "#\n"
    "# " (file-name-nondirectory buffer-file-name) "\n"
    "#\n" "#\n" "#\n"
    "########\n"
    "# $Author: " user-full-name " <" user-mail-address ">$\n"
    "# $Companion: $\n"
    "# $Writestamp: $\n"
    "#\n\n"
    "\n"
    "\n"
    "### Local Variables:\n"
    "### fill-column: 80\n"
    "### buffer-file-coding-system: utf-8-unix\n"
    "### End:\n"))

(define-auto-insert
  (cons "\\.\\([Hh]\\)\\'" "C/C++ header")
  '(nil
        "/* -*-coding:utf-8-unix-*-\n"
        " *\n"
        " * " (file-name-nondirectory buffer-file-name) "\n"
        " *\n" " *\n" " *\n"
        " ********\n"
        " * $Author: " (user-full-name) " <" user-mail-address ">$\n"
        " * $Companion: $\n"
        " * $Writestamp: $\n"
        " */\n"
        (let* ((noext (substring buffer-file-name 0 (match-beginning 0)))
           (nopath (file-name-nondirectory noext))
           (ident (concat "__" (upcase nopath) "_H")))
          (concat "#ifndef " ident "\n"
                  "#define " ident  "\n\n\n\n"
                  "\n\n#endif /* " ident " */\n"))))

(define-auto-insert
  (cons "\\.\\(cpp\\|C\\|cxx\\|ixx\\)\\'" "C/C++ module")
  '(nil
        "/* -*-coding:utf-8-unix-*-\n"
        " *\n"
        " * " (file-name-nondirectory buffer-file-name) "\n"
        " *\n"
        " ********\n"
        " * $Author: " (user-full-name) " <" user-mail-address ">$\n"
        " * $Compile: g++ -std=c++0x -lm " (file-name-nondirectory buffer-file-name) " && ./a && rm a.*$\n"
        " * $Writestamp: $\n"
        " */\n"
        "\n"
        "#include <cassert>\n"
        "#include <iostream>\n"
        "#include <sstream>\n"
        "#include <stdexcept>\n"
        "#include <algorithm>\n"
        "#include <functional>\n"
        "\n"
        "using namespace std;\n"
        "\n"
        "int main(int argc, char *argv[])\n"
        "{\n"
        "\ttry {\n"
        "\t} catch (const std::exception &ex) {\n"
        "\t\tcout << \"catched \" << ex.what() << endl;\n"
        "\t}\n"
        "\n\tcout << __FILE__ << \": ok\";\n\n"
        "\treturn 0;\n"
        "}\n"
        ))

(define-auto-insert
  (cons "\\.\\([Pp][Ll]\\)\\'" "Perl script")
  '(nil
        "#!/usr/bin/perl\n"
        "#\n"
        "# " (file-name-nondirectory buffer-file-name) "\n"
        "#\n" "#\n" "#\n"
        "########\n"
        "# $Author: " (user-full-name) " <" user-mail-address ">$\n"
        "# $Companion: $\n"
        "# $Compile: perl -w -e '' " (file-name-nondirectory buffer-file-name) "$\n"
        "# $Writestamp: $\n"
        "#\n\n"
        "use Carp;\n"
        "use strict;\n"
        "\n"
        "use vars qw/ $VERSION /;\n"
        "\n"
        "BEGIN {\n"
        "\t$VERSION = '0.1';\n"
        "}\n\n\n1;\n\n"
        "### Local Variables:\n"
        "### mode: cperl\n"
        "### fill-column: 80\n"
        "### buffer-file-coding-system: utf-8-unix\n"
        "### End:\n"))

(define-auto-insert
  (cons "\\.\\(sh\\)\\'" "Shell script")
  '(nil
        "#!bash\n"
        "#\n"
        "# " (file-name-nondirectory buffer-file-name) "\n"
        "#\n" "#\n" "#\n"
        "########\n"
        "# $Author: " (user-full-name) " <" user-mail-address ">$\n"
        "# $Companion: $\n"
        "# $Writestamp: $\n"
        "#\n\n"
        "\n"
        "\n"
        "### Local Variables:\n"
        "### fill-column: 80\n"
        "### buffer-file-coding-system: utf-8-unix\n"
        "### End:\n"))

(define-auto-insert
  (cons "\\.\\(pm\\)\\'" "Perl Module")
  '(nil
        "#!/usr/bin/perl\n"
        "#\n"
        "# " (file-name-nondirectory buffer-file-name) "\n"
        "#\n" "#\n" "#\n"
        "########\n"
        "# $Author: " (user-full-name) " <" user-mail-address ">$\n"
        "# $Companion: $\n"
        "# $Compile: perl -M" (file-name-sans-extension buffer-file-name) " -w -e ''$\n"
        "# $Writestamp: $\n"
        "#\n\n"
        "use Carp;\n"
        "use strict;\n"
        "use Exporter;\n"
        "\n"
        "use vars qw/ $VERSION @ISA @EXPORT /;\n"
        "\n"
        "BEGIN {\n"
        "\t$VERSION = '0.1';\n"
        "\t@ISA = qw/ Exporter /;\n"
        "\t@EXPORT = qw/ /;\n"
        "}\n\n\n1;\n\n"
        "### Local Variables:\n"
        "### mode: cperl\n"
        "### fill-column: 80\n"
        "### buffer-file-coding-system: utf-8-unix\n"
        "### End:\n"
        '(normal-mode)
        )
  )

(define-auto-insert
  (cons "\\.emacs\\.local\\'" "Local Emacs customization file")
  '(nil
    ";; -*-mode:emacs-lisp; fill-column:80; coding:utf-8-unix-*-\n"
    ";;\n"
    ";; " (file-name-nondirectory buffer-file-name) " -- " (file-name-directory (buffer-file-name (--startup-buffer))) "\n"
    ";;\n"
    ";; $Companion: " (file-name-nondirectory (buffer-file-name (--startup-buffer))) "$\n\n"
    ";; $Writestamp: $\n"
    '(normal-mode)
    )
  )

;;;; Code sekeletons (Abbrevations)
;;
;; Inserted when a keyword is typed (the prefix token). Tokens have to be
;; prepended by a special character. Abbrevs are also expanded in comments, and
;; are case-insensitive. A ";" prefix would be desirable (";class", ";if"etc.)
;; because normally a whitespace character is required after ";" in any text.
;; Alas, due to the "electricity" of some modes, this prefix cannot be choosen.
;; "y" seems to be a good compromise, because you rarely type "yif", "ytry" and
;; "yclass" etc.
;;
;; When the minor `abbrev-mode'is enabled skeletons are automatically pasted
;; when the token is typed. Or mark some text and call skeleton as a function.

(define-skeleton sk-try-catch "" nil
  > "try {" \n
  > _
  \n "} catch (...) {" >
  \n "throw;"
  \n "}" >)

(define-skeleton sk-ife "" nil
  > "if (" _ ") {" \n
  > \n
  "} else {" > \n
  "}" >\n)

(define-skeleton sk-class "" nil              ; full-featured class
  "class " (setq v1 (skeleton-read "Identifier? ")) > \n
  "{" > \n
  "/*** EXPORTED TYPES ***/" > \n
  "// friends and typedefs" > \n \n
  "/*** CONSTRUCTION ***/" > \n
  "public:" > \n
  v1 "() {}" > \n
  "virtual ~" v1 "() {}" > \n \n
  "/*** INTERFACE ***/" > \n
  "public:" > \n \n
  "/*** IMPLEMENTATION ***/" > \n
  "protected:" > \n \n
  "/*** ATTRIBUTES ***/" > \n
  "private:" > \n
  "};" > \n)

(define-skeleton sk-safe-bool "" nil  ; to be placed in the INTERFACE section of a class
  >
  "/**" > \n
  " * @short Test objects of this class." > \n
  " *" > \n
  " * Test validation of an object." > \n
  " *" > \n
  " * The technique used here is called the \"Safe Bool Idiom\". It does the" > \n
  " * trick of testing an object without `bool operator!' or `operator void*'." > \n
  " * For details see <http://www.artima.com/cppsource/safebool.html>." > \n
  " * " > \n
  " * Note that because this object is \"testable\", it can not have the cast" > \n
  " * operator" > \n
  " *" > \n
  " *operator const pointer() const throw()" > \n
  " *" > \n
  " */" > \n
  "private:" > \n
  "void this_type_does_not_support_this_comparison() const { }" > \n
  "typedef void (self::*bool_type)() const;" > \n
  "public:" > \n
  "bool null() const { return p==0; }" > \n
  "bool operator!() const { return null(); }" > \n
  "operator bool_type() const {" > \n
  "return !null() ? &self::this_type_does_not_support_this_comparison : 0;" > \n
  "}" > \n
  "/***/" > \n \n)

;;;; Abbrevations
;;
;; Inserted when a keyword is typed (the prefix token). Tokens have to be
;; prepended by a special character. Abbrevs are also expanded in comments, and
;; are case-insensitive. A ";" prefix would be desirable (";class", ";if"etc.)
;; because normally a whitespace character is required after ";" in any text.
;; Alas, due to the "electricity" of some modes, this prefix cannot be choosen.
;; "y" seems to be a good compromise, because you rarely type "yif", "ytry" and
;; "yclass" etc.
;;
;; When the minor `abbrev-mode'is enabled skeletons are automatically pasted
;; when the token is typed. Or mark some text and call skeleton as a function.

(eval-after-load "cc-mode"
  '(progn
     (unless c++-mode-abbrev-table
       (define-abbrev-table 'c++-mode-abbrev-table ()))
     (define-abbrev c++-mode-abbrev-table "ytry" "" 'sk-try-catch)
     (define-abbrev c++-mode-abbrev-table "yif" "" 'sk-ife)
     (define-abbrev c++-mode-abbrev-table "yclass" "" 'sk-class)
     (define-abbrev c++-mode-abbrev-table "ybool" "" 'sk-safe-bool)
     ))

(eval-after-load "cperl-mode"
  '(progn
     (unless cperl-mode-abbrev-table
       (define-abbrev-table 'cperl-mode-abbrev-table ()))
     (define-abbrev cperl-mode-abbrev-table "yif" "" 'sk-ife)
     ))

;; .emacs.el ends here
(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(safe-local-variable-values
   (quote
    ((eval hide-sublevels 9)
     (minor-mode . auto-revert)
     (buffer-file-coding-system . utf-8-unix)
     (buffer-file-coding-system . utf-8-auto)
     (buffer-file-coding-system . utf-8)))))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(cperl-array-face ((((class color) (background dark)) (:italic t :foreground "NavajoWhite")) (((class color) (background light)) (:italic t :foreground "darkslateblue"))))
 '(cperl-hash-face ((((class color) (background dark)) (:italic t :foreground "LightGoldenrod")) (((class color) (background light)) (:italic t :foreground "darkslateblue"))))
 '(escape-glyph ((((class color) (background dark)) (:bold t)) (((class color) (background light)) (:bold t :foreground "OrangeRed"))))
 '(fixed-pitch ((((class color) (background dark)) (:bold t :foreground "black") ((class color) (background light)) (:bold t :foreground "dimgrey"))))
 '(flyspell-duplicate ((((class color) (background dark)) (:underline t)) (((class color) (background light)) (:underline t))))
 '(flyspell-incorrect ((((class color) (background dark)) (:underline t)) (((class color) (background light)) (:underline t))))
 '(font-lock-builtin-face ((((class color) (background dark)) (:foreground "gray70")) (((class color) (background light)) (:bold t :foreground "blue4"))))
 '(font-lock-comment-face ((((class color) (background dark)) (:foreground "OliveDrab2")) (((class color) (background light)) (:foreground "Forestgreen"))))
 '(font-lock-constant-face ((((class color) (background dark)) (:foreground "Orange1")) (((class color) (background light)) (:foreground "DarkRed"))))
 '(font-lock-doc-face ((((class color) (background dark)) (:foreground "Chartreuse3" :width condensed)) (((class color) (background light)) (:underline t :foreground "Chartreuse2" :width condensed))))
 '(font-lock-function-name-face ((((class color) (background dark)) (:italic t :foreground "FloralWhite")) (((class color) (background light)) (:foreground "mediumblue"))))
 '(font-lock-keyword-face ((((class color) (background dark)) (:bold t :foreground "LightGoldenrod")) (((class color) (background light)) (:bold t :foreground "blue3"))))
 '(font-lock-label-face ((((class color) (background dark)) (:italic t :foreground "LightGoldenrod")) (((class color) (background light)) (:italic t :foreground "blue3"))))
 '(font-lock-preprocessor-face ((((class color) (background dark)) (:bold t :foreground "NavajoWhite4")) (((class color) (background light)) (:bold t :foreground "blue3"))))
 '(font-lock-string-face ((((class color) (background dark)) (:foreground "Coral")) (((class color) (background light)) (:foreground "PaleVioletRed"))))
 '(font-lock-type-face ((((class color) (background dark)) (:foreground "LightGoldenrod")) (((class color) (background light)) (:foreground "mediumblue"))))
 '(font-lock-variable-name-face ((((class color) (background dark)) (:foreground "LightGoldenrod")) (((class color) (background light)) (:foreground "darkslateblue"))))
 '(font-lock-warning-face ((((class color) (background dark)) (:bold t :italic t :underline t :foreground "OliveDrab1")) (((class color) (background light)) (:bold t :italic t :underline t :foreground "Darkred"))))
 '(hl-line ((((class color) (background dark)) (:background "black")) (((class color) (background light)) (:background "gray92"))))
 '(isearch ((((class color) (background dark)) (:foreground "black" :background "yellow2" :bold t :italic nil)) (((class color) (background light)) (:foreground "black" :background "yellow" :bold t :italic nil))))
 '(isearch-fail ((((class color) (background dark)) (:foreground "black" :background "OrangeRed1" :bold t :italic nil)) (((class color) (background light)) (:foreground "black" :background "OrangeRed1" :bold t :italic nil))))
 '(lazy-highlight-face ((((class color) (background dark)) (:foreground "black" :background "yellow2")) (((class color) (background light)) (:bold t :foreground "black" :background "lemonchiffon"))))
 '(linum ((((class color) (background dark)) (:foreground "gray50")) (((class color) (background light)) (:foreground "blue"))))
 '(makefile-space ((((class color) (background dark)) (:bold t :background "PaleGreen4"))))
 '(minibuffer-prompt ((((class color) (background dark)) (:foreground "Red" :background "Black" :bold t)) (((class color) (background light)) (:foreground "midnightblue" :background "whitesmoke" :bold t :italic t))))
 '(outline-1 ((((class color) (background light)) (:height 1.2 :underline t :foreground "dark goldenrod")) (((class color) (background dark)) (:height 1.2 :underline t :foreground "dark goldenrod"))))
 '(outline-2 ((((class color) (background light)) (:height 1.1 :foreground "goldenrod")) (((class color) (background dark)) (:height 1.1 :foreground "goldenrod"))))
 '(outline-3 ((((class color) (background light)) (:height 1.0 :foreground "dark khaki")) (((class color) (background dark)) (:height 1.0 :foreground "dark khaki"))))
 '(outline-4 ((((class color) (background light)) (:height 1.0 :foreground "khaki")) (((class color) (background dark)) (:height 1.0 :foreground "khaki"))))
 '(outline-5 ((((class color) (background light)) (:height 1.0 :foreground "cornsilk")) (((class color) (background dark)) (:height 1.0 :foreground "cornsilk"))))
 '(outline-6 ((((class color) (background light)) (:height 1.0 :italic t :foreground "deepskyblue")) (((class color) (background dark)) (:height 1.0 :italic t :foreground "deepskyblue4"))))
 '(region ((((class color) (background dark)) (:background "SeaGreen" :bold t)) (((class color) (background light)) (:foreground "springgreen" :background "black"))))
 '(sh-escaped-newline ((((class color) (background dark)) (:bold t)) (((class color) (background light)) (:bold t :foreground "OrangeRed"))))
 '(sh-heredoc-face ((((class color) (background dark)) (:bold t :foreground "Chocolate")) (((class color) (background light)) (:bold t :foreground "Firebrick"))))
 '(sh-quoted-exec ((((class color) (background dark)) (:bold t :foreground "Chocolate")) (((class color) (background light)) (:bold t :foreground "DarkOrange"))))
 '(show-paren-match ((((class color) (background light)) (:background "honeydew" :bold t)) (((class color) (background dark)) (:foreground "White" :background "Black" :bold t))))
 '(show-paren-mismatch ((((class color) (background light)) (:foreground "OrangeRed" :italic t :bold t)) (((class color) (background dark)) (:foreground "OrangeRed" :background "Black" :italic t :bold t))))
 '(trailing-whitespace ((((class color) (background dark)) (:bold t :background "lightpink4")) (((class color) (background light)) (:bold t :background "gray92"))))
 '(which-func ((((class color) (background dark)) (:foreground "Chartreuse3" :width condensed)) (((class color) (background light)) (:underline t :foreground "Chartreuse2" :width condensed)))))