Emacs の設定

_はじめに

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

基本方針は以下の通り:

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

:Eating your own dog food - Wikipedia

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

_leaf.elでEmacs のパッケージの導入と設定を行なう

設定にはleaf.elを利用します. VCS からインストールしたいパッケージが幾つかあるので, それらについてはel-getを利用しています. 今後はfeather.elも試してみたいですね.

_設定は Org mode で書きたい

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

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

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

ついでに,出力される init.el 用のおまじない(?)として lexsical-binding を有効にしておきます.

;; -*- lexical-binding: nil -*-

_ディレクトリ構成の修正

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

ディレクトリ構成は以下のようにしました:

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

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

(when load-file-name
  (setq user-emacs-directory
        (expand-file-name (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))
(defconst my:d:pkg:elpa
  (expand-file-name "pkg/elpa" user-emacs-directory))
(defconst my:d:pkg:elget
  (expand-file-name "pkg/el-get" user-emacs-directory))
(dolist (my:d '(my:d:share
                my:d:tmp
                my:d:pkg:elpa
                my:d:pkg:elget))
  (lambda ()
    (unless (file-directory-p my:d)
      (make-directory my:d t))))

その他, 良く使うディレクトリもここで設定しておきます.

(defconst my:d:org (concat (getenv "HOME") "/Nextcloud/org/"))

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

(setq custom-file (concat my:d:tmp "custom.el"))

暇がある時に custom.el の中身を確認して,必要に応じて init.el に戻しています.

_Byte-Compile 時の Common Lisp の読み込み

幾つかん関数で Common-Lisp 的挙動が期待されているので, cl-lib を読み込んでおきます.

(eval-when-compile (require 'cl-lib nil t))

_Package 関連: package.el, leaf.el, el-get

leaf.elのおかげで, 無いと途方に暮れるパッケージ以外のインストールは無視できるようになります.

_package.el

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

(setq url-http-attempt-keepalives nil)
(require 'gnutls nil 'noerror)
(require 'package nil 'noerror)
(setq package-enable-at-startup t
      package-user-dir my:d:pkg:elpa
      package-gnupghome-dir (expand-file-name ".gnupg" (getenv "HOME"))
      ;; elpa/gnutls workaround
      gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"
      )
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(eval-when-compile
  (unless (file-exists-p (locate-user-emacs-file "tmp/bootstrap-stamp"))
    (package-refresh-contents)
    (with-temp-buffer (write-file (locate-user-emacs-file "tmp/bootstrap-stamp")))
    ))
(package-initialize)

_leaf.el

個々のパッケージの設定にはleaf.elを利用します.

(unless (package-installed-p 'leaf)
  (package-install 'leaf))
(require 'leaf nil 'noerror)
;; support optional keywords
(leaf leaf-keywords
  :ensure t
  :init
  (leaf diminish :ensure t :require t)
  (leaf delight :ensure t :require t)
  :config
  (leaf-keywords-init)
  )

_el-get

自分で修正した版やオリジナル版を別の場所から持ってくる場合は leaf.elからel-getを呼び出します.

(defconst el-get-dir my:d:pkg:elget) ;; override default
(leaf el-get
  :ensure t
  :require t
  ;; :custom (el-get-notify-type . message)
  :init
  (setq el-get-notify-type 'message
        el-get-git-shallow-clone t)
  )

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

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

を読み込んでいます.

(leaf exec-path-from-shell
  :ensure t
  :config
  (setq exec-path-from-shell-check-startup-files nil
        exec-path-from-shell-variables
        '("SHELL"
          "DEBFULLNAME"
          "DEBEMAIL"
          "SKKSERVER"
          "TEXMFHOME"
          "http_proxy"
          "GPG_KEY_ID"
          "GPG_AGENT_INFO"
          "PASSWORD_STORE_DIR"
          "PATH"))
  (exec-path-from-shell-initialize)
  (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)))
  )

_言語の設定 [/]

最近のEmacsはlocaleから文字コードを自動判別するらしいので, 以前良く設定していた以下は不要らしいですね。

(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 をインストールすることにしています。

(leaf cp5022x
  :ensure t
  :require 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 対応

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

(leaf locale-eaw-emoji
  :el-get (locale-eaw-emoji
           :type github
           :pkgname "uwabami/locale-eaw-emoji")
  :require t
  :config
  (eaw-and-emoji-fullwidth)
  )

_ターミナルでもicon fontを使いたい。

all-the-icons.elのデータを修正して, icons in terminalを修正した自作フォントのデータを読みに行くようにしてみました。

(leaf all-the-icons
  :ensure t
  :init
  (setq all-the-icons-scale-factor 0.9
        all-the-icons-default-adjust 0.0)
  )
(leaf all-the-icons-in-terminal
  :el-get (all-the-icons-in-terminal
           :type github
           :pkgname "uwabami/isfit-plus")
  :require t
  :config
  (add-to-list 'all-the-icons-mode-icon-alist
               '(f90-mode all-the-icons-faicon "facebook")) ;; facebook!
  (add-to-list 'all-the-icons-mode-icon-alist
               '(wl-folder-mode all-the-icons-faicon "folder-o" ))
  (add-to-list 'all-the-icons-mode-icon-alist
               '(wl-summary-mode all-the-icons-faicon "folder-open-o"))
  (add-to-list 'all-the-icons-mode-icon-alist
               '(wl-draft-mode all-the-icons-material "drafts"))
  (add-to-list 'all-the-icons-mode-icon-alist
               '(mime-view-mode all-the-icons-faicon "envelope-o"))
  )

_macOS対応

最近良く触る様になったので設定している。 まあ, イマイチ慣れない訳ですけれど

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

_独自関数

細かい独自関数,など.

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

_ファイル名を minibuffer におさまる様に整形

zsh prompt風味.

(defun my:shorten-file-path (fpath max-length)
  "Show up to `max-length' characters of a directory name `fpath' like zsh"
  (let* ((path (reverse (split-string (abbreviate-file-name fpath) "/")))
         (output "")
         (top (mapconcat 'identity (reverse (last path 3)) "/"))
         (vmax (- max-length 4 (length top)))
         (path (butlast path 3))
         )
    (while (and path
                (and (< (length output) vmax)
                     (< (length (concat "/" (car path) output)) vmax)))
      (setq output (concat "/" (car path) output))
      (setq path (cdr path)))
    ;; 省略
    (when path
      (setq output (concat "/..." output)))
    (format "%s%s" top output)
    ))

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

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

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

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

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

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

稀に暴走する, ような…?

(leaf migemo
  :if (executable-find "cmigemo")
  :require t
  :config
  (cond
   ((and (eq system-type 'darwin)
         (file-directory-p "/usr/local/share/migemo/utf-8/"))
    (setq migemo-dictionary "/usr/local/share/migemo/utf-8/migemo-dict"))
   (t
    (setq migemo-dictionary "/usr/share/cmigemo/utf-8/migemo-dict"))
   )
  (setq migemo-command "cmigemo"
        migemo-options '("-q" "--emacs")
        migemo-user-dictionary nil
        migemo-regex-dictionary nil
        migemo-coding-system 'utf-8-unix)
  (migemo-init)
  )

_補完: ivy,counsel,swiper

counsel が swiper に,swiper が ivy に依存しているので, パッケージマネージャを使う場合は,counsel をインストールすれば, 3つのパッケージが同時にインストールされます.

_補完候補の絞り込み: ivy

まだ試行錯誤中.

(leaf ivy
  :ensure t
  :init
  (leaf flx :ensure t)
  (leaf ivy-hydra
    :ensure t
    :commands ivy-read
    :bind ((:ivy-minibuffer-map
            ("M-o" . hydra-ivy/body )))
    )
  ;; IDO-like ?
  :bind ((:ivy-minibuffer-map
          ("RET"   . ivy-alt-done)
          ;; ("C-j"   . ivy-immediate-done)
          ;; ("C-RET" . ivy-immediate-done)
          ))
  ;;
  :config
  (setq enable-recursive-minibuffers t
        minibuffer-depth-indicate-mode 1)
  (setq ivy-use-virtual-buffers nil
        ivy-use-selectable-prompt t
        ivy-fixed-height-minibuffer t
        ivy-wrap t
        ivy-height 11
        ivy-display-style 'fancy
        ivy-count-format (concat (all-the-icons-faicon "sort-amount-asc") " [%d/%d] ")
        ivy-extra-directories nil       ; default の "." と ".." を除外
        ivy-initial-inputs-alist nil
        ;; 入力前のリストの並び
        ;; ivy-sort-functions-alist '((t . ivy--regex-fuzzy))
        ;; ivy-format-functions-alist '((t . ivy-format-function-arrow))
        ivy-re-builders-alist '((t . ivy--regex-fuzzy))
        )
  )

_補完候補の調整: prescient

過去の候補を記憶しておいてくれる優れモノ.

;; override
(leaf prescient
  :ensure t
  :commands (ivy ivy-read)
  :init
  (setq prescient-save-file (expand-file-name  "prescient-save.el" my:d:tmp)
        prescient-aggressive-file-save t
        prescient-filter-method '(fuzzy regexp initialism))
  :config
  (prescient-persist-mode 1)
  )
(leaf ivy-prescient
  :ensure t
  :commands (ivy ivy-read)
  :init
  (setq ivy-prescient-retain-classic-highlighting t)
  :config
  (ivy-prescient-mode 1)
  )

_インジケータをアイコンに

まだちょっと整形する必要がありそう.

(leaf *ivy-format-function-arrow
  :after ivy
  :config
  (defun my:ivy-format-function-arrow (cands)
    "Custom; Transform CANDS into a string for minibuffer."
   (setq-local tab-width 1)
    (ivy--format-function-generic
     (lambda (str)
       (concat (all-the-icons-faicon
                "hand-o-right" :face 'minibuffer-prompt)
               "\t" (ivy--add-face str 'ivy-current-match)))
     (lambda (str)
       (concat ;; (all-the-icons-faicon "hand-o-right" :foreground 'background)
        "\t" str))
     cands
     "\n"))
  (setq ivy-format-functions-alist
        '((t . my:ivy-format-function-arrow)))
  )

_アイコン表示: all-the-icons-ivy

(leaf all-the-icons-ivy
  :ensure t
  :config
  (all-the-icons-ivy-setup)
  )

_counsel: ivy-read を使った既存のコマンド群の置き換え

まだ調整が必要そう.

(leaf smex
  :ensure t
  :config
  (setq smex-save-file (expand-file-name "smex-items" my:d:tmp)
        smex-history-length 50)
  )
(leaf counsel
  :ensure t
  :bind ((("M-x"     . counsel-M-x)
          ("C-x C-r" . my:counsel-recentf)
          ("C-x C-f" . counsel-find-file)
          ;;("C-x C-b" . counsel-ibuffer)
          ;;("C-x b"   . counsel-ibuffer)
          )
         (:counsel-find-file-map
          ("C-l"     . counsel-up-directory)))
  :init
  (setq-default counsel-mode-override-describe-bindings t)
  ;; recentf-list が長いので短縮表示
  (defun my:counsel-recentf ()
    "Custom: Find a file on `recentf-list'."
    (interactive)
    (require 'recentf)
    (recentf-mode)
    (ivy-read "Recentf: " (mapcar (lambda (f)
                                    (cons (my:shorten-file-path f 77) f))
                                  recentf-list)
              :action (lambda (f)
                        (with-ivy-window
                          (find-file (cdr f))))
              :require-match t
              :caller 'counsel-recentf)
    )
  :config
  ;; 補完で無視する拡張子の追加.そのうち増える.
  (dolist (ext '("./"
                 "../"
                 ".dvi"
                 ".fdb_latexmk"
                 ".fls"
                 ".ilg"
                 ".jqz"
                 ".mod"
                 ".nav"
                 ".out"
                 ".snm"
                 ".synctex.gz"
                 ".vrb"
                 ))
    (add-to-list 'completion-ignored-extensions ext))
  (setq counsel-find-file-ignore-regexp
        (regexp-opt completion-ignored-extensions))
  )

_検索強化: swiper

まだ設定していない.migemoと仲良くするために試行錯誤中.

(leaf swiper
  :init
  ;; (leaf avy-migemo
  ;;   :if (executable-find "cmigemo")
  ;;   :ensure t
  ;;   :after migemo
  ;;   :init
  ;;   (require 'avy-migemo-e.g.swiper)
  ;;   )
  ;; :bind ("C-s" . swiper)
  )

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

最近ぼちぼち他の拡張も入れる様になってきた.

_標準機能の設定: 表示関連

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

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

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

(dolist (mode
         '(tool-bar-mode
           ;; scroll-bar-mode
           menu-bar-mode
           blink-cursor-mode
           column-number-mode))
  (funcall mode -1))

ベル無効化

(setq ring-bell-function 'ignore)

現在行のハイライト

(global-hl-line-mode t)

選択リージョンに色付け

(transient-mark-mode t)

対応する括弧を強調表示

(leaf show-paren-mode
  :config
  (setq show-paren-style 'mixed)
  (show-paren-mode t)
  )

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

(leaf line-number-mode
  :config
  (setq linum-format "%5d ")
  (line-number-mode -1))

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)

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

(setq next-line-add-newlines nil)

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

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

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

~/.emacs.d/ 以下にファイルが転がるのがなんか嫌なので, 気がつく度に設定している.

(leaf *change-default-file-location
  :init
  (leaf url
    :init
    (setq url-configuration-directory (concat my:d:tmp "url"))
    )
  (leaf nsm
    :if (>= emacs-major-version 25)
    :config
    (setq nsm-settings-file (concat my:d:tmp "network-settings.data"))
    )
  (leaf bookmark
    :config
    (setq bookmark-default-file (concat my:d:share "bookmarks"))
    )
  )

他にもイロイロありそう. bookmark はちゃんと使いこなしたい所ではあるが.

_.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 が止まる」という事を頻繁に経験することになるだろう.

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

ファイルを開く際には counsel-recentf-open を使うので, 結局履歴を貯める設定をしている事になっている.

(leaf recentf-ext :ensure t)
(leaf recentf
  :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/\\.*"
                          "\\.*草稿\\.*"
                          "^/[^/:]+:"  ; exclude tramp
                          ))
  )

ディレクトリの履歴も取れるので recentf-ext を入れておく

_abbrev: 略語展開

あまり上手く使えていない.

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

minibuffer では eldoc にお黙り頂く。

(leaf eldoc
  :hook (emacs-lisp-mode-hook . turn-on-eldoc-mode)
  :diminish (eldoc-mode "")
  :preface
  (defun my:eldoc-message (f &optional string)
    (unless (active-minibuffer-window)
      (funcall f string)))
  :advice (:around eldoc-message
                   my:eldoc-message)
  )

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

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

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

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

_whitespace: 空白の強調表示

背景も変えようかなぁ…

(leaf whitespace
  :diminish ((global-whitespace-mode "")
             (whitespace-mode "")
             )
  :hook (after-init-hook . global-whitespace-mode)
  :init
  (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)
        )
  )

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

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

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

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

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

(leaf time-stamp
  :hook (before-save-hook . 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"
        )
  )

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

_tramp: ssh 越しにファイルを編集 [0/1]

(leaf tramp
  :init
  (setq tramp-persistency-file-name (concat my:d:tmp "tramp"))
  (add-hook 'kill-emacs-hook
            (lambda ()
              (if (file-exists-p custom-file)
                  (delete-file tramp-persistency-file-name))))
  )

_eww: 内蔵ブラウザ [/]

背景色の指定と幅の強制が上手く動いてくれない.一旦保留.

(leaf eww
  :bind (;; ("<f2>"    . eww)
         (: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)
          ("+"  . my:eww-increase-width)
          ("-"  . my:eww-decrease-width)
          ("h"  . backward-char)
          ("j"  . next-line)
          ("k"  . previous-line)
          ("l"  . forward-char)
          ("/"  . isearch-forward)
          ("?"  . isearch-backward)
          ("n"  . isearch-next)
          ("N"  . isearch-previous)))
         ;;("f"  . ace-link-eww)))
  :init
  (unless (file-directory-p (expand-file-name "eww" my:d:tmp))
    (make-directory (expand-file-name "eww" my:d:tmp)))
  :config
  (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 t)
  (defun my: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 'my:shr-colorize-region--disable)
  (advice-add 'eww-colorize-region :around 'my: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))
  )

_browse-url

ブラウザ呼び出しは xdg-open/open に丸投げ.

(leaf browse-url
  :require t
  :config
  (cond ((executable-find "xdg-open")
         (setq browse-url-browser-function 'browse-url-xdg-open
               shr-external-browser 'browse-url-xdg-open))
        ((eq system-type 'darwin)
         (setq browse-url-browser-function 'browse-url-default-macosx-browser
               shr-external-browser 'browse-url-default-macosx-browser))
        (t
         (setq browse-url-browser-function 'w3m-browse-url)))
  )

_server: Emacs server

(leaf server
  :require t
  :config
  (unless (server-running-p)
    (server-start))
  )

_ibuffer: buffer の操作

ibuffer というより hydra の設定の様な気がしてきた.

(leaf ibuffer
  :bind (("C-x C-b" . ibuffer-other-window)
         ("C-x b"   . ibuffer-other-window)
         ("C-x M-b" . ibuffer)
         (:ibuffer-mode-map
          ("C-x C-f" . my:ibuffer-counsel-find-file))
         ;; ("."      . hydra-ibuffer-main/body)
         )
  :init
  (defun my:ibuffer-counsel-find-file ()
    "Like `counsel-find-file', but default to the directory of the buffer at point."
    (interactive)
    (let ((default-directory
            (let ((buf (ibuffer-current-buffer)))
              (if (buffer-live-p buf)
                  (with-current-buffer buf
                    default-directory)
                default-directory))))
      (counsel-find-file default-directory)))
;;   (leaf hydra :ensure t
;;     :config
;;     (defhydra hydra-ibuffer-main (:color pink :hint nil)
;; "
;;  ^Navigation^ | ^Mark^        | ^Actions^        | ^View^
;; -^----------^-+-^----^--------+-^-------^--------+-^----^-------
;;   _k_:    ʌ   | _m_: mark     | _D_: delete      | _g_: refresh
;;  _RET_: visit | _u_: unmark   | _S_: save        | _s_: sort
;;   _j_:    v   | _*_: specific | _a_: all actions | _/_: filter
;; -^----------^-+-^----^--------+-^-------^--------+-^----^-------
;; "
;;     ("j"   ibuffer-forward-line)
;;     ("RET" ibuffer-visit-buffer :color blue)
;;     ("k"   ibuffer-backward-line)
;;     ("m"   ibuffer-mark-forward)
;;     ("u"   ibuffer-unmark-forward)
;;     ("*"   hydra-ibuffer-mark/body :color blue)

;;     ("D"   ibuffer-do-delete)
;;     ("S"   ibuffer-do-save)
;;     ("a"   hydra-ibuffer-action/body :color blue)

;;     ("g"   ibuffer-update)
;;     ("s"   hydra-ibuffer-sort/body :color blue)
;;     ("/"   hydra-ibuffer-filter/body :color blue)

;;     ("o" ibuffer-visit-buffer-other-window "other window" :color blue)
;;     ("q" quit-window "quit ibuffer" :color blue)
;;     ("." nil "toggle hydra" :color blue))

;;     (defhydra hydra-ibuffer-mark (:color teal :columns 5
;;                                          :after-exit (hydra-ibuffer-main/body))
;;       "Mark"
;;       ("*" ibuffer-unmark-all "unmark all")
;;       ("M" ibuffer-mark-by-mode "mode")
;;       ("m" ibuffer-mark-modified-buffers "modified")
;;       ("u" ibuffer-mark-unsaved-buffers "unsaved")
;;       ("s" ibuffer-mark-special-buffers "special")
;;       ("r" ibuffer-mark-read-only-buffers "read-only")
;;       ("/" ibuffer-mark-dired-buffers "dired")
;;       ("e" ibuffer-mark-dissociated-buffers "dissociated")
;;       ("h" ibuffer-mark-help-buffers "help")
;;       ("z" ibuffer-mark-compressed-file-buffers "compressed")
;;       ("b" hydra-ibuffer-main/body "back" :color blue))

;;     (defhydra hydra-ibuffer-action (:color teal :columns 4
;;                                            :after-exit
;;                                            (if (eq major-mode 'ibuffer-mode)
;;                                                (hydra-ibuffer-main/body)))
;;       "Action"
;;       ("A" ibuffer-do-view "view")
;;       ("E" ibuffer-do-eval "eval")
;;       ("F" ibuffer-do-shell-command-file "shell-command-file")
;;       ("I" ibuffer-do-query-replace-regexp "query-replace-regexp")
;;       ("H" ibuffer-do-view-other-frame "view-other-frame")
;;       ("N" ibuffer-do-shell-command-pipe-replace "shell-cmd-pipe-replace")
;;       ("M" ibuffer-do-toggle-modified "toggle-modified")
;;       ("O" ibuffer-do-occur "occur")
;;       ("P" ibuffer-do-print "print")
;;       ("Q" ibuffer-do-query-replace "query-replace")
;;       ("R" ibuffer-do-rename-uniquely "rename-uniquely")
;;       ("T" ibuffer-do-toggle-read-only "toggle-read-only")
;;       ("U" ibuffer-do-replace-regexp "replace-regexp")
;;       ("V" ibuffer-do-revert "revert")
;;       ("W" ibuffer-do-view-and-eval "view-and-eval")
;;       ("X" ibuffer-do-shell-command-pipe "shell-command-pipe")
;;       ("b" nil "back"))

;;     (defhydra hydra-ibuffer-sort (:color amaranth :columns 3)
;;       "Sort"
;;       ("i" ibuffer-invert-sorting "invert")
;;       ("a" ibuffer-do-sort-by-alphabetic "alphabetic")
;;       ("v" ibuffer-do-sort-by-recency "recently used")
;;       ("s" ibuffer-do-sort-by-size "size")
;;       ("f" ibuffer-do-sort-by-filename/process "filename")
;;       ("m" ibuffer-do-sort-by-major-mode "mode")
;;       ("b" hydra-ibuffer-main/body "back" :color blue))

;;     (defhydra hydra-ibuffer-filter (:color amaranth :columns 4)
;;       "Filter"
;;       ("m" ibuffer-filter-by-used-mode "mode")
;;       ("M" ibuffer-filter-by-derived-mode "derived mode")
;;       ("n" ibuffer-filter-by-name "name")
;;       ("c" ibuffer-filter-by-content "content")
;;       ("e" ibuffer-filter-by-predicate "predicate")
;;       ("f" ibuffer-filter-by-filename "filename")
;;       (">" ibuffer-filter-by-size-gt "size")
;;       ("<" ibuffer-filter-by-size-lt "size")
;;       ("/" ibuffer-filter-disable "disable")
;;       ("b" hydra-ibuffer-main/body "back" :color blue))
;;     )
  :config
  (define-ibuffer-column icon (:name "  ")
    (let ((icon
           (if (and (buffer-file-name)
                    (all-the-icons-auto-mode-match?))
               (all-the-icons-icon-for-file
                (file-name-nondirectory (buffer-file-name)))
             (all-the-icons-icon-for-mode major-mode ))))
      (if (symbolp icon)
          (setq icon (all-the-icons-faicon "file-o" :face 'all-the-icons-dsilver))
        icon)))
  ;;
  (setq ibuffer-formats
        `((mark modified read-only
                " " (icon 2 2 :left :elide)
                ,(propertize " " 'display `(space :align-to 8))
                (name 18 18 :left :elide)
                " " (size 9 -1 :right)
                " " (mode 16 16 :left :elide) " " filename-and-process)
          (mark " " (name 16 -1) " " filename)))
  )

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

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

(leaf-keys (("C-h"     . backward-delete-char)
            ("C-c M-a" . align-regexp)
            ("C-c ;"   . comment-region)
            ("C-c M-;" . uncomment-region)
            ("C-/"     . undo)
            ("C-c M-r" . replace-regexp)
            ("C-c r"   . replace-string)
            ("<home>"  . beginning-of-buffer)
            ("<end>"   . end-of-buffer)
            ("C-c M-l" . toggle-truncate-lines)
            ("C-c C-j" . browse-url-at-point)
            ))

_カラーコードに色付け: rainbow-mode

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

(leaf rainbow-mode
  :ensure t
  :config
  (with-eval-after-load 'rainbow-mode
    (diminish 'rainbow-mode (format " %s" "\x1F308")))
  )

モードラインの調整が上手く動いていない気がする(:diminish が効かない). しょうがないので with-eval-after-load で.

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

RainbowDelimiters: global に有効にするのは他のMajor modeとの衝突があるので止めた方が良い,らしい.

(leaf rainbow-delimiters
  :ensure t
  :diminish ""
  :hook (prog-mode-hook . rainbow-delimiters-mode)
  )

_ファイル操作: dired

all-the-icons-dired でアイコンを表示する様にしてみた。

(leaf all-the-icons-dired
  :ensure t
  :hook (dired-mode-hook . my:all-the-icons-dired-mode)
  :init
  (define-minor-mode my:all-the-icons-dired-mode
    "Custom: always Display all-the-icons icon for each files in a dired buffer."
    :lighter ""
    (if my:all-the-icons-dired-mode
        (progn
          (add-hook 'dired-after-readin-hook 'all-the-icons-dired--display t t)
          (when (derived-mode-p 'dired-mode)
            (all-the-icons-dired--display)))
      (remove-hook 'dired-after-readin-hook 'all-the-icons-dired--display t)
      (dired-revert)))
  )

_チラ見: quick-preview.el

ターミナルの場合でも強制的に動くようにした folk 版を作っている. とはいえ GNOME Sushi 前提なので,GNOME以外の環境だとシンドいかもなぁ…

(leaf quick-preview
  :el-get (quick-preview
           :type github
           :pkgname "uwabami/quick-preview.el")
  :bind (("C-c q" . quick-preview-at-point)
         (:dired-mode-map
          ("Q"    . quick-preview-at-point)))
  )

_Emacs-W3m

eww がイマイチしっくり来ないので, 結局Emacs-w3mを使っている.

(leaf w3m
  :if (executable-find "w3m")
  :commands (w3m-goto-url w3m-search)
  :bind (("<f2>"     . w3m)
         (:w3m-mode-map
          ("<left>"  . backward-char)
          ("<right>" . forward-char)
          ("<up>"    . previous-line)
          ("<down>"  . next-line))
         (:w3m-minor-mode-map
          ("<left>"  . backward-char)
          ("<right>" . forward-char)
          ("<up>"    . previous-line)
          ("<down>"  . next-line)))
  :config
  (setq w3m-search-default-engine "google"
        w3m-use-cookies t
        w3m-use-form t
        )
  )

とはいえ,これでbrowseすることは滅多に無いのだけれど.

_ace-link: リンクを簡単に辿る [0/1]

(leaf ace-link
  :ensure t
  :after w3m
  :bind ((:w3m-mode-map
          ("f" . ace-link-w3m))
         ;; (:eww-mode-map
         ;; ("f" . ace-link-eww))
         )
  :config
  (ace-link-setup-default)
  )

_Elscreen

_導入 [0/1]

emacs-jpのfolk版を利用中。 modeline の表示そのものは無効化しておく.

(leaf elscreen
  :el-get (elscreen
           :type github
           :pkgname "emacs-jp/elscreen")
  :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)
  )

_elscreen + zsh での連携

詳細は

などを参考に.

(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 本体側の設定

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

(unless (locate-library "skk")
  (package-install 'ddskk))
(defvar skk-user-directory (concat my:d:tmp "skk"))
(unless (file-directory-p skk-user-directory)
  (make-directory skk-user-directory))
(leaf skk
  :bind (("C-x j"   . skk-mode)
         ("C-x C-j" . skk-mode)
         ("C-\\"    . skk-mode))
  :init
  (setq skk-init-file (concat user-emacs-directory "init-ddskk")
        default-input-method "japanese-skk" )
  )

_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    . ("。" . "、"))
        (jp-en . ("。" . ", "))
        (en-jp . ("." . ","))
        (en    . (". " . ", "))
        ))
(setq-default skk-kutouten-type 'en-jp)

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

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

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

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

辞書の共有

(setq skk-share-private-jisyo t)

変換候補を縦に表示

(setq skk-show-inline 'vertical)

_インクリメンタルサーチ

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")))
 )
(when (file-exists-p "/usr/local/share/skkdic/SKK-JISYO.emoji.utf8")
  (setq skk-extra-jisyo-file-list
        (list '("/usr/local/share/skkdic/SKK-JISYO.emoji.utf8" . utf-8))))

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

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

_Linux では xclip を利用。

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

(leaf xclip
  :if (and (executable-find "xclip")
           (eq system-type 'gnu/linux))
  :ensure t
  :config
  (xclip-mode 1))

_macOS では pbcopy/pbpaste を利用する。

pbcopy/pbpase の呼び出し方が変わった? 動かない時がある様な。

(leaf *macOSclipborad
  :if (eq system-type 'darwin)
  :config
  (defun my:copy-from-osx ()
    "Get string via pbpaste"
    (shell-command-to-string "pbpaste"))
  (defun my:paste-to-osx (text &optional push)
    "put `TEXT' via pbcopy with `PUSH' mode"
    (let ((process-connection-type nil))
      (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
        (process-send-string proc text)
        (process-send-eof proc))))
  (setq interprogram-cut-function 'my:paste-to-osx
        interprogram-paste-function 'my:copy-from-osx)
  )

_校正,辞書等

_RedPen

便利そうなんだけれど, イマイチ上手く使いこなせていない.

(leaf redpen-paragraph
  :if (executable-find "redpen")
  :disabled t
  :ensure t
  :bind ("C-c R" . redpen-paragraph)
  ;; :hook (kill-emacs-hook . (if (file-exists-p redpen-temporary-filename)
  ;;                             (delete-file redpen-temporary-filename)))
  :init
  (setq redpen-commands
    '("redpen -r json -c ~/.config/redpen/redpen-conf-en.xml %s 2>/dev/null"
      "redpen -r json -c ~/.config/redpen/redpen-conf-ja.xml %s 2>/dev/null")
    )
  :config
  (add-hook 'kill-emacs-hook
            (lambda ()
              (if (file-exists-p redpen-temporary-filename)
                  (delete-file redpen-temporary-filename))))
  )

_spell checker: ispel, flyspell

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

(leaf ispell
  :if (file-executable-p "aspell")
  :init
  (setq-default ispell-program-name "aspell")
  :config
  (add-to-list 'ispell-skip-region-alist '("[^\000-\377]+")))

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

(leaf flyspell
  :preface
  (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 (:around flyspell-emacs-popup
                   my:flyspell-popup-choose)
  )

_辞書: lookup-el

無いとシンドい.

(leaf lookup
  :if (and (my:dpkg-status "lookup-el")
           (file-exists-p "/usr/local/share/dict/lookup-enabled"))
  :commands (lookup lookup-region lookup-pattern)
  :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 "研究社 英和活用大辞典 ")
          )))

_Google翻訳

たまに変なのだが,深追いしていない

(leaf google-translate
  :bind (("M-o t" . google-translate-at-point)
         ("M-o T" . google-translate-at-point-reverse))
  :ensure t
  :config
  (setq google-translate-default-source-language "en"
        google-translate-default-target-language "ja")
  )

_認証関連: plstore, oauth2, password-store

_oauth2, plstore

oauth2 の認証情報は plstore で保存される. ファイルの置き場所と暗号鍵の設定をしておく. また, plstore のデフォルトは対称鍵暗号化なので, GPG_KEY_ID を設定しておく.

(leaf *authehtification
  :if (getenv "GPG_KEY_ID")
  (leaf oauth2
    :ensure t
    :init
    (setq oauth2-token-file (concat my:d:tmp "oauth2.plstore"))
    )
  (leaf plstore
    :ensure t
    :init
    (setq plstore-secret-keys 'silent
          plstore-encrypt-to (getenv "GPG_KEY_ID"))
    )
  )

_password-store, auth-password-store

auth-source として password-store を使う拡張

(leaf *password-store
  :if (and my:d:password-store
           (executable-find "pass"))
  (leaf password-store :ensure t)
  (leaf auth-source-pass :ensure t)
  )

_id-manager の設定

ID と Password の簡単な組の管理をするのに非常に重宝していました。 最近は password-store を使う様になったのでそのうち全部移行しますが, とりあえず。

(leaf id-manager
  :if (file-exists-p "~/.gnupg/idm-db.gpg")
  :ensure t
  :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)
  )

_MUA の設定: wanderlust

MUA として Wanderlust を使っている

_Emacs 本体側の設定

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

(leaf 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)
  :preface
  (defun my:wl-mode-line-buffer-identification (&optional id)
    (force-mode-line-update t))
  :advice (:override wl-mode-line-buffer-identification
                     my:wl-mode-line-buffer-identification)
  :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")))
  :config
  )

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

_Wanderlust 本体の設定

実際の設定は以下の通り

_byte-compile の準備

(eval-and-compile
  (leaf el-x
    :el-get (el-x
             :type github
             :pkgname "sigma/el-x"
             :build `(("make" ,(format "EMACSBIN=%s" el-get-emacs)))
             :load-path "lisp"
             )
    :require t
    )
  )
(eval-when-compile
  (require 'cp5022x)
  (require 'wl)
  (require 'mime-def))

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

_rail

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

(leaf rail
  :init
  (setq rail-emulate-genjis t)
  :require 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 [0/1]

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

(leaf elscreen-wl
  :disabled t
  :el-get (elscreen-wl
           :type github
           :pkgname "syohex/emacs-elscreen-wl")
  )
_SEMI の追加設定

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

;; (setq mime-view-text/html-previewer 'shr)
;; (setq mime-setup-enable-inline-html 'shr)
;; 幅指定 → 実際の関数は eww の設定を参照
;; (defvar my:shr-width 78)
;; (defun my:shr-insert-document (&rest them)
;;   (let ((shr-width (min (1- (window-width)) my:shr-width)))
;;    (apply them)))
;; (defun my:mime-shr-preview-text/html (&rest args)
;;   (advice-add 'shr-insert-document :around 'my:shr-insert-document)
;;   (unwind-protect
;;       (apply args)
;;     (advice-remove 'shr-insert-document 'my:shr-insert-document)))
;; (advice-add 'mime-shr-preview-text/html :around
;;            'my:mime-shr-preview-text/html)
;;
(leaf mime-w3m :require t)
(leaf 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 より優先

(setq mime-view-type-subtype-score-alist
      '(((text . plain) . 0)
        ((text . html)  . 1)
        ))

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

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

送信時は確認する

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

_キーバインド関連

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"
      wl-summary-width 84)

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

(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 順: 返信が来た順

元ネタは Re: wanderlust で GMail 風、新着レス順にソート. あんまり頑張る気がなかったので 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)))
         (elmo-entity-to-number (x)
                                (elt (cddr x) 0))
         (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-entity-to-number a)))
     (max-reply-date (thread-get-family (elmo-entity-to-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)

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

face の色付け

(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 bold ))))
(my:wl-set-face 'wl-highlight-folder-zero-face
                '((t (:foreground "#f6f3e8" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-1
                '((t (:foreground "#7fff7f" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-2
                '((t (:foreground "#ffff7f" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-3
                '((t (:foreground "#7f7fff" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-4
                '((t (:foreground "#7fffff" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-5
                '((t (:foreground "#ff7fff" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-6
                '((t (:foreground "#ff7f7f" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-7
                '((t (:foreground "#4cff4c" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-8
                '((t (:foreground "#ffff4c" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-9
                '((t (:foreground "#4c4cff" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-10
                '((t (:foreground "#4cffff" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-11
                '((t (:foreground "#ff4cff" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-cited-text-12
                '((t (:foreground "#ff4c4c" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-date-header-contents
                '((t (:foreground "#4CFF4C" :bold t :italic nil :weight bold ))))
(my:wl-set-face 'wl-highlight-message-header-contents
                '((t (:foreground "#aaaaaa" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-headers
                '((t (:foreground "#4CFFFF" :bold t :italic nil :weight bold ))))
(my:wl-set-face 'wl-highlight-message-important-header-contents2
                '((t (:foreground "#4CFF4C" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-signature
                '((t (:foreground "#aaaaaa" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-message-important-header-contents
                '((t (:foreground "#FF4CFF" :bold t :italic nil :weight bold ))))
(my:wl-set-face 'wl-highlight-message-subject-header-contents
                '((t (:foreground "#FF4C4C" :bold t :italic nil :weight bold ))))
(my:wl-set-face 'wl-highlight-message-from-header-contents
                '((t (:foreground "#FFFF4C" :bold t :italic nil :weight bold ))))
(my:wl-set-face 'wl-highlight-message-unimportant-header-contents
                '((t (:foreground "#aaaaaa" :bold nil :italic nil :weight normal ))))
(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-refiled-face
                '((t (:foreground "#7F7FFF" :bold nil :italic nil :weight normal ))))
(my:wl-set-face 'wl-highlight-summary-thread-top-face
                '((t (:foreground "#F6F3E8" :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-folder-killed-face
;;                 '((t (:foreground ,my:h:black :5Dbold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-folder-many-face
;;                 '((t (:foreground ,my:h:magenta :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-folder-opened-face
;;                 '((t (:foreground "#4cffff" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-folder-path-face
;;                 '((t (:underline t :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-folder-unknown-face
;;                 '((t (:foreground "#4cffff" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-folder-unread-face
;;                 '((t (:foreground ,my:n:blue :bold nil :italic nil ))))
;; (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-summary-copied-face
;;                 '((t (:foreground "#4CFFFF" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-deleted-face
;;                 '((t (:foreground ,my:h:black :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-displaying-face
;;                 '((t (:underline t :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-disposed-face
;;                 '((t (:foreground "#aaaaaa" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-flagged-face
;;                 '((t (:foreground ,my:h:yellow :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-forwarded-face
;;                 '((t (:foreground ,my:h:blue :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-high-read-face
;;                 '((t (:foreground ,my:h:green :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-high-unread-face
;;                 '((t (:foreground ,my:h:orange :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-important-face
;;                 '((t (:foreground "#ffff4c" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-killed-face
;;                 '((t (:foreground ,my:h:black :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-l:read-face
;;                 '((t (:foreground "#4CFF4C" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-l:unread-face
;;                 '((t (:foreground ,my:h:lightb :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-new-face
;;                 '((t (:foreground "#ff4c4c" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-normal-face
;;                 '((t (:foreground "#f6f3e8" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-prefetch-face
;;                 '((t (:foreground ,my:n:blue :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-resend-face
;;                 '((t (:foreground ,my:h:orange :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-target-face
;;                 '((t (:foreground "#4CFFFF" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-temp-face
;;                 '((t (:foreground ,my:n:violet :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-summary-unread-face
;;                 '((t (:foreground "#ff4c4c" :bold nil :italic nil ))))
;; (my:wl-set-face 'wl-highlight-thread-indent-face
;;                 '((t (:underline t :bold nil :italic 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 を挿入するようにしている

(leaf c-sig
  :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)))
  )

_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)))
(leaf-keys ((:wl-summary-mode-map
             ("C-c : d" . my:epa-wl-decrypt-message)
             ("C-c : v" . my:epa-wl-verify-message))
            (:wl-draft-mode-map
             ("C-c : s" . epa-mail-sign)
             ("C-c : e" . epa-mail-encrypt)))
           )

_検索

notmuchを使う.

(leaf elmo-search
  :config
  (elmo-search-register-engine 'notmuch-custom 'local-file
                               :prog "notmuch-query-custom"
                               :args '(elmo-search-split-pattern-list)
                               :charset 'utf-8)
  (setq elmo-search-default-engine 'notmuch-custom))
(leaf wl-qs
  :config
  (setq wl-quicksearch-folder "[]"
        )
  )
(leaf-keys ((:wl-summary-mode-map
             ("v" . wl-quicksearch-goto-search-folder-wrapper))
            (:wl-folder-mode-map
             ("v" . wl-quicksearch-goto-search-folder-wrapper)))
           )

実際の呼び出しはスレッドを全部取得したいので以下を呼び出している

#!/bin/sh
if [ ! x"$*" = x"" ] ; then
    res=$(notmuch search --output=threads "$*")
fi
if [ ! x"$res" = x"" ] ; then
    echo $res | xargs notmuch search --sort=oldest-first --output=files
fi

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

(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

(leaf mhc
  :if (file-directory-p (concat (getenv "HOME") "/.config/mhc"))
  :ensure t
  :commands (mhc-import)
  :config
  (setq mhc-calendar-day-strings ["日" "月" "火" "水" "木" "金" "土"]
        mhc-calendar-header-function 'mhc-calendar-make-header-ja
        mhc-calendar-language 'japanese)
  )

_カレンダー: japanese-holidays

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

(leaf japanese-holidays
  :ensure t
  :require t
  :hook ((calendar-today-visible-hook   . japanese-holiday-mark-weekend)
         (calendar-today-invisible-hook . japanese-holiday-mark-weekend)
         (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-mode

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

_基本設定: org

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

(leaf org
  :delight (org-mode (all-the-icons-icon-for-mode 'org-mode))
  :bind (("C-x n s" . org-narrow-to-subtree)
         ("C-x n w" . widen))
  :init
  (with-eval-after-load "org"
    )
  :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-file-apps-defaults '((remote . emacs)  ;; xdg-open 任せ
                                 (system . "xdg-open %s")
                                 (t      . "xdg-open %s"))
        org-file-apps-defaults-gnu '((remote . emacs)  ;; xdg-open 任せ
                                     (system . "xdg-open %s")
                                     (t      . "xdg-open %s"))
        ;; 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)
    (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

使いこなせてないのだけれど.

(leaf org-id
  :config
  (setq org-id-locations-file (concat my:d:share "org-id-locations"))
  )

_Babel

(leaf org-src
  :diminish (org-src-mode (format " %s" (all-the-icons-octicon "code")))
  :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
        )
  )

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

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

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

(leaf org-agenda
  :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-Univ
    '((t (:foreground "#7FFF7F")))
    "Agenda 表示中, Univ.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"
             "Univ.org"
             "DebianJP.org"
             "twitter.org"
             "journal.org"
             "Wunderlist.org"
             "redmine_GFD.org"
             "redmine_FluidSoc.org"
             ))
    (add-to-list 'org-agenda-files (concat my:d:org file)))
  (add-to-list 'org-agenda-files (locate-user-emacs-file "README.org"))
  ;; 表示のカスタマイズ
  (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 "Univ:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face my:org-agenda-calendar-Univ)))
                (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)))
                (goto-char (point-min))
                (while (re-search-forward "休日:" nil t)
                  (add-text-properties (match-beginning 0) (point-at-eol)
                                       '(face org-agenda-date-weekend)))
                )))
  )

_Org-journal: 日記

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

(leaf org-journal
  :if (and (file-directory-p my:d:org)
           (>= emacs-major-version 25))
  :ensure t
  ;; :bind (("C-c C-j" . browse-url-at-point)
  ;; (:org-journal-mode-map
  ;;        ("C-c C-j" . browse-url-at-point)))
  :advice (:before org-journal-new-entry
                   my:org-journal-add-date-entry)
  :config
  (eval-and-compile 'browse-url)
  (with-eval-after-load 'org-journal
    (global-set-key (kbd "C-c C-j") 'browse-url-at-point))
  (add-hook 'org-journal-mode-hook (lambda ()
                                     (setq truncate-lines t)))
  (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)))
        ))
    )
  (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
        )
  )
;; 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 を追加したぐらい. notmuch のインデックスの方が良いかもしれない, と最近思っている.

(leaf ol-wl
 :if (and (or (my:dpkg-status "wl-beta")
              (my:dpkg-status "wl"))
          (file-directory-p my:d:org))
 :el-get (ol-wl
          :url "https://code.orgmode.org/bzg/org-mode/raw/master/contrib/lisp/ol-wl.el"
          )
 )
(leaf org-capture
  :if (file-directory-p my:d:org)
  :bind (("C-x m" . org-capture))
  :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 my:d:org "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
           )
          )
        )
  )

_OrgとGoogle カレンダーの連携: org-gcal

request token 等の置き場所の変更 実際の情報等は password-store を使って設定しておく.

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

ついでに agenda 表示の際の色付けを設定.

(leaf org-gcal
  :if (and my:d:password-store
           (file-directory-p my:d:org))
  :commands (org-gcal-fetch org-gcal-sync)
  :ensure t
  :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)
        alert-log-messages t
        alert-default-style 'log
        org-gcal-down-days   90  ;; 過去 3 month
        org-gcal-up-days    180  ;; 未来 6 month
        org-gcal-auto-archive nil)
  (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

(leaf *orgmine
  :if  (and my:d:password-store
            (file-directory-p my:d:org))
  :init
  (setq enable-local-variables :safe)
  (leaf elmine :ensure t)
  (add-hook 'org-mode-hook
            (lambda ()
              (if (assoc "om_server" org-file-properties) (orgmine-mode))))
  (leaf orgmine
    :commands (orgmine-mode)
    :el-get (orgmine
             :type github
             :pkgname "kametoku/orgmine")
    :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"))
    )
  )

_Outline Magic

どんどん増えそう.

(leaf outline
  :init
  (leaf outline-magic
    :ensure t
    :bind ((:outline-minor-mode-map
            ("C-c TAB" . outline-cycle)))
    :hook ((LaTeX-mode-hook . my:add-outline-headings)
           (LaTeX-mode-hook . outline-minor-mode))
    :init
    (defun my:add-outline-headings()
      "Custom: Add promotion headings"
      (setq outline-promotion-headings '("\\chapter"
                                         "\\section"
                                         "\\subsection"
                                         "\\subsubsection"
                                         "\\paragraph"
                                         "\\subparagraph")))
    )
  )

_VCS

_git{attributes,config,ignore}-mode, git-commit

(leaf *git
  :if (and (>= emacs-major-version 25)
           (executable-find "git"))
  :init
  (leaf git-commit :ensure t)
  (leaf gitattributes-mode :ensure t)
  (leaf gitconfig-mode :ensure t)
  (leaf gitignore-mode :ensure t)
  )

_magit:

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

(leaf magit
  :if (executable-find "git")
  :bind (("C-x g" . magit-status))
  :ensure t
  :config
  ;; magit-completing-read-function 'magit-ido-completing-read
  (setq magit-refs-show-commit-count 'all
        magit-log-buffer-file-locked t
        magit-revision-show-gravatars nil
        )
  )

_Git Gutter+

飽きたら止めるかもしれないけれど.

(leaf git-gutter+
  :if (and (executable-find "git")
           (>= emacs-major-version 25))
  :ensure t
  :bind ("C-x G" . global-git-gutter+-mode)
  )

_ghq

(leaf ivy-ghq
  :if (executable-find "ghq")
  :el-get (ivy-ghq
           :type github
           :pkgname "analyticd/ivy-ghq")
  :bind (("C-x f" . ivy-ghq-open))
  :config
  (setq ivy-ghq-short-list t)
  )

_Project 管理

リポジトリの移動には ghq を使っているけれど.

(leaf projectile
  :if (executable-find "ghq")
  :diminish (projectile-mode
             (format " %s" (all-the-icons-octicon "repo")))
  :hook (after-init-hook . projectile-mode)
  :ensure t
  :bind ((:projectile-mode-map
          ("C-c p" . projectile-command-map)))
  :config
  (setq projectile-known-projects-file
        (expand-file-name "projectile-bookmarks.eld" my:d:tmp)
        ;; projectile-project-search-path '("~/Sources"
        ;;                                  "~/Documents")
        projectile-cache-file (expand-file-name "projectile.cache" my:d:tmp)
        projectile-enable-caching t
        projectile-file-exists-remote-cache-expire (* 10 60)
        projectile-completion-system 'ivy
        projectile-dynamic-mode-line nil
        projectile-mode-line-prefix (format " %s" (all-the-icons-octicon "repo"))
        )
  )

_関数定義を辿る: dump-jump

あまり上手く使えていない

(leaf dumb-jump
  :if (executable-find "rg")
  :ensure t
  :disabled t
  :bind (("M-g o" . dumb-jump-go-other-window)
         ("M-g j" . dumb-jump-go)
         ("M-g i" . dumb-jump-go-prompt)
         ("M-g x" . dumb-jump-go-prefer-external)
         ("M-g z" . dumb-jump-go-prefer-external-other-window))
  :after ivy
  :config
  (setq dumb-jump-selector 'ivy
        dumb-jump-force-searcher 'rg
        )
)

_言語毎の補完: company-mode

まだうまく使いこなせていない.

を有効にしてみたが,これで良いのかしら…?

(leaf company
  :ensure t
  :diminish (company-mode
             (format " %s" (all-the-icons-octicon "light-bulb")))
  :bind ((:company-active-map
          ("C-n"   . company-select-next)
          ("C-p"   . company-select-previous)
          ("<tab>" . company-complete-common-or-cycle))
         (:company-search-map
          ("C-p" . company-select-previous)
          ("C-n" . company-select-next)))
  :hook (after-init-hook . global-company-mode)
  :init
  (defun my:edit-category-table-for-company-dabbrev (&optional table)
    "日本語をdabbrevから外す"
    (define-category ?s "word constituents for company-dabbrev" table)
    (let ((i 0))
      (while (< i 128)
        (if (equal ?w (char-syntax i))
            (modify-category-entry i ?s table)
          (modify-category-entry i ?s table t))
        (setq i (1+ i)))))
  :config
  ;; (global-set-key (kbd "<tab>") 'company-indent-or-complete-common)
  (setq company-idle-delay 0
        company-minimum-prefix-length 4
        company-selection-wrap-around t)
  (with-eval-after-load 'company
    (my:edit-category-table-for-company-dabbrev)
    ;; (add-hook 'TeX-mode-hook 'edit-category-table-for-company-dabbrev)
    (setq company-dabbrev-char-regexp "\\cs")
    )
  )

_言語毎のon-the-fly check: flycheck

わりと決め打ち多くて,flymakeの方が楽かもしれない,とか思ったり.

(leaf flycheck
  :ensure t
  )

_LSP

(leaf lsp-mode
  :ensure t
  :hook ((f90-mode     . lsp)
         (fortran-mode . lsp)
         )
  :init
  (leaf lsp-ui
    :ensure t
    :commands lsp-ui-mode
    :hook (lsp-mode . lsp-ui-mode)
    :config
    (setq lsp-ui-flycheck-enable nil) ;; ???
    )
  (leaf company-lsp
    :ensure t
    :commands company-lsp
    )
  :config
  (setq lsp-prefer-flymake nil  ;; ???
        lsp-auto-guess-root t
        )
  )

_TeX: AUCTeX

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

と言った所. Latexmkの設定にはauctex-latexmkを利用する.

(leaf tex-jp
  :if (and (executable-find "uplatex")
           (my:dpkg-status "auctex"))
  :mode ("\\.\\(tex\\|sty\\)\\'" . japanese-latex-mode)
  :init
  (leaf auctex-latexmk
    :el-get (auctex-latexmk
             :type github
             :pkgname "tom-tan/auctex-latexmk")
    :hook (LaTeX-mode-hook . auctex-latexmk-setup)
    :config
    (setq auctex-latexmk-inherit-TeX-PDF-mode nil
          TeX-command-default "LaTeXMk"
          japanese-LaTeX-command-default "LaTeX"
          )
    )
  (leaf reftex
    :hook (LaTeX-mode-hook . reftex-mode)
    :config
    (setq reftex-plug-into-AUCTeX t
          reftex-cite-prompt-optional-args t)
    )
  :hook ((LaTeX-mode-hook . TeX-source-correlate-mode)
         (LaTeX-mode-hook . TeX-PDF-mode))
  :config
  (dolist (command '("pTeX" "pLaTeX" "jTeX" "jLaTeX" "jBibTeX" "Mendex"
                     "upMendex" "pBibTeX" "BibTeX" "Biber" "Ps2pdf" ))
    (delq (assoc command TeX-command-list) TeX-command-list))
  (if (executable-find "atril")
      (add-hook 'LaTeX-mode-hook
                (function (lambda ()
                            (add-to-list 'TeX-command-list
                                         '("Atril"
                                        ;"synctex view -i \"%n:0:%b\" -o %s.pdf -x \"atril -i %%{page+1} %%{output}\""
                                           "TeX-atril-sync-view"
                                           TeX-run-discard-or-function t t :help "Forward search with Atril"))
                            ))))
  (setq japanese-TeX-engine-default 'ptex
        japanese-LaTeX-default-style "bxjsarticle"
        TeX-command-output-list '(("LaTeXMk" ("pdf")))
        TeX-engine 'ptex
        TeX-PDF-mode t
        TeX-source-correlate-method 'synctex
        TeX-source-correlate-start-server t
        TeX-source-correlate-mode t
        TeX-view-program-selection '((output-dvi "xdvi")
                                     (output-pdf "Atril")
                                     ;; (output-pdf "Evince")
                                     (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-script-display nil
        font-latex-fontify-sectioning 1.0
        )
  )

~/.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";

_Autoconf

いれてみたけれど,はてさて.

(leaf sh-autoconf
  :el-get (sh-autoconf
           :type http
           :url "https://download.tuxfamily.org/user42/sh-autoconf.el")
  :mode (("/configure\\.\\(ac\\|in\\)\\'"    . sh-mode)
         ("/ac\\(include\\|local\\)\\.m4\\'" . sh-mode))
  )

_Markdown

markdown自体はあまり好きじゃないんだけれど, 必要に迫られて書く事が増えてきたので設定しておく.

(leaf markdown-mode
  :if (executable-find "pandoc")
  :mode ("\\.\\(md\\|markdown\\|mkd\\)\\'" . gfm-mode)
  :preface
  (defun my:disable-electric-indent-local-mode ()
    (electric-indent-local-mode -1))
  :hook ((markdown-mode-hook . my:disable-electric-indent-local-mode)
         (gfm-mode-hook      . my:disable-electric-indent-local-mode)
         )
  :config
  (setq markdown-command
        "pandoc --from markdown_github -t html5 --mathjax --highlight-style pygments"
        )
  )

_SCSS

ちょいちょい弄る機会が増えてきたので導入.

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

_その他のモード設定

読み込むだけの mode の設定. 設定が増えたら別途まとめる。

(leaf *misc-mode
  :init
  (leaf yaml-mode
    :ensure t
    :mode "\\(\.yml\\|\.yaml\\)"
    )
  (leaf generic-x)
  (leaf textile-mode :ensure t)
  )

_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

(leaf moinmoin-mode
  :el-get (moinmoin-mode
           :type github
           :pkgname "uwabami/moinmoin-mode")
  )

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

_moomin

元々は moomin = emacs-request + helm + moinmoin-mode という奴. folk して ido-vertical-mode を support する様に 多少弄った版を使う。 uwabami/moomin-el: Edit MoinMoin with Emacs …とはいえ,結局 ido 使わなくなったので,今後はどうするのか決めていなかったり.

(leaf moomin
  :if (file-directory-p my:d:password-store)
  :el-get (moomin
           :type github
           :pkgname "uwabami/moomin-el")
  :bind (("C-x w" . counsel--moomin)
         (: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"))
  )

_日記: tDiary [0/1]

(leaf tdiary-mode
  :if (and (file-directory-p my:d:password-store)
           (file-directory-p (concat (getenv "HOME") "/Nextcloud/tdiary")))
  :commands tdiary-mode tdiary-replace tdiary-append
  :el-get (tdiary-mode
           :type github
           :pkgname "uwabami/tdiary-mode")
  :commands (tdiary-new tdiary-replace tdiary-append)
  :config
  (setq tdiary-text-directory (concat (getenv "HOME") "/Nextcloud/tdiary/")
        tdiary-diary-list '(("log" "https://uwabami.junkhub.org/log/"))
        tdiary-style-mode 'org-mode
        tdiary-text-suffix ".org"
        ;; tdiary-text-save-p t
        )
  (load (expand-file-name "tdiary-mode.gpg" my:d:password-store))
  (tdiary-passwd-file-load)
  )

_Tree: neotree

あまり使っていないけれども.

(leaf neotree
  :ensure t
  :after all-the-icons-in-terminal
  :advice (:override neo-buffer--insert-fold-symbol
                     my:neo-buffer--insert-fold-symbol)
  :commands neotree-toggle
  :bind (("<f1>"    . neotree-toggle)
         (:neotree-mode-map
          ("a"       . neotree-hidden-file-toggle)
          ("<left>"  . neotree-select-up-node)
          ("<right>" . neotree-change-root)
          ("RET"     . my:neotree-enter-hide)))
  :init
  (defun my:neo-open-file-hide (full-path &optional arg)
    "Open file and hiding neotree. The description of FULL-PATH & ARG is in `neotree-enter'."
    (neo-global--select-mru-window arg)
    (find-file full-path)
    (neotree-hide))
  (defun my:neotree-enter-hide (&optional arg)
    "Neo-open-file-hide if file, Neo-open-dir if dir. The description of ARG is in `neo-buffer--execute'."
    (interactive "P")
    (neo-buffer--execute arg 'my:neo-open-file-hide 'neo-open-dir))
  :config
  ;; force icon theme
  (defun my:neo-buffer--insert-fold-symbol (name &optional node-name)
    "Write icon by NAME, the icon style affected by neo-theme."
    (let ((n-insert-image (lambda (n)
                            (insert-image (neo-buffer--get-icon n))))
          (n-insert-symbol (lambda (n)
                             (neo-buffer--insert-with-face
                              n 'neo-expand-btn-face))))
      (setq-local tab-width 1)
      (or (and (equal name 'open)  (insert (all-the-icons-icon-for-dir (directory-file-name node-name) "down")))
          (and (equal name 'close) (insert (all-the-icons-icon-for-dir (directory-file-name node-name) "right")))
          (and (equal name 'leaf)  (insert (format "\t%s\t" (all-the-icons-icon-for-file node-name)))))
      ))
  )

_テーマ, フォント, モードライン, などなど

_xterm-color

色を端末と揃える。

(leaf xterm-color
  :disabled t
  :ensure t
  :config
  (setq xterm-color-names
        ["#020202"    ; black
         "#FF4C4C"    ; red
         "#4Cff4C"    ; green
         "#FFFF4C"    ; yellow
         "#4C4CFF"    ; blue
         "#FF4CFF"    ; magenta
         "#4CFFFF"    ; cyan
         "#AAAAAA"]   ; white
        xterm-color-names-bright
        ["#4C4C4C"    ; black
         "#FF7F7F"    ; red
         "#7FFF7F"    ; green
         "#FFFF7F"    ; yellow
         "#7F7FFF"    ; blue
         "#FF7FFF"    ; magenta
         "#7FFFFF"    ; cyan
         "#FFFFFF"]   ; white
        xterm-color-use-bold-for-bright nil
        )
  )

_フォント

(defun my:load-window-config ()
  "load window-system specific settings"
  (interactive)
  (when window-system
    (progn
      (set-frame-parameter nil 'alpha 95)
      (set-face-attribute 'default nil
                          :family "FSMRMP"
                          :height 200)
      (set-face-attribute 'fixed-pitch nil
                          :family "FSMRMP"
                          :height 200)
      (set-face-attribute 'variable-pitch nil
                          :family "FSMRMP"
                          :height 200)
      (setq use-default-font-for-symbols nil)
      (set-fontset-font nil
                        '(#xE0A0 . #xEEE0)
                        (font-spec :family "FSMRMP" :height 180))
      (toggle-frame-maximized)
      )))
(setq frame-background-mode (frame-parameter nil 'background-mode))
(when (window-system)
  (my:load-window-config))

_Major, Minor モードの表示のカスタマイズ: diminish, delight

基本個々のモードの設定でカスタマイズしているけれども.

(leaf *modeline-string
  ;; ここでやるより,modeline の設定時に一括で変換した方が良い気もしてきた.
  :delight ((lisp-interaction-mode
             (all-the-icons-icon-for-mode 'lisp-interaction-mode))
            (emacs-lisp-mode
             (all-the-icons-icon-for-mode 'emacs-lisp-mode))
            (text-mode
             (all-the-icons-icon-for-mode 'text-mode))
            )
  )

_doom-modeline

細かい所が気になるので,色々弄ってます.

他にも弄りたい所はあるけれど.

(leaf *doom-modeline-settings
  :diminish (;; minor-mode settings
             (isearch-mode (format " %s" (all-the-icons-faicon "search")))
             )
  :init
  (leaf doom-modeline
    :ensure t
    :hook (after-init-hook . doom-modeline-mode)
    :after all-the-icons-in-terminal
    :preface
    (defun my:doom-modeline--set-char-widths (alist)
      "Do nothing!")
    :advice (:override doom-modeline--set-char-widths
                       my:doom-modeline--set-char-widths)
    :init
    ;; ddskk そのものに modeline を更新する関数があるので無効化する
    (defun my:disable-skk-setup-modeline ()
      "skk-setup-modeline による modeline の更新を無効化"
      (setq skk-indicator-alist (skk-make-indicator-alist))
      (force-mode-line-update t))
    ;;
    (advice-add 'skk-setup-modeline :override 'my:disable-skk-setup-modeline)
    :config
    (setq doom-modeline-icons-alist
          '(;; macro
            ("fiber_manual_record"    . "\xe3cb")
            ("triangle-right"         . "\xe04c")
            ;; multiple-cursors
            ("i-cursor"               . "\xe2f7")
            ;; vcs
            ("git-compare"            . "\xe081")
            ("git-merge"              . "\xe01b")
            ("arrow-down"             . "\xe035")
            ("alert"                  . "\xe023")
            ("git-branch"             . "\xe01a")
            ;; checker: flycheck/flymake
            ("do_not_disturb_alt"     . "\xe5e5")
            ("check"                  . "\xe5ce")
            ("access_time"            . "\xe439")
            ("sim_card_alert"         . "\xe5f6")
            ("pause"                  . "\xe3a0")
            ("priority_high"          . "\xe617")
            ;; Persp
            ("aspect_ratio"           . "\xe64f")
            ;; LSP
            ("rocket"                 . "\xe029")
            ;; github
            ("github"                 . "\xe173")
            ;; debug
            ("bug"                    . "\xe245")
            ;; mu4e
            ("email"                  . "\xe3ea")
            ;; ("mail"                . "\xe158")
            ;; irc
            ("message"                . "\xe3f1")
            ;; Battery
            ("battery-charging"       . "\xebe4")
            ("battery-full"           . "\xe2f1")
            ("battery-three-quarters" . "\xe2f2")
            ("battery-half"           . "\xe2f3")
            ("battery-quarter"        . "\xe2f4")
            ("battery-empty"          . "\xe2f5")
            )
          )
    (setq doom-modeline-height 1
          doom-modeline-bar-width 0
          doom-modeline-buffer-file-name-style 'buffer-name
          doom-modeline-icon t
          doom-modeline-major-mode-icon t
          doom-modeline-major-mode-color-icon t
          doom-modeline-buffer-state-icon nil
          doom-modeline-buffer-modification-icon nil
          doom-modeline-minor-modes t
          doom-modeline-enable-word-count t
          doom-modeline-buffer-encoding t
          doom-modeline-indent-info nil
          doom-modeline-checker-simple-format t
          doom-modeline-vcs-max-length 12
          doom-modeline-persp-name t
          doom-modeline-persp-name-icon t
          doom-modeline-lsp nil
          doom-modeline-github nil
          doom-modeline-github-interval (* 30 60)
          doom-modeline-mu4e nil
          doom-modeline-irc nil
          doom-modeline-irc-stylize 'identity
          )
    ;;
    (eval-when-compile (require 'doom-modeline-core))
    (doom-modeline-def-segment input-method-skk
      "The current ddskk status."
      (concat
       (doom-modeline-spc)
       (propertize
        (cond
         ((not (boundp 'skk-modeline-input-mode))
          "[--]")
         (skk-modeline-input-mode
          (substring skk-modeline-input-mode 2 -1))
         (t "[--]")
         )
        )))
    (doom-modeline-def-segment my:buffer-encoding
      "Displays the encoding and eol style of the buffer."
      (when doom-modeline-buffer-encoding
        (propertize
         (concat
          (let ((sys (coding-system-plist buffer-file-coding-system) ))
            (cond ((memq (plist-get sys :category)
                         '(coding-category-undecided coding-category-utf-8))
                   " U")
                  ((memq (plist-get sys :name)
                         '(coding-category-undecided japanese-iso-8bit))
                   " E")
                  ((memq (plist-get sys :name)
                         '(coding-category-undecided iso-2022-jp))
                   " J")
                  ((memq (plist-get sys :name)
                         '(coding-category-undecided japanese-shift-jis))
                   " S")
                  (t " =")))
          (pcase (coding-system-eol-type buffer-file-coding-system)
            (0 "U")
            (1 "D")
            (2 "A")))
         'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive)
         'help-echo 'mode-line-mule-info-help-echo
         'mouse-face '(:box 0)
         'local-map mode-line-coding-system-map)))
    ;;
    (doom-modeline-def-segment buffer-position
      "The buffer position information."
      (let ((active (doom-modeline--active))
            (lc '(line-number-mode
                  (column-number-mode
                   (doom-modeline-column-zero-based " %l:%c" " %l:%C")
                   " %l")
                  (column-number-mode (doom-modeline-column-zero-based " :%c" " :%C")))))
        (propertize
         (concat (doom-modeline-spc)
                 (format-mode-line lc)
                 (format-mode-line '("" doom-modeline-percent-position "%%")))
         'face (if (doom-modeline--active) 'mode-line 'mode-line-inactive)
         'help-echo "Buffer position\n\
mouse-1: Display Line and Column Mode Menu"
         'mouse-face '(:box 0)
         'local-map mode-line-column-line-number-mode-map)))
    ;;
    (defun my:doom-modeline-update-buffer-file-icon (&rest _)
      "Update file icon in mode-line, just display major-mode icon. not filename."
      (setq doom-modeline--buffer-file-icon
            (when (and doom-modeline-icon doom-modeline-major-mode-icon)
              (let* ((icon (all-the-icons-icon-for-mode major-mode)))
                (if (symbolp icon)
                    (setq icon (doom-modeline-icon-faicon
                                "file-o"
                                :face 'all-the-icons-dsilver)))
                (unless (symbolp icon)
                  (propertize icon
                              'help-echo (format "Major-mode: %s" (format-mode-line mode-name))))))))
    (advice-add 'doom-modeline-update-buffer-file-icon
                :override 'my:doom-modeline-update-buffer-file-icon)
    ;;
    (defvar doom-modeline--buffer-file-state-icon nil)
    (defun my:doom-modeline-update-buffer-file-state-icon (&rest _)
      "Update the buffer or file state in mode-line."
      (setq doom-modeline--buffer-file-state-icon
            (ignore-errors
              (cond (buffer-read-only
                     (doom-modeline-buffer-file-state-icon
                      "lock"
                      (all-the-icons-material "lock")
                      'doom-modeline-warning))
                    ((and buffer-file-name (buffer-modified-p)
                          doom-modeline-buffer-modification-icon)
                     (doom-modeline-buffer-file-state-icon
                      "save"
                      (all-the-icons-material "save")
                      'doom-modeline-buffer-modified))
                    ((and buffer-file-name
                          (not (file-exists-p buffer-file-name)))
                     (doom-modeline-buffer-file-state-icon
                      "edit"
                      (all-the-icons-faicon "edit")
                      'doom-modeline-urgent))
                    ((or (buffer-narrowed-p)
                         (and (bound-and-true-p fancy-narrow-mode)
                              (fancy-narrow-active-p)))
                     (doom-modeline-buffer-file-state-icon
                      "vertical_align_center"
                      (all-the-icons-material "vertical_align_center")
                      'doom-modeline-warning))
                    (t
                     (doom-modeline-buffer-file-state-icon
                      "--"
                      "--"
                      (if (doom-modeline--active) 'mode-line 'mode-line-inactive)))
                    ))))
    (advice-add 'doom-modeline-update-buffer-file-state-icon
                :override 'my:doom-modeline-update-buffer-file-state-icon)
    ;;
    (doom-modeline-def-modeline 'main
      '(;; bar
        input-method-skk
        my:buffer-encoding
        remote-host
        buffer-info
        ;; matches
        ;; parrot
        ;; selection-info
                         )
      '(;; objed-state
        ;; misc-info
        ;; persp-name
        ;; fancy-battery
        ;; irc
        ;; mu4e
        ;; github
        ;; debug
        lsp
        minor-modes
        ;; indent-info
        ;; process
        vcs
        checker
        buffer-position
        " "
        ;; bar
        )
      )
    )
  )

_theme: doom-theme

これまで弄っていた font-lock を doom-theme をベースに移植中: uwabami/emacs-doom-darkpastel

;; (setq frame-background-mode (frame-parameter nil 'background-mode))
(leaf *doom-themes
  :if (>= emacs-major-version 25)
  :init
  (leaf doom-themes :ensure t)
  (leaf emacs-doom-darkpastel
    :el-get (emacs-doom-darkpastel
             :type github
             :pkgname "uwabami/emacs-doom-darkpastel"
             :prepare (add-to-list 'custom-theme-load-path default-directory)
             )
    )
  :config
  (load-theme 'doom-darkpastel t)
  )

_起動時間の出力

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

(add-hook 'emacs-startup-hook
          (lambda ()
            (message "Emacs 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/>.