Last modified: Thu Sep 01 15:15:41 JST 2022

善き魔術師への道(青年編)

これまでの 善き魔術師への道は Emacs 導入から boiled 環境の構築までを紹介してきました. 物語で言えば幼年期から少年まででしょうか. (以下, これまでの記事を少年編と呼びます) ここからは青年編と題して, boild を離れ Emacs を更に使いやすくする為の道のりを書いて行きます. (その他書きかけ)

ここまで

まずは少年編で最後に示した init.el について簡単な説明を.

1. 日本語環境

Mozc, boiled-mozc の設定に関しては少年編で説明しました. ただ以下の部分については私の独自のもので, 一般的ではありません.

;; 日本語変換中に C-o, C-i, C-p が使えるようにしたい. => Mozc 側で対応.
;; 
;; Lisp Interaction mode では \C-j が式の評価に割り当てられている.
;; boild-mozc を使うために \C-: に割当変更.
(define-key lisp-interaction-mode-map "\C-j" nil)
(define-key lisp-interaction-mode-map (kbd "C-:") 'eval-print-last-sexp)

「日本語変換中に C-o, C-i, C-p が使えるようにしたい.」と言うのは, 私の利用していた boiled 環境(Canna + YC)の環境と合わせたいという要求です. 変換領域を拡げたり縮めたりするのに C-o, C-i, ひらがなにするのに C-p を 多用していたので, このキーバインドを使えるようにするのが目標です.

boiled-mozc では文字列を Mozc に渡してからは, キー操作も Mozc に任せて いるようです. このため Google 日本語入力の設定の方で対応することにしました. 詳細は IN02: IME の切り替えをお読みください.

次の「Lisp Interaction mode では \C-j が...」と言うのは, (利用していた boiled 環境に合わせて) C-j を変換キーに割り当てましたが, *scratch* バッファなどのメジャーモード Lisp Interaction mode では C-j が「Lisp 式の評価」コマンドに割り当てられているため使えません. *scratch* バッファ内や init.el の編集中にも C-j を使いたいので, まず lisp-interraction-mode での C-j 割り当てを無くし(= nil への割当), 無くなってしまったコマンド eval-print-last-sexp を別のキー C-: に割り当てています.

これで Lisp モードでも C-j を boiled 変換キーとして利用でき, Lisp 式の評価は C-: で実現できます. 「私は boiled 変換キーはデフォルト推奨の C-o でいいと言う方は 以下で十分です.

[boiled-mozc.el の説明コメントより]
;; To use boiled-mozc.el, just add the following code into your .emacs:

(autoload 'boiled-mozc-rK-conv "boiled-mozc"
  "Romaji to Kana-Kanji conversion" t)
(autoload 'boiled-mozc-rhkR-conv "boiled-mozc"
  "Romaji to Hiragana conversion" t)
(global-set-key "\C-o" 'boiled-mozc-rK-conv)
(global-set-key "\M-o" 'boiled-mozc-rhkR-conv)

2. フレーム設定

ここも少年編で説明したので特に説明は要らないでしょう. フォントだけでなく, ウィンドウの配色や大きさ, メニューバーなどの表示設定を しています. 私は利用していませんが画面左に行番号表示をさせることも可能です. モードラインにデフォルトでカーソル位置の行番号が表示されているので, 慣れればこれで十分です. 余談ですが IN04: 行と列の話で迷うことってありません?

後, Lisp 式の中で t や nil と言う表現がよく出てきます. Lisp では true/false を t/nil で表現します.

3. 詳細設定

こちらも特に説明は要らないと思いますが, バックアップファイルの説明だけ しておきます.

バックアップファイル

Emacs はファイルを変更すると古いファイルをバックアップファイルとして残します. 設定例のようにバックアップファイルを作らないようにできますし, デフォルトの 1 世代バックアップだけでなく, 何世代ものバックアップを 残すこともできます. 更に, 初代は常に残しておくなどの設定も可能です.

プログラマーズ雑記帳 さんが OUT08: Emacs で自動作成されるファイルの設定 で詳しく説明されています.

追加機能(従来機能の実現)

少年編の冒頭で書いた通り, Emacs 導入は今まで使っていた Meadow の置き換えが 目的でした. 置き換えというからには少なくとも「Meadow で使っていた機能は すべて使えるようにしたい」です.

4. タイムスタンプ

Emacs にはタイムスタンプと言う便利な機能があります. デフォルトでは 以下のキーワードを先頭から 8 ライン目までに見つけると, ファイルセーブ時に '(任意の文字列)' の部分を '日付/時刻/ユーザ名' などのタイムスタンプ文字列に変換してくれます.

Time-stamp: <(任意の文字列)>
Time-stamp: "(任意の文字列)"

詳細は Emacs Wiki の OUT09: Time Stamp が詳しいです.

私の場合, Meadow の時代から キーワードは 'last modified: ' で日付フォーマットも英語のみに していました. 更にかなり後ろのラインにキーワードを置くこともあります. 古い資産からの継続を考えると, 今更変更できません. と言う訳で無理やり従来フォーマットに合わせています. 新たに使われる方はデフォルトのままで十分だと思います. その場合は もちろん以下の記述は不要です.

;;--------------------
;; タイムスタンプ挿入
;;--------------------
;; >> https://www.emacswiki.org/emacs/TimeStamp
;; 今までの形式に合わせる.
;; (add-hook 'before-save-hook 'time-stamp)
;; (defun time-stamp-lc-3a ()
;;   "Return a day of the week"
;;   (let ((aw (string-to-number (format-time-string "%w" (current-time)))))
;;     (cond
;;      ((= aw 0) "Sun") ((= aw 1) "Mon") ((= aw 2) "Tue") ((= aw 3) "Wed")
;;      ((= aw 4) "Thu") ((= aw 5) "Fri") ((= aw 6) "Sat"))))
;; (defun time-stamp-lc-3b ()
;;   "Return a month"
;;   (let ((am (string-to-number (format-time-string "%m" (current-time)))))
;;     (cond
;;      ((= am 01) "Jan") ((= am 02) "Feb") ((= am 03) "Mar")
;;      ((= am 04) "Apr") ((= am 05) "May") ((= am 06) "Jun")
;;      ((= am 07) "Jul") ((= am 08) "Aug") ((= am 09) "Sep")
;;      ((= am 10) "Oct") ((= am 11) "Nov") ((= am 12) "Dec"))))
;; (setq time-stamp-format (concat (time-stamp-lc-3a) " " (time-stamp-lc-3b)
;;                                 " %02d %02H:%02M:%02S %Z %:y"))
;; シンプルな方法
;; >> http://www.cozmixng.org/~kou/emacs/dot_emacs
(add-hook 'before-save-hook 'time-stamp-with-locale-c)
(defun time-stamp-with-locale-c ()
  (let ((system-time-locale "C"))
    (time-stamp)
    nil))
(setq time-stamp-format "%3a %3b %02d %02H:%02M:%02S %Z %:y")
(setq time-stamp-start "[Ll]ast modified:[ \t]")
(setq time-stamp-end "$")
(setq time-stamp-line-limit 100)

5. コピー & ペースト

コピー & ペーストと言っても C-k, C-y, M-w などキーボードを使った ものではありません. マウスを使ったコピーアンドペーストで 「Windows のアプリとの文字列のやり取り」です.

Emacs 自体は殆どの操作がキーボードででき, キーボードから手を離すことなく 作業を完結できると言う特徴があります. ここでマウス操作を持ち出すのは 邪道だと言われそうですが, Windows の他のアプリと行き来するためには, (私には)マウス操作欠かせません.

で, マウスで(Emacs の Yank バッファ及び Windows のクリップボードに) コピーできるようにする記述です. stack overflow の OUT10: How to combine... からの情報です. (マウスの左クリックをしながらコピー, 真ん中クリックでペースト になっていましたが, 真ん中クリックは使いづらいので右クリックに変更しています.)

;;--------------
;; Copy & Paste
;;--------------
;; >> https://www.emacswiki.org/emacs/CopyAndPaste
;(global-set-key (kbd "<mouse-2>") 'clipboard-yank)
;; マウス操作でクリップボードへ
;; >> https://stackoverflow.com/questions/13036155/
(setq select-active-regions nil)
(setq mouse-drag-copy-region t)
;(global-set-key [mouse-2] 'mouse-yank-at-click) ; 中クリック
(global-set-key [mouse-3] 'mouse-yank-at-click) ; 右クリック

6. Windows との連携強化

Windows から Meadow を使うときに利用していた機能に

の 2 つがあります. 例えば単純に runemacs.exe を txt ファイルに関連付けすると, txt ファイルを開くたびに, 別々の Emacs が立ち上がってしまいます. まるっきり使い物にならないというわけではありませんが, カットアンドペーストで用いる Yank バッファが共用できないなど, Emacs の良さが活かせません.

Meadow では gnuserv と呼ばれるサーバー化手法を使いこれを解決していました. 最初に立ち上げた Emacs をサーバとして, それ以降に立ち上げたものは, その子ウィンドウとして開きます. これによりウィンドウ間でのデータ共有が できます.( Windows との連携強化参照)

当然, 本家 Emacs でもできる筈. で, 探せばありました. OUT11: EmacsMsWindowsIntegration, これを参考に実行します. OUT12: emacsclientw を使うための設定(NTEmacs @ ウィキ), こちらも有用です.

6.0. 下準備

まずは下準備です. init.el の先頭に以下を追加します. ';' で始まる行(コメント行)は入力不要です

;;============
;; サーバ設定
;;============
;(require 'server)
;(unless (server-running-p)
;  (server-start))
;; 以下に置き換え.
(require 'server)
(server-force-delete)
(server-start)

そして環境変数 EMACS_SERVER_FILE に %HOME%\.emacs.d\server\server を 設定します. (サーバとして立ち上げると server ディレクトリの server と言うファイルが作成されます. 終了するとファイルが消されます.)

Windows 環境変数
変数 値(例) コメント
EMACS_SERVER_FILE C:\Users\uranov\.emacs.d\server\server 環境変数を使わずに具体的に書くのが良いようです

6.1. ショートカットの作成

まずはデスクトップへショートカットを設置します. 既に少年編でショートカットを作っているので, これを編集します. ショートカットを右クリックしてプロバティ(R)を選びます. ショートカットタブでリンク先(T)を以下のように設定します.

C:\emacs\bin\emacsclientw.exe -c -n -a C:\emacs\bin\runemacs.exe
[emacs shortcut property2]

6.2. アプリケーションへの関連付け

テキストファイルに emacsclientw を関連付けし, テキストファイルの ダブルクリックで Emacs が開くようにします. emacsclientw をオプション引数付きで立ち上げます. Meadow の場合は環境変数を使っていました. Emacs ではコマンドラインで 設定します. コマンドプロンプトを管理者で立ち上げ, 以下の 3 行を実行します. (コマンドラインからの関連付け方法を初めて知りました. 上述の参考ページでは .txt だけでなく色々なファイルを関連付けています.)

> ftype txtfile=C:\emacs\bin\emacsclientw.exe -na C:\emacs\bin\runemacs.exe "%1"
> assoc .txt=txtfile
> assoc .log=txtfile
(2010/10/15 追記) Windows update 後, txt ファイルへの関連付けが おかしくなってしまった. 毎回「このファイルを開く方法を選んで下さい。」 と聞かれる. その度に GNU Emacs Client を選択する必要がある. 上記 assoc をやり直してもだめ. 結局 [コントロールパネル] → [既定のプログラム] → [既定のプログラムの設定] → [既定のアプリの選択] → [ファイルの種類ごとに既定のアプリを選ぶ] の画面から .txt の関連付けを GNU Emacs Client にする必要があった. 本来 assoc コマンドで設定したらここが書き換えられるはずなのに 何故 assoc が効かないのかは不明. Windows は, 設定にレジストリを多用しつつも, その設定方法, 反映方法が しっかり統一できていないお馬鹿さんなので諦めるしかないが, update の度に問題を起こしたり, 勝手な設定に戻すのは勘弁してほしい.

7. Migemo(日本語インクリメンタル検索)

Migemo は日本語のインクリメンタル検索機能の名称です. 検索文字列にローマ字を入力すると日本語文字列も検索してくれます. それも Emacs 特有のインクリメンタル検索です. 当初(2002 頃)は Ruby 版で動作も遅めでしたが, 途中から C 言語版の C/Migemo が出て速さも実用的になりました. 昔はインストールが大変だったと記憶していますが, 今回は非常に簡単に インストールできました. 関係各位に感謝!!

るびきち さんの OUT13: migemo.el: ローマ字で日本語検索... の説明に従い実行すれば OK です. 一応私の作業を書き留めておきます.

  1. まずは migomo パッケージのインストール. (少年編の 4. Mozc パッケージのインストールを参考にして下さい) ~/.emacs.d/elpa/migemo-20200913.12 フォルダ以下にインストールされます.
  2. 次に, 香り屋 さんのページ DL06: C/Migemo から C/Migemo のバイナリ(64bit 版)をダウンロード.
  3. 入手した ZIP ファイルを適当な場所に展開し, 中身を以下のようにコピー.
  4. 最後に init.el に以下の記述を加えて作業完了.
;;--------
;; Migemo
;;--------
(require 'migemo)
(setq migemo-command "C:/emacs/bin/cmigemo.exe")
(setq migemo-options '("-q" "--emacs"))
;; 辞書ファイルの場所. ホームディレクトリも絶対パスで書き出して下さい.
(setq migemo-dictionary "C:/Users/uranov/.emacs.d/elpa/migemo-20200913.12/utf-8/migemo-dict")
(setq migemo-user-dictionary nil)
(setq migemo-regex-dictionary nil)
(setq migemo-coding-system 'utf-8)
(load-library "migemo")
(migemo-init)

青年から大人へ

これで従来 Meadow で使っていたほとんどの機能を Emacs に持たせることが できました. もう前の世代(Meadow)の背中を見て進む必要はありません. 今まで Meadow + Canna がインストールされていた PC も機会を見て Emacs に変えてゆく予定です.

今後は, 今までに使っていなかった機能を試してみます. 面白い機能が見つかったら 善き魔術師への道(大人編)として紹介するつもりです.

以下, ここまでの私の init.el を書いておきます. (「最初から全部公開しろよ」 と言う話もありますが, パッケージを入れないとエラーで init.el の読み込みが 完了しないので... こんな形にしました. お許しください.)

;; -*- mode: lisp-interaction; syntax: elisp; coding: utf-8 -*-
;; last modified: Wed Oct 07 22:32:50 JST 2020
;;
;; .emacs (http://dreamserver2.dsmynas.com/uranov/)
;;

;;============
;; サーバ設定
;;============
;(require 'server)
;(unless (server-running-p)
;  (server-start))
;; 以下に置き換え.
(require 'server)
(server-force-delete)
(server-start)

;;============
;; 日本語環境
;;============
(set-language-environment "Japanese")
(prefer-coding-system 'utf-8)
(set-file-name-coding-system 'cp932)
(set-keyboard-coding-system 'cp932)
(set-terminal-coding-system 'cp932)
;;------
;; Mozc
;;------
;; >> http://ubiqlog.com/archives/8538
;; >> https://blog.rustle.info/archives/1881
(require 'mozc)
(setq default-input-method "japanese-mozc")
;(global-set-key (kbd "C-o") 'toggle-input-method)
(setq mozc-helper-program-name "C:/emacs/bin/mozc_emacs_helper.exe")
;; Windows の mozc は接続直後 direct モード になるので hiragana モード にする.
(advice-add 'mozc-session-execute-command
            :after (lambda (&rest args)
                     (when (eq (nth 0 args) 'CreateSession)
                       ;; (mozc-session-sendkey '(hiragana)))))
                       (mozc-session-sendkey '(Hankaku/Zenkaku)))))
;;-------------
;; boiled-mozc
;;-------------
(autoload 'boiled-mozc-rK-conv "boiled-mozc"
  "Romaji to Kana-Kanji conversion" t)
(autoload 'boiled-mozc-rhkR-conv "boiled-mozc"
  "Romaji to Hiragana conversion" t)
;;(global-set-key "\C-o" 'boiled-mozc-rK-conv)
;;(global-set-key "\M-o" 'boiled-mozc-rhkR-conv)
;; 次行は (define-key global-map "\C-j" 'boiled-mozc-rK-conv) と等価.
(global-set-key "\C-j" 'boiled-mozc-rK-conv)
(global-set-key "\M-j" 'boiled-mozc-rhkR-conv)
;; 日本語変換中に C-o, C-i, C-p が使えるようにしたい. => Mozc 側で対応.
;; 
;; Lisp Interaction mode では \C-j が式の評価に割り当てられている.
;; boild-mozc を使うために \C-: に割当変更.
(define-key lisp-interaction-mode-map "\C-j" nil)
(define-key lisp-interaction-mode-map (kbd "C-:") 'eval-print-last-sexp)
;;--------
;; Migemo
;;--------
(require 'migemo)
(setq migemo-command "C:/emacs/bin/cmigemo.exe")
;(setq migemo-options '("-q" "--emacs" "-i" "\a"))
(setq migemo-options '("-q" "--emacs"))
;; 辞書ファイルの場所. ホームディレクトリも絶対パスで書き出して下さい.
(setq migemo-dictionary "D:/Users/uranov/.emacs.d/elpa/migemo-20200913.12/utf-8/migemo-dict")
(setq migemo-user-dictionary nil)
(setq migemo-regex-dictionary nil)
;(setq migemo-use-pattern-alist t)
;(setq migemo-use-frequent-pattern-alist t)
;(setq migemo-coding-system 'utf-8-unix)
(setq migemo-coding-system 'utf-8)
;(setq migemo-pattern-alist-length 1000)
(load-library "migemo")
(migemo-init)

;;==============
;; フレーム設定
;;==============
;;------------------
;; 初期フレーム設定
;;------------------
;; フォントセット, サイズ, 行間は気に入ったものを探すしかない.
;; 最後にフレームの高さを調整.
(setq default-frame-alist
      (append (list '(foreground-color . "black")
                    '(background-color . "LemonChiffon")
                    '(background-color . "gray")
                    '(border-color . "black")
                    '(mouse-color . "white")
                    '(cursor-color . "black")
;                   '(font . "MeiryoKe_Gothic-10") ; MeiryoKe - 10pt
;                   '(line-spacing . 1)
                    '(font . "MeiryoKe_Console-10"); MeiryoKe(console) - 10pt
                    '(line-spacing . 2)
;;                  '(font . "MeiryoKe_Console-9") ; MeiryoKe(console) - 9pt
;;                  '(line-spacing . 2)
;                   '(font . "Ricty Diminished-10"); Ricty Diminished - 10pt
;                   '(line-spacing . 1)
                    '(width . 80)
                    '(height . 40)
;                   '(height . 80) ; MeiryoKe_Console-10 で縦 1080 ほぼ一杯
                    '(top . 0)
                    '(left . 100))
              default-frame-alist))
;;------------------------------
;; メニューバー, スクロールバー
;;------------------------------
(tool-bar-mode -1)
(menu-bar-mode -1)
;(scroll-bar-mode -1)
;;--------
;; その他
;;--------
;; スタート画面を表示しない
(setq inhibit-startup-message t)
;;(setq initial-scratch-message "") 
;; 行番号表示
;(global-linum-mode t) ; Emacs 26.0.50 まで
;(global-display-line-numbers-mode) ; それ以降
;; モードラインにカラム番号を追加(デフォルトはライン番号のみ)
;(column-number-mode t)

;;==============
;; キーバインド
;;==============
;; C-z の割当解除.
(global-unset-key "\C-z")
;; C-h バックスペース.
;;(keyboard-translate ?\C-h ?\C-?)

;;==========
;; 詳細設定
;;==========
;;------------------
;; バックアップ不要
;;------------------
(setq make-backup-files nil)
;;------
;; ベル
;;------
;;(setq visible-bell t)
(setq ring-bell-function 'ignore)
;;--------------------
;; タイムスタンプ挿入
;;--------------------
;; >> https://www.emacswiki.org/emacs/TimeStamp
;; (add-hook 'before-save-hook 'time-stamp)
;; (defun time-stamp-lc-3a ()
;;   "Return a day of the week"
;;   (let ((aw (string-to-number (format-time-string "%w" (current-time)))))
;;     (cond
;;      ((= aw 0) "Sun") ((= aw 1) "Mon") ((= aw 2) "Tue") ((= aw 3) "Wed")
;;      ((= aw 4) "Thu") ((= aw 5) "Fri") ((= aw 6) "Sat"))))
;; (defun time-stamp-lc-3b ()
;;   "Return a month"
;;   (let ((am (string-to-number (format-time-string "%m" (current-time)))))
;;     (cond
;;      ((= am 01) "Jan") ((= am 02) "Feb") ((= am 03) "Mar")
;;      ((= am 04) "Apr") ((= am 05) "May") ((= am 06) "Jun")
;;      ((= am 07) "Jul") ((= am 08) "Aug") ((= am 09) "Sep")
;;      ((= am 10) "Oct") ((= am 11) "Nov") ((= am 12) "Dec"))))
;; (setq time-stamp-format (concat (time-stamp-lc-3a) " " (time-stamp-lc-3b)
;;                                 " %02d %02H:%02M:%02S %Z %:y"))
;;
;; >> http://www.cozmixng.org/~kou/emacs/dot_emacs
(add-hook 'before-save-hook 'time-stamp-with-locale-c)
(defun time-stamp-with-locale-c ()
  (let ((system-time-locale "C"))
    (time-stamp)
    nil))
(setq time-stamp-format "%3a %3b %02d %02H:%02M:%02S %Z %:y")
(setq time-stamp-start "[Ll]ast modified:[ \t]")
(setq time-stamp-end "$")
(setq time-stamp-line-limit 100)
;;--------------------------------
;; コピー & ペースト (マウス操作)
;;--------------------------------
;; >> https://www.emacswiki.org/emacs/CopyAndPaste
;(global-set-key (kbd "<mouse-2>") 'clipboard-yank)
;; マウス操作でクリップボードへ
;; >> https://stackoverflow.com/questions/13036155/
(setq select-active-regions nil)
(setq mouse-drag-copy-region t)
;(global-set-key [mouse-2] 'mouse-yank-at-click) ; 中クリック
(global-set-key [mouse-3] 'mouse-yank-at-click) ; 右クリック
;;----------------
;; パッケージ管理
;;----------------
;; >> https://qiita.com/Maizu/items/fee34328f559c7dc59d8
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/"))
(add-to-list 'package-archives '("marmalade" . "https://marmalade-repo.org/packages/"))
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/"))
(package-initialize)

;; EOF

リンク一覧