目次

Related: Index

はじめに

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

Sorry, your browser does not support SVG. Fork me on GitHub

基本方針は以下の通り:

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))))

行末の無駄な空白/改行を削除する

@see 無駄な行末の空白を削除する(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)

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

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

(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)))

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)))))

常に 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)

環境変数の読み込み: 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
  • PATH

を読み込んでいます.

(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"
     "PATH"
     ))
  (setq user-full-name (concat (getenv "DEBFULLNAME"))
        user-mail-address (concat (getenv "DEBEMAIL"))
        my:d:password-store (concat (getenv "PASSWORD_STORE_DIR") "/Emacs/" system-name))
  )

言語の設定

日本語, UTF-8 にしています.

(set-language-environment "Japanese")
(prefer-coding-system 'utf-8)
(set-file-name-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-default 'buffer-file-coding-system 'utf-8)

その他, 機種依存文字等についての設定をアレコレ.

cp5022x.el

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

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

(use-package cp5022x
  :ensure t
  :config
  (set-charset-priority 'ascii 'japanese-jisx0208 'latin-jisx0201
                        'katakana-jisx0201 'iso-8859-1 'unicode)
  (set-coding-system-priority 'utf-8 'euc-jp 'iso-2022-jp 'cp932)
  )

East Asian Ambiguos 対応

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

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

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)

現在行のハイライト

(global-hl-line-mode t)

選択リージョンに色付け

(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-")
      auto-save-default t
      auto-save-timeout 15
      auto-save-interval 60
      make-backup-files t
      backup-by-copying t ; symlink は使わない
      backup-directory-alist `(("." . ,my:d:tmp))
      auto-save-file-name-transforms `((".*" ,my:d:tmp t))
      version-control t
      kept-new-versions 5
      kept-old-versions 5
      delete-old-versions t
      delete-auto-save-files t
      )

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

(setq undo-limit 200000
      undo-strong-limit 260000)
(savehist-mode 1)
(setq history-length t  ; t で無制限
      savehist-file (concat my:d:tmp "history"))

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

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

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

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

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

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

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

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

ガベージコレクションの 頻度を下げる 表示をしない

message に gc が走っていることを表示しない

(setq gc-cons-threshold (* 8 1024 1024)
      garbage-collection-messages nil)

gc-cons-threshold はとりあえず default の設定に. メモリ喰いな拡張を入れている場合には, 安易に gc-cons-threshold を上げるのは考えものである. 「gc が走る→大きな領域を掃除するのでその間 emacs が止まる」という事を頻繁に経験することになるだろう.

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 [?\□])
                                      (tab-mark ?\t [?\u00BB ?\t] [?\\ ?\t]))
        whitespace-space-regexp "\\(\u3000+\\)"
        whitespace-global-modes '(not
                                  eww-mode
                                  term-mode
                                  eshell-mode
                                  org-agenda-mode
                                  calendar-mode)
        )
  (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: ssh 越しにファイルを編集

(use-package tramp
  :config
  (setq tramp-persistency-file-name (concat my:d:tmp "tramp"))
  )

bookmark: bookmark ファイル

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

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

eww: 内蔵ブラウザ

内蔵ブラウザの設定: 幅と背景色の指定がメインだが、上手くうごいてくれていない、ような。

(use-package eww
  :config
  (bind-keys :map eww-mode-map
             ("r"  . eww-reload)
             ("o"  . eww)
             ("&"  . eww-browse-with-external-browser)
             ("b"  . eww-back-url)
             ("]"  . eww-next-url)
             ("["  . eww-previous-url)
             ("g"  . eww-top-url))
  ;; eww
  (unless (file-directory-p (expand-file-name "eww" my:d:tmp))
    (make-directory (expand-file-name "eww" my:d:tmp)))
  (setq eww-bookmarks-directory (expand-file-name "eww" my:d:tmp)
        eww-search-prefix "https://www.google.com/search?&gws_rd=cr&complete=0&pws=0&tbs=li:1&lr=lang_ja|lang_en&q=")
  ;; 背景色等の設定
  ;; (defvar eww-disable-colorize nil)
  ;; (defun shr-colorize-region--disable (orig start end fg &optional bg &rest _)
  ;;   (unless eww-disable-colorize
  ;;     (funcall orig start end fg)))
  ;; (advice-add 'shr-colorize-region :around 'shr-colorize-region--disable)
  ;; (advice-add 'eww-colorize-region :around 'shr-colorize-region--disable)
  ;; (defun eww-disable-color ()
  ;;   "eww で文字色を反映させない"
  ;;   (interactive)
  ;;   (setq-local eww-disable-colorize t)
  ;;   (eww-reload))
  ;; (defun eww-enable-color ()
  ;;   "eww で文字色を反映させる"
  ;;   (interactive)
  ;;   (setq-local eww-disable-colorize nil)
  ;;   (eww-reload))
  ;; テキスト幅の指定. setq で shr-width を指定しても反映されていない, 様な?
  ;; (defun my:shr-insert-document--for-eww (&rest them)
  ;;   (let ((shr-width 68)) (apply them)))
  ;; (defun my:eww-display-html--fill-column (&rest them)
  ;;   (advice-add 'shr-insert-document :around 'my:shr-insert-document--for-eww)
  ;;   (unwind-protect
  ;;       (apply them)
  ;;     (advice-remove 'shr-insert-document 'my:shr-insert-document--for-eww)))
  ;; (advice-add 'eww-display-html :around 'my:eww-display-html--fill-column)
  ;; buffer を rename
  ;; (defun eww-mode-hook--rename-buffer ()
  ;;   "Rename eww browser's buffer so sites open in new page."
  ;;   (rename-buffer "eww" t))
  ;; (add-hook 'eww-mode-hook 'eww-mode-hook--rename-buffer)
  )

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) ))))
  (if (executable-find "firefox")
      (setq browse-url-browser-function 'browse-url-firefox
            shr-external-browser 'browse-url-firefox)
    (setq browse-url-browser-function 'eww-browse-url))
  )

server: Emacs server

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

shell との連携

詳細は

などを参考に.

(defun return-current-working-directory-to-shell ()
  (expand-file-name
   (with-current-buffer
       (if (featurep 'elscreen)
           (let* ((frame-confs (elscreen-get-frame-confs (selected-frame)))
                  (num (nth 1 (assoc 'screen-history frame-confs)))
                  (cur-window-conf
                   (assoc 'window-configuration
                          (assoc num (assoc 'screen-property frame-confs))))
                  (marker (nth 2 cur-window-conf)))
             (marker-buffer marker))
         (nth 1
              (assoc 'buffer-list
                     (nth 1 (nth 1 (current-frame-configuration))))))
     default-directory)))

日本語入力: 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)

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

(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 に任せることに.

辞書の設定

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

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

を参考に. 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"
        skk-server-portnum "1178"
        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
  (xclip-mode 1))

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

インクリメンタル検索: migemo

(use-package migemo
  :if (executable-find "cmigemo")
  :config
  (setq migemo-command "cmigemo"
        migemo-options '("-q" "--emacs")
        migemo-dictionary "/usr/share/cmigemo/utf-8/migemo-dict"
        migemo-user-dictionary nil
        migemo-regex-dictionary nil
        migemo-coding-system 'utf-8-unix)
  (migemo-init)
  )

補完: ido

補完は ido が軽いし速いので好み. 見た目がちょっと簡素すぎる気もするので、なんとか弄りたい所ではある。

ido の設定

(use-package ido
  :bind (("C-x C-f" . ido-find-file)
         ;; ("C-x d"   . ido-dired)
         ;; ("C-x C-d" . ido-dired)
         ;; ("C-x b"   . ibuffer)
         ;; ("C-x C-b" . ibuffer)
         ;; ("C-x M-b" . ibuffer)
         )
  :config
  (ido-mode t)
  ;; (ido-everywhere t)  <- Wanderlust みたいに,過去の選択を覚えている奴と相性悪い.
  (setq ido-enable-prefix nil             ; prefix match 入力を先頭一致可能
        ido-confirm-unique-completion t   ; TAB で名前の一致まで. その後 RET で実行
        ido-enable-flex-matching t        ; flx matching を試す際には prefix を無効化すること
        ido-enable-dot-prefix t           ; . を prefix として扱う
        ido-default-file-method   'selected-window
        ido-default-buffer-method 'selected-window
        ido-max-directory-size 10000
        ido-enable-tramp-completion nil
        ido-use-faces t
        ido-ignore-extensions t
        ido-cannot-complete-command 'ido-next-match
        ido-save-directory-list-file (concat my:d:tmp "ido.last"))
  ;; 補完で無視する拡張子の追加.そのうち増える.
  (cl-loop for ext in
           '(".dvi"
             ".fdb_latexmk"
             ".fls"
             ".ilg"
             ".jqz"
             ".mod"
             ".nav"
             ".out"
             ".snm"
             ".synctex.gz"
             ".vrb"
             )
           do (add-to-list 'completion-ignored-extensions ext))
  (add-hook 'ido-setup-hook
            (lambda ()
              (define-key ido-completion-map (kbd "C-h") 'ido-delete-backward-updir)
              (define-key ido-completion-map (kbd "C-l") 'ido-delete-backward-updir)))
  (defun my:ido-disable-line-trucation ()
    (set (make-local-variable 'truncate-lines) nil))
  (add-hook 'ido-minibuffer-setup-hook 'my:ido-disable-line-trucation)
  )

flx-ido: flex match の強化

曖昧マッチが非常に直感的になった.地味に便利で手放せない.

(use-package flx-ido
  :ensure t
  :config
  (flx-ido-mode 1)
  (setq flx-ido-use-faces nil
        flx-ido-threshold 10000)
  )

ido-grid-mode: 候補を並べて表示

横に並ぶと正直シンドイので並べてみる。

(unless (package-installed-p 'ido-grid)
  (quelpa '(ido-grid
            :fetcher github
            :repo "larkery/ido-grid.el")))
(use-package ido-grid
  :ensure t
  :config
  (setq ido-grid-enabled t
        ido-grid-start-small nil
        ido-grid-rows 0.15
        ido-grid-max-columns nil
        ido-grid-indent 1
        ido-grid-column-padding 3
        ido-grid-bind-keys t
        )
  (ido-grid-enable)
  (defun my:ido-grid-force-one-columns (o &rest args)
    (let ((ido-grid-max-columns 1) ;; single vertical col
          (ido-grid-start-small nil) ;; popup immediately
          (ido-grid-rows 0.15)) ;; 15% of frame height
      (apply o args)
      ))
  )

ido-recentf: recentf を ido で

(defun ido-recentf-open ()
  "Use `ido-completing-read' to \\[find-file] a recent file"
  (interactive)
  (if (find-file (ido-completing-read "Find recent file: " recentf-list))
      (message "Opening file...")
    (message "Aborting")))
(bind-key "C-x C-r" 'ido-recentf-open)

smex

M-x を ido で。

(use-package smex
  :bind (("M-x" . smex))
  :ensure t
  :config
  (setq smex-auto-update t
        smex-save-file (concat my:d:tmp "smex-items")
        smex-prompt-string "smex: "
        smex-flex-matching nil
        )
  )

Elscreen [/]

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

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

zoom-window

(use-package zoom-window
  :ensure t
  :bind ("C-x C-z" . zoom-window-zoom)
  :init
  (setq zoom-window-use-elscreen t)
  :config
  (zoom-window-setup)
  (setq zoom-window-mode-line-color "#7fff7f")
  )

認証関連: id-manager, plstore, oauth2, 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
  )

Emacs-w3m

あまり使わないけれど, 一応設定しておく.

(use-package w3m
  :defer t
  :config
  (setq w3m-search-default-engine "google"
        w3m-use-cookies t)
;; (with-eval-after-load "w3m-search"
;;   '(add-to-list 'w3m-search-engine-alist
;;                 '("google" "https://encrypted.google.com/search?num=100&ie=utf-8&oe=utf-8&hl=ja&safe=off&filter=0&pws=0&complete=0&gbv=1&q=%s" utf-8)))
  )

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
  (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")))
  )

割と /etc/emacs/site-start.d/65wl-beta.el と重複している気がするが…

Wanderlust 本体の設定

実際の設定は以下の通り

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

rail

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

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 'iso-2022-jp)
elscreen-wl

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

(use-package elscreen-wl)
SEMI の追加設定

HTML メールを表示するために emacs-w3m を使う. 本当は eww でやりたいのだけれど base64 decode に難あり. mime-setup がロードされる前に記述する必要あり.

;; (setq mime-view-text/html-previewer 'shr)
;; (setq mime-setup-enable-inline-html 'shr)
(use-package w3m
  :config
  (require 'mime-w3m)
  (setq w3m-fill-column 72
        mime-view-text/html-previewer 'w3m
        mime-setup-enable-inline-html 'w3m))
(unless (locate-library "w3m")
  (progn
    (setq mime-view-text/html-previewer 'shr
          mime-setup-enable-inline-html 'shr)))
(with-eval-after-load 'shr
  (defun shr-colorize-region (start end fg &optional bg) nil))
(use-package mime-setup)

どのアプリケーションで開くか → 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 より優先 → 最近は 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 "/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 t)
フォルダの位置の 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 "/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/")

アドレス帳

(setq wl-use-petname t)
(setq wl-address-file  "~/.mua/Address")

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 "/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 で設定しておいた方が良いかなぁ… 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
        ))

メッセージ表示

いったん全て非表示に
(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:"
        ))
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)
メール本文の文字コード

丸囲み数字なんかが入ってしまうと 勝手にエンコーディングが変わってしまって鬱陶しい. どうしたモンだろうかね.

(add-hook 'wl-draft-mode-hook
          (lambda ()
            (add-to-list 'mime-charset-type-list '(utf-8 8 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)
(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)))
(bind-keys :map wl-summary-mode-map
           ("C-c : d" . my:epa-wl-decrypt-message)
           ("C-c : v" . my:epa-wl-verify-message))
(bind-keys :map wl-draft-mode-map
           ("C-c : s" . epa-mail-sign)
           ("C-c : e" . epa-mail-encrypt))

検索

mu(maildir-utils)を使う. 偶にセグフォるので悩み所

(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 2000000000)
(setq elmo-multi-number 2000000000)

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;

メールからの予定の取り込み: mhc

(use-package mhc
  :if (executable-find "mhc")
  )

校正,辞書等

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)
        mark-holidays-in-calendar t     ; 祝日をカレンダーに表示
        calendar-month-name-array       ; 月と曜日の表示調整
        ["01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" ]
        calendar-day-name-array
        ["日" "月" "火" "水" "木" "金" "土"]
        calendar-day-header-array
        ["日" "月" "火" "水" "木" "金" "土"]
        calendar-date-style 'iso         ; ISO format (YYYY/MM/DD) に変更
        japanese-holiday-weekend '(0 6)  ; 土曜日・日曜日を祝日として表示
        japanese-holiday-weekend-marker
        '(holiday nil nil nil nil nil japanese-holiday-saturday)
        ;; 日曜開始
        calendar-week-start-day 0)
  (calendar-set-date-style 'iso)
  )

Org

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

基本設定: org

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

(defvar my:d:org (concat (getenv "HOME") "/Nextcloud/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                 ;; Nextcloud に保存する
        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))
        ;; org-completion-use-ido nil
        ;; 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)
  )

Org-Id, Orglink

ファイル間のリンクを uuid で行なう設定

(use-package org-id
  :bind (("C-c l"   . org-store-link)
         ("C-c C-l" . org-insert-link))
  :config
  (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id
        org-id-track-globally t
        )
  (when (file-directory-p "~/Public/cc-env")
    (setq org-id-extra-files (f-glob "*.org" "~/Public/cc-env"))
    (add-to-list 'org-id-extra-files
                 (concat user-emacs-directory "README.org")))
  )

Org-journal: 日記

単一ファイルに記述すること,および エントリ作成時に日付を入れるために org-jounnal-new-entryadvice している

(use-package org-journal
  :ensure t
  :if (file-directory-p my:d:org)
  :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 my:d:org
        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 "** MEMO "
        org-journal-find-file 'find-file
        )
  (defun my:org-journal-add-date-entry (prefix &optional time)
    "Insert date entry to `org-journal-file'"
    (find-file (expand-file-name org-journal-file-format org-journal-dir))
    (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)))
        ))
    )
  (advice-add 'org-journal-new-entry :before 'my:org-journal-add-date-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)))

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
  (defun my:org-journal-add-date-entry-capture ()
    (my:org-journal-add-date-entry nil)
    (goto-char (point-max))
    )
  ;; @see https://github.com/sprig/org-capture-extension/issues/37
  ;; Brackets '{' '}' in link description cause broken org-mode link #37]]
(defun my:transform-square-brackets-to-round-ones (string-to-transform)
  "Transforms [ into ( and ] into ), other chars left unchanged."
  (concat
   (mapcar #'(lambda (c) (if (equal c ?[) ?\( (if (equal c ?]) ?\) c)))
           string-to-transform))
  )
  (setq org-default-notes-file (concat org-directory "journal.org")
        org-capture-templates
        `(
          ("t" "TODO" plain
           (function my:org-journal-add-date-entry-capture)
           "** TODO %^{title} %^g\n  %?\n  %a"
           :prepend nil
           :unnarrowed nil
           :kill-buffer t
           )
          ;; "* TODO <%<%Y-%m-%d>> %:subject %^g\n  %?\n  %a\n  #+BEGIN_QUOTE\n%i\n  #+END_QUOTE"
          ("e" "Email TODO" plain
           (function my:org-journal-add-date-entry-capture)
           "** TODO [[wl:\%5Bmsgid:%:message-id-no-brackets\%5D][%(my:transform-square-brackets-to-round-ones \"%:subject\")]]\n  :PROPERTIES:\n  :CREATED: %u\n  :END:%?\n"
           :prepend nil
           :unnarrowed nil
           :kill-buffer t
           )
          ("m" "Memo/Journal Entry" plain
           (function my:org-journal-add-date-entry-capture)
           "** MEMO %T %?"
           :prepend nil
           :unnarrowed nil
           :kill-buffer t
           )
          ("a" "Aritcle Entry" plain
           (function my:org-journal-add-date-entry-capture)
           "** ARTICLE %T %? "
           :prepend nil
           :unnarrowed nil
           :kill-buffer t
           )
          )
        )
)

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

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

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

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

(use-package org-agenda
  :diminish org-agenda-mode
  :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 表示中, Twitter 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
  ;; 使用するファイル
  (dolist (file
           '("Archive.org"
             "Holidays.org"
             "Memo.org"
             "Schedule.org"
             "MHC.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)))
  (add-to-list 'org-agenda-files (expand-file-name "README.org" user-emacs-directory))
  ;; 表示のカスタマイズ
  (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-agenda-finalize-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 "MHC:" 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)))
                )))
  )

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とGoogle カレンダーの連携: org-gcal

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 (concat my:d:password-store "/org-gcal.gpg")))

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))
  :diminish (orgmine-mode)
  :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_server" 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 (concat my:d:password-store "/orgmine.gpg"))
  )

Org-Export

一般設定

(use-package ox
    :config
    (setq org-export-with-toc nil
          org-export-with-section-numbers nil)
    ;; for Beamer
    (add-to-list 'org-export-options-alist
                 '(:shortdate    "SHORTDATE" nil nil))
    (add-to-list 'org-export-options-alist
                 '(:shorttitle   "SHORTTITLE" nil nil))
    ;; for Jekyll
    (add-to-list 'org-export-options-alist
                 '(:layout    "LAYOUT" nil "default"))
    (add-to-list 'org-export-options-alist
                 '(:ref       "REF" nil nil))
    (add-to-list 'org-export-options-alist
                 '(:permalink "PERMALINK" nil nil))
    (add-to-list 'org-export-options-alist
                 '(:redirect_from "redirect_from" nil nil))
    (add-to-list 'org-export-options-alist
                 '(:redirect_to "redirect_to" nil 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\}"))
               )
  ;;
  (add-to-list 'org-latex-classes
               '("my:beamer-uplatex"
                 "\\documentclass[dvipdfmx,presentation]{beamer}
                     [NO-DEFAULT-PACKAGES] [NO-PACKAGES] [EXTRA]"
                 ("\\section\{%s\}" . "\\section*\{%s\}")
                 ("\\subsection\{%s\}" . "\\subsection*\{%s\}")
                 ("\\subsubsection\{%s\}" . "\\subsubsection*\{%s\}"))
               )
  (add-to-list 'org-latex-classes
               '("my:beamer-pdflatex"
                 "\\documentclass[unicode,presentation]{beamer}
                     [NO-DEFAULT-PACKAGES] [NO-PACKAGES] [EXTRA]"
                 ("\\section\{%s\}" . "\\section*\{%s\}")
                 ("\\subsection\{%s\}" . "\\subsection*\{%s\}")
                 ("\\subsubsection\{%s\}" . "\\subsubsection*\{%s\}"))
               )
  )

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

HTML export

後述の 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 用の Backend の定義

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

(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)
    )
  :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に誤認される `{%', `%}'
;;  - `:' の escape
;;  - 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))
    (perform-replace "<nav id=\"table-of-contents" "<div id=\"toc-wrapper\">
<nav id=\"table-of-contents" nil nil nil nil nil (point-min) (point-max))
    (perform-replace "</nav>" (format "</nav>
</div>
<a href=\"#toc-toggle\" class=\"btn toc-btn\" id=\"toc-toggle\">%s</a>"
                                      (org-html--translate "Table of Contents" info))
                     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-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)))

Org-Wiki

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

(unless (package-installed-p 'plain-org-wiki)
  (quelpa '(plain-org-wiki
            :fetcher github
            :repo "uwabami/plain-org-wiki")))
(defun my:load-plain-org-wiki ()
  (lambda ()
    (use-package plain-org-wiki
      :bind (("C-x M" . plain-org-wiki ))
      :config
      (setq pow-directory (concat (getenv "HOME") "/Public/cc-env/")
            pow-extra-dirs (list user-emacs-directory)
            pow-template "#+TITLE:
#+DATE: 20
#+LANGUAGE: ja
#+REF: cc-env/%s
#+LAYOUT: cc-env
#+SETUPFILE: ~/Public/_setup.org
#+PERMALINK: /cc-env/%s.html
Related [[wiki:index][Index]]
")
      )))
(my:load-plain-org-wiki)

Org-Project

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

(use-package htmlize)
(use-package ox-publish
  :if (file-directory-p "~/Public/.git")
  :init (my:load-plain-org-wiki)
  :config
  (defun org-publish-to-jekyll (plist filename pub-dir)
    "publishing org to html with Jekyll YAML front matter."
    (org-id-update-id-locations)
    (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
        '(("org"
           :base-directory "~/Public/"
           :base-extension "org"
           :exclude "\\(_.*\\|cc-env\\)"
           :publishing-directory "~/Public/"
           :publishing-function org-publish-to-jekyll
           :recursive t
           :with-toc nil
           :headline-levels 5
           )
          ("cc-env"
           :base-directory "~/Public/cc-env/"
           :base-extension "org"
           :publishing-directory "~/Public/cc-env/"
           :publishing-function org-publish-to-jekyll
           :recursive t
           :with-toc t
           :headline-levels 5
           )
          ;; ("web" :components ("org" "cc-env"))
          )
        )
  )

Howm

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

(use-package howm
  :if (and (my:dpkg-status "howm")
           (executable-find "ag"))
  :diminish howm-mode
  :bind (:map howm-mode-map
              ("C-c , ,"     . howm-menu)
              ("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
  ;;; ディレクトリの設定
  ;; メモの内容は Nextcloud で同期することに
  (setq howm-directory "~/Nextcloud/org")
  ;; メニューと履歴を検索対象から除外するために別ディレクトリへ
  (setq howm-keyword-file "~/Nextcloud/howm/keys"
        howm-history-file "~/Nextcloud/howm/history"
        howm-menu-file "~/Nextcloud/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
  (use-package "elscreen-howm")
  ;; 色付けは org-mode 任せ: howm の font-lock を無効化
  (setq howm-use-color nil)
  ;;; 以下,決まり文句
  ;; 検索で大文字小文字を区別しない
  (setq howm-keyword-case-fold-search t)
  ;; grep の 代わりに ag を使う
  (setq howm-view-use-grep t
        howm-view-grep-command "ag"
        howm-view-grep-option "--nocolor --nogroup"
        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)
  (defun my:howm:add-dev-null (args)
    (let ((str   (car args))               ;; 検索文字列
          (files (nth 1 args)))            ;; ファイルリスト
      (when (= 1 (length files))           ;; 単一ファイル?
        (if (file-regular-p (car files))   ;; 通常ファイル?
            ;; 単一の通常ファイルが指定された場合に /dev/null を追加
            (setq files (append files '("/dev/null")))))
      (list str files)))
  (advice-add 'howm-real-grep-single :filter-args #'my:howm:add-dev-null)
  ;; 検索対象のディレクトリの追加...とりあえず追加しないことに.
  (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))
  )

日記: tDiary

tdiary-mode をちまちまと弄っている所

(unless (locate-library "tdiary-mode")
  (quelpa '(tdiary-mode
            :fetcher github
            :repo "uwabami/tdiary-mode")))
(use-package tdiary-mode
  :if (file-directory-p "~/Nextcloud/tdiary")
  :commands (tdiary-mode tdiary-new tdiary-new-directory tdiary-replace)
  :config
  (load (concat my:d:password-store "/tdiary-mode.gpg"))
  (setq tdiary-browser-function 'browser-url
        tdiary-coding-system 'utf-8-dos
        tdiary-style-mode 'rd-mode
        tdiary-hour-offset 2
        tdiary-text-save-p t
        tdiary-text-suffix ".rd")
  )

MoinMoin: moinmoin-mode, moomin.el

Debian Wiki や職場の Wiki を編集するための MoinMoin の設定.

moinmoin-mode

MoinMoin 本体の moinmoin-mode 自体は古くて screen-lines に依存していたりするので folk して更新中. uwabami/moinmoin-mode: Fork from EmacsForMoinMoin, for Emacs >= 25

(unless (locate-library "moinmoin-mode")
  (quelpa '(moinmoin-mode
            :fetcher github
            :repo "uwabami/moinmoin-mode")))
(use-package moinmoin-mode)

そのうち気になる所を弄る,ということで.

moomin

元々は moomin = emacs-request + helm + moinmoin-mode という奴. folk して ido-vertical-mode を support する様に 多少弄った版を使う。 uwabami/moomin-el: Edit MoinMoin with Emacs

(unless (locate-library "moomin")
  (quelpa '(moomin
            :fetcher github
            :repo "uwabami/moomin-el")))
(use-package moomin
  :if (file-directory-p my:d:password-store)
  :bind (("C-x w" . ido-moomin)
         :map moinmoin-mode-map
         ("C-c C-c" . moomin-save-current-buffer)
         ("C-c C-s" . moomin-save-current-buffer)
         ("C-c C-o" . moomin-browse-current-page)
         ("C-c C-r" . moomin-reload-current-page))
  :config
  (setq moomin-history-file
        (concat my:d:tmp ".moomin_history"))
  (load (concat my:d:password-store "/moomin.gpg"))
  )

プログラム環境

VCS: magit

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

(use-package magit
  :bind (("C-x g" . magit-status))
  :config
  ;; (setq magit-completing-read-function 'magit-ido-completing-read)
  )

VCS: ido-ghq

ghq list を ido で選んで dired で開く

(unless (locate-library "ido-ghq")
  (quelpa '(ido-ghq
            :fetcher github
            :repo "uwabami/ido-ghq")))
(use-package ido-ghq
  :bind (("C-x f" . ido-ghq-open))
  :config
  (setq ido-ghq-short-list t)
  )

対応する括弧を見易く: rainbow-delimiters

(use-package rainbow-delimiters
  :config
  (add-hook 'emacs-lisp-mode-hook #'rainbow-delimiters-mode))

設定ファイル: generic-x

(use-package generic-x)

Textile

(use-package textile-mode
  :ensure t
  :diminish textile-mode
  )

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)
              (orgtbl-mode)
              ))
  (add-hook 'gfm-mode-hook
            (lambda ()
              (electric-indent-local-mode -1)
              (orgtbl-mode)
              ))
  :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")))

rainbow-mode

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

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

YAML

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

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
;;  :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$"
  )

rdoc-mode: 本体の方はどうも動かないなぁ…

(defface rdoc-header-1
  '((t (:inherit outline-1)))
  "rdoc mode header level 1")

(defface rdoc-header-2
  '((t (:inherit outline-2)))
  "rdoc mode header level 2")

(defface rdoc-header-3
  '((t (:inherit outline-3)))
  "rdoc mode header level 3")

(defface rdoc-header-4
  '((t (:inherit outline-4)))
  "rdoc mode header level 4")

(define-generic-mode 'rdoc-mode
  ()                    ;comment-list
  '()                   ;keyword-list
  '(                    ;font-lock-list
    ("^=[^=].*"                                             . 'rdoc-header-1)
    ("^==[^=].*"                                            . 'rdoc-header-2)
    ("^===[^=].*"                                           . 'rdoc-header-3)
    ("^====[^=].*"                                          . 'rdoc-header-4)
    ("^[\\*#]\\{1,9\\} "                                    . 'bold)
    ("\\(?:[^a-zA-Z0-9]\\)?\\*[^*]+\\*\\(?:[^a-zA-Z0-9]\\)" . 'bold)
    ("\\(?:[^a-zA-Z0-9]\\)?\\_[^_]+\\_\\(?:[^a-zA-Z0-9]\\)" . 'italic)
    )
  '("README_FOR_APP" "\\.rdoc$")    ;auto-mode-list
  '((lambda () (auto-fill-mode t))) ;function-list
  "Major mode for editing RDOC files.")

rd-mode

(use-package rd-mode
  :mode "\\.rd$"
  :config
  (add-hook 'rd-mode-hook
            'rd-show-other-block-all))

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 において, 幾つかのコマンドが追加/上書きされているが, あまり使うことの無いコマンドが表示されるのが嫌なのでそれらを削除.
  • コンパイルには latexmk を使う,です.

    (use-package tex-jp
      :if (and (executable-find "uplatex")
               (my:dpkg-status "auctex"))
      :defer t
      :init (progn
              (add-hook 'LaTeX-mode-hook #'TeX-source-correlate-mode)
              (add-hook 'LaTeX-mode-hook #'TeX-PDF-mode)
              (add-hook 'LaTeX-mode-hook #'turn-on-reftex))
      :config
      (add-hook 'LaTeX-mode-hook
                (function
                 (lambda ()
                   (dolist (command '("pTeX" "LaTeX" "pLaTeX" "pBibTeX" "jTeX" "jLaTeX" "jBibTeX"))
                     (delq (assoc command TeX-command-list) TeX-command-list))
                   (setq TeX-command-default "LaTeX"
                         japanese-LaTeX-command-default "LaTeX"
                         TeX-PDF-mode t
                         TeX-command-output-list '(("LaTeX" ("pdf")))
                         )
                   (add-to-list 'TeX-expand-list
                                '("%(LATEXENC)"
                                  (lambda ()
                                    (let ((str (japanese-TeX-get-encoding-string)))
                                      (if str (format "%s" str) "")))))
                   (add-to-list 'TeX-command-list
                                '("LaTeX"
                                  "LATEXENC=%(LATEXENC) latexmk -gg %t"
                                  TeX-run-TeX nil (latex-mode) :help "Run Latexmk")))))
      (setq TeX-source-correlate-method 'synctex
            TeX-source-correlate-start-server t
            TeX-view-program-selection '((output-dvi "xdvi")
                                         (output-pdf "Evince")
                                         ;; (output-pdf "Okular")
                                         (output-html "xdg-open"))
            TeX-auto-save t
            TeX-auto-local  (expand-file-name "auctex/auto" my:d:tmp)
            TeX-style-local (expand-file-name "auctex/style" my:d:tmp)
            TeX-parse-self t
            TeX-auto-untabify t
            font-latex-fontify-script nil
            font-latex-fontify-sectioning 1.0
            font-latex-script-display nil
            reftex-plug-into-AUCTeX t
            )
      )
    

~/.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
  :disabled t
  :init
  (add-hook 'LaTeX-mode-hook 'zotelo-minor-mode)
  (add-hook 'TeX-mode-hook   'zotelo-minor-mode)
  :config
  (setq zotelo-translator-charsets '((BibTeX . "Unicode")
                                     (Default . "Unicode"))
        zotelo-use-journal-abbreviation t)
)

補完: auto-complete

ちょいちょい上手く動かなかったりするんだけれど、どうしたモンかな.

(use-package auto-complete-config
  :config
  (ac-flyspell-workaround)
  (ac-set-trigger-key "M-TAB")
  (ac-config-default)
  (add-to-list 'ac-dictionary-directories (concat my:d:share "ac-dict"))
  (setq ac-comphist-file (concat my:d:tmp "ac-comphist.dat")
        ac-auto-start 4                          ; 4 文字以上で起動
        ac-use-menu-map t                        ; キーバインド
        ac-auto-show-menu 1                      ; 1秒でメニュー表示
        ac-use-comphist t                        ; 補完候補をソート
        ac-candidate-limit nil                   ; 補完候補表示を無制限に
        ac-use-quick-help nil)                   ; tool tip 無し
  ;; (dolist (mode
  ;;          '(
  ;;            ))
  ;;  (add-to-list 'ac-modes mode))
  )

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

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

(bind-keys*
 ("<f2>"    . eww)
 ("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)
 )

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

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

(use-package diminish :ensure t)
(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)
(my:diminish ""        'develock-mode)
(setq auto-revert-mode-text "")

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

(add-hook 'emacs-lisp-mode-hook '(lambda () (setq mode-name "")))
(add-hook 'lisp-interaction-mode-hook '(lambda () (setq mode-name "")))
(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 "")))

フォントと色

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

(defun my:load-window-config ()
  "load window-system specific settings"
  (interactive)
  (when window-system
    (progn
      (set-face-attribute 'default nil
                          :family "Cica"
                          :height 135) ;; 135pt
      (set-background-color "#242424")
      )))
(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" ))))
 ;; basic
 '(font-lock-builtin-face              ((t (:foreground "#7FBFFF" ))))
 '(font-lock-comment-delimiter-face    ((t (:foreground "#a5a5a6" ))))
 '(font-lock-comment-face              ((t (:foreground "#a5a5a6" ))))
 '(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 ))))
 '(mode-line                           ((t (:foreground "#F6F3E8" :background "#222244" ))))
 '(mode-line-inactive                  ((t (:foreground "#666666" :background "#999999" :bold nil ))))
 '(fringe                              ((t (:foreground "#666666" :background "#282828" ))))
;; '(hl-line                             ((t (:inherit highlight :underline t ))))
;; '(highlight                           ((t (:background "#333333" ))))
 '(minibuffer-prompt                   ((t (:foreground "#BF7FFF" ))))
 '(region                              ((t (:background "#222244" ))))
 ;; dired
 '(dired-directory                     ((t (:bold t :foreground "#7F7FFF" ))))
 '(dired-flagged                       ((t (:inherit error ))))
 ;; '(dired-header
 '(dired-ignored                       ((t (:inherit shadow ))))
 ;; '(dired-mark
 ;; '(dired-marked
 '(dired-perm-write                    ((t (:bold t :foreground "#FFFF7F" ))))
 '(dired-symlink                       ((t (:bold t :foreground "#7FFFFF" ))))
 '(dired-warning                       ((t (:inherit font-lock-warning-face ))))
 ;; helm
 '(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-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-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-ff-executable                  ((t (:inherit helm-ff-file :foreground "#7FFF7F" :bold t))))
 '(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" ))))
 ;; ido
 '(ido-first-match                     ((t (:underline t :weight bold))))
 '(ido-only-match                      ((t (:foreground "#FFFF4C" :overline nil :weight bold))))
 '(ido-subdir                          ((t (:inherit dired-directory))))
 ;; '(ido-vertical-first-match-face       ((t (:inherit ido-first-match))))
 ;;'(ido-vertical-match-face             ((t (:foreground "#4CFF4C"))))
 ;; '(ido-grid-mode-match ((t (:inherit ido-first-match ))))
 ;; powerline
 '(powerline-active1                   ((t (:background "#000000":foreground "#F6F3E8"))))
 '(powerline-active2                   ((t (:background "#666666" :foreground "#F6F3E8"))))
 '(powerline-inactive1                 ((t (:inherit modeline-inactive))))
 '(powerline-inactive2                 ((t (:inherit modeline-inactive))))
 ;; preview-latex
 '(font-latex-sectioning-0-face        ((t (:inherit font-latex-sectioning-1-face))))
 '(font-latex-sectioning-1-face        ((t (:inherit font-latex-sectioning-2-face))))
 '(font-latex-sectioning-2-face        ((t (:inherit font-latex-sectioning-3-face))))
 '(font-latex-sectioning-3-face        ((t (:inherit font-latex-sectioning-4-face))))
 '(font-latex-sectioning-4-face        ((t (:inherit font-latex-sectioning-5-face ))))
 '(font-latex-sectioning-5-face        ((t (:inherit font-lock-type-face :bold t))))
 '(font-latex-slide-title-face         ((t (:inherit font-lock-type-face :bold t))))
 '(font-latex-subscript-face           ((t nil)))
 '(font-latex-superscript-face         ((t nil)))
 '(font-latex-math-face                ((t (:inherit font-lock-constant-face ))))
 '(font-latex-script-char-face         ((t (:inherit font-lock-preprocessor-face :bold t))))
 '(font-latex-verbatim-face            ((t (:inherit font-lock-doc-string-face ))))
 ;; 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 ))))
 ;; git-gutter
 '(git-gutter:added                    ((t (:inherit default :bold t :foreground "#4CFF4C" :background "#666666"))))
 '(git-gutter:deleted                  ((t (:inherit default :bold t :foreground "#FF7FBF" :background "#666666"))))
 '(git-gutter:modified                 ((t (:inherit default :bold t :foreground "#FFFF4C" :background "#666666"))))
 '(git-gutter:unchanged                ((t (:inherit default :background "#666666" ))))
 '(git-gutter:separator-face           ((t (:inherit default :foreground "#FF4C4C" :background "#666666"))))
  ;;; 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 ))))
 ;; 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" ))))
 ;;
 ;; moinmoin
 '(moinmoin-h1                         ((t (:inherit outline-1))))
 '(moinmoin-h2                         ((t (:inherit outline-2))))
 '(moinmoin-h3                         ((t (:inherit outline-3))))
 '(moinmoin-h4                         ((t (:inherit outline-4))))
 '(moinmoin-h5                         ((t (:inherit outline-5))))
 '(moinmoin-url                        ((t (:inherit font-lock-link-face))))
 '(moinmoin-url-title                  ((t (:inherit moinmoin-url :bold t))))
 '(moinmoin-anchor-ref-id              ((t (:inherit moinmoin-url :underline t))))
 '(moinmoin-anchor-ref-title           ((t (:inherit moinmoin-url :bold t))))
 '(moinmoin-wiki-link                  ((t (:inherit moinmoin-url :underline t ))))
 '(moinmoin-inter-wiki-link            ((t (:inherit moinmoin-url :underline t ))))
 '(moinmoin-item                       ((t (:inherit font-lock-doc-face ))))
 '(moinmoin-item-2                     ((t (:inherit font-lock-doc-face ))))
 )
;; 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))))

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

ddskk の表示のカスタマイズ

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 をベースに見たい物だけ表示するようにしてみた. 変更点として,

  • separater は環境によってズレるので,半角スペースに変更
  • vc-mode でのアイコン表示に U+26A1⚡ High Voltage を使う

といった事をしている. East Asian ambiguous Width char の扱いは面倒ですね

(use-package powerline
  :config
  (setq powerline-default-separator 'utf-8
        powerline-utf-8-separator-left  #x20
        powerline-utf-8-separator-right #x20
        )
  (defpowerline my:powerline-vc
    (when (and (buffer-file-name (current-buffer)) vc-mode)
      (format "%s%s"
              (char-to-string #x26a1)
              (format-mode-line '(vc-mode vc-mode)))))
  (defun my:powerline-theme ()
    "Setup customize theme."
    (interactive)
    (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-mule-info mode-line 'l)
                     (powerline-raw "%*" mode-line 'l)
                     (powerline-buffer-id mode-line-buffer-id '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)
                     (my: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)
  )

起動時間の計測

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

(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/>.
Top