TAB/半角空白 トグル変換
実行するごとに「TAB ⇔ 半角空白」の相互変換をします。
選択範囲内のみ の「TAB ⇔ 半角空白」の相互変換も可。
[編集] メニュー >> [選択範囲の変換] サブメニュー のコマンド「タブを空白に変換」と「空白をタブに変換」は...
- メニューの中をたどってコマンドを見つけるのが面倒
- 選択範囲がないと実行できない
- 選択した範囲を無視して論理行全体が変換される
- トリプルクリックや行番号のクリック(ドラッグ)で範囲選択した状態から実行すると、ひとつ下の行まで変換されてしまう
などのような使いづらい部分があります。
このマクロでは、キャレット位置に TAB や連続する半角空白があるときは自動的に空白文字列を範囲選択して「TAB ⇔ 半角空白」変換します。
連続で実行した場合にはトグル式に相互変換しますので、ツールバーアイコンひとつでふたつの機能(+α)を利用できます。
設定項目
indentSize (初期値: 0)
「タブの桁数」(半角空白で何コ分の幅か)を数値で指定します。
- 変更する場合は、[オプション] ダイアログ >> [基本] カテゴリ の「タブの桁数」の設定値で指定してください。
- e.g.
indentSize = 4で「半角空白6コ」の選択範囲を変換すると「TAB1コ+半角空白2コ」になります。
indentSize = 0なら「タブの桁数」を Mery から自動取得します。
- Mery ver 3 以降では
Document.IndentSizeプロパティでの取得を試行します。Document.IndentSizeを取得できなかった場合や Mery ver 2.x では Mery.ini から「タブの桁数」を読みこみます。
wholeLines (初期値: true)
論理行全体(複数行可)の「TAB ⇔ 半角空白」変換を許可するかしないかの設定です。
wholeLines = trueのときで、選択範囲がなくキャレット位置に変換対象になる空白文字列がない場合や、選択範囲があっても変換対象になる空白文字列がない(または半角空白の数が「タブの桁数」に満たない)場合、選択範囲に非空白文字(全角空白や改行も)がふくまれている場合は、論理行全体を選択範囲にして「TAB ⇔ 半角空白」の変換を試行します。
- Mery の標準コマンドの「タブを空白に変換」と「空白をタブに変換」で処理するので複数行の範囲選択状態からでも変換可能ですが、つねに論理行全体、論理行内のすべての TAB とすべての連続する半角空白が対象となります。
- トリプルクリックや行番号のクリックまたはドラッグで「行全体+末尾改行のある範囲選択状態」から実行したとき、ひとつ下の行は変換対象になりません。
FullToHalf2 (初期値: false)
全角空白を「空白をタブに変換」の対象に含めるための設定です。
- 設定項目で FullToHalf2 = true にすると全角空白を「半角空白×2」とみなして「空白 ⇒ TAB」変換します。
- さいしょに「全角空白 ⇒ 半角空白×2」変換してから「TAB ⇒ 半角空白」「空白 ⇒ TAB」の順に試行します。
以下の理由によりあまり役に立つ機能ではなさそうなので、初期値を false に設定してあります。
- 「連続する全角空白」や半角空白や TAB と混在文字列では、空白文字列すべてを自動選択することはできません。 あらかじめ範囲選択してから実行してください。
- 「全角空白 ⇒ 半角空白×2」の変換は一方通行(不可逆)です。
- このマクロの基本プランが「TAB ⇔ 半角空白」の相互変換であるため、「全角空白 ⇒ 半角空白×2」変換は単独的機能として設計していません。 全角空白をふくむ選択範囲から「全角空白 ⇒ 半角空白×2」変換した「連続する半角空白」の先頭が TAB の区切り位置にあれば、「空白 ⇒ TAB」変換します。
使用上の注意
- 優先ルール
- 「TAB+半角空白」からの実行では、つねに「TAB ⇒ 半角空白」変換になります(再度実行すれば「半角空白 ⇒ TAB」変換できます)。
- 本来、全角空白は「空白をタブに変換」の対象外です。
FullToHalf2 = falseで全角空白をふくむ空白文字列を範囲選択している場合は、選択範囲をふくむ行全体が変換対象になります。
- また、選択範囲が複数行にまたがっている場合は、つねに論理行全体が変換対象になります。
- ※
wholeLines = falseのときは変換なし。
- このマクロの設定項目
indentSizeの値と Mery の [オプション] の「タブの桁数」の設定値(または EditorConfig のindent_sizeの値)がことなると、「半角空白 ⇒ TAB」変換の可否判定や変換結果がうまくないかんじになる場合があります。
- EditorConfig で
indent_sizeをカスタマイズしている場合、このマクロの設定はvar indentSize = 0にしてください(Mery ver 3.0.x 以降)。 - ※「TAB ⇔ 半角空白」変換されなかったときには「変更行」のマーキングがつかないようにしてあります。
- マルチカーソル複数選択や矩形選択には非対応です。 回避処理は入れていませんので、意図したとおりの結果にならなかったときは Undo (Ctrl+Z) してください。
- キャレット位置または選択範囲内の「TAB ⇔ 半角空白」変換
wholeLines = falseのときで、選択範囲内に改行がある場合や、非空白文字(全角空白も含む)がある場合は変換しません。
- キャレット位置の空白文字列を変換するとき、行頭の TAB インデントから半角空白への変換では後ろの文字列がズレることはないようですが、
行の途中の TAB を半角空白に変換した場合や、TAB の区切り位置からズレた連続する半角空白幅を TAB に変換した場合は、うしろの文字列の先頭位置がズレます。
⇒ うしろの非空白文字列がズレないようにしました(2020/05/29 更新)。
- ※ 連続する半角空白を中途半端な位置から範囲選択して「半角空白 ⇒ TAB」変換すると、選択範囲よりうしろの文字列の先頭位置がズレます。
- 行の途中にある TAB ひとつを「TAB ⇒ 半角空白」変換するとき、TAB の見かけ上の幅が「タブの桁数」
indentSizeより小さいと、「TAB ⇒ 半角空白」したあとの半角空白の数が「タブの桁数」よりも少なくなります。
- ※「TAB ⇒ 半角空白」変換後にこのマクロを再実行しても「半角空白 ⇒ TAB」変換にならないことがあります。
- 行全体の「TAB ⇔ 半角空白」変換
- 複数行選択の状態から「TAB ⇔ 半角空白」変換したときに、選択範囲内の行のブックマーク設定が維持されるかどうかは Mery 本体のバージョンによってことなります。 最新のベータバージョン(2020/05/29 時点で ver 3.0.3)ではブックマーク設定が維持されますが、2020/05/29 時点での
正式版
ver 2.6.7 ではブックマーク設定がズレたり消えたりします。
ダウンロード
- 「ファイル:TAB/半角空白変換.zip」(アイコン入り)
- TAB/半角空白変換.js
- マテリアルデザインっぽい専用アイコン
- (オマケ)タブを空白に変換.js
- (オマケ)空白をタブに変換.js
2020/05/29: 第2版
2020/05/27: 初版
ソースコード
#title = "TAB ⇔ 半角空白 トグル変換"
#tooltip = "キャレット位置だけ TAB ⇔ 半角空白 の変換をする"
#icon = "tabify[3].ico"
/**
* ---------------------------------------------------------
* 「TAB/半角空白変換」マクロ
* sukemaru, 2020/05/27 - 2020/05/29
* ---------------------------------------------------------
* キャレット位置または選択範囲内だけの「TAB ⇔ 半角空白」変換可
* 2020/05/29: うしろの非空白文字列の開始位置がズレないようコード改編
*
* ※ 優先ルール: タブ+半角空白 からの変換のばあいは「TAB ⇒ 半角空白」変換
* (再度実行すれば「半角空白 ⇒ TAB」変換)
* ※ EditorConfig でタブの桁数をカスタマイズしている場合は、
* indentSize = 0 にすること。
*/
// ---------- ▼ 設定項目 ▼ ---------- //
// ■ タブの桁数
// ※ Mery から自動取得するなら indentSize = 0 にする
var indentSize = 0;
// ■ 論理行全体(複数行可)の「TAB ⇔ 半角空白」変換
var wholeLines = true; // true: する / false: しない
// ■「全角空白 ⇒ 半角空白×2」変換
// ※「全角空白 ⇒ 半角空白×2」変換後に「空白をタブに変換」する
var FullToHalf2 = false; // true: する / false: しない
// ---------- ▲ 設定項目 ▲ ---------- //
var d = editor.ActiveDocument, s = d.selection;
var sv = d.Saved;
var isEmpty = s.IsEmpty;
var pos = ( isEmpty ) ? s.GetActivePos() : -1;
if ( d.ReadOnly ) {
Status = " ドキュメントは書き換え禁止です。";
}
else {
if ( ! indentSize || ! ( indentSize > 0 ) ) {
// Mery ver 3 以降?
if ( "IndentSize" in Document ) {
indentSize = d.IndentSize;
}
// Mery.ini から「タブの桁数」を取得する
if ( ! indentSize || ! ( indentSize > 0 ) ) {
indentSize = GetIniOptionNum( "TabColumns" ) || 4;
}
}
Status = " タブの桁数: " + indentSize;
if ( isEmpty ) {
s.SelectWord();
}
var act = s.GetActivePos();
var anc = s.GetAnchorPos();
var ty = s.GetTopPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );
var st = s.Text;
if ( st && indentSize > 0 && /^[\t ]+$/.test( st ) ) {
var ty = s.GetTopPointY( mePosLogical );
var bx = s.GetBottomPointX( mePosLogical );
// 全角空白 ⇒ 半角空白×2
if ( FullToHalf2 && st.indexOf( " " ) > -1 ) {
st = st.replace( /[ ]/g, " " );
}
// TAB ⇒ 半角空白(キャレット位置または選択範囲内のみ)
if ( st.indexOf( "\t" ) > -1 ) {
// Act1: 行頭から選択範囲の末尾までを新規の行にする
s.Text = "\n" + d.GetLine( ty, 0 ).slice( 0, bx - 1 ) + "\n";
s.CharLeft(); s.WordLeft( true );
// Act2: 「タブを半角空白に変換」して行末の空白文字列を取得
s.Untabify();
s.Collapse( meCollapseEnd ); s.WordLeft( true );
st = s.Text;
// Act1, Act2 を巻き戻して「TAB ⇒ 半角空白」変換終了
d.Undo(); d.Undo();
s.Text = st;
s.SetAnchorPos( s.GetActivePos() - st.length );
}
// 半角空白 ⇒ TAB(キャレット位置または選択範囲内のみ)
// else if ( RegExp( "[ ]{" + indentSize + "}", "" ).test( st ) ) { // }
else if ( st.indexOf( " " ) > -1 ) {
// Act1: 行頭から選択範囲の末尾までを新規の行にする
s.Text = "\n" + d.GetLine( ty, 0 ).slice( 0, bx - 1 ) + "\n";
s.CharLeft(); s.WordLeft( true );
// Act2: 「半角空白をタブに変換」して行末の空白文字列を取得
s.Tabify();
s.Collapse( meCollapseEnd ); s.WordLeft( true );
st = s.Text;
// Act1, Act2 を巻き戻して「半角空白 ⇒ TAB」変換終了
d.Undo(); d.Undo();
if ( st !== s.Text ) {
s.Text = st;
s.SetAnchorPos( s.GetActivePos() - st.length );
}
}
}
// wholeLines = true のとき
if ( st === s.Text && wholeLines ) {
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 );
st = s.Text;
// TAB ⇒ 半角空白(行全体)
if ( st.indexOf( "\t" ) > -1 ) {
s.Untabify();
}
// 半角空白 ⇒ TAB(行全体)
else if ( RegExp( "[ ]{" + indentSize + "}", "" ).test( st ) ) {
s.Tabify();
if ( st === s.Text ) { d.Undo(); d.Saved = sv; }
}
// else {
// s.Tabify();
// if ( st === s.Text ) { d.Undo(); d.Saved = sv; }
// }
// キャレット位置または選択範囲の復帰
if ( st === s.Text ) {
if ( pos >= 0 ) { s.SetActivePos( pos ); }
else { s.SetActivePos( act ); s.SetAnchorPos( anc ); }
}
// 行全体を変換したときは論理行全体を範囲選択
else { s.SelectLine( true ); }
}
}
/**
* 関数 GetIniOptionNum( key )
* 引数で指定された設定項目の「値」を返す(※数値のみ)
*/
function GetIniOptionNum( key ) {
var Fso = new ActiveXObject( "Scripting.FileSystemObject" );
// Mery.ini を探す
var meryPath = editor.FullName;
var mery = Fso.GetBaseName( meryPath );
var iniPath = meryPath.replace( /\.exe$/i, ".ini" );
if ( ! Fso.FileExists( iniPath ) ) {
iniPath = new ActiveXObject( "WScript.Shell" )
.ExpandEnvironmentStrings( "%APPDATA%" )
+ "\\Mery\\" + mery + ".ini";
}
// Mery.ini を読み込んで項目 key の値を取得する
var iniFile = Fso.OpenTextFile( iniPath, 1 );
var iniText = iniFile.ReadAll();
iniFile.Close(); Fso = null;
var value = "";
if ( ( reg = RegExp( "^" + key + "=(\\d*)$", "m" ) ).test( iniText ) )
{ value = reg.exec( iniText )[1]; }
return Number( value );
}
メモ
- 2020/05/27:
- 前半部分は、行頭インデントの「ハード ⇔ ソフト」変換を目的として「Yes/No マクロ」への自家用追加コードとしてつくった簡易的な処理なので、
行の途中にある空白文字列の「TAB ⇔ 半角空白」に使うには適していないとおもいます。
Alert(Document.IndentSize);で -1 が返ってくるファイルもあって、なんかモヤっとしてたり...。
- 2020/05/29:
- 投稿した後になってからエラーや弱点を修正するのが「毎度」のパターンですみません。
スポンサーリンク