「.NETプラグイン開発 テキスト操作編」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
MSY-07 (トーク | 投稿記録)
機種依存記号を修正
MSY-07 (トーク | 投稿記録)
単語の修正
 
(同じ利用者による、間の1版が非表示)
3行目: 3行目:


== テキスト操作 ==
== テキスト操作 ==
プラグインでやる意味は非常に薄いのですが、マクロと同じことをやってみます。<br>
プラグインでやる意味は非常に薄いのですが、マクロと同じことをやってみます。Mery に標準で同梱されている「昇順で並べ替え」をプラグインで実装します。
Mery に標準で同梱されている「昇順で並べ替え」をプラグインで実装します。<br>
 
<br>
OnCommand に以下のコードを貼り付けて、ビルドし、Mery で実行します。
OnCommand に以下のコードを貼り付けて、ビルドし、Mery で実行します。


28行目: 27行目:
</syntaxhighlight>
</syntaxhighlight>


(1) は後の節で説明します。<br>
(1) は後の節で説明します。
(2) はマクロでの「ActiveDocument.Text」による取得と同じです。<br>
 
(3)~(5) はただの C# のコードですが、分割、ソート、マージと元のマクロと同じことをしているだけです。<br>
(2) はマクロでの「ActiveDocument.Text」による取得と同じです。
(6) は「ActiveDocument.Text」にテキストを設定するのと同じです。<br>
 
<br>
(3)~(5) はただの C# のコードですが、分割、ソート、マージと元のマクロと同じことをしているだけです。
見てわかるように、マクロ上では Text 一つのプロパティだったものが、それぞれ Set / Get で分かれています。<br>
 
これは Set / Get が明確にわかるように、という意味以上に、GetText が高コスト(重い)処理であることが理由です。<br>
(6) は「ActiveDocument.Text」にテキストを設定するのと同じです。
内部的には「GetLine()」を行数分繰り返しています(API の制約)<br>
 
<br>
見てわかるように、マクロ上では Text 一つのプロパティだったものが、それぞれ Set / Get で分かれています。これは Set / Get が明確にわかるように、という意味以上に、GetText が高コスト(重い)処理であることが理由です。内部的には「GetLine()」を行数分繰り返しています(API の制約)。
プラグインといえど、気をつけないとあっという間に遅いものとなってしまうことに注意が必要です。<br>
 
プラグインといえど、気をつけないとあっという間に遅いものとなってしまうことに注意が必要です。


== プラグインのアクセスの基本 ==
== プラグインのアクセスの基本 ==
44行目: 44行目:
var editor = new Editor(hWnd);
var editor = new Editor(hWnd);
</syntaxhighlight>
</syntaxhighlight>
ですが、この中で hWnd は OnCommand の引数で、自動で渡されるハンドルです。<br>
 
これは「コマンドが実行された Editor のハンドル」です。<br>
ですが、この中で hWnd は OnCommand の引数で、自動で渡されるハンドルです。これは「コマンドが実行された Editor のハンドル」です。
<br>
 
プラグインではマクロのように Editors -> Editor -> Documents -> Document のように独立したオブジェクトになっておらず、直接アクセスすることもできません。<br>
プラグインではマクロのように Editors -> Editor -> Documents -> Document のように独立したオブジェクトになっておらず、直接アクセスすることもできません。プラグインでの基本的なアクセス単位は全て「Editor」に対してとなります。その時の操作は常に「ActiveDocument」への操作となります。
プラグインでの基本的なアクセス単位は全て「Editor」に対してとなります。<br>
 
その時の操作は常に「ActiveDocument」への操作となります。
では複数のタブがある場合に、別のタブを操作するにはどうするかと言えば、ActiveDocument の切り替え、つまり処理対象のタブをアクティブにします。Mery.DotNetLib.Editor.SetActiveDocument() というメソッドが用意されているので、これで別のタブをアクティブにし処理をします。元の状態に戻す必要があるならば、最初のアクティブなタブを覚えておき、最後に戻してあげる必要があります。
<br>
 
では複数のタブがある場合に、別のタブを操作するにはどうするかと言えば、ActiveDocument の切り替え、つまり処理対象のタブをアクティブにします。<br>
このように、マクロとプラグインではアクセスの単位が異なります。マクロで用意されている機能のほとんどはプラグインでも利用可能ですが、その使用方法には違いがあることに注意してください(さらに、マクロで提供されていてプラグインで提供されていない機能もあるので、プラグインも万能ではありません)。
Mery.DotNetLib.Editor.SetActiveDocument() というメソッドが用意されているので、これで別のタブをアクティブにし処理をします。<br>
元の状態に戻す必要があるならば、最初のアクティブなタブを覚えておき、最後に戻してあげる必要があります。<br>
<br>
このように、マクロとプラグインではアクセスの単位が異なります。<br>
マクロで用意されている機能のほとんどはプラグインでも利用可能ですが、その使用方法には違いがあることに注意してください。<br>
(さらに、マクロで提供されていてプラグインで提供されていない機能もあるので、プラグインも万能ではありません)


== タブ操作 ==
== タブ操作 ==
全タブへの操作のサンプルを書いてみます。<br>
全タブへの操作のサンプルを書いてみます。


<syntaxhighlight lang="csharp">
<syntaxhighlight lang="csharp">
88行目: 82行目:
</syntaxhighlight>
</syntaxhighlight>


複数のタブを開いて実行してみてください。<br>
複数のタブを開いて実行してみてください。全てのタブの合計文字数が表示されるはずです。
全てのタブの合計文字数が表示されるはずです。<br>
 
<br>
(3) で N 個のタブを開いているのがわかります。インデックスは 0 始まりで N-1 までなので、それに合わせてループし (4) でアクティブ化します。(5) でタブ内の全文字数を取得し、合算しています。マクロであれば、ActiveDocument.Text.length と表現するため、editor.GetText().Length としたくなりますが、上で書いているように GetText() は重い処理となるため専用の GetLength() を使用しています(もし興味があれば、非常にでかいテキストに対し実行して、違いを確認してみてください。10 万行を超えてくると違いが顕著になります)。
(3) で N 個のタブを開いているのがわかります。<br>
 
インデックスは 0 始まりで N-1 までなので、それに合わせてループし (4) でアクティブ化します。<br>
実行してみて気づくことがあります。それはパタパタとタブの切り替えが見えてしまうことです。プラグインにおける弱点の 1 つがこれで、マクロであればアクティブ化が必要ないためこのようなことがないのですが、プラグインでは常にアクティブ化を意識する必要があり、結果切り替えが見えてしまいます。マクロにおける window.Redraw に該当する Editor.SetRedraw() が存在するため、(1)と(2)の間に editor.SetRedraw(false); を、(6)と(7)の間に editor.SetRedraw(true); を入れてみてください。実行してみると、パタパタしなくなることがわかります。
(5) でタブ内の全文字数を取得し、合算しています。<br>
 
マクロであれば、ActiveDocument.Text.length と表現するため、editor.GetText().Length としたくなりますが、上で書いているように GetText() は重い処理となるため専用の GetLength() を使用しています。<br>
ただし注意事項として、マクロの Redraw は true にしなくとも勝手に再描画されるようになりますが、プラグインの場合はなりません。意図的に true にしてあげないと描画が止まり、Mery が固まったように見えてしまいます。万全を期すならば、try - finally で確実に描画を再開できるようにする必要があります。
(もし興味があれば、非常にでかいテキストに対し実行して、違いを確認してみてください。10 万行を超えてくると違いが顕著になります)<br>
 
<br>
実行してみて気づくことがあります。<br>
それはパタパタとタブの切り替えが見えてしまうことです。<br>
プラグインにおける弱点の 1 つがこれで、マクロであればアクティブ化が必要ないためこのようなことがないのですが、プラグインでは常にアクティブ化を意識する必要があり、結果切り替えが見えてしまいます。<br>
マクロにおける window.Redraw に該当する Editor.SetRedraw() が存在するため、(1)と(2)の間に editor.SetRedraw(false); を、(6)と(7)の間に editor.SetRedraw(true); を入れてみてください。<br>
実行してみると、パタパタしなくなることがわかります。<br>
<br>
ただし注意点として、マクロの Redraw は true にしなくとも勝手に再描画されるようになりますが、プラグインの場合はなりません。<br>
意図的に true にしてあげないと描画が止まり、Mery が固まったように見えてしまいます。<br>
万全を期すならば、try - finally で確実に描画を再開できるようにする必要があります。<br>
<br>
プラグインはマクロより危険な状態になりやすいため、扱いには気をつけましょう。
プラグインはマクロより危険な状態になりやすいため、扱いには気をつけましょう。

2024年9月2日 (月) 02:15時点における最新版

概要[編集]

基本的なテキスト操作、およびプラグインからの操作の考え方です。

テキスト操作[編集]

プラグインでやる意味は非常に薄いのですが、マクロと同じことをやってみます。Mery に標準で同梱されている「昇順で並べ替え」をプラグインで実装します。

OnCommand に以下のコードを貼り付けて、ビルドし、Mery で実行します。

// (1)コマンドが実行されたエディタのハンドルから、エディタオブジェクトを生成
var editor = new Editor(hWnd);

// (2)エディタでアクティブなドキュメントからテキストを取得
var text = editor.GetText();

// (3)テキストを行単位に分割
var array = text.Split(new char[] { '\n' });

// (4)行を昇順ソート
Array.Sort(array, StringComparer.CurrentCulture);

// (5)ソートした結果をマージ
text = string.Join("\n", array);

// (6)結果をアクティブなドキュメントに対して反映
editor.SetText(text);

(1) は後の節で説明します。

(2) はマクロでの「ActiveDocument.Text」による取得と同じです。

(3)~(5) はただの C# のコードですが、分割、ソート、マージと元のマクロと同じことをしているだけです。

(6) は「ActiveDocument.Text」にテキストを設定するのと同じです。

見てわかるように、マクロ上では Text 一つのプロパティだったものが、それぞれ Set / Get で分かれています。これは Set / Get が明確にわかるように、という意味以上に、GetText が高コスト(重い)処理であることが理由です。内部的には「GetLine()」を行数分繰り返しています(API の制約)。

プラグインといえど、気をつけないとあっという間に遅いものとなってしまうことに注意が必要です。

プラグインのアクセスの基本[編集]

// (1)コマンドが実行されたエディタのハンドルから、エディタオブジェクトを生成
var editor = new Editor(hWnd);

ですが、この中で hWnd は OnCommand の引数で、自動で渡されるハンドルです。これは「コマンドが実行された Editor のハンドル」です。

プラグインではマクロのように Editors -> Editor -> Documents -> Document のように独立したオブジェクトになっておらず、直接アクセスすることもできません。プラグインでの基本的なアクセス単位は全て「Editor」に対してとなります。その時の操作は常に「ActiveDocument」への操作となります。

では複数のタブがある場合に、別のタブを操作するにはどうするかと言えば、ActiveDocument の切り替え、つまり処理対象のタブをアクティブにします。Mery.DotNetLib.Editor.SetActiveDocument() というメソッドが用意されているので、これで別のタブをアクティブにし処理をします。元の状態に戻す必要があるならば、最初のアクティブなタブを覚えておき、最後に戻してあげる必要があります。

このように、マクロとプラグインではアクセスの単位が異なります。マクロで用意されている機能のほとんどはプラグインでも利用可能ですが、その使用方法には違いがあることに注意してください(さらに、マクロで提供されていてプラグインで提供されていない機能もあるので、プラグインも万能ではありません)。

タブ操作[編集]

全タブへの操作のサンプルを書いてみます。

// (1)コマンドが実行されたエディタのハンドルから、エディタオブジェクトを生成
var editor = new Editor(hWnd);

// (2)現在アクティブなタブのインデックス番号を取得
int activedIndex = editor.GetActiveDocumentIndex();

// (3)Editor 内の全タブ数を取得
int tabCount = editor.GetDocumentCount();

int total = 0;
for (int i = 0; i < tabCount; i++) {
    // (4)処理対象のタブをアクティブ化
    editor.SetActiveDocument(i);

    // (5)タブ内の文字数を取得して、全文字数へ加算
    total += editor.GetLength(true);
}

// (6)最初にアクティブだったタブをアクティブ化
editor.SetActiveDocument(activedIndex);

// (7)結果の表示
MessageBox.Show("全タブの文字数:" + total);

複数のタブを開いて実行してみてください。全てのタブの合計文字数が表示されるはずです。

(3) で N 個のタブを開いているのがわかります。インデックスは 0 始まりで N-1 までなので、それに合わせてループし (4) でアクティブ化します。(5) でタブ内の全文字数を取得し、合算しています。マクロであれば、ActiveDocument.Text.length と表現するため、editor.GetText().Length としたくなりますが、上で書いているように GetText() は重い処理となるため専用の GetLength() を使用しています(もし興味があれば、非常にでかいテキストに対し実行して、違いを確認してみてください。10 万行を超えてくると違いが顕著になります)。

実行してみて気づくことがあります。それはパタパタとタブの切り替えが見えてしまうことです。プラグインにおける弱点の 1 つがこれで、マクロであればアクティブ化が必要ないためこのようなことがないのですが、プラグインでは常にアクティブ化を意識する必要があり、結果切り替えが見えてしまいます。マクロにおける window.Redraw に該当する Editor.SetRedraw() が存在するため、(1)と(2)の間に editor.SetRedraw(false); を、(6)と(7)の間に editor.SetRedraw(true); を入れてみてください。実行してみると、パタパタしなくなることがわかります。

ただし注意事項として、マクロの Redraw は true にしなくとも勝手に再描画されるようになりますが、プラグインの場合はなりません。意図的に true にしてあげないと描画が止まり、Mery が固まったように見えてしまいます。万全を期すならば、try - finally で確実に描画を再開できるようにする必要があります。

プラグインはマクロより危険な状態になりやすいため、扱いには気をつけましょう。

スポンサーリンク