「選択範囲を広げる」の版間の差分
ナビゲーションに移動
検索に移動
マークアップの追加 |
編集の要約なし |
||
| 5行目: | 5行目: | ||
=== 未選択状態での動作: === | === 未選択状態での動作: === | ||
* | * 選択範囲が空の場合、カーソル位置の単語を選択します。 | ||
* | * カーソル位置が括弧だった場合は、括弧の中身を選択します。 | ||
* ドットを検出した場合は、ドットの1つ右の単語まで拡張します。 | |||
=== 選択状態での動作: === | === 選択状態での動作: === | ||
* | * 選択範囲がある場合、選択範囲の前後にある括弧を検出し、その中身を選択します。 | ||
* | * ドットを検出した場合は、ドットの1つ左または右の単語まで拡張します。 | ||
* これらの記号を検出しなかった場合は、単純な選択範囲の拡張を行います。 | |||
* | |||
=== ソースコード: === | === ソースコード: === | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
#title="選択範囲を広げる" | #title = "選択範囲を広げる" | ||
/** | |||
* 選択範囲を広げるためのマクロです。 | |||
* | |||
* 選択範囲が空の場合、カーソル位置の単語を選択します。 | |||
* カーソル位置が括弧だった場合は、括弧の中身を選択します。 | |||
* ドットを検出した場合は、ドットの1つ右の単語まで拡張します。 | |||
* | |||
* 選択範囲がある場合、選択範囲の前後にある括弧を検出し、その中身を選択します。 | |||
* ドットを検出した場合は、ドットの1つ左または右の単語まで拡張します。 | |||
* これらの記号を検出しなかった場合は、単純な選択範囲の拡張を行います。 | |||
*/ | |||
BeginUndoGroup(); | BeginUndoGroup(); | ||
Redraw = false; | Redraw = false; | ||
//■括弧の定義(0+2n:開き/1+2n:閉じ) | //■括弧の定義(0+2n:開き/1+2n:閉じ) | ||
var BRACKET = '()<>[]{} | var BRACKET = '()<>[]{}「」『』【】()[]{}〈〉《》〔〕〘〙〚〛〖〗‘’“”'; | ||
var doc = document; | |||
var sel = document.selection; | var sel = document.selection; | ||
var txt = | var txt = document.Text; | ||
function main() { | |||
if (sel.IsEmpty) { | |||
// 未選択の場合 | |||
sel.SelectWord(); | |||
var selChar = sel.Text; | |||
var selCharIndex = BRACKET.indexOf(selChar); | |||
if (selChar.length === 1 && selCharIndex !== -1) { | |||
// 選択文字が括弧記号1文字の場合、括弧の中身を選択 | |||
if (selCharIndex % 2 === 1) { | |||
// 閉じ括弧の場合 | |||
sel.CharLeft(); | |||
var topX = sel.GetTopPointX(mePosLogical); | |||
var topY = sel.GetTopPointY(mePosLogical); | |||
var bottomX = sel.GetBottomPointX(mePosLogical); | |||
var bottomY = sel.GetBottomPointY(mePosLogical); | |||
selectToBracketStart(topX, topY, bottomX, bottomY, selChar); | |||
} else if (selCharIndex % 2 === 0) { | |||
// 開き括弧の場合 | |||
var topX = sel.GetTopPointX(mePosLogical); | |||
var topY = sel.GetTopPointY(mePosLogical); | |||
var bottomX = sel.GetBottomPointX(mePosLogical); | |||
var bottomY = sel.GetBottomPointY(mePosLogical); | |||
var activePos = sel.GetActivePos(); | |||
selectToBracketEnd(topX, topY, bottomX, bottomY, selChar); | |||
if (activePos !== sel.GetActivePos()) { | |||
// 括弧の中身が選択された場合、閉じ括弧も選択する | |||
sel.SetActivePos(sel.GetActivePos() + 1, true); | |||
} | |||
} | |||
} else if (selChar === ".") { | |||
// ドットの場合 | |||
// ドットの1つ右の単語まで拡張 | |||
selectFuncNameToChild(sel.GetActivePos()); | |||
} | |||
} else { | |||
// 選択済みの場合 | |||
// 選択範囲の左右の文字を取得 | |||
var topX = sel.GetTopPointX(mePosLogical); | |||
var topY = sel.GetTopPointY(mePosLogical); | |||
var bottomX = sel.GetBottomPointX(mePosLogical); | |||
var bottomY = sel.GetBottomPointY(mePosLogical); | |||
// 選択範囲の左右の文字を取得 | |||
var leftChar = "dummy"; | |||
if (topX - 2 >= 0) doc.GetLine(topY, meGetLineWithNewLines).charAt(topX - 2); | |||
var rightChar = doc.GetLine(bottomY, meGetLineWithNewLines).charAt(bottomX - 1); | |||
var rightIndex = BRACKET.indexOf(rightChar); | |||
var leftIndex = BRACKET.indexOf(leftChar); | |||
if (rightChar === ".") { | |||
// 選択範囲の右にドットがある場合 | |||
// 末尾方向にドットを検索 | |||
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false); | |||
selectFuncNameToChild(sel.GetActivePos() + 1); | |||
sel.SetAnchorPoint(mePosLogical, topX, topY); | |||
} else if (rightIndex % 2 === 0) { | |||
// 右位置に開き括弧があるかをチェック | |||
// 選択範囲を広げる | |||
selectToBracketEnd(topX, topY, bottomX, bottomY, rightChar); | |||
// 閉じ括弧も選択する | |||
sel.CharRight(true); | |||
} else if (leftChar === ".") { | |||
// 選択範囲の左にドットがある場合 | |||
// 先頭方向にドットを検索 | |||
sel.SetActivePoint(mePosLogical, topX, topY, false); | |||
selectFuncNameToParent(sel.GetActivePos() - 2); | |||
sel.SetAnchorPoint(mePosLogical, bottomX, bottomY); | |||
} else if (rightIndex % 2 === 1) { | |||
// 右位置に閉じ括弧があるかをチェック | |||
// 選択範囲を広げる | |||
selectToBracketStart(topX, topY, bottomX, bottomY, rightChar); | |||
} else if (leftIndex % 2 === 0) { | |||
alert(leftChar) | |||
// 左位置に括弧があるかをチェック | |||
// 選択範囲を広げる | |||
selectToBracketEnd(topX, topY, bottomX, bottomY, leftChar); | |||
} else { | |||
// いずれでもない場合は、選択開始位置と終了位置の両方で単語選択を行う | |||
simpleExpand(topX, topY, bottomX, bottomY, 0); | |||
} | |||
var afterTopX = sel.GetTopPointX(mePosLogical); | |||
var afterTopY = sel.GetTopPointY(mePosLogical); | |||
var afterBottomX = sel.GetBottomPointX(mePosLogical); | |||
var afterBottomY = sel.GetBottomPointY(mePosLogical); | |||
// 選択範囲を広げる処理の後も同じ位置の場合、通常の選択範囲を広げる処理を行う | |||
if (topX === afterTopX | |||
&& topY === afterTopY | |||
&& bottomX === afterBottomX | |||
&& bottomY === afterBottomY) { | |||
simpleExpand(afterTopX, afterTopY, afterBottomX, afterBottomY, 1); | |||
} | |||
} | |||
} | } | ||
function | function selectFuncNameToChild(pos) { | ||
var minIndex = txt.length; | |||
var toSeparator = txt.indexOf(".", pos); | |||
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator; | |||
toSeparator = txt.indexOf("\n", pos); | |||
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator; | |||
toSeparator = txt.indexOf(" ", pos); | |||
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator; | |||
toSeparator = txt.indexOf("\t", pos); | |||
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator; | |||
toSeparator = txt.indexOf(" ", pos); | |||
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator; | |||
sel.SetActivePos(minIndex, true); | |||
} | } | ||
function | function selectFuncNameToParent(pos) { | ||
var toSeparator1 = txt.lastIndexOf(".", pos); | |||
var toSeparator2 = txt.lastIndexOf("\n", pos); | |||
var toSeparator3 = txt.lastIndexOf(" ", pos); | |||
var toSeparator4 = txt.lastIndexOf("\t", pos); | |||
var toSeparator5 = txt.lastIndexOf(" ", pos); | |||
var maxIndex = Math.max(toSeparator1, toSeparator2, toSeparator3, toSeparator4, toSeparator5); | |||
sel.SetActivePos(maxIndex + 1, true); | |||
} | } | ||
function | // 単純な選択範囲の広げ | ||
function simpleExpand(topX, topY, bottomX, bottomY, offset) { | |||
// 左側を広げ位置を取得 | |||
sel.SetActivePoint(mePosLogical, topX, topY, false); | |||
sel.CharLeft(false, 1 + offset); | |||
sel.SelectWord(); | |||
var simpleExpandTopX = sel.GetTopPointX(mePosLogical); | |||
var simpleExpandTopY = sel.GetTopPointY(mePosLogical); | |||
// 右側を広げ位置を取得 | |||
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false); | |||
if (offset > 0) sel.CharRight(false, offset); | |||
sel.SelectWord(); | |||
var simpleExpandBottomX = sel.GetBottomPointX(mePosLogical); | |||
var simpleExpandBottomY = sel.GetBottomPointY(mePosLogical); | |||
// 選択範囲を広げる | |||
sel.SetActivePoint(mePosLogical, simpleExpandTopX, simpleExpandTopY, false); | |||
sel.SetActivePoint(mePosLogical, simpleExpandBottomX, simpleExpandBottomY, true); | |||
} | } | ||
function | // 先頭方向の開き括弧まで選択範囲を広げる | ||
function selectToBracketStart(topX, topY, bottomX, bottomY, endChar) { | |||
var endBracketIndex = BRACKET.indexOf(endChar); | |||
var | |||
sel.SetActivePoint(mePosLogical, topX, topY, false); | |||
var | var startPos = sel.GetActivePos(); | ||
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false); | |||
var | var endPos = sel.GetActivePos(); | ||
var nest = 1; | var nest = 1; | ||
| 202行目: | 201行目: | ||
var e; | var e; | ||
var pairChar; | var pairChar; | ||
pairChar = BRACKET.charAt(endBracketIndex - 1); //対応する開き括弧を取得 | |||
e = txt.lastIndexOf(endChar, endPos); | |||
while (nest) { | |||
s = txt.lastIndexOf(pairChar, e - 1); | s = txt.lastIndexOf(pairChar, e - 1); | ||
e = txt.lastIndexOf(endChar, e - 1); | e = txt.lastIndexOf(endChar, e - 1); | ||
if (s === -1 || startPos <= 0) break; | if (s === -1 || startPos <= 0) break; | ||
if (s < e && s !== -1) { | if (s < e && s !== -1) { | ||
nest++; | |||
s = e; | |||
} else { | } else { | ||
nest--; | |||
e = s; | |||
} | } | ||
if (s !== -1 && startPos > s) { | if (s !== -1 && startPos > s) { | ||
startPos = s + 1; | |||
} | } | ||
} | } | ||
sel.SetActivePos(startPos); | sel.SetActivePos(startPos); | ||
sel.SetActivePos(endPos, | sel.SetActivePos(endPos, true); | ||
} | } | ||
function | // 末尾方向の閉じ括弧まで選択範囲を広げる | ||
function selectToBracketEnd(topX, topY, bottomX, bottomY, startChar) { | |||
var startBracketIndex = BRACKET.indexOf(startChar); | |||
var | |||
sel.SetActivePoint(mePosLogical, topX, topY, false); | |||
var | var startPos = sel.GetActivePos(); | ||
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false); | |||
var | var endPos = sel.GetActivePos(); | ||
var nest = 1; | var nest = 1; | ||
| 443行目: | 239行目: | ||
var e; | var e; | ||
var pairChar; | var pairChar; | ||
pairChar = BRACKET.charAt(startBracketIndex + 1); //対応する閉じ括弧を取得 | |||
s = txt.indexOf(startChar, startPos - 1); | |||
while (nest) { | |||
e = txt.indexOf(pairChar, s + 1); | e = txt.indexOf(pairChar, s + 1); | ||
s = txt.indexOf(startChar, s + 1); | s = txt.indexOf(startChar, s + 1); | ||
if (e === -1) break; | if (e === -1) break; | ||
if (s < e && s !== -1) { | if (s < e && s !== -1) { | ||
nest++; | |||
e = s; | |||
} else { | } else { | ||
nest--; | |||
s = e; | |||
} | } | ||
if (e !== -1 && endPos < e) { | if (e !== -1 && endPos < e) { | ||
endPos = e; | |||
} | } | ||
} | |||
} else if (rightCharIsEndBracket(selectEndPos)) { | sel.SetActivePos(startPos); | ||
sel.SetActivePos(endPos, true); | |||
} | |||
function moveToBracketEnd(selectStartPos, selectEndPos) { | |||
//■範囲選択(true:する/false:しない) | |||
var SHIFT = true; | |||
quit: { | |||
var startPos = selectStartPos; | |||
var endPos = selectEndPos; | |||
var startChar = txt.charAt(startPos - 1); //選択範囲開始左側の文字を取得 | |||
var startBrcIdx = BRACKET.indexOf(startChar); | |||
var endChar = txt.charAt(selectEndPos); //選択範囲末尾右側の文字を取得 | |||
var endBrcIdx = BRACKET.indexOf(endChar); | |||
var nest = 1; | |||
var s; | |||
var e; | |||
var pairChar; | |||
if (leftCharIsStartBracket(selectStartPos)) { | |||
//◆開き括弧の場合、末尾方向へ探す | |||
pairChar = BRACKET.charAt(startBrcIdx + 1); //対応する閉じ括弧を取得 | |||
s = txt.indexOf(startChar, startPos - 1); | |||
while (nest) { | |||
e = txt.indexOf(pairChar, s + 1); | |||
s = txt.indexOf(startChar, s + 1); | |||
if (e === -1) break; | |||
if (s < e && s !== -1) { | |||
nest++; | |||
e = s; | |||
} else { | |||
nest--; | |||
s = e; | |||
} | |||
if (e !== -1 && endPos < e) { | |||
endPos = e; | |||
} | |||
} | |||
} else if (rightCharIsEndBracket(selectEndPos)) { | |||
//◆閉じ括弧の場合、先頭方向へ探す | |||
pairChar = BRACKET.charAt(endBrcIdx - 1); //対応する開き括弧を取得 | |||
e = txt.lastIndexOf(endChar, endPos); | |||
while (nest) { | |||
s = txt.lastIndexOf(pairChar, e - 1); | |||
e = txt.lastIndexOf(endChar, e - 1); | |||
if (s === -1 || startPos <= 0) break; | |||
if (s < e && s !== -1) { | |||
nest++; | |||
s = e; | |||
} else { | |||
nest--; | |||
e = s; | |||
} | |||
if (s !== -1 && startPos > s) { | |||
startPos = s + 1; | |||
} | |||
} | |||
} else { | } else { | ||
break quit; | |||
} | } | ||
sel.SetActivePos(startPos); | |||
sel.SetActivePos(endPos, SHIFT); | |||
} | } | ||
} | } | ||
| 492行目: | 328行目: | ||
var d = document, s = d.selection; | var d = document, s = d.selection; | ||
s.Mode = meModeMulti; | s.Mode = meModeMulti; | ||
// | // ① まず、GetActivePos と GetAnchorPos で複数選択のリストを作成します | ||
var selections = [{ s: s.GetAnchorPos(), e: s.GetActivePos() }]; | var selections = [{ s: s.GetAnchorPos(), e: s.GetActivePos() }]; | ||
if (s.Count > 0) { | if (s.Count > 0) { | ||
| 502行目: | 338行目: | ||
var q = 0; | var q = 0; | ||
for (var i = 0; i < selections.length; i++) { | for (var i = 0; i < selections.length; i++) { | ||
// | // ② そのリストを上から順に SetActivePos で、「シングルカーソル」で範囲選択します。この段階で複数選択は解除され、通常のマクロ操作が可能となります | ||
s.SetActivePos(selections[i].s + p); | s.SetActivePos(selections[i].s + p); | ||
s.SetActivePos(selections[i].e + p, true); | s.SetActivePos(selections[i].e + p, true); | ||
q = d.TextLength; | q = d.TextLength; | ||
// | // ③ <ここで通常のマクロの機能を使って普通に編集などを行います> | ||
fn(); | fn(); | ||
p += d.TextLength - q; | p += d.TextLength - q; | ||
// | // ④ 処理を行った後の選択範囲をリストに反映し、これをリストの最後まで繰り返します | ||
selections[i] = { s: s.GetAnchorPos(), e: s.GetActivePos() }; | selections[i] = { s: s.GetAnchorPos(), e: s.GetActivePos() }; | ||
} | } | ||
// | // ⑤ そのリストを上から順に document.selection.AddPos(StartPos, EndPos) で複数選択として復元します | ||
for (var i = 0; i < selections.length; i++) | for (var i = 0; i < selections.length; i++) | ||
s.AddPos(selections[i].s, selections[i].e); | s.AddPos(selections[i].s, selections[i].e); | ||
} | |||
if (sel.Mode === meModeMulti) { | |||
doMultiAction(main); | |||
} else { | |||
main(); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== 更新履歴 == | == 更新履歴 == | ||
* 2023/07/21 | |||
** 処理を見直し、より適切な範囲に拡張するよう調整しました。 | |||
* 2020/03/22 | |||
** Mery Ver.3.0.1 マルチカーソル対応化の試験実装メソッドを使った実装を追加しました。 | |||
* 2020/03/15 | * 2020/03/15 | ||
** | ** マルチカーソル時の動作を考慮し処理を追加しました。 | ||
2023年7月21日 (金) 19:33時点における版
選択範囲を広げる
選択範囲を徐々に広げます。VSCode や IntelliJ っぽいやつです。
私は Sublime Text に倣い、Ctrl+Shift+Space に割り当てて使っています。
未選択状態での動作:
- 選択範囲が空の場合、カーソル位置の単語を選択します。
- カーソル位置が括弧だった場合は、括弧の中身を選択します。
- ドットを検出した場合は、ドットの1つ右の単語まで拡張します。
選択状態での動作:
- 選択範囲がある場合、選択範囲の前後にある括弧を検出し、その中身を選択します。
- ドットを検出した場合は、ドットの1つ左または右の単語まで拡張します。
- これらの記号を検出しなかった場合は、単純な選択範囲の拡張を行います。
ソースコード:
#title = "選択範囲を広げる"
/**
* 選択範囲を広げるためのマクロです。
*
* 選択範囲が空の場合、カーソル位置の単語を選択します。
* カーソル位置が括弧だった場合は、括弧の中身を選択します。
* ドットを検出した場合は、ドットの1つ右の単語まで拡張します。
*
* 選択範囲がある場合、選択範囲の前後にある括弧を検出し、その中身を選択します。
* ドットを検出した場合は、ドットの1つ左または右の単語まで拡張します。
* これらの記号を検出しなかった場合は、単純な選択範囲の拡張を行います。
*/
BeginUndoGroup();
Redraw = false;
//■括弧の定義(0+2n:開き/1+2n:閉じ)
var BRACKET = '()<>[]{}「」『』【】()[]{}〈〉《》〔〕〘〙〚〛〖〗‘’“”';
var doc = document;
var sel = document.selection;
var txt = document.Text;
function main() {
if (sel.IsEmpty) {
// 未選択の場合
sel.SelectWord();
var selChar = sel.Text;
var selCharIndex = BRACKET.indexOf(selChar);
if (selChar.length === 1 && selCharIndex !== -1) {
// 選択文字が括弧記号1文字の場合、括弧の中身を選択
if (selCharIndex % 2 === 1) {
// 閉じ括弧の場合
sel.CharLeft();
var topX = sel.GetTopPointX(mePosLogical);
var topY = sel.GetTopPointY(mePosLogical);
var bottomX = sel.GetBottomPointX(mePosLogical);
var bottomY = sel.GetBottomPointY(mePosLogical);
selectToBracketStart(topX, topY, bottomX, bottomY, selChar);
} else if (selCharIndex % 2 === 0) {
// 開き括弧の場合
var topX = sel.GetTopPointX(mePosLogical);
var topY = sel.GetTopPointY(mePosLogical);
var bottomX = sel.GetBottomPointX(mePosLogical);
var bottomY = sel.GetBottomPointY(mePosLogical);
var activePos = sel.GetActivePos();
selectToBracketEnd(topX, topY, bottomX, bottomY, selChar);
if (activePos !== sel.GetActivePos()) {
// 括弧の中身が選択された場合、閉じ括弧も選択する
sel.SetActivePos(sel.GetActivePos() + 1, true);
}
}
} else if (selChar === ".") {
// ドットの場合
// ドットの1つ右の単語まで拡張
selectFuncNameToChild(sel.GetActivePos());
}
} else {
// 選択済みの場合
// 選択範囲の左右の文字を取得
var topX = sel.GetTopPointX(mePosLogical);
var topY = sel.GetTopPointY(mePosLogical);
var bottomX = sel.GetBottomPointX(mePosLogical);
var bottomY = sel.GetBottomPointY(mePosLogical);
// 選択範囲の左右の文字を取得
var leftChar = "dummy";
if (topX - 2 >= 0) doc.GetLine(topY, meGetLineWithNewLines).charAt(topX - 2);
var rightChar = doc.GetLine(bottomY, meGetLineWithNewLines).charAt(bottomX - 1);
var rightIndex = BRACKET.indexOf(rightChar);
var leftIndex = BRACKET.indexOf(leftChar);
if (rightChar === ".") {
// 選択範囲の右にドットがある場合
// 末尾方向にドットを検索
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false);
selectFuncNameToChild(sel.GetActivePos() + 1);
sel.SetAnchorPoint(mePosLogical, topX, topY);
} else if (rightIndex % 2 === 0) {
// 右位置に開き括弧があるかをチェック
// 選択範囲を広げる
selectToBracketEnd(topX, topY, bottomX, bottomY, rightChar);
// 閉じ括弧も選択する
sel.CharRight(true);
} else if (leftChar === ".") {
// 選択範囲の左にドットがある場合
// 先頭方向にドットを検索
sel.SetActivePoint(mePosLogical, topX, topY, false);
selectFuncNameToParent(sel.GetActivePos() - 2);
sel.SetAnchorPoint(mePosLogical, bottomX, bottomY);
} else if (rightIndex % 2 === 1) {
// 右位置に閉じ括弧があるかをチェック
// 選択範囲を広げる
selectToBracketStart(topX, topY, bottomX, bottomY, rightChar);
} else if (leftIndex % 2 === 0) {
alert(leftChar)
// 左位置に括弧があるかをチェック
// 選択範囲を広げる
selectToBracketEnd(topX, topY, bottomX, bottomY, leftChar);
} else {
// いずれでもない場合は、選択開始位置と終了位置の両方で単語選択を行う
simpleExpand(topX, topY, bottomX, bottomY, 0);
}
var afterTopX = sel.GetTopPointX(mePosLogical);
var afterTopY = sel.GetTopPointY(mePosLogical);
var afterBottomX = sel.GetBottomPointX(mePosLogical);
var afterBottomY = sel.GetBottomPointY(mePosLogical);
// 選択範囲を広げる処理の後も同じ位置の場合、通常の選択範囲を広げる処理を行う
if (topX === afterTopX
&& topY === afterTopY
&& bottomX === afterBottomX
&& bottomY === afterBottomY) {
simpleExpand(afterTopX, afterTopY, afterBottomX, afterBottomY, 1);
}
}
}
function selectFuncNameToChild(pos) {
var minIndex = txt.length;
var toSeparator = txt.indexOf(".", pos);
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator;
toSeparator = txt.indexOf("\n", pos);
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator;
toSeparator = txt.indexOf(" ", pos);
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator;
toSeparator = txt.indexOf("\t", pos);
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator;
toSeparator = txt.indexOf(" ", pos);
if (toSeparator !== -1 && toSeparator < minIndex) minIndex = toSeparator;
sel.SetActivePos(minIndex, true);
}
function selectFuncNameToParent(pos) {
var toSeparator1 = txt.lastIndexOf(".", pos);
var toSeparator2 = txt.lastIndexOf("\n", pos);
var toSeparator3 = txt.lastIndexOf(" ", pos);
var toSeparator4 = txt.lastIndexOf("\t", pos);
var toSeparator5 = txt.lastIndexOf(" ", pos);
var maxIndex = Math.max(toSeparator1, toSeparator2, toSeparator3, toSeparator4, toSeparator5);
sel.SetActivePos(maxIndex + 1, true);
}
// 単純な選択範囲の広げ
function simpleExpand(topX, topY, bottomX, bottomY, offset) {
// 左側を広げ位置を取得
sel.SetActivePoint(mePosLogical, topX, topY, false);
sel.CharLeft(false, 1 + offset);
sel.SelectWord();
var simpleExpandTopX = sel.GetTopPointX(mePosLogical);
var simpleExpandTopY = sel.GetTopPointY(mePosLogical);
// 右側を広げ位置を取得
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false);
if (offset > 0) sel.CharRight(false, offset);
sel.SelectWord();
var simpleExpandBottomX = sel.GetBottomPointX(mePosLogical);
var simpleExpandBottomY = sel.GetBottomPointY(mePosLogical);
// 選択範囲を広げる
sel.SetActivePoint(mePosLogical, simpleExpandTopX, simpleExpandTopY, false);
sel.SetActivePoint(mePosLogical, simpleExpandBottomX, simpleExpandBottomY, true);
}
// 先頭方向の開き括弧まで選択範囲を広げる
function selectToBracketStart(topX, topY, bottomX, bottomY, endChar) {
var endBracketIndex = BRACKET.indexOf(endChar);
sel.SetActivePoint(mePosLogical, topX, topY, false);
var startPos = sel.GetActivePos();
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false);
var endPos = sel.GetActivePos();
var nest = 1;
var s;
var e;
var pairChar;
pairChar = BRACKET.charAt(endBracketIndex - 1); //対応する開き括弧を取得
e = txt.lastIndexOf(endChar, endPos);
while (nest) {
s = txt.lastIndexOf(pairChar, e - 1);
e = txt.lastIndexOf(endChar, e - 1);
if (s === -1 || startPos <= 0) break;
if (s < e && s !== -1) {
nest++;
s = e;
} else {
nest--;
e = s;
}
if (s !== -1 && startPos > s) {
startPos = s + 1;
}
}
sel.SetActivePos(startPos);
sel.SetActivePos(endPos, true);
}
// 末尾方向の閉じ括弧まで選択範囲を広げる
function selectToBracketEnd(topX, topY, bottomX, bottomY, startChar) {
var startBracketIndex = BRACKET.indexOf(startChar);
sel.SetActivePoint(mePosLogical, topX, topY, false);
var startPos = sel.GetActivePos();
sel.SetActivePoint(mePosLogical, bottomX, bottomY, false);
var endPos = sel.GetActivePos();
var nest = 1;
var s;
var e;
var pairChar;
pairChar = BRACKET.charAt(startBracketIndex + 1); //対応する閉じ括弧を取得
s = txt.indexOf(startChar, startPos - 1);
while (nest) {
e = txt.indexOf(pairChar, s + 1);
s = txt.indexOf(startChar, s + 1);
if (e === -1) break;
if (s < e && s !== -1) {
nest++;
e = s;
} else {
nest--;
s = e;
}
if (e !== -1 && endPos < e) {
endPos = e;
}
}
sel.SetActivePos(startPos);
sel.SetActivePos(endPos, true);
}
function moveToBracketEnd(selectStartPos, selectEndPos) {
//■範囲選択(true:する/false:しない)
var SHIFT = true;
quit: {
var startPos = selectStartPos;
var endPos = selectEndPos;
var startChar = txt.charAt(startPos - 1); //選択範囲開始左側の文字を取得
var startBrcIdx = BRACKET.indexOf(startChar);
var endChar = txt.charAt(selectEndPos); //選択範囲末尾右側の文字を取得
var endBrcIdx = BRACKET.indexOf(endChar);
var nest = 1;
var s;
var e;
var pairChar;
if (leftCharIsStartBracket(selectStartPos)) {
//◆開き括弧の場合、末尾方向へ探す
pairChar = BRACKET.charAt(startBrcIdx + 1); //対応する閉じ括弧を取得
s = txt.indexOf(startChar, startPos - 1);
while (nest) {
e = txt.indexOf(pairChar, s + 1);
s = txt.indexOf(startChar, s + 1);
if (e === -1) break;
if (s < e && s !== -1) {
nest++;
e = s;
} else {
nest--;
s = e;
}
if (e !== -1 && endPos < e) {
endPos = e;
}
}
} else if (rightCharIsEndBracket(selectEndPos)) {
//◆閉じ括弧の場合、先頭方向へ探す
pairChar = BRACKET.charAt(endBrcIdx - 1); //対応する開き括弧を取得
e = txt.lastIndexOf(endChar, endPos);
while (nest) {
s = txt.lastIndexOf(pairChar, e - 1);
e = txt.lastIndexOf(endChar, e - 1);
if (s === -1 || startPos <= 0) break;
if (s < e && s !== -1) {
nest++;
s = e;
} else {
nest--;
e = s;
}
if (s !== -1 && startPos > s) {
startPos = s + 1;
}
}
} else {
break quit;
}
sel.SetActivePos(startPos);
sel.SetActivePos(endPos, SHIFT);
}
}
function doMultiAction(fn) {
var d = document, s = d.selection;
s.Mode = meModeMulti;
// ① まず、GetActivePos と GetAnchorPos で複数選択のリストを作成します
var selections = [{ s: s.GetAnchorPos(), e: s.GetActivePos() }];
if (s.Count > 0) {
selections = [];
for (var i = 0; i < s.Count; i++)
selections.push({ s: s.GetActivePos(i), e: s.GetAnchorPos(i) });
}
var p = 0;
var q = 0;
for (var i = 0; i < selections.length; i++) {
// ② そのリストを上から順に SetActivePos で、「シングルカーソル」で範囲選択します。この段階で複数選択は解除され、通常のマクロ操作が可能となります
s.SetActivePos(selections[i].s + p);
s.SetActivePos(selections[i].e + p, true);
q = d.TextLength;
// ③ <ここで通常のマクロの機能を使って普通に編集などを行います>
fn();
p += d.TextLength - q;
// ④ 処理を行った後の選択範囲をリストに反映し、これをリストの最後まで繰り返します
selections[i] = { s: s.GetAnchorPos(), e: s.GetActivePos() };
}
// ⑤ そのリストを上から順に document.selection.AddPos(StartPos, EndPos) で複数選択として復元します
for (var i = 0; i < selections.length; i++)
s.AddPos(selections[i].s, selections[i].e);
}
if (sel.Mode === meModeMulti) {
doMultiAction(main);
} else {
main();
}
更新履歴
- 2023/07/21
- 処理を見直し、より適切な範囲に拡張するよう調整しました。
- 2020/03/22
- Mery Ver.3.0.1 マルチカーソル対応化の試験実装メソッドを使った実装を追加しました。
- 2020/03/15
- マルチカーソル時の動作を考慮し処理を追加しました。
スポンサーリンク