Emacs の設定ファイル群
Makefile
Fetching latest commit…
Cannot retrieve the latest commit at this time.

README.org

Emacs の設定

はじめに

ここでは,私の Emacs の設定についてまとめています.

https://travis-ci.org/uwabami/emacs.svg https://img.shields.io/badge/License-GPLv3-blue.svg

基本方針は以下の通り:

Emacs のパッケージ(package.el)と quelpa, use-package を使う

基本は package.el を使いますが、 VCS からインストールしたいパッケージが幾つかあるので、 それらについては quelpa を使います。

Debian パッケージがインストールされているならば,それを優先する

:Eating your own dog food - Wikipedia

Emacsに関連するDebianパッケージを幾つかメンテナンスしているので, 可能な限りDebianパッケージを使うことにしています.

設定は Org mode で書きたい

以前こんなブログ記事を書きました: Emacsの設定ファイルをorgで書く

というわけで,設定は Org Babel で書いています. 本ファイル(README.org) から, Makefile 内の以下のスクリプトで ~/init.el を生成し,byte-compile します.

init.el: README.org
	$(EMACS) -q --batch --eval \
		 "(progn \
		    (require 'ob-tangle) \
		    (org-babel-tangle-file \"$<\" \"$@\" \"emacs-lisp\")))"
%.elc: %.el
	$(EMACS) -l $< -batch -f batch-byte-compile $<

ディレクトリ構成

分割した設定ファイル群やパッケージで install したパッケージ の置き場所は user-emacs-directory 以下にまとめています.

試行錯誤の結果,ディレクトリ構成は以下のようにしました:

~/.emacs.d/
 |-- Makefile    ←  byte-compile 用の rule
 |-- README.org  ←  本ファイル.`org-babel-tangle' で init.el を生成
 |-- elpa/       ←  package.el で導入したパッケージが置かれる場所
 |-- quelpa/     ←  quelpa で導入したパッケージが置かれる場所
 |-- share/      ←  (基本的に)参照するだけの資源置き場所
 `-- tmp/        ←  一次ファイルの置き場所

上記ディレクトリ構成を設定ファイルで使用するためにディレクトリ配置を宣言しておきます.

(when load-file-name
  (setq user-emacs-directory (file-name-directory load-file-name)))
(defconst my:d:share
  (expand-file-name "share/" user-emacs-directory))
(defconst my:d:tmp
  (expand-file-name "tmp/" user-emacs-directory))

ついでに, custom-set-variables は別ファイルに出力,終了時に削除するようにしています.

(setq custom-file (concat my:d:tmp "custom.el"))
(add-hook 'kill-emacs-hook
          (lambda ()
            (if (file-exists-p custom-file)
                (delete-file custom-file))))

init.elが汚れる気がしてあまり好きではないのですが…皆さん気にしてないんですかね

Package 関連: package.el, use-package, quelpa

use-package のおかけで、 無いと途方に暮れるパッケージ以外のインストールは無視できるようになります。

package.el

パッケージは基本的に pacakge.el で導入するので、先ずはその設定.

(setq url-http-attempt-keepalives nil)
(require 'package nil 'noerror)
(setq package-enable-at-startup t)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("org"   . "http://orgmode.org/elpa/") t)
(eval-when-compile
  (unless (file-exists-p (concat user-emacs-directory "tmp/bootstrap-stamp"))
    (package-refresh-contents)))
(package-initialize)
(unless (package-installed-p 'package-utils)
  (package-install 'package-utils))

また,初回起動時に make で org の最新版等を導入するために batch でインストールできる様に,以下を emacs-batch-install.el として出力します.

(setq url-http-attempt-keepalives nil)
(require 'package nil 'noerror)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("org"   . "http://orgmode.org/elpa/") t)
(package-refresh-contents)
(package-initialize)
(package-install pkg-install)

batch でのインストールは例えば

	$(EMACS) -q --batch --eval \
	  "(deconst pkg-install 'org-plus-contrib)" -l emacs-batch-install.el

とすれば良いかと.

use-package

個々のパッケージの設定には use-package を利用します.

(unless (require 'use-package nil t)
  (package-install 'use-package))

quelpa

melpa に登録されていないパッケージや自作の elisp 等をインストールできる様に quelpa を入れておきます.とはいえ、これでパッケージを入れる訳ではないので、 melpa の同期はしません。

(use-package quelpa
  :ensure t
  :config
  (setq quelpa-upgrade-p nil
        quelpa-checkout-melpa-p nil
        quelpa-update-melpa-p nil
        quelpa-melpa-recipe-stores nil)
  )

独自関数

細かい独自関数,など.

カーソルのある位置の face を調べる関数

わりと良く使う. 地味に便利

(defun my:describe-face-at-point ()
  (interactive)
  (message "%s" (get-char-property (point) 'face)))

機能を無効化するための関数の定義

line-number-mode など「有効無効をtoggleする関数」は 慣習的に 0 以下の数字を指定すると明示的に無効化できるので, -1 を設定する関数を定義しておく.

(defun my:disable-builtin-mode (mode)
  "与えられた mode が存在するのであれば -1 をセットして無効化"
  (if (fboundp mode) (funcall mode -1)))

dpkg-status

もっと良い方法がありそうなモンですが.

(defun my:dpkg-status (package)
  "Return the package status from dpkg --get-selections."
  (string-match "^ii" (shell-command-to-string (format "dpkg -l %s" package))))

常に cl-lib を読み込む

以前は(今も?)「 cl.el は名前衝突があるので byte compile 時以外は読み込まない様にしよう」 というお話でした.つまり,

(eval-when-compile (require 'cl))

としておくこと,という.

今は「 cl.el は deprecated なので cl-lib を使いましょう」ということみたいです. 名前衝突の回避のために,関数の接頭詞として cl- が付くようになったのは御愛嬌.

(eval-and-compile (use-package cl-lib))

後方互換性: el-x

古い flet と同じ挙動をする dflet を使うために el-x を導入しておく

(use-package el-x
  :ensure t)

url-retrieve の置き換え: mb-url

標準関数の url-retrieve 等の proxy 環境下での挙動が怪しいので, mb-url で advice (上書き)することに. curl のバッファが増殖するのだけれど,これはなんとかならないかなぁ…

(use-package mb-url
  :ensure t
  :config
  (advice-add 'url-http :override 'mb-url-http-curl))

環境変数の読み込み: exec-path-from-shell

zsh で設定した PATH などの環境変数を Emacs に引き継ぐために purcell/exec-path-from-shell を使います. 今の所

  • SHELL
  • DEBFULLNAME
  • DEBEMAIL
  • TEXMFHOME
  • SKKSERVER
  • http_proxy
  • GPG_KEY_ID
  • GPG_AGENT_INFO
  • PASSWORD_STORE_DIR

を読み込んでいます.

(defvar my:d:password-store nil)
(use-package exec-path-from-shell
  :ensure t
  :config
  (when (memq window-system '(mac ns)) (exec-path-from-shell-initialize))
  (exec-path-from-shell-copy-envs
   '("SHELL"
     "DEBFULLNAME"
     "DEBEMAIL"
     "SKKSERVER"
     "TEXMFHOME"
     "http_proxy"
     "GPG_KEY_ID"
     "GPG_AGENT_INFO"
     "PASSWORD_STORE_DIR"
     ))
  (setq user-full-name (concat (getenv "DEBFULLNAME"))
        user-mail-address (concat (getenv "DEBEMAIL"))
        my:d:password-store (getenv "PASSWORD_STORE_DIR"))
  )

言語の設定

過去にはいろいろ設定していたのですが…

いきなり矛盾しますが,最近の Emacs(例:23.3) では文字コードの設定は不要です.

というわけで OS 依存の条件分岐だけを記述しています.

ちなみに prefer-coding-system を設定すると default-file-name-coding-system が設定されます. 優先順位は以下の通り:

  1. file-name-coding-system を見る
  2. file-name-coding-system が nil なら default-file-name-coding-system を利用

cp5022x.el

Emacs23 から内部が Unicode ベースになっています.

しかし文字コードの変換は GNU libc の iconv をベースにしているため, 環境によっては文字の変換がうまく行なえません. そこで言語設定前に cp5022x.el をインストールすることにしています.

(use-package cp5022x
  :ensure t
  )

East Asian Ambiguos 対応

CJK 以外の East Asian Ambiguos,絵文字も2文字幅にするようにしています. 拙作の修正ロケールはこちら: https://github.com/uwabami/locale-eaw-emoji

(unless (package-installed-p 'eaw_and_emoji)
  (quelpa '(eaw_and_emoji
            :fetcher url
            :url "https://raw.githubusercontent.com/uwabami/locale-eaw-emoji/master/eaw_and_emoji.el")))
(use-package eaw_and_emoji
  :config
  (eaw-and-emoji-fullwidth))
;; (setq nobreak-char-display nil)

OSの違いに起因する条件分岐

Mac と Linux では同じ Unicode でも正規化が異なります (具体的には Mac のファイルシステムである HFS+ では Unicode の正規化が異なります). Unicode の正規化と Mac OS X 特有の事情については

等が参考になるでしょう.

日本語のファイル名を扱うことは滅多にないものの, たまに祟りがあるのでそれを回避するための設定をしています.

Windows の場合はファイル名などは cp932 にしているものの, 最近 Windows 使っていないので良く知りません(というわけで,設定を捨てました). さらに,最近は Mac OS でも Emacs 使ってないから,これが正しのか良くわからない…

(use-package ucs-normalize
  :if (eq system-type 'darwin)
  :config
  (set-file-name-coding-system 'utf-8-hfs)
  (setq locale-coding-system 'utf-8-hfs)
  ;; ついでにキーバインド: Ctrl を Mac から奪い取る
  (setq mac-pass-control-to-system t)
  ;; Cmd と Option を逆にする
  (setq ns-command-modifier 'meta)
  (setq ns-alternate-modifier 'super)
  (global-set-key [ns-drag-file] 'ns-find-file)
  )

主にEmacs本体に同梱されている拡張に関する設定

標準機能の設定

表示関連

起動時のスプラッシュ画面を表示しない

(setq inhibit-startup-screen t
      inhibit-startup-message t)

大抵の場合ターミナル内で -nw として起動するし, メニューは触ったことないので使わないので, フレーム, ツールバー等を非表示にする.

(my:disable-builtin-mode 'tool-bar-mode)
(my:disable-builtin-mode 'scroll-bar-mode)
(my:disable-builtin-mode 'menu-bar-mode)
(my:disable-builtin-mode 'blink-cursor-mode)
(my:disable-builtin-mode 'column-number-mode)

ベル無効化

(setq ring-bell-function 'ignore)

選択リージョンに色付け

(setq transient-mark-mode t)

対応する括弧を強調表示

(show-paren-mode +1)
(setq show-paren-style 'mixed)

行番号を表示する linum-mode は基本使わない(必要に応じて有効にする) ので通常はモードラインに行番号や桁番号を表示しないようする. ついでに linum-mode を有効にした場合の桁表示を 5 桁に.

(my:disable-builtin-mode 'line-number-mode)
(setq linum-format "%5d ")

debug は表示しない: 必要に応じて t に変更する

(setq debug-on-error nil)

Compile-Log の非表示: ほとんど見ないし.

(let ((win (get-buffer-window "*Compile-Log*")))
  (when win (delete-window win)))

Warning の抑制: これもほとんど見ないし.

(setq byte-compile-warnings
      '(not
        free-vars
        unresolved
        callargs
        redefine
        obsolete
        noruntime
        cl-functions
        interactive-only
        make-local
        ))

編集関連

yes or no を y or n に

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

ファイル名の大文字小文字を区別しない(zsh風)

(setq read-file-name-completion-ignore-case t)

tab 幅 4, tab でのインデントはしない

(setq-default tab-width 4)
(setq-default indent-tabs-mode nil)

文字列は 72 文字で折り返し(RFC2822風味)

(setq-default fill-column 72)
(setq paragraph-start '"^\\([  ・○<\t\n\f]\\|(?[0-9a-zA-Z]+)\\)")
(setq-default auto-fill-mode nil)

長い行の折り返し: デフォルトは折り返し有で \C-c M-l で toggle

(set-default 'truncate-lines nil)
(setq truncate-partial-width-windows nil)
(define-key global-map (kbd "C-c M-l") 'toggle-truncate-lines)

バッファ終端で newline を入れない

(setq next-line-add-newlines nil)

symlink は常においかける

(setq vc-follow-symlinks t)

変更のあったファイルの自動再読み込み

(global-auto-revert-mode 1)

バックアップとauto-saveの作成/位置の変更:

(setq auto-save-list-file-prefix (concat my:d:tmp ".saves-"))
(setq auto-save-default t)
(setq auto-save-timeout 15)
(setq auto-save-interval 60)
(setq make-backup-files t)
(setq backup-by-copying t) ; symlink は使わない
(setq backup-directory-alist `(("." . ,my:d:tmp)))
(setq auto-save-file-name-transforms `((".*" ,my:d:tmp t)))
(setq version-control t)
(setq kept-new-versions 5)
(setq kept-old-versions 5)
(setq delete-old-versions t)
(setq delete-auto-save-files t)

recentf: 最近使ったファイル履歴の保管

(setq recentf-max-saved-items 10000)
(setq recentf-save-file
      (expand-file-name (concat my:d:tmp "recentf")))
(setq recentf-auto-cleanup 'never)
(setq recentf-exclude
      '(".recentf"
        "^/tmp\\.*"
        "^/private\\.*"
        "^/var/folders\\.*"
        "/TAGS$"
        "^/home/uwabami/.mozilla/firefox/jhitnbb2.default/itsalltext\\.*"
        ))
(add-hook 'after-init-hook 'recentf-mode)

Undo/Redo: そのうち undohist と undo-tree を試そうと思っているのですが, 今のところ特に弄ってません. undo-limit は無限大にしたいのですが,どうするのかな…?

(setq undo-limit 200000)
(setq undo-strong-limit 260000)
(savehist-mode 1)        ; ミニバッファの履歴を保存しリストア
(setq savehist-file (concat my:d:tmp "history"))
(setq history-length t)  ; t で無制限

行末の無駄な空白/改行を削除する: 無駄な行末の空白を削除する(Emacs Advent Calendar jp:2010)

ただし, RD や Markdown だと空白行に意味があったりするので, 必要に応じて拡張子で判断して外している.

(defvar my:delete-trailing-whitespace-exclude-suffix
  (list "\\.rd$" "\\.md$" "\\.rbt$" "\\.rab$"))
(defun my:delete-trailing-whitespace ()
  (interactive)
  (cond
   ((equal nil
           (cl-loop for pattern in my:delete-trailing-whitespace-exclude-suffix
                    thereis (string-match pattern buffer-file-name)))
    (delete-trailing-whitespace))))
(add-hook 'before-save-hook 'my:delete-trailing-whitespace)

ファイル,デイレクトリ整理

他にもイロイロありそう.

(use-package url
  :init
  (setq url-configuration-directory (concat my:d:tmp "url")))
(use-package nsm
  :init
  (setq nsm-settings-file (concat my:d:tmp "network-settings.data")))

.elc.el の timestamp を比較し,新しい方を読み込む

load-prefer-newer は Emacs >= 24.4 から.

(when (boundp 'load-prefer-newer)
  (setq load-prefer-newer t))

ガベージコレクションの頻度を下げる

とりあえず 128 MB にしておく.

(setq gc-cons-threshold (* 128 1024 1024))

scratch を殺さない. 消したら再生成

…元ネタがどこだったのか忘れてしまった…

(defun my:make-scratch (&optional arg)
  (interactive)
  (progn
    ;; "*scratch*" を作成して buffer-list に放り込む
    (set-buffer (get-buffer-create "*scratch*"))
    (funcall initial-major-mode)
    (erase-buffer)
    (when (and initial-scratch-message (not inhibit-startup-message))
      (insert initial-scratch-message))
    (or arg
        (progn
          (setq arg 0)
          (switch-to-buffer "*scratch*")))
    (cond ((= arg 0) (message "*scratch* is cleared up."))
          ((= arg 1) (message "another *scratch* is created")))))

(defun my:buffer-name-list ()
  (mapcar (function buffer-name) (buffer-list)))
(add-hook 'kill-buffer-query-functions
          ;; *scratch* バッファで kill-buffer したら内容を消去するだけにする
          (function (lambda ()
                      (if (string= "*scratch*" (buffer-name))
                          (progn (my:make-scratch 0) nil)
                        t))))
(add-hook 'after-save-hook
          ;; *scratch* バッファの内容を保存したら
          ;; *scratch* バッファを新しく作る.
          (function
           (lambda ()
             (unless (member "*scratch*" (my:buffer-name-list))
               (my:make-scratch 1)))))

空になったファイルを尋ねずに自動削除

ゴミが残らないし,地味に便利.

(defun my:delete-file-if-no-contents ()
  (when (and (buffer-file-name (current-buffer))
             (= (point-min) (point-max)))
    (delete-file
     (buffer-file-name (current-buffer)))))
(if (not (memq 'my:delete-file-if-no-contents after-save-hook))
    (setq after-save-hook
          (cons 'my:delete-file-if-no-contents after-save-hook)))

abbrev: 略語展開

(use-package abbrev
  :diminish abbrev-mode
  :config
  (setq abbrev-file-name (concat my:d:share "abbrev_defs")
        save-abbrevs t
  )
  (setq-default abbrev-mode t)
  )

eldoc: emacs-lisp document

(use-package eldoc
  :diminish eldoc-mode
  :config
  (add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
  )

midnight: 一定期間使用しなかった buffer を自動削除

(use-package midnight
  :config
  (setq clean-buffer-list-delay-general 1))

uniquify: モードラインのファイル名にディレクトリも表示する

(use-package uniquify
  :config
  (setq uniquify-buffer-name-style 'post-forward-angle-brackets
        uniquify-min-dir-content 1))

whitespace: 空白の強調表示

(use-package whitespace
  :diminish global-whitespace-mode
  :config
  (setq whitespace-line-column 72
        whitespace-style
        '(face              ; faceを使って視覚化する.
          trailing          ; 行末の空白を対象とする.
          tabs              ; tab
          spaces            ; space
          )
        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]))
        whitespace-space-regexp "\\(\u3000+\\)")
  (global-whitespace-mode 1))

saveplace: 前回の修正位置を記憶する.

記憶の保存先は ~/.emacs.d/tmp/emacs-places に変更.

(use-package saveplace
  :config
  (setq-default save-place t)
  (setq save-place-file (concat my:d:tmp "emacs-places")))

time-stamp: 保存時に timestamp を自動更新

デフォルトではいろいろと衝突したので 更新文字列を変更し, $Lastupdate: 2 ($は半角) があったら timestamp を更新する様にした.

(use-package time-stamp
  :config
  (setq time-stamp-active t
        time-stamp-line-limit 10
        time-stamp-start "$Lastupdate: 2"
        time-stamp-end "\\$"
        time-stamp-format "%03y-%02m-%02d %02H:%02M:%02S")
  (add-hook 'before-save-hook 'time-stamp))

モード独自の設定(例えば Org とか)に関しては別途.

tramp: 使わないので無効化?

無効化したいんだけれど,うまくいってない,ような…?

(setq tramp-mode nil
      tramp-persistency-file-name (concat my:d:tmp "tramp")
      tramp-default-method "scpx")

bookmark: bookmark ファイル

イマイチ使いこなせてない. 場所だけ変更しておく.

(setq bookmark-default-file (concat my:d:share "bookmarks"))

browse-url

Firefox の呼び出し方が変わったので,そのために関数を追加. 詳細は http://www.emacswiki.org/emacs/BrowseUrl を参照のこと.

(use-package browse-url
  :bind (("C-c C-j" . browse-url-at-point))
  :config
  (defun browse-url-firefox (url &optional new-window)
    "@see http://www.emacswiki.org/emacs/BrowseUrl"
    (interactive (browse-url-interactive-arg "URL: "))
    (setq url (browse-url-encode-url url))
    (let* ((process-environment (browse-url-process-environment))
           (window-args (if (browse-url-maybe-new-window new-window)
                            (if browse-url-firefox-new-window-is-tab
                                '("-new-tab")
                              '("-new-window"))))
           (ff-args (append browse-url-firefox-arguments window-args (list url)))
           (process-name (concat "firefox " url))
           (process (apply 'start-process process-name nil
                           browse-url-firefox-program ff-args) ))))
  (setq browse-url-browser-function 'browse-url-firefox)
  )

server: Emacs server

(use-package server
  :config
  (unless (server-running-p)
    (server-start)))

日本語入力: ddskkの設定

Daredevil SKK (DDSKK) をメインで使用中.無いと途方に暮れる. ちなみにGTKが有効になっていると gtk-immodule なんかと衝突するので ~/.Xresources で xim を無効にしておくと良い. 例えば以下の様に:

! disable XIM
Emacs*useXIM: false

Emacs 本体側の設定

実際の設定は別ファイルで行なわれるため ここでは設定ファイルの位置変更を変更している.

(use-package skk
  :bind (("C-x j"   . skk-mode)
         ("C-x C-j" . skk-mode)
         ("C-\\"    . skk-mode))
  :init
  (setq skk-user-directory (concat my:d:tmp "skk")
        skk-init-file (concat user-emacs-directory "init-ddskk")
        default-input-method "japanese-skk" )
  :config
  )

DDSKK 本体の設定

sticky shift: sticky shift を参照のこと. ddskk の 14.2 以降から同梱されるようになった(ありがたい)

(setq skk-sticky-key ";")

変換候補の表示位置

(setq skk-show-candidates-always-pop-to-buffer t)

候補表示件数を2列に

(setq skk-henkan-show-candidates-rows 2)

日本語表示しない

(setq skk-japanese-message-and-error nil)

メニューを日本語にしない -> toolbar 非表示だし.

(setq skk-show-japanese-menu nil)

注釈の表示

(setq skk-show-annotation nil)

インジケータの表示のカスタマイズ

(setq skk-latin-mode-string "[_A]")
(setq skk-hiragana-mode-string "[あ]")
(setq skk-katakana-mode-string "[ア]")
(setq skk-jisx0208-latin-mode-string "[A]")
(setq skk-jisx0201-mode-string "[_ア]")
(setq skk-abbrev-mode-string "[aA]")
(setq skk-indicator-use-cursor-color nil)

インジケータを左端に表示

(setq skk-status-indicator 'left)

mode-line が動くのが許せないので,ちょっと修正

(defadvice skk-make-indicator-alist
    (after my:set-skk-default-indicator activate)
  (dolist (elem
           '((abbrev " [aA]" . "--[aA]:")
             (latin " [_A]" . "--[_A]:")
             (default " [--]" . "--[--]:")))
    (setq ad-return-value
          (append (cons elem nil)
                  (delq (assoc (car elem) ad-return-value) ad-return-value)))))
(setq skk-show-inline t)

カーソルには色をつけない

(setq skk-use-color-cursor nil)

編集関連

キーバインド

(global-set-key "\C-x\C-j" 'skk-mode)
(global-set-key "\C-xj" 'skk-mode)
(global-set-key "\C-j" 'skk-mode)
(global-set-key "\C-\\" 'skk-mode)

半角カナを入力

(setq skk-use-jisx0201-input-method t)

Enter で改行しない

(setq skk-egg-like-newline t)

“「”を入力したら”」”も自動で挿入

(setq skk-auto-insert-paren t)

句読点変換ルール

(setq skk-kuten-touten-alist
      '(
        (jp    .    ("" . "" ))
        (en-jp   .    ("" . "" ))
        (en    .    (". " . ", "))
        ))
(setq-default skk-kutouten-type 'en-jp)

全角記号の変換: @ での日付入力は使わない

(setq skk-rom-kana-rule-list
      (append skk-rom-kana-rule-list
              '(("!" nil "!")
                (":" nil ":")
                (";" nil ";")
                ("?" nil "?")
                ("z " nil " ")
                ("\\" nil "\\")
                ("@" nil "@")
                )))

送り仮名が厳密に正しい候補を優先

(setq skk-henkan-strict-okuri-precedence t)

辞書の共有

(setq skk-share-private-jisyo t)

インクリメンタルサーチ

minibuffer 内では強制的に skk off.

(add-hook 'skk-mode-hook
          (lambda ()
            (and (skk-in-minibuffer-p)
                 (skk-mode-exit))))
(setq skk-isearch-start-mode 'latin)

インクリメンタルサーチは migemo に任せることに.

辞書の設定

追加している辞書の一覧は

といった所. はてなキーワードからの辞書の抽出は id:znzznz さんの

を参考に. MatsuCon で公開されている顔文字に関しては 顔文字に ; や が含まれている場合に, 適宜quoteする必要があるので 以下のスクリプトで適当に変換.

#!/usr/bin/env ruby
require 'nkf'
src = ARGV[0]
if ARGV.size < 1
  puts "usage: ime2skk.rb ime_dictionary"
  exit 0
end
File.open(src, "r") {|f|
  f.each do |line|
    line_euc = NKF.nkf("-S -e",line)
    if line_euc =~ /^([^!]+?)\t(.+?)\t.+$/
      entry = $1
      content = $2
      if content =~/;/
        puts entry + " /(concat \"" + content.gsub(';','\\\\073') + "\")/"
      elsif content =~/\//
        puts entry + " /(concat \"" + content.gsub('/','\\\\057') + "\")/"
      else
        puts entry + " /" + content + "/"
      end
    end
  end
}

他にも quote する必要あるような気もするけれど, それは気がついた時に.

辞書サーバの指定は以下.

(cond
 ((getenv "SKKSERVER")
  (setq skk-server-host "127.0.0.1")
  (setq skk-server-portnum "1178")
  (setq skk-large-jisyo nil)
  (add-to-list 'skk-search-prog-list
               '(skk-server-completion-search) t)
  (add-to-list 'skk-search-prog-list
               '(skk-comp-by-server-completion) t))
 (t
  (setq skk-get-jisyo-directory (concat my:d:tmp "skk-jisyo")
        skk-large-jisyo (concat skk-get-jisyo-directory "/SKK-JISYO.L")))
 )

辞書登録の際に送り仮名を削除

(setq skk-check-okurigana-on-touroku 'auto)

漢字登録のミスをチェックする

(setq skk-check-okurigana-on-touroku t)

動的補完

まだ設定していない…

;; ;; 動的補完
;; (setq skk-dcomp-activate t)
;; (setq skk-dcomp-multiple-activate t)
;; (setq skk-dcomp-multiple-rows 5)
;; ;; 動的補完の複数表示群のフェイス
;; (set-face-foreground 'skk-dcomp-multiple-face "Black")
;; (set-face-background 'skk-dcomp-multiple-face "LightGoldenrodYellow")
;; (set-face-bold-p 'skk-dcomp-multiple-face nil)
;; ;; 動的補完の複数表示郡の補完部分のフェイス
;; (set-face-foreground 'skk-dcomp-multiple-trailing-face "dim gray")
;; (set-face-bold-p 'skk-dcomp-multiple-trailing-face nil)
;; ;; 動的補完の複数表示郡の選択対象のフェイス
;; (set-face-foreground 'skk-dcomp-multiple-selected-face "White")
;; (set-face-background 'skk-dcomp-multiple-selected-face "LightGoldenrod4")
;; (set-face-bold-p 'skk-dcomp-multiple-selected-face nil)

部首変換, 総画数変換

上手く使いこなせていない

(add-to-list 'skk-search-prog-list
             '(skk-tankan-search 'skk-search-jisyo-file
                                 skk-large-jisyo 10000))

Copy & Paste: xclip

xclip で clipboard とデータをやりとり.

(use-package xclip
  :ensure t
  :if (executable-find "xclip")
  :config
  (turn-on-xclip))

clipboard と PRIMARY の同期には gpaste を使っている.

Elscreen [/]

modeline の表示そのものは無効化しておく.

  • [ ] Debian パッケージ版は古い.更新すべき
(use-package elscreen
  :ensure t
  :init
  (setq elscreen-tab-display-control nil)
  (setq elscreen-prefix-key (kbd "C-o"))
  (setq elscreen-display-tab 8)
  (setq elscreen-display-screen-number nil)
  :config
  (elscreen-start))

認証関連: password-store

id-manager の設定

ID と Password の簡単な組の管理をするのに非常に重宝している.

(use-package id-manager
  :ensure t
  :if (file-exists-p "~/.gnupg/idm-db.gpg")
  :bind ("M-7" . idm-open-list-command)
  :config
  (setq idm-database-file
        (expand-file-name "~/.gnupg/idm-db.gpg"))
  (setq idm-clipboard-expire-time-sec 30))

plstore

デフォルトは対称鍵暗号化なので, GPG_KEY_ID を設定しておく

(use-package plstore
  :init
  (setq plstore-secret-keys 'silent
        plstore-encrypt-to (getenv "GPG_KEY_ID")))

oauth2

oauth2 の認証情報は plstore で保存される. ファイルの置き場所と暗号鍵の設定をしておく

(use-package oauth2
  :ensure t
  :init
  (setq oauth2-token-file (concat my:d:tmp "oauth2.plstore")))

password-store

(use-package password-store
  :ensure t
  :if my:d:password-store
  )

MUA の設定: wanderlust

MUA として Wanderlust を使っている

Emacs 本体側の設定

Emacs 本体での設定は以下の通り. Wanderlust 自体の設定は別ファイルで行なわれる. ここでは wl-init-file を指定することで,設定ファイルを明示している.

(use-package wl
  :if (and (or (my:dpkg-status "wl")
               (my:dpkg-status "wl-beta"))
           (my:dpkg-status "rail"))
  :commands (wl wl-other-frame wl-draft wl-user-agent wl-user-agent-compose wl-draft-send wl-draft-kill)
  :init
  (unless (package-installed-p 'gcontacts-get-wl)
    (quelpa '(gcontacts-get-wl
              :fetcher url
              :url "https://raw.githubusercontent.com/uwabami/gcontacts-get-wl/master/gcontacts-get-wl.el")))
  (define-mail-user-agent
    'wl-user-agent
    'wl-user-agent-compose
    'wl-draft-send
    'wl-draft-kill
    'mail-send-hook)
  (setq elmo-msgdb-directory "~/.cache/wanderlust"
        elmo-maildir-folder-path "~/.cache/wanderlust"
        elmo-cache-directory "~/.cache/wanderlust"
        wl-score-files-directory "~/.cache/wanderlust"
        wl-init-file (concat user-emacs-directory "init-wl")
        mail-user-agent 'wl-user-agent
        read-mail-command 'wl)
  (unless (file-directory-p elmo-msgdb-directory)
    (make-directory elmo-msgdb-directory))
  (unless (file-directory-p (concat elmo-msgdb-directory "/local"))
    (make-directory (concat elmo-msgdb-directory "/local")))
  (unless (file-directory-p (concat elmo-msgdb-directory "/local/Trash"))
    (make-directory (concat elmo-msgdb-directory "/local/Trash")))
  )

Wanderlust 本体の設定

実際の設定は以下の通り

依存/追加ライブラリのインストールと読み込み

rail

SEMI や FLIM などの UA の表示に rail を使っている. ちなみに rail を有効にすると, 以下の様に User-Agent が表示される

http://uwabami.github.io/rail/images/wanderlust_with_or_without_rail.png

(eval-when-compile (require 'mime-def))
(use-package rail
  :config
  (setq rail-emulate-genjis t))

cp5022x を使う

ISO-2022-JP を CP50220 として扱う. Wanderlustと文字コード も参照のこと.

(add-to-list 'mime-charset-coding-system-alist '(iso-2022-jp . cp50220))
(setq wl-mime-charset 'utf-8)

gcontacts-get-wl

gcontacts-get-wl は Google Contacts の連絡先を Wanderlust の .Address に出力するだけのパッケージ. google-contacs.el の方が便利そうではあるものの「ふりがな」の扱いと, オフラインでの処理を考えて,結局安直な方法を選んでしまった.

(use-package gcontacts-get-wl
  :if (my:dpkg-status "wl-beta")
  :commands (gcontacts-update-wl-address)
  :config
  (load (expand-file-name "emacs/gcontacts-get.gpg" my:d:password-store)))

oauth token は pass で管理している.中身は以下の通り

(setq gcontacts-get-oauth-client-ID "XXXXXXXXXXXXXXXX.apps.googleusercontent.com"
      gcontacts-get-oauth-client-secret "YYYYYYYYYYYYYYYYYYYYYYYYY"
      gcontacts-get-ask nil)

elscreen-wl

メール作成時に elscreen と連携してくれる.便利

(use-package elscreen-wl)

SEMI の追加設定

HTML メールを表示するための設定: eww を使うことに. mime-setup がロードされる前に記述する必要あり.

(setq mime-view-text/html-previewer 'shr)
(setq mime-setup-enable-inline-html 'shr)
(use-package mime-setup
  :init
  (defun shr-colorize-region (start end fg &optional bg) nil))

どのアプリケーションで開くか → xdg-open に丸投げ.

(setq mime-view-mailcap-files '("~/.mailcap"))

~/.mailcap 自体は以下

applications/*; xdg-open %s;
image/*; xdg-open %s;
video/*; xdg-open %s;

MIME の例の保存先の変更

(setq mime-situation-examples-file
      (concat my:d:tmp "mime-example"))

text/plain を html より優先

(set-alist 'mime-view-type-subtype-score-alist '(text . html) 0)

音を鳴らすアレやコレの無効化

(setq mime-play-find-every-situations nil
      mime-play-delete-file-immediately nil
      process-connection-type nil)

個人情報の設定

具体的な設定内容は以下のファイルに置いている

(load (concat my:d:password-store "/emacs/wl-info.gpg"))

設定している内容は以下の通り

自身のメールアドレスと購読メーリングリストの設定

;; From: の設定
(setq wl-from (concat user-full-name " <" user-mail-address ">"))
;; (system-name) が FQDN を返さない場合、
;; `wl-local-domain' にホスト名を除いたドメイン名を設定
(setq wl-local-domain "example.com")
;; 自分のメールアドレスのリスト
(setq wl-user-mail-address-list
      (list (wl-address-header-extract-address wl-from)
            ;; "e-mail2@example.com"
            ;; "e-mail3@example.net" ...
            ))
;; 自分の参加しているメーリングリストのリスト
(setq wl-subscribed-mailing-list
      '("wl@lists.airs.net"
        "apel-ja@m17n.org"
        "emacs-mime-ja@m17n.org"
        ;; "ml@example.com" ...
        ))

送受信用サーバの設定

受信(IMAP)

(setq elmo-imap4-default-server "your imap server")
(setq elmo-imap4-default-port '993)
(setq elmo-imap4-default-stream-type 'ssl)

送信(SMTP)

(setq wl-smtp-posting-server "your smtp server")
(setq wl-smtp-posting-user "your account")
(setq wl-smtp-posting-port 587)
(setq wl-smtp-connection-type 'starttls)
(setq wl-smtp-authenticate-type "login")

From に応じて送信サーバをきりかえる.

本来はメール作成時/返信時の template の切り替えなのだれど, 送信時の SMTP の設定を from に合わせてきりかえるようにする. default に二重に指定しているのは, 一度別のアカウントに切り替えた後に再びトグルして戻って来た際に元に戻す(上書き)するため.

(setq wl-template-alist
      '(("default"
         ("From" . wl-from)
         (wl-smtp-posting-server . "your smtp server")
         (wl-smtp-posting-user . "your account")
         (wl-smtp-posting-port . 587)
         (wl-smtp-connection-type . 'starttls)
         (wl-smtp-authenticate-type . "login")
         )
        ("example1"
         ("From" . "Your Name <account@example1.com>")
         (wl-smtp-posting-server . "smtp.example1.com")
         (wl-smtp-posting-user . "your account")
         (wl-smtp-posting-port . 587)
         (wl-smtp-connection-type . 'starttls)
         (wl-smtp-authenticate-type . "login")
         )
        ("example2"
         ("From" . "Your Name <account@example2.com>")
         (wl-smtp-posting-server . "smtp.example2.com")
         (wl-smtp-posting-user . "your account")
         (wl-smtp-posting-port . 587)
         (wl-smtp-connection-type . 'starttls)
         (wl-smtp-authenticate-type . "plain")
         )
        ("ssh:smtp"
         ;; need ssh tunnel
         ;; ssh -f -N -L 20025:localhost:25 smtp.server.com
         ("From" . "Your Name <account@example3.com>")
         (wl-smtp-posting-server . "localhost")
         (wl-smtp-posting-user . "your ssh account")
         (wl-smtp-posting-port . 20025)
         (wl-smtp-connection-type . 'nil)
         (wl-smtp-authenticate-type . 'nil)
         )
        ))

ssh tunnel を自動的にやる事はできないモンだろうか (送信時に open して, 送信後に close する, みたいなの).

ついでに template の切り替えに関して幾つか設定.

;; template 切り替え時に 内容を表示
(setq wl-template-visible-select t)

draft-modeC-c C-n をするとテンプレートを切り替え

(define-key wl-draft-mode-map "\C-c\C-n" 'wl-template-select)

from に応じて wl-from, wl-envelope-from, 送信 smtp サーバを変更する送信時に変更

(add-hook 'wl-draft-send-hook
          (lambda ()
            (set (make-local-variable 'wl-from)
                 (std11-fetch-field "From"))))

送信時に自動的に wl-draft-config-alist を適用…しない?

(remove-hook 'wl-draft-send-hook 'wl-draft-config-exec)

基本設定

imap 関連

デフォルトの認証設定 フォルダ名は UTF-7 でエンコードされているので, 表示する際にこれをデコードする

(setq elmo-imap4-use-modified-utf7 t)

非同期チェック

なんか挙動が変な,ような….

(setq wl-folder-check-async nil)

フォルダの位置の default からの変更

~/.cache/wanderlust/ に集約している local の Mail folder の位置

(setq elmo-maildir-folder-path "~/.cache/wanderlust"
      elmo-localdir-folder-path "~/.cache/wanderlust/local")

local フォルダの設定: .lost+foundelmo-maildir-folder-path からの相対パスになっていることに注意

(setq elmo-lost+found-folder ".lost+found")
(setq wl-queue-folder "+queue")

folders の位置の変更

(setq wl-folders-file (concat my:d:password-store "/emacs/wl-folders.gpg"))

Drafts, Trash の置き場所

(setq wl-draft-folder "+Drafts")
(setq wl-trash-folder "+Trash")
(setq elmo-lost+found-folder "+lost+found")
(setq wl-temporary-file-directory "~/Downloads/")

アドレス帳 -> gcontacts-get-wlを使う. GNOME を使っているのであれば eweouz もおもしろそう.とりあえず読み込んでおく.

(setq wl-use-petname t)
(setq wl-address-file  "~/.mua/Address.wl")
(use-package eweouz
  :config
  (add-hook 'wl-hook 'eweouz-insinuate-wl))

LDAP サーバからアドレスを引くことも可能. 以前は GCALDaemon を使って local に ldap サーバを上げていたのだけれども, Google Contacts の API が変わったらしく GCALDaemon で LDAP サーバは使えなくなったのでコメントアウト.

(setq wl-use-ldap t)
(setq wl-ldap-server "localhost")
(setq wl-ldap-port "389")
(setq wl-ldap-base "dc=math,dc=kyoto-u,dc=ac,dc=jp")

パスワードの保存先

(setq elmo-passwd-alist-file-name (concat my:d:password-store "/emacs/wl-passwd.gpg"))

フォルダ編集時に backup を作成しない.

(setq wl-fldmgr-make-backup nil)

FCC, BCC の設定

(setq wl-fcc nil)
     ;; (setq wl-fcc "%Sent")

fcc を既読にする場合は以下.=wl-fcc= が nil の場合には意味は無い

(setq wl-fcc-force-as-read t)

bcc は常に自身に.

(setq wl-bcc (concat user-mail-address))

起動時に %INBOX のみをチェック

(setq wl-auto-check-folder-name "%INBOX")

フォルダ選択時の初期設定

imap の namespace を毎度入力するのが面倒なので,これを追加しておく.

(setq wl-default-spec "%")

confirm 関連の設定

スキャン時の問い合わせの無効化. ちなみに confirm を nil にしても 問い合わせが無いだけで threshold は効くので, 明示的に nil に.

(setq elmo-folder-update-confirm nil)
(setq elmo-folder-update-threshold nil)
(setq elmo-message-fetch-confirm nil)
(setq elmo-message-fetch-threshold nil)
(setq wl-prefetch-confirm nil)
(setq wl-prefetch-threshold nil)

終了時に確認しない

(setq wl-interactive-exit nil)

送信時は確認する :tangle init-wl.el

(setq wl-interactive-send t)

misc.

大きいメッセージを送信時に分割しない

(setq mime-edit-split-message nil)

スレッドは常に閉じる

(setq wl-thread-insert-opened nil)

3 pain 表示 -> 使わない

(setq wl-stay-folder-window nil)

未読を優先的に読む

(setq wl-summary-move-order 'unread)

改ページ無視

(setq wl-break-pages nil)

icon を使わない → GUI でもメニュー表示してないし, 体感的には遅くなる

(setq wl-highlight-folder-with-icon nil)

dispose, delete の設定

Gmail用に%INBOXでは削除を wl-trash-folder への移動ではなく,「delete」に.

(add-to-list 'wl-dispose-folder-alist
             '("^%INBOX" . remove))

迷惑メール関連も

(add-to-list 'wl-dispose-folder-alist
             '(".*Junk$" . remove))

折り返しの設定

message は折り返す.

(setq wl-message-truncate-lines nil)

draft も折り返す

(setq wl-draft-truncate-lines nil)

mode-line の設定

長いと嫌なのでイロイロ削る

(setq wl-summary-mode-line-format "") ; "%f {%t}(%n/%u/%a)"
(setq wl-message-mode-line-format "") ; "<< %f:%F>> [%m]"

キーバインド関連

use-package で設定しておいた方が良いかなぁ…

<f2> で Addrbook の更新

(global-set-key [f2] 'gcontacts-update-wl-address)

C-c C-j を browse-url に明け渡す

(define-key wl-draft-mode-map "\C-c\C-j" 'browse-url-at-point)

M-u で unread にする

(define-key wl-summary-mode-map "\M-u" 'wl-summary-mark-as-unread)

i で sync <- Mew 風

(define-key wl-summary-mode-map "i" 'wl-summary-sync-update)

C-o は elscreen で使う

(define-key wl-summary-mode-map "\C-o" nil )

M-oauto-refile (Mew 風)

(define-key wl-summary-mode-map "\M-o" 'wl-summary-auto-refile)

flag とフォルダを行き来する関数の追加

”=” でフラグ付きフォルダと 実際にメッセージのあるフォルダを行き来する. Gmail の「スター付き」フォルダでも有効

(require 'elmo nil 'noerror)
(defun my:wl-summary-jump-to-referer-message ()
  (interactive)
  (when (wl-summary-message-number)
    (if (eq (elmo-folder-type-internal wl-summary-buffer-elmo-folder) 'flag)
        (progn
          (let* ((referer (elmo-flag-folder-referrer
                           wl-summary-buffer-elmo-folder
                           (wl-summary-message-number)))
                 (folder (if (> (length referer) 1)
                             (completing-read
                              (format "Jump to (%s): " (car (car referer)))
                              referer
                              nil t nil nil (car (car referer)))
                           (car (car referer)))))
            (wl-summary-goto-folder-subr folder 'no-sync nil nil t)
            (wl-summary-jump-to-msg (cdr (assoc folder referer)))))
      (when (eq (elmo-folder-type wl-summary-last-visited-folder) 'internal)
        (wl-summary-goto-last-visited-folder)))))
(define-key wl-summary-mode-map "=" 'my:wl-summary-jump-to-referer-message)

summary-mode の表示のカスタマイズ

自分が差出人である mail は To:某 と表示

(setq wl-summary-showto-folder-regexp ".*")
(setq wl-summary-from-function 'wl-summary-default-from)

サマリ行の表示関連

サマリ行のフォーマット指定

(setq wl-summary-line-format
      "%T%P%1@%1>%Y/%M/%D %21(%t%[%19(%c %f%)%]%) %#%~%s")

サマリ表示は切り詰めない

(setq wl-subject-length-limit t)

スレッドの幅の指定

(setq wl-thread-indent-level 2)
(setq wl-thread-have-younger-brother-str "+"
      wl-thread-youngest-child-str "+"
      wl-thread-vertical-str "|"
      wl-thread-horizontal-str "-"
      wl-thread-space-str " ")

以下の二つの設定を有効にするには elmo-msgdb-extra-fields を設定する必要がある. この変数は振り分け判定にも使用するのでそこで設定している

Gmail 風に, 自分宛のメールに “>” をつけて表示する

元ネタ http://d.hatena.ne.jp/khiker/20080206/wanderlust

(setq wl-user-mail-address-regexp "^uwabami.*\\|^sasakyh.*")
;; 一覧表示での置き換え規則に追加
(defun my:wl-summary-line-for-me ()
  (if (catch 'found
        (let ((to (elmo-message-entity-field wl-message-entity 'to))
              (cc (elmo-message-entity-field wl-message-entity 'cc)))
          (when (or (stringp to) cc)
            (setq to
                  (append (if (stringp to) (list to) to)
                          (when cc
                            (if (stringp cc) (list cc) cc)))))
          (dolist (i to)
            (when (wl-address-user-mail-address-p (eword-decode-string i))
              (throw 'found t)))))
      ">"
    ""))
;; > を summary-line-format に追加
(setq wl-summary-line-format-spec-alist
      (append wl-summary-line-format-spec-alist
              '((?> (my:wl-summary-line-for-me)))))

添付ファイルがあったら, サマリ行に “@” を付ける

(setq wl-summary-line-format-spec-alist
      (append wl-summary-line-format-spec-alist
              '((?@ (wl-summary-line-attached)))))

クォートされた文字列もデコードする

(setq mime-header-lexical-analyzer
      '(
        ;; eword-analyze-quoted-string
        eword-analyze-domain-literal
        eword-analyze-comment
        eword-analyze-spaces
        eword-analyze-special
        eword-analyze-encoded-word
        eword-analyze-atom))

Subject が変わってもスレッドを切らない

(setq wl-summary-divide-thread-when-subject-changed nil)

Subject での Tab や複数スペースを無視

(defadvice std11-unfold-string (after simply activate)
  (setq ad-return-value
        (elmo-replace-in-string ad-return-value "[ \t]+" " ")))

重複メッセージを非表示に

フォルダ内の Message-ID が同じメールを非表示にする

(setq wl-folder-process-duplicates-alist
      '(
        (".*" . hide)
        ))

sort 順: 返信が来た順

flet を書き換えるのが面倒で el-x にある dflet を使うように変更

(defun wl-summary-overview-entity-compare-by-reply-date (a b)
  "Compare message A and B by latest date of replies including thread."
  (dflet ((string-max2 (x y)
                       (cond ((string< x y) y)
                             ('t x)))
          (thread-number-get-date (x)
                                  (timezone-make-date-sortable (elmo-msgdb-overview-entity-get-date
                                                                (elmo-message-entity
                                                                 wl-summary-buffer-elmo-folder x))))
          (thread-get-family (x)
                             (cons x (wl-thread-entity-get-descendant (wl-thread-get-entity x))))
          (max-reply-date (x)
                          (cond ((eq 'nil x)
                                 'nil)
                                ((eq 'nil (cdr x))
                                 (thread-number-get-date (car x)))
                                ('t
                                 (string-max2 (thread-number-get-date (car x))
                                              (max-reply-date (cdr x)))))))
    (string<
     (max-reply-date (thread-get-family (elmo-message-entity-number a)))
     (max-reply-date (thread-get-family (elmo-message-entity-number b))))))
(add-to-list 'wl-summary-sort-specs 'reply-date)
(setq wl-summary-default-sort-spec 'reply-date)

振り分け設定

$ 以外を振り分け対象に

(setq wl-summary-auto-refile-skip-marks '("$"))

振り分け判定に使用するヘッダ

添付の有無の表示にも使うので Content-Type も登録. あと Delivered-To はメールの検索の時に結構重宝している.

(setq elmo-msgdb-extra-fields
      '(
        "List-Post"
        "List-Id"
        "List-ID"                  ;; たまに List-ID で来るメールあるよね?
        "Resent-CC"
        "Mailing-List"
        "X-Mailing-List"
        "X-ML-Address"
        "X-ML-Name"
        "X-ML-To"
        "Delivered-To"
        "Content-Type"              ;; 添付の有無の表示の為に追加
        "X-Google-Appengine-App-Id" ;; GAEの送信するメールの振り分け用
        "To"
        "Cc"
        "From"
        "Subject"
        "Reply-To"
        "Auto-Submitted"            ;; Git commit/Cron notify
        ))

日本語添付ファイル名のデコード

日本語の添付ファイルに関しては, いまだにうまくいかない時がある.

(defvar my-mime-filename-coding-system-for-decode
  '(iso-2022-jp japanese-shift-jis japanese-iso-8bit))
(defun my-mime-decode-filename (filename)
  (let ((filename (if (string-match "\n\t*" filename)
                      (replace-match "" nil nil filename)
                    filename))
        (rest (eword-decode-string filename)))
    (or (when (and my-mime-filename-coding-system-for-decode
                   (string= rest filename))
          (let ((dcs (mapcar (function coding-system-base)
                             (detect-coding-string filename))))
            (unless (memq 'emacs-mule dcs)
              (let ((pcs my-mime-filename-coding-system-for-decode))
                (while pcs
                  (if (memq (coding-system-base (car pcs)) dcs)
                      (setq rest (decode-coding-string filename (car pcs))
                            pcs nil)
                    (setq pcs (cdr pcs))))))))
        rest)))
(eval-after-load "mime"
  '(defadvice mime-entity-filename
       (after eword-decode-for-broken-MUA activate)
     "Decode encoded file name for BROKEN MUA."
     (when (stringp ad-return-value)
       (setq ad-return-value (my-mime-decode-filename ad-return-value)))))
(require 'std11 nil 'noerror)
(eval-after-load "std11"
  '(defadvice std11-wrap-as-quoted-string
       (before encode-string activate)
     "Encode a string."
     (require 'eword-encode)
     (ad-set-arg 0 (eword-encode-string (ad-get-arg 0)))))
;; 二重エスケープを回避
    (defun shell-quote-argument (file) file)

メッセージ表示

いったん全て非表示に

(setq wl-message-ignored-field-list '("^.*:"))

見たいヘッダだけ表示

(setq wl-message-visible-field-list
      '("^Subject:"
        "^From:"
        "^To:"
        "^Cc:"
        "^Date:"
        "^Message-ID:"
        ))

表示順の変更

Mew 風…

(setq wl-message-sort-field-list
      '("^Subject:"
        "^From:"
        "^To:"
        "^Cc:"
        "^Date:"
        "^Message-ID:"
        ))

mime の画像表示の切り替え

M-T でトグル

(defun wl-summary-w3m-safe-toggle-inline-images (&optional arg)
  "Toggle displaying of all images in the message buffer.
     If the prefix arg is given, all images are considered to be safe."
  (interactive "P")
  (with-current-buffer wl-message-buffer
    (w3m-toggle-inline-images arg)))
(eval-after-load "wl-summary"
  '(define-key wl-summary-mode-map
     "\M-T" 'wl-summary-w3m-safe-toggle-inline-images))

From, To を省略表示しない

To や From にアドレスが沢山指定されていると省略されるので,これを無効化

(setq wl-message-use-header-narrowing nil)

作成/返信設定

自分宛のメールに返信する場合は To:, Cc: から自分のアドレスを削除

(setq wl-draft-always-delete-myself t)

“a” (without-argument)では Reply-To:From: などで 指定された唯一人または唯一つの投稿先に返信. また, X-ML-Name:Reply-To: がついているなら Reply-To: 宛に返信

(setq wl-draft-reply-without-argument-list
      '((("X-ML-Name" "Reply-To") . (("Reply-To") nil nil))
        ("X-ML-Name" . (("To" "Cc") nil nil))
        ("Followup-To" . (nil nil ("Followup-To")))
        ("Newsgroups" . (nil nil ("Newsgroups")))
        ("Reply-To" . (("Reply-To") nil nil))
        ("Mail-Reply-To" . (("Mail-Reply-To") nil nil))
        ("From" . (("From") nil nil))))

C-u a (with-argument)であれば関係する全ての人・投稿先に返信

(setq wl-draft-reply-with-argument-list
      '(("Followup-To" . (("From") nil ("Followup-To")))
        ("Newsgroups" . (("From") nil ("Newsgroups")))
        ("Mail-Followup-To" . (("Mail-Followup-To") nil ("Newsgroups")))
        ("From" . (("From") ("To" "Cc") ("Newsgroups")))))

サマリ表示には petname を使うが, 引用には使わない

(setq wl-default-draft-cite-decorate-author nil)

draft mode で orgtbl を有効に

(add-hook 'wl-draft-mode-hook 'turn-on-orgtbl)

c-sig

署名の選択に c-sig を使用している. 設定は以下の通り. Mew 風に C-c <tab> で signature を挿入するようにしている

(use-package c-sig
  :init
  :config
  (eval-when-compile (require 'wl))
  (setq sig-insert-end t
        sig-save-to-sig-name-alist nil
        message-signature-file nil)
  (define-key wl-draft-mode-map "\C-c\t" 'insert-signature-eref)
  (add-hook 'wl-draft-mode-hook
            '(lambda ()
               (define-key (current-local-map) "\C-c\C-w"
                 'insert-signature-eref)))
  )

Face の設定

デフォルトより細かく指定するために幾つかの face 定義を追加.

(setq wl-highlight-message-header-alist
      '(("Subject[ \t]*:"
         . wl-highlight-message-subject-header-contents)
        ("From[ \t]*:"
         . wl-highlight-message-from-header-contents)
        ("Date[ \t]*:"
         . wl-highlight-message-date-header-contents)
        ("\\(.*To\\|Cc\\|Newsgroups\\)[ \t]*:"
         . wl-highlight-message-important-header-contents)
        ("\\(User-Agent\\|X-Mailer\\|X-Newsreader\\)[ \t]*:" .
         wl-highlight-message-unimportant-header-contents)
        ))
(defun my:wl-set-face (face spec)
  (make-face face)
  (cond ((fboundp 'face-spec-set)
         (face-spec-set face spec))
        (t
         (wl-declare-face face spec))))
(my:wl-set-face 'wl-highlight-folder-closed-face                  '((t (:foreground "#4cff4c" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-folder-few-face                     '((t (:foreground "#FF4C4C" :bold t :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-folder-killed-face                  '((t (:foreground ,my:h:black :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-folder-many-face                    '((t (:foreground ,my:h:magenta :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-folder-opened-face                  '((t (:foreground "#4cffff" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-folder-path-face                    '((t (:underline t :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-folder-unknown-face                 '((t (:foreground "#4cffff" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-folder-unread-face                  '((t (:foreground ,my:n:blue :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-folder-zero-face                    '((t (:foreground "#F6F3E8" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-header-separator-face               '((t (:inherit highlight :bold t ))))
;; (my:wl-set-face 'wl-highlight-message-citation-header             '((t (:foreground ,my:h:green :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-1                '((t (:foreground "#7fff7f" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-2                '((t (:foreground "#ffff7f" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-3                '((t (:foreground "#7f7fff" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-4                '((t (:foreground "#7fffff" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-5                '((t (:foreground "#ff7fff" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-6                '((t (:foreground "#ff7f7f" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-7                '((t (:foreground "#4cff4c" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-8                '((t (:foreground "#ffff4c" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-9                '((t (:foreground "#4c4cff" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-10               '((t (:foreground "#4cffff" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-11               '((t (:foreground "#ff4cff" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-cited-text-12               '((t (:foreground "#ff4c4c" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-date-header-contents        '((t (:foreground "#4CFF4C" :bold t :italic nil ))))
(my:wl-set-face 'wl-highlight-message-header-contents             '((t (:foreground "#aaaaaa" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-headers                     '((t (:foreground "#4CFFFF" :bold t :italic nil ))))
(my:wl-set-face 'wl-highlight-message-important-header-contents2  '((t (:foreground "#4CFF4C" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-signature                   '((t (:foreground "#aaaaaa" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-message-important-header-contents   '((t (:foreground "#FF4CFF" :bold t :italic nil ))))
(my:wl-set-face 'wl-highlight-message-subject-header-contents     '((t (:foreground "#FF4C4C" :bold t :italic nil ))))
(my:wl-set-face 'wl-highlight-message-from-header-contents        '((t (:foreground "#FFFF4C" :bold t :italic nil ))))
(my:wl-set-face 'wl-highlight-message-unimportant-header-contents '((t (:foreground "#aaaaaa" :bold nil :italic nil ))))
(my:wl-set-face 'wl-highlight-summary-answered-face               '((t (:foreground "#4CFF4C" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-copied-face                 '((t (:foreground "#4CFFFF" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-deleted-face                '((t (:foreground ,my:h:black :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-displaying-face             '((t (:underline t :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-disposed-face               '((t (:foreground "#aaaaaa" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-flagged-face                '((t (:foreground ,my:h:yellow :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-forwarded-face              '((t (:foreground ,my:h:blue :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-high-read-face              '((t (:foreground ,my:h:green :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-high-unread-face            '((t (:foreground ,my:h:orange :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-important-face              '((t (:foreground "#ffff4c" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-important-flag-face         '((t (:foreground "#ffff4c" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-killed-face                 '((t (:foreground ,my:h:black :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-l:read-face                 '((t (:foreground "#4CFF4C" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-l:unread-face               '((t (:foreground ,my:h:lightb :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-new-face                    '((t (:foreground "#ff4c4c" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-normal-face                 '((t (:foreground "#f6f3e8" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-prefetch-face               '((t (:foreground ,my:n:blue :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-summary-refiled-face                '((t (:foreground "#7F7FFF" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-resend-face                 '((t (:foreground ,my:h:orange :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-target-face                 '((t (:foreground "#4CFFFF" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-temp-face                   '((t (:foreground ,my:n:violet :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-summary-thread-top-face             '((t (:foreground "#F6F3E8" :bold t :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-summary-unread-face                 '((t (:foreground "#ff4c4c" :bold nil :italic nil :weight normal ))))
;; (my:wl-set-face 'wl-highlight-thread-indent-face                  '((t (:underline t :bold nil :italic nil :weight normal ))))

GPG 署名

以前は mailcrypt を使っていたけれど, epa があるので主にキーバインドの設定のみ. draft-mode の文字コードをあらかじめ指定しておかないと, 送信時に文字コードが変換されるので不正な署名となってしまう.

もっとうまい方法/正攻法がありそうな気がするけれど, 使えてるから, まあ良いかな, とか.

(setq mime-pgp-verify-when-preview nil)
(add-hook 'wl-draft-mode-hook
          (lambda ()
            (set-buffer-file-coding-system 'iso-2022-jp)
            ))
(defun my:epa-wl-decrypt-message ()
  (interactive)
  (save-window-excursion
    (wl-summary-jump-to-current-message)
    (wl-message-decrypt-pgp-nonmime)))
(defun my:epa-wl-verify-message ()
  (interactive)
  (save-selected-window
    (wl-summary-jump-to-current-message)
    (wl-message-verify-pgp-nonmime)))
(define-key wl-summary-mode-map "\C-c : d" 'my:epa-wl-decrypt-message)
(define-key wl-summary-mode-map "\C-c : v" 'my:epa-wl-verify-message)
(define-key wl-draft-mode-map "\C-c : s" 'epa-mail-sign)
(define-key wl-draft-mode-map "\C-c : e" 'epa-mail-encrypt)

検索

imap の検索か mu(maildir-utils) の検索. mu の検索が偶にセグフォるので悩み所

(use-package elmo-search
  :bind (:map wl-summary-mode-map
              ("v" . wl-quicksearch-goto-search-folder-wrapper)
              :map wl-folder-mode-map
              ("v" . wl-quicksearch-goto-search-folder-wrapper))
  :config
  (elmo-search-register-engine
   'mu 'local-file
   :prog "mu"
   :args '("find" "-u" elmo-search-split-pattern-list "--fields" "l" "--sortfield" "date" "-r")
   :charset 'utf-8)
  (setq elmo-search-default-engine 'mu)
  (setq wl-quicksearch-folder "[]"))

検索時にメールが多すぎると怒られるので. 数字は適当.

(setq elmo-multi-divide-number 10000000)
(setq elmo-multi-number 10000000)

Linux Desktop で mailto: リンクを扱うために

ついでに mailto のリンクを emacsclient で扱うために,以下の関数を定義しておく

(defun my:mailto-compose-mail (mailto-url)
  (if (and (stringp mailto-url)
           (string-match "\\`mailto:" mailto-url))
      (progn
        (require 'rfc2368)
        (let* ((headers (mapcar (lambda (h) (cons (intern (car h)) (cdr h)))
                                (rfc2368-parse-mailto-url mailto-url)))
               (good-headers (remove-if (lambda (h) (member (car h) '(Body))) headers))
               (body (cdr (assoc 'Body headers))))
          (wl-draft good-headers nil nil body)))))

Desktop の設定では

#!/bin/sh
# emacs-mailto-handler

mailto=$1
mailto="mailto:${mailto#mailto:}"
mailto=$(printf '%s\n' "$mailto" | sed -e 's/[\"]/\\&/g')
elisp_expr="(my:mailto-compose-mail \"$mailto\")"

emacsclient -a "" -n --eval "$elisp_expr" \
	'(set-window-dedicated-p (selected-window) t)'

をメーラとして指定すれば良い. GNOME は .desktop ファイルが無いと「お気に入り」登録ができないので 以下のファイルを適当な名前で ~/.local/share/applications/ 以下に放り込んでおくと良いだろう

[Desktop Entry]
Name=Emacs Mail Handler
GenericName=Mail User Agent
X-GNOME-FullName=Emacs Mail Handler
Comment=Use emacsclient as MUA, handling mailto link
Keywords=email
Exec=/home/uwabami/bin/emacs-mailto-handler %U
Icon=emacs25
Terminal=false
Type=Application
Categories=GNOME;GTK;Office;Email;
StartupNotify=false
MimeType=application/mbox;message/rfc822;x-scheme-handler/mailto;

補完: helm

以前はデフォルトの挙動が嫌で割とイロイロと設定していたのだけれど, 最近はそんなに邪魔しない感じ…なのかな? とりあえず現状は以下の通り.

(use-package helm
  :ensure t
  :defines helm-map
  :diminish (helm-migemo-mode)
  :bind (("M-x"     . helm-M-x)
         ("C-x f"   . helm-find-files)
         ("C-x C-f" . helm-find-files)
         ("C-x b"   . helm-buffers-list)
         ("C-x C-b" . helm-buffers-list)
         ("C-x C-r" . helm-recentf)
         )
  :config
  (define-key helm-map (kbd "TAB") 'helm-execute-persistent-action)
  (define-key helm-map (kbd "C-i") 'helm-execute-persistent-action)
  (global-unset-key (kbd "C-z"))
  (define-key helm-map (kbd "C-z") 'helm-select-action)
  (my:disable-builtin-mode 'helm-mode)   ; helm-mode は基本使わない
  (setq helm-command-prefix-key "C-z"    ; helm-command-prefix-key
        ;; dired での skk との競合(C-x C-j の奪い合い)を避ける
        dired-bind-jump nil
        ;; mode line には何も表示しない
        helm-completion-mode-string ""
        ;; minibuffer に input method の状態を引き継がない
        helm-inherit-input-method nil
        ;; 余計なファイルは表示しない
        helm-ff-skip-boring-files t
        ;; helm-adaptive の保存先の変更
        helm-adaptive-history-file (concat my:d:tmp "helm-adaptive-history")
        ;; mode line には何も表示しない
        helm-completion-mode-string ""
        )
  ;; 一つ上のディレクトリ(../)を候補から外す
  (advice-add 'helm-ff-filter-candidate-one-by-one
              :around (lambda (orig-func file)
                        (unless (string-match "\\(?:/\\|\\`\\)\\.\\{2\\}\\'" file)
                          (funcall orig-func file))))
  ;; 存在しないファイルには何もしない(default は新規 buffer ができる)
  (advice-add 'helm-ff-kill-or-find-buffer-fname
              :around (lambda (orig-func candidate)
                        (when (file-exists-p candidate)
                          (funcall orig-func candidate))))
  (if (and (locate-library "migemo")     ; あれば migemo を有効化
           (executable-find "cmigemo"))
      (setq helm-migemo-mode t)
    (setq helm-migemo-mode nil))
  (helm-autoresize-mode)
  (setq helm-autoresize-min-height 30 ; fixed 30%
        helm-autoresize-max-height 30)
  )

helm-flx

曖昧検索は flx に任せる.かなり良い.

(use-package helm-flx
  :ensure t
  :config
  (helm-flx-mode +1)
  (setq helm-flx-for-helm-find-files t ;; t by default
        helm-flx-for-helm-locate t) ;; nil by default
  )

helm-locate

default の mlocate の option を修正しておく.

(use-package helm-locate
  :if (executable-find "mlocate")
  :config
  (setq helm-locate-command "mlocate %s -e -A --regex %s"))

helm-descbinds

helm-M-x の際にキーバインドが表示されるようになる

(use-package helm-descbinds
  :ensure t
  :config
  (helm-descbinds-mode))

helm-ag

ripgrep があればそっちを使うようにしてみた.

(use-package helm-ag
  :ensure t
  :if (or (executable-find "ag")
          (executable-find "rg"))
  :bind (("M-g ." . helm-ag)
         ("M-g ," . helm-ag-pop-stack)
         ("C-M-s" . helm-ag-this-file))
  :config
  (cond
   ((executable-find "rg")
    (setq helm-ag-base-command "rg --vimgrep --no-heading"))
   (t
    (setq helm-ag-base-command "ag --nocolor --nogroup --ignore-case"
          helm-ag-command-option "--all-text")))
  (setq helm-ag-insert-at-point 'symbol)
  )

補完: yasnippet, auto-complete [/]

  • [ ] 上手く設定できていないので保留

yasnippet

(use-package yasnippet
  :disabled t
  :bind (:map yas-minor-mode-map
              ("C-x y i" . yas-insert-snippet)
              ("C-x y n" . yas-new-snippet)
              ("C-x y v" . yas-visit-snippet-file)
              ("<tab>"   . nil)
              ("TAB"     . nil)
              ("C-<tab>" . yas-expand))
  :diminish yas-minor-mode
  :init
  (defconst my:d:yasnippet
    (expand-file-name "yasnippet" my:d:share))
  (unless (file-directory-p my:d:yasnippet)
    (make-directory my:d:yasnippet))
  :config
  (setq yas-snippet-dirs
        (list my:d:yasnippet yas-installed-snippets-dir))
  (yas-global-mode 1)
  (setq yas-verbosity 2))

auto-complete

(use-package auto-complete-config
  :disabled t
  :diminish auto-complete-mode
  :bind (:map ac-menu-map
              ("C-n"   . ac-next)
              ("C-p"   . ac-previous)
              :map ac-completing-map
              ("<tab>" . ac-complete)
              ("RET"   .  nil)
              ("M-/"   . ac-stop))
  :config
  ;; おまじない
  (ac-flyspell-workaround)
  ;; 辞書追加
  (add-to-list 'ac-dictionary-directories (concat my:d:share "ac-dict"))
  (setq ac-comphist-file (concat my:d:tmp "ac-comphist.dat"))
  (setq ac-auto-start 4)                         ; 4 文字以上で起動
  (setq ac-auto-show-menu 1)                     ; 1秒でメニュー表示
  (setq ac-use-comphist t)                       ; 補完候補をソート
  (setq ac-candidate-limit nil)                  ; 補完候補表示を無制限に
  (setq ac-use-quick-help nil)                   ; tool tip 無し
  (setq ac-use-menu-map t)                       ; キーバインド
  ;; yasnippet 対応
  (setf (symbol-function 'yas-active-keys)
        (lambda ()
          (remove-duplicates
           (mapcan #'yas--table-all-keys (yas--get-snippet-tables)))))
  (ac-config-default)
  (global-auto-complete-mode t)
  )

校正,辞書等

spell checker

ispell はコマンドとして aspell を利用する.

(use-package ispell
  :init
  (setq-default ispell-program-name "aspell")
  :config
  (add-to-list 'ispell-skip-region-alist '("[^\000-\377]+")))

flyspell-mode は別途有効化しておいた方が良いのかもしれない

(use-package flyspell
  :diminish flyspell-mode
  :config
  (defun my:flyspell-popup-choose (orig event poss word)
    (if (window-system)
        (funcall orig event poss word)
      (flyspell-emacs-popup-textual event poss word)))
  (advice-add 'flyspell-emacs-popup :around #'my:flyspell-popup-choose)
  )

辞書

(use-package lookup
  :commands (lookup lookup-region lookup-pattern)
  :if (and (my:dpkg-status "lookup-el")
           (file-exists-p "/usr/local/share/dict/lookup-enabled"))
  :bind (("C-c w" . lookup-pattern)
         ("C-c W" . lookup-word))
  :init
  (setq lookup-search-agents
        '(
          (ndeb "/usr/local/share/dict/eijiro"    :alias "英辞郎")
          (ndeb "/usr/local/share/dict/waeijiro"  :alias "和英辞郎")
          (ndeb "/usr/local/share/dict/rikagaku5" :alias "理化学辞典 第5版")
          (ndeb "/usr/local/share/dict/koujien4"  :alias "広辞苑 第4版")
          (ndeb "/usr/local/share/dict/wadai5"    :alias "研究社 和英大辞典 第5版")
          (ndeb "/usr/local/share/dict/eidai6"    :alias "研究社 英和大辞典 第6版")
          (ndeb "/usr/local/share/dict/colloc"    :alias "研究社 英和活用大辞典 ")
          )))

カレンダー: japanese-holidays

日本の祝日を表示するために japanese-holidays をインストール

(use-package japanese-holidays
  :ensure t
  :init
  (add-hook 'calendar-today-visible-hook   'japanese-holiday-mark-weekend)
  (add-hook 'calendar-today-invisible-hook 'japanese-holiday-mark-weekend)
  (add-hook 'calendar-today-visible-hook   'calendar-mark-today)
  :config
  ;; とりあえず日本のみを表示
  (setq calendar-holidays
        (append japanese-holidays holiday-local-holidays))
  ;; 祝日をカレンダーに表示
  (setq mark-holidays-in-calendar t)
  ;; 月と曜日の表示調整
  (setq calendar-month-name-array
        ["01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" ])
  (setq calendar-day-name-array
        ["" "" "" "" "" "" ""])
  (setq calendar-day-header-array
        ["" "" "" "" "" "" ""])
  ;; ISO format (YYYY/MM/DD) に変更
  (setq calendar-date-style 'iso)
  (calendar-set-date-style 'iso)
  ;; 土曜日・日曜日を祝日として表示
  (setq japanese-holiday-weekend '(0 6)
        japanese-holiday-weekend-marker
        '(holiday nil nil nil nil nil japanese-holiday-saturday))
  ;; 日曜開始
  (setq calendar-week-start-day 0))

Org

org-mode が無いと生きていけない体になりました

基本設定: org

目新しい設定はしていない,と思う.強いて言えば 以前のメモの整理のために howm: Hitori Otegaru Wiki Modoki も使っているので, howm も有効にしている,ぐらい.

(defvar my:d:org (concat (getenv "HOME") "/Dropbox/org/"))
(use-package org
  :bind (("C-x n s" . org-narrow-to-subtree)
         ("C-x n w" . widen))
  :init
  :config
  (setq org-directory my:d:org                 ;; Dropbox に保存する
        org-return-follows-link t              ;; return でリンクを辿る
        org-startup-folded t                   ;; 見出しを畳んで表示
        org-startup-truncated t                ;; 折り返し無し
        org-emphasis-alist                     ;; 基本 "-nw" なので色変更
        (cons '("+" '(:strike-through t :foreground "#999999"))
              (cl-delete "+" org-emphasis-alist :key 'car :test 'equal))
        ;; GTD: 状態の追加
        org-todo-keywords '((sequence "TODO(t)" "WAIT(w)" "|" "DONE(d)" "CANCEL(c)" "SOMEDAY(s)")
                            (type "ARTICLE(a)")
                            (type "MEMO(m)"))
        ;; GTD: タグの追加
        org-tag-alist '(("OFFICE"     . ?o)
                        ("HOME"       . ?h)
                        ("MAIL"       . ?m)
                        ("WORK"       . ?w)
                        ("Debian"     . ?d)
                        ("Computer"   . ?c)
                        ("Book"       . ?b)
                        ("Emacs"      . ?e)
                        ("TeX"        . ?t)
                        ("Ruby"       . ?r)
                        )
        )
  ;; GTD: TODO→...→DONE としたエントリを =Arhive.org= に移動
  (defun my:org-archive-done-tasks ()
    (interactive)
    ;; ARCHIVE タグを付けるだけなら以下
    ;;   (org-map-entries 'org-archive-set-tag "/DONE" 'file))
    ;; org-archive-location に refile したいなら以下
    (org-map-entries 'org-archive-subtree "/DONE" 'file))
  (setq org-archive-location "Archive.org::")
  (add-hook 'org-todo-statistics-hook 'my:org-archive-done-tasks)
  (add-hook 'org-todo-after-statistics-hook 'my:org-archive-done-tasks)
  ;; 文字コード強制 ... 今時いらないかも.
  (modify-coding-system-alist 'file "\\.org\\'" 'utf-8)
  ;; howm ファイルも org-mode で.
  (add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
  (add-to-list 'auto-mode-alist '("\\.howm$" . org-mode))
  ;;; timestamp 更新文字列の変更
  ;;  org-mode では #+DATE: をひっかける用に(#は小文字).
  (defun my:org-timestamp-hook ()
    "Change `time-stamp-start' in org-mode"
    (set (make-local-variable 'time-stamp-start) "#\\+DATE: 2")
    (set (make-local-variable 'time-stamp-end)   "\$")
    )
  (add-hook 'org-mode-hook 'my:org-timestamp-hook)
  )

Orglink

org 形式の link を他のモードでも使えるようにする

(use-package orglink
  :ensure t
  :diminish orglink-mode
  :config
  (global-orglink-mode +1)
  )

Capture: メモ取り

キーバインドは以前 changelog memo をやっていた時の癖で C-x m をメモにしている. 他には wanderlust のメールを扱えるように org-wl を読み込んで template を追加したぐらい. mu のインデックスの方が良いかもしれない,と最近思っている.

(use-package org-wl
  :if (and (my:dpkg-status "wl-beta")
           (file-directory-p org-directory)))
(use-package org-capture
  :bind (("C-x m" . org-capture))
  :if (file-directory-p org-directory)
  :config
  (setq org-default-notes-file (concat org-directory "Memo.org")
        org-capture-templates
        `(
          ("t" "TODO" plain
           (file (concat org-directory "Memo.org"))
           "* TODO %^{title} %^g\n  %?\n  %a"
           :prepend nil
           :unnarrowed t
           :kill-buffer t
           )
          ;; "* TODO <%<%Y-%m-%d>> %:subject %^g\n  %?\n  %a\n  #+BEGIN_QUOTE\n%i\n  #+END_QUOTE"
          ("e" "Email TODO" plain
           (file (concat org-directory "Memo.org"))
           "* TODO [[wl:\%5Bmsgid:%:message-id-no-brackets\%5D][%(replace-regexp-in-string \"\\\\[.*\\\\] \" \"\" \"%:subject\")]]\n  :PROPERTIES:\n  :CREATED: %u\n  :END:%?\n"
           :prepend nil
           :unnarrowed nil
           :kill-buffer t
           )
          ("m" "Memo" plain
           (file (concat org-directory "Memo.org"))
           "* MEMO %t %^{titlle}\n  %?\n  %a"
           :prepend nil
           :unnarrowed t
           :kill-buffer t
           )
          ))
  )

Agenda: スケジュール,TODO 表示

GTD 用の設定.後述の org-gcalorgmine で取得したデータも表示している. ついでに

  • 土曜日をの face を追加.
  • 祝日, 休日を日曜と同じfaceにする.

なんて事もやっている.元ネタは Org-mode and holidays

(use-package org-agenda
  :if (file-directory-p my:d:org)
  :bind (("C-c a" . org-agenda))
  :init
  (defface my:org-agenda-date-saturday
    '((t (:foreground "#7FBFFF" :bold t )))
    "Agenda 表示中の土曜日用のface")
  (defface my:org-agenda-date-today-saturday
    '((t (:inherit my:org-agenda-date-saturday :underline t)))
    "Agenda 表示中の今日かつ土曜日用のface")
  (defface my:org-agenda-date-today-weekend
    '((t (:inherit org-agenda-date-weekend :underline t)))
    "Agenda 表示中の今日かつ日・祝日用のface")
  ;; こっからは org-gcal で同期したカレンダーの色
  (defface my:org-agenda-calendar-KUSM
    '((t (:foreground "#7FFF7F")))
    "Agenda 表示中, KUSM.org の表示 face"
    :group 'org-agenda )
  (defface my:org-agenda-calendar-Schedule
    '((t (:foreground "#7FFFFF")))
    "Agenda 表示中, Schedule.org の表示 face"
    :group 'org-agenda )
  (defface my:org-agenda-calendar-GFD
    '((t (:foreground "#FFFF7F")))
    "Agenda 表示中, GFD.org の表示 face"
    :group 'org-agenda )
  (defface my:org-agenda-calendar-DebianJP
    '((t (:foreground "#BF7FFF")))
    "Agenda 表示中, DebianJP.org の表示 face"
    :group 'org-agenda )
  (defface my:org-agenda-calendar-twitter
    '((t (:foreground "#CCCCCC")))
    "Agenda 表示中, Twiiter log の表示 face"
    :group 'org-agenda )
  ;; 更新用の関数 - とりあえず動いているので良しとするが,リファクタリングしたい
  (defun my:org-agenda-day-face-function (date)
    "Compute DATE face for saturday, holidays."
    (cl-dolist (file (org-agenda-files nil 'ifmode))
      (cond
       ((member (calendar-day-of-week date) '(7))
        (if (org-agenda-todayp date)
            (cl-return 'my:org-agenda-date-today-weekend))
        (cl-return 'org-agenda-date-weekend))
       ((member (calendar-day-of-week date) '(6))
        (if (org-agenda-todayp date)
            (cl-return 'my:org-agenda-date-today-saturday))
        (cl-return 'my:org-agenda-date-saturday)))
      (let ((face
             (cl-dolist (entry (org-agenda-get-day-entries file date))
               (let ((category (with-temp-buffer
                                 (insert entry)
                                 (org-get-category (point-min)))))
                 (when (or (string= "祝日" category)
                           (string= "休日" category))
                   (if (org-agenda-todayp date)
                       (cl-return 'my:org-agenda-date-today-weekend)
                     (cl-return 'org-agenda-date-weekend)))))))
        (when face (cl-return face)))))
  :config
  ;; 使用するファイル
  (setq org-agenda-files nil)
  (dolist (file
           '("Archive.org"
             "Diary.org"
             "Memo.org"
             "Schedule.org"
             "GFD.org"
             "KUSM.org"
             "DebianJP.org"
             "twitter.org"
             "journal.org"
             "redmine_GFD.org"
             "redmine_FluidSoc.org"
             "redmine_KUSM.org"
             ))
    (add-to-list 'org-agenda-files (concat org-directory file)))
  ;; 表示のカスタマイズ
  (setq org-agenda-span 'day                   ;; day or week
        org-agenda-format-date "%Y/%m/%d (%a)" ;; YY/MM/DD (曜)
        org-agenda-weekend-days '(0)           ;; 日曜始まり
        ;; 表示関数
        org-agenda-day-face-function 'my:org-agenda-day-face-function
        org-agenda-custom-commands             ;; GTD 用の設定
        '(
          ("n" "agenda and all TODO list"
           (
            (agenda ""
                    ((org-agenda-ndays 1)
                     (org-agenda-entry-types '(:timestamp :sexp))))
            (todo "TODO"
                  ((org-agenda-prefix-format " %i %-22:c"))
                  )
            (todo "新規|着手|進行中|確認"
                  ((org-agenda-prefix-format " %i %-22:c"))
                  )
            (todo "WAIT"
                  ((org-agenda-prefix-format " %i %-22:c"))
                  )
            (todo "SOMEDAY"
                  ((org-agenda-prefix-format " %i %-22:c"))
                  )
            ))
          ("N" "All memo entry"
           (;;
            (todo "MEMO")
            ))
           )
        )
  ;; 色付け
  (add-hook 'org-finalize-agenda-hook
            (lambda ()
              (save-excursion
                (goto-char (point-min))
                (while (re-search-forward "KUSM:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                     '(face my:org-agenda-calendar-KUSM)))
                (goto-char (point-min))
                (while (re-search-forward "Schedule:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face my:org-agenda-calendar-Schedule)))
                (goto-char (point-min))
                (while (re-search-forward "DebianJP:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face my:org-agenda-calendar-DebianJP)))
                (goto-char (point-min))
                (while (re-search-forward "GFD:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face my:org-agenda-calendar-GFD)))
                (goto-char (point-min))
                (while (re-search-forward "twitter:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face my:org-agenda-calendar-twitter)))
                (goto-char (point-min))
                (while (re-search-forward "祝日:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face org-agenda-date-weekend)))
                (goto-char (point-min))
                (while (re-search-forward "休日:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face org-agenda-date-weekend)))
                )))
  )

org-journal: 日記

エントリ作成時に日付を入れるために org-jounnal-new-entrydefadvice している

(use-package org-journal
  :ensure t
  :if (file-directory-p my:d:org)
  :bind (("C-c C-j" . browse-url-at-point))
  :init
  (add-hook 'org-journal-mode-hook
            (setq truncate-lines t))
  :config
  (unbind-key "C-c C-j" org-journal-mode-map)
  (bind-key "C-c C-j" 'browse-url-at-point)
  (setq org-journal-dir org-directory
        org-journal-file-format "journal.org"
        org-journal-date-format "%x (%a)"
        org-journal-date-prefix "* "
        org-journal-time-format "<%Y-%m-%d %R> "
        org-journal-time-prefix "** ")
  (defadvice org-journal-new-entry (before my:org-journal-add-date-entry)
    "Insert date entry"
    (find-file-other-window (concat org-journal-dir org-journal-file-format))
    (org-journal-decrypt)
    (unless
        (string-match (format-time-string org-journal-date-format)
                      (buffer-substring-no-properties (point-min) (point-max)))
      (progn
        (goto-char (point-max))
        (insert (concat "\n" org-journal-date-prefix
                        (format-time-string org-journal-date-format)))
        ))
    )
  (ad-activate 'org-journal-new-entry))
  ;; Key bindings -- 使えてない...
  ;; (define-key org-journal-mode-map (kbd "C-c C-f") 'org-journal-open-next-entry)
  ;; (define-key org-journal-mode-map (kbd "C-c C-b") 'org-journal-open-previous-entry)
  ;; (define-key org-journal-mode-map (kbd "C-c C-j") 'org-journal-new-entry)
  ;; (define-key calendar-mode-map "j" 'org-journal-read-entry)
  ;; (define-key calendar-mode-map (kbd "C-j") 'org-journal-display-entry)
  ;; (define-key calendar-mode-map "]" 'org-journal-next-entry)
  ;; (define-key calendar-mode-map "[" 'org-journal-previous-entry)
  ;; (define-key calendar-mode-map (kbd "i j") 'org-journal-new-date-entry)
  ;; (define-key calendar-mode-map (kbd "f f") 'org-journal-search-forever)
  ;; (define-key calendar-mode-map (kbd "f w") 'org-journal-search-calendar-week)
  ;; (define-key calendar-mode-map (kbd "f m") 'org-journal-search-calendar-month)
  ;; (define-key calendar-mode-map (kbd "f y") 'org-journal-search-calendar-year)))

Babel

org-src

(use-package org-src
  :diminish org-src-mode
  :config
  (setq org-src-fontify-natively t       ;; font-lock
        org-src-tab-acts-natively t      ;; indent
        org-edit-src-content-indentation 0
        org-src-preserve-indentation t
        )
  )

org-ditaa

(use-package ob-ditaa
  :if (file-exists-p (concat (getenv "HOME") "/bin/jditaa.jar"))
  :config
  (setq org-ditaa-jar-path (concat (getenv "HOME") "/bin/jditaa.jar"))
  (org-babel-do-load-languages 'org-babel-load-languages
                               '((ditaa . t)))
  )

Org-gcal

Google カレンダーと org の予定を同期

token 等の置き場所の変更

(use-package request
  :ensure t
  :init
  (setq request-storage-directory (concat my:d:tmp "request"))
  (unless (file-directory-p request-storage-directory)
    (make-directory request-storage-directory)))

org-gcal 本体の設定

実際の情報等は password-store を使って設定しておく. ついでに agenda 表示の際の色付けを設定.

(use-package org-gcal
  :ensure t
  :if (and my:d:password-store
           (file-directory-p my:d:org))
  :commands (org-gcal-fetch)
  :init
  (setq org-gcal-dir (concat my:d:tmp "org-gcal"))
  (unless org-gcal-dir
    (make-directory org-gcal-dir))
  (setq org-gcal-token-file (expand-file-name ".org-gcal-token" org-gcal-dir))
  (setq alert-log-messages t)
  (setq alert-default-style 'log)
  (setq org-gcal-down-days   90) ;; 過去 3 month
  (setq org-gcal-up-days    180) ;; 未来 6 month
  (setq org-gcal-auto-archive nil)
  :config
  (load (expand-file-name "emacs/org-gcal.gpg" my:d:password-store)))

password-store には multiline で設定を書く.例えば以下:

(setq org-gcal-client-id "XXXXXXXXXXX"
      org-gcal-client-secret "XXXXXXXXXXX"
      org-gcal-file-alist
      '(("XXXXX@gmail.com" . "~/org/Schedule.org")
        ("YYYYY@group.calendar.google.com" . "~/org/Project1.org")))

OrgとRedmine の連携: orgmine

素晴しい!! kametoku/orgmine: Emacs minor mode for org-mode with redmine integration

(use-package orgmine
  :if (and my:d:password-store
           (file-directory-p org-directory))
  :commands (orgmine-mode)
  :init
  (unless (package-installed-p 'orgmine)
    (package-install 'elmine)
    (quelpa '(orgmine
              :fetcher github
              :repo "kametoku/orgmine")))
  (add-to-list 'safe-local-variable-values
               '(orgmine-note-block-begin . "#+BEGIN_SRC textile"))
  (add-hook 'org-mode-hook
            (lambda ()
              (if (assoc "om_project" org-file-properties) (orgmine-mode))))
  :config
  (setq orgmine-note-block-begin "#+BEGIN_SRC gfm"   ;; 要調整
        orgmine-note-block-end   "#+END_SRC\n"
        orgmine-default-todo-keyword "新規")
  ;; サーバ設定
  (load (expand-file-name "emacs/orgmine.gpg" my:d:password-store)))

Org-Wiki

計算機関連のメモは org-wiki で書いています.

(unless (package-installed-p 'org-wiki)
  (quelpa '(org-wiki
            :fetcher github
            :repo "caiorss/org-wiki")))
(use-package org-wiki
  :config
  (setq org-wiki-location (concat (getenv "HOME") "/Public/cc-env/"))
  (defun my:org-wiki-header ()
    "Insert a header at the top of the file, customize for personal use"
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (insert (format
               (string-trim "
#+TITLE:
#+DATE: 20
#+LANGUAGE: ja
#+REF: cc-env/%s
#+LAYOUT: default
#+SETUPFILE: ~/Public/_setup.org
#+PERMALINK: /cc-env/%s.html
")
               (file-name-base (buffer-file-name))
               (file-name-base (buffer-file-name))))))
  (advice-add 'org-wiki-header :override 'my:org-wiki-header)
  )

Export

一般設定

(use-package ox
    :config
    (setq org-export-with-toc nil
          org-export-with-section-numbers nil)
    )

Beamer export

(use-package ox-beamer
  :config
  (add-to-list 'org-latex-classes
               '("my:beamer"
                 "\\documentclass[dvipdfmx,presentation]{beamer}
                     [NO-DEFAULT-PACKAGES] [NO-PACKAGES] [EXTRA]"
                 ("\\section\{%s\}" . "\\section*\{%s\}")
                 ("\\subsection\{%s\}" . "\\subsection*\{%s\}")
                 ("\\subsubsection\{%s\}" . "\\subsubsection*\{%s\}"))))

LATEX_CLASS に my:beamer を指定すると,上記設定で export される.

HTML 出力: ox-html

後述の Jekyll 用の設定も参照のこと.

(use-package ox-html
  :config
  (setq org-html-use-infojs nil
        org-html-html5-fancy t
        org-export-htmlize-output-type 'inline-css
        org-html-doctype "html5"
        org-html-text-markup-alist
        '((bold           . "<strong>%s</strong>")
          (code           . "<code>%s</code>")
          (italic         . "<i>%s</i>")
          (strike-through . "<del>%s</del>")
          (underline      . "<span class=\"underline\">%s</span>")
          (verbatim       . "<code>%s</code>")))
  )

Jekyll 用の設定

Web サイトは Jekyll で作成しています. yoshinari-nomura/org-octopress: org-mode in octopressox-jekyll を参考に 改造して , html export の際に必要な yaml front matter を出力できるようにしてます. あと,src-block が liquid に解釈されない様に escape してます.

Jekyll 用の Backend の定義

(org-export-define-derived-backend 'jekyll 'html
  :menu-entry
  '(?j "Jekyl: export to html with YAML front matter."
       ((?H "To temporary buffer"
            (lambda (a s v b) (org-jekyll-export-as-html a s v)))
        (?h "To file" (lambda (a s v b) (org-jekyll-export-to-html a s v)))))
  :translate-alist
  '((template  . org-jekyll-template)
    )
  :options-alist
  '((:layout    "LAYOUT" nil "default")
    (:ref       "REF" nil nil)
    (:permalink "PERMALINK" nil nil)
    (:redirect_from "redirect_from" nil nil )
    (:redirect_to "redirect_to" nil nil )
    )
  :filters-alist
  '((:filter-final-output . org-jekyll-finalized))
  )
;; template
(defun org-jekyll-template (contents info)
  "Return complete document string after HTML conversion."
  (concat (org-jekyll--yaml-front-matter info) contents))
;;; 幾つかの文字列を置換する
;;  - liquid templateに誤認される `{%', `%}'
;;  - table-of-contents の処理
(defun org-jekyll-finalized (contents _backend info)
  "Publish src-block to html, Escape liquid tags, e.g. {%, %}"
  (with-temp-buffer
    (insert contents)
    (perform-replace "&$58;" "&#58;" nil nil nil nil nil (point-min) (point-max))
    (perform-replace "{%" "&#123;%" nil nil nil nil nil (point-min) (point-max))
    (perform-replace "%}" "%&#125;" nil nil nil nil nil (point-min) (point-max))
    (set-auto-mode t)
    (buffer-substring-no-properties (point-min) (point-max))))
;;
(defun org-jekyll--get-option (info property-name &optional default)
  (let ((property (org-export-data (plist-get info property-name) info)))
    (format "%s" (or property default ""))))
;;
(defun org-jekyll--yaml-front-matter (info)
  (let ((title
         (org-jekyll--get-option info :title))
        (date
         (org-jekyll--get-option info :date))
        (language
         (org-jekyll--get-option info :language))
        (layout
         (org-jekyll--get-option info :layout))
        (jekyll-ref
         (org-jekyll--get-option info :ref ))
        (jekyll-permalink
         (org-jekyll--get-option info :permalink ))
        (jekyll-redirect-from
         (org-jekyll--get-option info :redirect_from ))
        (jekyll-redirect-to
         (org-jekyll--get-option info :redirect_to ))
        (convert-to-yaml-list
         (lambda (arg)
           (mapconcat #'(lambda (text)(concat "\n- " text)) (split-string arg) " "))))
    (concat
     "---"
     "\ntitle: "      (s-replace ":" "&$58;" title)
     "\ndate: "       date
     "\nlayout: "     layout
     "\nlang: "       language
     (unless (string-equal jekyll-ref "")
       (concat "\nref: " jekyll-ref))
     (unless (string-equal jekyll-permalink "")
       (concat "\npermalink: " jekyll-permalink))
     (unless (string-equal jekyll-ref "")
       (concat "\nref: " jekyll-ref))
     (unless (string-equal jekyll-redirect-from "")
       (concat "\nredirect_from: " jekyll-redirect-from))
     (unless (string-equal jekyll-redirect-to "")
       (concat "\nredirect_to: " jekyll-redirect-to))
     "\n---\n")))

(defun org-jekyll-export-as-html
    (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a HTML buffer adding some YAML front matter."
  (interactive)
  (org-export-to-buffer 'jekyll "*Org Jekyll HTML Export*"
    async subtreep visible-only body-only ext-plist (lambda () (html-mode))))

(defun org-jekyll-export-to-html
    (&optional async subtreep visible-only body-only ext-plist)
  "Export current buffer to a HTML file adding some YAML front matter."
  (interactive)
  (let ((outfile (org-export-output-file-name ".html" subtreep)))
    (org-export-to-file 'jekyll outfile async subtreep visible-only body-only ext-plist)))

Project の定義

org-publish-all 等で batch で一括出力できるようにしておきます.

(use-package ox-publish
  :if (file-directory-p "~/Public/.git")
  :config
  (defun org-publish-to-jekyll (plist filename pub-dir)
    "publishing org to html with Jekyll YAML front matter."
    (org-publish-org-to 'jekyll filename ".html" plist pub-dir))
  (setq org-publish-use-timestamps-flag t
        org-publish-timestamp-directory "~/Public/.org-timestamps/"
        org-publish-project-alist
        '(("web"
           :base-directory "~/Public/"
           :base-extension "org"
           :exclude "\\(_.*\\|cc-env\\)"
           :publishing-directory "~/Public/"
           :publishing-function org-publish-to-jekyll
           :recursive t
           :headline-level 2
           )
          ("cc-env"
           :base-directory "~/Public/cc-env"
           :base-extension "org"
           :exclude "\\(_.*\\)"
           :publishing-directory "~/Public/cc-env"
           :publishing-function org-publish-to-jekyll
           :with-toc t
           :recursive t
           :headline-level 2
           )
          ))
  )

Howm

Org を使う前は Howm を使っていました. 過去のメモを検索するためだけに未だに Howm を使っています.

Rust で書かれた ripgrep がとても速いらしいので, howmripgrep がある時だけ 読み込むようにしています.

(use-package howm
  :if (and (my:dpkg-status "howm")
           (executable-find "rg"))
  :diminish howm-mode
  :bind (:map howm-mode-map
              ("C-c C-c"     . nil)
              ("C-x C-z C-c" . howm-save-and-kill-buffer/screen))
  :init
  (add-hook 'howm-menu-hook (lambda ()
                              (setq truncate-lines t)))
  :config
  ;;; ディレクトリの設定
  ;; メモの内容は Dropbox で同期することに
  (setq howm-directory "~/Dropbox/org")
  ;; メニューと履歴を検索対象から除外するために別ディレクトリへ
  (setq howm-keyword-file "~/Dropbox/.howm/keys"
        howm-history-file "~/Dropbox/.howm/history"
        howm-menu-file "~/Dropbox/.howm/menu")
  ;; メモファイルは日付時刻毎に分離
  (setq howm-file-name-format "%Y%m%d-%H%M%S.howm")
  ;;;  メモはorgで書く
  ;; - org-mode の hook として howm-mode を登録
  ;; - C-c が org に取られるので, howm の prefix は C-xC-z に
  (add-hook 'org-mode-hook 'howm-mode)
  (global-unset-key (kbd "C-x C-z"))
  (setq howm-prefix (kbd "C-x C-z"))
  ;; title header は "*"
  (setq howm-view-title-header "*")
  ;; :config
  (when (locate-library "elscreen-howm")
    (require 'elscreen-howm nil 'noerror))
  ;; 色付けは org-mode 任せ: howm の font-lock を無効化
  (setq howm-use-color nil)
  ;;; 以下,決まり文句
  ;; 検索で大文字小文字を区別しない
  (setq howm-keyword-case-fold-search t)
  ;; grep の 代わりに rg (ripgrep) を使う
  (setq howm-view-use-grep t
        howm-view-grep-command "rg"
        howm-view-grep-option "-nH --no-heading --color never"
        howm-view-grep-extended-option nil
        howm-view-grep-fixed-option "-F"
        howm-view-grep-expr-option nil
        howm-view-grep-file-stdin-option nil)
  ;; 検索対象のディレクトリの追加...とりあえず追加しないことに.
  (setq howm-search-other-dir nil)
  ;; 検索対象外のファイル: ad hoc にどんどん増えていくなぁ...
  (setq howm-excluded-file-regexp
        "/\\.#\\|[~#]$\\|\\.bak$\\|/CVS/\\|\\.doc\\|\\.pdf\\|\\.txt$\\|\\.html$\\|\\.tex$\\|\\.dvi$\\|\\.fdb_latexmk$\\|\\.ppt$\\|\\.xls$\\|\\.howm-menu$\\|.howm-keys$\\|\\.png$\\|\\.gif$\\|\\.tif$\\|\\.tiff$\\|\\.jpg$\\|\\.jpeg$\\|\\.el$\\|\\.aux$\\|\\.log$\\|Makefile\\|\\.txt$\\|EUC-UCS2\\|\\.fdb_latexmk$\\|latexmkrc\\|\\.gpg$\\|\\.org$")
  ;; org-mode の日付検索用
  (setq howm-reminder-regexp-grep-format
        (concat "<" howm-date-regexp-grep "[ :0-9]*>%s"))
  (setq howm-reminder-regexp-format
        (concat "\\(<" howm-date-regexp "[ :0-9]*>\\)\\(\\(%s\\)\\([0-9]*\\)\\)"))
  ;;; 表示設定
  (setq howm-menu-top nil
        howm-menu-lang 'ja)
  ;; 一覧にタイトル表示しない
  (setq howm-list-title nil)
  ;; save 時にメニューを更新しない
  (setq howm-menu-refresh-after-save nil)
  (setq howm-refresh-after-save nil)
  ;; 新規メモを上に
  (setq howm-prepend t)
  ;; 全メモ一覧時にタイトル表示
  (setq howm-list-all-title t)
  ;; 「最近のメモ」一覧時にタイトル表示
  (setq howm-list-recent-title t)
  ;; 「最近のメモ」の表示件数
  (setq howm-menu-recent-num 20)
  ;; メニューを 2 時間キャッシュ
  (setq howm-menu-expiry-hours 2)
  ;; RET でファイルを開く際, 一覧バッファを消す. C-u RET なら残る
  (setq howm-view-summary-persistent nil)
  ;;; メニュー表示用の関数定義
  ;; 正規表現で検索, 逆順,  表示件数は =howm-menu-recent-num=, という ad hoc な関数
  (defun my:howm-menu-search (key &optional formatter regexp-p)
    "Embed search result of KEY into menu, reverse-order, howm-menu-recent-num"
    (let ((fixed-p (not regexp-p)))
      (howm-menu-general "menu-search"
                         formatter
                         (howm-first-n
                          (howm-sort-items-by-reverse-date
                           (howm-view-search-folder-items key (howm-folder) nil fixed-p)
                           ) howm-menu-recent-num)
                         )))
  (setq howm-menu-allow
        (append '(my:howm-menu-search) howm-menu-allow))
  ;; 編集テンプレートの
  (setq howm-dtime-format (concat "<" howm-dtime-body-format ">")
        howm-insert-date-format "<%s>"
        howm-template-date-format "<%Y-%m-%d %a %H:%M:%S>"
        howm-template-file-format "==>%s"
        howm-template "* MEMO %date %cursor\n%file\n"
        howm-reminder-today-format (format howm-insert-date-format howm-date-format))
  )

プログラム環境

コードのタグ付け: ggtags, helm-gtags

無いと途方に暮れる. Debian 版の GNU Global がすったもんだの挙句ようやく更新された!

(use-package helm-gtags
  :ensure t
  :if (executable-find "gtags")
  :diminish helm-gtags-mode
  :init
  (add-hook 'helm-gtags-mode-hook
            (lambda ()
              (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 "C-t") 'helm-gtags-pop-stack)))
  :config
  (setq helm-gtags-path-style 'root
        helm-gtags-ignore-case t)
  (add-hook 'c-mode-hook    'helm-gtags-mode)
  (add-hook 'cc-mode-hook   'helm-gtags-mode)
  (add-hook 'f90-mode-hook  'helm-gtags-mode)
  (add-hook 'ruby-mode-hook 'helm-gtags-mode)
  (add-hook 'emacs-lisp-mode-hook 'helm-gtags-mode))

プロジェクト管理: bbatsov/projectile

これも無いと途方に暮れる.bbatsov/helm-projectile と一緒に使っている.

(use-package projectile
  :config
  (setq projectile-keymap-prefix (kbd "C-c p")  ; default
        projectile-enable-caching t
        projectile-cache-file (concat my:d:tmp "projectile.cache")
        projectile-completion-system 'helm
        projectile-tags-backend 'ggtags
        projectile-mode-line '(:eval
                               (if
                                   (file-remote-p default-directory)
                                   ""
                                 (format " [%s]"
                                         (projectile-project-name))))
        projectile-known-projects-file (concat my:d:tmp "projectile-bookmarks.eld")
        ;; projectile-globally-ignored-files
        ;; projectile-globally-ignored-directories
        )
  (projectile-global-mode)
  (helm-projectile-on)
  )

VCS: magit, git-gutter

magit は Emacs の Git Frontend. 結局の所 CUI でコマンド叩く事も多いけれど,これはこれで重宝している.

(use-package magit
  :bind (("C-x g" . magit-status))
  )

git-gutter で差分を視覚的に表示してくれる. @see git-gutter.elの紹介 - Qiita

(use-package git-gutter
  :ensure t
  :if (locate-library "magit")
  :bind (("C-x p" . git-gutter:previous-hunk)
         ("C-x n" . git-gutter:previous-hunk)
         ("C-x =" . git-gutter:popup-hunk))
  :config
  (setq git-gutter:window-width 2
        git-gutter:added-sign "+ "
        git-gutter:deleted-sign-sign "- "
        git-gutter:modified-sign "::"
        git-gutter:unchanged-sign "  "     ;; 空白 2つ
        git-gutter:always-show-separator nil
        ;; git-gutter:modified-sign "⇔"
        ;; git-gutter:added-sign "⇒"
        ;; git-gutter:deleted-sign "⇐"
        git-gutter:lighter ""
        )
  (global-git-gutter-mode +1)
  )

flycheck

(use-package flycheck
  :ensure t
  :diminish flycheck-mode
  :init
  :config
  (global-flycheck-mode)
  (setq-default flycheck-disabled-checkers
                '(
                  emacs-lisp-checkdoc
                  ))
  ;; gcc
  (defun my:setup-flycheck-gcc-project-path ()
    "gcc: Add projectile root for include path"
    (let ((root (ignore-errors (projectile-project-root))))
      (when root
        (add-to-list
         (make-variable-buffer-local 'flycheck-gcc-include-path)
         root))))
  ;; gfortran
  (add-hook 'c-mode-hook 'my:setup-flycheck-gcc-project-path)
  (defun my:setup-flycheck-gfortran-project-path ()
    "gfortran: Add projectile root for include path"
    (let ((root (ignore-errors (projectile-project-root))))
      (when root
        (add-to-list
         (make-variable-buffer-local 'flycheck-gfortran-include-path)
         root))))
  (add-hook 'c-mode-hook 'my:setup-flycheck-gfortran-project-path)
  )

rainbow-mode

#RRGGBB のカラーコードに勝手に色が付く.CSS の編集中なんかで地味に便利.

(use-package rainbow-mode
  :diminish rainbow-mode
  )

Textile

(use-package textile-mode
  :ensure t
  )

Markdown

(use-package markdown-mode
  :if (executable-find "pandoc")
  :mode ("\\.\\(md\\|markdown\\)\\'" . gfm-mode)
  :init
  (add-hook 'markdown-mode-hook
            '(lambda ()
               (electric-indent-local-mode -1)))
  (add-hook 'gfm-mode-hook
            '(lambda ()
               (electric-indent-local-mode -1)))
  :config
  (setq markdown-command
        "pandoc --from markdown_github -t html5 --mathjax --highlight-style pygments")
  )

SCSS

(use-package scss-mode
  :ensure t
  :if (executable-find "sass")
  :mode "\\.scss\\'"
  :config
  (setq scss-sass-command (executable-find "sass")))

YAML

(use-package yaml-mode
  :mode "\\(\.yml\\|\.yaml\\)"
  )

設定ファイル: generic-x

(use-package generic-x)

Ruby

素の ruby-mode. Gemfile も ruby-mode で扱う

(use-package ruby-mode
  :mode "\\.rb\\'"
  :interpreter "ruby"
  :init
  (add-to-list 'auto-mode-alist '("Gemfile$" . ruby-mode)))

ruby-electric: 括弧や do ... end の補完

(use-package ruby-electric
  :ensure t
  :init
  (add-hook 'ruby-mode-hook (lambda () (ruby-electric-mode t)))
  :config
  (setq ruby-electric-expand-delimiters-list nil))

ruby-block: do...end の対応をハイライト

(use-package ruby-block
  :ensure t
  :diminish ruby-block-mode
  :config
  (ruby-block-mode t)
  (setq ruby-block-highlight-toggle 'overlay)
  )

rspec-mode:

(use-package rspec-mode
  :ensure t
  :config
  (setq rspec-use-rake-flag nil))

rabbit-mode: Rabbit 編集用

(use-package rabbit-mode
  :mode "\\.rab$"
  )

C

(use-package cc-mode
  :init
  (c-add-style "my:bsd-like"
               '("bsd"
                 (c-basic-offset . 2)
                 (c-hanging-braces-alist . ((inline-open       before after)
                                            (block-open        before after)
                                            (substatement-open before after)))
                 (c-offsets-alist . ((brace-list-entry . +)))
                 ))
  :config
  (setq-default c-default-style "my:bsd-like")
  (add-hook 'c-mode-hook
            (lambda ()
              (c-set-style "my:bsd-like")
              (electric-indent-local-mode -1)
              (set (make-local-variable 'eldoc-idle-delay) 0.20)
              (c-turn-on-eldoc-mode)
              ))
  )

Fortran

(use-package f90
  :mode ("\\.\\(f|F\\)\\(90|95|03|08\\)$" . f90-mode)
  :config
  (add-hook 'f90-mode-hook
            (lambda ()
              (setq f90-do-indent 2
                    f90-if-indent 2
                    f90-type-indent 2
                    f90-program-indent 2
                    f90-continuation-indent 2
                    f90-directive-comment-re "!omp\\$"
                    f90-indented-comment-re "!"
                    f90-break-delimiters "[-+\\*/><=,% \t]"
                    f90-break-before-delimiters t
                    f90-beginning-ampersand nil
                    f90-smart-end 'blink
                    f90-auto-keyword-case nil
                    f90-leave-line-no nil
                    f90-comment-region "!! "
                    f90-indent-comment "! "
                    indent-tabs-mode nil
                    f90-font-lock-keywords f90-font-lock-keywords-2)
              (ggtags-mode 1)))
  )

AUCTeX

Debian パッケージ版を使う.やっている事は

  • japanese-latex-mode において, 幾つかのコマンドが追加/上書きされているが, あまり使うことの無いコマンドが表示されるのが嫌なのでそれらを削除.
  • auctex-latexmk を参考に file encoding を取得する関数と latexmk の実行用関数をカスタマイズ
    (use-package tex-jp
      :if (my:dpkg-status "auctex")
      :config
      (dolist (command '("pTeX" "pLaTeX" "pBibTeX" "jTeX" "jLaTeX" "jBibTeX"))
        (delq (assoc command TeX-command-list) TeX-command-list))
      ;; @see https://github.com/tom-tan/auctex-latexmk/auctex-latexmk.el
      (defvar my:auctex-latexmk-encoding-alist
        '((japanese-iso-8bit      . "euc")
          (japanese-iso-8bit-unix . "euc")
          (euc-jp                 . "euc")
          (euc-jp-unix            . "euc")
          (utf-8                  . "utf8")
          (utf-8-unix             . "utf8")
          (japanese-shift-jis     . "sjis")
          (japanese-shift-jis-dos . "sjis"))
        "Encoding mapping for platex.")
      (defun my:TeX-run-latexmk ()
        "Guess TeX file encoding and Excecute latexmk"
        (let ((TeX-sentinel-default-function 'Latexmk-sentinel)
              (pair (assq buffer-file-coding-system my:auctex-latexmk-encoding-alist)))
          (unless (null pair)
            (setenv "LATEXENC" (cdr pair)))
          (TeX-run-TeX name command file)
          (setenv "LATEXENC" nil)))
      ;; customize latexmk command
      (defun my:latexmk-setup ()
        "Add LatexMk command to TeX-command-list."
        (delq (assoc "LaTeX" TeX-command-list) TeX-command-list)
        (add-to-list 'TeX-command-list
                     '("LaTeX" "latexmk -gg -pdfdvi %t" my:TeX-run-latexmk nil
                       (plain-tex-mode latex-mode doctex-mode)
                       :help "Run LatexMk, with epLaTeX, dvipdfmx"))
        (add-to-list 'TeX-command-list
                     '("LaTeXMk" "latexmk %t" my:TeX-run-latexmk nil
                       (plain-tex-mode latex-mode doctex-mode)
                       :help "Run LatexMk without any options"))
        (add-to-list 'TeX-command-list
                     '("LaTeXMk(ps2pdfwr)" "latexmk -gg -pdfps %t" my:TeX-run-latexmk nil
                       (plain-tex-mode latex-mode doctex-mode)
                       :help "Run LatexMk, with (e)pLaTeX, dvips, ps2pdfwr"))
        (setq LaTeX-clean-intermediate-suffixes
              (append
               '("\\.nav" "\\.snm" "\\.fdb_latexmk" "\\.aux.bak" "\\.synctex.gz")
               LaTeX-clean-intermediate-suffixes))
        (setq TeX-command-output-list
              '(("latexmk" ("pdf")))))
      (add-hook 'LaTeX-mode-hook 'my:latexmk-setup)
      )
        

~/.latexmkrc の設定は以下の通り.

#!/usr/bin/env perl
$kanji  = defined $ENV{"LATEXENC"} ? "-kanji=$ENV{\"LATEXENC\"}" : "-kanjii=utf8" ;
$latex  = "platex -interaction=nonstopmode -src-specials -shell-escape --synctex=1 $kanji";
$latex_silent = "platex -interaction=batchmode -src-specials -shell-escape --synctex=1 $kanji";
$bibtex = "pbibtex $kanji";
$makeindex = "touch -m %D";
$dvipdf = "dvipdfmx %O -o %D %S";
$dvips = 'dvips %O -z -f %S | convbkmk -u > %D';
$ps2pdf = 'ps2pdfwr %O %S %D';
$pdf_mode = 3;
$pdf_previewer = 'start xdg-open';
$pdf_update_method = 0;
$clean_ext = "snm nav vrb synctex.gz";

AUCTeX と Zotero との連携

イマイチ使いこなせてないけれど.

(use-package zotelo
  :ensure t
  :if (my:dpkg-status "zotelo")
  :init
  (add-hook 'LaTeX-mode-hook 'zotelo-minor-mode)
  :config
  (setq zotelo-translator-charsets '((BibTeX . "Unicode")
                                     (Default . "Unicode")))
  )

フォントと色

そろそろテーマにした方が良い,とは思ってはいる.

(defun my:load-window-config ()
  "load window-system specific settings"
  (interactive)
  (when window-system
    (progn
      (add-to-list 'default-frame-alist '(font . "Monospace-12"))
      (set-background-color "#242424")
      (set-face-attribute 'default t :font "Monospace" :height 135)
      (set-frame-font "Monospace-13.5" nil t)
      )))
(setq frame-background-mode (frame-parameter nil 'background-mode))
(setq default-frame-alist
      '(
        (foreground-color . "#F6F3E8")
        (scroll-bar-foreground-color . "red")
        (vertical-scroll-bars . right)
        ))
(when (window-system)
  (my:load-window-config))

現在修正中.

(custom-set-faces
 '(default                             ((t (:foreground "#F6F3E8" ))))
 ;;
 '(cursor                              ((t (:foreground "#4CFF4C" :background "#4CFF4C" ))))
 '(font-lock-builtin-face              ((t (:foreground "#7FBFFF" ))))
 '(font-lock-comment-delimiter-face    ((t (:foreground "#e5e5e6" ))))
 '(font-lock-comment-face              ((t (:foreground "#e5e5e6" ))))
 '(font-lock-constant-face             ((t (:foreground "#FFBF7F" ))))
 '(font-lock-doc-face                  ((t (:foreground "#7FFF7F" ))))
 '(font-lock-doc-string-face           ((t (:foreground "#7FFF7F" ))))
 '(font-lock-function-name-face        ((t (:foreground "#BF7FFF"))))
 '(font-lock-keyword-face              ((t (:foreground "#FF7F7F"))))
 '(font-lock-link-face                 ((t (:foreground "#7FFFFF" ))))
 '(font-lock-negation-char-face        ((t (:foreground "#7FFFFF" :bold t   :italic nil))))
 '(font-lock-preprocessor-face         ((t (:foreground "#FF4C4C" :bold nil :italic nil))))
 '(font-lock-regexp-grouping-backslash ((t (:foreground "#A5EE4C" :bold t   :italic nil))))
 '(font-lock-regexp-grouping-construct ((t (:foreground "#7F7FFF" :bold t   :italic nil))))
 '(font-lock-string-face               ((t (:foreground "#7FFF7F" ))))
 '(font-lock-type-face                 ((t (:foreground "#FFFF7F" ))))
 '(font-lock-variable-name-face        ((t (:foreground "#7F7FFF" ))))
 '(font-lock-warning-face              ((t (:foreground "#FF7FBF" :bold t ))))
 '(fringe                              ((t (:foreground "#666666" :background "#282828" ))))
 '(hl-line                             ((t (:background "#4C4C4C" ))))
 '(highlight                           ((t (:background "#4C4C4C" ))))
 '(minibuffer-prompt                   ((t (:foreground "#BF7FFF" ))))
 '(mode-line                           ((t (:foreground "#F6F3E8" :background "#222244" ))))
 '(mode-line-inactive                  ((t (:foreground "#666666" :background "#999999" :bold nil ))))
 '(region                              ((t (:background "#222244" ))))
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 ;; '(fixed-pitch ((t (:family "Ricty" ))))
 ;; '(variable-pitch ((t (:family "Ricty" ))))
 ;; '(fixed-pitch ((t (:family "Monospace" :height 135 ))))
 ;; '(variable-pitch ((t (:family "Monospace" :height 135 ))))
 ;;
 ;; elscreen
 '(elscreen-tab-control-face        ((t (:background "#222244" :foreground "#f6f3e8" :underline t :bold t ))))
 '(elscreen-tab-current-screen-face ((t (:background "#222244" :foreground "#f6f3e8" :underline t :bold t ))))
 '(elscreen-tab-other-screen-face   ((t (:background "#222244" :foreground "#aaaaaa" :underline t :bold nil ))))
 '(elscreen-tab-background-face     ((t (:background "#222244" :foreground "#aaaaaa" :underline t :bold nil ))))
 ;; dired
 '(dired-directory                  ((t (:bold t :foreground "#7F7FFF" ))))
 ;; '(dired-flagged
 ;; '(dired-header
 ;; '(dired-ignored
 ;; '(dired-mark
 ;; '(dired-marked
 ;; '(dired-perm-write
 '(dired-symlink                    ((t (:bold t :foreground "#7FFFFF" ))))
 ;; '(dired-warning
 '(flx-highlight-face               ((t (:bold t :undeline t))))
 ;; git-gutter
 '(git-gutter:added                  ((t (:inherit default :bold t :foreground "#4CFF4C"))))
 '(git-gutter:deleted                ((t (:inherit default :bold t :foreground "#FF7FBF"))))
 '(git-gutter:modified               ((t (:inherit default :bold t :foreground "#FFFF4C"))))
 '(git-gutter:unchanged              ((t (:inherit default ))))
 ;; helm: header-line
 '(helm-source-header               ((t (:foreground "#F6F3E8" :background "#224488" :bold t))))
 '(helm-visible-mark                ((t (:inherit highlight ))))
 '(helm-selection                   ((t (:inherit highlight ))))
 '(helm-selection-line              ((t (:inherit highlight ))))
 ;; helm: directory
 '(helm-ff-directory                ((t (:inherit dired-directory ))))
 '(helm-bookmark-directory          ((t (:inherit helm-ff-directory ))))
 '(helm-buffer-directory            ((t (:inherit helm-ff-directory ))))
 '(helm-ff-dotted-directory         ((t (:inherit helm-ff-directory ))))
 ;; helm: file
 '(helm-ff-file                     ((t (:inherit default ))))
 '(helm-bookmark-file               ((t (:inherit helm-ff-file ))))
 '(helm-buffer-file                 ((t (:inherit helm-ff-file ))))
 '(helm-grep-file                   ((t (:inherit helm-ff-file ))))
 '(helm-etags-file                  ((t (:inherit helm-ff-file ))))
 ;; helm: file + executable
 '(helm-ff-executable               ((t (:inherit helm-ff-file :foreground "#7FFF7F" :bold t))))
 ;; helm: symlink
 '(helm-ff-symlink                  ((t (:inherit default :foreground "#7FFFFF" :bold t))))
 '(helm-ff-dotted-symlink-directory ((t (:inherit helm-ff-symlink ))))
 '(helm-ff-invalid-symlink          ((t (:inherit default :foreground "#FF7F7F" ))))
 ;;; howm
 '(howm-mode-keyword-face            ((t (:foreground "#7F7FFF" :background nil ))))
 '(howm-mode-title-face              ((t (:foreground "#4CFFFF" :background nil ))))
 '(howm-reminder-deadline-face       ((t (:bold t :foreground "#FF4C4C" :background nil ))))
 '(howm-reminder-late-deadline-face  ((t (:bold t :underline t :foreground "#FF0000" :background nil ))))
 '(howm-reminder-today-face          ((t (:bold t :foreground "#FFBF7F" :background nil ))))
 '(howm-reminder-tomorrow-face       ((t (:bold t :foreground "#FF7FBF" :background nil ))))
 ;; ido
 ;; '(ido-first-match     ((t (:inherit default ))))
 ;; '(ido-only-match      ((t (:foreground "#FFFF4C" ))))
 ;; '(ido-subdir          ((t (:foreground "#7F7FFF" :bold t))))
 ;; '(ido-grid-mode-match ((t (:inherit ido-first-match ))))
 ;; ido-grid-mode-common-match
 ;; ido-grid-mode-jump-face
 ;; ido-incomplete-regexp
 ;; ido-indicator
 ;; ido-virtual
 ;; outline
 '(outline-1 ((t (:inherit font-lock-function-name-face :bold t))))
 '(outline-2 ((t (:inherit font-lock-string-face :bold t))))
 '(outline-3 ((t (:inherit font-lock-keyword-face :bold t))))
 '(outline-4 ((t (:inherit font-lock-type-face :bold t ))))
 '(outline-5 ((t (:inherit font-lock-constant-face :bold t ))))
 '(outline-6 ((t (:inherit font-lock-variable-name-face :bold t))))
 '(outline-7 ((t (:inherit font-lock-builtin-face :bold t ))))
 ;; '(outline-8 ((t (:inherit font-lock-comment-face :bold t ))))
 ;;
 ;; org
 '(org-agenda-date-today           ((t (:underline t ))))
 '(org-agenda-date                 ((t (:foreground "#FFFFFF" ))))
 '(org-agenda-date-weekend         ((t (:foreground "#FF7F7F" :bold t))))
 '(org-agenda-calendar-event       ((t (:foreground "#F6F3E8" ))))
 '(org-hide                        ((t (:foreground "#4C4C4C" ))))
 ;; review
 ;; '(review-mode-header1-face  ((t (:inherit outline-1))))
 ;; '(review-mode-header2-face  ((t (:inherit outline-2))))
 ;; '(review-mode-header3-face  ((t (:inherit outline-3))))
 ;; '(review-mode-header4-face  ((t (:inherit outline-4))))
 ;; '(review-mode-header5-face  ((t (:inherit outline-5))))
 )

diminish: モードラインの短縮表示

use-package で読み込まれているので,可能な限りそちらで指定するように変更.

(defmacro my:diminish (file mode &optional new-name)
  "original: https://github.com/larstvei/dot-emacs/blob/master/init.org"
  `(with-eval-after-load ,file
     (diminish ,mode ,new-name)))
(my:diminish "isearch"          'isearch-mode)
(setq auto-revert-mode-text "")

メジャーモードは hook で設定.

(add-hook 'emacs-lisp-mode-hook '(lambda () (setq mode-name "El")))
(add-hook 'lisp-interaction-mode-hook '(lambda () (setq mode-name "Li")))
(add-hook 'wl-folder-mode-hook  '(lambda () (setq mode-name "")))
(add-hook 'wl-summary-mode-hook '(lambda () (setq mode-name "")))
(add-hook 'wl-draft-mode-hook   '(lambda () (setq mode-name "")))
(add-hook 'mime-view-mode-hook  '(lambda () (setq mode-name "")))

powerline: モードラインを綺麗に

milkypostman/powerline: emacs powerline で modeline を良い感じに表示する.

SKK の状態がヒョコヒョコ動くのが嫌なので, skk-modeline-input-mode に常に現在の状況を表示する様にしておく.

(defun my:skk-modeline-input-mode ()
  "skk が読み込まれていない場合でも skk-modeline-input-mode に文字を入れて返す"
  (unless (boundp 'skk-modeline-inpt-mode)
    (setq skk-modeline-input-mode "--[--]:")))
(my:skk-modeline-input-mode)

ddskk そのものに modeline を更新する関数があるので無効化する

(defadvice skk-setup-modeline (around my:disable-skk-setup-modeline activate)
  "skk-setup-modeline による modeline の更新を無効化"
  (setq skk-indicator-alist (skk-make-indicator-alist))
  (force-mode-line-update t))

powerline 本体の設定.default-theme をベースに見たい物だけ表示するようにしてみた.

(use-package powerline
  :ensure t
  :config
  (when (eq system-type 'darwin)
    (setq powerline-default-separator 'utf-8
          powerline-utf-8-separator-left  #x20
          powerline-utf-8-separator-right #x20))
  (defun my:powerline-theme ()
    "Setup customize theme."
    (interactive)
    (my:skk-modeline-input-mode)
    (setq-default
     mode-line-format
     '("%e"
       (:eval
        (let* ((active (powerline-selected-window-active))
               (mode-line-buffer-id (if active 'mode-line-buffer-id 'mode-line-buffer-id-inactive))
               (mode-line (if active 'mode-line 'mode-line-inactive))
               (face1 (if active 'powerline-active1 'powerline-inactive1))
               (face2 (if active 'powerline-active2 'powerline-inactive2))
               (separator-left (intern (format "powerline-%s-%s"
                                               (powerline-current-separator)
                                               (car powerline-default-separator-dir))))
               (separator-right (intern (format "powerline-%s-%s"
                                                (powerline-current-separator)
                                                (cdr powerline-default-separator-dir))))
               (lhs (list
                     (powerline-raw (substring skk-modeline-input-mode 2 -1) nil 'l)
                     (powerline-raw "%*" mode-line 'l)
                     (powerline-raw mode-line-mule-info mode-line 'l)
                     (powerline-buffer-id mode-line-buffer-id 'l)
                     ;; (when (and (boundp 'which-func-mode) which-func-mode)
                     ;;   (powerline-raw which-func-format nil 'l))
                     (powerline-raw " ")
                     (funcall separator-left mode-line face1)
                     (powerline-major-mode face1 'l)
                     (powerline-process face1)
                     (powerline-narrow face1 'l)
                     (powerline-raw " " face1)
                     (funcall separator-left face1 face2)
                     (powerline-vc face2 'r)
                     ))
               (rhs (list
                     (powerline-raw global-mode-string face2 'r)
                     (funcall separator-right face2 face1)
                     (powerline-raw " " face1)
                     (powerline-minor-modes face1 'r)
                     (funcall separator-right face1 mode-line)
                     (powerline-raw " ")
                     (powerline-raw "%6p" mode-line 'r)
                     ))
               )
          (concat (powerline-render lhs)
                  (powerline-fill face2 (powerline-width rhs))
                  (powerline-render rhs)))))))
  (my:powerline-theme)
  )

基本的なキーバインドの設定 [/]

  • [ ] 設定が効かない事がある.読み込む順番が関係するのかな…?

既に手癖になってしまっているアレコレ. 特に [home][end] は無いと途方に暮れます.

(bind-keys*
 ("C-h"     . backward-delete-char)
 ("C-c M-a" . align-regexp)
 ("C-c ;"   . comment-region)
 ("C-c M-;" . uncomment-region)
 ("C-/"     . undo)
 ("C-x M-b" . ibuffer-other-window)
 ("C-c M-r" . replace-regexp)
 ("C-c r"   . replace-string)
 ("<home>"  . beginning-of-buffer)
 ("<end>"   . end-of-buffer)
 ("C-c C-j" . browse-url-at-point)
 )

鬼軍曹.el とかで強制した方が良いのかも,とかごく偶に思いますが(思うだけ).

起動時間の計測

起動時間を計測する 改訂版 - すぎゃーんメモ

(add-hook 'after-init-hook
          (lambda ()
            (message "init time: %.3f sec"
                     (float-time (time-subtract after-init-time before-init-time)))))

LICENSE

幾つかの関数の元ネタとして Emacs 本体のコードを参照したので,GPL-3 or later です.

Copyright (C) 2011--2017 Youhei SASAKI <uwabami@gfd-dennou.org>
.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.