TiddlyWikiで日本語インクリメンタルサーチ(Firefox専用)

ローマ字のまま日本語インクリメンタルサーチを可能にする「migemo」というライブラリがあります。漢字変換というプロセス抜きの検索は、ユーザビリティが著しく向上していて、自分の周りにもファンが多いライブラリです。

TiddlyWikiの検索機能はインクリメンタルサーチに対応しているのですが、当然ながらmigemoのような日本語インクリメンタルサーチを行うことができませんでした。(普通の日本語検索には対応しています)

最近になって、migemoC言語版「C/Migemo」の開発者KoRoNさんが、C/MigemoFirefoxJavaScriptから呼び出すモジュール、「nsIMigemo」を公開なさっていました。これを使えば、TiddlyWikiを日本語インクリメンタルサーチ対応にできるのではないかと考え、ちょっと試してみたので報告します。

TiddlyWikiの検索インターフェースもマクロで表現されているので、これをベースにmigemo_searchマクロを作っています。TiddlyWiki 1.2.32、Firefox 1.0.7、nsIMigemo 20050903で動作を確認しました。Windows用のFirefox以外のブラウザではエラーとなります。nsIMigemoは「初期の実験段階」ということなので、注意して下さい*1

nsIMigemoのインストール

nsIMigemoをダウンロードし、付属のREADME.txtに従ってインストールして下さい。
http://www.kaoriya.net/testdir/CMigemoXPCOM-20050903.zip

TiddlyWikiマクロのインストール

適当な名前のtiddlerを作成し、以下のコードを記述して、タグに"systemConfig"を追加して下さい。一度保存して、ブラウザで再読込を行うと、コードが呼び出され、マクロが登録されます。

config.macros.migemo_search = {
  initMigemoError : "Failed to initialize nsIMigemo library - %0",
  regexpError : "Failed to create regular expression - %0",
  navigatorError : "This migemo_search macro is available only in Gecko based Browser."
};

config.macros.migemo_search.handler = function( place,macroName,params )
{
  var lastSearchText = "";
  var searchTimeout = null;
  var migemo;

  // Initialize nsIMigemo
  if( window.Components ) {
    try {
      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
      const cid = "@kaoriya.net/migemo/nsMigemo;1";
      migemo = Components.classes[cid].createInstance();
      migemo = migemo.QueryInterface( Components.interfaces.nsIMigemo );
    } catch ( err ) {
      displayMessage( this.initMigemoError.format([err]) );
    }
  } else {
    displayMessage( this.navigatorError );
    return;
  }
  
  var doSearch = function( txt ) {
    var mregexp;
    
    // Create Regexp to search Tiddler
    try {
      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
      mregexp = migemo.query( txt.value );
    } catch ( err ) {
      displayMessage( this.regexpError.format([err]) );
      return;
    }
    
    closeAllTiddlers();
    var matches = store.search( mregexp,
                                config.options.chkCaseSensitiveSearch,
                                true,
                                "title","excludeSearch" );
    for ( var t = matches.length - 1; t >= 0; t-- ) {
      // In order to highlight text matched by migemo, need to modify "wikify" function.
      displayTiddler( null,
                      matches[t].title,
                      0,
                      txt.value,
                      config.options.chkCaseSensitiveSearch,
                      false,
                      false );
    }
    
    if ( matches.length > 0 ) {
      displayMessage( config.macros.search.successMsg.format([matches.length.toString(), "/" + txt.value + "/"]) );
    } else {
      displayMessage( config.macros.search.failureMsg.format(["/" + txt.value + "/"]) );
    }
    
    lastSearchText = txt.value;
  };
  
  var clickHandler = function( e ) {
    doSearch( this.nextSibling );
  }
  
  var keyHandler = function( e ) {
    if (!e) var e = window.event;
    switch(e.keyCode) {
    case 27:
      this.value = "";
      clearMessage();
      break;
    }
    if((this.value.length > 2) && (this.value != lastSearchText)) {
      if(searchTimeout) {
        clearTimeout(searchTimeout);
      }
      var txt = this;
      searchTimeout = setTimeout(function () { doSearch( txt ); },200);
    }
  };

  var focusHandler = function( e ) {
    this.select();
  }

  var btn = createTiddlyButton( place, config.macros.search.label, config.macros.search.prompt, clickHandler );
  var txt = createTiddlyElement( place,"input",null,null,null );
  if ( params[0] ) {
    txt.value = params[0];
  }
  txt.onkeyup = keyHandler;
  txt.onfocus = focusHandler;
  txt.setAttribute( "size", config.macros.search.sizeTextbox );
  txt.setAttribute( "autocomplete" , "off" );
  txt.setAttribute( "type" , "text" );
}

サイドバーの検索部分を書き換える

"SideBarOptions"というtiddlerを作成します。このとき、新規tiddlerを作ってリネームしてもよいのですが、適当な場所に"SideBarOptions"と記述しそのリンクをたどってtiddlerを作成するようにすれば、だいたい以下のような内容になっているはずです。

<<search>><<closeAll>><<permaview>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel options 'Change TiddlyWiki advanced options'>>

この"SideBarOptions"のtiddlerの内容を、上記の"<>"を、"<>"に置き換えたものとし、編集を終了して下さい。

これでTiddlyWikiで日本語インクリメンタルサーチができるようになります。残念ながら、検索結果のハイライト表示はマクロの域を超えているので、まだ実装できていませんが、TiddlyWikiの柔軟性は今後も向上していくと思いますので、そのうち実装できるのではないかと思います。

*1:TiddlyWiki 2.0.x および Firefox 1.5.x では検証してないので注意してください