メリーの範囲選択の起点と終点に目印をつけたい
-
Mery: 3.7.13 (x86, Portable)
Oniguruma: 6.9.10
C/Migemo: 1.3
Tidy: 5.8.0
Hunspell: 1.7.1
アウトライン: 3.2.2 (Outline.dll)
アウトライン: 3.2.2 (AlphaBlend.dll)
OS: Windows 10 (Version 22H2, OS Build 19045.5608, 64-bit Edition)メリーの範囲選択の起点と終点に目印をつけたい
現状 とても便利に使わせてもらってます
この機能のないテキストエディタは使う気になれないほどUSBゲームコントローラで操作していてキーボードのシフトカーソルで選択などがすごく不便です 持ち帰る手間が発生します
アンドロイドでもこの方式にすると範囲選択がすごくらくなのにと思ってます本題です
ただし 範囲選択がバグかなにかでうまくできないことがわりとあります その場合 別の始点と終点にかえることで
リセットできますそのために 始点A 終点Bに適当な目印 アイコンのポップアップだったり なにかそれとわかりやすいものをつけていただけると
助かります 先述のバグなのかよめない状況もハッキリしやすいというのもありますマルチカーソルは使ってないですが
その辺の兼ね合いもどういう仕様にするのがいいかわからないですけど| いお | 返信 -
ご報告ありがとうございます。
> ただし 範囲選択がバグかなにかでうまくできないことがわりとあります その場合 別の始点と終点にかえることで
> リセットできます範囲選択の動作に不具合があるとのことですが、具体的にどんな操作をしたときに問題が発生するのか教えていただけると、調査がしやすくなります。
> そのために 始点A 終点Bに適当な目印 アイコンのポップアップだったり なにかそれとわかりやすいものをつけていただけると
> 助かります 先述のバグなのかよめない状況もハッキリしやすいというのもあります以前にも同じ内容のご投稿をいただいてますね。
【参考】文字列範囲選択機能の始点終点目印希望
https://www.haijin-boys.com/discussions/8005回答としては、だいたい上記の内容と重なりますが、アイコンのポップアップみたいな特殊な仕様を標準機能で実装するのは難しいかと思います。
ただ、ちょっと進展がありまして、プラグインなら実現できるかもしれません。
具体的には、Ver 3.7.2 で追加されたプラグイン API の
Editor_DevToViewやEditor_ViewToDevメソッドを使うことで、デバイス座標と表示座標の相互変換ができるようになりました。この機能を使えば、アイコンをポップアップするプラグインを作ることができると思います。
ちなみに、開発環境の Delphi Community Edition は無料で利用できるので、プラグイン開発に興味があれば、ぜひ試してみてくださいね。
もし実装が必要で、どうしても自分でやるのが難しい場合は、クラウドソーシング サービスを活用する方法もあります。
【参考】クラウドソーシング サービス
https://www.haijin-boys.com/software/mery/mery-3-7-0#56ちなみに、私個人としてはカスタマイズやプラグインの開発依頼を受け付けていないので、その点だけご了承くださいね。
【参考】サポート対象外の内容について
https://www.haijin-boys.com/discussion-guidelines#7| Kuro | 返信 -
コードはまるでわかりませんがクロードと悪戦苦闘しながらようやく泥臭い方法で始点がわかるものができました よかったら使ってくださいまた 改良点などあれば記載願います
#Requires Mery Macro
/* ============================================================
ファイル名を変更する場合は、下記 BASE_NAME を
「js/iniファイルの拡張子より前の部分」と必ず同じ文字列に
書き換えてください。BASE_NAME と実際のファイル名が一致して
いる限り、このマクロと同じフォルダの ini ファイルが自動的に
読み込まれます。
============================================================ */
var BASE_NAME = "始点マーカー選択コピー";/* このマクロファイル自身の場所を基準に ini パスを組み立てます。
Mery のマクロ実行環境では自分自身のパスを直接取得する手段が
ないため、下記 SCRIPT_DIR に、js/ini を置いているフォルダの
絶対パスを指定してください。 */
var SCRIPT_DIR = "Z:\\MeryPortable-2.8.6\\Macros"; // js/ini を置いているフォルダvar INI_PATH = SCRIPT_DIR + "\\" + BASE_NAME + ".ini";
var DEFAULT_MARKER = "【始始始】";function writeIniUtf8(path, marker) {
// 文字コード不一致(文字化け)を避けるため、明示的に UTF-8 で書き込む
var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 2; // adTypeText
stream.Charset = "UTF-8";
stream.Open();
stream.WriteText("Marker=" + marker + "\r\n");
stream.SaveToFile(path, 2); // adSaveCreateOverWrite
stream.Close();
}function readMarkerFromIni(path, defaultMarker) {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var marker = defaultMarker;if (!fso.FileExists(path)) {
// ini が無ければデフォルトのマーカーで新規作成する(UTF-8固定)
writeIniUtf8(path, defaultMarker);
return defaultMarker;
}// 文字コード不一致(文字化け)を避けるため、明示的に UTF-8 で読み込む
var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 2; // adTypeText
stream.Charset = "UTF-8";
stream.Open();
stream.LoadFromFile(path);
var content = stream.ReadText();
stream.Close();// 先頭に BOM が残っている場合は除去する
if (content.charCodeAt(0) === 0xFEFF) {
content = content.substr(1);
}var lines = content.split("\n");
for (var i = 0; i < lines.length; i++) {
var line = lines[i].replace(/[\r\n]+$/, "");
if (line.indexOf("Marker=") === 0) {
marker = line.substr(7);
break;
}
}if (marker === "") {
marker = defaultMarker;
}
return marker;
}var MARK = readMarkerFromIni(INI_PATH, DEFAULT_MARKER);
/* ------------------------------------------------------------
安全装置1:文字化け等で MARK が空になっていた場合、
無限ループの原因になるため、ここで強制的にデフォルトへ
復旧し、ini ファイルも UTF-8 で書き直して自己修復する。
------------------------------------------------------------ */
if (MARK === "" || MARK === null) {
MARK = DEFAULT_MARKER;
writeIniUtf8(INI_PATH, DEFAULT_MARKER);
}/* ============================================================
status には「マーカー挿入済みかどうか」と、挿入時点の
おおよその位置(参考値。複数マーカーが見つかった場合に
直近作成分を選ぶための目安として使用。厳密な座標としては
使用しない)を保持します。
============================================================ */
var a = status.split(":");if (a.length > 1 && a[0] == "MARK_SET" && !isNaN(a[1])) {
/* ---------------- 2回目のF5:選択してコピー ---------------- */
var refPos = parseInt(a[1], 10); // 挿入時点の参考位置
var curPos = document.selection.GetActivePos();// 文書先頭へ移動し、全文検索の準備(ActivePos→AnchorPosの順で設定)
document.selection.SetActivePos(0);
document.selection.SetAnchorPos(0);var foundPositions = [];
var SAFETY_LIMIT = 2000; // 異常時の無限ループを防ぐための上限回数
var loopCount = 0;
var lastEndPos = -1;while (document.selection.Find(MARK, meFindNext) === 1) {
var a1 = document.selection.GetAnchorPos();
var a2 = document.selection.GetActivePos();
var startPos = Math.min(a1, a2);
var endPos = Math.max(a1, a2);// 安全装置2:カーソルが前回と同じ位置から進んでいない場合は
// ループが空回りしている(=異常状態)とみなして強制停止する
if (endPos <= lastEndPos) {
break;
}
lastEndPos = endPos;foundPositions.push(startPos);
// 次の検索はマッチ末尾から続行するため、ActivePos→AnchorPosの順で
// マッチ末尾に揃えてから次の Find を呼ぶ
document.selection.SetActivePos(endPos);
document.selection.SetAnchorPos(endPos);loopCount++;
if (loopCount >= SAFETY_LIMIT) {
// 安全装置3:想定外に大量ヒットした場合も強制停止する
break;
}
}if (foundPositions.length === 0) {
// マーカーが見つからない場合は何もしない
status = "";
} else {
// 参考位置に最も近いマーカーを「直近作成分」として優先する
var chosen = foundPositions[0];
var minDiff = Math.abs(foundPositions[0] - refPos);
for (var i = 1; i < foundPositions.length; i++) {
var diff = Math.abs(foundPositions[i] - refPos);
if (diff < minDiff) {
minDiff = diff;
chosen = foundPositions[i];
}
}var markStart = chosen;
var markEnd = chosen + MARK.length;// マーカー文字列を削除(ActivePos→AnchorPosの順で設定するのが正しい仕様)
document.selection.SetActivePos(markEnd);
document.selection.SetAnchorPos(markStart);
document.selection.Delete();// 削除に伴う後方位置のズレを補正
if (curPos > markStart) {
curPos -= MARK.length;
}// 始点(markStart)~現在位置(curPos)を範囲選択(ActivePos→AnchorPosの順)
document.selection.SetActivePos(curPos);
document.selection.SetAnchorPos(markStart);// 選択範囲をクリップボードへ格納
if (document.selection.Text !== "") {
window.clipboardData.setData("Text", document.selection.Text);
}status = "";
}} else {
/* ---------------- 1回目のF5:始点マーカー挿入 ---------------- */
var insertPos = document.selection.GetActivePos();
document.selection.Text = MARK;// 参考値として挿入位置を記録(正確な座標としては使用しない)
status = "MARK_SET:" + insertPos;
}> ご報告ありがとうございます。
>
> > ただし 範囲選択がバグかなにかでうまくできないことがわりとあります その場合 別の始点と終点にかえることで
> > リセットできます
>
> 範囲選択の動作に不具合があるとのことですが、具体的にどんな操作をしたときに問題が発生するのか教えていただけると、調査がしやすくなります。
>
> > そのために 始点A 終点Bに適当な目印 アイコンのポップアップだったり なにかそれとわかりやすいものをつけていただけると
> > 助かります 先述のバグなのかよめない状況もハッキリしやすいというのもあります
>
> 以前にも同じ内容のご投稿をいただいてますね。
>
> 【参考】文字列範囲選択機能の始点終点目印希望
> https://www.haijin-boys.com/discussions/8005
>
> 回答としては、だいたい上記の内容と重なりますが、アイコンのポップアップみたいな特殊な仕様を標準機能で実装するのは難しいかと思います。
>
> ただ、ちょっと進展がありまして、プラグインなら実現できるかもしれません。
>
> 具体的には、Ver 3.7.2 で追加されたプラグイン API の`Editor_DevToView`や`Editor_ViewToDev`メソッドを使うことで、デバイス座標と表示座標の相互変換ができるようになりました。
>
> この機能を使えば、アイコンをポップアップするプラグインを作ることができると思います。
>
> ちなみに、開発環境の Delphi Community Edition は無料で利用できるので、プラグイン開発に興味があれば、ぜひ試してみてくださいね。
>
> もし実装が必要で、どうしても自分でやるのが難しい場合は、クラウドソーシング サービスを活用する方法もあります。
>
> 【参考】クラウドソーシング サービス
> https://www.haijin-boys.com/software/mery/mery-3-7-0#56
>
> ちなみに、私個人としてはカスタマイズやプラグインの開発依頼を受け付けていないので、その点だけご了承くださいね。
>
> 【参考】サポート対象外の内容について
> https://www.haijin-boys.com/discussion-guidelines#7| いお | 返信 -
マーカー文字列を実際に挿入して位置を保持するという発想は面白いですね。
編集しても位置がずれないマーカーとして、うまく実現できていると思います。
Mery のマクロ機能ではブックマークも利用できますが、こちらは行単位なので、ご希望の動作には少し機能不足かもしれませんね。
一応、Mery の標準機能として、[文字の選択を開始] (デフォルトでは F8 キー) という機能があり、Shift キーを押さなくても方向キーだけで選択範囲を操作できます。こちらの機能ではイメージされている操作とは少し違う感じでしょうか?
もともとのご要望は、アイコンのポップアップなどで始点や終点を視覚的に分かるようにしたい、という内容でしたので、Mery 側での対応は難しいと回答させていただきました。ただ、今回のマクロを拝見すると、どのような操作をイメージされていたのか、少し気になりました。
もし今回ご投稿いただいたマクロのような操作を想定されていたのであれば、F8 キーの機能でも近いことができそうな気もします。
それとも、選択範囲とは別に、始点をマーカー文字列として文書内に残しておきたい、という用途なのでしょうか。
ともあれ、マクロでうまく実現できたとのことで安心しました。
| Kuro | 返信