選択範囲を広げる
選択範囲を徐々に広げます。VSCode や IntelliJ っぽいやつです。
私は Sublime Text に倣い、Ctrl+Shift+Space に割り当てて使っています。
未選択状態での動作:
- カーソルの左、もしくは右に括弧記号がある場合は括弧の中全体を選択
- それ以外はカーソル位置の単語を選択
選択状態での動作:
- 選択状態によって選択範囲を広げる
- 選択範囲の開始位置に括弧の開始記号がある場合は、括弧全体に選択範囲を広げる
- 上記の条件に当てはまらず、選択範囲末尾の右側に括弧の終了記号がある場合は、括弧全体に選択範囲を広げる
- 上記の条件に当てはまらず、選択範囲末尾の右側にドットがある場合には、そのドット連なりの一番右側の単語まで選択範囲を広げる
- 上記の条件に当てはまらず、選択範囲末尾の右側に括弧の開始記号がある場合には、その括弧を全て洗濯する
- 上記の動作によって選択範囲が広がらなかった場合には、選択範囲を左右それぞれ1単語ずつ広げる
#title="選択範囲を広げる"
BeginUndoGroup();
Redraw = false;
//■括弧の定義(0+2n:開き/1+2n:閉じ)
var BRACKET = '()<>[]{}「」『』【】()';
var sel = document.selection;
var txt = Document.Text;
if (sel.IsEmpty) {
var selectStartPos = selectBottomPos = sel.GetActivePos();
if (leftCharIsStartBracket(selectStartPos)
|| rightCharIsEndBracket(selectBottomPos)) {
// カーソルの左右いずれかに開き括弧があった場合
moveToBracketEnd(selectStartPos, selectBottomPos);
} else {
// 単語を選択
sel.SelectWord();
}
} else {
expandSelection();
}
function expandSelection() {
var EXTEND_ON = true;
var EXTEND_OFF = false;
// 選択範囲取得
var topX = sel.GetTopPointX(mePosLogical);
var topY = sel.GetTopPointY(mePosLogical);
var bottomX = sel.GetBottomPointX(mePosLogical);
var bottomY = sel.GetBottomPointY(mePosLogical);
// 選択終了位置のポジション取得
sel.SetActivePoint(mePosLogical, bottomX, bottomY, EXTEND_OFF);
var selectBottomPos = sel.GetActivePos();
// 選択開始位置に移動
sel.SetActivePoint(mePosLogical, topX, topY, EXTEND_OFF);
var selectTopPos = sel.GetActivePos();
var selectStartPos, selectEndPos;
if (selectTopPos <= selectBottomPos) {
selectStartPos = selectTopPos;
selectEndPos = selectBottomPos;
} else {
selectStartPos = selectBottomPos;
selectEndPos = selectTopPos;
}
if (bothSideCharIsBracket(selectStartPos, selectEndPos)) {
// 両脇が括弧だった場合
sel.CharLeft(EXTEND_OFF);
sel.SetActivePos(selectEndPos, EXTEND_ON);
sel.CharRight(EXTEND_ON);
} else if (txt.charAt(selectEndPos) === '.') {
// 選択範囲末尾右側がドットだった場合
selectRightSideWordsOfDot(selectStartPos, selectEndPos);
} else if (leftCharIsStartBracket(selectEndPos + 1)) {
// 選択範囲右側が開始括弧だった場合
selectRightSideWordsOfBracket(selectStartPos, selectEndPos);
} else if (
leftCharIsStartBracket(selectStartPos) ||
rightCharIsEndBracket(selectEndPos)
) {
// 左右どちらかが括弧だった場合
moveToBracketEnd(selectStartPos, selectEndPos);
} else {
// 選択範囲を拡大
sel.WordLeft(EXTEND_OFF);
sel.SetActivePos(selectEndPos, EXTEND_ON);
sel.WordRight(EXTEND_ON);
}
// 選択範囲拡大後の選択範囲取得
var expandedTopX = sel.GetTopPointX(mePosLogical);
var expandedTopY = sel.GetTopPointY(mePosLogical);
var expandedBottomX = sel.GetBottomPointX(mePosLogical);
var expandedBottomY = sel.GetBottomPointY(mePosLogical);
// 選択範囲が変わっていない場合は、左右1単語ずつ拡大する
if (
topX === expandedTopX &&
topY === expandedTopY &&
bottomX === expandedBottomX &&
bottomY === expandedBottomY
) {
sel.SetActivePos(selectStartPos);
sel.WordLeft(EXTEND_OFF);
sel.SetActivePos(selectEndPos, EXTEND_ON);
sel.WordRight(EXTEND_ON);
}
}
function selectRightSideWordsOfDot(selectStartPos, selectEndPos) {
if (txt.charAt(selectEndPos) !== '.') {
return;
}
var EXTEND_ON = true;
sel.SetActivePos(selectStartPos);
sel.SetActivePos(selectEndPos, EXTEND_ON);
sel.CharRight(EXTEND_ON);
sel.WordRight(EXTEND_ON);
selectRightSideWordsOfDot(selectStartPos, sel.GetActivePos());
}
function selectRightSideWordsOfBracket(selectStartPos, selectEndPos) {
if (!leftCharIsStartBracket(selectEndPos + 1)) {
return;
}
moveToBracketEnd(selectEndPos + 1, selectEndPos + 1);
var movedEndPos = sel.GetActivePos() + 1;
var EXTEND_ON = true;
sel.SetActivePos(selectStartPos);
sel.SetActivePos(movedEndPos, EXTEND_ON);
}
function leftCharIsStartBracket(selectStartPos) {
var startPos;
if (selectStartPos) {
startPos = selectStartPos;
} else {
startPos = Document.Selection.GetActivePos();
}
var startChar = txt.charAt(startPos - 1); //カーソル左側の文字を取得
var startBrcIdx = BRACKET.indexOf(startChar);
return startBrcIdx !== -1 && startChar !== '' && startBrcIdx % 2 === 0;
}
function rightCharIsEndBracket(selectEndPos) {
var endPos;
if (selectEndPos) {
endPos = selectEndPos;
} else {
endPos = Document.Selection.GetActivePos();
}
var endChar = txt.charAt(endPos); //カーソル右側の文字を取得
var endBrcIdx = BRACKET.indexOf(endChar);
return endBrcIdx !== -1 && endChar !== '' && endBrcIdx % 2 === 1;
}
function bothSideCharIsBracket(selectStartPos, selectEndPos) {
var txt = Document.Text;
var sPos = selectStartPos; //カーソル始点
var ePos = selectEndPos; //カーソル終点
var sBrc = txt.charAt(sPos - 1); //カーソル始点左側の文字を取得
var eBrc = txt.charAt(ePos); //カーソル終点右側の文字を取得
var isBrc = BRACKET.indexOf(sBrc);
var ieBrc = BRACKET.indexOf(eBrc);
return (
!(isBrc === -1 || sBrc === '') &&
!(ieBrc === -1 || eBrc === '') &&
ieBrc - isBrc === 1
);
}
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 (startBrcIdx !== -1 && startChar !== '' && startBrcIdx % 2 === 0) {
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 (endBrcIdx !== -1 && endChar !== '' && endBrcIdx % 2 === 1) {
} 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);
}
}
スポンサーリンク