Menu

#85 WSHプラグイン

closed
nobody
None
5
2012-11-09
2009-10-31
syat
No

WSHを使ったプラグイン機能の土台を作りました。
プラグインの方式はFirefoxやEclipseのように、
プログラム+メタ情報を一つのフォルダに格納する形式です。
このパッチではプログラムの部分がJScriptやVBScriptになります。

たぶん実例を見たほうが早いので、Rubyのアウトライン解析
プラグインを添付します。
今のところアウトライン解析しかプラグできません。

DLLではなくWSHを選んだのは、WSHのほうが簡単だし
すそ野が広そうだというのと、今までのEditorオブジェクトを
そのまま利用できるためです。いちおう、CPluginを継承して
CDllPluginを作ってやればDLLにも対応できるんじゃないかと
思っていますが、DLLにあまり詳しくないので何とも…

今後の課題として私のほうで把握してるのは、
・エディタウィンドウを開くたびにプラグインをロードしてるので遅い。
 ControlProcessで1回だけ読み込むようにしたい。
・DLLプラグイン対応。DLLからEditorオブジェクトを呼べるの?
・少なくとも自動インデント機能はプラグ可能にしたい。
・設定画面との矛盾とか、似たようなプラグインの競合とか、
 細かい部分のつじつま合わせ。

Discussion

1 2 > >> (Page 1 of 2)
  • syat

    syat - 2009-10-31

    パッチ。インタフェースオブジェクト複数化。WSHプラグイン機能。

     
  • syat

    syat - 2009-10-31

    Rubyアウトラインプラグイン。sakura.iniのあるフォルダに plugins フォルダを作成し、その中に解凍する。

     
  • syat

    syat - 2009-10-31

    説明書。

     
  • ds14050

    ds14050 - 2009-10-31

    プラグインの必須情報として「Extension=rb」というのがあります。プラグイン側が適合するファイルを規定するのではなく、タイプ別設定の「アウトライン解析方法」にプラグイン定義の選択肢を追加して、エディタ使用者が選択できるようにするのではいけないですか?

    コマンドを追加しようとするとき、単純なテキスト置換コマンドもタイプ別設定や拡張子にしばられてしまいそうですし。

     
  • syat

    syat - 2009-10-31

    ds14050さん、コメントありがとうございます。
    作ってる途中で「ファイルタイプでプラグインの有効無効を切り替える必要があるな」と思い、ファイルタイプ名は環境ごとに違うので駄目だし、じゃあ拡張子でとExtensionを足しました。今冷静に考えると、おっしゃるようにタイプ別設定に選択肢を増やす方が今までのエディタの作りに合っている気がします。
    個人的な希望としては、プラグインは置くだけで使える状態になってるのが理想なんですが、それはプラグイン側の工夫でどうにでもできるのかもしれません。(初回ロード時は ruby のタイプ別設定を探してアウトライン解析の設定を書き換えてしまうとか。)
    技術的な難点は、追加された選択肢を選び、エディタ終了で設定ファイルに書き出した後、次回起動したときにそのプラグインが存在する保証がないこと。また、n番目のプラグインという風に指定したくても、ロードする順序も保証されないためできない、という点でしょうか。設定ファイルにプラグイン名を含めるか、世界的にユニークなプラグインIDを振るなどして識別しなきゃならないかもしれません。

     
  • ds14050

    ds14050 - 2009-10-31

    技術的な点に関してだけいえば、名前ベースでいいんじゃないかと思っています。あるプラグインが「Ruby」や「Ruby(hogeプラグイン)」というアウトライン解析を提供する、というように。名前が同じならどのプラグインがその解析方法を提供していても気にする必要はないと思います。

     
  • syat

    syat - 2009-11-01

    選択肢の追加はAddOutlineMethodというマクロ関数を追加して、EditorStartイベント内で呼び出すようにしました。Extensionは廃止の方向で。まだアウトライン解析の呼び側ができていないのでアップしません。

    >ds14050さん
    名前ベースというのは、選択肢でRuby(hoge)を選んだら、Ruby(hoge)を提供するプラグインを探して実行する・複数あったらどっちかを使う、みたいな感じですかね?そこは作り次第でそれもいいと思います。現状のサクラのソースは割と数値にコード化してるところが多いので、なんとなくそっちの方向を考えていました。

    下で技術的な難問と言っていたのは、各種設定をiniに保存するとき整数値にしている部分が結構あり、たとえばアウトライン解析も 3:テキストとか、1: C++ とかになっています。そこでどうやってプラグインを識別するかという話でした。
    デフォルトで12個ルールがあるとして、今回Rubyアウトラインを単純に13番とします。設定ファイルに13番と書き込みます。次回の起動までにJSプラグインが追加され、もしJSが先に読み込まれた場合、JSが13、Rubyが14になるかもしれません。そうなるとiniの設定が予期せぬことになります。これを避けるため、設定ファイルには何か、プラグインを識別する情報が必要だと思うのです。
    今考えていたのは、XXXYYのようなプラグインIDを振り(XXX=作者ID、YY=プラグインID)、アウトライン解析の値はそれをそのまま使う。コマンドのように複数あるものは XXXYY01、XXXYY02のようなコードで、既存のコマンドIDとかに紛れ込ませたらどうだろう?という感じです。

     
  • ds14050

    ds14050 - 2009-11-01

    自分の考えを押しつけるつもりで食い下がるのではありませんが、微妙に伝わっていないようなので。1、2、3、と保存しているところに Rubyと保存するのです。エディタ起動時にプラグイン定義ファイルだけはすべて読み込んでいるでしょうから、名前とスクリプトパスとの対応付けはそのときに済ませています。名前に対応するスクリプトが存在しなければ既存の設定:組み込みの解析ルールを指す数値であると仮定して、再度解析ルールを探せば、後方互換性も確保できます。

     
  • syat

    syat - 2009-11-04

    文字列と数字を混在させるのはやめた方がよいと思います。名前が1というプラグインがあったときに組み込みかプラグインかの区別ができません。組み込みルールも文字列にするのはアリですが。
    ただ名前ベースだと重複する可能性が大きいです。Rubyのアウトライン解析を作ったら、ふつうはRubyという名前にするでしょう。同じ機能のプラグインが複数あったら、とりあえず全部インストールして使い比べしたくなりませんか?
    #iniファイルの項目名が nDefaultOutline のようにハンガリアンなので、文字列化するのが面倒くさいという理由も…。

     
  • ds14050

    ds14050 - 2009-11-04

    すべて承知しています。
    1という名前のアウトライン解析をプラグインが追加することもあるでしょう。設定を変更せずプラグインの有無のみで組み込みの解析ルールとプラグインのを切り替える目的で。
    名前が重複するのを嫌うのであれば、すでに例示したように「Ruby(hogeプラグイン)」という名前をつければいいのです。名前付け規則は運用まかせです。
    C++には不要な、悪しきシステムハンガリアンですよね。nDefaultOutlineという項目は古い sakuraW.exeのために残しておいて、新しい sakuraW.exeは別の文字列項目でそれを上書きする、というのが最も互換性がありそうです。

    全部インストールして使い比べ
    するにはやはり
    プラグインは置くだけで使える状態になってる
    のでは競合してしまって困りますよね。

    そこで最初にもどるわけなんですが、ユーザーに選んでもらうためには選択肢が必要で、選択肢がそのまま IDで十分なんじゃないかと思ったわけです。選択肢が同じ文字列であればユーザーは区別ができません。区別ができないものは区別する必要もないだろうと。選択肢に強制的にプラグイン名なりプラグインIDを含めて、iniにもそれを含めて書き込むのはもちろんありなのですが、不自由に感じました(自由も良し悪しですが)。プラグインを識別するかどうかは一長一短なのでどちらでもいいのですが、作者IDって何でしょう?これに限っては全く不要に思います。

    # Python V.S. Rubyという構図が頭をよぎりました。ファイルやディレクトリで名前が区切られる Pythonと、オープンクラスでどこからでも上書き、拡張可能な Ruby。(もちろん Ruby派です)

     
  • syat

    syat - 2009-11-07

    パッチ2。アウトライン解析を選択肢から選べるように。コマンド追加機能。

     
  • syat

    syat - 2009-11-07

    Rubyアウトラインプラグイン。パッチ2対応版。

     
  • syat

    syat - 2009-11-07

    作者IDの理由ですが、将来プラグインが順調に受け入れられていけば、有志の方が自作プラグインをWebで公開してくれることを期待しています。仮にプラグインの識別をIDで行うとすると、重複しないようにどこか(たとえばWiki)で払い出しをすると思いますが、プラグイン一個作るたびにID払い出しを待つのは面倒くさいので、作者IDだけ登録すれば、下位のプラグインID(例えば2ケタで01~99)は作者が好きに決めることができて便利だろうと思いました。まあ、それは運用の話で、5桁の数字で重複しないように乱数生成するでもいいんですけどね。

    少し実装を進めたのでパッチをアップします。アウトライン解析ルールが選択肢から選べるようになったのと、コマンドを追加する機能を付けています。
     WSH_Plugin_U2.patch
    プラグイン識別の話は、とりあえず実装が簡単な数字IDで進めています。今は、プラグインID2ケタ(XX)、プラグID2ケタ(YY)で考えていて、追加コマンドの機能番号は 2XXYY を割り当てています。int型だから十分幅があると思っていたのに、Funccode_x.hsrcの以下のコメントを見て、泣きながら作者IDを捨てました。
    // Windows 95では32768以上のコマンドをメニューやアクセラレータに設定すると
    // 動作しない.
    このコメントって32768個のことを言ってるのか、IDの最大値が32768と言っているのかどっちなんだろう?

    世界的に一意のプラグインIDを持たなくても、新しいプラグインが追加されたときにサクラエディタが連番を振って、それをオプションファイルに書き込んでおけば、プラグインIDが2ケタでもやっていけるのでは?と思っています。99個までは。

     
  • ds14050

    ds14050 - 2009-11-12

    理由も聞かずに不要だと断定したのは間違いでした。すみません。順調に開発が進んでいる中、横やりをはさむばかりで心苦しいのですが、自由にプラグインを作成して公開してもらうことを考えると、作者やプラグインを一カ所でシリアライズするよりは UUIDやハッシュ値を導入する方が利便性が高い(シリアルの管理コストがない、心理障壁が低い)ように思います。設定ファイルに書き出すときは UUIDを使い、起動の度に使われている UUIDを配列に格納しそのインデックスを内部での(プロセスが存続する限りの)IDにするなど方法はあるはずです。

     
  • syat

    syat - 2009-11-15

    パッチ3。スマートインデント機能をプラグ可能に。追加コマンドをツールバー・メニューに登録可能に。

     
  • syat

    syat - 2009-11-15

    Rubyインデントプラグイン。

     
  • syat

    syat - 2009-11-15

    説明書。

     
  • syat

    syat - 2009-11-15

    横やりをはさむだなんてとんでもない。自分と違う考え方を聞いてはじめて気付かされることも多々あるので、とても助かっています^^

    プラグインIDについてはエディタで発行するのも微妙だし、UUIDを使えるのならそっちのほうがいい気もします。別のプラグインに依存したり拡張したりするプラグインが出てこないとも限らないし、そのとき一意のIDを持っていたら良いのかも。

    設定ファイルの機能番号にUUIDを突っ込めたらいいんだけど、ちょっと手間がかかりそうなので、エディタにプラグイン管理テーブルのようなものを設定に持ち、UUIDと内部ID(2ケタ)の対応付けを行う感じでしょうか。

    パッチのほうは、当初から言っていた自動インデントのプラグイン化を実装しました。また追加コマンドをツールバーに登録できるようにしたのと、メニューの「ツール」下にメニュー登録するようにもしました。ツールバーのアイコンはとりあえず全コマンド共通でbmpの右下を一コ予約。将来的にプラグイン同梱の画像ファイルからアイコンを読み込めたらかっこいいですね。

    自動インデントは、できなくはないけれども、課題が2点ほど。
    ・タブのサイズは取得できるのに、タブ文字か空白かの設定を取得できない。
     新たに関数を追加するより、どうせなら Editor.GetTypeSetting( "IndentUsingSpace" ) のように汎用的にいろいろ取得できたらよいのでは?
    ・一文字入力ごとに、jsを読み込んで解析して実行して破棄して、かなり重い。ロードしたスクリプトをメモリ上に保持する機能は必須ぽい。

     
  • syat

    syat - 2009-12-01

    2週間ほど経ちますがあんまり進んでいません。
    方向をいろいろ考えてはいるのですが、これという決め手がなくて。。

    今考えていることを箇条書き、というか思考の流れで並べると、、、
    ・プラグインがGUIDのようなものを持つのは良いと思う。
    ・内部的には長いIDを扱いづらいため、00~19まで(←99から減らした)の番号(プラグイン番号と呼ぶ)に変換する。
    ・このプラグイン番号を加工して、アウトライン解析のルール番号やコマンドの機能番号を生成しているため、IDと番号の関係を設定ファイルなどに永続化する必要がある。

    ここまではある程度固まっています。ここから下は頭の暴走です。
    ・設定ファイルに持つということはControlProcessが管理するのだろう。
    ・ということはプラグイン情報をControlProcessですべて読み込むの? →否。
     なぜなら共有メモリはFileMappingなので、可変数とかメモリ動的確保と相性が悪く、もしやるなら固定長×有限数の領域を用意しておく。
    ・共有メモリにはプラグイン情報をどこまで載せるのか? →最小限(番号、ID、プラグイン名)
    ・最小限の情報をControlProcessで管理し、残りの情報はNormalProcessで必要に応じて読み込む。
    ・プラグインの追加があった場合、ControlProcessの初期化で検知して、「インストールしますか」的なダイアログを出した方がよいのでは? ファイルを置いただけで有効になってしまうのは、セキュリティ的にどうかと。
    ・共通設定の「プラグイン」タブでプラグイン一覧が見れたらいいよね?
    ・プラグインのバージョンが上がったらIDは変えるの? →改版する毎にIDが変わったら設定が無駄になるので変えない。IDとバージョンの組で一つのプラグインを特定することになる。うーん。バージョン番号の仕様も決めといた方が良くないか?

    ?ばっかですみません。ツッコミ等歓迎します。
    参考:Eclipseプラグインについて書かれた↓のサイトはとてもためになります。
    http://www.genpaku.org/other/eclipse/plugin_architecturej/plugin_architecture.html

    想像だけ飛躍してもしょうがないので、叩き台として実際に動くパッチを作って近いうちにアップしたいと思ってます。

     
  • syat

    syat - 2009-12-06

    パッチ4。共通設定のプラグインタブ。DLLプラグイン(仮)

     
  • syat

    syat - 2009-12-06

    下から2行目の右端にプラグインコマンド用アイコンを追加

     
  • syat

    syat - 2009-12-06

    サンプル詰め合わせ(Rubyアウトライン・Rubyインデント・DLLサンプル)

     
  • syat

    syat - 2009-12-06

    まず謝らなければいけないのは、今まで何個かパッチをアップロードしましたが、ファイルに抜けがあり、おそらくコンパイルも通っていなかったであろうことに、今さら気付きました。大変失礼いたしました。
    どうやら新しく追加したソースは、TortoiseSVNで「追加」コマンドをしないとパッチに含めてくれないらしく…泣。
    今日アップしたものは、ちゃんとチェックしたので大丈夫! おそらく;
     WSH_Plugin_U4.patch

    主な変更点は、
    ・プラグイン導入方法の変更…plugins配下に配置したあと、共通設定の「プラグイン」タブで「新規プラグインの追加」ボタンを押して一個ずつインストールする。新しいプラグインは、以降開いたウィンドウで有効になる。
     なお当初はControlProcessでインストールをやろうと思っていましたが、ControlProcessの初期化でユーザ入力待ちなどで時間を食うと、NormalProcessがビジーエラーを出してしまい、駄目でした。
    ・プラグインのID…GUIDでも良いですが、今のところ63文字までの任意の文字列を許容しています。長さに気をつければ、Javaのパッケージ名風IDも可です。
    ・DLLプラグイン…おまけ程度で作ってみました。定義ファイルに記述された関数をDLLから探して呼び出します。エディタ本体とのデータのやり取りを一切作っていないので実用性ありません。
     WSHのインタフェースオブジェクトを渡そうかと思いましたが、WSHと同じことをDLLでやっても意味ないと思い、「DLLでなければできないこと」が見えるまでは当分放置したいところ。

    自分のイメージしていたものはこれで大体作り終わりました。細かい部分はまだいくつかありますけど。

     
  • syat

    syat - 2010-01-09

    パッチ5。WSHをメモリに保持る機能。若干のブラッシュアップ

     
  • syat

    syat - 2010-01-09

    パッチ5に対応したサンプル詰め合わせ。

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.