VSCode風、行頭/行末に移動
VSCode風の行頭、行末移動操作を再現しました(2021/07時点のVSCode仕様に基づく)。
⚠ このマクロの動作は、Mery Ver 3.6.1 以降で標準ショートカットの「行頭またはテキストの開始位置へ移動」(Homeキー) および行末移動 (Endキー) の動作と変わりません。
デフォルトでは選択状態が外れ移動動作となるため、選択動作にしたい場合は先頭の shift 変数を false に設定してください。
- Home/End キー、及び範囲選択の場合 Shift + Home/End キーにそれぞれ割り当てることを想定
- マルチカーソル対応
行頭移動の動作 (Home)
- 表示行で折り返し1行目にカーソルがある場合
- インデント記号 (半角スペース、全角スペース、タブ記号) を意識した論理行頭移動を行う
- 表示行で折り返し2行目以降にカーソルがある場合
- 1桁目にカーソルがある場合
- インデント記号 (半角スペース、全角スペース、タブ記号) を意識した論理行頭移動を行う
- 2桁目以降にカーソルがある場合
- 表示行上の先頭に移動する
- 1桁目にカーソルがある場合
行末移動の動作 (End)
- 最後の桁以外にカーソルがある場合
- 表示行上で最後の桁に移動する
- 最後の桁にカーソルがある場合
- 論理行上で最後の桁に移動する
ソースコード
行頭移動の動作 (Home)
#title = "行頭に移動"
Redraw = false;
// シフトの状態(true の場合は選択、false の場合は移動)
var shift = false;
if (document.selection.Mode === meModeMulti) {
doMultiAction(homeLikeVscode);
} else {
homeLikeVscode();
}
function homeLikeVscode() {
var actViewX = document.selection.GetActivePointX(mePosView);
var actViewY = document.selection.GetActivePointY(mePosView);
var ancViewX = document.selection.GetAnchorPointX(mePosView);
var ancViewY = document.selection.GetAnchorPointY(mePosView);
document.selection.SetActivePoint(
mePosLogical,
1,
document.selection.GetActivePointY(mePosLogical)
);
var actViewY2 = document.selection.GetActivePointY(mePosView);
document.selection.SetActivePoint(mePosView, ancViewX, ancViewY);
if (shift) {
document.selection.SetActivePoint(mePosView, actViewX, actViewY, true);
}
if (actViewY !== actViewY2 && actViewX > 1) {
document.selection.StartOfLine(shift, mePosView);
} else {
indentHome();
}
}
function indentHome() {
// インデントとして認識する文字(半角空白、全角空白、タブ)
var indent = new RegExp(' | |\t');
// 現在位置取得
var x1 = document.selection.GetActivePointX(mePosLogical);
var y1 = document.selection.GetActivePointY(mePosLogical);
// 選択開始位置取得
var x2 = document.selection.GetAnchorPointX(mePosLogical);
var y2 = document.selection.GetAnchorPointY(mePosLogical);
// カーソルを行末に移動
document.selection.EndOfLine(false, mePosLogical);
// カーソルを行頭に移動(これで1行選択)
document.selection.StartOfLine(true, mePosLogical);
var s = document.selection.Text;
var i = 0;
// 行頭からタブの数を確認
var slen = s.length;
for (var j = 0; j < slen; j++) {
c = s.charAt(j);
if (indent.test(c)) i++;
else break;
}
// シフトオンの場合、選択終了位置に移動
if (shift) {
document.selection.SetActivePoint(mePosLogical, x2, y2, false);
document.selection.SetActivePoint(mePosLogical, i + 1, y1, shift);
}
// 現在位置が1より大きくてタブの数以下の場合は行頭に移動
if (x1 > 1 && x1 <= i + 1) {
document.selection.SetActivePoint(mePosLogical, 1, y1, shift);
// それ以外の場合はタブの数だけ進める
} else {
document.selection.SetActivePoint(mePosLogical, i + 1, y1, shift);
}
}
function doMultiAction(fn) {
var d = document,
s = d.selection;
s.Mode = meModeMulti;
var startX = s.GetAnchorPointX(mePosView);
var startY = s.GetAnchorPointY(mePosView);
var endX = s.GetActivePointX(mePosView);
var endY = s.GetActivePointY(mePosView);
var selections = [{sx: startX, sy: startY, ex: endX, ey: endY}];
if (s.Count > 0) {
for (var i = 0; i < s.Count; i++) {
startX = s.GetAnchorPointX(mePosView, i);
startY = s.GetAnchorPointY(mePosView, i);
endX = s.GetActivePointX(mePosView, i);
endY = s.GetActivePointY(mePosView, i);
selections.push({sx: startX, sy: startY, ex: endX, ey: endY});
}
}
var p = 0;
var q = 0;
for (var i = 0; i < selections.length; i++) {
s.SetActivePoint(mePosView, selections[i].sx, selections[i].sy);
s.SetActivePoint(mePosView, selections[i].ex, selections[i].ey, true);
q = d.TextLength;
fn();
p += d.TextLength - q;
startX = s.GetAnchorPointX(mePosView);
startY = s.GetAnchorPointY(mePosView);
endX = s.GetActivePointX(mePosView);
endY = s.GetActivePointY(mePosView);
selections[i] = {sx: startX, sy: startY, ex: endX, ey: endY};
}
for (var i = 0; i < selections.length; i++) {
s.AddPoint(mePosView, selections[i].sx, selections[i].sy, selections[i].ex, selections[i].ey);
}
}
行末移動の動作 (End)
#title = "行末に移動"
Redraw = false;
// シフトの状態(true の場合は選択、false の場合は移動)
var shift = false;
if (document.selection.Mode === meModeMulti) {
doMultiAction(endLikeVscode);
} else {
endLikeVscode();
}
function endLikeVscode() {
var actViewX = document.selection.GetActivePointX(mePosView);
var actViewY = document.selection.GetActivePointY(mePosView);
var ancViewX = document.selection.GetAnchorPointX(mePosView);
var ancViewY = document.selection.GetAnchorPointY(mePosView);
document.selection.EndOfLine(false, mePosView);
var actViewX2 = document.selection.GetActivePointX(mePosView);
document.selection.SetActivePoint(mePosView, ancViewX, ancViewY);
if (shift) {
document.selection.SetActivePoint(mePosView, actViewX, actViewY, true);
}
if (actViewX !== actViewX2) {
document.selection.EndOfLine(shift, mePosView);
} else {
document.selection.EndOfLine(shift, mePosLogical);
}
}
function doMultiAction(fn) {
var d = document,
s = d.selection;
s.Mode = meModeMulti;
var startX = s.GetAnchorPointX(mePosView);
var startY = s.GetAnchorPointY(mePosView);
var endX = s.GetActivePointX(mePosView);
var endY = s.GetActivePointY(mePosView);
var selections = [{sx: startX, sy: startY, ex: endX, ey: endY}];
if (s.Count > 0) {
for (var i = 0; i < s.Count; i++) {
startX = s.GetAnchorPointX(mePosView, i);
startY = s.GetAnchorPointY(mePosView, i);
endX = s.GetActivePointX(mePosView, i);
endY = s.GetActivePointY(mePosView, i);
selections.push({sx: startX, sy: startY, ex: endX, ey: endY});
}
}
var p = 0;
var q = 0;
for (var i = 0; i < selections.length; i++) {
s.SetActivePoint(mePosView, selections[i].sx, selections[i].sy);
s.SetActivePoint(mePosView, selections[i].ex, selections[i].ey, true);
q = d.TextLength;
fn();
p += d.TextLength - q;
startX = s.GetAnchorPointX(mePosView);
startY = s.GetAnchorPointY(mePosView);
endX = s.GetActivePointX(mePosView);
endY = s.GetActivePointY(mePosView);
selections[i] = {sx: startX, sy: startY, ex: endX, ey: endY};
}
for (var i = 0; i < selections.length; i++) {
s.AddPoint(mePosView, selections[i].sx, selections[i].sy, selections[i].ex, selections[i].ey);
}
}
スポンサーリンク