いきなり slime が動かなくなった件

原因は不明ながら、slime が急にエラーで動かなくなってしまったので経過をメモ。
(思い出しながら書いているので、あやふやな部分あり)

検索したサイトを見ながら popwin の設定やら ac-slime のインストールやらをしていたら、ある時 M-x slime するとエラーするようになってしまった。
※正確には swank サーバへの接続待ちのままになった。表示通りに M-x slime-abort-connection するとキャンセルされて REPL には入れる。

その状態で (require 'asdf) (require 'alexandria) すると /usr/share/common-lisp/source/cl-asdf/build/asdf-TMP.lisp が FILE OPEN エラーになってデバッガに入ってしまった。
emacs を終了してコンソールから直接 sbcl で実行しても同じエラーになった。

~/.cache/common-lisp/ を削除してみたが直らず。
apt で slime と cl-asdf を再インストールしてもダメ。

以前に作成した以下のファイルを削除したら slime は起動するようになった。

;;;; ~/.config/common-lisp/source-registry.conf
(:source-registry
  (:tree "~/quicklisp/dists/")
  :INHERIT-CONFIGURATION)


require もエラーしなくなった… はず。ただ、相変らず (require 'alexandria) の返り値が nil だったのでダメかと思って作業を継続した。
この時点で最終結果と同じ状態に戻っていたのかもしれない。
(require 'asdf) の返り値が nil だったかは覚えていない。

その後、~/quicklisp/ も削除して slime から (load "/usr/share/cl-quicklisp/quicklisp.lisp") (quicklisp-quickstart:install) で再インストールしてみた。
ここで (ql:quickload 'alexandria) するとインストールが行われ、(alexandria:lastcar '(a b c)) が動作した。
そのまま更に (ql:add-to-init-file) を実行して設定ファイル(sbcl だったので ~/.sbclrc)に quicklisp の自動ロードを設定した。
一旦 emacs を再起動し、require するも返り値は nil のまま。
コンソールから sbcl でやっても同じく nil が返っていたが、何の気なしに alexandria:lastcar をやってみたら動作した。

ふと思い付いて .sbclrc の quicklisp 設定をコメントアウトしてから、コンソールで (require 'alexandria) したらエラーになった。
そのまま (load "~/quicklisp/setup.lisp") したところ alexandria:lastcar が動作した。

quicklisp 設定をコメントアウトしたままの状態で ~/.config/common-lisp/source-registry.conf をエラー前に戻してみた。
そうしたら (require 'alexandria) がエラーせずに nil を返し、alexandria:lastcar も動作するようになった。

元々は .sbclrc の quicklisp 設定はコメントアウトされていたので、結局エラー前と同じ設定に戻ったことになる。
経過から見るとキャッシュを壊していた確率が高いが、問題の原因は特定できず…
とりあえず動作するので、まあいいかと。

最終的にはコンソールでも slime でも以下のように動いている。
(行頭に「?>」があるのがプロンプトと入力内容で、次のプロンプトまでが出力)

?> (require 'asdf)
("ASDF" "asdf" "UIOP" "uiop")

?> (alexandria:lastcar '(a b c))
※以下のエラーが発生した
debugger invoked on a SB-INT:SIMPLE-READER-PACKAGE-ERROR in thread
#:
Package ALEXANDRIA does not exist.

Stream: #

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.

(SB-IMPL::READER-FIND-PACKAGE "ALEXANDRIA" #)

※ 0 でデバッガを終了してトップレベルに戻る

?> (require 'alexandria)
nil

?> (alexandria:lastcar '(a b c))
c

以上。

persp-mode を設定してみた(ついでに helm も)

えー、今回は common lisp のコードを書こうと思ったらキーバインドが気になって、init.el を編集してるうちに elisp パッケージ探しに走ってしまい、気が付いたらリファレンスを見ながら elisp を書いていたという yak shaving の最たるものになってしまいました。
なので、せめて動いたコード片だけでも載せておこうと思います。

以下は persp-mode で新規パースペクティブを作成した時(厳密にはバッファがないパースペクティブに切り替えた時)にバッファを選択して登録する設定です。
毎度おなじみ rubikitch 様のサイトからコピーして、四苦八苦しながら希望する動作になるよう改造(改悪?)しました。
ホント、いつもお世話になってます。密度の濃い情報ありがとうございます。 > rubikitch 様
設定した persp-mode のバージョンは 20161226.2218 です。

;;; persp-mode 設定
(setq persp-add-on-switch-or-display t)
(persp-mode 1)
;;; 新規パースペクティブ作成時に追加するバッファを選択する
(defun persp-register-buffers () ; 関数名変更
  (interactive)
  (dolist (bufname (condition-case _
                       (helm-comp-read
                        "Buffers: "
                        (mapcar 'buffer-name (buffer-list))
                        :must-match t
                        :marked-candidates t)
                     (quit nil)))
    (persp-add-buffer (get-buffer bufname))))
;; ここから追加分
(defun persp-register-buffers-if-empty (mode)
  (interactive)
  (if (null (persp-buffer-list)) ; パースペクティブのバッファが空の時だけ
      (persp-register-buffers))) ; 上のバッファ選択関数を呼ぶ
(add-hook 'persp-activated-functions 'persp-register-buffers-if-empty) ; フック名が変わった?

それから、persp-mode 用の helm アクションも見様見真似で作ってみました。
いちおう動いているようですが、使用は自己責任でお願いします。

(defun helm-persp-add-buffer (buffer-or-name)
  (persp-add-buffer (helm-marked-candidates)))
(defun helm-persp-kill-buffer (buffer-or-name)
  (persp-kill-buffer (helm-marked-candidates)))
(setq helm-type-buffer-actions
      (append helm-type-buffer-actions
              '(("Add buffer(s) to perspective" . helm-persp-add-buffer)
                ("Kill buffer(s) from perspective." . helm-persp-kill-buffer))))

以上です。

Putty 経由の Emacs で C-M-S-v が入らない件(未解決)

今回は Emacs です。
以前から使ってはいたのですが、ここを参考に設定しなおしてみようかと思いまして。

とりあえず Ubuntu Linux の仮想マシンを用意して Putty でログインして Emacs をいじっていました。
で、サンプルの通りにキーバインド「C-,」を割り当てて使ってみると動きません。
現在の割り当てを調べる「C-h c C-,」を使ったところ、どうも「C-,」が Linux に入っていないようでした。

この問題については最終的にこのサイトを参考にして解決できました。

該当ページ中から「xterm風定義」リンクを辿ると他のキー一覧もあります。
その中でカンマを示す「VKey188」の行ですが、以下(4番目が \033[27;6;60~)が正しいのではないかと思います。
VKey188=\054,<,\033[27;5;44~,\033[27;6;60~,\033\054,\033<,\033[27;13;44~,\033[27;14;60~

引き続いて「C-M-v」の別ウィンドウスクロールの逆方向版を「C-M-S-v」(Shift を追加する)に割り当てようとしましたが、こちらは解決できませんでした。
「C-,」と同様に「VKey…」を追加すればいいかと思って下のように色々試したのですがダメでした。

試した内容

  • VKey86=,,,,,,,\033[27;14;118~
  • VKey86=,,,,,,,\033[27;14;86~
  • VKey86=,,,,,,,\033[27;14;v~
  • VKey86=,,,,,,,\033[27;14;V~
  • VKey86=,,,,,,,\033[27;5;118~
  • VKey86=,,,,,,,\033[27;5;86~
  • VKey86=,,,,,,,\033[27;5;v~
  • VKey86=,,,,,,,\033[27;5;V~

カンマ区切りのキーコード出力部の内容は 「\033[27;≪修飾コード≫;≪キーコード≫~」だろうと思っています。
この中にある「27」は多分 Escape キーの VKey コードでしょう。

どれも思うようにいかなかったので、現在はエスケープシーケンスの規則を調査中です。
参考サイトに書いてある気もしますが、英語を読むのが面倒なので Try&Error で頑張ります。

参考サイト

ちなみに「C-,」問題は nadoka で「key C-Comma = &SendText("\e[27;5;44~")」でも解決できましたが、対象文字列を入れる時に一文字ずつ(少しだけ)ウェイトがかかって微妙な気分になるので止めました…

コードのスタイルを統一するなら EditorConfig

複数の作業環境を渡り歩いてソースコードを編集することって結構ありますよね?
こんな時、新しく編集した部分だけインデント文字(タブかスペース)やオフセットが変わってしまって、手作業でスタイルを合わせる破目になった経験があるでしょう。
テキストエディタが同じなら作業前に設定ファイルをコピーすればなんとかなりますが、違うエディタだと設定に使った時間の方がコーディング時間より長くなったという悲劇(笑い話?)も聞きます。

そんな時に頼りになる最終兵器 EditorConfig を発見しました。
共通の設定ファイルを用意しておけば、エディタにプラグインを入れるだけで同じスタイルで書けるようにしてくれます。
設定できる項目はインデント文字、オフセット幅、改行文字、文字コード等です。
ディレクトリを遡りながら設定ファイルを探すので、スタイルがプロジェクトごとに違っていても対応できます。

興味がわいた方は、分かりやすい説明がここにあるので参照してみてください。

参考

  • 公式サイトはここ
  • Emacs 用プラグインは Github

Emacs キーバインド その3 矩形リージョン・レジスタ

さて、第3回です。
今回は、使う場面が限定されるけど、使いこなすとスゴいシリーズです。

いろいろ
「消去」は「キル」と違って、内容を覚えずに消します。

  • M-SPC :カーソル前後の空白文字をまとめて消去
  • C-x o :前後の空行を 1行だけ残して消去
  • C-h w COMMAND :コマンド COMMAND を実行するキーバインドを表示

矩形リージョン
通常のリージョン(カーソルとマークの間の文字全て)ではなく、カーソルとマークが左上と右下に来るような矩形(四角形)の中の文字だけを対象とします。
よって、カーソル・マーク間の行に含まれていても、矩形の外側の文字は対象になりません。

  • C-x r k :矩形をキルして右側の文字列を左へ(詰めるように)移動
  • C-x r y :最後にキルした矩形を、カーソル位置を左上としてヤンク(ヤンク矩形範囲内の文字列は右へ(逃がすように)移動)
  • C-x r d :矩形内を消去して右側の文字列を左へ(詰めるように)移動
  • C-x r c :矩形内を空白で上書き(範囲外への影響は無し)
  • C-x r o :矩形サイズの空白を挿入して、矩形内の文字列を右へ(逃がすように)移動

レジスタ
レジスタとは 1文字の名前(a、b、x、y など)が付いた保管場所です。
新しい物を入れると、前に入っていた物は消えてしまいます。

以下の REG_CHAR はレジスタを表す 1文字の名前とします。

  • C-x r s REG_CHAR :リージョン内容をレジスタにコピー
  • C-x r i REG_CHAR :レジスタ内容をカーソル位置に挿入
  • C-x r C-SPC/C-@ REG_CHAR :カーソル位置をレジスタに記録
  • C-x r j REG_CHAR :レジスタに記録されている位置へカーソルを移動
  • M-x list-register :空でないレジスタの内容を一覧表示

Emacs キーバインド その2 ヘルプ・リージョン・キーマクロ

続けての投稿です。

第2回はちょっと慣れてきた人向けのシリーズです。
ヘルプ、範囲選択と切り貼り、+α を書いています。

ヘルプ

  • C-h b :キーバインドの一覧を表示
  • C-h k KEY :キーバインド KEY の説明を表示
  • C-h m :現在のモードに関する説明を表示
  • C-h a STRING :文字列 STRING を含むコマンドのリストを表示

マーク

  • C-SPC/C-@ :カーソル位置にマークを設定してリージョン指定を開始
  • C-u C-SPC/C-@ :一つ前のマーク位置に移動
  • C-x C-x :カーソル位置とマーク位置を入れ替え(と同時にリージョンに設定)

「リージョン」とはマークとカーソルに挟まれている部分です。
リージョンを対象にするコマンドや、リージョン設定中に実行するとリージョン内だけで動くコマンドがあります。

キルとヤンク
「キル」は「切り取り(カット)」の、「ヤンク」は「貼り付け(ペースト)」の Emacs 版です。

  • C-w :リージョンをキル
  • M-w :リージョンの内容を残したままキル(いわゆる「コピー」)
  • C-y :カーソル位置へヤンク(キルしてあった内容を挿入)
  • M-z CHAR :文字 CHAR まで(CHAR も含めて)キル

いろいろ

  • C-x C-n :カーソルのある桁位置を行移動(C-n,C-p)の目標桁に設定
  • C-u C-x C-n :上で設定した目標桁を解除
  • C-x = :カーソル位置の情報(文字コード、文字位置、桁位置)を表示
  • M-( :かっこの対「()」を挿入して、その中にカーソルを移動
  • C-x n n :表示(と編集)をリージョン内のみに限定(ナローイング)
  • C-x w :ナローイングの解除

キーボードマクロ
記録開始から終了までの操作を覚えておいて再利用します。

  • C-x ( :マクロの記録を開始
  • C-x ) :マクロの記録を終了
  • C-x e :最後に記録したマクロを実行
  • M-x insert-kbd-macro ENTER :最後に記録したマクロの内容をカーソル位置に挿入

設定ファイル(.emacs など)にマクロ内容を保存しておく事で、次回以降の Emacs 起動時でも利用できます。
ただし、名前を付けてキーバインドを設定(global-set-key などを利用)しないとダメですが。

Emacs キーバインド その1 カーソル移動

ふと思い立って Emacs マニュアルを片手にキーバインドをまとめ直したので記録します。

第1回はカーソル移動についてです。…一部検索も含みますが。

言うまでもありませんが「C-x」は Ctrl キーを押しながら x を押すという意味です。
同様に「M-x」は Alt キーを押しながら(あるいは ESC を押してから) x を押します。
あと「C-x n」は「C-x」の後に(Ctrl を放してから) n を押します。

以下で使用している「a/b」は独自表記で a または b を意味します。
そのキーバインドの説明で【上、下】のように書いてあれば、a の時が「上」で b の時は「下」と考えてください。

単位ごとの移動

  • C-p/C-n :【後方(上)、前方(下)】の行へ移動
  • C-b/C-f :1文字【後方(左)、前方(右)】に移動
  • M-b/M-f :1単語【後方(左)、前方(右)】に移動
  • M-a/M-e :文 1つだけ【後方(左)、前方(右)】に移動
  • M-[/M-](角括弧の開き/閉じ) :1段落【後方(上)、前方(下)】に移動
  • C-x [/](角括弧の開き/閉じ) :1ページ(^L文字で区切られている)【後方(上)、前方(下)】に移動

先頭と末尾への移動

  • C-a/C-e :行の【先頭、末尾】へ移動
  • M-</M-> :バッファの【先頭、末尾】へ移動

スクロール・位置指定

  • C-v :1画面進む(下)方向にスクロール
  • M-v :1画面戻る(上)方向にスクロール
  • C-l :現在行が画面中央に来るようにスクロール
  • M-g M-g :指定する行番号へ移動
  • M-r :画面中央の行へカーソル移動

検索(インクリメンタルサーチ)
文字を入力しながら検索します。1文字入れるごとに候補を絞り込みます。

  • C-s :前方(画面下)へサーチ、サーチ中なら前方の次候補へ移動
  • C-r :後方(画面上)へサーチ、サーチ中なら後方の次候補へ移動

現在位置で検索を終了したければ ENTER か、カーソル移動コマンドを使えばいいです。
検索開始位置に戻りたい場合には C-g を利用します。


特殊:プログラムのソースファイル向け

  • C-M-b/C-M-f :式 1つ分だけ【後方(左)、前方(右)】に移動
  • C-M-p/C-M-n :リスト 1つ分だけ【後方(左)、前方(右)】に移動
  • C-M-a/C-M-e :最上位のまとまり(関数定義など) 1つ分だけ【後方(上)、前方(下)】に移動
  • C-M-u/C-M-d :リスト階層で 1つ【上(外)、下(中)】へ移動
  • M-m :現在行の先頭の非空白文字(字下げした行頭)へ移動

とまあ色々とありますが、とりあえず下の 3パターンだけ覚えておけば何とかなります。

  • C-p/C-n/C-b/C-f :1つ【上、下、左、右】へ移動
  • C-s/C-r :【前方(下)、後方(上)】へ検索開始・次候補へ移動
  • C-v/M-v :1画面【前方(下)、後方(上)】へスクロール

余裕があれば 単語移動の M-b/M-f、行頭 C-a、行末 C-e、バッファ先頭/末尾 M-<、M-> も覚えておくと便利です。

How to add elisp library on Debian

突然ですが Emacs 紹介のページで rainbow-delimiters という「対応する括弧を色付けする」elisp を見付けました。
これは早速入れるべしという事で、まずはパッケージを探したのですが案の定そんなパッケージは存在せず、泣きながら(←誇張)手動でインストールとなりました。

で、「どうせだからパッケージと同じようにシステムにインストールしよう」と(いつもと同様)唐突に思い立ち、なんとか目的を達成したのでメモしておきます。

なお、フォルダのパーミッションの都合上、以下の作業は root で行いました。
手順は windows-el パッケージを参照させて頂きました。メンテナの方に感謝です。

  1. まずは elisp ファイルをダウンロードします。しないと話が始まりません。
  2. それを /usr/share/emacs/site-lisp/ 以下に置きます。今回は 1ファイルだったのでグループ化しませんでしたが、複数ファイルの場合はフォルダを掘って入れるのが良いようです。
  3. 続いて、元と同様のフォルダ構造で /usr/share/?flavor?/site-lisp/ 以下に elisp ファイルへの symlink を張ります。「?flavor?」の部分には実際の emacs の名前を入れてください。今回は「emacs24」でした。
  4. いよいよバイトコンパイルの時間です。symlink したファイル群に対して「emacs24 -batch -q -no-site-file -f batch-byte-compile elispファイル名」を叩いてください。「emacs24」の部分は環境に合わせて読み替えて下さい。(当然ながら作業フォルダは symlink 先だった  /usr/share/?flavor?/site-lisp/ 以下ですよ)
    コンパイル時に別ファイルを読ませる必要があれば「-l ファイルパス」(←小文字のエルです。アイでも1でもありません)をコマンドラインに追加すればいいようです。
  5. 最後に /etc/emacs/site-start.d/ に、ライブラリ読み込み用の設定ファイルを作成します。今回は 50windows-el.el70rainbow-delimiters.el にコピーさせてもらって、ちょこっと編集して使いました。
    基本的には元の elisp ファイルの存在を確認した後で emacs の load-path に追加して、require しているようでした。
    1ファイルしか無い今回は load-path 設定の部分をコメントアウトして require だけにしましたが、動作したので OK ということで。

これでシステムワイドにライブラリを読み込んでくれるので、後は個人設定で add-hook するなり global-rainbow-delimiters-mode で常に ON にするなり、好きなように料理できます。

いやぁ、今日の思い付きは短時間で済んだので本人もびっくりです。持つべきものは「バラせる(←ここ重要。テストに出ます)既存品(つまり windows-el パッケージ)」ですね。