;; -*- lexical-binding: t -*-

(setq load-prefer-newer t)

;; We set `user-emacs-directory' here so we can use command-line
;; switch different emacs configuration like following:
;;
;;    emacs -q -l ~/coldnew-spacemacs/init.el
(defconst user-emacs-directory
  (file-name-directory (or load-file-name (buffer-file-name)))
  "My emacs config directory.")

(defconst user-cache-directory
  (file-name-as-directory (concat user-emacs-directory ".cache"))
  "My emacs storage area for persistent files.")
;; create the `user-cache-directory' if not exists
(make-directory user-cache-directory t)

(defconst user-ramdisk-directory
    (let ((ramdisk "/Volumes/ramdisk/")
          (user-ramdisk                   ; ~/ramdisk/
           (concat (getenv "HOME") "/ramdisk/"))
          (tmp "/tmp/"))
      (if (eq system-type 'darwin)
          ramdisk
        ;; if ~/ramdisk/ exist, use it
        (if (file-exists-p user-ramdisk)
            user-ramdisk
          ;; fallcack to system default ramdisk dir
          temporary-file-directory)))
  "My ramdisk path in system.")

(defun my/load-secret ()
  "Load my secret setting include password... etc."
  (let ((secret "~/.secret.el.gpg"))
    (when (file-exists-p secret) (load-file secret))))

;; This must come before configurations of installed packages.
;; Don't delete this line. If you don't want it, just comment it out by adding a
;; semicolon to the start of the line. You may delete these explanatory
;; comments.
(package-initialize)

(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/"))

(add-to-list 'auto-mode-alist '("Cask$" . emacs-lisp-mode))

(require 'cask "~/.cask/cask.el")
(cask-initialize)

(require 'pallet)
(pallet-mode t)

(require 'use-package)                  ; Installed by Cask
;; Auto install non-installed packages.
;; (setq use-package-always-ensure t)

(require 'req-package)

(require 'paradox)                  ; Installed by Cask

;; Add directories to emacs's `load-path' recursively.
;; if path does not exist, create directory.
(let* ((lisp-dir '("local-lisp/" "themes/")))
  (dolist (lisp-path lisp-dir)
    (when (not (file-exists-p lisp-path))
      (make-directory (concat user-emacs-directory lisp-path) t))
    (let* ((load-dir (concat user-emacs-directory lisp-path))
           (default-directory load-dir))
      (setq load-path
            (append
             (let ((load-path (copy-sequence load-path)))
               (append
                (copy-sequence (normal-top-level-add-to-load-path '(".")))
                (normal-top-level-add-subdirs-to-load-path)))
             load-path)))))

;;;; add some system site-lisp to my load-path

;; Mac OSX
(when (equal system-type 'darwin)
  (let ((default-directory "/usr/local/share/emacs/site-lisp/"))
    (normal-top-level-add-subdirs-to-load-path)))

;; Linux
(when (equal system-type 'gnu/linux)
  (let ((default-directory "/usr/share/emacs/site-lisp/"))
    (normal-top-level-add-subdirs-to-load-path)))

;; load the `load-modules.el' file which help me load external modulept
(let ((script (concat user-emacs-directory "modules/load-modules.el")))
  (when (file-exists-p script)
    (load script)))

(setq user-full-name "Yen-Chin, Lee")
(setq user-mail-address "coldnew.tw@gmail.com")

;; Only start server mode if I'm not root
(unless (string-equal "root" (getenv "USER"))
  (require 'server)
  (unless (server-running-p) (server-start)))

(setq mac-option-modifier 'super)
(setq mac-command-modifier 'meta)
(setq mac-pass-command-to-system nil)

(require 'noflet)
(defadvice save-buffers-kill-emacs (around no-query-kill-emacs activate)
  "Prevent annoying \"Active processes exist\" query when you quit Emacs."
  (noflet ((process-list ())) ad-do-it))

(setq kill-buffer-query-functions
      (remq 'process-kill-buffer-query-function
            kill-buffer-query-functions))

(setq-default custom-file (concat user-cache-directory "custom.el"))
;; load custom-file only when file exist
(when (file-exists-p custom-file)
  (load-file custom-file))

(require 'async)   ; Installed by Cask
;; If I'm edit my init.org, async generate init.el when save.
(defun tangle-init ()
  "If the current buffer is 'init.org' the code-blocks are tangled."
  (let ((buffer-name "async-make-init.el"))
    (when (equal (buffer-file-name)
                 (expand-file-name (concat user-emacs-directory "init.org")))
      ;; If previous building buffer exist, discard it
      ;; (when (get-buffer (concat "*" buffer-name "*"))
      ;;   (kill-buffer (concat "*" buffer-name "*")))
      ;; build with `make init.el' command
      (async-start-process buffer-name "make"
                           '(lambda (result)
                              (message "Re-Generate init.el")) "init.el"))))
;; Add to hook
(add-hook 'after-save-hook 'tangle-init)

(setq auto-save-list-file-prefix
      (concat user-cache-directory "auto-save-list/.saves-"))

(setq auto-save-interval 100)
(setq auto-save-timeout  60)
(setq auto-save-visited-file-name nil)
(setq delete-auto-save-files t)

(let ((backup-dir (concat user-cache-directory "backup")))
  ;; Move backup file to `~/.emacs.d/.cache/backup'
  (setq backup-directory-alist `(("." . ,backup-dir)))
  ;; Makesure backup directory exist
  (when (not (file-exists-p backup-dir))
    (make-directory backup-dir t)))

(setq delete-by-moving-to-trash nil)
(setq version-control t)
(setq kept-old-versions 10)
(setq kept-new-versions 20)
(setq delete-old-versions t)
(setq backup-by-copying t)

(when (featurep 'menu-bar) (menu-bar-mode -1))

(when (featurep 'tool-bar) (tool-bar-mode -1))

(blink-cursor-mode -1)

(when (featurep 'scroll-bar) (scroll-bar-mode -1))

(setq inhibit-startup-screen t)

(blink-cursor-mode -1)

(setq ring-bell-function #'ignore)

(setq initial-scratch-message "")

(setq visible-bell t)

(defalias 'yes-or-no-p 'y-or-n-p)

(prefer-coding-system 'utf-8)
(setq system-time-locale "en_US")

(eval-after-load 'bookmark
  '(progn
     (setq bookmark-default-file
           (concat user-cache-directory "bookmarks"))))

(eval-after-load 'dilwave
  '(progn
     (setq idlwave-config-directory
           (concat user-cache-directory "idlwave"))))

;; change srecode cache file path
(eval-after-load 'srecode
  '(progn
     (setq srecode-map-save-file
           (concat user-cache-directory "srecode-map.el"))))

(eval-after-load 'request
  '(progn
     (setq request-storage-directory
           (concat user-cache-directory "request"))))

(eval-after-load 'nsm
  '(progn
     (setq nsm-settings-file
           (concat user-cache-directory "network-security.data"))))

(eval-after-load 'url
  '(progn
     (setq url-configuration-directory
           (file-name-as-directory
            (concat user-cache-directory "url")))))

(req-package ag
  :if (executable-find "ag"))

(req-package ascii
  :config
  (defun ascii-toggle ()
    "Toggle ascii-mode."
    (interactive)
    (if (not (ascii-off)) (ascii-on)))

  ;; alias ascii to ascii-toggle
  (defalias 'ascii 'ascii-toggle))

(req-package ascii-art-to-unicode)

(req-package avy)

(req-package buffer-move)

(req-package bpr)

(req-package calfw)

(req-package cbm)

(req-package crux)

(req-package darkroom)

(req-package discover-my-major)

(when (require 'doxymacs nil 'noerror)
  (add-hook 'prog-mode-hook '(lambda () (doxymacs-mode))))

(req-package esup)

(req-package exec-path-from-shell
  :config
  (when (memq window-system '(mac ns x))
    (exec-path-from-shell-initialize)))

(req-package expand-region
  :bind (("M-v" . er/expand-region)))

(req-package fancy-narrow)

(req-package focus)

(req-package google-translate)

(req-package howdoi)

(req-package htmlize)

(req-package hungry-delete
  :config
  (global-hungry-delete-mode))

(req-package hydra
  :config
    (defhydra hydra-window ()
       "
    Movement^^        ^Split^         ^Switch^      ^Resize^
    ----------------------------------------------------------------
    _h_ ←         _v_ertical      _b_uffer        _q_ X←
    _j_ ↓         _x_ horizontal  _f_ind files    _w_ X↓
    _k_ ↑         _z_ undo        _a_ce 1     _e_ X↑
    _l_ →         _Z_ reset       _s_wap      _r_ X→
    _F_ollow        _D_lt Other     _S_ave      max_i_mize
    _SPC_ cancel    _o_nly this     _d_elete
    "
       ("h" windmove-left )
       ("j" windmove-down )
       ("k" windmove-up )
       ("l" windmove-right )
       ("q" hydra-move-splitter-left)
       ("w" hydra-move-splitter-down)
       ("e" hydra-move-splitter-up)
       ("r" hydra-move-splitter-right)
       ("b" helm-mini)
       ("f" helm-find-files)
       ("F" follow-mode)
       ("a" (lambda ()
              (interactive)
              (ace-window 1)
              (add-hook 'ace-window-end-once-hook
                        'hydra-window/body)))
       ("v" (lambda ()
              (interactive)
              (split-window-right)
              (windmove-right)))
       ("x" (lambda ()
              (interactive)
              (split-window-below)
              (windmove-down)))
       ("s" (lambda ()
              (interactive)
              (ace-window 4)
              (add-hook 'ace-window-end-once-hook
                        'hydra-window/body)))
       ("S" save-buffer)
       ("d" delete-window)
       ("D" (lambda ()
              (interactive)
              (ace-window 16)
              (add-hook 'ace-window-end-once-hook
                        'hydra-window/body)))
       ("o" delete-other-windows)
       ("i" ace-maximize-window)
       ("z" (progn
              (winner-undo)
              (setq this-command 'winner-undo)))
       ("Z" winner-redo)
       ("SPC" nil))
  
  ;;(global-set-key (kbd "C-x w") 'hydra-window/body)
  (defhydra hydra-movement ()
    "
       ^Forward^          ^Backward^      ^Up^     ^Down^   ^Char^
      ^^^^^^^^---------------------------------------------------
                         _c_: char
      ^^^^^^^^
       _n_: scroll down  _p_: scroll up
      "
    ("c" avy-goto-char)
    ;; others
    ("n" evil-scroll-page-down)
    ("p" evil-scroll-page-up)
    )
  
  ;;(global-set-key (kbd "C-x m") 'hydra-movement/body)
  (defhydra hydra-font-setup ()
    "
  Font Size^^
  ----------------------------------------------------------------
  _=_ ↑
  _\-_ ↓
  "
    ("=" text-scale-increase)
    ("-" text-scale-decrease))
  (defhydra hydra-window-buffer (:color red :hint nil)
  "
   ^Window^             ^Buffer^           ^Frame^
  ^^^^^^^^---------------------------------------------------
   ^hjkl^: move         _p_: previous      _u_: winner undo      ....../ \-.   .
   _s_: split below     _n_: next          _r_: winner redo   .-/     (    o\.//
   _v_: split right     _b_: switch        _w_: revert all     |  ...  \./\---'
   _c_: delete this     _;_: last          ^ ^                 |.||  |.||
   _o_: delete other    _K_: kill current  ^ ^
  ^^^^^^^^
  "
    ("w" revert-all-buffers :color blue)
  
    ("u" winner-undo)
    ("r" winner-redo)
  
    ("h" windmove-left)
    ("j" windmove-down)
    ("k" windmove-up)
    ("l" windmove-right)
  
    ("p" previous-buffer)
    ("n" next-buffer)
    ("b" ido-switch-buffer)
    (";" mode-line-other-buffer :color blue)
  
    ("s" split-window-below)
    ("v" split-window-right)
  
    ("K" kill-this-buffer)
  
    ("c" delete-window)
    ("o" delete-other-windows :color blue)
  
    ;; ("H" hydra-move-splitter-left)
    ;; ("J" hydra-move-splitter-down)
    ;; ("K" hydra-move-splitter-up)
    ;; ("L" hydra-move-splitter-right)
  
    ("q" nil))
    (global-set-key (kbd "C-x w") 'hydra-window-buffer/body))

(req-package iedit
  :bind (("C-;" . iedit-mode)))

(req-package know-your-http-well)

(req-package kurecolor)

(req-package lentic)

(req-package link-hint)

(req-package manage-minor-mode)

(req-package mustache)

(req-package mwim
  :bind
  (("C-a" . mwim-beginning-of-code-or-line)
   ("C-e" . mwim-end-of-code-or-line)))

(req-package moedict)

(req-package noflet)

(req-package nand2tetris
  :require (company company-nand2tetris nand2tetris-assembler)
  :if (file-exists-p "~/Workspace/nand2tetris")
  :config
  (setq nand2tetris-core-base-dir "~/Workspace/nand2tetris"))

(req-package pangu-spacing
  :config
  ;; start pangu-spacing globally
  (global-pangu-spacing-mode 1)
  ;; Always insert `real' space in org-mode.
  (add-hook 'org-mode-hook
            '(lambda ()
               (set (make-local-variable 'pangu-spacing-real-insert-separtor) t))))

(req-package password-generator :defer t)

(req-package rainbow-mode)

(req-package reveal-in-osx-finder
  :when (eq system-type 'darwin))

(req-package smartparens
  :require smartparens-config
  :config
  (smartparens-mode 1))

(req-package spray)

(req-package sicp)

(req-package string-inflection)

(req-package sx :require sx-load)

(req-package tldr
  :init
  (setq tldr-directory-path (concat user-cache-directory "tldr/"))
  (setq tldr-saved-zip-path (concat user-cache-directory "tldr-source.zip")))

(req-package travis)

(req-package url-shortener)

(req-package verify-url)

(req-package which-key
  :config
  ;; enable globally
  (which-key-mode)
  ;; Hide/Modify some function prefix in which-key show menu
  (setq which-key-description-replacement-alist
        '(("Prefix Command" . "prefix")
          ("which-key-show-next-page" . "wk next pg")
          ("\\`calc-" . "") ; Hide "calc-" prefixes when listing M-x calc keys
          ("/body\\'" . "") ; Remove display the "/body" portion of hydra fn names
          ("modi/" . "m/") ; The car is intentionally not "\\`modi/" to cover
                                        ; cases like `hydra-toggle/modi/..'.
          ("\\`hydra-" . "+h/")
          ("\\`org-babel-" . "ob/")
          ("\\`my/" . ""))))

(req-package xkcd
  :init
  (setq xkcd-cache-dir (concat user-cache-directory "xkcd/"))
  (when (not (file-directory-p xkcd-cache-dir))
    (make-directory xkcd-cache-dir :parents)))

(req-package zzz-to-char
  :bind (("M-z" . zzz-to-char)))

(defun nuke-all-buffers ()
  "Kill all buffers, leaving *scratch* only."
  (interactive)
  (mapcar (lambda (x) (kill-buffer x)) (buffer-list))
  (delete-other-windows))

(defun my/save-buffer-always ()
  "Save the buffer even if it is not modified."
  (interactive)
  (set-buffer-modified-p t)
  (save-buffer))

(defun minibuffer-keyboard-quit ()
  "Abort recursive edit.
In Delete Selection mode, if the mark is active, just deactivate it;
then it takes a second \\[keyboard-quit] to abort the minibuffer."
  (interactive)
  (if (and delete-selection-mode transient-mark-mode mark-active)
      (setq deactivate-mark t)
    (when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
    (abort-recursive-edit)))

(defun untabify-buffer ()
  (interactive)
  (save-excursion
    (untabify (point-min) (point-max))))

(defun indent-whole-buffer ()
  "Indent whole buffer."
  (interactive)
  (save-excursion
    (indent-region (point-min) (point-max))))

(defun cleanup-buffer ()
  "Perform a bunch of operations on the whitespace content of a buffer."
  (interactive)
  (save-excursion
    (delete-trailing-whitespace)
    (indent-region (point-min) (point-max))
    (untabify (point-min) (point-max))))

(defun eval-and-replace ()
  "Replace the preceding sexp with its value."
  (interactive)
  (backward-kill-sexp)
  (condition-case nil
      (prin1 (eval (read (current-kill 0)))
             (current-buffer))
    (error (message "Invalid expression")
           (insert (current-kill 0)))))

(defun quick-folding-source ()
  "Use emacs buildin easy to folding code."
  (interactive)
  (set-selective-display
   (if selective-display nil 1)))

(defun my/narrow-or-widen-dwim (p)
  "Widen if buffer is narrowed, narrow-dwim otherwise.
Dwim means: region, org-src-block, org-subtree, or defun,
whichever applies first. Narrowing to org-src-block actually
calls `org-edit-src-code'.

With prefix P, don't widen, just narrow even if buffer is
already narrowed."
  (interactive "P")
  (declare (interactive-only))
  (cond ((and (buffer-narrowed-p) (not p)) (widen))
        ((region-active-p)
         (narrow-to-region (region-beginning) (region-end)))
        ;; org-mode
        ((derived-mode-p 'org-mode)
         ;; `org-edit-src-code' is not a real narrowing
         ;; command. Remove this first conditional if you
         ;; don't want it.
         (cond ((ignore-errors (org-edit-src-code))
                (delete-other-windows))
               ((ignore-errors (org-narrow-to-block) t))
               (t (org-narrow-to-subtree))))
        ;; latex-mode
        ((derived-mode-p 'latex-mode)
         (LaTeX-narrow-to-environment))
        (t (narrow-to-defun))))

(defun insert-U200B-char ()
  "Insert <U200B> char, this character is nice use in org-mode."
  (interactive)
  (insert "\ufeff"))

(defun insert-empty-line ()
  "Insert an empty line after current line and position cursor on newline."
  (interactive)
  (move-end-of-line nil)
  (open-line 1)
  (next-line 1))

(defun insert-lorem ()
  "Insert a lorem ipsum."
  (interactive)
  (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."))

(defun delete-word (arg)
  "Delete characters forward until encountering the end of a word.
With argument, do this that many times."
  (interactive "p")
  (delete-region (point) (progn (forward-word arg) (point))))

(defun backward-delete-word (arg)
  "Delete characters backward until encountering the end of a word.
With argument, do this that many times."
  (interactive "p")
  (delete-word (- arg)))

(defun set-mark-mode/rectangle-mark-mode ()
  "toggle between set-mark-command or rectangle-mark-mode"
  (interactive)
  (if (not mark-active)
     (call-interactively 'set-mark-command)
    (call-interactively 'rectangle-mark-mode)))

(defun indent-region-or-buffer-and-cleanup ()
  "Indents a region if selected, otherwise the whole buffer."
  (interactive)
  (cl-flet ((format-fn (BEG END) (indent-region BEG END) (untabify BEG END)))
    (save-excursion
      (if (region-active-p)
          (progn
            (delete-trailing-whitespace (region-beginning) (region-end))
            (format-fn (region-beginning) (region-end))
            (message "Indented selected region and clear whitespace and untabify."))
        (progn
          (delete-trailing-whitespace)
          (format-fn (point-min) (point-max))
          (message "Indented whole buffer and clear whitespace and untabify."))))))

(defun my/copy-and-comment ()
  "Copy region and comment it."
  (interactive)
  (kill-ring-save (region-beginning) (region-end))
  (comment-dwim nil))

(defun file-reopen-as-root ()
  (interactive)
  (when buffer-file-name
    (find-alternate-file
     (concat "/sudo:root@localhost:"
             buffer-file-name))))

(defun delete-current-buffer-file ()
  "Removes file connected to current buffer and kills buffer."
  (interactive)
  (let ((filename (buffer-file-name))
        (buffer (current-buffer))
        (name (buffer-name)))
    (if (not (and filename (file-exists-p filename)))
        (ido-kill-buffer)
      (when (yes-or-no-p "Are you sure you want to remove this file? ")
        (delete-file filename)
        (kill-buffer buffer)
        (message "File '%s' successfully removed" filename)))))

(defun rename-current-buffer-file ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (error "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " filename)))
        (if (get-buffer new-name)
            (error "A buffer named '%s' already exists!" new-name)
          (rename-file filename new-name 1)
          (rename-buffer new-name)
          (set-visited-file-name new-name)
          (set-buffer-modified-p nil)
          (message "File '%s' successfully renamed to '%s'"
                   name (file-name-nondirectory new-name)))))))

(defun set-file-executable()
  "Add executable permissions on current file."
  (interactive)
  (when (buffer-file-name)
    (set-file-modes buffer-file-name
                    (logior (file-modes buffer-file-name) #o100))
    (message (concat "Made " buffer-file-name " executable"))))

(defun clone-file-and-open (filename)
  "Clone the current buffer writing it into FILENAME and open it"
  (interactive "FClone to file: ")
  (save-restriction
    (widen)
    (write-region (point-min) (point-max) filename nil nil nil 'confirm))
  (find-file filename))

(defun my/file-info ()
  "Show current buffer information."
  (interactive)
  (if (buffer-file-name (current-buffer))
      (progn
        (let* ((file-name (buffer-file-name (current-buffer)))
               (f-attr (file-attributes file-name))
               (f-size (nth 7 f-attr))  ; ファイルサイズ
               (f-mode (nth 8 f-attr))  ; ファイル属性
               (mes1 (format "file path: %s\n" file-name))
               (mes2 (format "file size: %s byte\n" f-size))
               (mes3 (format "file type: %s" f-mode))
               (mess (concat mes1 mes2 mes3)))
          (message "%s" mess)))
    nil))

(defun eval-buffer-until-error ()
  "Evaluate emacs buffer until error occured."
  (interactive)
  (goto-char (point-min))
  (while t (eval (read (current-buffer)))))

(defun what-face (pos)
  "Display face found at the current point."
  (interactive "d")
  (let ((face (or (get-char-property (point) 'read-face-name)
                  (get-char-property (point) 'face))))
    (if face (message "Face: %s" face) (message "No face at %d" pos))))

(defun my/reload-init ()
  "Reload init.el file"
  (interactive)
  (load-file user-init-file))

(defun my/other-window-or-split ()
  "Switch to other window or split it."
  (interactive)
  (when (one-window-p)
    (split-window-horizontally))
  (other-window 1))

;; Make `load-theme' fully unload previous theme before loading a new one.
(defadvice load-theme
    (before theme-dont-propagate activate)
  (mapc #'disable-theme custom-enabled-themes))

;; My light theme
(req-package coldnew-theme-day-theme
  :require (powerline powerline-evil))

;; My night them (default)
(req-package coldnew-theme-night-theme
  :config (coldnew-theme-night))

;;(req-package coldnew-modeline-config
;;  :require (powerline powerline-evil))
;; TODO:
(req-package spaceline
  :config
  (require 'spaceline-config)
  (spaceline-spacemacs-theme))

(req-package minibuffer                  ; buildin
  :config
  ;; only use `bar' type of cursor shape
  (add-hook 'minibuffer-setup-hook '(lambda () (setq cursor-type 'bar)))
  ;; define some helper function to insert to minibuffer quickly
  (defun my/minibuffer-insert (p)
    (kill-line 0) (insert p))
  
  (defun my/minibuffer-switch-to-ramdisk ()
    "Insert ramdisk path according to system type"
    (interactive)
    (my/minibuffer-insert user-ramdisk-directory))
  
  (defun my/minibuffer-switch-to-home ()
    "Insert $HOME path."
    (interactive)
    (my/minibuffer-insert (file-name-as-directory (getenv "HOME"))))
  
  (defun my/minibuffer-switch-to-rootdir ()
    "Insert / path."
    (interactive)
    (my/minibuffer-insert "/"))
  
  (defun my/minibuffer-switch-to-tramp ()
    "Insert /ssh:."
    (interactive)
    (my/minibuffer-insert "/ssh:"))
  (eval-after-load 'minibuffer
    '(progn
       (lexical-let ((default-threshold gc-cons-threshold))
         (defun my/minibuffer-gc-setup-hook ()
           (setq gc-cons-threshold most-positive-fixnum))
         (add-hook 'minibuffer-setup-hook #'my/minibuffer-gc-setup-hook)
         ;; When exit, set back to default threshold
         (defun my/minibuffer-gc-exit-hook ()
           (setq gc-cons-threshold default-threshold))
         (add-hook 'minibuffer-exit-hook #'my/minibuffer-gc-exit-hook))))
  (bind-keys :map minibuffer-local-map
             ("C-w" . backward-kill-word)
             ("M-p" . previous-history-element)
             ("M-n" . next-history-element)
             ("C-g" . minibuffer-keyboard-quit)
             ("M-t" . my/minibuffer-switch-to-ramdisk)
             ("M-h" . my/minibuffer-switch-to-home)
             ("M-/" . my/minibuffer-switch-to-rootdir)
             ("M-s" . my/minibuffer-switch-to-tramp)))

(req-package savehist
  :config
  (setq savehist-file (concat user-cache-directory "savehist.dat"))
  (savehist-mode 1))

(use-package org
  :pin gnu                              ; fetch fron `gnu'
  :mode (("\\.org\\'" . org-mode)
         ("\\.org_archive\\'" . org-mode))
  :config
  ;; fontify source code
  (setq org-src-fontify-natively t)
  ;; Use current window when switch to source block
  (setq org-src-window-setup 'current-window)
  ;; Disable prompting to evaluate babel blocks
  (setq org-confirm-babel-evaluate nil)
  ;; Disable add validation link when export to HTML
  (setq org-html-validation-link nil)
  ;; Always enable auto indent mode
  (use-package org-indent
    :config
    (setq org-indent-mode t))
  (setq org-todo-keywords '((sequence "☛ TODO(t)" "|" "✔ DONE(d)")
                            (sequence "⚑ WAITING(w)" "|")
                            (sequence "|" "✘ CANCELED(c)")))
  (add-hook 'org-mode-hook #'visual-line-mode)
  (add-to-list 'org-structure-template-alist
               '("E" "#+BEGIN_SRC emacs-lisp\n?\n#+END_SRC"))
  (add-to-list 'org-structure-template-alist
               '("S" "#+BEGIN_SRC sh\n?\n#+END_SRC"))
  (add-to-list 'org-structure-template-alist
               '("p" "#+BEGIN_SRC plantuml :file uml.png \n?\n#+END_SRC"))
  (org-babel-do-load-languages
   'org-babel-load-languages
   '((emacs-lisp . t)
     (C . t)
     (ditaa . t)
     (dot . t)
     (js . t)
     (latex . t)
     (perl . t)
     (python . t)
     (ruby . t)
     (sh . t)
     (plantuml . t)
     (clojure . t)))
  ;; make dot work as graphviz-dot
  (add-to-list 'org-src-lang-modes '("dot" . graphviz-dot))
  (setq org-link-abbrev-alist
        '(("google" . "http://www.google.com/search?q=")
          ("google-map" . "http://maps.google.com/maps?q=%s")
          ))
  ;; make agenda show on current window
  (setq org-agenda-window-setup 'current-window)
  ;; highlight current in agenda
  (add-hook 'org-agenda-mode-hook 'hl-line-mode)
  ;; Setup files for agenda
  (setq org-agenda-files (list "~/Org/task/Office.org" "~/Org/task/Personal.org"))
  ;;
  (setq org-directory "~/Org")
  (setq org-default-notes-file (f-join org-directory "task" "Office.org"))
  
  ;; Always use `C-g' to exit agenda
  (add-hook 'org-agenda-mode-hook
            '(lambda ()
               (local-set-key (kbd "C-g") 'org-agenda-exit)))
  (eval-after-load 'ispell
    '(progn
       (add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:"))
       (add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" . "#\\+END_SRC"))
       ))
  (use-package org-crypt
    :config
    ;; Auto encrypt when save file
    (org-crypt-use-before-save-magic)
    ;; Encrypt with tagname: `secret'
    (setq org-crypt-tag-matcher "secret")
    ;; Prevent the `secret' tag inherit by child
    ;; (The child item still will be encrypt)
    (setq org-tags-exclude-from-inheritance (quote ("secret")))
    ;; Use my own password to encrypt
    (setq org-crypt-key nil))
  (use-package org-redmine
    :ensure t
    :config
    ;; NOTE: in personal private setting
    (setq org-redmine-uri nil)
    (setq org-redmine-auth-api-key nil)
    (setq org-redmine-auth-password nil)
                                          ;
    ;; Advice org-remine function so it will load my private config
    (defadvice org-redmine-get-issue (before load-password activate)
      (my/load-secret))
    (defadvice org-redmine-anything-show-issue-all (before load-password activate)
      (my/load-secret)))
  (setq org-format-latex-options
        '(:forground "black" :background "white"
                     :scale 1.5
                     :html-foreground "Black" :html-background "Transparent"
                     :html-scale 1.0
                     :matchers ("begin" "$1" "$" "$$" "\\(" "\\[")))
  (use-package ox-textile
    :ensure t)
  (bind-keys :map org-mode-map
             ("M-p"   . org-previous-visible-heading)
             ("M-n"   . org-next-visible-heading)
             ("C-c a" . org-agenda)
             ("C-c c" . org-capture)
             ("C-c l" . org-stored-links)
             ("C-c b" . org-metaleft)
             ("C-c f" . org-metaright)
             ("C-c p" . org-metaup)
             ("C-c n" . org-metadown)
             ("C-c i" . org-insert-link)
             ("C-c I" . org-toggle-inline-images))
  (bind-keys :map org-src-mode-map
             ("C-c C-c" . org-edit-src-exit)))

(req-package org-bullets
  :config
  (add-hook 'org-mode-hook (lambda () (org-bullets-mode 1))))

(defvar coldnew-editor-map (make-keymap))

(define-minor-mode coldnew-editor-mode
  "coldnew's editor minor mode."
  :init-value t
  :keymap coldnew-editor-map)

(define-globalized-minor-mode global-coldnew-editor-mode
  coldnew-editor-mode (lambda ()
                        (if (not (minibufferp (current-buffer)))
                            (coldnew-editor-mode 1))))

;; Gloabal enable
(global-coldnew-editor-mode t)

(req-package linum :init (global-linum-mode 1))

(req-package linum-off
  :config
    (setq linum-disabled-mode-list
          '(eshell-mode shell-mode term-mode erc-mode compilation-mode
                        woman-mode w3m-mode calendar-mode org-mode)))

(global-auto-revert-mode 1)
(setq global-auto-revert-non-file-buffers t)
(setq auto-revert-verbose nil)
(setq revert-without-query '(".*")) ;; disable revert query

(req-package rainbow-delimiters
  :config
  (add-hook 'prog-mode-hook #'rainbow-delimiters-mode))

(req-package 'editorconfig
  :if (executable-find "editorconfig")
  :mode ("\\.editorconfig\\'" . conf-unix-mode))

(req-package dtrt-indent
  :config
  ;; enable dtrt-indent-mode globally
  (dtrt-indent-mode 1))

(req-package epa-file
  :config
  (epa-file-enable)
  ;; Control whether or not to pop up the key selection dialog.
  (setq epa-file-select-keys 0)
  ;; Cache passphrase for symmetric encryption.
  (setq epa-file-cache-passphrase-for-symmetric-encryption t))

(req-package tramp
  :init
  (setq tramp-persistency-file-name (concat user-cache-directory "tramp"))
  :config
  (setq tramp-default-method "rsync"))

(req-package whitespace-cleanup-mode
  :config
  (add-hook 'prog-mode-hook 'whitespace-cleanup-mode))

(req-package recentf
  :init
  (setq recentf-save-file (expand-file-name "recentf" user-cache-directory))
  :config
  (recentf-mode 1))

(req-package highlight-numbers
  :config
  ;; json-mode has it's own highlight numbers method
  (add-hook 'prog-mode-hook '(lambda()
                               (if (not (derived-mode-p 'json-mode))
                                   (highlight-numbers-mode)))))

(req-package highlight-escape-sequences
  :config
  ;; Make face the same as builtin face
  (put 'font-lock-regexp-grouping-backslash 'face-alias 'font-lock-builtin-face)
  ;; Enable globally
  (hes-mode 1))

(defun font-lock-comment-annotations ()
  "Highlight a bunch of well known comment annotations.
This functions should be added to the hooks of major modes for programming."
  (font-lock-add-keywords
   nil
   '(("\\<\\(FIX\\(ME\\)?\\|BUG\\|HACK\\):" 1 font-lock-warning-face t)
     ("\\<\\(NOTE\\):" 1 'org-level-2 t)
     ("\\<\\(TODO\\):" 1 'org-todo t)
     ("\\<\\(DONE\\):" 1 'org-done t))
   ))

(add-hook 'prog-mode-hook 'font-lock-comment-annotations)

(req-package undo-tree
  :config
  ;; Persistent undo-tree history across emacs sessions
  (let ((dir
         (file-name-as-directory (concat user-cache-directory "undo-tree"))))
    (setq undo-tree-history-directory-alist `(("." . ,dir))))
  (setq undo-tree-auto-save-history t)
  ;; global enable undo-tree
  (global-undo-tree-mode))

(req-package keyfreq
  :config
  ;; setup cache file
  (setq keyfreq-file (concat user-cache-directory "keyfreq"))
  (setq keyfreq-file-lock (concat keyfreq-file ".lock"))
  ;; enable globally
  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1))

(req-package ethan-wspace
  :config
  ;; Turn off `mode-require-final-newline' since ethan-wspace
  ;; supersedes `require-final-newline'.
  (setq mode-require-final-newline nil)

  ;; Enable ethan-wspace globally
  (global-ethan-wspace-mode 1)

  ;; Prevent etha-wspace touch my TAB on makefile mode
  (add-hook 'makefile-mode-hook
            '(lambda()
               (setq ethan-wspace-errors (remove 'tabs ethan-wspace-errors))))

  ;; Not use in diff-mode since it breaking my syntax-highlight
  (add-hook 'diff-mode-hook
            '(lambda()
               (ethan-wspace-mode -1)))

  ;; Ignore no trailing newline error
  (setq-default ethan-wspace-errors (remove 'no-nl-eof ethan-wspace-errors)))

(req-package indent-guide
  :config
  ;; Only show indent-guide in idle-time.
  (setq indent-guide-delay 0.1))

(show-paren-mode 1)
(setq show-paren-delay 0)               ; no delay

(setq tab-always-indent 'complete)

(req-package god-mode
  :bind
  ("M-o" . god-local-mode)
  :config
  (bind-keys :map god-local-mode-map
             ("z" . repeat)
             ("i" . god-local-mode)))

(req-package vi-tilde-fringe
  :if window-system
  :config
  (global-vi-tilde-fringe-mode))

(req-package evil
  :require (undo-tree)
  :config
  ;; enable evil-mode globally
  (evil-mode t)
  ;; some configs setup later
  ;; default state set to insert-state
  (setq evil-default-state 'insert)
  (setcdr evil-insert-state-map nil)
  (define-key evil-insert-state-map
    (read-kbd-macro evil-toggle-key) 'evil-emacs-state)
  (define-key evil-insert-state-map [escape] 'evil-normal-state)
  (dolist (m evil-emacs-state-modes)
    (add-to-list 'evil-insert-state-modes m))
  ;; extra keybindings defined in `Keybinding' section
  (evil-define-key 'normal coldnew-editor-map
      (kbd "C-x C-f") 'helm-find-files
      (kbd "C-x C-q") 'read-only-mode
      (kbd "C-x M-1") 'deft-or-close
      (kbd "C-x M-2") 'multi-eshell
      (kbd "C-x M-3") 'mu4e
      (kbd "C-x M-4") 'erc-start-or-switch
      (kbd "C-x vl") 'magit-log
      (kbd "C-x vp") 'magit-push
      (kbd "C-x vs") 'magit-status
      (kbd "C-x b") 'helm-buffers-list
      (kbd "M-[") 'winner-undo
      (kbd "M-]") 'winner-redo
      (kbd "M-x") 'helm-M-x
      (kbd "M-s") 'helm-occur
      (kbd "C-x C-o") 'other-frame
      (kbd "M-o") 'other-window)
  (evil-define-key 'insert coldnew-editor-map
    (kbd "<delete>") 'hungry-delete-backward
   ;; (kbd "TAB") 'yas/expand
    (kbd "C-;") 'iedit-mode
    (kbd "C-d") 'hungry-delete-forward
    (kbd "C-l") 'hungry-delete-backward
    (kbd "C-n") 'evil-next-line
    (kbd "M-z")   'zzz-to-char
    (kbd "C-o") 'evil-execute-in-normal-state
    (kbd "C-p") 'evil-previous-line
    (kbd "C-w") 'backward-kill-word
    (kbd "C-x C-f") 'helm-find-files
    (kbd "C-x C-n") 'company-complete
    (kbd "C-x C-q") 'read-only-mode
    (kbd "C-x M-1") 'deft-or-close
    (kbd "C-x M-2") 'multi-eshell
    (kbd "C-x M-3") 'mu4e
    (kbd "C-x M-4") 'erc-start-or-switch
    (kbd "C-x vl") 'magit-log
    (kbd "C-x vp") 'magit-push
    (kbd "C-x vs") 'magit-status
    (kbd "C-x b") 'helm-buffers-list
    (kbd "M-<SPC>") 'insert-U200B-char
    (kbd "M-[") 'winner-undo
    (kbd "M-]") 'winner-redo
    (kbd "M-s") 'helm-occur
    (kbd "s-<RET>") 'insert-empty-line
    (kbd "s-<SPC>") 'insert-U200B-char
    (kbd "C-v") 'set-mark-mode/rectangle-mark-mode
    (kbd "C-x C-i") 'indent-region-or-buffer-and-cleanup
    (kbd "M-v") 'er/expand-region
    (kbd "M-x") 'helm-M-x
    (kbd "M-y") 'helm-show-kill-ring
    ;; (kbd "M-o") 'other-window
    (kbd "C-x C-o") 'other-frame
    (kbd "C-x t") 'sane-term
    (kbd "C-x T") 'sane-term
    (kbd "M-y") 'helm-show-kill-ring
    )
  (evil-ex-define-cmd "ag" 'helm-ag)
  (evil-ex-define-cmd "agp[roject]" 'helm-projectile-ag)
  (evil-ex-define-cmd "agi[nteractive]" 'helm-do-ag)
  (evil-ex-define-cmd "google" 'helm-google)
  (evil-ex-define-cmd "google-suggest" 'helm-google-suggest)
  (evil-ex-define-cmd "gtag" 'ggtags-create-tags)
  (evil-ex-define-cmd "howdoi" 'howdoi-query))

(req-package evil-leader
  :config
  ;; enable evil-leader globally
  (global-evil-leader-mode)
  ;; extra keybindings defined in `Keybinding' section
  (evil-leader/set-leader "<SPC>")
  (evil-leader/set-key
    "1" 'select-window-1
    "2" 'select-window-2
    "3" 'select-window-3
    "4" 'select-window-4
    "5" 'select-window-5
    "6" 'select-window-6
    "7" 'select-window-7
    "8" 'select-window-8
    "9" 'select-window-9
    "0" 'select-window-0))

(req-package evil-surround
  :config
  (global-evil-surround-mode 1))

(req-package projectile
  :config
  (projectile-global-mode)
  ;; save projectile-known-projects-file in cache folder
  (setq projectile-known-projects-file
        (concat user-cache-directory "projectile-bookmarks.eld"))
  (setq projectile-cache-file
        (concat user-cache-directory "projectile.cache"))
  ;; Enable projectile globally
  (projectile-global-mode))

(req-package semantic
  :config
  (setq semanticdb-default-save-directory
        (concat user-cache-directory "semanticdb/"))

  (global-semanticdb-minor-mode 1)
  (global-semantic-idle-scheduler-mode 1)

  (semantic-mode 1))

(req-package gdb
  :config
  ;; Use many window in gdb
  (setq gdb-many-windows t)
  ;; Display source file containing the main routine at startup.
  ;; Also display the main routine in the disassembly buffer if present.
  (setq gdb-show-main t))

(req-package realgud)

(req-package xcscope
  :config
  ;; Use gtas's cscope command
  (setq cscope-program "gtags-cscope")
  ;; basic setup
  (cscope-setup))

(req-package flycheck
  :config
  ;; enable globally
  (global-flycheck-mode))

(req-package helm
  :require helm-config
  :config
  ;; enable helm globally
  (helm-mode 1)
  ;; extra helm configs
  ;; Use fuzzy match in helm
  (setq helm-M-x-fuzzy-match t)
  (setq helm-buffers-fuzzy-matching t)
  (setq helm-recentf-fuzzy-match t)
  ;; make helm can select anything even not match
  (setq helm-move-to-line-cycle-in-source nil)
  (setq helm-ff-search-library-in-sexp t)
  (setq helm-ff-file-name-history-use-recentf t)
  (bind-keys :map helm-map
             ("TAB"   . helm-execute-persistent-action)
             ("<tab>" . helm-execute-persistent-action)
             ("C-w"   . backward-kill-word)
             ("M-t" . my/minibuffer-switch-to-ramdisk)
             ("M-h" . my/minibuffer-switch-to-home)
             ("M-/" . my/minibuffer-switch-to-rootdir)
             ("M-s" . my/minibuffer-switch-to-tramp)))

(req-package helm-projectile
  :require (helm projectile)
  :config
  ;; make projectile use helm as completion system
  (setq projectile-completion-system 'helm)
  ;; start helm-projectile
  (helm-projectile-on))

(req-package helm-gtags
  :config
  (setq helm-gtags-ignore-case t)
  (setq helm-gtags-auto-update t)
  (setq helm-gtags-use-input-at-cursor t)
  (setq helm-gtags-pulse-at-cursor t)
  ;; add to following modes
  (add-hook 'c-mode-hook #'helm-gtags-mode)
  (add-hook 'c++-mode-hook #'helm-gtags-mode))

(req-package helm-bm)

(req-package helm-yasnippet
  :require (helm yasnippet)
  :config
  (setq helm-yas-space-match-any-greedy t))

(req-package helm-cscope
  :config
  (add-hook 'c-mode-common-hook 'helm-cscope-mode))

(req-package fontawesome)

(req-package helm-swoop)

(req-package helm-dash
  :require helm)

(req-package company
  :config
  ;; enable globally
  (global-company-mode 1)
  ;; some configuration add here by noweb
  (setq company-idle-delay nil)
  (bind-keys :map company-active-map
             ("C-g" . company-abort)
             ("C-n" . company-select-next)
             ("C-s" . company-filter-candidates)
             ("C-p" . company-select-previouse)
             ("TAB" . company-complete-selction)
             ("<tab>" . company-complete-selction))
  
  (bind-keys :map company-search-map
             ("C-n" . company-select-next)
             ("C-p" . company-select-previous)) )

(req-package company-c-headers
  :require company
  :config
  (add-to-list 'company-backends 'company-c-headers))

(req-package company-flx
  :require company
  :config
  (company-flx-mode +1))

(req-package company-statistics
  :config
  ;; save cache file to `user-cache-directory'
  (setq company-statistics-file (concat user-cache-directory
                                        "company-statistics-cache.el"))
  ;; start company-statictics-mode after init
  (add-hook 'after-init-hook 'company-statistics-mode))

(req-package yasnippet
  :mode ("emacs.+/snippets/" . snippet-mode)
  :config
  ;; enable yasnippet globally
  (yas-global-mode 1)
  ;; extra yasnipet configs
  (setq yas/prompt-functions '(yas-dropdown-prompt
                               yas-completing-prompt
                               yas-ido-prompt))
  (setq yas/snippet-dirs (concat user-emacs-directory "snippets"))
  (add-hook 'term-mode-hook (lambda() (yas-minor-mode -1)))
  (defadvice yas-expand (around major-mode-expand activate)
    "Try to complete a structure template before point like org-mode does.
  This looks for strings like \"<e\" on an otherwise empty line and
  expands them.
  Before use this function, you must setup `major-mode-name'-expand-alist variable.
  
  Take emacs-lisp-mode as example, if you wand to use <r to expand your snippet `require'
  in yasnippet, you muse setup the emacs-lisp-mode-expand-alist variable.
  
   (setq emacs-lisp-expand-alist '((\"r\" . \"require\")))"
    (let* ((l (buffer-substring (point-at-bol) (point)))
           (expand-symbol (intern (concat (symbol-name major-mode) "-expand-alist")))
           (expand-alist (if (boundp expand-symbol) (symbol-value expand-symbol) nil))
           a)
      (when (and (looking-at "[ \t]*$")
                 (string-match "^[ \t]*<\\([a-zA-Z]+\\)$" l)
                 (setq a (assoc (match-string 1 l) expand-alist)))
        (backward-delete-char (1+ (length (car-safe a))))
        (if (symbolp (cdr-safe a))
            (funcall (cdr-safe a))
          (insert (cdr-safe a)))
        t)
      ad-do-it)))

(req-package arduino-mode
  :mode ("\\.pde\\'" "\\.ino\\'"))

(req-package android-mode
  :config
  (setq android-mode-sdk-dir (getenv "ANDROID_HOME")))

(req-package elogcat)

(req-package flymake-shell
  :require (flymake shell)
  :config (add-hook 'sh-set-shell-hook 'flymake-shell-load))

(req-package bison-mode
  :mode ("\\.y\\'" "\\.l\\'" "\\.jison\\'"))

(req-package bitbake
  :mode ("\\.bb\\'" "\\.bbappend\\'"))

(req-package brainfuck-mode
  :mode "\\.bf\\'")

(req-package crontab-mode
  :mode "\\.?cron\\(tab\\)?\\'")

(req-package cmake-mode
  :mode ("CMakeLists\\.txt\\'" "\\.cmake\\'"))

(req-package dockerfile-mode
  :mode "Dockerfile\\'")

(req-package dts-mode
  :mode ("\\.dts\\'" "\\.dtsi\\'"))

(req-package elixir-mode)

(req-package alchemist)

(req-package gnuplot
  :commands gnuplot-mode
  :mode "\\.gp$")

(req-package graphviz-dot-mode
  :mode "\\.dot\\'"
  :config
  ;; alias `dot-mode' to graphviz-dot-mode
  (defalias 'dot-mode 'graphviz-dot-mode))

(req-package glsl-mode
  :mode (("\\.vs\\'" . glsl-mode)
         ("\\.fs\\'" . glsl-mode)
         ("\\.gs\\'" . glsl-mode))
  :config
  (setq glsl-other-file-alist '(("\\.fs$" (".vs")) ("\\.vs$" (".fs")))))

(req-package js2-mode
  :mode "\\.js\\'")

(req-package js2-refactor)

(req-package jsx-mode
  :mode "\\.jsx\\'")

(req-package import-js)

(req-package json-mode
  :mode "\\.json\\'")

(req-package json-reformat :commands json-reformat-region)

(req-package flymake-json
  :require flymake
  :config
  (add-hook 'json-mode-hook (lambda () (flymake-json-load))))

(req-package lua-mode
  :mode "\\.lua$")

(req-package markdown-mode
  :mode "\\.\\(md\\|markdown\\)\\'")

(req-package po-mode
  :mode "\\.po\\'\\|\\.po\\."
  :config

  ;; To use the right coding system automatically under Emacs 20 or newer,
  ;; also add:
  (when (require 'po nil 'noerror)
    (modify-coding-system-alist 'file "\\.po\\'\\|\\.po\\."
                                'po-find-file-coding-system))
  )

(req-package php-mode
  :mode "\\.php\\'")

(req-package python
  :mode (("\\.py\\'" . python-mode)
         ("SConstruct\\'" . python-mode)
         ("SConscript\\'" . python-mode)))

(req-package qml-mode
  :mode "\\.qml$")

(req-package ruby-mode
  :mode (("Gemfile\\'"  . ruby-mode)
         ("Kirkfile\\'" . ruby-mode)
         ("Rakefile\\'" . ruby-mode)
         ("Vagrantfile\\'" . ruby-mode)
         ("\\.builder\\'"  . ruby-mode)
         ("\\.gemspec\\'"  . ruby-mode)
         ("\\.irbrc\\'" . ruby-mode)
         ("\\.pryrc\\'" . ruby-mode)
         ("\\.rake\\'"  . ruby-mode)
         ("\\.rjs\\'"   . ruby-mode)
         ("\\.ru\\'"    . ruby-mode)
         ("\\.rxml\\'"  . ruby-mode))
  :config
  ;; We never want to edit Rubinius bytecode
  (add-to-list 'completion-ignored-extensions ".rbc"))

(req-package rust-mode
  :mode "\\.rs\\'")

(req-package llvm-mode)

(req-package lua-mode
  :mode "\\.lua$")

(req-package haskell-mode
  :mode "\\.hs\\'"
  :config
  (bind-keys :map haskell-mode-map
             ("C-c '" . my/narrow-or-widen-dwim)))

(req-package scala-mode2
  :mode "\\.scala$")

(req-package sbt-mode
  :mode "\\.sbt$")

(req-package ssh-config-mode
  :mode ((".ssh/config\\'"       . ssh-config-mode)
         ("sshd?_config\\'"      . ssh-config-mode)
         ("known_hosts\\'"       . ssh-known-hosts-mode)
         ("authorized_keys2?\\'" . ssh-authorized-keys-mode)))

(req-package swift-mode)

(req-package systemd)

(req-package toml-mode
  :mode "\\.toml$")

(use-package nxml-mode
  :mode (("\\.plist\\'" . nxml-mode)
         ("\\.rss\\'"   . nxml-mode)
         ("\\.svg\\'"   . nxml-mode)
         ("\\.xml\\'"   . nxml-mode)
         ("\\.xsd\\'"   . nxml-mode)
         ("\\.xslt\\'"  . nxml-mode)
         ("\\.pom$"     . nxml-mode))
  :config
  ;; Any file start with xml will be treat as nxml-mode
  (add-to-list 'magic-mode-alist '("<\\?xml" . nxml-mode))
  ;; Use nxml-mode instead of sgml, xml or html mode.
  (mapc
   (lambda (pair)
     (if (or (eq (cdr pair) 'xml-mode)
             (eq (cdr pair) 'sgml-mode))
         (setcdr pair 'nxml-mode)))
   auto-mode-alist))

(req-package yaml-mode)

(use-package cc-mode
  :mode
  (("\\.h\\'" . c-mode)
   ("\\.c\\'" . c-mode)
   ("\\.hpp\\'" . c++-mode)
   ("\\.cpp\\'" . c++-mode))
  :config
  (add-to-list 'magic-mode-alist
               `(,(lambda ()
                    (and (string= (file-name-extension (or (buffer-file-name) "")) "h")
                         (or (re-search-forward "#include <\\w+>"
                                                magic-mode-regexp-match-limit t)
                             (re-search-forward "\\W\\(class\\|template\\namespace\\)\\W"
                                                magic-mode-regexp-match-limit t)
                             (re-search-forward "std::"
                                                magic-mode-regexp-match-limit t))))
                 . c++-mode))
  (use-package cff :ensure t)
  ;; subword-mode, e.g., someThing is treated as two words
  (add-hook 'c-mode-common-hook '(lambda () (subword-mode 1)))
  (use-package srefactor
    :ensure t)
  (add-hook 'c-mode-hook
            '(lambda ()
               (c-set-style "linux")
               (setq c-basic-offset 8)
               ;; Make TAB equivilent to 8 spaces
               (setq tab-width 8)))
  (defun c-lineup-arglist-tabs-only (ignored)
    "Line up argument lists by tabs, not spaces"
    (let* ((anchor (c-langelem-pos c-syntactic-element))
           (column (c-langelem-2nd-pos c-syntactic-element))
           (offset (- (1+ column) anchor))
           (steps (floor offset c-basic-offset)))
      (* (max steps 1)
         c-basic-offset)))
  
  ;; Add Linux kernel style
  (add-hook 'c-mode-common-hook
            (lambda ()
              (c-add-style "linux-kernel"
                           '("linux" (c-offsets-alist
                                      (arglist-cont-nonempty
                                       c-lineup-gcc-asm-reg
                                       c-lineup-arglist-tabs-only))))))
  
  (defun linux-kernel-development-setup ()
    (let ((filename (buffer-file-name)))
      ;; Enable kernel mode for the appropriate files
      (when (and filename
                 (or (locate-dominating-file filename "Kbuild")
                     (locate-dominating-file filename "Kconfig")
                     (save-excursion (goto-char 0)
                                     (search-forward-regexp "^#include <linux/\\(module\\|kernel\\)\\.h>$" nil t))))
        ;; (setq indent-tabs-mode t)
        ;; (setq show-trailing-whitespace t)
        (c-set-style "linux-kernel")
        (message "Setting up indentation for the linux kernel"))))
  
  (add-hook 'c-mode-hook 'linux-kernel-development-setup)
  (add-hook 'c++-mode-hook
            '(lambda ()
  
               ;; Use stroustrup style
               (c-set-style "stroustrup")
  
               ;; Setting indentation lvel
               (setq c-basic-offset 4)
  
               ;; Make TAB equivilent to 4 spaces
               (setq tab-width 4)
  
               ;; Use spaces to indent instead of tabs.
               (setq indent-tabs-mode nil)
  
               ;; Indent the continuation by 2
               (setq c-continued-statement-offset 2)
  
               ;; Brackets should be at same indentation level as the statements they open
               ;; for example:
               ;;                 if (0)        becomes        if (0)
               ;;                     {                        {
               ;;                        ;                         ;
               ;;                     }                        }
               (c-set-offset 'substatement-open 0)
  
               ;; make open-braces after a case
               (c-set-offset 'case-label '+)
  
               ;; Not indent code inside a namespace
               ;; for example:
               ;;                namespace A {
               ;;
               ;;                int namespace_global_variable;
               ;;
               ;;                class Class {
               ;;
               ;;                Class();
               ;;                //...
               ;;                };
               ;;
               ;;                }
               (c-set-offset 'innamespace 0)
               ))
  (bind-keys :map c-mode-base-map
             ("C-c '" . my/narrow-or-widen-dwim)
             ("C-c C-c" . compile)
             ("C-c C-g" . gdb)
             ("C-c C-o" . cff-find-other-file))
  
  ;; Some keys may override global map add here
  (bind-keys :map c-mode-base-map
             ("M-." . helm-gtags-dwim)
             ("M-," . helm-gtags-pop-stack)))

(req-package dummy-h-mode
  :require cc-mode
  :mode "\\.h$"
  :config
  (add-hook 'dummy-h-mode-hook
            (lambda ()
              ;; use c-mode by default
              (setq dummy-h-mode-default-major-mode 'c-mode)
              ;; setup search limit
              (setq dummy-h-mode-search-limit 60000))))

(req-package c-eldoc
  :require eldoc
  :config
  (add-hook 'c-mode-common-hook
            '(lambda ()
               (setq c-eldoc-includes "`pkg-config --cflags --libs` -I./ -I../")
               (c-turn-on-eldoc-mode))))

(req-package cwarn
  :config
  (add-hook 'c-mode-common-hook '(lambda () (cwarn-mode 1))))

(defun my/cc-mode/highlight-if-0 ()
  "highlight c/c++ #if 0 #endif macros"
  (setq cpp-known-face 'default)
  (setq cpp-unknown-face 'default)
  (setq cpp-known-writable 't)
  (setq cpp-unknown-writable 't)
  (setq cpp-edit-list '(("0" '(foreground-color . "gray")  default both)
                        ("1" default font-lock-comment-face both)))
  (cpp-highlight-buffer t))

;; Add to c/c++ mode
(defun my/cc-mode/highlight-if-0-hook ()
  (when (or (eq major-mode 'c++-mode) (eq major-mode 'c-mode))
    (my/cc-mode/highlight-if-0)))
(add-hook 'after-save-hook #'my/cc-mode/highlight-if-0-hook)

(dolist (m '(c-mode c++-mode))
  (font-lock-add-keywords
   m
   '(("\\<\\(int8_t\\|int16_t\\|int32_t\\|int64_t\\|uint8_t\\|uint16_t\\|uint32_t\\|uint64_t\\)\\>" . font-lock-keyword-face))))

(req-package cpputils-cmake
  :require (flymake flycheck)
  :config
  (add-hook 'c-mode-common-hook
            (lambda ()
              (when (derived-mode-p 'c-mode 'c++-mode)
                (cppcm-reload-all)))))

(add-hook 'c-mode-common-hook 'electric-pair-mode)

(req-package lispy
  :require (hungry-delete projectile)
  :config
  ;; My special hack for lispy-mode
  (defun my/lispy-mode ()
    (lispy-mode 1)
    ;; `M-m' is preserved for mode setting
    (define-key lispy-mode-map (kbd "M-m") nil)
    ;; `M-s' is for my search command, rebind to `C-c s'
    (define-key lispy-mode-map (kbd "M-s") nil)
    (define-key lispy-mode-map (kbd "C-c s") 'lispy-splice)
    ;; `[' and `]' just insert them
    (define-key lispy-mode-map (kbd "[") 'lispy-open-square)
    (define-key lispy-mode-map (kbd "]") 'lispy-close-square))

  ;; Use projectile to find file
  (setq lispy-visit-method 'projectile)

  (add-hook 'emacs-lisp-mode-hook #'my/lispy-mode)
  (add-hook 'lisp-interaction-mode-hook #'my/lispy-mode)
  (add-hook 'clojure-mode-hook #'my/lispy-mode)
  (add-hook 'scheme-mode-hook #'my/lispy-mode)
  (add-hook 'lisp-mode-hook #'my/lispy-mode))

(use-package indent-guide
  :ensure t
  :config
  (add-hook 'emacs-lisp-mode-hook #'indent-guide-mode)
  (add-hook 'lisp-interaction-mode-hook #'indent-guide-mode)
  (add-hook 'clojure-mode-hook #'indent-guide-mode)
  (add-hook 'scheme-mode-hook #'indent-guide-mode)
  (add-hook 'lisp-mode-hook #'indent-guide-mode))

(global-prettify-symbols-mode 1)

(req-package emacs-lisp-mode
  :config
  (use-package macrostep)
  (bind-keys :map emacs-lisp-mode-map
             ("C-c '" . my/narrow-or-widen-dwim)))

(req-package el-spice)

(req-package eldoc
  :config
  (add-hook 'emacs-lisp-mode-hook
            '(lambda ()
               ;; enable eldoc
               (turn-on-eldoc-mode)
               ;; fix for paredit if exist
               (eval-after-load 'paredit
                 '(progn
                    (eldoc-add-command 'paredit-backward-delete
                                       'paredit-close-round))))))

(req-package litable
  :config
  ;; Save cache file to `user-cache-direcotry'
  (setq litable-list-file (concat user-cache-directory ".litable-lists.el"))
  ;; Enable litable-mode globally
  (litable-mode))

(req-package cl-lib-highlight
  :config
  (cl-lib-highlight-initialize))

(req-package page-break-lines
  :config
  ;; enable globally
  (global-page-break-lines-mode 1))

(defun remove-elc-on-save ()
  "If you're saving an elisp file, likely the .elc is no longer valid."
  (make-local-variable 'after-save-hook)
  (add-hook 'after-save-hook
            (lambda ()
              (if (file-exists-p (concat buffer-file-name "c"))
                  (delete-file (concat buffer-file-name "c"))))))

(add-hook 'emacs-lisp-mode-hook 'remove-elc-on-save)

(req-package elmacro
  :config
  (elmacro-mode))

(req-package clojure-mode
  :require (clojure-mode-extra-font-locking flycheck-clojure lispy)
  :mode "\\.\\(clj\\|boot\\|cljx\\|edn\\|cljs\\|cljs.hl\\)\\'"
  :config
  (req-package cider
    :require (cider-decompile cider-eval-sexp-fu eldoc projectile)
    :config
  
    ;; Enable eldoc in Clojure buffers
    (add-hook 'cider-mode-hook 'cider-turn-on-eldoc-mode)
  
    ;; Hide `*nrepl-connection*' and `*nrepl-server*' buffers from appearing
    ;; in some buffer switching commands like switch-to-buffer
    (setq nrepl-hide-special-buffers t)
  
    ;; Enabling CamelCase support for editing commands(like forward-word,
    ;; backward-word, etc) in the REPL is quite useful since we often have
    ;; to deal with Java class and method names. The built-in Emacs minor
    ;; mode subword-mode provides such functionality
    (add-hook 'cider-repl-mode-hook #'subword-mode)
  
    ;; The use of paredit when editing Clojure (or any other Lisp) code is
    ;; highly recommended. You're probably using it already in your
    ;; clojure-mode buffers (if you're not you probably should). You might
    ;; also want to enable paredit in the REPL buffer as well.
    ;; (add-hook 'cider-repl-mode-hook #'paredit-mode)
  
    ;; Auto-select the error buffer when it's displayed:
    (setq cider-auto-select-error-buffer t)
  
    ;; Controls whether to pop to the REPL buffer on connect.
    (setq cider-repl-pop-to-buffer-on-connect nil)
  
    ;; Controls whether to auto-select the error popup buffer.
    (setq cider-auto-select-error-buffer t)
  
    ;; T to wrap history around when the end is reached.
    (setq cider-repl-wrap-history t)
  
    ;; Log protocol messages to the `nrepl-message-buffer-name' buffer.
    (setq nrepl-log-messages t))
  (req-package clojure-cheatsheet)
  (defun my/cider-send-and-evaluate-sexp ()
    "Sends the s-expression located before the point or the active
    region to the REPL and evaluates it. Then the Clojure buffer is
    activated as if nothing happened."
    (interactive)
    (if (not (region-active-p))
        (cider-insert-last-sexp-in-repl)
      (cider-insert-in-repl
       (buffer-substring (region-beginning) (region-end)) nil))
    (cider-switch-to-repl-buffer)
    (cider-repl-closing-return)
    (cider-switch-to-last-clojure-buffer)
    (message ""))
  (bind-keys :map clojure-mode-map
             ;; M-m     . refactor command
             ("C-c C-f" . projectile-find-file)
             ("C-c M-c" . cider-connect)
             ("C-c M-j" . cider-jack-in)
             ("C-c '"   . my/narrow-or-widen-dwim)
             ("C-c h"   . clojure-cheatsheet)
             ("C-c C-k" . cider-load-buffer)
             ("C-x C-e" . cider-eval-last-sexp)
             ("C-c C-v" . my/cider-send-and-evaluate-sexp)
             ("C-c C-t" . projectile-toggle-between-implementation-and-test)))

(req-package clj-refactor
  :require (helm cljr-helm)
  :config
  ;; Add clj-refactor to clojure-mode
  (add-hook 'clojure-mode-hook '(lambda () (clj-refactor-mode 1)))
  ;; Use `C-c C-x' as prefix
  (cljr-add-keybindings-with-prefix "M-m"))

(req-package clojars)

(use-package scheme
  :mode ("\\.scm\\'" . scheme-mode)
  :config
  (use-package geiser
    :ensure t
    :init
    ;; On opening a scheme file, Geiser will try to guess its Scheme,
    ;; defaulting to the first in the list. Use `C-c C-s' to select the
    ;; implementation by hand (on a per file basis).
    (setq geiser-active-implementations '(guile chicken)))
  (bind-keys :map scheme-mode-map
             ("C-c '" . my/narrow-or-widen-dwim)))

(use-package racket-mode
  :ensure t
  :mode "\\.rkt[dl]?\\'")

(req-package lisp-mode
  :mode "\\.lisp\\'"
  :config
  (bind-keys :map lisp-mode-map
             ("C-c '" . my/narrow-or-widen-dwim)))

(req-package newlisp-mode)

(req-package web-mode
  :mode (("\\.html?\\'" . web-mode)
         ("\\.ejs?\\'" . web-mode)))

(req-package css-mode :mode "\\.css\\'")

(req-package css-eldoc
  :config
  (progn
    (add-hook 'css-mode-hook 'turn-on-css-eldoc)
    (add-hook 'scss-mode-hook 'turn-on-css-eldoc)
    (add-hook 'less-css-mode-hook 'turn-on-css-eldoc)))

(req-package less-css-mode
  :init (add-to-list 'auto-mode-alist '("\\.less$" . less-css-mode))
  :mode "\\.less$")

(req-package scss-mode
  :mode "\\.scss\\'"
  :config
  (progn
    ;; dont' build scss to css after save file
    (setq scss-compile-at-save nil)))

(req-package mustache-mode :mode "\\.mustache$")

;; Create *scratch* automatically
(run-with-idle-timer 1 t
                     '(lambda ()
                        (unless (get-buffer "*scratch*")
                          (with-current-buffer (get-buffer-create "*scratch*")
                            (lisp-interaction-mode)))))

(req-package uniquify
  :config
  ;; starting separator for buffer name components
  (setq uniquify-separator " • ")
  ;; rerationalize buffer names after a buffer has been killed.
  (setq uniquify-after-kill-buffer-p t)
  ;; ignore non file buffers
  (setq uniquify-ignore-buffers-re "^\\*"))

(req-package magit
  :config
  (setq magit-commit-arguments '("--verbose" "--signoff")))

(req-package gitconfig-mode
  :require flyspell
  :mode (("/\\.?git/?config\\'" . gitconfig-mode)
         ("/\\.gitmodules\\'" . gitconfig-mode)
         ("/_gitconfig\\'" . gitconfig-mode))
  :config
  (add-hook 'gitconfig-mode-hook 'flyspell-mode))

(req-package gitignore-mode
  :mode (("/\\.gitignore\\'" . gitignore-mode)
         ("/\\.git/info/exclude\\'" . gitignore-mode)
         ("/git/ignore\\'" . gitignore-mode)))

(req-package git-gutter-fringe
  :if window-system                     ; git-gutter-fringe only work on GUI
  :require fringe-helper
  :config
  ;; enable globally
  (git-gutter-mode))

(defadvice term-handle-exit (after kill-buffer-after-exit activate)
  "Kill the term buffer if the process finished."
  (kill-buffer (current-buffer)))

(req-package sane-term
  :config
  ;; shell to use for sane-term
  (setq sane-term-shell-command "/bin/bash")
  ;; sane-term will create first term if none exist
  (setq sane-term-initial-create t)
  ;; `C-d' or `exit' will kill the term buffer.
  (setq sane-term-kill-on-exit t)
  ;; After killing a term buffer, not cycle to another.
  (setq sane-term-next-on-kill nil))

(req-package eshell
  :config
  ;; extra eshell configs
  ;; move eshell cache dir to ~/.emacs.d/.cache
  (setq eshell-directory-name (concat user-cache-directory "eshell"))
  ;; Make eshell prompt look likes default bash prompt
  (setq eshell-prompt-function
        '(lambda ()
           (concat
            user-login-name "@" system-name " "
            (if (search (directory-file-name (expand-file-name (getenv "HOME"))) (eshell/pwd))
                (replace-regexp-in-string (expand-file-name (getenv "HOME")) "~" (eshell/pwd))
              (eshell/pwd))
            (if (= (user-uid) 0) " # " " $ "))))
  ;; Add color for eshell prompt like Gentoo does
  (defun colorfy-eshell-prompt ()
    (let* ((mpoint)
           (user-string-regexp (concat "^" user-login-name "@" system-name)))
      (save-excursion
        (goto-char (point-min))
        (while (re-search-forward (concat user-string-regexp ".*[$#]") (point-max) t)
          (setq mpoint (point))
          (overlay-put (make-overlay (point-at-bol) mpoint) 'face '(:foreground "dodger blue")))
        (goto-char (point-min))
        (while (re-search-forward user-string-regexp (point-max) t)
          (setq mpoint (point))
          (overlay-put (make-overlay (point-at-bol) mpoint) 'face '(:foreground "green3"))))))
  ;; Make eshell prompt more colorful
  (add-hook 'eshell-output-filter-functions 'colorfy-eshell-prompt)
  (setq eshell-visual-commands
        '("less" "tmux" "htop" "top" "bash" "zsh" "fish" "ssh" "tail"))
  
  (setq eshell-visual-subcommands
        '(("git" "log" "diff" "show"))))

(req-package multi-eshell
  :require eshell
  :config
  (setq multi-eshell-shell-function '(eshell))
  (setq multi-eshell-name "*eshell*"))

(req-package eshell-autojump :require eshell)

(defun eshell/.. (&optional level)
  "Go up LEVEL directories"
  (interactive)
  (let ((level (or level 1)))
    (eshell/cd (make-string (1+ level) ?.))
    (eshell/ls)))

(defun eshell/clear ()
  "Clears the shell buffer ala Unix's clear or DOS' cls"
  ;; the shell prompts are read-only, so clear that for the duration
  (let ((inhibit-read-only t))
    ;; simply delete the region
    (delete-region (point-min) (point-max))))

(defun eshell/emacs (&rest args)
  "Open a file in emacs. Some habits die hard."
  (if (null args)
      ;; If I just ran "emacs", I probably expect to be launching
      ;; Emacs, which is rather silly since I'm already in Emacs.
      ;; So just pretend to do what I ask.
      (bury-buffer)
    ;; We have to expand the file names or else naming a directory in an
    ;; argument causes later arguments to be looked for in that directory,
    ;; not the starting directory
    (mapc #'find-file (mapcar #'expand-file-name (eshell-flatten-list (reverse args))))))

(defalias 'eshell/e 'eshell/emacs)

(defun eshell/unpack (file)
  (let ((command (some (lambda (x)
                         (if (string-match-p (car x) file)
                             (cadr x)))
                       '((".*\.tar.bz2" "tar xjf")
                         (".*\.tar.gz" "tar xzf")
                         (".*\.bz2" "bunzip2")
                         (".*\.rar" "unrar x")
                         (".*\.gz" "gunzip")
                         (".*\.tar" "tar xf")
                         (".*\.tbz2" "tar xjf")
                         (".*\.tgz" "tar xzf")
                         (".*\.zip" "unzip")
                         (".*\.Z" "uncompress")
                         (".*" "echo 'Could not unpack the file:'")))))
    (eshell-command-result (concat command " " file))))

(modify-all-frames-parameters '((fullscreen . maximized)))

(req-package winner
  :config
  ;; I use my own keymap for winner-mode
  (setq winner-dont-bind-my-keys t)
  ;; Start winner-mode globally
  (winner-mode t))

(req-package eyebrowse
  :config
  ;; enable eyebrowse globally
  (eyebrowse-mode t))

(req-package window-numbering)

(req-package firefox-controller)

(req-package bbdb
  :init
  (setq bbdb-file (concat user-cache-directory "bbdb"))
  :config
  (bbdb-initialize))

;; setup loadpath later
(when (eq system-type 'darwin)
  (add-to-list 'load-path "/usr/local/Cellar/mu/HEAD/share/emacs/site-lisp/mu4e"))

(req-package mu4e
  :config
  ;; Use mu4e as default mail agent
  (setq mail-user-agent 'mu4e-user-agent)
  ;; Mail folder set to ~/Maildir
  (setq mu4e-maildir "~/Maildir")
  ;; Fetch mail by offlineimap
  (setq mu4e-get-mail-command "offlineimap")
  ;; Fetch mail in 60 sec interval
  (setq mu4e-update-interval 60)
  ;; Setup default mu4e search result mails list, if I want to see
  ;; more, use M-x `mu4e-headers-toggle-full-search' to make mi4e show all mails
  (setq mu4e-headers-results-limit 1000)
  ;; Make mu4e does not show the "Indexing..." message
  (setq mu4e-hide-index-messages t)
  (req-package mu4e-contrib
    :config
    (setq mu4e-html2text-command 'mu4e-shr2text)
    ;; try to emulate some of the eww key-bindings
    (add-hook 'mu4e-view-mode-hook
              (lambda ()
                (local-set-key (kbd "<tab>") 'shr-next-link)
                (local-set-key (kbd "<backtab>") 'shr-previous-link))))
  ;; SMTP setup
  (setq message-send-mail-function 'smtpmail-send-it
        smtpmail-stream-type 'starttls
        starttls-use-gnutls t)
  ;; don't save messages to Sent Messages, Gmail/IMAP takes care of this
  (setq mu4e-sent-messages-behavior 'delete)
  (setq coldnew/mu4e-account-alist
        '(("Gmail"
           (mu4e-sent-folder "/Gmail/Sent")
           (mu4e-drafts-folder "/Gmail/Drafts")
           (mu4e-trash-folder "/Gmail/Trash")
           (user-mail-address "coldnew.tw@gmail.com")
           (smtpmail-smtp-server "smtp.gmail.com")
           (smtpmail-smtp-service 587)
           (smtpmail-smtp-user "coldnew.tw@gmail.com")
           (user-full-name "Yen-Chin, Lee")
           (mu4e-compose-signature ""))))
  (defun coldnew/mu4e-set-default-account (account)
    "Setup the default account based on coldnew/mu4e-account-alist."
    (let* ((account (cdr (assoc account coldnew/mu4e-account-alist))))
      (when account (mapc #'(lambda (a)
                              (set (car a) (if (stringp (cadr a)) (cadr a) (eval (cadr a))))) account))))
  
  ;; set Gmail to default
  (coldnew/mu4e-set-default-account "Gmail")
  (defun coldnew/mu4e-set-account ()
    "Set the account for composing a message."
    (interactive)
    (let* ((account
            (if mu4e-compose-parent-message
                (let ((maildir (mu4e-msg-field mu4e-compose-parent-message :maildir)))
                  (string-match "/\\(.*?\\)/" maildir)
                  (match-string 1 maildir))
              (completing-read (format "Compose with account: (%s) "
                                       (mapconcat #'(lambda (var) (car var)) coldnew/mu4e-account-alist "/"))
                               (mapcar #'(lambda (var) (car var)) coldnew/mu4e-account-alist)
                               nil t nil nil (caar coldnew/mu4e-account-alist))))
           (account-vars (cdr (assoc account coldnew/mu4e-account-alist))))
      (if account-vars
          (mapc #'(lambda (var)
                    (set (car var) (cadr var)))
                account-vars))))
  
  (add-hook 'mu4e-compose-pre-hook 'coldnew/mu4e-set-account)
  (defun mu4e~view-fontify-diff ()
    "Colorize diff message."
    (interactive)
    (let ((inhibit-read-only t))
      (save-excursion
        (goto-char (point-min))
        ;; consider only lines that heuristically look like a citation line...
        (while (re-search-forward "^\\(\\(\\+\\)[^+]\\|\\(-\\)[^-]\\)" nil t)
          (let ((cur-point (or (match-beginning 2) (match-beginning 3)))
                (color (if (match-beginning 2)
                           "green"
                         "deep pink")))
            (end-of-line)
            (add-text-properties cur-point (point)
                                 `(face ((foreground-color . ,color))))))
        (goto-char (point-min))
        (while (re-search-forward "^\\(\\+\\+\\+\\|---\\)" nil t)
          (let ((cur-point (match-beginning 1)))
            (end-of-line)
            (add-text-properties cur-point (point)
                                 '(face ((weight . bold)))))))))
  
  (add-hook 'mu4e-view-mode-hook 'mu4e~view-fontify-diff)
  (bind-keys :map mu4e-view-mode-map
             ("C-f" . evil-scroll-page-down)
             ("C-b" . evil-scroll-page-up)))

(defun offlineimap-get-password (host port)
  (require 'netrc)
  (let* ((netrc (netrc-parse (expand-file-name "~/.authinfo.gpg")))
         (hostentry (netrc-machine netrc host port port)))
    (when hostentry (netrc-get hostentry "password"))))

(req-package erc
  :require (erc-notify)
  :config
  (progn
    ;; set prompt to ->>
    (setq erc-prompt "->> ")
    ;; Encoding with utf-8
    (setq erc-server-coding-system '(utf-8 . utf-8))
    ;; column with is 100
    (setq erc-fill-column 100)
    ;; Auto join irc server when erc start
    (erc-autojoin-mode t)
    ;; truncate too long line
    (erc-truncate-mode +1)
    ;; Interpret mIRC-style color commands in IRC chats
    (setq erc-interpret-mirc-color t)
    ;; Kill buffers for channels after /part
    (setq erc-kill-buffer-on-part t)
    ;; Kill buffers for private queries after quitting the server
    (setq erc-kill-queries-on-quit t)
    ;; Kill buffers for server messages after quitting the server
    (setq erc-kill-server-buffer-on-quit t)
    ;; open query buffers in the current window
    (setq erc-query-display 'buffer)
    (setq erc-save-buffer-on-part t)))

(setq erc-autojoin-channels-alist
      '(
        ;; english channel
        (".*\\.freenode.net" "#clojure" "#wayland" "#libhybris" "#webos-ports")
        (".*\\.mozilla.org" "#b2g")
        ;; Chinese channel
        (".*\\.freenode.net" "#emacs.tw" "#cschat.tw" "#clojure.tw" "#lisp.tw")))

(setq erc-hide-list
      '(;; notices
        "JOIN" "PART" "QUIT" "LEFT" "NICK"
        ;; robot
        "^j[a-z]*bot!" "^fussbot!"))

(erc-timestamp-mode 1)
(setq erc-insert-timestamp-function 'erc-insert-timestamp-left)

(req-package erc-hl-nicks)

(eval-after-load 'erc
  '(progn
     ;; enable track-mode
     (erc-track-mode t)
     ;; do not track some type of message
     (setq erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE"
                                     "324" "329" "332" "333" "353" "477"))))

(req-package erc-spelling
  :config
  (progn
    (erc-spelling-mode 0)))

(req-package erc-autoaway
  :config
  (progn
    (setq erc-auto-discard-away t)
    (setq erc-autoaway-idle-seconds 600)
    (setq erc-autoaway-use-emacs-idle t)))

(defun erc-start-or-switch ()
  "Connect to IRC, if already connected, switch to active irc buffer."
  (interactive)
  (let ((irc-active-p (and (fboundp 'erc-buffer-list)
                           (erc-buffer-list))))
    ;; we track irc.freenode.net to make sure erc is already active
    (if irc-active-p
        (erc-track-switch-buffer 1)
      (progn
        ;; connect to irc server
        (erc-tls :server "irc.freenode.net" :port 6697 :nick erc-nick)
        (erc-tls :server "irc.debian.org" :port 6697 :nick erc-nick)
        (erc-tls :server "irc.mozilla.org" :port 6697 :nick erc-nick)))))

(bind-keys :map global-map
           ("C-x C-s" . my/save-buffer-always)
           ("M-g" . avy-goto-char-2))

(bind-keys :map global-map
           ("C-=" . hydra-font-setup/body))

(bind-keys :map global-map
           ("M-1" . select-window-1)
           ("M-2" . select-window-2)
           ("M-3" . select-window-3)
           ("M-4" . select-window-4)
           ("M-5" . select-window-5)
           ("M-6" . select-window-6)
           ("M-7" . select-window-7)
           ("M-8" . select-window-8)
           ("M-9" . select-window-9)
           ("M-0" . select-window-0))

(global-unset-key (kbd "<down-mouse-1>"))
(global-unset-key (kbd "<mouse-1>"))
(global-unset-key (kbd "<down-mouse-3>"))
(global-unset-key (kbd "<mouse-3>"))

(req-package-finish)

(let ((secret "~/.personal.el"))
  (when (file-exists-p secret) (load-file secret)))