Emacs

[ Emacs ] 2015年init.el振り返り

More than 1 year has passed since last update.

去年(2015年)のinit.elを晒します

去年はメインマシンをWindowsからMacに移行した関係で、長年継ぎ足した秘伝の初期設定を捨て、ゼロベースでinit.elを作りなおしたりしました。(公開するの忘れたので2016年のこんなタイミングに…)

ちなみにEmacsのバージョンは24.4で、Macの端末上で稼働させています。

現在はメインエディタとしてVimも併用しているので、init.elの更新頻度は落ちていますが、Emacs好きは相変わらずです。VS CodeのキーバインドはEmacs寄りにしてみたり。

新しくinit.elを作成していると発見も多く、その中で特に便利だと感じた設定やプラグインなどについて説明していきます。(init.el全コードは最後に貼りました)

helm

言わずと知れたanythingの後継プラグインですね。そんなに特殊なことはやってないと思います。

  • 端末上でhelmインターフェースの起動キーをC-lにしたのが最初慣れなかった(元々WindowsのGUIで使っていたのでC-;を割り当てていたのですが、端末ではC-;が効かないので慣れるまで大変だった)
  • helm-swoopがライフチェンジングで震える
  • helm-agも爆速でいいですね(要The Silver Searcher)
  • ace-iserchからのhelm-swoop連携もすてき

smex

これが非常に便利!helm-M-xから乗り換えました。実際に使ってみないと良さが分からないかと思いますが、入力した端からガンガンあいまい検索がかかるのは脳汁出ます。ただマシンパワーを少々使う印象が。貧弱な環境ではご注意を。

multiverse

ファイルのスナップショットを取るやつですね。いくつかの実装をパパッと試したい時なんかに便利。

whitespace

タブやスペース、全角スペースなどを視覚化するプラグイン。これは好みだと思いますが、僕はファイルセーブ時の自動クリーンナップをオンにしています。

key-chord

キーマップ枯渇対策に無くてはならないプラグイン。ここらへんの設定が気に入ってます

キーマップ 挙動
jk同時押し ビューモードに移行
df同時押し helm-descbinds起動
c連続入力(cc) org-captureでメモをとる
u連続入力(uu) 直前に開いていたバッファに戻る
i連続入力(ii) カーソル上の単語を選択

個人的にはよく使うのですがおすすめできないのが11で「他のウィンドウをすべて閉じる」というやつです。11は普通に入力しますものねw

ただ上記の同時押し系や連続入力系はあまり英単語的に出てこないのでオススメです。

org-capture

僕はデザインから演出、3Dソフトから映像ソフト、JSやPythonなどのスクリプトなど、様々な業務を行うので、作業中の気付きをパパッとメモを取るときにorg-modeを多用しています。
ccでorg-captureを立ち上げ、その後頭文字を入力して各メモにアクセスしています。またそれらのメモはCopyというオンラインストレージサービスで同期しています。

(注) Copyはサービスクローズしちゃいました。DropBoxなどで同期すると良いかと思います。

magit

gitは端末から操作することが多かったのですが、magitよく出来てる!すてき!なので使ってみてはいかがでしょうか。

anzu

通常のquery-replace/query-replace-regexpを置き換えて使っています。置き換え結果が目視できて非常にいい感じ。

追記 thing-opt

昔から使っている拡張ですが、非常に便利なのでご紹介。Vimの素晴らしいところはテキストオブジェクトの扱いが非常に柔軟な点ですが、こちらを利用することでEmacsでもリージョン選択をより便利に行えるようになります。

以下全初期設定

改めて見ると1400行くらいなのでライトな方じゃないでしょうか。emacsclientでサーバを立ち上げて使ってるので起動の重さは感じませんが、初期起動は少し待つなーって感じはします。

※ 参考にさせていただいた書籍やブログなど、数多くを先達から学ばせていただきました。この場を借りてお礼申し上げます。

init.el
;; ------------------------------------------------------------------------
;; @ パスの設定

(setq org-capture-path "~/Copy/emacs/memo/")
(setq root-path "~/projects/dotfiles/.emacs.d/")

;; ------------------------------------------------------------------------
;; @ 曖昧文字幅の対策

(defun set-east-asian-ambiguous-width (width)
  (cond ((= emacs-major-version 22) (set-east-asian-ambiguous-width-22 width))
        ((> emacs-major-version 22) (set-east-asian-ambiguous-width-23 width))))

(defun set-east-asian-ambiguous-width-23 (width)
  (while (char-table-parent char-width-table)
         (setq char-width-table (char-table-parent char-width-table)))
  (let ((table (make-char-table nil)))
    (dolist (range
              '(#x00A1 #x00A4 (#x00A7 . #x00A8) #x00AA (#x00AD . #x00AE)
                (#x00B0 . #x00B4) (#x00B6 . #x00BA) (#x00BC . #x00BF)
                #x00C6 #x00D0 (#x00D7 . #x00D8) (#x00DE . #x00E1) #x00E6
                (#x00E8 . #x00EA) (#x00EC . #x00ED) #x00F0
                (#x00F2 . #x00F3) (#x00F7 . #x00FA) #x00FC #x00FE
                #x0101 #x0111 #x0113 #x011B (#x0126 . #x0127) #x012B
                (#x0131 . #x0133) #x0138 (#x013F . #x0142) #x0144
                (#x0148 . #x014B) #x014D (#x0152 . #x0153)
                (#x0166 . #x0167) #x016B #x01CE #x01D0 #x01D2 #x01D4
                #x01D6 #x01D8 #x01DA #x01DC #x0251 #x0261 #x02C4 #x02C7
                (#x02C9 . #x02CB) #x02CD #x02D0 (#x02D8 . #x02DB) #x02DD
                #x02DF (#x0300 . #x036F) (#x0391 . #x03A9)
                (#x03B1 . #x03C1) (#x03C3 . #x03C9) #x0401
                (#x0410 . #x044F) #x0451 #x2010 (#x2013 . #x2016)
                (#x2018 . #x2019) (#x201C . #x201D) (#x2020 . #x2022)
                (#x2024 . #x2027) #x2030 (#x2032 . #x2033) #x2035 #x203B
                #x203E #x2074 #x207F (#x2081 . #x2084) #x20AC #x2103
                #x2105 #x2109 #x2113 #x2116 (#x2121 . #x2122) #x2126
                #x212B (#x2153 . #x2154) (#x215B . #x215E)
                (#x2160 . #x216B) (#x2170 . #x2179) (#x2190 . #x2199)
                (#x21B8 . #x21B9) #x21D2 #x21D4 #x21E7 #x2200
                (#x2202 . #x2203) (#x2207 . #x2208) #x220B #x220F #x2211
                #x2215 #x221A (#x221D . #x2220) #x2223 #x2225
                (#x2227 . #x222C) #x222E (#x2234 . #x2237)
                (#x223C . #x223D) #x2248 #x224C #x2252 (#x2260 . #x2261)
                (#x2264 . #x2267) (#x226A . #x226B) (#x226E . #x226F)
                (#x2282 . #x2283) (#x2286 . #x2287) #x2295 #x2299 #x22A5
                #x22BF #x2312 (#x2460 . #x24E9) (#x24EB . #x254B)
                (#x2550 . #x2573) (#x2580 . #x258F) (#x2592 . #x2595)
                (#x25A0 . #x25A1) (#x25A3 . #x25A9) (#x25B2 . #x25B3)
                (#x25B6 . #x25B7) (#x25BC . #x25BD) (#x25C0 . #x25C1)
                (#x25C6 . #x25C8) #x25CB (#x25CE . #x25D1)
                (#x25E2 . #x25E5) #x25EF (#x2605 . #x2606) #x2609
                (#x260E . #x260F) (#x2614 . #x2615) #x261C #x261E #x2640
                #x2642 (#x2660 . #x2661) (#x2663 . #x2665)
                (#x2667 . #x266A) (#x266C . #x266D) #x266F #x273D
                (#x2776 . #x277F) (#xE000 . #xF8FF) (#xFE00 . #xFE0F)
                #xFFFD
                ))
      (set-char-table-range table range width))
    (optimize-char-table table)
    (set-char-table-parent table char-width-table)
    (setq char-width-table table)))

(set-east-asian-ambiguous-width 2)

;; ------------------------------------------------------------------------
;; @ 高速化

;; GCを減らして軽くする
(setq gc-cons-threshold (* 128 1024 1024))

;; スクロールバーを非表示に
(scroll-bar-mode -1)

;; ------------------------------------------------------------------------
;; @ 一般設定

;;; デバッグモードでの起動
(require 'cl)

;; 質問をy/nで回答する
(fset 'yes-or-no-p 'y-or-n-p)

;; load-path を追加する関数を定義
(defun add-to-load-path (&rest paths)
  (let (path)
    (dolist (path paths paths)
      (let ((default-directory
              (expand-file-name (concat user-emacs-directory path))))
        (add-to-list 'load-path default-directory)
        (if (fboundp 'normal-top-level-add-subdirs-to-load-path)
            (normal-top-level-add-subdirs-to-load-path))))))

;; 引数のディレクトリとそのサブディレクトリをload-pathに追加
(add-to-load-path "elisp" "conf" "public_repos")

;;; ファイル名の扱い
;; Mac OS Xの場合のファイル名の設定
(when (eq system-type 'darwin)
  (require 'ucs-normalize)
  (set-file-name-coding-system 'utf-8-hfs)
  (setq locale-coding-system 'utf-8-hfs))

;;; キー操作
;; C-mにnewline-and-indentを割り当てる。
(global-set-key (kbd "C-m") 'newline-and-indent)

;;; 文字コードを指定する
(set-language-environment "Japanese")
(prefer-coding-system 'utf-8)

;; ファイルサイズを表示
(size-indication-mode t)

;;; タブ文字の表示幅
;; TABの表示幅。初期値は8
(setq-default tab-width 4)
;; インデントにタブ文字を使用しない
(setq-default indent-tabs-mode nil)

;; C、C++、JAVA、PHPなどのインデント
(add-hook 'c-mode-common-hook
          '(lambda ()
             (c-set-style "bsd")))

;; emacs-lisp-mode-hook用の関数を定義
(defun elisp-mode-hooks ()
  "lisp-mode-hooks"
  (when (require 'eldoc nil t)
    (setq eldoc-idle-delay 0.2)
    (setq eldoc-echo-area-use-multiline-p t)
    (turn-on-eldoc-mode)))

;; emacs-lisp-modeのフックをセット
(add-hook 'emacs-lisp-mode-hook 'elisp-mode-hooks)

;; auto-installの設定
(when (require 'auto-install nil t)
  (setq auto-install-directory (concat root-path "elisp/"))
  (auto-install-update-emacswiki-package-name t)
  (auto-install-compatibility-setup))

(when (require 'redo+ nil t)
  (global-set-key (kbd "M-/") 'redo)
  )
(setq undo-no-redo t)           ;;Undo時に過去のUndoがRedoされないように設定
(setq undo-limit 600000)        ;;デフォルトでは20000
(setq undo-strong-limit 900000) ;;デフォルトでは30000

;; 編集履歴を記憶する undohist
;; undohistの設定
(when (require 'undohist nil t)
  (undohist-initialize))

;;end
;; ------------------------------------------------------------------------
;; @ MELPA
;; http://d.hatena.ne.jp/tomoya/20130519/1368942603

;; Lispパッケージマネージャの対象リポジトリにMELPAを追加
(when (require 'package nil t)
  (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/"))
  (add-to-list 'package-archives '("ELPA" . "http://tromey.com/elpa/"))
  (package-initialize))

;; ------------------------------------------------------------------------
;; @ clip boad
;; http://ta.com/tstomoki/items/24d63217f797c6929a23

;; ターミナルのみ適用
(when (eq window-system nil)
  (defun copy-from-osx ()
    (shell-command-to-string "pbpaste"))

  (defun paste-to-osx (text &optional push)
    (let ((process-connection-type nil))
      (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
        (process-send-string proc text)
        (process-send-eof proc))))

  (setq interprogram-cut-function 'paste-to-osx)
  (setq interprogram-paste-function 'copy-from-osx)
  )

;; ------------------------------------------------------------------------
;; @ helm
;; http://d.hatena.ne.jp/tomoya/20130519/1368942603

;;; helm
(require 'helm-config)
(helm-descbinds-mode)
(helm-mode 1)

;; ターミナルではC-;は使用できないためC-lに移植
(global-set-key (kbd "C-l") 'helm-mini)

;; C-x b で helm-for-files
(define-key global-map (kbd "C-x b") 'helm-for-files)

;; option+y で anything-show-kill-ring (非常に多用するのでM-yに変更)
(define-key global-map (kbd "M-y") 'helm-show-kill-ring)

;; http://qiita.com/scalper/items/aa98922a9e2b1db61e88
;; http://d.hatena.ne.jp/a_bicky/20140104/1388822688
(global-set-key (kbd "C-c d") 'helm-descbinds)
(global-set-key (kbd "C-c b") 'helm-bookmarks) ;helm-buffers-listはC-l(helm-mini)で代用できるため差し替え
(global-set-key (kbd "C-c o") 'helm-swoop) ;helm-"o"ccurの後継ということでこのキーバインドに
(global-set-key (kbd "C-c s") 'helm-ag)
(global-set-key (kbd "C-c r") 'helm-recentf) ;cmd+Zにレジュームを割り当てたので、recentf(最近使ったファイル)はC-c rに
(key-chord-define-global "rr" 'helm-recentf) ;多用するのでrrでrecentfを起動できるように
(global-set-key (kbd "C-c i") 'helm-imenu)
(global-set-key (kbd "M-z") 'helm-resume) ;レジューム(1つ前のhelmに戻る)のはよく使うため、cmd+Zで使えるようにした

(setq helm-idle-delay 0.3
      helm-candidate-number-limit 100
      helm-su-or-sudo "sudo"
      helm-allow-skipping-current-buffer nil)

;; http://ongaeshi.hatenablog.com/entry/ace-isearch
(require 'ace-isearch)
(global-ace-isearch-mode +1)
;; 検索文字数が6文字を超えたら自動的にhelm-swoopに移行(デフォルト
;; (setq ace-isearch-use-function-from-isearch nil)
(define-key isearch-mode-map (kbd "M-o") 'helm-multi-swoop-all-from-isearch)

;; http://rubikitch.com/2014/12/25/helm-swoop/
(require 'helm-migemo)
(eval-after-load "helm-migemo"
  '(defun helm-compile-source--candidates-in-buffer (source)
     (helm-aif (assoc 'candidates-in-buffer source)
         (append source
                 `((candidates
                    . ,(or (cdr it)
                           (lambda ()
                             ;; Do not use `source' because other plugins
                             ;; (such as helm-migemo) may change it
                             (helm-candidates-in-buffer (helm-get-current-source)))))
                   (volatile) (match identity)))
       source)))

;; helmコマンド内のキーバインド
;; http://qiita.com/masa86/items/9829363279108f10e7b6
(define-key helm-map (kbd "C-h") 'delete-backward-char)
(define-key helm-read-file-map (kbd "C-h") 'delete-backward-char)
(define-key helm-find-files-map (kbd "C-h") 'delete-backward-char)

;; Emulate `kill-line' in helm minibuffer
;; http://d.hatena.ne.jp/a_bicky/20140104/1388822688
(setq helm-delete-minibuffer-contents-from-point t)
(defadvice helm-delete-minibuffer-contents (before helm-emulate-kill-line activate)
  "Emulate `kill-line' in helm minibuffer"
  (kill-new (buffer-substring (point) (field-end))))

;; ------------------------------------------------------------------------
;; @ smex
;; あいまい検索できるM-x検索システム(helmより便利なので乗り換え)絞り込んできたらC-s/C-rで。先頭のものが選ばれる
;; http://rubikitch.com/2014/12/16/smex/

(smex-initialize)
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "M-X") 'smex-major-mode-commands)

;; ------------------------------------------------------------------------
;; @ foreign-regexp
;; http://yo.eki.do/notes/foreign-regexp-el
;; HHでanzu-query-replace-regexpでを起動。\(hoge\) -> \1mojaでインタラクティブに置換結果がhogemojaになる

(require 'foreign-regexp)

(custom-set-variables
'(foreign-regexp/regexp-type 'ruby) ;; Choose your taste of foreign regexp
                                    ;; from 'perl, 'ruby or 'javascript.
'(reb-re-syntax 'foreign-regexp))   ;; Tell re-builder to use foreign regex.

;; ------------------------------------------------------------------------
;; @ scratch-log
;; スクラッチバッファのログをとるプラグイン

(require 'scratch-log)
(setq sl-scratch-log-file (concat root-path "scratchlog/scratch-log.org"))
(setq sl-prev-scratch-string-file (concat root-path "scratchlog/scratch-log-prev.org"))

(setq sl-restore-scratch-p nil)
(setq sl-prohibit-kill-scratch-buffer-p nil)

;; ------------------------------------------------------------------------
;; @ sequential-command
;; 同じコマンドを連続実行した時の振る舞いを変更する
;; C-a : 行頭→文頭→元の位置→行頭…とトグル
;; C-e : 行末→文末→元の位置→行末…とトグル
;; M-u : 直前の単語を順次大文字にする
;; M-l : 直前の単語を順次小文字にする
;; M-c : 直前の単語を順次キャメライズ

(require 'sequential-command-config)
(sequential-command-setup-keys)

;; ------------------------------------------------------------------------
;; @ htmlize
;; http://yohshiy.blog.fc2.com/blog-entry-8.html

(autoload 'htmlize-buffer "htmlize" "Convert BUFFER to HTML, preserving colors and decorations." t)
(autoload 'htmlize-region "htmlize" "Convert the region to HTML, preserving colors and decorations." t)
(autoload 'htmlize-file "htmlize" "Load FILE, fontify it, convert it to HTML, and save the result." t)

;; ------------------------------------------------------------------------
;; @ quickrun
;; http://aikotobaha.blogspot.jp/2013/04/popwinel.html
;; ポップアップウィンドウはC-gで消すことができる

(require 'popwin)
(setq display-buffer-function 'popwin:display-buffer)
(setq popwin:popup-window-position 'bottom)

;; popwin対象
(push '("*quickrun*") popwin:special-display-config)

;; ------------------------------------------------------------------------
;; @ quickrun
;; http://blog.bokuweb.me/entry/emcas-nyumon

(require 'quickrun)

;; coffeeなどで出力されたJSを見るときなど
(global-set-key "\C-cc" 'quickrun-compile-only)

;; ファイルを実行する
(global-set-key (kbd "<f10>") 'quickrun)

;; ------------------------------------------------------------------------
;; @ yasnippet
;; http://fukuyama.co/yasnippet

(require 'yasnippet)
(setq snippet-path (concat root-path "snippets"))
(setq yas-snippet-dirs
      '(snippet-path))
(yas-global-mode 1)

;; http://j.mp/1Sep7Nh
(define-key yas-minor-mode-map (kbd "TAB") 'yas-expand)

;; 既存スニペットを挿入する
(define-key yas-minor-mode-map (kbd "C-x i i") 'yas-insert-snippet)
;; 新規スニペットを作成するバッファを用意する
(define-key yas-minor-mode-map (kbd "C-x i n") 'yas-new-snippet)
;; 既存スニペットを閲覧・編集する
(define-key yas-minor-mode-map (kbd "C-x i v") 'yas-visit-snippet-file)

;; http://d.hatena.ne.jp/syohex/20121207/1354885367
(defun my-yas/prompt (prompt choices &optional display-fn)
  (let* ((names (loop for choice in choices
                      collect (or (and display-fn (funcall display-fn choice))
                                  choice)))
         (selected (helm-other-buffer
                    `(((name . ,(format "%s" prompt))
                       (candidates . names)
                       (action . (("Insert snippet" . (lambda (arg) arg))))))
                    "*helm yas/prompt*")))
    (if selected
        (let ((n (position selected names :test 'equal)))
          (nth n choices))
      (signal 'quit "user quit!"))))
(custom-set-variables '(yas/prompt-functions '(my-yas/prompt)))

;; yas/chooseを使えるように。
(require 'dropdown-list)
(setq yas/prompt-functions '(yas/dropdown-prompt
                             yas/ido-prompt
                             yas/completing-prompt))

;; ------------------------------------------------------------------------
;; @ recentf-ext
;;履歴拡張(ディレクトリも履歴に含める)
;; http://d.hatena.ne.jp/rubikitch/20091224/recentf
;; http://qiita.com/catatsuy/items/f9fad90fa1352a4d3161

(require 'recentf-ext)
(setq recentf-max-saved-items 500)
(setq recentf-exclude '("/TAGS$" "/var/tmp/" "/.emacs.d/"))

;; ------------------------------------------------------------------------
;; @ fringe

;; 現在行をハイライト
;; http://d.hatena.ne.jp/tm_tn/20110605/1307238416
(require 'hlinum)
(hlinum-activate)

(custom-set-variables
 '(global-linum-mode t))

;; 行番号のフォーマット
(setq linum-format "%5d ")

;; linumに起因する高速化
;; http://qiita.com/takc923/items/acebbdae04994de16c6d
(setq linum-delay t)
(defadvice linum-schedule (around my-linum-schedule () activate)
  (run-with-idle-timer 0.2 nil #'linum-update-current))

(custom-set-faces
 '(linum-highlight-face ((t (:foreground "color-248"
                                         :background nil)))))

;; ------------------------------------------------------------------------
;; @ modeline

;; 行番号の表示
(line-number-mode t)

;; 列番号の表示
(column-number-mode t)

;; 時刻の表示
(require 'time)
(setq display-time-24hr-format t)
(setq display-time-string-forms '(24-hours ":" minutes))
(display-time-mode t)

;; ------------------------------------------------------------------------
;; @ cursor

;; カーソル点滅表示(GUIのみ効く)
(blink-cursor-mode 1)

;; スクロール時のカーソル位置の維持
(setq scroll-preserve-screen-position t)

;; スクロール行数(一行ごとのスクロール)
(setq vertical-centering-font-regexp ".*")
(setq scroll-conservatively 35)
(setq scroll-margin 0)
(setq scroll-step 1)

;; 画面スクロール時の重複行数
(setq next-screen-context-lines 1)

;; ------------------------------------------------------------------------
;; @ default setting

;; ⌘キーがメタキーとして解釈される
;; http://qiita.com/hayamiz/items/0f0b7a012ec730351678
(when (eq system-type 'darwin)
  (setq ns-command-modifier (quote meta)))

;; 起動メッセージの非表示
(setq inhibit-startup-message t)

;; スタートアップ時のエコー領域メッセージの非表示
(setq inhibit-startup-echo-area-message -1)

;;BackSpaceを有効に(isearch時にも効くように)
(define-key key-translation-map (kbd "C-h") (kbd "<DEL>"))

;; ビープ音を消す
(setq visible-bell t)
(setq ring-bell-function 'ignore)

;; 現在行をセンタリングして再描画 : C-lをhelmで潰したためC-M-lに変更
;; (多用するためC-x C-lは破棄)
(global-set-key (kbd "C-M-l") 'recenter-top-bottom)

;; C-k 1回で行全体を削除する
(setq kill-whole-line t)

;;キルリングカスタマイズ(  "ポイントが空行ならキルリングに追加しない")
(defun my-kill-or-delete-line ()
  "ポイントが空行ならキルリングに追加しない"
  (interactive)
  (if (and (bolp) (eolp)) ;お気に入り
      (my-delete-line)
    (my-kill-line)))
;; kill-line から置換
(defun my-delete-line (&optional arg)
  (interactive "P")
  (delete-region (point)
                 (progn
                   (if arg
                       (forward-visible-line (prefix-numeric-value arg))
                     (if (eobp)
                         (signal 'end-of-buffer nil))
                     (let ((end
                            (save-excursion
                              (end-of-visible-line) (point))))
                       (if (or (save-excursion
                                 (unless show-trailing-whitespace
                                   (skip-chars-forward " \t" end))
                                 (= (point) end))
                               (and kill-whole-line (bolp)))
                           (forward-visible-line 1)
                         (goto-char end))))
                   (point))))
(global-set-key (kbd "C-k") 'my-kill-or-delete-line)

;;my-kill-line(C-u C-k)
(defun my-kill-line ()
  "C-u C-k でキルリングに入れない"
  (interactive)
  (if current-prefix-arg
      (delete-region (point)
                     (save-excursion (end-of-line) (point)))
    (kill-line)))

;;C-h(BackSpace)でリージョンを一括削除
(delete-selection-mode 1)

;;ツールバーを非表示に
(tool-bar-mode nil)

;;*scratch* で最初に書かれる message を消す
(setq initial-scratch-message "")

;; システムへ修飾キーを渡さない
(setq ns-command-modifier (quote meta))
(setq ns-alternate-modifier (quote super))

;; cua-modeを廃止して24.4のビルトインを利用する
;; http://rubikitch.com/2014/10/23/emacs244-package-news/
(global-set-key (kbd "C-x SPC") 'cua-rectangle-mark-mode)

(defadvice cua-sequence-rectangle (around my-cua-sequence-rectangle activate)
  "連番を挿入するとき、カーソルの文字を上書きしないで左にずらす"
  (interactive
   (list (if current-prefix-arg
             (prefix-numeric-value current-prefix-arg)
           (string-to-number
            (read-string "Start value: (0) " nil nil "0")))
         (string-to-number
          (read-string "Increment: (1) " nil nil "1"))
         (read-string (concat "Format: (" cua--rectangle-seq-format ") "))))
  (if (= (length format) 0)
      (setq format cua--rectangle-seq-format)
    (setq cua--rectangle-seq-format format))
  (cua--rectangle-operation 'clear nil t 1 nil
                            '(lambda (s e l r)
                               (kill-region s e)
                               (insert (format format first))
                               (yank)
                               (setq first (+ first incr)))))

;; 関数内の強調表示
(show-paren-mode 1)
(setq show-paren-delay 0)
(setq show-paren-style 'expression)
;; (set-face-attribute 'show-paren-match-face nil :background "#0d5e56" :foreground "#ffffff") ;railscastテーマのとき
(set-face-attribute 'show-paren-match-face nil :background "color-237" :foreground "#ffffff")

;; mini-bufferでヤンクできるように
(define-key isearch-mode-map "\C-y" 'isearch-yank-kill)

;; 選択範囲をisearch
(defadvice isearch-mode (around isearch-mode-default-string (forward &optional regexp op-fun recursive-edit word-p) activate)
  (if (and transient-mark-mode mark-active (not (eq (mark) (point))))
      (progn
        (isearch-update-ring (buffer-substring-no-properties (mark) (point)))
        (deactivate-mark)
        ad-do-it
        (if (not forward)
            (isearch-repeat-backward)
          (goto-char (mark))
          (isearch-repeat-forward)))
    ad-do-it))

;;yankした文字列をハイライト表示する
(defadvice yank (after ys:highlight-string activate)
  (let ((ol (make-overlay (mark t) (point))))
    (overlay-put ol 'face 'highlight)
    (sit-for 0.5)
    (delete-overlay ol)))
(defadvice yank-pop (after ys:highlight-string activate)
  (when (eq last-command 'yank)
    (let ((ol (make-overlay (mark t) (point))))
      (overlay-put ol 'face 'highlight)
      (sit-for 0.5)
      (delete-overlay ol))))

;; 折り返し表示ON/OFF
(defun toggle-truncate-lines ()
  "折り返し表示をトグル動作します."
  (interactive)
  (if truncate-lines
      (setq truncate-lines nil)
    (setq truncate-lines t))
  (recenter))
(global-set-key (kbd "C-c C-l") 'toggle-truncate-lines)

;; C-u C-SPC C-SPC C-SPC... のように C-SPC を連続で入力するだけで,連続でマークを辿れるように
(setq set-mark-command-repeat-pop t)

;; キーストロークをエコーエリアに表示する時間を短く
(setq echo-keystrokes 0.1)

;; 動的略称モードを起動時にON
(setq-default abbrev-mode t)

;; 文字列で展開が聞かない時などは任意のタイミングで動的略語展開を行う
(global-set-key (kbd "C-c e") 'dabbrev-expand)
(define-key minibuffer-local-map (kbd "C-c e") 'dabbrev-expand)

;; 静的略称モードは不要
;; (read-abbrev-file "~/abbrev_defs")
;; (setq save-abbrevs t)

;; ブックマークを変更したら即保存する
(setq bookmark-save-flag 1)
;; 使用したブックマークを上位に
(progn
  (setq bookmark-sort-flag nil)
  (defun bookmark-arrange-latest-top ()
    (let ((latest ( bookmark-get-bookmark bookmark)))
      (setq bookmark-alist (cons latest (delq latest bookmark-aliset))))
    (bookmark-save))
  (add-hook 'bookmark-after-jump-hook 'bookmark-arrange-latest-top))

;; 改行コード(^M)を改行に置き換え
(defun replace-line-feed-code()
  (interactive)
  (beginning-of-buffer)
  (replace-string "
" "
")
  )

;; ------------------------------------------------------------------------
;; @ multiverse
;; 現在のファイルのスナップショットを取る
;; http://d.hatena.ne.jp/rubikitch/20081218/multiverse

;; M-x multiverse-storeで名前をつけてスナップショットを保存する。
;; M-x multiverse-restoreで保存したスナップショットに戻る。undoも効くから取り消すこともできる。
;; M-x multiverse-forgetでスナップショットを削除する。これは選択後にやろう。
;; M-x multiverse-diff-currentとM-x multiverse-diff-otherはスナップショットとのdiffを取る
(require 'multiverse)

;; C-x C-sで通常のセーブ、C-u C-x C-sでスナップショット作成(multiverse-store)
(defun my-save-buffer (arg)
  (interactive "P")
  (if arg
      (multiverse-store)
    (save-buffer)))
(global-set-key (kbd "C-x C-s") 'my-save-buffer)  ;; ストリングを選択

;; end
;; ------------------------------------------------------------------------
;; @ dired

;;diredで削除したときにゴミ箱へ移動させる
(setq delete-by-moving-to-trash t)

;; dired-modeでもC-tでバッファ切り替えを実装(C-t ...は潰す)
(define-key dired-mode-map (kbd "C-t") 'other-window-or-split)

;;diredの機能を拡張する(C-x C-jで現在のカレントディレクトリでdiredを一発起動など)
(load "dired-x")

;; サイズ表記をMB単位で
(setq dired-listing-switches "-alh")

;; dired-modeで.zipで終わるファイルをZキーで展開できるように
(add-to-list 'dired-compress-file-suffixes '("\\.zip\\'" ".zip" "unzip"))

;; diredでマークをつけたファイルを開く(E-dit)
(eval-after-load "dired"
  '(progn
     (define-key dired-mode-map (kbd "E") 'my-dired-find-marked-files)
     (defun my-dired-find-marked-files (&optional arg)
       "Open each of the marked files, or the file under the point, or when prefix arg, the next N files "
       (interactive "P")
       (let* ((fn-list (dired-get-marked-files nil arg)))
         (mapc 'find-file fn-list)))))

;; diredでマークをつけたファイルをviewモードで開く(V-iew)
(eval-after-load "dired"
  '(progn
     (define-key dired-mode-map (kbd "V") 'my-dired-view-marked-files)
     (defun my-dired-view-marked-files (&optional arg)
       "Open each of the marked files, or the file under the point, or when prefix arg, the next N files "
       (interactive "P")
       (let* ((fn-list (dired-get-marked-files nil arg)))
         (mapc 'view-file fn-list)))))

;;wdiredをオンに(diredモード時にrで起動)
;;C-c C-c(C-x C-s)で変更確定/C-x C-k(C-x Esc)でキャンセル
(require 'wdired)
(define-key dired-mode-map "r" 'wdired-change-to-wdired-mode)

;;dired-mode時、スペース(SPACE)でマークをトグル (デフォルトではm,uを使い分ける必要がある)
(define-key dired-mode-map " " 'dired-toggle-mark)
(defun dired-toggle-mark (arg)
  "Toggle the current (or next ARG) files."
  (interactive "P")
  (let ((dired-marker-char
         (if (save-excursion (beginning-of-line)
                             (looking-at " "))
             dired-marker-char ?\040)))
    (dired-mark arg)
    (dired-previous-line 1)))

;; ファイル名のみ表示をトグル
(add-hook 'dired-mode-hook 'dired-hide-details-mode)
(define-key dired-mode-map (kbd "C-c h") 'dired-hide-details-mode)

;; 2ペインのdiredを使用しているとき、他方のディレクトリにペーストする
;; http://keens.github.io/blog/2013/10/04/emacs-dired/
(setq dired-dwim-target t)

;; ------------------------------------------------------------------------
;; @ neotree
;; http://kiririmode.hatenablog.jp/entry/20150806/1438786800

(require 'neotree)
(global-set-key [f8] 'neotree-toggle)

;; 隠しファイルをデフォルトで表示
(setq neo-show-hidden-files t)

;; neotree でファイルを新規作成した後、自動的にファイルを開く
(setq neo-create-file-auto-open t)

;; delete-other-window で neotree ウィンドウを消さない
(setq neo-persist-show t)

;; キーバインドをシンプルにする
(setq neo-keymap-style 'concise)

;; neotree ウィンドウを表示する毎に current file のあるディレクトリを表示する
(setq neo-smart-open t)

;; たぶんまだ動かない https://github.com/jaypei/emacs-neotree/issues/105
(setq neo-vc-integration '(face char))

;; popwin との共存
(when neo-persist-show
  (add-hook 'popwin:before-popup-hook
            (lambda () (setq neo-persist-show nil)))
  (add-hook 'popwin:after-popup-hook
            (lambda () (setq neo-persist-show t))))

;; ------------------------------------------------------------------------
;; @ smartrep
;; 連続操作のプリフィックスキーを省略する
;; http://sheephead.homelinux.org/2011/12/19/6930/

(require 'smartrep)
;; Org-modeのキーバインド設定
(smartrep-define-key
    org-mode-map "C-c" '(("C-n" . (outline-next-visible-heading 1))
                         ("C-p" . (outline-previous-visible-heading 1))))

;; org-mode C-c C-xをプリフィックスキーとして、C-n/C-pでリンク移動
(smartrep-define-key
    org-mode-map "C-c C-x" '(("C-n" . (org-next-link))
                             ("C-p" . (org-previous-link))))

;; dired-modeのキーバインド設定
(smartrep-define-key
    dired-mode-map "C-x" '(("C-j" . (dired-jump))
                           ))

;; ------------------------------------------------------------------------
;; @ whitespace
;; http://qiita.com/itiut@github/items/4d74da2412a29ef59c3a
;; http://d.hatena.ne.jp/syohex/20110119/1295450495

(require 'whitespace)
(setq whitespace-style '(face           ; faceで可視化
                         trailing       ; 行末
                         tabs           ; タブ
                         spaces         ; スペース
                         empty          ; 先頭/末尾の空行
                         space-mark     ; 表示のマッピング
                         tab-mark
                         ))

(setq whitespace-display-mappings
      '((space-mark ?\u3000 [?\u25a1])
        ;; WARNING: the mapping below has a problem.
        ;; When a TAB occupies exactly one column, it will display the
        ;; character ?\xBB at that column followed by a TAB which goes to
        ;; the next TAB column.
        ;; If this is a problem for you, please, comment the line below.
        (tab-mark ?\t [?\u00BB ?\t] [?\\ ?\t])))

;; スペースは全角のみを可視化
(setq whitespace-space-regexp "\\(\u3000+\\)")

;; 保存前に自動でクリーンアップ
(setq whitespace-action '(auto-cleanup))

(global-whitespace-mode 1)

(defvar my/bg-color "#232323")
(set-face-attribute 'whitespace-trailing nil
                    :background my/bg-color
                    :foreground "DeepPink"
                    :underline t)
(set-face-attribute 'whitespace-tab nil
                    :background my/bg-color
                    :foreground "LightSkyBlue"
                    :underline t)
(set-face-attribute 'whitespace-space nil
                    :background my/bg-color
                    :foreground "GreenYellow"
                    :weight 'bold)
(set-face-attribute 'whitespace-empty nil
                    :background my/bg-color)

;; markdown-modeでは自動クリーンナップを発動させない
(add-hook 'markdown-mode-hook
          '(lambda ()
             (set (make-local-variable 'whitespace-action) nil)))

;; ------------------------------------------------------------------------
;; @ key chord

;;key-chode.elを使用して同時押しでコマンドを実行する
(require 'key-chord)
(setq key-chord-two-keys-delay 0.04)
(key-chord-mode 1)
(key-chord-define-global "jk" 'view-mode)            ;;jk同時押しでview-modeのトグル
(key-chord-define-global "df" 'helm-descbinds)       ;;df同時押しでhelm-descbinds起動
(key-chord-define-global "11" 'delete-other-windows) ;;他のウィンドウを閉じる(C-x 1)
(key-chord-define-global "cc" 'org-capture)          ;;org-captureでメモをとる
(key-chord-define-global "sn" 'snippet-mode)         ;;snippetモード
(key-chord-define-global "kk" 'mark-filename)        ;;ファイルパスを選択
(key-chord-define-global "uu" '(lambda ()            ;;直前に開いていたバッファに戻る
                                 (interactive)
                                 (switch-to-buffer nil)))

;; key-chord.el の input-method-function が勝手に nil にされることがあるので修正
;; http://d.hatena.ne.jp/grandVin/20080917/1221653750
(defadvice toggle-input-method (around toggle-input-method-around activate)
  (let ((input-method-function-save input-method-function))
    ad-do-it
    (setq input-method-function input-method-function-save)))

;; view-modeのモードライン設定
(require 'viewer)
(viewer-stay-in-setup)
(setq viewer-modeline-color-unwritable "tomato"
      viewer-modeline-color-view "orange")
(viewer-change-modeline-color-setup)

;; 書き込み不能なファイルはview-modeで開くように
(defadvice find-file
    (around find-file-switch-to-view-file (file &optional wild) activate)
  (if (and (not (file-writable-p file))
           (not (file-directory-p file)))
      (view-file file)
    ad-do-it))

;; 書き込み不能な場合はview-modeを抜けないように
(defvar view-mode-force-exit nil)
(defmacro do-not-exit-view-mode-unless-writable-advice (f)
  `(defadvice ,f (around do-not-exit-view-mode-unless-writable activate)
     (if (and (buffer-file-name)
              (not view-mode-force-exit)
              (not (file-writable-p (buffer-file-name))))
         (message "File is unwritable, so stay in view-mode.")
       ad-do-it)))
(do-not-exit-view-mode-unless-writable-advice view-mode-exit)
(do-not-exit-view-mode-unless-writable-advice view-mode-disable)

;;リージョン選択機能の拡張(単語選択など)
(require 'thing-opt)
(define-thing-commands)
(key-chord-define-global "ii" 'mark-word*)   ;; i連続押しで現在の単語を選択
(global-set-key (kbd "C-c 2") 'mark-string)  ;; ストリングを選択
(global-set-key (kbd "C-c 8") 'mark-up-list) ;; リスト(...)を選択
(global-set-key (kbd "C-c 7") 'mark-symbol)  ;; シンボル'...を選択(シングルクォート)

;; 突然の死
(require 'sudden-death)
(key-chord-define-global "sd" 'sudden-death)

;; ------------------------------------------------------------------------
;; @ backup

;; オートセーブOff
(setq auto-save-default nil)

;; バックアップファイルを作らない
(setq backup-inhibited t)

;; 変更ファイルのバックアップ
(setq make-backup-files nil)

;; 変更ファイルの番号つきバックアップ
(setq version-control nil)

;; 編集中ファイルのバックアップ
(setq auto-save-list-file-name nil)
(setq auto-save-list-file-prefix nil)

;; ロックファイルを生成しない
(setq create-lockfiles nil)

;; ------------------------------------------------------------------------
;; @ key bind

;; 標準キーバインド変更
(global-set-key "\C-z"          'scroll-down)

;; ------------------------------------------------------------------------
;; @ window

;; http://d.hatena.ne.jp/rubikitch/20100210/emacs
(defun other-window-or-split ()
  (interactive)
  (when (one-window-p)
    (split-window-horizontally))
  (other-window 1))

(global-set-key (kbd "C-t") 'other-window-or-split)

;; ------------------------------------------------------------------------
;; @ migemo

;; http://weblog.ymt2.net/blog/html/2013/08/23/install_migemo_to_emacs_24_3_1.html
(require 'migemo)
(setq migemo-command "/usr/local/bin/cmigemo")
(setq migemo-options '("-q" "--emacs"))
(setq migemo-dictionary "/usr/local/share/migemo/utf-8/migemo-dict")
(setq migemo-user-dictionary nil)
(setq migemo-coding-system 'utf-8)
(setq migemo-regex-dictionary nil)
(load-library "migemo")
(migemo-init)

;; ------------------------------------------------------------------------
;; @ auto-complete

(when (require 'auto-complete-config nil t)
  (add-to-list 'ac-dictionary-directories
               (concat root-path "ac-dict"))
  (define-key ac-mode-map (kbd "M-TAB") 'auto-complete)
  (ac-config-default))

(setq ac-auto-show-menu 0.1)                            ;; 0.1秒後に自動で表示
(define-key ac-completing-map (kbd "C-p") 'ac-previous) ;;M-pから変更
(define-key ac-completing-map (kbd "C-n") 'ac-next)     ;;M-nから変更
(define-key ac-completing-map (kbd "C-i") nil)          ;;C-iで決定されないよう設定(C-iでyasnippetを実行)
(add-to-list 'ac-modes 'html-mode)                      ;; html-modeでac-modeを有効に
(add-to-list 'ac-modes 'org-mode)                       ;; org-modeでac-modeを有効に
(add-to-list 'ac-modes 'coffee-mode)                    ;; coffee-modeでac-modeを有効に

;;auto-complete表示中にC-iが押された場合は、auto-completeを中断してyasnippetを展開する
(define-key ac-completing-map (kbd "C-i")
  (progn 'ac-stop
         'yas/expand))

;; カラー設定
(set-face-background 'ac-completion-face "#ffffff")  ;保管中のカーソルカラー
(set-face-foreground 'ac-candidate-face "#111111")   ;候補テキストカラー
(set-face-background 'ac-candidate-face "color-246") ;候補背景カラー
(set-face-background 'ac-selection-face "color-60")  ;選択中の帯
(set-face-foreground 'popup-summary-face "white")    ;; 候補のサマリー部分
(set-face-background 'popup-tip-face "color-233")    ;; ドキュメント部分
(set-face-foreground 'popup-tip-face "color-249")

;; ------------------------------------------------------------------------
;; @ web-mode
;; http://fukuyama.co/web-mode

(require 'web-mode)

;;; 適用する拡張子
(add-to-list 'auto-mode-alist '("\\.phtml$"     . web-mode))
(add-to-list 'auto-mode-alist '("\\.tpl\\.php$" . web-mode))
(add-to-list 'auto-mode-alist '("\\.jsp$"       . web-mode))
(add-to-list 'auto-mode-alist '("\\.as[cp]x$"   . web-mode))
(add-to-list 'auto-mode-alist '("\\.erb$"       . web-mode))
(add-to-list 'auto-mode-alist '("\\.html?$"     . web-mode))

;;; インデント数
(defun web-mode-hook ()
  "Hooks for Web mode."
  (setq web-mode-html-offset   2)
  (setq web-mode-css-offset    2)
  (setq web-mode-script-offset 2)
  (setq web-mode-php-offset    2)
  (setq web-mode-java-offset   2)
  (setq web-mode-asp-offset    2))
(add-hook 'web-mode-hook 'web-mode-hook)

;; ------------------------------------------------------------------------
;; @ css-mode

;; rainbow-mode
(add-hook 'css-mode-hook 'rainbow-mode)

;; ------------------------------------------------------------------------
;; @ org-mode

(require 'org-install)
(setq org-startup-truncated nil)
(setq org-return-follows-link t)
(add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
(setq org-directory org-capture-path)
(setq org-default-notes-file (concat org-directory "notes.org"))
(setq org-capture-templates
      '(("t" "Todo" entry
         (file+headline nil "TODO")
         "** %?\n   %i\n   %a\n   %t")
("n" "Notes" entry
         (file+headline nil "Notes")
         "** %?\n   %i\n   %a\n   %t")
("e" "Emacs" entry
         (file+headline (concat org-capture-path "emacs.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("s" "Shell" entry
         (file+headline (concat org-capture-path "shell.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("l" "MayaLT" entry
         (file+headline (concat org-capture-path "maya.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("m" "Modo" entry
         (file+headline (concat org-capture-path "modo.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("c" "C4D" entry
         (file+headline (concat org-capture-path "c4d.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("a" "AE" entry
         (file+headline (concat org-capture-path "ae.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("z" "Zbrush" entry
         (file+headline (concat org-capture-path "zbrush.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("j" "JS" entry
         (file+headline (concat org-capture-path "js.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")
("p" "Python" entry
         (file+headline (concat org-capture-path "python.org") "Contents")
         "** %?\n   %i\n   %a\n   %t")))

;; quickrunとバッティングするのでコメントアウト、org-captureはccで行う
;; (global-set-key (kbd "C-c c") 'org-capture)

(key-combo-define org-mode-map ":"  '(" : " ":"))
(key-combo-define org-mode-map ">"  '(" > " ">"))

;; ショートカット
(define-key org-mode-map [(control up)] 'outline-previous-visible-heading)
(define-key org-mode-map [(control down)] 'outline-next-visible-heading)

;; org-mode( M-p/M-n見えている範囲内でリンクの行き来 )
(defun org-next-visible-link ()
  "Move forward to the next link.
If the link is in hidden text, expose it."
  (interactive)
  (when (and org-link-search-failed (eq this-command last-command))
    (goto-char (point-min))
    (message "Link search wrapped back to beginning of buffer"))
  (setq org-link-search-failed nil)
  (let* ((pos (point))
         (ct (org-context))
         (a (assoc :link ct))
         srch)
    (if a (goto-char (nth 2 a)))
    (while (and (setq srch (re-search-forward org-any-link-re nil t))
                (goto-char (match-beginning 0))
                (prog1 (not (eq (org-invisible-p) 'org-link))
                  (goto-char (match-end 0)))))
    (if srch
        (goto-char (match-beginning 0))
      (goto-char pos)
      (setq org-link-search-failed t)
      (error "No further link found"))))
(defun org-previous-visible-link ()
  "Move backward to the previous link.
If the link is in hidden text, expose it."
  (interactive)
  (when (and org-link-search-failed (eq this-command last-command))
    (goto-char (point-max))
    (message "Link search wrapped back to end of buffer"))
  (setq org-link-search-failed nil)
  (let* ((pos (point))
         (ct (org-context))
         (a (assoc :link ct))
         srch)
    (if a (goto-char (nth 1 a)))
    (while (and (setq srch (re-search-backward org-any-link-re nil t))
                (goto-char (match-beginning 0))
                (not (eq (org-invisible-p) 'org-link))))
    (if srch
        (goto-char (match-beginning 0))
      (goto-char pos)
      (setq org-link-search-failed t)
      (error "No further link found"))))
(define-key org-mode-map "\M-n" 'org-next-visible-link)
(define-key org-mode-map "\M-p" 'org-previous-visible-link)

;; ------------------------------------------------------------------------
;; @ key-combo
;; smartchrの代替。自動整形トグル機能。
;; http://qiita.com/akisute3@github/items/0141c92dca0992732af8
;; http://d.hatena.ne.jp/uk-ar/20111208/1322572618

(require 'key-combo)
(key-combo-load-default)                ;おまかせ設定

(key-combo-define-global (kbd "{") '("{`!!'}"))
(key-combo-define-global (kbd "{}") "{}")
(key-combo-define-global (kbd "(") '("(`!!')"))
(key-combo-define-global (kbd "()") "()")
(key-combo-define-global (kbd "[") '("[`!!']"))
(key-combo-define-global (kbd "[]") "[]")
;; (key-combo-define-global (kbd "'") '("'`!!''"))
;; (key-combo-define-global (kbd "''") "''")

;; ------------------------------------------------------------------------
;; @ color-theme

;; (setq custom-theme-directory (concat root-path "themes/"))
;; (load-theme 'railscast t)

;; 真っ黒テーマのujellyに乗り換えてみる
;; http://rubikitch.com/2015/08/04/ujelly-theme/
(load-theme 'ujelly t)

;; mode-lineのテキストを黒に
(set-face-foreground 'mode-line "black")

;; ------------------------------------------------------------------------
;; @ anzu
;; http://qiita.com/syohex/items/56cf3b7f7d9943f7a7ba

(require 'anzu)

(global-anzu-mode +1)
(setq anzu-use-migemo t)
(setq anzu-search-threshold 1000)
(setq anzu-minimum-input-length 3)
(setq anzu-mode-lighter "")

;; 通常のquery-replace/query-replace-regexpを置き換え
(key-chord-define-global "hh" 'anzu-query-replace)
(key-chord-define-global "HH" 'anzu-query-replace-regexp)

;; ------------------------------------------------------------------------
;; @ git-commit-mode
;; http://blog.inouetakuya.info/entry/20110808/1312803553

(require 'git-commit)

;; ------------------------------------------------------------------------
;; @ dired-filter
;; http://blog.livedoor.jp/tek_nishi/archives/8777116.html
;; http://qiita.com/ballforest/items/0ddbdfeaa9749647b488

;; / n  : 名前でフィルタリング (dired-filter-by-name)
;; / r  : 正規表現でフィルタリング (dired-filter-by-regexp)
;; / .  : 拡張子でフィルタリング (dired-filter-by-extension)
;; / h  : ドットで始まるファイルを隠す (dired-filter-by-dot-files)
;; / o  : dired-omit-modeによるフィルタリング (dired-filter-by-omit)
;; / e  : 説明がめんどくさいので割愛 (dired-filter-by-predicate)
;; / f  : ファイルだけ表示 (dired-filter-by-file)
;; / d  : ディレクトリだけ表示 (dired-filter-by-directory)
;; / m  : メジャーモードでフィルタリング (dired-filter-by-mode)
;; //   : フィルタを抜ける
(require 'cl-lib)
(autoload 'dired-filter-mode "dired-filter" nil t)

;; dired-modeでonにする
(defun dired-mode-hooks()
  (dired-filter-mode))
(add-hook 'dired-mode-hook 'dired-mode-hooks)

;; ------------------------------------------------------------------------
;; @ ediff
;; http://qiita.com/l3msh0/items/97909d6e2c92af3acc00
;; http://yohshiy.blog.fc2.com/blog-entry-231.html

;; コントロール用のバッファを同一フレーム内に表示
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; diffのバッファを上下ではなく左右に並べる
(setq ediff-split-window-function 'split-window-horizontally)

;; ------------------------------------------------------------------------
;; @ ace-jump-helm-line
;; 候補選択をショートカットキーで。(helm発動後@キー)
;; http://j.mp/1M0B1Xe

(require 'ace-jump-helm-line)

(define-key helm-map (kbd "`") 'ace-jump-helm-line--with-error-fallback)
(define-key helm-map (kbd "@") 'ace-jump-helm-line-and-execute-action)

;;; anything-shortcut-keys-alistと同じように設定
(setq avy-keys (append "asdfghjklzxcvbnmqwertyuiop" nil))

;;; ちょっとアレンジ
(defun ajhl--insert-last-char ()
  (insert (substring (this-command-keys) -1)))
(defun ace-jump-helm-line--with-error-fallback ()
  "ヒント文字以外の文字が押されたらその文字を挿入するように修正"
  (interactive)
  (condition-case nil
      (ace-jump-helm-line)
    (error (ajhl--insert-last-char))))
(defun ace-jump-helm-line-and-execute-action ()
  "anything-select-with-prefix-shortcut互換"
  (interactive)
  (condition-case nil
      (progn (ace-jump-helm-line)
             (helm-exit-minibuffer))
    (error (ajhl--insert-last-char))))

;; ------------------------------------------------------------------------
;; @ magit
;; http://qiita.com/takc923/items/c7a11ff30caedc4c5ba7

;; Emacs のMagitで`git reset --hard <commit id>`を楽にやる
;; http://qiita.com/tnarihi/items/981e5166d896f39e37da

;; emacs mag-menu.el : 最強magitメニューインターフェースライブラリ
;; http://rubikitch.com/2014/12/20/mag-menu/

;; emacs helm-ls-git.el : gitで管理されているファイル群をhelmで絞り込み検索して操作する
;; http://rubikitch.com/2014/08/31/helm-ls-git/

;; emacs orgit.el : org-modeでmagitへのリンクを作成する
;; http://rubikitch.com/2015/05/18/orgit/

(require 'magit)
(global-set-key (kbd "C-c m") 'magit-status)

;; ------------------------------------------------------------------------
;; dired-open
;; http://yak-shaver.blogspot.jp/2013/07/dired-mac-open.html

(defun open-mac (path)
  (start-process "dired-open-mac" nil "open" path))

(defun quicklook-file (path)
  (interactive)
  (defvar cur nil)
  (defvar old nil)
  (setq old cur)
  (setq cur (start-process "ql-file" nil "qlmanage" "-p" path))
  (when old (delete-process old)))

(defun my-dired-open ()
  (interactive)
  (let ((exts-ql   '(
                     "jpeg"
                     "jpg"
                     "png"
                     "gif"))
        (exts-open '("avi"
                     "mkv"
                     "mp4"
                     "psd"
                     "ai"
                     "c4d"
                     "aep"
                     "lxo"
                     "pdf")))
     (cond ((file-accessible-directory-p (dired-get-file-for-visit))
            (call-interactively 'dired-find-alternate-file))
           ((member (downcase (file-name-extension (dired-get-file-for-visit))) exts-ql)
            (funcall 'quicklook-file (dired-get-file-for-visit)))
           ((member (downcase (file-name-extension (dired-get-file-for-visit))) exts-open)
            (funcall 'open-mac (dired-get-file-for-visit)))
           (t
            (call-interactively 'dired-find-file-other-window)))))

(add-hook 'dired-mode-hook
          '(lambda ()
             (define-key dired-mode-map "o"  'my-dired-open)))

;; ------------------------------------------------------------------------
;; reveal-in-finder  2014-02-02
;; http://d.hatena.ne.jp/kaz_yos/20140202/1391362618
;; Original: http://stackoverflow.com/questions/20510333/in-emacs-how-to-show-current-file-in-finder
;; Modified version
;; 不可視ディレクトリ直下では使えないようだ

(defun reveal-in-finder ()
  (interactive)
  (let ((path (buffer-file-name))
        dir file)
    (if path
        ;; if path has been successfully obtained.
        (progn (setq dir (file-name-directory path))
               (setq file (file-name-nondirectory path)))
      ;; if path is empty, there is no file name. Use the default-directory variable
      (setq dir (expand-file-name default-directory))
      )
    ;; (message (concat "Opening in Finder: " dir file))  ; Show the file name
    (reveal-in-finder-1 dir file)
    ))

(defun reveal-in-finder-1 (dir file)
  (let ((script
         (if file
             (concat
              "set thePath to POSIX file \"" (concat dir file) "\"\n"
              "tell application \"Finder\"\n"
              " set frontmost to true\n"
              " reveal thePath \n"
              "end tell\n"
              )
           (concat
            "set thePath to POSIX file \"" (concat dir) "\"\n"
            "tell application \"Finder\"\n"
            " set frontmost to true\n"
            " reveal thePath \n"
            "end tell\n"))))
    ;; (message script)  ; Show the script in the mini-buffer
    (start-process "osascript-getinfo" nil "osascript" "-e" script)
    ))

(global-set-key (kbd "C-c f") 'reveal-in-finder)

;; ------------------------------------------------------------------------
;; @ markdown-mode

;; markdown-mode
(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))

;; ------------------------------------------------------------------------
;; @ js2-mode,tern-mode
;; http://syati.info/?p=2163
;; 今はjs3-modeというのもあるらしい。またtern-auto-completeがどうしても重い場合はcompany-ternというのもあるらしい。あとで見てみる。

;; company-ternを使ってemacsでjavascriptの補完
;; http://qiita.com/sune2/items/e54bb5db129ae73d004b

(autoload 'js2-mode "js2-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode))

(add-hook 'js2-mode-hook
          (lambda ()
            (tern-mode t)))

(eval-after-load 'tern
  '(progn
     (require 'tern-auto-complete)
     (tern-ac-setup)))

;; ------------------------------------------------------------------------
;; @ coffee-mode
;; http://blog.bokuweb.me/entry/emcas-nyumon
;; http://qiita.com/ironsand/items/f9a83ef328f56e3d05e4

(require 'coffee-mode)
(add-to-list 'auto-mode-alist '("\.coffee$" . coffee-mode))
(add-to-list 'auto-mode-alist '("Cakefile" . coffee-mode))
(defun coffee-custom ()
  "coffee-mode-hook"
  (and (set (make-local-variable 'tab-width) 2)
       (set (make-local-variable 'coffee-tab-width) 2))
  )
(add-hook 'coffee-mode-hook
          '(lambda() (coffee-custom)))

(key-combo-define coffee-mode-map "="  '(" = " " => " "="))
(key-combo-define coffee-mode-map "-"  '(" - " " -> " "-"))
(key-combo-define coffee-mode-map ":"  '(" : " ":"))

(require 'flymake-coffee)
(add-hook 'coffee-mode-hook 'flymake-coffee-load)

;; ------------------------------------------------------------------------
;; @ emmet-mode.el
;; http://catcher-in-the-tech.net/55/

(require 'emmet-mode)
(add-hook 'sgml-mode-hook 'emmet-mode) ;; マークアップ言語全部で使う
(add-hook 'css-mode-hook  'emmet-mode) ;; CSSにも使う
(add-hook 'php-mode-hook 'emmet-mode)
(add-hook 'emmet-mode-hook (lambda () (setq emmet-indentation 2))) ;; indent はスペース2個
;; (define-key emmet-mode-keymap (kbd "C-j") 'emmet-expand-line)
(define-key emmet-mode-keymap (kbd "C-j") 'emmet-expand-yas) ;; yasnippetで展開

;; ------------------------------------------------------------------------
;; @ actionscript-mode

(require 'actionscript-mode)
(setq auto-mode-alist
      (append '(("\\.as$" . actionscript-mode))
              auto-mode-alist))

;; ac-modeを有効に
(add-hook 'actionscript-mode-hook 'ac-mode)

;; ------------------------------------------------------------------------
;; @ Cocoa Emacs(ほとんど使ってないけど)

(when window-system
  ;; 透明度を設定(アクティブ 非アクティブの透明度)
  (add-to-list 'default-frame-alist '(alpha . (0.9 0.5)))
  ;; メニューバーを非表示に
  (menu-bar-mode -1)
  ;; ツールバーを非表示に
  (tool-bar-mode -1)
  ;; 最大表示に
  (set-frame-size (selected-frame) 200 56)
  (set-frame-position (selected-frame) 0 0)

  ;; 環境変数のPATHを設定
  ;; http://qiita.com/catatsuy/items/3dda714f4c60c435bb25
  (let ((envs '("PATH" "VIRTUAL_ENV" "GOROOT" "GOPATH")))
    (exec-path-from-shell-copy-envs envs))
  )

We ♥ Emacs!!!!