改めてGaucheとrlwrapの連携について

rlwrapコマンドを使うと、入力にReadLineの機能が使えるようになる。また補完機能やカッコの対応表示も働く。キーバインドは→GNU Readline Library:1.4 Bindable Readline Commands
ヒストリ(Ctrl+p、Ctrl+nなど)と補完(Tab)だけでもかなり便利。
rlwrapをGaucheで利用する場合、オプションにc、q、b、mあたりを指定する。

rlwrap -c -q '"' -b "'"'(){}[].,#@;|`"' -m gosh

補完したい単語は、ファイル

~/.gosh_completions

に並べておく。環境変数$RLWRAP_HOMEが設定されているなら

$RLWRAP_HOME/gosh_completions

というファイル。ファイル名のドットのあるなしに注意。
一般的には、補完語ファイルは

~/.コマンド名_completions
$RLWRAP_HOME/コマンド名_completions

なので、コマンド名を変えている場合はそれに応じたファイル名にするか-Cオプションを使って「-C gosh」とする。
また f オプションを使って補完語ファイルを指定することもできる。ファイルはいくつ指定してもよい。

rlwrap -f 補完語ファイル1 -f 補完語ファイル2 -f … その他のオプション ラップしたいコマンド名

ファイルの指定により、任意のファイルから補完語を追加できる。プログラムのソースを指定すればそこに出てくる名前を補完語に追加できるし、複数のコマンドで補完語ファイルを共有することもできる。

-C, --command-name
italic;">command_name: 補完語ファイルとヒストリファイルの名前に使われるコマンド名を変更する。
-c, --complete-filenames
ファイル名補完を働くようにする(ファイル名も補完の候補になる)。
-q, --quote-characters
italic;">list_of_characters: 引用符文字を明示的に指定する(指定しない場合のデフォルトの引用符は"と')。引用符で囲まれている部分にカッコが現れても、カッコの対応付けから外される。LispSchemeでは単一引用符「'」は引用符扱いしない方がよい。
-f, --file
italic;">file: ファイルfileの内容を単語に分割して、補完語リストに追加する。複数のファイルを指定したい場合は、必要なだけfオプションを繰り返す。
-b, --break-chars
italic;">list_of_characters: 単語の区切り文字を明示的に指定する(空白文字はつねに区切り文字になる)。区切り文字の情報は補完語を決めるときに使われる。デフォルトの区切り文字には「+-=&%^」などが含まれているので、LispSchemeではそれらを含めないよう明示的に指定した方が良い。
-m, --multi-line
Ctrl+^でエディタを起動させ編集できるようになる。エディタは環境変数$RLWRAP_EDITOR で指定する。

たとえば.bashrcとかに

export RLWRAP_EDITOR='vim -c "set filetype=scheme"'

と書いておいたり、あるいは

export RLWRAP_EDITOR='vim -c "set filetype=scheme"'
rlwrap -c -q '"' -b "'"'(){}[].,#@;|`"' -m gosh "$@"

のようなスクリプトを作ってこれを実行すれば、read-eval-printループ中にCtrl+^を打つとVimSchemeモードで起動する。
(その他のオプション等→http://utopia.knoware.nl/~hlub/rlwrap/rlwrap.html)

Gaucheの補完語リストの作成

1. Gaucheのマニュアルから作る

Gaucheのマニュアルのインデックスの部分をそのまま補完語用のテキストにする。

htmlファイルをプレーンテキストにする処理が面倒なら、ブラウザ上で「すべて選択」→エディタにコピペ→セーブ、で補完用ファイルを作成する。リファレンス・セクション名など余分な単語が入っているけれど特に気にしなくていい。

2. Gaucheから作る

以下のプログラムで作成できる。ただしいくつか足りない名前があったり逆に補完語にいれなくても良さそうなものが出力されていたりする。

(use srfi-1)
(use file.util)

(define (main args)
  (define predefined-modules '(null scheme gauche))
  (define exclude-files '("gauche/matrix.scm" "os/windows.scm" "srfi/"))
  (define obsoleted-modules '(gauche.let-opt gauche.validator gauche.singleton))

  (dolist (pattern (list "*/*" "srfi-*" "gauche/mop/*"))
    (library-for-each
      pattern
      (lambda (_ path)
        (unless (or
                  (any (cut string-scan path <>) exclude-files)
                  (any (cut library-has-module? path <>) obsoleted-modules))
          (guard (exc (else 'nop))  ; モジュールをロードしたときのエラーは無視する
            (load path))))
      :paths (filter absolute-path? *load-path*)
      :allow-duplicates? #t))

  (let ((symbol-list1 (append-map module-exports (all-modules)))
        (symbol-list2
          (append-map
            (lambda (module)
              (hash-table-keys (module-table (find-module module))))
            predefined-modules)))
    (dolist (name (sort
                    (delete-duplicates 
                      (map symbol->string (append symbol-list1 symbol-list2)))))
      (print name))))