「選択範囲を広げる」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Yuko (トーク | 投稿記録)
編集の要約なし
Yuko (トーク | 投稿記録)
編集の要約なし
1行目: 1行目:
== 選択範囲を広げる ==
選択範囲を徐々に広げます。VSCode や IntelliJ っぽいやつです。
選択範囲を徐々に広げます。VSCode や IntelliJ っぽいやつです。


私は Sublime Text に倣い、Ctrl+Shift+Space に割り当てて使っています。
私は Sublime Text に倣い、Ctrl+Shift+Space に割り当てて使っています。


未選択状態での動作:
=== 未選択状態での動作: ===


*カーソルの左、もしくは右に括弧記号がある場合は括弧の中全体を選択
*カーソルの左、もしくは右に括弧記号がある場合は括弧の中全体を選択
*それ以外はカーソル位置の単語を選択
*それ以外はカーソル位置の単語を選択


選択状態での動作:
=== 選択状態での動作: ===


*選択状態によって選択範囲を広げる
*選択状態によって選択範囲を広げる
28行目: 30行目:
var txt = Document.Text;
var txt = Document.Text;


if (sel.IsEmpty) {
if (sel.Mode === meModeMulti) {
  // マルチカーソル動作中の場合は SelectWord しか行わない
  sel.SelectWord();
} else if (sel.IsEmpty) {
   var selectStartPos = selectBottomPos = sel.GetActivePos();
   var selectStartPos = selectBottomPos = sel.GetActivePos();
   if (leftCharIsStartBracket(selectStartPos)
   if (leftCharIsStartBracket(selectStartPos)
248行目: 253行目:


</source>
</source>
== 更新履歴 ==
2020/03/15 マルチカーソル時の動作を考慮し処理を追加

2020年3月15日 (日) 06:41時点における版

選択範囲を広げる

選択範囲を徐々に広げます。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.Mode === meModeMulti) {
  // マルチカーソル動作中の場合は SelectWord しか行わない
  sel.SelectWord();
} else 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);
  }
}

更新履歴

2020/03/15 マルチカーソル時の動作を考慮し処理を追加

スポンサーリンク