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

提供: MeryWiki
ナビゲーションに移動 検索に移動
(同じ利用者による、間の1版が非表示)
16行目: 16行目:
 
**上記の条件に当てはまらず、選択範囲末尾の右側に括弧の終了記号がある場合は、括弧全体に選択範囲を広げる
 
**上記の条件に当てはまらず、選択範囲末尾の右側に括弧の終了記号がある場合は、括弧全体に選択範囲を広げる
 
**上記の条件に当てはまらず、選択範囲末尾の右側にドットがある場合には、そのドット連なりの一番右側の単語まで選択範囲を広げる
 
**上記の条件に当てはまらず、選択範囲末尾の右側にドットがある場合には、そのドット連なりの一番右側の単語まで選択範囲を広げる
**上記の条件に当てはまらず、選択範囲末尾の右側に括弧の開始記号がある場合には、その括弧を全て洗濯する
+
**上記の条件に当てはまらず、選択範囲末尾の右側に括弧の開始記号がある場合には、その括弧を全て選択する
 
**上記の動作によって選択範囲が広がらなかった場合には、選択範囲を左右それぞれ1単語ずつ広げる
 
**上記の動作によって選択範囲が広がらなかった場合には、選択範囲を左右それぞれ1単語ずつ広げる
 +
 +
=== ソースコード: ===
  
 
<source lang="javascript">
 
<source lang="javascript">
250行目: 252行目:
 
     sel.SetActivePos(endPos, SHIFT);
 
     sel.SetActivePos(endPos, SHIFT);
 
   }
 
   }
 +
}
 +
 +
</source>
 +
 +
=== Mery Ver.3.0.1 以降に対応するマルチカーソル対応実装 (試験実装メソッドを利用): ===
 +
 +
<source lang="javascript">
 +
#title="選択範囲を広げる"
 +
BeginUndoGroup();
 +
Redraw = false;
 +
 +
//■括弧の定義(0+2n:開き/1+2n:閉じ)
 +
var BRACKET = '()<>[]{}「」『』【】()';
 +
 +
var sel = document.selection;
 +
var txt = Document.Text;
 +
 +
if (sel.Mode === meModeMulti) {
 +
  doMultiAction(main);
 +
} else {
 +
  main();
 +
}
 +
 +
 +
function main() {
 +
  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 (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);
 
}
 
}
  

2020年3月22日 (日) 23:27時点における版

選択範囲を広げる

選択範囲を徐々に広げます。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);
  }
}

Mery Ver.3.0.1 以降に対応するマルチカーソル対応実装 (試験実装メソッドを利用):

#title="選択範囲を広げる"
BeginUndoGroup();
Redraw = false;

//■括弧の定義(0+2n:開き/1+2n:閉じ)
var BRACKET = '()<>[]{}「」『』【】()';

var sel = document.selection;
var txt = Document.Text;

if (sel.Mode === meModeMulti) {
  doMultiAction(main);
} else {
  main();
}


function main() {
  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 (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);
}

更新履歴

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

スポンサーリンク