「字下げ・字上げ」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
(masme版を更新)
(→‎sukemaru 版: ブックマーク対応版)
79行目: 79行目:
 
= sukemaru 版 =
 
= sukemaru 版 =
 
<br>
 
<br>
'''ダウンロード:''' 「[[ファイル:字下げ/字上げ.zip]](アイコン入り)」 最終更新: 2019/04/07
+
'''ダウンロード:''' 「[[ファイル:字下げ/字上げ.zip]]」(アイコン入り)<br>
 +
最終更新: 2019/11/10 '''ブックマーク対応版'''
 
* [[#字下げ(スペース×2 追加)|スペース×2 追加]].js
 
* [[#字下げ(スペース×2 追加)|スペース×2 追加]].js
 
* [[#字上げ(スペース×2 削除)|スペース×2 削除]].js
 
* [[#字上げ(スペース×2 削除)|スペース×2 削除]].js
 
* [[#インデント|インデント]].js
 
* [[#インデント|インデント]].js
 
* [[#逆インデント|アンインデント]].js
 
* [[#逆インデント|アンインデント]].js
それぞれ専用の「マテリアルデザインっぽいアイコン」を同梱
+
: それぞれ専用の「マテリアルデザインっぽいアイコン」を同梱
 +
<br>
 +
※ ブックマーク対応の '''2019/11/10 版'''の動作要件: '''Mery ver 2.8.6 以上''' <br>
 +
: <span style="color:#c00;">※ ブックマークを正常に保持できるのは Mery ver 2.8.6 以上の場合だけです。</span>
 +
:それ以前のバージョンでは、Mery 本体側のブックマーク機能の仕様が安定していないので、ブックマークを正しく復元できません。
 +
: → ver 2.8.5 以前の Mery には 2019/04/07 版(ブックマーク非対応)
  
  
 
== 字下げ(スペース×2 追加) ==
 
== 字下げ(スペース×2 追加) ==
;スペース×2 追加.js
+
;スペース×2 追加.js <br>
<br>
 
 
キャレットまたは選択範囲をふくむ論理行の各先頭に「半角スペース×2」を追加します。
 
キャレットまたは選択範囲をふくむ論理行の各先頭に「半角スペース×2」を追加します。
 
* 選択範囲がなかった場合は「タブ文字」を追加、または「半角スペース×2」を行頭に追加します。
 
* 選択範囲がなかった場合は「タブ文字」を追加、または「半角スペース×2」を行頭に追加します。
99行目: 104行目:
 
#title = "字下げ"
 
#title = "字下げ"
 
#tooltip = "スペース×2 追加"
 
#tooltip = "スペース×2 追加"
 +
#icon = "space_x2[1].ico"
 
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",247
 
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",247
// ※「引用の追加」マクロから行頭に文字列を追加するコードを拝借した
 
  
// ■選択範囲なしのときには「タブ文字×1」を追加するか?
+
var start = new Date(); // 所要時間計測(開始)
 +
 
 +
/**
 +
* ---------------------------------------------------------
 +
* 「字下げ(スペース×2 追加)」マクロ
 +
*  sukemaru, 2018/11/01 - 2019/11/10
 +
* ---------------------------------------------------------
 +
* 最初に選択範囲がなかった場合は「タブ文字」を追加、
 +
* または「半角スペース×2」を行頭に追加する。
 +
* 選択範囲があった場合は、つねに「半角スペース×2」を行頭に追加する(空行は無視)。
 +
* ※「引用の追加」マクロから行頭に文字列を追加するコードを拝借した
 +
*
 +
* 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 +
*/
 +
 
 +
// ---------- ▼ 設定項目 ▼ ----------
 +
 
 +
// ■ 選択範囲なしのときには「タブ文字×1」を追加するか?
 
var tabEnable = 0;
 
var tabEnable = 0;
 +
  /**
 +
  * 0: 「半角空白×2」を行頭に追加する(空行は無視)
 +
  * 1: 選択範囲なしのときは「タブ文字×1」を行頭に追加
 +
  * 2: 選択範囲なしのときは「タブ文字×1」をキャレット位置に追加
 +
  */
 +
  
  // 0 なら、「半角スペース×2」を行頭に追加する(空行は無視)
+
// ■ 行頭に追加する空白文字の定義(初期値:「半角空白×2」)
  // 1 なら、選択範囲なしのときは「タブ文字×1」を行頭に追加する
+
var blank = "  "; // 半角空白×2
  // 2 なら、選択範囲なしのときは「タブ文字×1」をキャレット位置に追加する
 
  
// ■行頭に追加する空白文字の定義(初期値:「半角スペース×2 "  "」)
+
// ---------- ▲ 設定項目 ▲ ----------
var blank = "  "; // 半角スペース×2
 
  
 +
Redraw = false;
 +
var sx = ScrollX,  sy = ScrollY;
  
var s = document.selection;
+
var tab = "\t";
 +
var d = editor.ActiveDocument;
 +
var s = editor.ActiveDocument.selection;
 +
var len = 0;
  
 
// "選択範囲なし" のフラグ
 
// "選択範囲なし" のフラグ
 
var pos = s.IsEmpty ? s.GetActivePos() : "";
 
var pos = s.IsEmpty ? s.GetActivePos() : "";
  
// キャレット位置に「タブ文字×1」を挿入して終了するパターン
+
if ( d.ReadOnly ) {
if ( pos && tabEnable > 1 ) { // tabEnable == 2
+
  Status = " ドキュメントは書き換え禁止です。";
   s.Text = "\t";
+
}
 +
 
 +
/* キャレット位置に「タブ文字×1」を挿入するパターン */
 +
else if ( tabEnable == 2 && pos ) {
 +
   s.Text = tab;
 
}
 
}
 +
 
else {
 
else {
  var sx = ScrollX,  sy = ScrollY;
 
 
 
   // 選択範囲を取得
 
   // 選択範囲を取得
 
   var ty = s.GetTopPointY( mePosLogical );
 
   var ty = s.GetTopPointY( mePosLogical );
136行目: 170行目:
 
   s.EndOfLine( false, mePosLogical );
 
   s.EndOfLine( false, mePosLogical );
 
   s.SetAnchorPoint( mePosLogical, 1, ty );
 
   s.SetAnchorPoint( mePosLogical, 1, ty );
 +
 +
  // ブックマーク行を収集(選択範囲の先頭行は確認不要)
 +
  if ( ty < by ) {
 +
    var tp = s.GetAnchorPos(), bp = s.GetActivePos();
 +
    var bmArray = [];
 +
    s.SetActivePos( tp );
 +
    while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
 +
      bmArray.push( s.GetActivePointY( mePosLogical ) );
 +
    }
 +
    len = bmArray.length;
 +
    s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
 +
    ScrollX = sx;  ScrollY = sy;
 +
  }
 +
 
   // 選択範囲の文字列を取得
 
   // 選択範囲の文字列を取得
 
   var st = s.Text;
 
   var st = s.Text;
  
   // 最初に選択範囲がなかった場合は、行頭に「タブ文字×1」を追加
+
   /* 最初に選択範囲がなかった場合は、行頭に「タブ文字×1」を追加するパターン */
   if ( pos && tabEnable == 1 ) {
+
   if ( tabEnable == 1 && pos ) {
    var tab = "\t";
 
 
     s.Text = InsertSpace( st, tab );
 
     s.Text = InsertSpace( st, tab );
 
     s.SetActivePos( pos + tab.length ); // 範囲選択を残さない
 
     s.SetActivePos( pos + tab.length ); // 範囲選択を残さない
 
   }
 
   }
  
   // 選択範囲があった場合は、行頭に「半角スペース×2」を追加(空行は無視)
+
   /* 選択範囲があった場合は、行頭に「半角スペース×2」を追加(空行は無視) */
   else { // ( ! pos || tabEnable == 0 )
+
   else { // ( tabEnable == 0 || ! pos )
 
     var t = InsertSpace( st, blank );
 
     var t = InsertSpace( st, blank );
 
     if ( t != st ) {
 
     if ( t != st ) {
 
       s.Text = t;
 
       s.Text = t;
 +
 +
      // ブックマークを復元
 +
      if ( len ) {
 +
        var ep = s.GetActivePos();
 +
        for ( var i = 0; i < len; i ++ ) {
 +
          s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
 +
          s.SetBookmark();
 +
        }
 +
        s.SetActivePos( ep );
 +
      }
 
     }
 
     }
  
156行目: 213行目:
 
       s.SetActivePos( pos + ( t.length - st.length ) );
 
       s.SetActivePos( pos + ( t.length - st.length ) );
 
     }
 
     }
     else { // 範囲選択を残す
+
     else { // 範囲選択を残す(論理行単位)
       s.SetActivePoint( mePosLogical, 1, by + 1 );
+
       s.SetActivePos( s.GetActivePos() + 1 );
 
       s.SetAnchorPoint( mePosLogical, 1, ty );
 
       s.SetAnchorPoint( mePosLogical, 1, ty );
 
     }
 
     }
 
   }
 
   }
   ScrollX = sx;  ScrollY = sy;
+
 
 +
   Status = " 「スペース×2 追加」マクロ"
 
}
 
}
  
// 「引用の追加」マクロより拝借
+
ScrollX = sx;  ScrollY = sy;
function InsertSpace( arg1, arg2 ) {
+
Redraw = true;
   var a = arg1.split( "\n" );
+
 
   for ( var i = 0; i < a.length; i ++ )
+
var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
     if ( a[i].length || arg2 == "\t" )
+
Status += "  [ "
       a[i] = arg2 + a[i];
+
      + elapsedSec.replace( /\./, ". " )
 +
      + " 秒 ]";
 +
 
 +
/**
 +
* 関数 InsertSpace( str, blank )
 +
* str の各行の先頭に blank を挿入する
 +
*/
 +
function InsertSpace( str, blank ) {
 +
   var a = str.split( "\n" );
 +
   for ( var i = 0; i < a.length; i ++ ) {
 +
     if ( a[i].length || blank == "\t" ) {
 +
       a[i] = blank + a[i];
 +
    }
 +
  }
 
   return a.join( "\n" );
 
   return a.join( "\n" );
 
}
 
}
176行目: 247行目:
  
 
== 字上げ(スペース×2 削除) ==
 
== 字上げ(スペース×2 削除) ==
;スペース×2 削除.js
+
;スペース×2 削除.js <br>
<br>
 
 
キャレットまたは選択範囲をふくむ論理行の各先頭から「半角スペース×2」を削除します。
 
キャレットまたは選択範囲をふくむ論理行の各先頭から「半角スペース×2」を削除します。
 
* 行頭の「空白文字」を削除、またはキャレット位置の前後にある「タブ文字」を削除します。
 
* 行頭の「空白文字」を削除、またはキャレット位置の前後にある「タブ文字」を削除します。
191行目: 261行目:
 
#title = "字上げ"
 
#title = "字上げ"
 
#tooltip = "スペース×2 削除"
 
#tooltip = "スペース×2 削除"
 +
#icon = "space_x2[2].ico"
 
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",249
 
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",249
// ※「引用の追加」マクロから行頭の文字列を削除するコードを拝借した
 
  
// ■選択範囲なしのときに、キャレット位置の前後にある「タブ文字」を優先的に削除するか?
+
var start = new Date(); // 所要時間計測(開始)
var nearestTab = true;
+
 
 +
/**
 +
* ---------------------------------------------------------
 +
* 「字上げ(スペース×2 削除)」マクロ
 +
*  sukemaru, 2018/11/01 - 2019/11/10
 +
* ---------------------------------------------------------
 +
* 行頭の「空白文字」を削除、またはキャレット位置の前後にある「タブ文字」を削除する。
 +
* 選択範囲があった場合は、つねに行頭の「空白文字」だけを削除する。
 +
* 削除対象の「空白文字」は、「半角スペース×2」以外の空白文字もふくめて
 +
* 配列 blank で定義する。
 +
* ※「引用の追加」マクロから行頭の文字列を削除するコードを流用した
 +
*
 +
* 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 +
*/
 +
 
 +
// ---------- ▼ 設定項目 ▼ ----------
  
   // false にすると、つねに行頭の空白文字のみを削除
+
// ■ 選択範囲なしのときに、キャレット位置の前後にある「タブ文字」を優先的に削除するか?
  // true にすると、キャレット付近の「タブ文字×1」を優先的に削除(タブ文字がなければ行頭の空白を削除)
+
var deleteNearestTab = true;
 +
   /**
 +
  * false にすると、つねに行頭の空白文字のみを削除
 +
  * true にすると、キャレット付近の「タブ文字×1」を優先的に削除
 +
  *    (タブ文字がなければ行頭の空白を削除)
 +
  */
  
// ■削除対象(削除の単位)にする行頭の空白文字の定義
 
var blank = new Array( "  " , " " , " " , "\t" );
 
  
  // 初期値: new Array( "  " , " " , " " , "\t" )
+
// ■ 削除対象(削除の単位)にする行頭の空白文字の定義
   // i.e. 「半角スペース×2 "  "」「半角スペース×1 " "」「全角スペース×1 " " 」「タブ文字×1 "\t"
+
var blank = [ "  " , " " , " " , "\t" ];
   // 前に置いたもののほうが優先順位が高くなるので、行頭に半角スペースが3つある行で連続で実行した場合、
+
   /**
   //   1回目では「半角スペース×2」を削除し、2回目で「半角スペース×1」を削除する
+
  * 初期値: [ "  " , " " , " " , "\t" ]
  // ※ 空白文字以外の "文字列" を Array() のなかに追加するのも可
+
  * i.e. 「半角空白×2」「半角空白×1」「全角空白×1」「タブ文字×1」
 +
  * ※ 前に置いたもののほうが優先順位が高くなる。
 +
  *    e.g. 行頭に半角空白が3つある行で連続で実行した場合、
 +
  *   1回目では「半角空白×2」を削除し、2回目で「半角空白×1」を削除する。
 +
  * 削除対象を「半角空白×4 ~ 1」「全角空白×2 ~ 1」「タブ文字×1」にするなら
 +
  *   blank = [ "    " , "   " , "  " , " " , "  " , " " , "\t" ];
 +
  * ※ 空白文字以外の "文字列" を [ ... ] のなかに追加するのも可。
 +
  */
  
 +
// ---------- ▲ 設定項目 ▲ ----------
  
var s = document.selection;
+
Redraw = false;
 +
var sx = ScrollX,  sy = ScrollY;
  
// "選択範囲なし" のフラグ
+
var d = editor.ActiveDocument;
var pos = s.IsEmpty ? s.GetActivePos() : "";
+
var s = editor.ActiveDocument.selection;
 +
var len = 0;
 +
 
 +
var pos = s.IsEmpty ? s.GetActivePos() : ""; // "選択範囲なし" のフラグ
 +
var isDone = false; // Quit() メソッドの代用フラグ
 +
 
 +
if ( d.ReadOnly ) {
 +
  Status = " ドキュメントは書き換え禁止です。";
 +
  isDone = true;
 +
}
  
// キャレット付近の「タブ文字×1」を優先的に削除するパターン
+
/* カーソル付近の「タブ文字×1」を削除するパターン(左側優先) */
var isDone = false;
+
else if ( pos && deleteNearestTab ) {
if ( pos && nearestTab ) {
+
   if ( d.Text.charAt( pos - 1 ) == "\t" ) {
   if ( document.Text.charAt( pos - 1 ) == "\t" ) {
 
 
     s.DeleteLeft();
 
     s.DeleteLeft();
 
     isDone = true;
 
     isDone = true;
 
   }
 
   }
   else if ( document.Text.charAt( pos ) == "\t" ) {
+
   else if ( d.Text.charAt( pos ) == "\t" ) {
 
     s.Delete();
 
     s.Delete();
 
     isDone = true;
 
     isDone = true;
 
   }
 
   }
 
}
 
}
 +
 
if ( ! isDone ) {
 
if ( ! isDone ) {
  var sx = ScrollX,  sy = ScrollY;
 
 
 
   // 選択範囲を取得
 
   // 選択範囲を取得
 +
  var tx = s.GetTopPointX( mePosLogical );
 
   var ty = s.GetTopPointY( mePosLogical );
 
   var ty = s.GetTopPointY( mePosLogical );
 +
  var bx = s.GetBottomPointX( mePosLogical );
 
   var by = s.GetBottomPointY( mePosLogical );
 
   var by = s.GetBottomPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
 
 
   // 選択範囲を拡張
 
   // 選択範囲を拡張
 
   if ( by != ty && bx == 1 ) {
 
   if ( by != ty && bx == 1 ) {
241行目: 346行目:
 
   s.EndOfLine( false, mePosLogical );
 
   s.EndOfLine( false, mePosLogical );
 
   s.SetAnchorPoint( mePosLogical, 1, ty );
 
   s.SetAnchorPoint( mePosLogical, 1, ty );
 +
 +
  // ブックマーク行を収集(選択範囲の先頭行は確認不要)
 +
  if ( ty < by ) {
 +
    var tp = s.GetAnchorPos(), bp = s.GetActivePos();
 +
    var bmArray = [];
 +
    s.SetActivePos( tp );
 +
    while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
 +
      bmArray.push( s.GetActivePointY( mePosLogical ) );
 +
    }
 +
    len = bmArray.length;
 +
    s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
 +
    ScrollX = sx;  ScrollY = sy;
 +
  }
 +
 
   // 選択範囲の文字列を取得
 
   // 選択範囲の文字列を取得
 
   var st = s.Text;
 
   var st = s.Text;
  
   // 行頭の空白文字を削除
+
   /* 行頭の空白文字を削除 */
 
   var t = DeleteSpace( st, blank );
 
   var t = DeleteSpace( st, blank );
 
   if ( t != st ) {
 
   if ( t != st ) {
 
     s.Text = t;
 
     s.Text = t;
 +
 +
    // ブックマークを復元
 +
    if ( len ) {
 +
      var ep = s.GetActivePos();
 +
      for ( var i = 0; i < len; i ++ ) {
 +
        s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
 +
        s.SetBookmark();
 +
      }
 +
      s.SetActivePos( ep );
 +
    }
 
   }
 
   }
  
   if ( pos ) { // 範囲選択を残さない
+
   if ( pos ) { // 範囲選択を残さない
     s.SetActivePos( pos - ( st.length - t.length ) );
+
     if ( st.length - t.length >= tx ) {
 +
      s.SetActivePoint( mePosLogical, 1, ty );
 +
    }
 +
    else {
 +
      s.SetActivePos( pos - ( st.length - t.length ) );
 +
    }
 
   }
 
   }
   else { // 範囲選択を残す
+
   else { // 範囲選択を残す(論理行単位)
     s.SetActivePoint( mePosLogical, 1, by + 1 );
+
     s.SetActivePos( s.GetActivePos() + 1 );
 
     s.SetAnchorPoint( mePosLogical, 1, ty );
 
     s.SetAnchorPoint( mePosLogical, 1, ty );
 
   }
 
   }
   ScrollX = sx;  ScrollY = sy;
+
 
 +
   Status = " 「スペース×2 削除」マクロ"
 
}
 
}
  
// 「引用の追加」マクロより拝借
+
ScrollX = sx;  ScrollY = sy;
function DeleteSpace( arg1, arg2 ) {
+
Redraw = true;
   var a = arg1.split( "\n" );
+
 
 +
var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
 +
Status += "  [ "
 +
      + elapsedSec.replace( /\./, ". " )
 +
      + " 秒 ]";
 +
 
 +
/**
 +
* 関数 DeleteSpace( str, blank )
 +
* str の各行の先頭から blank を削除する
 +
* ※ blank は空白文字列のパターンを収録した配列
 +
*/
 +
function DeleteSpace( str, blank ) {
 +
   var a = str.split( "\n" );
 
   for ( var i = 0; i < a.length; i ++ ) {
 
   for ( var i = 0; i < a.length; i ++ ) {
     for ( var j = 0; j < arg2.length; j ++ ) {
+
    if ( ! a[i] ) { continue; }
       if ( arg2[j].length == 0 )
+
     for ( var j = 0; j < blank.length; j ++ ) {
        continue;
+
       if ( blank[j] && a[i].substr( 0, blank[j].length ) == blank[j] ) {
      if ( a[i].substr( 0, arg2[j].length ) == arg2[j] ) {
+
         a[i] = a[i].substr( blank[j].length );
         a[i] = a[i].substr( arg2[j].length );
 
 
         break;
 
         break;
 
       }
 
       }
291行目: 437行目:
 
#title = "インデント"
 
#title = "インデント"
 
#tooltip = "選択範囲がなくてもインデント"
 
#tooltip = "選択範囲がなくてもインデント"
#icon = "Mery用 マテリアルデザインっぽいアイコン.icl",260
+
#icon = "indent_right.ico"
 +
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",260
 +
 
 +
var start = new Date(); // 所要時間計測(開始)
 +
 
 +
/**
 +
* ---------------------------------------------------------
 +
* 「インデント」マクロ
 +
*  sukemaru, 2018/11/15 - 2019/11/10
 +
* ---------------------------------------------------------
 +
* ・選択範囲なしでも、論理行全体をタブインデント(行頭)して範囲選択する
 +
*  選択範囲が1行内ならもとの選択範囲を維持し、複数行なら対象の論理行全体を範囲選択する
 +
* ・またはカーソル位置にタブ文字を挿入する
 +
* 【推奨設定】 Tab キーに割りあてるなら tabEnable = 2,
 +
*              ツールバーアイコンにするなら tabEnable = 0
 +
*
 +
* 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 +
*/
 +
 
 +
// ---------- ▼ 設定項目 ▼ ----------
 +
 
 +
// ■ 選択範囲があるときに、選択範囲を「タブ文字」にするか?
 +
//    行全体をタブインデントするか?
  
// ■選択範囲があるときに、選択範囲を「タブ文字」にするか? 行全体をタブインデントするか?
 
 
var tabEnable = 0;
 
var tabEnable = 0;
  
   // 0 にすると、選択範囲がなくてもつねに行全体をタブインデント(行頭)
+
   /**
  // 1 にすると、選択範囲があれば行全体をタブインデント(※ツールバーアイコンの「インデント」に似た動作)
+
  * 0: 選択範囲がなくてもつねに行全体をタブインデント(行頭)
  // 2 にすると、選択範囲が1行内のときだけ選択範囲を「タブ文字」にする (※Tab キーの通常動作にちかい)
+
  * 1: 選択範囲があれば行全体をタブインデント、なければキャレット位置にタブ文字を挿入
  // 3 にすると、つねに選択範囲を「タブ文字」にする(※インデントしない)
+
  *  (※ ツールバーアイコンの「インデント」に似た動作)
 +
  * 2: 選択範囲が1行内(論理行)のときだけ選択範囲を「タブ文字」にする
 +
  *  (※ Tab キーの通常動作にちかい ← Mery 標準機能では "表示行" で1行内)
 +
  * 3: つねに選択範囲を「タブ文字」にする(※ インデントしない)
 +
  * 4: 選択範囲が1行内(論理行)のときは選択範囲の先頭に「タブ文字」を追加し、
 +
  *    それ以外の場合には 0 と同じ動作(行全体をタブインデント)をする
 +
  *
 +
  * ※ 0 の場合、「タブ文字」を挿入することができないので、ツールバーアイコン向けの設定。
 +
  * ※ 1 の場合、選択範囲を「タブ文字」にすることができないので、
 +
  *      Tab キーにマクロを割りあてると少し不便になるかも?
 +
  *      範囲選択 → 削除 (Delete / BackSpace) → 「インデント」マクロ (Tab)
 +
  * ※ 2 の場合に1行だけインデントさせるなら、行頭でクリックするか、
 +
  *      行内でトリプルクリック、または行番号のクリックで行全体を選択範囲にして
 +
  *    「インデント」マクロ (末尾改行まで含める必要あり)。
 +
  *    [EOF] マークのある(さいごに改行がない)文書末行だけの1行選択ではインデントできない。
 +
  *      ⇔ Tab キーの通常動作では末尾改行を含める必要はない
 +
  * ※ 3 は、わざわざマクロでやる意味もないかと。
 +
  * ※ 4 は、0 と 1 の動作の統合型(1 の動作条件を反転させたもの)。
 +
  */
  
  // ※ 0 の場合、「タブ文字」を挿入することができないので、ツールバーアイコン向けの設定。
+
// ---------- ▲ 設定項目 ▲ ----------
  // ※ 1 の場合、選択範囲を「タブ文字」にすることができないので、Tab キーにマクロを割りあてると少し不便になるかも?
 
  //  範囲選択 → 削除 (Delete / BackSpace) → 「インデント」マクロ (Tab)
 
  // ※ 2 の場合に1行だけインデントさせるなら、行頭でクリックするか、行内でトリプルクリック
 
  //  または行番号のクリックで行全体を選択範囲にして「インデント」マクロ (末尾改行まで含める必要あり)。
 
  //  [EOF] マークのある(さいごに改行がない)文書末行だけの1行選択ではインデントできない。
 
  //  ⇔ Tab キーの通常動作では末尾改行を含める必要はない
 
  // ※ 3 は、わざわざマクロでやる意味もないかと。
 
  
 +
var tab = "\t";
  
 +
Redraw = false;
 
var sx = ScrollX,  sy = ScrollY;
 
var sx = ScrollX,  sy = ScrollY;
var s = document.selection;
+
var d = editor.ActiveDocument;
 +
var s = editor.ActiveDocument.selection;
 +
var len = 0;
  
// 選択範囲
+
if ( d.ReadOnly ) {
var act = s.GetActivePos();
+
  Status = " ドキュメントは書き換え禁止です。";
var anc = s.GetAnchorPos();
+
}
var ty = s.GetTopPointY( mePosLogical );
 
var bx = s.GetBottomPointX( mePosLogical );
 
var by = y = s.GetBottomPointY( mePosLogical );
 
  
// カーソル位置にタブを挿入して終了するパターン
 
if ( ( s.IsEmpty && tabEnable == 1 ) || ( tabEnable == 2 && ty == by ) || tabEnable == 3 ) {
 
  s.Text = "\t";
 
}
 
 
else {
 
else {
   // 選択範囲を拡張
+
   // 選択範囲
   if ( ty != by && bx == 1 ) {
+
   var act = s.GetActivePos();
     y --; // 選択範囲の末尾が行頭 x = 1 にあるときの調整
+
  var anc = s.GetAnchorPos();
 +
  var tx = s.GetTopPointX( mePosLogical );
 +
  var ty = s.GetTopPointY( mePosLogical );
 +
  var bx = s.GetBottomPointX( mePosLogical );
 +
  var by = yy = s.GetBottomPointY( mePosLogical );
 +
  var inLine = ( ty == by && act != anc );
 +
 
 +
  /* 行の途中の選択範囲を字下げするパターン */
 +
  if ( inLine && tabEnable == 4 ) {
 +
     s.Text = tab + s.Text;
 +
    s.SetAnchorPoint( mePosLogical, tx, ty );
 
   }
 
   }
  s.SetActivePoint( mePosLogical, 1, y );
 
  s.EndOfLine( false, mePosLogical );
 
  s.SetAnchorPoint( mePosLogical, 1, ty );
 
  var st = s.Text;
 
  
   // インデント
+
   /* カーソル位置にタブを挿入するパターン */
   s.Text = st.replace( /^/gm , "\t" );
+
   else if ( ( tabEnable == 1 && s.IsEmpty )
 +
        || ( tabEnable == 2 && ty == by )
 +
        ||  tabEnable == 3 ) {
 +
    s.Text = tab;
 +
  }
  
  // 選択範囲を復元
 
  if ( ty == by ) {
 
    s.SetActivePos( act + 1 );
 
    s.SetAnchorPos( anc + 1 );
 
  }
 
 
   else {
 
   else {
     s.SetActivePos( s.GetActivePos() + 1 );
+
    // 選択範囲を拡張
 +
    if ( ty != by && bx == 1 ) {
 +
      yy --; // 選択範囲の末尾が行頭にあるときの調整
 +
    }
 +
     s.SetActivePoint( mePosLogical, 1, yy );
 +
    s.EndOfLine( false, mePosLogical );
 
     s.SetAnchorPoint( mePosLogical, 1, ty );
 
     s.SetAnchorPoint( mePosLogical, 1, ty );
 +
 +
    // ブックマーク行を収集(選択範囲の先頭行は確認しない)
 +
    if ( ty < by ) {
 +
      var tp = s.GetAnchorPos(), bp = s.GetActivePos();
 +
      s.SetActivePos( tp );
 +
      var bmArray = [];
 +
      while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
 +
        bmArray.push( s.GetActivePointY( mePosLogical ) );
 +
      }
 +
      len = bmArray.length;
 +
      s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
 +
      ScrollX = sx;  ScrollY = sy;
 +
    }
 +
 +
    // インデント
 +
    var st = s.Text;
 +
    s.Text = st.replace( /^/gm , tab );
 +
 +
    // ブックマークを復元
 +
    if ( len ) {
 +
      var ep = s.GetActivePos();
 +
      for ( var i = 0; i < len; i ++ ) {
 +
        s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
 +
        s.SetBookmark();
 +
      }
 +
      s.SetActivePos( ep );
 +
    }
 +
 +
    // 選択範囲を復元
 +
    if ( ty == by ) {
 +
      s.SetActivePos( act + tab.length );
 +
      s.SetAnchorPos( anc + tab.length );
 +
    }
 +
    else {
 +
      s.SetActivePos( s.GetActivePos() + 1 );
 +
      s.SetAnchorPoint( mePosLogical, 1, ty );
 +
    }
 
   }
 
   }
 +
 +
  Status = " 「インデント」マクロ"
 
}
 
}
  
 
ScrollX = sx;  ScrollY = sy;
 
ScrollX = sx;  ScrollY = sy;
 +
Redraw = true;
 +
 +
var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
 +
Status += "  [ "
 +
      + elapsedSec.replace( /\./, ". " )
 +
      + " 秒 ]";
 
</source>
 
</source>
  
363行目: 593行目:
  
  
【推奨設定】 「字上げ」マクロと並存させるなら ''deleteSpace = 0'' , 「字上げ」マクロなしで Shift+Tab キーに割りあてるなら ''deleteSpace ≠ 0'' <br>  
+
【推奨設定】 「字上げ」マクロと並存させるなら ''deleteSpace = 0'' , 「字上げ」マクロなしで Shift+Tab キーに割りあてるなら ''deleteSpace '''''' 0'' ( 1 以上の値)<br>  
 
: 設定用変数 ''deleteSpace = n'' で '''3''' 以上の数値を指定するさいは、Mery のオプション設定の「タブの桁数」を目安にしてください(大きな数字や非整数値を入れての動作検証はしていません)。
 
: 設定用変数 ''deleteSpace = n'' で '''3''' 以上の数値を指定するさいは、Mery のオプション設定の「タブの桁数」を目安にしてください(大きな数字や非整数値を入れての動作検証はしていません)。
  
371行目: 601行目:
 
#title = "逆インデント"
 
#title = "逆インデント"
 
#tooltip = "選択範囲がなくてもアンインデント"
 
#tooltip = "選択範囲がなくてもアンインデント"
#icon = "Mery用 マテリアルデザインっぽいアイコン.icl",261
+
#icon = "indent_left.ico"
 +
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",261
  
// ■選択範囲なしのときに、カーソル位置の前後にある「タブ文字」を優先的に削除するか?
+
var start = new Date(); // 所要時間計測(開始)
var nearestTab = true;
 
  
   // false にすると、つねに行頭の空白文字のみを削除
+
/**
   // true にすると、カーソル付近の「タブ文字×1」を優先的に削除(タブ文字がなければ行頭の空白を削除)
+
* ---------------------------------------------------------
 +
* 「逆インデント」マクロ
 +
*   sukemaru, 2018/11/15 - 2019/11/10
 +
* ---------------------------------------------------------
 +
* 選択範囲なしでも、行頭またはカーソル付近の「タブ文字×1」か、
 +
* 行頭の「半角スペース×2」を削除する
 +
* ・選択範囲なしならカーソル付近のタブを削除するか、
 +
*   またはカーソルのある1行をアンインデントして、カーソル位置を復帰する
 +
* ・選択範囲ありなら論理行全体をアンインデントして範囲選択する
 +
*
 +
* 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 +
*/
  
// ■行頭の「半角スペース」や「「全角スペース」も削除するか?
+
// ---------- ▼ 設定項目 ▼ ----------
 +
 
 +
 
 +
// ■ 選択範囲なしのときに、カーソル位置の前後にある「タブ文字」を優先的に削除するか?
 +
// ※ 選択範囲が1行内で、先頭に「タブ文字」がある場合も優先的に削除するか?
 +
var deleteNearestTab = true;
 +
  /**
 +
  * false にすると、つねに行頭の空白文字のみを削除
 +
  * true にすると、カーソル付近の「タブ文字×1」を優先的に削除
 +
  * (タブ文字がなければ行頭の空白を削除)
 +
  */
 +
 
 +
 
 +
// ■行頭の「半角スペース」や「全角スペース」も削除するか?
 
var deleteSpace = 1;
 
var deleteSpace = 1;
 +
  /**
 +
  * ※ 正の整数値で指定してください
 +
  * 0: 行頭の「タブ文字×1」だけを削除
 +
  * 1: 行頭の「タブ文字×1」と「半角スペース×1~2」も削除
 +
  * 2: 行頭の「タブ文字×1」と「半角スペース×1~2」と「全角スペース×1」も削除
 +
  * 3: 1回の逆インデントで削除できる「半角スペース×n」の最大数が増加
 +
  *  ※ 削除できる「全角スペース」の最大数は n / 2 ( → roundDecimal 変数で設定 )
 +
  */
  
  // ※ 正の整数値で指定してください
 
  // 0 にすると、「タブ文字×1」だけを削除
 
  // 1 にすると、行頭の「半角スペース×2」と「半角スペース×1」も削除
 
  // 2 にすると、行頭の「半角スペース×2」と「半角スペース×1」と「全角スペース×1」も削除
 
  // 3 以上にすると、1回の逆インデントで削除できる「半角スペース×n」の最大数が増加
 
  //  → 削除できる「全角スペース」の最大数は n / 2 (初期設定では小数点以下を切り捨て)
 
  
 +
    // ■deleteSpace が 3 以上のとき、削除できる「全角スペース」の最大数
 +
    var roundDecimal = false;
 +
      /**
 +
      * ※ deleteSpace が奇数のときの小数点以下の処理
 +
      * false にすると ( deleteSpace / 2 ) の小数点以下を切り捨て
 +
      * true にすると  ( deleteSpace / 2 ) の小数点以下を切り上げ(四捨五入)
 +
      */
  
 +
// ---------- ▲ 設定項目 ▲ ----------
 +
 +
Redraw = false;
 
var sx = ScrollX,  sy = ScrollY;
 
var sx = ScrollX,  sy = ScrollY;
var s = document.selection;
+
var d = editor.ActiveDocument;
 +
var s = editor.ActiveDocument.selection;
  
// "選択範囲なし" のフラグ
+
var pos = s.IsEmpty ? s.GetActivePos() : ""; // "選択範囲なし" のフラグ
var pos = s.IsEmpty ? s.GetActivePos() : "";
+
var isDone = false; // Quit() メソッドの代用フラグ
 +
var len = 0;
 +
 
 +
if ( d.ReadOnly ) {
 +
  Status = " ドキュメントは書き換え禁止です。";
 +
  isDone = true;
 +
}
  
// カーソル付近の「タブ文字×1」を削除する場合(左側優先)
+
/* カーソル付近の「タブ文字×1」を削除するパターン(左側優先) */
var isDone = false;
+
else if ( pos && deleteNearestTab ) {
if ( pos && nearestTab ) {
+
   if ( d.Text.charAt( pos - 1 ) == "\t" ) {
   if ( document.Text.charAt( pos - 1 ) == "\t" ) {
 
 
     s.DeleteLeft();
 
     s.DeleteLeft();
 
     isDone = true;
 
     isDone = true;
 
   }
 
   }
   else if ( document.Text.charAt( pos ) == "\t" ) {
+
   else if ( d.Text.charAt( pos ) == "\t" ) {
 
     s.Delete();
 
     s.Delete();
 
     isDone = true;
 
     isDone = true;
 
   }
 
   }
 
}
 
}
 +
 
if ( ! isDone ) {
 
if ( ! isDone ) {
 
   // 選択範囲
 
   // 選択範囲
 
   var act = s.GetActivePos();
 
   var act = s.GetActivePos();
 
   var anc = s.GetAnchorPos();
 
   var anc = s.GetAnchorPos();
 +
  var tx = s.GetTopPointX( mePosLogical );
 
   var ty = s.GetTopPointY( mePosLogical );
 
   var ty = s.GetTopPointY( mePosLogical );
 
   var bx = s.GetBottomPointX( mePosLogical );
 
   var bx = s.GetBottomPointX( mePosLogical );
   var by = y = s.GetBottomPointY( mePosLogical );
+
   var by = yy = s.GetBottomPointY( mePosLogical );
   // 選択範囲を拡張
+
   var inLine = ( ty == by && act != anc );
  if ( ty != by && bx == 1 ) {
 
    y --; // 選択範囲の末尾が行頭 x = 1 にあるときの調整
 
  }
 
  s.SetActivePoint( mePosLogical, 1, y );
 
  s.EndOfLine( false, mePosLogical );
 
  s.SetAnchorPoint( mePosLogical, 1, ty );
 
 
   var st = s.Text;
 
   var st = s.Text;
  
   // 逆インデント
+
   /* 選択範囲が1行内のときに、先頭の「タブ文字」を優先的に削除するパターン */
   // ( deleteSpace >= 3 ) では、/^\t|^[ ]{1,n}|^[ ]{1,m}/gm  の n に deleteSpace の値、m に n/2 を代入 ※toString().replace() で小数点以下を切り捨て
+
   if ( inLine && deleteNearestTab && st.charAt( 0 ) == "\t" ) {
  // ■ m = n/2 の小数点以下を切り上げ(四捨五入)にするなら Math.round() 関数の行を使用する
+
    s.Text = st.replace( /^\t/, "" );
  // ※必ず ( deleteSpace >= 3 ) の行のひとつをコメントアウト状態にしておくこと
+
    s.SetAnchorPoint( mePosLogical, tx, ty );
  var indent = ( deleteSpace == 1 ) ? "^\\t|^[ ]{1,2}"
 
            : ( deleteSpace == 2 ) ? "^\\t|^[ ]{1,2}|^[ ]"
 
            : ( deleteSpace >= 3 ) ? "^\\t|^[ ]{1," + deleteSpace + "}|^[ ]{1," + ( deleteSpace / 2 ).toString().replace( /\.\d+$/ , "" ) + "}"
 
          // : ( deleteSpace >= 3 ) ? "^\\t|^[ ]{1," + deleteSpace + "}|^[ ]{1," + Math.round( deleteSpace / 2 ) + "}"
 
              /*      else      */ : "^\\t";
 
 
 
  var u = st.replace( new RegExp( indent , "gm" ) , "" );
 
  if ( u != s.Text ) {
 
    s.Text = u;
 
 
   }
 
   }
  
  // カーソル位置または選択範囲を復元
 
  if ( ty == by ) {
 
    s.SetActivePos( act - ( st.length - u.length ) );
 
    s.SetAnchorPos( anc - ( st.length - u.length ) );
 
    if ( s.GetTopPointY( mePosLogical ) != ty )
 
      s.SetActivePoint( mePosLogical, 1, ty );
 
  }
 
 
   else {
 
   else {
     s.SetActivePos( s.GetActivePos() + 1 );
+
    // 選択範囲を拡張
 +
    if ( ty != by && bx == 1 ) {
 +
      yy --; // 選択範囲の末尾が行頭 x = 1 にあるときの調整
 +
    }
 +
     s.SetActivePoint( mePosLogical, 1, yy );
 +
    s.EndOfLine( false, mePosLogical );
 
     s.SetAnchorPoint( mePosLogical, 1, ty );
 
     s.SetAnchorPoint( mePosLogical, 1, ty );
 +
 +
    // ブックマーク行を収集(選択範囲の先頭行は確認不要)
 +
    if ( ty < by ) {
 +
      var tp = s.GetAnchorPos(), bp = s.GetActivePos();
 +
      var bmArray = [];
 +
      s.SetActivePos( tp );
 +
      while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
 +
        bmArray.push( s.GetActivePointY( mePosLogical ) );
 +
      }
 +
      len = bmArray.length;
 +
      s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
 +
      ScrollX = sx;  ScrollY = sy;
 +
    }
 +
 +
    /* 逆インデント */
 +
    var regStr1 = "^\\t|^[ ]{1,2}";
 +
    var regStr2 = "^\\t|^[ ]{1,2}|^[ ]";
 +
    var regStr3 = "^\\t|^[ ]{1," + deleteSpace + "}|^[ ]{1,"
 +
                + ( roundDecimal ? Math.round( deleteSpace / 2 ) // 切り上げ
 +
                                : Math.floor( deleteSpace / 2 ) ) // 切り捨て
 +
                + "}";
 +
    var indent = ( deleteSpace == 1 ) ? regStr1
 +
              : ( deleteSpace == 2 ) ? regStr2
 +
              : ( deleteSpace >= 3 ) ? regStr3
 +
                /*    else      */ : "^\\t";
 +
 +
    st = s.Text;
 +
    var u = st.replace( new RegExp( indent , "gm" ) , "" );
 +
    if ( u != st ) {
 +
      s.Text = u;
 +
 +
      // ブックマークを復元
 +
      if ( len ) {
 +
        var ep = s.GetActivePos();
 +
        for ( var i = 0; i < len; i ++ ) {
 +
          s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
 +
          s.SetBookmark();
 +
        }
 +
        s.SetActivePos( ep );
 +
      }
 +
    }
 +
 +
    // 選択範囲が1行だったときは、位置関係を維持して選択範囲を復元する
 +
    if ( ty == by ) {
 +
      var gap = st.length - u.length;
 +
      if ( bx <= gap ) {
 +
        s.SetActivePoint( mePosLogical, 1, ty );
 +
      }
 +
      else if ( anc < act && tx <= gap ) {
 +
        s.SetActivePos( act - gap );
 +
        s.SetAnchorPoint( mePosLogical, 1, ty );
 +
      }
 +
      else if ( tx <= gap ) {
 +
        s.SetActivePoint( mePosLogical, 1, ty );
 +
        s.SetAnchorPos( anc - gap );
 +
      }
 +
      else {
 +
        s.SetActivePos( act - gap );
 +
        s.SetAnchorPos( anc - gap );
 +
      }
 +
    }
 +
    // 選択範囲が複数行だったときは、拡張した選択範囲を復元する
 +
    else {
 +
      s.SetActivePos( s.GetActivePos() + 1 );
 +
      s.SetAnchorPoint( mePosLogical, 1, ty );
 +
    }
 
   }
 
   }
 +
 +
  Status = " 「インデント」マクロ"
 
}
 
}
 +
 
ScrollX = sx;  ScrollY = sy;
 
ScrollX = sx;  ScrollY = sy;
 +
Redraw = true;
 +
 +
var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
 +
Status += "  [ "
 +
      + elapsedSec.replace( /\./, ". " )
 +
      + " 秒 ]";
 
</source>
 
</source>
  
458行目: 790行目:
 
*(2019/04/07 sukemaru)
 
*(2019/04/07 sukemaru)
 
:ソースコードから Quit() メソッドを削除
 
:ソースコードから Quit() メソッドを削除
 +
----
 +
*(2019/11/10 sukemaru)
 +
:Mery 2.8.6 以上でブックマークを保持
 +
:※ Mery 2.8.5 以前ではブックマーク機能の仕様が不安定なので、個別対応はあきらめた
 +
----

2019年11月10日 (日) 12:48時点における版

論理行単位で字下げ・字上げします。
インデントには任意の文字列を設定できます。※初期設定は半角空白2個です。

Indent-Unindent.png

masme 版

更新履歴

  • 2019/06/01
    • 字下げ・字上げした次の行に変更行の印がつかないようにした。
      末尾の改行(次の行頭)を範囲に含めず書き換えるように変更。
    • with 文を使用せず変数化した(他の自作マクロに合わせた)。
  • 2019/04/12
    • (字下げ) Quit() → break ラベル文に変更。
  • 2015/02/14
    • (字上げ) 「インデントの定義」に正規表現の特殊文字があると誤動作する不具合を修正。
    • 矩形選択(始点or終点が左下かつ論理行頭)時、下端の行が範囲から漏れる不具合を修正。
  • 2014/02/09
    • 初版公開。

字下げ (インデント)

  • 複数行選択時 (選択範囲が2行以上) は字下げします。
    単一行選択時 (選択範囲が1行以内) または非選択時はタブ文字を挿入します。
    ※選択範囲の行数はステータスバーの「xx文字 (xx行) 選択」の部分で判断してください。
  • 空行 (改行のみの行) は初期状態では字下げしません。
  • 「Tab」キーなどに割り当ててご利用ください。
//■字下げ(インデント)
// 2014/02/09-2019/06/01
//・論理行単位で字下げする。空行は字下げしない。非選択時/単行選択時はタブ挿入。

//■インデントの定義 ●初期値="  "
var INDENT = "  ";

quit: {
var Sel = Document.Selection;
if (Sel.GetTopPointY(mePosView)===Sel.GetBottomPointY(mePosView)) {
  Sel.Text = "\t"; break quit; //非選択時/単行選択時はタブ挿入して終了
}
var ty = Sel.GetTopPointY(mePosLogical);
var by = Sel.GetBottomPointY(mePosLogical);
var bx = Sel.GetBottomPointX(mePosLogical);
var nn =(Sel.Text.match(/\n/g)||[]).length;
if (bx===1 && nn<=by-ty && nn) by--; //末尾改行対策
Sel.SetActivePoint(mePosLogical, 1, by);
Sel.EndOfLine(false, mePosLogical);
Sel.SetAnchorPoint(mePosLogical, 1, ty);
Sel.Text = Sel.Text.replace(/^(?!$)/gm,INDENT);
Sel.SetActivePoint(mePosLogical, 1, by+1);
Sel.SetAnchorPoint(mePosLogical, 1, ty);
}

字上げ (アンインデント)

  • 単一行選択時 (選択範囲が1行以内) または非選択時でも字上げします。
  • 「Shift + Tab」キーなどに割り当ててご利用ください。
//■字上げ(アンインデント)
// 2014/02/09-2019/06/01
//・論理行単位で字上げする。非選択時/単行選択時でも字上げする。

//■インデントの定義 ●初期値="  "
var INDENT = "  ";

var Sel = Document.Selection;
var ty = Sel.GetTopPointY(mePosLogical);
var by = Sel.GetBottomPointY(mePosLogical);
var bx = Sel.GetBottomPointX(mePosLogical);
var nn =(Sel.Text.match(/\n/g)||[]).length;
if (bx===1 && nn<=by-ty && nn) by--; //末尾改行対策
Sel.SetActivePoint(mePosLogical, 1, by);
Sel.EndOfLine(false, mePosLogical);
Sel.SetAnchorPoint(mePosLogical, 1, ty);
var pat = "^"+ INDENT.replace(/[$()*+.?\[\\\]^{|}]/g,"\\$&");
Sel.Text = Sel.Text.replace(new RegExp(pat,"gm"),"");
Sel.SetActivePoint(mePosLogical, 1, by+1);
Sel.SetAnchorPoint(mePosLogical, 1, ty);

sukemaru 版


ダウンロード:ファイル:字下げ/字上げ.zip」(アイコン入り)
最終更新: 2019/11/10 ブックマーク対応版

それぞれ専用の「マテリアルデザインっぽいアイコン」を同梱


※ ブックマーク対応の 2019/11/10 版の動作要件: Mery ver 2.8.6 以上

※ ブックマークを正常に保持できるのは Mery ver 2.8.6 以上の場合だけです。
それ以前のバージョンでは、Mery 本体側のブックマーク機能の仕様が安定していないので、ブックマークを正しく復元できません。
→ ver 2.8.5 以前の Mery には 2019/04/07 版(ブックマーク非対応)


字下げ(スペース×2 追加)

スペース×2 追加.js

キャレットまたは選択範囲をふくむ論理行の各先頭に「半角スペース×2」を追加します。

  • 選択範囲がなかった場合は「タブ文字」を追加、または「半角スペース×2」を行頭に追加します。
  • 選択範囲があった場合は、つねに「半角スペース×2」を行頭に追加します。
  • 行頭に「半角スペース×2」を追加する場合は、空行を無視します。
  • 選択範囲が末尾に改行を含んでいた場合は、最後の改行を無視します。
#title = "字下げ"
#tooltip = "スペース×2 追加"
#icon = "space_x2[1].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",247

var start = new Date();	// 所要時間計測(開始)

/**
 * ---------------------------------------------------------
 * 「字下げ(スペース×2 追加)」マクロ
 *   sukemaru, 2018/11/01 - 2019/11/10
 * ---------------------------------------------------------
 * 最初に選択範囲がなかった場合は「タブ文字」を追加、
 * または「半角スペース×2」を行頭に追加する。
 * 選択範囲があった場合は、つねに「半角スペース×2」を行頭に追加する(空行は無視)。
 * ※「引用の追加」マクロから行頭に文字列を追加するコードを拝借した
 * 
 * 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 */

// ---------- ▼ 設定項目 ▼ ----------

// ■ 選択範囲なしのときには「タブ文字×1」を追加するか?
var tabEnable = 0;
  /**
   * 0: 「半角空白×2」を行頭に追加する(空行は無視)
   * 1: 選択範囲なしのときは「タブ文字×1」を行頭に追加
   * 2: 選択範囲なしのときは「タブ文字×1」をキャレット位置に追加
   */


// ■ 行頭に追加する空白文字の定義(初期値:「半角空白×2」)
var blank = "  ";		// 半角空白×2

// ---------- ▲ 設定項目 ▲ ----------

Redraw = false;
var sx = ScrollX,  sy = ScrollY;

var tab = "\t";
var d = editor.ActiveDocument;
	var s = editor.ActiveDocument.selection;
	var len = 0;

// "選択範囲なし" のフラグ
var pos = s.IsEmpty ? s.GetActivePos() : "";

if ( d.ReadOnly ) {
  Status = " ドキュメントは書き換え禁止です。";
}

/* キャレット位置に「タブ文字×1」を挿入するパターン */
else if ( tabEnable == 2 && pos ) {
  s.Text = tab;
}

else {
  // 選択範囲を取得
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  // 選択範囲を拡張
  if ( by != ty && bx == 1 ) {
    by -= 1;
  }
  s.SetActivePoint( mePosLogical, 1, by );
  s.EndOfLine( false, mePosLogical );
  s.SetAnchorPoint( mePosLogical, 1, ty );

  // ブックマーク行を収集(選択範囲の先頭行は確認不要)
  if ( ty < by ) {
    var tp = s.GetAnchorPos(), bp = s.GetActivePos();
    var bmArray = [];
    s.SetActivePos( tp );
    while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
      bmArray.push( s.GetActivePointY( mePosLogical ) );
    }
    len = bmArray.length;
    s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
    ScrollX = sx;  ScrollY = sy;
  }

  // 選択範囲の文字列を取得
  var st = s.Text;

  /* 最初に選択範囲がなかった場合は、行頭に「タブ文字×1」を追加するパターン */
  if ( tabEnable == 1 && pos ) {
    s.Text = InsertSpace( st, tab );
    s.SetActivePos( pos + tab.length );	// 範囲選択を残さない
  }

  /* 選択範囲があった場合は、行頭に「半角スペース×2」を追加(空行は無視) */
  else {	// ( tabEnable == 0 || ! pos )
    var t = InsertSpace( st, blank );
    if ( t != st ) {
      s.Text = t;

      // ブックマークを復元
      if ( len ) {
        var ep = s.GetActivePos();
        for ( var i = 0; i < len; i ++ ) {
          s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
          s.SetBookmark();
        }
        s.SetActivePos( ep );
      }
    }

    if ( pos ) {	// 範囲選択を残さない
      s.SetActivePos( pos + ( t.length - st.length ) );
    }
    else {			// 範囲選択を残す(論理行単位)
      s.SetActivePos( s.GetActivePos() + 1 );
      s.SetAnchorPoint( mePosLogical, 1, ty );
    }
  }

  Status = " 「スペース×2 追加」マクロ"
}

ScrollX = sx;  ScrollY = sy;
Redraw = true;

var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
Status += "  [ "
       + elapsedSec.replace( /\./, ". " )
       + " 秒 ]";

/**
 * 関数 InsertSpace( str, blank )
 * str の各行の先頭に blank を挿入する
 */
function InsertSpace( str, blank ) {
  var a = str.split( "\n" );
  for ( var i = 0; i < a.length; i ++ ) {
    if ( a[i].length || blank == "\t" ) {
      a[i] = blank + a[i];
    }
  }
  return a.join( "\n" );
}


字上げ(スペース×2 削除)

スペース×2 削除.js

キャレットまたは選択範囲をふくむ論理行の各先頭から「半角スペース×2」を削除します。

  • 行頭の「空白文字」を削除、またはキャレット位置の前後にある「タブ文字」を削除します。
  • 選択範囲があった場合は、つねに行頭の「空白文字」だけを削除します。
  • 削除対象の行頭の「空白文字」には「半角スペース×2」以外の空白文字もふくめます。
i.e. 「半角スペース×2」「半角スペース×1」「全角スペース×1」「タブ文字×1」
  • 選択範囲が末尾に改行を含んでいた場合は、最後の改行を無視します。

※ sukemaru 版の「字上げ」と「逆インデント」マクロを並存させるメリットは少ないとおもいますので、お好みで選んでください。
「字上げ」マクロなら、削除対象に「空白文字」以外の任意の "文字列" や "記号" なども追加できます。

#title = "字上げ"
#tooltip = "スペース×2 削除"
#icon = "space_x2[2].ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",249

var start = new Date();	// 所要時間計測(開始)

/**
 * ---------------------------------------------------------
 * 「字上げ(スペース×2 削除)」マクロ
 *   sukemaru, 2018/11/01 - 2019/11/10
 * ---------------------------------------------------------
 * 行頭の「空白文字」を削除、またはキャレット位置の前後にある「タブ文字」を削除する。
 * 選択範囲があった場合は、つねに行頭の「空白文字」だけを削除する。
 * 削除対象の「空白文字」は、「半角スペース×2」以外の空白文字もふくめて
 * 配列 blank で定義する。
 * ※「引用の追加」マクロから行頭の文字列を削除するコードを流用した
 * 
 * 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 */

// ---------- ▼ 設定項目 ▼ ----------

// ■ 選択範囲なしのときに、キャレット位置の前後にある「タブ文字」を優先的に削除するか?
var deleteNearestTab = true;
  /**
   * false にすると、つねに行頭の空白文字のみを削除
   * true にすると、キャレット付近の「タブ文字×1」を優先的に削除
   *    (タブ文字がなければ行頭の空白を削除)
   */


// ■ 削除対象(削除の単位)にする行頭の空白文字の定義
var blank = [ "  " , " " , " " , "\t" ];
  /**
   * 初期値: [ "  " , " " , " " , "\t" ]
   * i.e. 「半角空白×2」「半角空白×1」「全角空白×1」「タブ文字×1」
   * ※ 前に置いたもののほうが優先順位が高くなる。
   *    e.g. 行頭に半角空白が3つある行で連続で実行した場合、
   *   1回目では「半角空白×2」を削除し、2回目で「半角空白×1」を削除する。
   * ※ 削除対象を「半角空白×4 ~ 1」「全角空白×2 ~ 1」「タブ文字×1」にするなら
   *   blank = [ "    " , "   " , "  " , " " , "  " , " " , "\t" ];
   * ※ 空白文字以外の "文字列" を [ ... ] のなかに追加するのも可。
   */

// ---------- ▲ 設定項目 ▲ ----------

Redraw = false;
var sx = ScrollX,  sy = ScrollY;

var d = editor.ActiveDocument;
var s = editor.ActiveDocument.selection;
var len = 0;

var pos = s.IsEmpty ? s.GetActivePos() : "";	// "選択範囲なし" のフラグ
var isDone = false;	// Quit() メソッドの代用フラグ

if ( d.ReadOnly ) {
  Status = " ドキュメントは書き換え禁止です。";
  isDone = true;
}

/* カーソル付近の「タブ文字×1」を削除するパターン(左側優先) */
else if ( pos && deleteNearestTab ) {
  if ( d.Text.charAt( pos - 1 ) == "\t" ) {
    s.DeleteLeft();
    isDone = true;
  }
  else if ( d.Text.charAt( pos ) == "\t" ) {
    s.Delete();
    isDone = true;
  }
}

if ( ! isDone ) {
  // 選択範囲を取得
  var tx = s.GetTopPointX( mePosLogical );
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = s.GetBottomPointY( mePosLogical );
  // 選択範囲を拡張
  if ( by != ty && bx == 1 ) {
    by -= 1;
  }
  s.SetActivePoint( mePosLogical, 1, by );
  s.EndOfLine( false, mePosLogical );
  s.SetAnchorPoint( mePosLogical, 1, ty );

  // ブックマーク行を収集(選択範囲の先頭行は確認不要)
  if ( ty < by ) {
    var tp = s.GetAnchorPos(), bp = s.GetActivePos();
    var bmArray = [];
    s.SetActivePos( tp );
    while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
      bmArray.push( s.GetActivePointY( mePosLogical ) );
    }
    len = bmArray.length;
    s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
    ScrollX = sx;  ScrollY = sy;
  }

  // 選択範囲の文字列を取得
  var st = s.Text;

  /* 行頭の空白文字を削除 */
  var t = DeleteSpace( st, blank );
  if ( t != st ) {
    s.Text = t;

    // ブックマークを復元
    if ( len ) {
      var ep = s.GetActivePos();
      for ( var i = 0; i < len; i ++ ) {
        s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
        s.SetBookmark();
      }
      s.SetActivePos( ep );
    }
  }

  if ( pos ) {	// 範囲選択を残さない
    if ( st.length - t.length >= tx ) {
      s.SetActivePoint( mePosLogical, 1, ty );
    }
    else {
      s.SetActivePos( pos - ( st.length - t.length ) );
    }
  }
  else {		// 範囲選択を残す(論理行単位)
    s.SetActivePos( s.GetActivePos() + 1 );
    s.SetAnchorPoint( mePosLogical, 1, ty );
  }

  Status = " 「スペース×2 削除」マクロ"
}

ScrollX = sx;  ScrollY = sy;
Redraw = true;

var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
Status += "  [ "
       + elapsedSec.replace( /\./, ". " )
       + " 秒 ]";

/**
 * 関数 DeleteSpace( str, blank )
 * str の各行の先頭から blank を削除する
 * ※ blank は空白文字列のパターンを収録した配列
 */
function DeleteSpace( str, blank ) {
  var a = str.split( "\n" );
  for ( var i = 0; i < a.length; i ++ ) {
    if ( ! a[i] ) { continue; }
    for ( var j = 0; j < blank.length; j ++ ) {
      if ( blank[j] && a[i].substr( 0, blank[j].length ) == blank[j] ) {
        a[i] = a[i].substr( blank[j].length );
        break;
      }
    }
  }
  return a.join( "\n" ); 
}


インデント

インデント.js

既存のツールバーアイコンのアイテム「インデント」から置きかえて使う目的のマクロで、選択範囲がなくてもタブインデントします。
ソースコードの内容は「字上げ(スペース×2 追加)」マクロとほぼ同じですが、こちらの「インデント」マクロの場合は、挿入する空白は「タブ文字」のみで空白行にたいしてもインデントを追加します。

  • 論理行全体をタブインデント(行頭)して範囲選択します。
    選択範囲が1行内ならもとの選択範囲を維持し、複数行なら対象の論理行全体を範囲選択します。
  • またはカーソル位置にタブ文字を挿入します。
  • 選択範囲が末尾に改行を含んでいた場合は、最後の改行を無視します。


【推奨設定】 Tab キーに割りあてるなら tabEnable = 2 , ツールバーアイコンにするなら tabEnable = 0

#title = "インデント"
#tooltip = "選択範囲がなくてもインデント"
#icon = "indent_right.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",260

var start = new Date();	// 所要時間計測(開始)

/**
 * ---------------------------------------------------------
 * 「インデント」マクロ
 *   sukemaru, 2018/11/15 - 2019/11/10
 * ---------------------------------------------------------
 * ・選択範囲なしでも、論理行全体をタブインデント(行頭)して範囲選択する
 *   選択範囲が1行内ならもとの選択範囲を維持し、複数行なら対象の論理行全体を範囲選択する
 * ・またはカーソル位置にタブ文字を挿入する
 * 【推奨設定】 Tab キーに割りあてるなら tabEnable = 2, 
 *              ツールバーアイコンにするなら tabEnable = 0
 * 
 * 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 */

// ---------- ▼ 設定項目 ▼ ----------

// ■ 選択範囲があるときに、選択範囲を「タブ文字」にするか? 
//    行全体をタブインデントするか?

var tabEnable = 0;

  /**
   * 0: 選択範囲がなくてもつねに行全体をタブインデント(行頭)
   * 1: 選択範囲があれば行全体をタブインデント、なければキャレット位置にタブ文字を挿入
   *  (※ ツールバーアイコンの「インデント」に似た動作)
   * 2: 選択範囲が1行内(論理行)のときだけ選択範囲を「タブ文字」にする
   *  (※ Tab キーの通常動作にちかい ← Mery 標準機能では "表示行" で1行内)
   * 3: つねに選択範囲を「タブ文字」にする(※ インデントしない)
   * 4: 選択範囲が1行内(論理行)のときは選択範囲の先頭に「タブ文字」を追加し、
   *    それ以外の場合には 0 と同じ動作(行全体をタブインデント)をする
   * 
   * ※ 0 の場合、「タブ文字」を挿入することができないので、ツールバーアイコン向けの設定。
   * ※ 1 の場合、選択範囲を「タブ文字」にすることができないので、
   *      Tab キーにマクロを割りあてると少し不便になるかも?
   *      範囲選択 → 削除 (Delete / BackSpace) → 「インデント」マクロ (Tab)
   * ※ 2 の場合に1行だけインデントさせるなら、行頭でクリックするか、
   *      行内でトリプルクリック、または行番号のクリックで行全体を選択範囲にして
   *    「インデント」マクロ (末尾改行まで含める必要あり)。
   *     [EOF] マークのある(さいごに改行がない)文書末行だけの1行選択ではインデントできない。
   *      ⇔ Tab キーの通常動作では末尾改行を含める必要はない
   * ※ 3 は、わざわざマクロでやる意味もないかと。
   * ※ 4 は、0 と 1 の動作の統合型(1 の動作条件を反転させたもの)。
   */

// ---------- ▲ 設定項目 ▲ ----------

var tab = "\t";

Redraw = false;
var sx = ScrollX,  sy = ScrollY;
var d = editor.ActiveDocument;
var s = editor.ActiveDocument.selection;
var len = 0;

if ( d.ReadOnly ) {
  Status = " ドキュメントは書き換え禁止です。";
}

else {
  // 選択範囲
  var act = s.GetActivePos();
  var anc = s.GetAnchorPos();
  var tx = s.GetTopPointX( mePosLogical );
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = yy = s.GetBottomPointY( mePosLogical );
  var inLine = ( ty == by && act != anc );

  /* 行の途中の選択範囲を字下げするパターン */
  if ( inLine && tabEnable == 4 ) {
    s.Text = tab + s.Text;
    s.SetAnchorPoint( mePosLogical, tx, ty );
  }

  /* カーソル位置にタブを挿入するパターン */
  else if ( ( tabEnable == 1 && s.IsEmpty )
         || ( tabEnable == 2 && ty == by )
         ||   tabEnable == 3 ) {
    s.Text = tab;
  }

  else {
    // 選択範囲を拡張
    if ( ty != by && bx == 1 ) {
      yy --;	// 選択範囲の末尾が行頭にあるときの調整
    }
    s.SetActivePoint( mePosLogical, 1, yy );
    s.EndOfLine( false, mePosLogical );
    s.SetAnchorPoint( mePosLogical, 1, ty );

    // ブックマーク行を収集(選択範囲の先頭行は確認しない)
    if ( ty < by ) {
      var tp = s.GetAnchorPos(), bp = s.GetActivePos();
      s.SetActivePos( tp );
      var bmArray = [];
      while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
        bmArray.push( s.GetActivePointY( mePosLogical ) );
      }
      len = bmArray.length;
      s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
      ScrollX = sx;  ScrollY = sy;
    }

    // インデント
    var st = s.Text;
    s.Text = st.replace( /^/gm , tab );

    // ブックマークを復元
    if ( len ) {
      var ep = s.GetActivePos();
      for ( var i = 0; i < len; i ++ ) {
        s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
        s.SetBookmark();
      }
      s.SetActivePos( ep );
    }

    // 選択範囲を復元
    if ( ty == by ) {
      s.SetActivePos( act + tab.length );
      s.SetAnchorPos( anc + tab.length );
    }
    else {
      s.SetActivePos( s.GetActivePos() + 1 );
      s.SetAnchorPoint( mePosLogical, 1, ty );
    }
  }

  Status = " 「インデント」マクロ"
}

ScrollX = sx;  ScrollY = sy;
Redraw = true;

var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
Status += "  [ "
       + elapsedSec.replace( /\./, ". " )
       + " 秒 ]";


逆インデント

アンインデント.js

既存のツールバーアイコンのアイテム「逆インデント」から置きかえて使う目的のマクロで、選択範囲がなくてもアンインデントします。
機能的には「字上げ(スペース×2 削除)」マクロとほぼ同じですが、削除できる「半角スペース×n」の最大数をかんたんに設定できるようにしてあります ( "␣␣␣␣", "␣␣␣", "␣␣", "␣" なら deleteSpace = 4 と指定するだけ)。

  • 行頭またはカーソル付近の「タブ文字×1」か、行頭の「半角スペース×n」を削除します。
  • 選択範囲なしならカーソル付近のタブを削除するか、またはカーソルのある1行をアンインデントして、カーソル位置を復帰します。
  • 選択範囲ありなら論理行全体をアンインデント(行頭)して範囲選択します。
  • 選択範囲が末尾に改行を含んでいた場合は、最後の改行を無視します。


【推奨設定】 「字上げ」マクロと並存させるなら deleteSpace = 0 , 「字上げ」マクロなしで Shift+Tab キーに割りあてるなら deleteSpace 0 ( 1 以上の値)

設定用変数 deleteSpace = n3 以上の数値を指定するさいは、Mery のオプション設定の「タブの桁数」を目安にしてください(大きな数字や非整数値を入れての動作検証はしていません)。

※ sukemaru 版の「逆インデント」と「字上げ(スペース×2 削除)」マクロを並存させるメリットは特にないとおもいますので、お好みで選んでください。

#title = "逆インデント"
#tooltip = "選択範囲がなくてもアンインデント"
#icon = "indent_left.ico"
// #icon = "Mery用 マテリアルデザインっぽいアイコン.icl",261

var start = new Date();	// 所要時間計測(開始)

/**
 * ---------------------------------------------------------
 * 「逆インデント」マクロ
 *   sukemaru, 2018/11/15 - 2019/11/10
 * ---------------------------------------------------------
 * 選択範囲なしでも、行頭またはカーソル付近の「タブ文字×1」か、
 * 行頭の「半角スペース×2」を削除する
 * ・選択範囲なしならカーソル付近のタブを削除するか、
 *   またはカーソルのある1行をアンインデントして、カーソル位置を復帰する
 * ・選択範囲ありなら論理行全体をアンインデントして範囲選択する
 * 
 * 2019/11/10: ブックマークの保守(要: Mery ver 2.8.6 以上)
 */

// ---------- ▼ 設定項目 ▼ ----------


// ■ 選択範囲なしのときに、カーソル位置の前後にある「タブ文字」を優先的に削除するか?
// ※ 選択範囲が1行内で、先頭に「タブ文字」がある場合も優先的に削除するか?
var deleteNearestTab = true;
  /**
   * false にすると、つねに行頭の空白文字のみを削除
   * true にすると、カーソル付近の「タブ文字×1」を優先的に削除
   * (タブ文字がなければ行頭の空白を削除)
   */


// ■行頭の「半角スペース」や「全角スペース」も削除するか?
var deleteSpace = 1;
  /**
   * ※ 正の整数値で指定してください
   * 0: 行頭の「タブ文字×1」だけを削除
   * 1: 行頭の「タブ文字×1」と「半角スペース×1~2」も削除
   * 2: 行頭の「タブ文字×1」と「半角スペース×1~2」と「全角スペース×1」も削除
   * 3: 1回の逆インデントで削除できる「半角スペース×n」の最大数が増加
   *  ※ 削除できる「全角スペース」の最大数は n / 2 ( → roundDecimal 変数で設定 )
   */


    // ■deleteSpace が 3 以上のとき、削除できる「全角スペース」の最大数
    var roundDecimal = false;
      /**
       * ※ deleteSpace が奇数のときの小数点以下の処理
       * false にすると ( deleteSpace / 2 ) の小数点以下を切り捨て
       * true にすると  ( deleteSpace / 2 ) の小数点以下を切り上げ(四捨五入)
       */

// ---------- ▲ 設定項目 ▲ ----------

Redraw = false;
var sx = ScrollX,  sy = ScrollY;
var d = editor.ActiveDocument;
var s = editor.ActiveDocument.selection;

var pos = s.IsEmpty ? s.GetActivePos() : "";	// "選択範囲なし" のフラグ
var isDone = false;	// Quit() メソッドの代用フラグ
var len = 0;

if ( d.ReadOnly ) {
  Status = " ドキュメントは書き換え禁止です。";
  isDone = true;
}

/* カーソル付近の「タブ文字×1」を削除するパターン(左側優先) */
else if ( pos && deleteNearestTab ) {
  if ( d.Text.charAt( pos - 1 ) == "\t" ) {
    s.DeleteLeft();
    isDone = true;
  }
  else if ( d.Text.charAt( pos ) == "\t" ) {
    s.Delete();
    isDone = true;
  }
}

if ( ! isDone ) {
  // 選択範囲
  var act = s.GetActivePos();
  var anc = s.GetAnchorPos();
  var tx = s.GetTopPointX( mePosLogical );
  var ty = s.GetTopPointY( mePosLogical );
  var bx = s.GetBottomPointX( mePosLogical );
  var by = yy = s.GetBottomPointY( mePosLogical );
  var inLine = ( ty == by && act != anc );
  var st = s.Text;

  /* 選択範囲が1行内のときに、先頭の「タブ文字」を優先的に削除するパターン */
  if ( inLine && deleteNearestTab && st.charAt( 0 ) == "\t" ) {
    s.Text = st.replace( /^\t/, "" );
    s.SetAnchorPoint( mePosLogical, tx, ty );
  }

  else {
    // 選択範囲を拡張
    if ( ty != by && bx == 1 ) {
      yy --;		// 選択範囲の末尾が行頭 x = 1 にあるときの調整
    }
    s.SetActivePoint( mePosLogical, 1, yy );
    s.EndOfLine( false, mePosLogical );
    s.SetAnchorPoint( mePosLogical, 1, ty );

    // ブックマーク行を収集(選択範囲の先頭行は確認不要)
    if ( ty < by ) {
      var tp = s.GetAnchorPos(), bp = s.GetActivePos();
      var bmArray = [];
      s.SetActivePos( tp );
      while ( s.NextBookmark() && s.GetActivePointY( mePosLogical ) <= by ) {
        bmArray.push( s.GetActivePointY( mePosLogical ) );
      }
      len = bmArray.length;
      s.SetAnchorPos( tp );  s.SetActivePos( bp, true );
      ScrollX = sx;  ScrollY = sy;
    }

    /* 逆インデント */
    var regStr1 = "^\\t|^[ ]{1,2}";
    var regStr2 = "^\\t|^[ ]{1,2}|^[ ]";
    var regStr3 = "^\\t|^[ ]{1," + deleteSpace + "}|^[ ]{1,"
                + ( roundDecimal ? Math.round( deleteSpace / 2 )	// 切り上げ
                                 : Math.floor( deleteSpace / 2 ) )	// 切り捨て
                + "}";
    var indent = ( deleteSpace == 1 ) ? regStr1
               : ( deleteSpace == 2 ) ? regStr2
               : ( deleteSpace >= 3 ) ? regStr3
                 /*     else       */ : "^\\t";

    st = s.Text;
    var u = st.replace( new RegExp( indent , "gm" ) , "" );
    if ( u != st ) {
      s.Text = u;

      // ブックマークを復元
      if ( len ) {
        var ep = s.GetActivePos();
        for ( var i = 0; i < len; i ++ ) {
          s.SetActivePoint( mePosLogical, 1, bmArray[i], false );
          s.SetBookmark();
        }
        s.SetActivePos( ep );
      }
    }

    // 選択範囲が1行だったときは、位置関係を維持して選択範囲を復元する
    if ( ty == by ) {
      var gap = st.length - u.length;
      if ( bx <= gap ) {
        s.SetActivePoint( mePosLogical, 1, ty );
      }
      else if ( anc < act && tx <= gap ) {
        s.SetActivePos( act - gap );
        s.SetAnchorPoint( mePosLogical, 1, ty );
      }
      else if ( tx <= gap ) {
        s.SetActivePoint( mePosLogical, 1, ty );
        s.SetAnchorPos( anc - gap );
      }
      else {
        s.SetActivePos( act - gap );
        s.SetAnchorPos( anc - gap );
      }
    }
    // 選択範囲が複数行だったときは、拡張した選択範囲を復元する
    else {
      s.SetActivePos( s.GetActivePos() + 1 );
      s.SetAnchorPoint( mePosLogical, 1, ty );
    }
  }

  Status = " 「インデント」マクロ"
}

ScrollX = sx;  ScrollY = sy;
Redraw = true;

var elapsedSec = ( ( new Date() - start ) / 1000 ).toFixed( 3 );
Status += "  [ "
       + elapsedSec.replace( /\./, ". " )
       + " 秒 ]";


メモ

  • (2019/04/07 sukemaru)
ソースコードから Quit() メソッドを削除

  • (2019/11/10 sukemaru)
Mery 2.8.6 以上でブックマークを保持
※ Mery 2.8.5 以前ではブックマーク機能の仕様が不安定なので、個別対応はあきらめた

スポンサーリンク