月の頭に書きましたが,現在,WindowsでのテキストエディタをMeadowからNTEmacsに移行しています.
MeadowのNetinstallで入っていたElScreenが,NTEmacsにはなく,インストールしました.
使っていると,いろいろ不満も出てきたので,Emacs Lispの復習を兼ねて,機能拡張を試みました.
ElScreenのインストール
シェルを開いて,こうすればいいんですかね.
wget ftp://ftp.morishima.net/pub/morishima.net/naoto/ElScreen/elscreen-1.4.6.tar.gz tar xf elscreen-1.4.6.tar.gz cp elscreen-1.4.6/elscreen.el ~/.ntemacs.d/elisp
「~/.ntemacs.d」というのはあまり自然ではありませんが,Meadowと棲み分けるためです.あるマシンには,MeadowなしでNTEmacsを入れる予定で,そういうのでも大丈夫になることを念頭に置いています.もちろん,~/.ntemacs.d/elispというディレクトリは,あらかじめ作っておきます.
~/.emacsに書くのはこんな感じですか.
(add-to-list 'load-path "~/.ntemacs.d/elisp") (when (require 'elscreen nil t) (if window-system (define-key elscreen-map (kbd "C-z") 'iconify-or-deiconify-frame) (define-key elscreen-map (kbd "C-z") 'suspend-emacs)))
しかし,起動すると,エラーが出ました.少し苦労した結果,APEL (A Portable Emacs Library)というのが必要そうです.コマンドは
wget http://kanji.zinbun.kyoto-u.ac.jp/~tomo/lemi/dist/apel/apel-10.8.tar.gz tar xf apel-10.8.tar.gz mv apel-10.8 ~/.ntemacs.d/elisp/apel
とし,~/.emacsは
(add-to-list 'load-path "~/.ntemacs.d/elisp/apel")
を書き加えました.
これで,うまく動きました.
Shiftを押しながらDragで,複数のファイルを別々のスクリーンで開く
C-z C-cでスクリーンを開き,C-z C-nで次のスクリーンに移動.不要なスクリーンはC-z kとするか,上のタブの「[X]」のところをクリック.
…と,しばらくは快適だったのですが,不満が出てきました.ドラッグ&ドロップでファイルを開いたときに,今参照なり編集なりしていたスクリーンで開かれます.
これを,新規にスクリーンを作って開くようにしましょう.複数のファイルをドラッグ&ドロップしたら,別々にスクリーンを作りましょう.キーバインドは,Shiftを押しながらドラッグ&ドロップとしましょう.…
出来上がったコードは,以下のとおりです.
(defun w32-drag-n-drop-elscreen-onefile (event) "Edit the file using ElScreen" (interactive "e") (elscreen-create) (find-file event)) (defun w32-drag-n-drop-elscreen (event) "Edit the files using ElScreen" (interactive "e") (mapcar 'w32-drag-n-drop-elscreen-onefile (car (cdr (cdr event))))) (global-set-key [S-drag-n-drop] 'w32-drag-n-drop-elscreen)
参考にしたのは,(NTEmacsのディレクトリ)/lisp/term/w32-win.elです.この中には,w32-drag-n-drop,w32-drag-n-drop-other-frame*1という関数が定義されています.前者の関数と,
(defun drag-n-drop-trial (event) "Edit the files using ElScreen" (interactive "e") (insert event)) (global-set-key [S-drag-n-drop] 'drag-n-drop-trial)
をM-x eval-regionしたあとで,Shiftを押しながらドラッグ&ドロップをしたときの結果から,(car (cdr (cdr event)))がファイル名のリストになっていることを確認しました.
mapcarは,w32-drag-n-drop-other-frameの定義で知りました.http://www.offshorecad.com.ph/autocad/lesson/autolisp/entry709/も参考にしました.
…と,苦労したところで,ElScreen | Fragments of Realityを読み直すと,ElScreen-dndというのが,同じことをしてくれるようです.elscreen-dnd-0.0.0.tar.gzをダウンロードし,elscreen-dnd.elを見てみたものの,訳の分からないコードのオンパレードです.理解する体力も時間の余裕もなく,心の中でごめんなさいと唱えてファイルを削除しました.
番号を指定してスクリーンを消す
C-x k RETでバッファを消すのと同様に,C-z k RETでスクリーンを消したいと思うようになりました.素の設定では,C-z kでスクリーンが消え,その後のRETは,バッファで改行をしてしまうことになります.
RETの前に数字を入力できるようにしたいものです.デフォルトはカレントのスクリーンです.存在しないスクリーン番号を指定したときには,何も消さないようにします.
あれこれ苦労しながら出来上がったコードは:
(defun elscreen-kill-by-number (arg) "Kill screen" (interactive "sKill screen: ") (if (string= arg "") (elscreen-kill) (let* ((scrnum (elscreen-get-current-screen)) (killnum (string-to-number arg))) (if (eq scrnum killnum) (elscreen-kill) (if (elscreen-goto killnum) (progn (elscreen-kill) (elscreen-goto scrnum))))))) (define-key elscreen-map "k" 'elscreen-kill-by-number)
interactiveに関しては,http://kzk9.net/column/emacs/elisp_interactive.htmlと,自分がこれまでに書き残したEmacs Lispを参考にしました.「"sKill screen: "」の先頭文字のsは任意の文字列をとる(ミニバッファでユーザが入力できる)ことを意味します.ここをnにすると,どうも必ず数値を入力することが要求され,RETのみを押すことができません.
動作確認を終えてほどなく,elscreen-kill-screen-and-buffersの存在に気づきました.現在のスクリーンだけでなくバッファも消去するという関数です.
C-z k RETでスクリーンを消すのと同様に,C-z M-k RETでスクリーンとバッファを消したいと思うようになりました.コードを作り替えます.
(defun elscreen-kill-by-number-and-method (arg method) (if (string= arg "") (eval method) (let* ((scrnum (elscreen-get-current-screen)) (killnum (string-to-number arg))) (if (eq scrnum killnum) (eval method) (if (elscreen-goto killnum) (progn (eval method) (elscreen-goto scrnum))))))) (defun elscreen-kill-by-number (arg) "Kill screen" (interactive "sKill screen: ") (elscreen-kill-by-number-and-method arg (list 'elscreen-kill))) (defun elscreen-kill-screen-and-buffer-by-number (arg) "Kill screen and buffer" (interactive "sKill screen: ") (elscreen-kill-by-number-and-method arg (list 'elscreen-kill-screen-and-buffers))) (define-key elscreen-map "k" 'elscreen-kill-by-number) (define-key elscreen-map "\M-k" 'elscreen-kill-screen-and-buffer-by-number)
期待通りの動作をしてくれます.
「(list 'elscreen-kill)」と「(list 'elscreen-kill-screen-and-buffers)」という書き方は,もっと簡潔な記述に置き換えられそうですが,分かりません.
elscreen-createしてからfind-file
C-x C-fは言わずと知れたfind-fileです.C-x fで,「今日のファイル」を開けるようにしたのは,「今日のファイル」「昨日のファイル」「数日前のファイル」を開く - わさっきのことです.
ファイル名を指定すると,elscreen-createしてからfind-fileするような機能があるといいのですが…これもコードにしました.
(defun find-file-new-screen (filename) "Edit file on new screen" (interactive "fFind file: ") (elscreen-create) (find-file filename)) (global-set-key "\C-xg" 'find-file-new-screen)
C-x gというキーバインドは,たまたま空いていたので割り当てたのですが,これが分かりやすいかどうかは何とも言えません.C-x C-gとすると,C-xが無効になって,何もしないのと同じになるのですが.
*1:Ctrlを押しながらドラッグ&ドロップだと,フレーム(いわゆる別ウィンドウ)を作ってそこにファイルを開きます.これはこれで,使いどころがあるように思います.