Ruby開発支援ツールRSenseを秀丸から使ってみたの巻

やあ (´・ω・`) はじめに謝っておこう。
このマクロはいまのところさほど快適ではないから、過度の期待をもって使うときっとがっかりするだろう。君のがっかりした顔を見るのは僕もつらいんだ。あとでゆっくり制限事項について話しあおう。
 
さて「Rubyのための最も優れた開発援助ツール」というダイソンばりのキャッチーなコピーとともに登場したRSenseは、はやくもRubystたちのハートをがっちり掴んだようですね。
IDEみたいな軟弱なツールを使わずにエディタひとつでストイックに開発するのもこれまたRubyの伝統ではありますが、それでもやっぱり仕事で必要にせまられてVisualStudioなんか使ったりするともう楽で楽でしょうがない。僕だってVB.NETのメソッドなんてそれぞれ頭1文字くらいしかおぼえてないのに、それでもさくさくとうろおぼえコーディングができてしまう現実を目のあたりにするとなんというか技術ってすばらしいって思ったり思わなかったり。
 
話がそれました。本題に入る前にWindowsでRSense環境を整備するところからはじめましょう。
 

環境構築

とりあえずダウンロードしたファイルをC:\rsense-0.2あたりに展開します。
 
次にHOMEディレクトリに.rsenseファイルを作成します。
Windowsの場合、環境変数HOMEをC:\Documents and Settings\mynameのような値に設定したくなりますが、RSenseはスペース付のディレクトリ指定はうまくいかないようです。なのでとりあえずrsenseをインストールしたディレクトリをHOMEとし、サーバを起動するときに環境変数を変更することにします。

  cd \rsense-0.2
  ruby etc/config.rb > .rsense

以下のバッチファイルを作り、ダブルクリックしてRSenseサーバを起動します。
rsense_start.bat

set RSENSE_HOME=c:\rsense-0.2
set HOME=c:\rsense-0.2
ruby bin/rsense server

これだとユーザーごとに環境を変えられないですが、まあ自分専用のPCであればよしとしましょう。クライアント側はHOMEを見ていないようだしシステム全体の設定を変える必要がないので他のHOMEを見ているアプリにも影響がなく安全です。
 
サーバプロセスはCtrl-Cなどでは停止できません。クライアントから終了コマンドを送信して終了させます。これもこんなサーバ停止用バッチを用意しておくと便利です。
rsense_stop.bat

ruby bin/rsense exit

 

秀丸マクロ

型表示用マクロ
rsense_type_help.mac

// rsense_type_help.mac - RSense client for Hidemaru Editor
//
// Copyright (C) 2010 aike. All rights reserved.
//
// 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 program 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 <http://www.gnu.org/licenses/>.

$rsense_command = "ruby c:/rsense-0.2/bin/rsense";

call CheckCharset;
if (updated) {
    save;
}
call GetCharsetString;
$charset = $$return;
call RsenseGetTypeInfo filename3, $charset, lineno, column;
endmacro;

CheckCharset:
    ##code = charset & 0x3F;
    if ((##code != 1) && (##code != 6)) {
        message "ERROR: encoding must be Shift_JIS or UTF-8.";
        endmacro;
    }
    ##linebreak = charset & 0xC0;
    if (##linebreak != 0x40) {
        message "ERROR: linebreak code must be LF.";
        endmacro;
    }

GetCharsetString:
    ##code = charset & 0x3F;
    if (##code == 1) { return "SJIS"; }
    return "UTF-8";

RsenseGetTypeInfo:
    $$pos = str(##3) + ":" + str(##4);
    #hSource = hidemaruhandle(0);
    newfile;
    showwindow 0;
    #hTemp = hidemaruhandle(0);
    run $rsense_command + " type-inference"
        + " --file=" + $$1
        + " --encoding=" + $$2
        + " --location=" + $$pos
        + " --format=plain";
    left;
    $rmenu[0] = gettext(6, 0, x, y);
    if ($rmenu[0] == "") {
        $rmenu[0] = "No type information";
    }
    setactivehidemaru #hSource;
    closehidemaruforced #hTemp;
    menuarray $rmenu, 1;
    return;

 
コード補完用マクロ
rsense_complete.mac

// rsense_complete.mac - RSense client for Hidemaru Editor
//
// Copyright (C) 2010 aike. All rights reserved.
//
// 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 program 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 <http://www.gnu.org/licenses/>.

$rsense_command = "ruby c:/rsense-0.2/bin/rsense";

call CheckCharset;
if (updated) {
    save;
}
call GetPeriodPos;
#pos = ##return;
if (#pos > 0) {
    call GetCharsetString;
    $charset = $$return;
    call GetPrefix #pos;
    $prefix = $$return;
    if ($prefix == "") {
        #pos = #pos + 1;
    }
    call RsenseGetMethod filename3, $charset, lineno, #pos, $prefix;
    call ReplaceMethod ##return, #pos;
}
endmacro;

CheckCharset:
    ##code = charset & 0x3F;
    if ((##code != 1) && (##code != 6)) {
        message "ERROR: encoding must be Shift_JIS or UTF-8.";
        endmacro;
    }
    ##linebreak = charset & 0xC0;
    if (##linebreak != 0x40) {
        message "ERROR: linebreak code must be LF.";
        endmacro;
    }

GetCharsetString:
    ##code = charset & 0x3F;
    if (##code == 1) { return "SJIS"; }
    return "UTF-8";

GetPeriodPos:
    ##c = column;
    ##l = lineno;
    ##pos = -1;
    left;
    while (column > 0) {
        if ((code == 0x20) || (code == 0x09)) {
            break;
        }
        if (code == 0x2E) { // '.'
            ##pos = column;
            break;
        }
        left;
    }
    movetolineno ##c + 1, ##l;
    return ##pos;

GetPrefix:
    return gettext2(##1 + 1, lineno, column, lineno);

RsenseGetMethod:
    $$pos = str(##3) + ":" + str(##4);
    #hSource = hidemaruhandle(0);
    newfile;
    showwindow 0;
    #hTemp = hidemaruhandle(0);
    run $rsense_command + " code-completion"
        + " --file=" + $$1
        + " --encoding=" + $$2
        + " --location=" + $$pos
        + " --format=plain";
    if ($$5 != "") {
        #hTemp2 = #hTemp;
        localgrep "completion: " + $$5, casesense, noregular, nohilight;
        showwindow 0;
        #hTemp = hidemaruhandle(0);
        closehidemaruforced #hTemp2;
    }

    replaceallfast ".*completion: ([^ ]+) .*", "\\1", casesense, regular;

    moveto 0, 0;
    while (code != eof) {
        golineend2;
        $rsense_menu[y] = gettext(0, y, x, y);
        down;
    }
    ##cnt = y;

    setactivehidemaru #hSource;
    closehidemaruforced #hTemp;

    menuarray $rsense_menu, ##cnt;
    return result;

ReplaceMethod:
    if (##1 <= 0) {
        return;
    }
    while (((code >= 0x30) && (code <= 0x5A))
        || ((code >= 0x61) && (code <= 0x7A))
        || (code == 0x21)
        || (code == 0x5f)) {
        right;
    }
    while (column >= ##2 + 2) {
        backspace;
    }
    insert $rsense_menu[##1 - 1];
    return;

秀丸の設定

こんな感じでマクロ登録します。その後これらをF11、F12などのキーに割りあてると良いと思います。

 
スクリーンショットはこんな感じです。
コード補完

 
型表示

 

制限事項

・実行すると強制的にファイルを保存します
・テンポラリのウィンドウが一瞬開いたりするのが見えちゃいます
・改行コードはLFのみに対応しています
文字コードShift_JISUTF-8のみに対応しています
・インクリメンタルな絞込みはできません
・なのでピリオドを押したときに自動起動するような設定はたぶん使いにくいので
 ファンクションキーなどにアサインすることをお勧めします
 
続きはgithubで!