css-modeの初期設定

最近CSS弄りの楽しさを知り,このブログの表示が乱れまくっています.CSSのコーディングなら古臭いEmacsなんて使わずに現代的なツールでやってやろうと思い,Xcodeなどを試してみたんですが...

やっぱEmacs最高!!css-mode最高!!ってことでその初期設定です.

環境

globalな設定

こういうのは検索すればいっぱい出てくるから,出てこなさそうな部分だけ.

auto-complete-modeでキーワードの補完

いきなり有名所ですが,css-mode用の辞書も入ってるのでとりあえず.

コメントアウトの仕方を少し改善

上級者であればcomment-dwimを使いこなすんでしょうが,未熟な僕にはcomment-or-uncomment-regionがいい塩梅です.コメントアウトとコメントインをトグルしやすいところとか.

(defun my-comment-or-uncomment-region (beg end &optional arg)
  (interactive "*r\nP")
  (comment-normalize-vars)
  (let ((comment-style 'extra-line))
    (comment-or-uncomment-region beg end arg)))

(global-set-key (kbd "M-c") 'comment-or-uncomment-region)
(global-set-key (kbd "M-C") 'my-comment-or-uncomment-region)

;; コメントを適当にインデントさせる
(setq comment-style 'indent)

参考:最近の Emacs のコメント機能についてのまとめ。 - 日々、とんは語る。

バッファを整形

かなり前に海外のサイトを見て知ったもの.単純だけど重宝してます.

(defun indent-& ()
  (interactive)
  (delete-trailing-whitespace)                ; 行末空白を削除
  (indent-region (point-min) (point-max) nil) ; インデント
  (untabify (point-min) (point-max)))         ; TABを半角空白に変換

(global-set-key (kbd "C-c C-i") 'indent-&)
キーバインドMacのデフォルトに近付ける

Carbon Emacsの頃,mac-key-modeを愛用していた僕としてはCocoa Emacsキーバインドは物足りなく感じます.

(defun anything-occur-or-occur ()
  (interactive)
  (if (fboundp 'anything-occur)
      (call-interactively 'anything-occur)
    (call-interactively 'occur)))

(defun context-menu (event)
  (interactive "e")
  (popup-menu menu-bar-edit-menu))

(defun kill-this-frame-or-buffer ()
  (interactive)
  (or (ignore-errors
        (delete-frame)
        t)
      (kill-this-buffer)))

;; irie @ ウィキ - redo+.el
;; http://www11.atwiki.jp/s-irie/pages/18.html
(when (require 'redo+ nil t)
  (global-set-key (kbd "s-Z") 'redo))

(global-set-key (kbd "s-a") 'mark-whole-buffer)
(global-set-key (kbd "s-w") 'kill-this-frame-or-buffer)
(global-set-key (kbd "s-.") 'keyboard-quit)
(global-set-key (kbd "s-/") 'info)
;; ↓なんか文字化けしてるけど,command + option + f です.
(global-set-key (kbd "M-s-ƒ") 'anything-occur-or-occur)
(global-set-key (kbd "<s-up>") 'beginning-of-buffer)
(global-set-key (kbd "<s-down>") 'end-of-buffer)
(global-set-key (kbd "<s-right>") 'end-of-line)
(global-set-key (kbd "<s-left>") 'beginning-of-line)
(global-set-key (kbd "<s-mouse-1>") 'browse-url-at-mouse)
(global-set-key (kbd "<mouse-3>") 'context-menu)
(global-set-key (kbd "<C-down-mouse-1>") 'context-menu)
(global-set-key (kbd "<S-s-mouse-1>") 'mouse-buffer-menu)

css-modeの設定

imenuでインデックスを作成

Emacs標準搭載のimenuでセレクターのインデックスし,M-x imenuやメニューバーから飛べるようにします.

(defun my-css-mode-setup-imenu ()
  (setq imenu-generic-expression
        '(("Selectors" "^[[:blank:]]*\\(.*[^ ]\\) *{" 1)))
  (setq imenu-case-fold-search nil)
  (setq imenu-auto-rescan t)
  (setq imenu-space-replacement " ")
  (imenu-add-menubar-index)
  )
(add-hook 'css-mode-hook 'my-css-mode-setup-imenu)

こんな感じになります.

smartchrで変態補完

smartchrは変態っぽくて敬遠していたんですが,今回はじめて使ってみました.skeletonでは物足りないけど,yasnippet持ち出す程でもない,そんな時にちょうどいいです.

;; smartchr.el を使って生産性を上げる | tech.kayac.com - KAYAC engineers' blog
;; http://tech.kayac.com/archive/emacs-tips-smartchr.html
(require 'smartchr)

(defun my-smartchr-braces ()
  "Insert a pair of braces like below.
\n    {\n    `!!'\n}"
  ;; foo {
  ;;     `!!'
  ;; }
  (lexical-let (beg end)
    (smartchr-make-struct
     :insert-fn (lambda ()
                  (setq beg (point))
                  (insert "{\n\n}")
                  (indent-region beg (point))
                  (forward-line -1)
                  (indent-according-to-mode)
                  (goto-char (point-at-eol))
                  (setq end (save-excursion
                              (re-search-forward "[[:space:][:cntrl:]]+}" nil t))))
     :cleanup-fn (lambda ()
                   (delete-region beg end))
     )))

(defun my-smartchr-comment ()
  "Insert a multiline comment like below.
\n/*\n * `!!'\n */"
  ;; /*
  ;;  * `!!'
  ;;  */
  (lexical-let (beg end)
    (smartchr-make-struct
     :insert-fn (lambda ()
                  (setq beg (point))
                  (insert "/*\n* \n*/")
                  (indent-region beg (point))
                  (setq end (point))
                  (forward-line -1)
                  (goto-char (point-at-eol)))
     :cleanup-fn (lambda ()
                   (delete-region beg end))
     )))

(defun my-smartchr-semicolon ()
  "Insert a semicolon at end of line."
  (smartchr-make-struct
   :insert-fn (lambda ()
                (save-excursion
                  (goto-char (point-at-eol))
                  (insert ";")))
   :cleanup-fn (lambda ()
                 (save-excursion
                   (goto-char (point-at-eol))
                   (delete-backward-char 1)))
   ))

(defun my-css-mode-setup-smartchr ()
  (local-set-key (kbd "(") (smartchr '("(" "(`!!')")))
  (local-set-key (kbd ",") (smartchr '("," ", ")))
  (local-set-key (kbd "'") (smartchr '("'" "'`!!''" "'`!!'', ")))
  (local-set-key (kbd "\"") (smartchr '("\"" "\"`!!'\"" "\"`!!'\", ")))
  (local-set-key (kbd ":") (smartchr '(":" ": `!!';")))
  (local-set-key (kbd ";") (smartchr '(";" my-smartchr-semicolon)))
  (local-set-key (kbd "{") (smartchr '("{" "{ `!!' }" my-smartchr-braces)))
  (local-set-key (kbd "/") (smartchr '("/" "/* `!!' */" my-smartchr-comment)))
  )
(add-hook 'css-mode-hook 'my-css-mode-setup-smartchr)
その他
(defun search-in-google-with-css ()
  (interactive)
  (let ((query (symbol-at-point)))
    (when query
      (browse-url (concat "http://www.google.co.jp/search?q="
                          (url-hexify-string (format "css %s" query))))
      (message "Search `%s' in Google..." query))))

(defun my-css-mode-setup-main ()
  (local-set-key (kbd "C-c g") 'search-in-google-with-css)
  (local-set-key (kbd "<RET>") 'newline-and-indent)
  (local-set-key (kbd "<DEL>") 'backward-delete-char-untabify)
  (setq backward-delete-char-untabify-method 'all)
  )
(add-hook 'css-mode-hook 'my-css-mode-setup-main)