情弱ログ

参考にならないので当てにしないでください

よく使うEmacs拡張

弊校では学部1年生からEmacsの使用が強制されており、習得度の低い学生が素のEmacsを使わされています。その結果、非常に残念なことにEmacsはただただ不便なだけのエディタとしてその名が知られています。そこで、弊校におけるEmacsの悪印象を払拭し、Emacsは便利なエディタであると布教するために僕がよく使っているEmacs拡張とその設定を挙げていきたいと思います。

  • package.el

パッケージマネージャです。最近のEmacsだと標準で入っています。追加のリポジトリにMELPAとMarmaladeを使っています。これ以降のパッケージに関しては標準では入っていないので、以下の設定をinit.elに記述した後、Emacsを再起動してM-x package-list-packagesから追加でインストールしてください。

(require 'package)
;; package.elが管理していないelisp置き場
(add-to-list 'load-path "~/.emacs.d/elisp/")
;; MELPAを追加(package.el)
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/"))
;; Marmaladeを追加(package.el)
(add-to-list 'package-archives  '("marmalade" . "http://marmalade-repo.org/packages/"))

;; package.elの初期化
(package-initialize)
  • init-loader

設定ファイルの分割に使っています。その他MacLinuxで設定が異なる場合などに重宝します。僕の場合、package.elとinit-loader.elの設定は~/.emacs.d/init.elに記述し、それ以外は~/.emacs.d/inits/00_editor.el等のファイルに分けて記述しています。

(require 'init-loader)
(setq init-loader-show-log-after-init nil)
(init-loader-load "~/.emacs.d/inits/")
  • smartparens

括弧を自動補完してくれるやつです。ブラケットなどはもちろんのこと、ダブルクォーテーションやシングルクォーテーションなども補完してくれます。

(require 'smartparens)
(smartparens-global-mode t)
  • company

オートコンプリート機能です。昔はauto-completeを使っていましたが、何かのはずみでcompany-modeに移行しました。

;; オートコンプリートの有効化
(require 'company)
(global-company-mode) ; 全バッファで有効にする
(setq company-idle-delay 0) ; デフォルトは0.5
(setq company-minimum-prefix-length 2) ; デフォルトは4
(setq company-selection-wrap-around t) ; 候補の一番下でさらに下に行こうとすると一番上に戻る
  • anzu

単語を検索した時に何番目のマッチかを表示する拡張です。とりあえず入れておくと便利です。

(require 'anzu)
(global-anzu-mode +1)
  • expand-region

賢く範囲選択をしてくれる拡張です。vimでいうvi"みたいなことができます。超便利。

;; expand regionの設定
(require 'expand-region)
(global-set-key (kbd "C-@") 'er/expand-region)
(global-set-key (kbd "C-M-@") 'er/contract-region) ;; リージョンを狭める
(transient-mark-mode t)

google翻訳に丸投げしてくれる拡張です。ライセンス的に大丈夫なんだろうか。

;; google-translateの設定
;; キーバインドの設定
(require 'google-translate)
(global-set-key "\C-xt" 'google-translate-at-point)
(global-set-key "\C-xT" 'google-translate-query-translate)

;; 翻訳のデフォルト値を設定(en -> ja)
(custom-set-variables
 '(google-translate-default-source-language "en")
 '(google-translate-default-target-language "ja"))

(require 'popwin)
;; おまじない(よく分かってない)
(setq display-buffer-function 'popwin:display-buffer)
;; ポップアップを画面下に表示
(setq popwin:popup-window-position 'bottom)

;; google-translate.elの翻訳バッファをポップアップで表示させる
(push '("*Google Translate*") popwin:special-display-config)
  • helm

なんか色々変わるやつです。M-x等でコマンド名が前方一致してなくても良くなったり、正規表現が使えるようになったりします。

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

(define-key global-map (kbd "M-x")     'helm-M-x)
(define-key global-map (kbd "C-x C-f") 'helm-find-files)
(define-key global-map (kbd "C-x C-r") 'helm-recentf)
(define-key global-map (kbd "M-y")     'helm-show-kill-ring)
(define-key global-map (kbd "C-c i")   'helm-imenu)
(define-key global-map (kbd "C-x b")   'helm-buffers-list)

(define-key helm-map (kbd "C-h") 'delete-backward-char)
(define-key helm-find-files-map (kbd "C-h") 'delete-backward-char)
(define-key helm-find-files-map (kbd "TAB") 'helm-execute-persistent-action)
(define-key helm-read-file-map (kbd "TAB") 'helm-execute-persistent-action)

;; Disable helm in some functions
(add-to-list 'helm-completing-read-handlers-alist '(find-alternate-file . nil))

;; Emulate `kill-line' in helm minibuffer
(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))))

(defadvice helm-ff-kill-or-find-buffer-fname (around execute-only-if-exist activate)
  "Execute command only if CANDIDATE exists"
  (when (file-exists-p candidate)
    ad-do-it))

(defadvice helm-ff-transform-fname-for-completion (around my-transform activate)
  "Transform the pattern to reflect my intention"
  (let* ((pattern (ad-get-arg 0))
         (input-pattern (file-name-nondirectory pattern))
         (dirname (file-name-directory pattern)))
    (setq input-pattern (replace-regexp-in-string "\\." "\\\\." input-pattern))
    (setq ad-return-value
          (concat dirname
                  (if (string-match "^\\^" input-pattern)
                      ;; '^' is a pattern for basename
                      ;; and not required because the directory name is prepended
                      (substring input-pattern 1)
                    (concat ".*" input-pattern))))))
  • helm-gtags

タグジャンプ用です。必須に近いので絶対に入れておきたい拡張です。helm-gtags-dwimが便利すぎて脳が退化しそうになります。尚、使う時はあらかじめソースコードの格納されたディレクトリの一番上でgtagsコマンドを実行する必要があります。タグファイルの生成は少し時間がかかりますが、作ってしまえばLinux Kernelのような超巨大なプロジェクトでも1秒とかからずジャンプができます。僕の設定が悪いのかもしれませんが、Linux KernelのMakefileから生成するTAGSファイルやctagsとは比べ物にならない程早いです。

(require 'helm-gtags)

(custom-set-variables
 ;'(helm-gtags-path-style 'relative)
 '(helm-gtags-ignore-case t)
 '(helm-gtags-auto-update t))

(add-hook 'helm-gtags-mode-hook
          '(lambda ()
             ;; do what i mean
             (local-set-key (kbd "M-.") 'helm-gtags-dwim)
             ;;入力されたタグの定義元へジャンプ
             (local-set-key (kbd "M-t") 'helm-gtags-find-tag)
             ;;入力タグを参照する場所へジャンプ
             (local-set-key (kbd "M-r") 'helm-gtags-find-rtag)
             ;;入力したシンボルを参照する場所へジャンプ
             (local-set-key (kbd "M-s") 'helm-gtags-find-symbol)
             ;;タグ一覧からタグを選択し, その定義元にジャンプする
             (local-set-key (kbd "M-l") 'helm-gtags-select)
             ;;ジャンプ前の場所に戻る
             (local-set-key (kbd "M-,") 'helm-gtags-pop-stack)
             (local-set-key (kbd "M-g M-p") 'helm-gtags-parse-file)
             (local-set-key (kbd "C-c <") 'helm-gtags-previous-history)
             (local-set-key (kbd "C-c >") 'helm-gtags-next-history)))
  • flycheck,flymake

構文チェッカーです。flycheckの方が何も考えなくて良いので楽ですが、Makefile内にcheck-syntaxというルールがある場合はflymakeを使ってほしいので以下のようなemacs lispを追加しました。

;;;; シンタックスチェック
(require 'flycheck)
(require 'flymake)
(require 'helm-flycheck)
(add-hook 'after-init-hook #'global-flycheck-mode)
(defadvice flymake-post-syntax-check (before flymake-check-was-interrupted)
  (setq flymake-check-was-interrupted t))
(ad-activate 'flymake-post-syntax-check)

(eval-after-load 'flycheck
  '(define-key flycheck-mode-map (kbd "C-c ! h") 'helm-flycheck))
(with-eval-after-load 'flycheck
  (flycheck-pos-tip-mode))

(defun has-check-syntax ()
  (if (file-exists-p "Makefile")
      (progn (with-temp-buffer
               (insert-file-contents "Makefile")
               (let ((buffer (buffer-string)))
                 (if (string-match "check-syntax" buffer)
                     t
                   nil)
                 )))
    nil))

(defun switch-flycheck-or-flymake ()
  (if (has-check-syntax)
      (progn
        (flymake-mode t)
        (flycheck-mode -1)
        )
    (flymake-mode -1)
    (flycheck-mode t))
  )
  • semantic,srefactor

C/C++等の構文を静的に解析していろいろな機能を提供するsemantic(CEDET?)と、それを利用したリファクタリングツールであるsrefactorです。正直gtagsでジャンプするのでsemanticはあまり使っていませんが、srefactorは禿げるほど便利なので必要以上にリファクタリングがしたくなります。

;;;; semantic
(semantic-mode 1)
(global-semantic-idle-scheduler-mode 1)
(global-semanticdb-minor-mode 1)
(global-semantic-idle-completions-mode 1)
(global-semantic-decoration-mode 1)
(global-semantic-stickyfunc-mode 1)
(global-semantic-mru-bookmark-mode 1)

;;;; srefactor
(require 'srefactor)
(require 'srefactor-lisp)
(define-key c-mode-map (kbd "M-RET") 'srefactor-refactor-at-point)
(define-key c++-mode-map (kbd "M-RET") 'srefactor-refactor-at-point)
  • irony

companyモードのバックエンド?です。色々試してみてcompany-irony-c-headersが一番いい感じに補完できたのでこれを使っています。

;; irony
(require 'irony)
(add-hook 'c-mode-hook 'irony-mode)
(add-hook 'c++-mode-hook 'irony-mode)
(add-hook 'objc-mode-hook 'irony-mode)
(add-hook 'irony-mode-hook 'irony-cdb-autosetup-compile-options)

;;(require 'company-c-headers)
;;(add-to-list 'company-backends 'company-c-headers)
;;(require 'company-irony)
;;(add-to-list 'company-backends 'company-irony)
;;(require 'company-yasnippet)
;;(add-to-list 'company-backends 'company-yasnippet)
(require 'company-irony-c-headers)
(add-to-list 'company-backends 'company-irony-c-headers)

(delete 'company-semantic company-backends)

スニペット機能です。テンプレートを使った補完みたいなやつです。

(require 'yasnippet)
(require 'helm-c-yasnippet)
(setq helm-yas-space-match-any-greedy t)
(global-set-key (kbd "C-c y") 'helm-yas-complete)
(push '("emacs.+/snippets/" . snippet-mode) auto-mode-alist)
(yas-global-mode 1)

だいたいこんな感じです。とりあえずC言語を書くだけなら十分だと思います。
ここまで書いておいて何ですが、Emacsは宗教です。沼にはまる前に適切なIDEを探すことをおすすめします。