MikoScript は、簡単なツールの作成はもちろんのこと、本格的なオブジェクト指向
プログラミングも手軽にできるスクリプト言語です。
本エディタでは、この MikoScript の汎用部に、本エディタ専用のオブジェクトと関数を
組み込んで特化しています。この汎用部に関しては、
MikoScript のホームページをご覧ください。ここでは、特化部について説明します。
特化部には、
・Epsaly オブジェクト
・各種リレー型関数
があります。
Epsaly オブジェクトは、スクリプトから本エディタにアクセスする時に使います。
また、各種リレー型関数は、主に、編集テキスト内の位置を規定する時に使います。
これらの詳細は、後述します。
「リレー型関数」自身の仕様に関しては、
MikoScript のホームページの関連箇所をご覧ください。
本エディタ用の MikoScript では、print 文の出力先が、
本エディタの「スクリプトコンソールウィンドウ」に
なっています。そのため、例えば、
print "Hello, world.";
を実行すると、そのウィンドウに「Hello, world.」の1行がプリントされます。
本スクリプトのグローバルスコープは、一度生成されると、
本エディタが終了するまで、存続します。(「補足説明」参照 )
そのため、例えば、あるスクリプトで、
::GlobalVar = 123;
を実行すると、このスクリプトの終了後も、この GlobalVar 変数は、
存続しているので、別のスクリプトの実行時に、この変数にアクセスできます。
テキスト編集に関連する ::Clipboard オブジェクトや各種文字列操作関数等は、
本エディタ用の特化部ではなく、MikoScript の汎用部に実装されています。
そのため、本ヘルプには、その説明はありません。
Epsaly オブジェクトは、MikoScript から、本エディタにアクセスするための 各種のメンバー関数が装備された組み込みオブジェクトです。 このオブジェクトは、クラスとして使用するのではなく、 そのオブジェクト単体で使用するようになっています。 そのため、そのインスタンスやコピーを生成する必要はありません。
Epsaly オブジェクトは、MikoScript のグローバルスコープに登録されています。 このメンバー関数をコールするには、
::Epsaly.関数名( 引数列 )
という書式になります。この他、状況に応じて、いろいろと簡便な書式も利用できます。 これについては後述します。
Epsaly オブジェクトのメンバー関数は、次のように、3グループに分類して説明しています。
(1)現編集ウィンドウを対象とする関数 |
(2)全編集ウィンドウ共通の関数 |
(3)プロジェクト関連の関数 |
ActiveX スクリプトにも、Epsaly オブジェクトが組み込まれますが、それと、 この MikoScript 用の Epsaly オブジェクトとの互換性はありません。 それぞれ、独自の仕様になっています。
編集テキスト内の位置を規定するパラメータには、論理行番号、表示行番号、桁番号、
文字数、文字コードインデックス、単語数、X座標、などがあります。
これらのパラメータの値は、テキストの先頭からの場合や、ある行の先頭から、あるいは、
現在位置からの場合等があります。また、これらには、いろいろな組み合わせが
想定されます。
本スクリプトでは、このようなパラメータを、各種の関数(カーソル移動、範囲選択、削除、
部分テキストの取得等)で、共通した仕様で柔軟に使えるようにするために、
専用のリレー型関数群を装備しています。
このリレー型関数の主な機能は、その対象に、編集テキスト内の位置を規定するパラメータの
種別を示す属性を設定することです。例えば、'LineNo というリレー型関数は、
「行番号」の属性を、その対象に設定します。これを使って、
100'LineNo
とすれば、「行番号」の属性を、整数値 100 に設定します。
これで、100 行目の位置を表わす値になります。
また、「桁番号」の属性を設定する 'Column というリレー型関数を使って、
20'Column
とすれば、20 桁目の位置を表わす値になります。これらを組み合せて、
100'LineNo, 20'Column
とすれば、100 行 20 桁の位置を表わすことができます。
このリレー型関数のなかには、その対象が不要なものや、省略可能なものもあります。
例えば、
'TextTop
は、「テキストの先頭」を表わします。また、
'LineNo
は、現カーソル行の「行番号」を表わします。
次に、その他のいろいろな例を示します。
現位置から 5 文字先:
5'DKn
次の表示行の行頭:
+1'VLn, 'LineTop
前の論理行の行末から 3 単語前:
-1'LLn, 'LineEnd, -3'DWn
テキスト先頭からの文字コード数が 1200 の位置:
1200'Ci
論理行インデックスが line という変数の値で、
その行頭からのX座標が x という変数の値になる位置:
line'LLi, x'Xc
このような表記で規定する位置は、Epsaly オブジェクトのメンバー関数の引数に使います。
例えば、カーソル移動では、
::Epsaly.MoveTo( 100'LineNo, 20'Column );
のようになります。これは、100 行 20 桁目の位置を、カーソルの移動先として
指定した例です。
また、文字範囲の選択で、例えば、2 行前の表示行の先頭を、その始点に指定する場合は、
::Epsaly.SelectChars( -2'VLn, 'LineTop );
のようになります。
この形態での引数の個数は、0〜8 個の範囲で任意です。
当メンバー関数の引数で、このように、リレー型関数を使って、編集テキスト内の位置を
指定する際には、「現位置」というものを意識しておく必要があります。
この「現位置」は、最初、現カーソル位置になり、以降、各引数のリレー型関数の実行で、
順次更新され、最終の「現位置」が、当メンバー関数の目標位置になります。
例えば、
+1'LLn, 'LineEnd, -2'DKn
の場合、「現位置」は、最初、現カーソル位置で、以降、次のように変わっていきます。
(1) +1'LLn で、現カーソル行の次の論理行
(2) 'LineEnd で、その行の行末
(3) -2'DKn で、その行末から 2 字前
この最後の時点での「現位置」が、目標位置になります。
この「現位置」の変遷時に、行位置が変わらなければ、「現位置」の行は、
現カーソル行のままです。また、桁位置が変わらなければ、
「現位置」の桁は、現カーソル桁のままです。
メンバー関数によっては、その結果を特別に扱う場合もあります。
また、この変遷時に、「現位置」が、移動できない桁やX座標に指定された場合、
「現位置」は、その時点の行内で移動可能な最寄の桁位置で(一時的に)代替されます。
なお、「現位置」は、フリーカーソル時には、改行コード以降の桁にも移動できます。
「現位置」には、論理行か表示行かの「行種別」も含まれます。
これは、最初、環境設定の行番号欄で選ばれている方になり、以降、
リレー型関数で更新されれば、その方に変わります。この最終結果は、
それに関係するメンバー関数( ::Epsaly.GetLineText() 等 )で参照されます。
リレー型関数で属性が設定された引数を必要とする関数が、属性の無い引数を
受け取ると、通常の処理は行なわずに、null を返します。例えば、
::Epsaly.MoveTo( 20, 8'Column );
では、最初の引数の 20 の値が何を意味するのか不明なので、null が返ります。
また、属性の無い通常の引数と、リレー型関数を使う引数の両方が必要な関数もあります。例えば、
::Epsaly.GetLineCond( 2, 100'LineNo );
では、最初の引数は、テキスト内の位置を規定するのではなく、取得する状態の種類を指定しています。
リレー型関数で設定された属性は、通常の演算には全く影響しません。
例えば、あまり意味はありませんが、
120'LineNo + 40'Column
とすることもできます。ちなみに、この結果は、160 になります。また、
print 'LineNo, 'Column;
を実行すると、スクリプトコンソールウィンドウに、
現カーソル位置の行番号と桁番号がプリントされます。
各リレー型関数については、以下で詳しく説明します。
次に、MikoScript でのプログラム例を示します。
クリップボードのテキストの各行頭に「 > 」を付けた文字列を 現カーソル位置に挿入する。
text = ::Clipboard.GetText(); if( text ) ::Epsaly.Insert( text'subst( "@(.*\n|.+$)", "> @1" ) );
選択されているテキスト(矩形範囲も可)内で、 正規表現の「検索文字列」に一致する全ての箇所を「置換文字列」に置き換える。
if( ::Epsaly.GetSelType() <= 0 ) // 範囲選択なし? return; if(( FindString = ::Input( "検索文字列" )) == null ) return; if(( ReplString = ::Input( "置換文字列" )) == null ) return; ::Epsaly.SetSelText( ::Epsaly.GetSelText()'subst( FindString, ReplString ) );
現在開いている編集ファイルの一覧を、フルパス名で、 スクリプトコンソールウィンドウにプリントする。
for( i = 0 ; ( id = ::Epsaly.GetWindowId( i )) != 0 ; i++ ) print id's(2), ::Epsaly.GetFileName( id );
スクリプトを記述する際、Epsaly オブジェクトを使う箇所が多くなる場合があります。 例えば、次のスクリプトは、現編集テキスト内の全ての空白行を除去するプログラムですが、 ここでは、::Epsaly を 6 箇所で使っています。
::Epsaly.UndoBlockBegin(); ::Epsaly.MoveTo( 'TextTop ); ::Epsaly.SetFindCond( $"(^[ \t]*\n)+", "RGE" ); while( ::Epsaly.FindFwd() >= 0 ) ::Epsaly.Delete(); ::Epsaly.UndoBlockEnd();
このように、逐一、::Epsaly と表記するのは、ちょっと面倒なので、 MikoScript では、いろいろな対応ができるようになっています。 そのうちの主なものを3通り、次に示します。
'AddScope で、現関数のローカルスコープ内に、::Epsaly オブジェクト内のスコープを 追加します。そうすれば、::Epsaly のメンバー関数は、あたかも、現ローカルスコープ内に あるかのようにアクセスできます。この場合、上記のスクリプトは、次のように書けます。
'AddScope( ::Epsaly ); UndoBlockBegin(); MoveTo( 'TextTop ); SetFindCond( $"(^[ \t]*\n)+", "RGE" ); while( FindFwd() >= 0 ) Delete(); UndoBlockEnd();
scope 構文で、現メンバースコープを一時的に、::Epsaly オブジェクトのスコープに 変えます。そうすれば、::Epsaly のメンバー関数は、あたかも、現メンバースコープ内に あるかのようにアクセスできます。この場合、上記のスクリプトは、次のように書けます。
scope ::Epsaly { .UndoBlockBegin(); .MoveTo( 'TextTop ); .SetFindCond( $"(^[ \t]*\n)+", "RGE" ); while( .FindFwd() >= 0 ) .Delete(); .UndoBlockEnd(); }
::Epsaly への参照を適当な変数に代入して、それで、::Epsaly オブジェクトに アクセスします。この場合、上記のスクリプトは、次のように書けます。
e := ::Epsaly; // ※ e.UndoBlockBegin(); e.MoveTo( 'TextTop ); e.SetFindCond( $"(^[ \t]*\n)+", "RGE" ); while( e.FindFwd() >= 0 ) e.Delete(); e.UndoBlockEnd();
≪注意≫ ※ 印の行を、
e = ::Epsaly;
としてしまうと、::Epsaly の複製が代入されるので、
処理時間とメモリーの浪費になります。
選択テキスト(矩形範囲も可)内の半角空白と TAB を除去する。
'AddScope( ::Epsaly ); if( GetSelType() > 0 ) SetSelText( GetSelText()'subst( $"[ \t]+", "" ) );
現編集テキスト内で、連続する複数の空行を1つの空行にまとめる。
'AddScope( ::Epsaly ); UndoBlockBegin(); MoveTo( 'TextTop ); SetFindCond( $"(^[ \t]*\n)+", "RGE" ); while( FindFwd() >= 0 ) Insert( "\r\n" ); UndoBlockEnd();
選択テキスト(矩形範囲も可)内の各行の選択部の先頭に、括弧付きの連番を付加する。
'AddScope( ::Epsaly ); switch( GetSelType() ) { case 1: case 2: eol = ""; break; case 3: eol = "\r\n"; break; default: return; } text = ""; ( MinLi, MaxLi ) = GetSelRange( 0 ); i = 1; for( Li = MinLi ; Li <= MaxLi ; Li++ ) text += "(%d)"'fmt( i++ ) + GetSelText( Li ) + eol; SetSelText( text );
Epsaly 用の MikoScript は、DLL(ダイナミック・リンク・ライブラリ)として、 実装されています。これは最初、Epsaly エディタ本体には、リンクされていません。 MikoScript を始めて起動した時に、動的にリンクされます。そのため、 最初の MikoScript の起動には、若干時間がかかります。しかし、2回目以降は、 高速に起動されます。もし、MikoScript を最初から全く使わなければ、 このDLLはリンクされないので、その分のメモリー等のリソースが、節約されます。
本エディタでは、ファイルの拡張子が、.mc の場合、MikoScript のソースファイル として扱うということは、既に述べましたが、これは、 Windows に登録されている拡張子の関連付けとは無関係です。 つまり、拡張子の関連付けがどのようになっていても、 本エディタでは、.mc を、MikoScript のソースとして扱います。 この扱いが、他のアプリケーションに影響することはありません。