VSCode風、行頭/行末に移動

提供:MeryWiki
ナビゲーションに移動 検索に移動

VSCode風の行頭、行末移動操作を再現しました。 (2021/07時点のVSCode仕様に基づく)

デフォルトでは選択状態が外れ移動動作となるため、選択動作にしたい場合は先頭の shift 変数を false に設定してください。

  • Home/End キー、及び範囲選択の場合 Shift + Home/End キーにそれぞれ割り当てることを想定
  • マルチカーソル対応

行頭移動の動作 (Home)[編集]

  • 表示行で折り返し1行目にカーソルがある場合
    • インデント記号 (半角スペース、全角スペース、タブ記号) を意識した論理行頭移動を行う
  • 表示行で折り返し2行目以降にカーソルがある場合
    • 1桁目にカーソルがある場合
      • インデント記号 (半角スペース、全角スペース、タブ記号) を意識した論理行頭移動を行う
    • 2桁目以降にカーソルがある場合
      • 表示行上の先頭に移動する

行末移動の動作 (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);
  }
}
スポンサーリンク