主要テキストエディタの行・桁指定起動オプション一覧
コマンドラインからテキストエディタを起動する際の、「読み取り専用で開く」「開いたファイルの特定行へ移動」「開いたファイルの特定桁位置へ移動」を指定するコマンドラインオプションの一覧を、以下に示します。
(後述しますが、以下のエディタをTresGrepの外部ビューアとして指定した際には、この表の起動オプションがデフォルトで適用されます)
エディタ名 (exeファイル名) |
起動オプション | 備考 | |
---|---|---|---|
読取専用指定 | 行番号/桁位置指定 | ||
Mery (Mery.exe) |
/r | /l <Y> /cl <X> | |
秀丸エディタ (Hidemaru.exe) |
/r | /j<Y>,<K1> | |
サクラエディタ (sakura.exe) |
-R | -Y=<Y> -X=<X> | |
gPad (gPad.exe) |
(指定不能) | -Y=<Y> | |
Notepad++ (notepad++.exe) |
-ro | -n<Y> -c<X> | |
VS Code (Code.exe) |
(指定不能) | %1:<Y>:<X> | (2020.06.25記述追加) |
Sublime Text (sublime_text.exe) |
(指定不能) | %1:<Y>:<X> | |
MIFES (MIW.exe) |
/R | /+<Y>@<K#> | |
xyzzy (xyzzy.exe) |
-ro | -g <Y> -c <X> | |
EmEditor (EmEditor.exe) |
/r | /l <Y> /cl <X> | |
NoEditor系各種 (NoEditor/UnEditor/OuiEditor/DeuxEditor.exe) |
(指定不能) | /I=%1=<Y> %1 |
※Unicode対応不完全 |
TeraPad (TeraPad.exe) |
/r | /jl=<Y> | ※Unicode対応不完全 につき使用非推奨 |
<Y>は行番号(1開始)を指します。
<X>、もしくは<K1><K#>は、桁位置(1開始)を指します。
桁位置の数え方はエディタによって若干差異があります。(そもそもエディタによっては桁位置指定ができないものもあります)
<X>を指定するエディタは、全角文字も半角文字もTAB文字も一律で1文字=1桁として数えた桁位置を引き渡します。
<K1><K#>を指定するエディタの場合は、全角文字を2桁としてカウントした桁位置を引き渡す必要があります。
桁位置として<K#>を指定するエディタはTAB文字の取り扱いが特殊で、TABによるインデントを考慮した論理的な桁位置を指定する必要があります。(例えば、TABインデント4文字分の環境で『<TAB><TAB>ABC』の「A」の桁位置を指定する場合は、桁位置として9を指定します)
<K1>を指定するエディタは、TAB1文字=1桁としてカウントします。
一部のエディタでは行番号・桁位置指定オプション引数にファイル名も含める必要があります。上記の表では、ファイル名を指定する箇所を「%1」と表記しています。
TresGrepの外部ビューア指定では、上記のテキストエディタ、バイナリエディタBz/FavBinEdit/xedit/Stirling、アーカイバExpLzh/LhaForge/WinRARを自動認識し、起動オプションをデフォルトで設定するようになっています。
例えば秀丸エディタの場合はこんな感じになります。
読み取り専用指定をやめたい、とか、他の起動オプションも指定したいような場合には、適宜起動オプションを修正してください。
最近のTresGrepの変更点2点
最新版TresGrepのリリースから1か月以上経ってしまっていますが・・・
TresGrepの検索モードの種類が増え、.NET Frameworkの正規表現に加えてbregonig.dllを利用した正規表現検索ができるようになりました。
bregonig.dllとは、サクラエディタ・K2Editorなどのテキストエディタで正規表現検索/置換を使用できるようにするためのライブラリです。
正規表現にはライブラリ・処理系ごとに使用できる構文の相違(方言)があり、TresGrep(.NET Framework)標準の正規表現構文/bregonig.dllで使用できる正規表現構文にも当然差異があります。
TresGrep上でもbregonig.dllを使用できるようになったことで、(少なくとも理屈の上では)bregonig.dllを正規表現ライブラリに採用しているテキストエディタと同一の正規表現検索/置換結果が得られるようになりました。
検索モードプルダウンの「鬼雲検索」「鬼雲xxx検索」がbregonig.dllを用いて検索を行うモードです。
これらのモードを使用するためにはbregonog.dllが必要です。
公式ページ http://k-takata.o.oo7.jp/mysoft/bregonig.html より最新バージョンzipをダウンロード・解凍のうえ、TresGrep.exeと同じフォルダに32bit版bregonig.dll(x64ではなくフォルダ直下のほうのファイル)を配置してください。
なお、C#からbregonig.dllの正規表現を利用する処理のソースコードをGitHubで公開しています。使ってみたい人がいましたらどうぞご利用ください。
続いてもう一点の変更点ですが、Altキーを単独押しor長押しした際にキーヒント(Altアクセスキーの一覧)が表示されるようになりました。
※上記の画面は2018年時点のものです。最新のバージョンでは見た目が異なります。
検索キーワードオプションのON/Off切替はマウスクリックせずともAltアクセスキー(あるいはCtrlショートカットキー)で操作可能なのですが、TresGrepは無駄にオプションの種類が多いのでいちいち覚えていられないと思います。そこで、特定のオプションを使いたくなった時にAltアクセスキーの一覧を画面上に表示できるようにしてみました。
この機能が不要な方は、設定の「ツールヒント表示設定」でOffにすることもできます。
正式バージョン1.00 リリース
またまた大変ご無沙汰になってしまいました。
TresGrepも昨年秋に一括置換機能ベータ版をリリースして以降しばらく放置状態になっていましたが(この時期ですが、grepをほとんど使わない環境にいたため開発意欲も必要性もすっかり薄れていました・・・)、一応ちょっとずつ不具合改修や改善を入れてバージョンアップしています。
今回8/15の公開でバージョン番号が1.00に到達しました。
といってもバージョン0.xxの連番を使い切ってしまっただけというのが正直なところなのですが、初公開からおおむね1年が経過し、大きな問題もなく利用できる状態になっているので(たぶん)、このバージョンをもってTresGrepの正式版といたします。
今回のバージョンで画面の見た目がちょっとだけ変わりました。
またWindows10については260文字以上の長いパスについても検索できるようになりました。
Multiline複数行TextBoxで改行/Tabマークを表示
C#(WinForms)標準のテキストボックスで複数行にまたがるような文字列を表示/入力するような画面を作っていて、改行やTabがどこにあるのか見てもわからないのが不便だったので、改行/Tabマークを表示して視認できるよう対応してみました。
出来上がりはこんな感じです。
実現方法
マーク表示については自前で描画処理を追加し、WM_PAINTをフックしてTab/改行の位置に記号文字を書き足しています。
その際にWin32APIのGetScrollInfoを利用してTextBox内のスクロール位置(現在表示対象となっているテキストの範囲)を把握し、テキスト本文が描画されていない部分はこれらのマークも描画しないように対処しています。
また、スクロール操作/キーボード操作/マウス操作時には画面描画を更新最新化することで、最新化前に書き足された記号がゴミとして残らないよう消去しています。
TextBoxEx.csソースコード
WinFormsのTextBoxを継承してTextBoxExというコントロールを作成しました。
以下の2プロパティが追加されています。表示ありにする場合はプロパティをtrueに設定してください。
- Tabをマーク表示するか指定するプロパティ「ShowTab」
- 改行をマーク表示するか指定するプロパティ「ShowEOL」
ほか、以下の処理のソースも混じっています。
- ウォーターマークを表示する場合の内容「WatermarkText」
- Tabキーのインデント幅設定「TabIndent」:既定は8文字ですが、それ以外の文字数にする場合は整数で設定してください。
Win32API(GetScrollInfo)の部分は別クラスになっています。
using System; using System.ComponentModel; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; /// <summary> /// 改良版TextBox /// <para>・WatermarkText:ウォーターマーク機能追加(WM_PAINTで対応)</para> /// <para>・ShowTab/ShowEOL:Tab/改行マーク表示機能追加(WM_PAINTで対応)</para> /// <para>・TabIndent:タブインデント幅設定機能</para> /// <para>・LF改行含む文字列が単一行TextBoxに貼り付けできてしまう不具合を是正</para> /// </summary> public class TextBoxEx : TextBox { //ウォーターマーク表示、改行/TABマーク表示----------------------------- /// <summary> /// テキストが空の場合に表示する文字列を取得・設定します。 /// </summary> [Category("表示")] [DefaultValue("")] [Description("テキストが空の場合に表示する文字列です。")] [RefreshProperties(RefreshProperties.Repaint)] public string WatermarkText { get { return _watermarkText; } set { _watermarkText = value; this.Invalidate(); } } private string _watermarkText = ""; //ウォーターマーク表示内容text /// <summary> /// TAB入力文字を表示するかどうかを取得・設定します。 /// </summary> [Category("表示")] [DefaultValue(false)] [Description("入力されたTAB文字を示すマークを表示するかどうかを取得・設定します。")] [RefreshProperties(RefreshProperties.Repaint)] public bool ShowTab { get { return _showTab; } set { _showTab = value; this.Invalidate(); } } private bool _showTab = false; /// <summary> /// 複数行入力時に改行マークを表示するかどうかを取得・設定します。 /// </summary> [Category("表示")] [DefaultValue(false)] [Description("複数行入力時、改行を示すマークを表示するかどうかを取得・設定します。")] [RefreshProperties(RefreshProperties.Repaint)] public bool ShowEOL { get { return _showEOL; } set { _showEOL = value; this.Invalidate(); } } private bool _showEOL = false; ///<summary> ///描画拡張(テキスト未設定時ウォーターマークを描画、Tab/改行マークを描画) ///</summary> ///<param name="m"></param> protected override void WndProc(ref Message m) { const int WM_PAINT = 0x000F; const int WM_HSCROLL = 0x0114; const int WM_VSCROLL = 0x0115; const int WM_KEYDOWN = 0x0100; const int WM_LBUTTONUP = 0x0202; const int WM_MOUSEWHEEL = 0x020A; base.WndProc(ref m); if (m.Msg == WM_PAINT && string.IsNullOrEmpty(this.Text) && string.IsNullOrEmpty(WatermarkText) == false) { using (Graphics g = Graphics.FromHwnd(this.Handle)) { //ウォーターマークをテキストボックス内の適切な座標に描画 Rectangle rect = this.ClientRectangle; rect.Offset(1, 1); TextFormatFlags format = TextFormatFlags.Top | TextFormatFlags.Left | TextFormatFlags.NoPrefix; if (this.Multiline && this.WordWrap) { //複数行ならウォーターマークも折り返し&さらに座標調整 format |= TextFormatFlags.WordBreak; rect.Offset(2, 1); } TextRenderer.DrawText(g, WatermarkText, this.Font, rect, SystemColors.GrayText, format); } } else if (m.Msg == WM_PAINT) { //改行・タブのマーク表示を試みる TryDraw(this.ShowEOL && this.Multiline, '\n', '\u21B5'); //改行を0x21B5の改行記号で表示 TryDraw(this.ShowTab, '\t', '\u02EA'); //タブを0x02EAのカギ記号で表示 } else if ((this.ShowTab || this.ShowEOL) && (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL || m.Msg == WM_KEYDOWN || m.Msg == WM_LBUTTONUP || m.Msg == WM_MOUSEWHEEL)) { //スクロール時等に改行・タブのマーク表示が乱れるので画面再描画 this.Invalidate(); } } /// <summary> /// 改行・タブマーク等表示 /// </summary> /// <param name="flg">表示要否</param> /// <param name="ch">表示対象の制御文字</param> /// <param name="dispChar">画面に表示する際に使用する記号マーク文字</param> private void TryDraw(bool flg, char ch, char dispChar) { //そもそも表示否だったり、表示対象文字がテキストに含まれていない場合は処理を行わない if (flg == false) { return; } string text = base.Text; int pos = text.IndexOf(ch); if (pos < 0) { return; } using (Graphics g = this.CreateGraphics()) { //現在のTextBoxのスクロール表示範囲と1行当たり描画行高さより、描画範囲を把握 ScrollInfo info = ScrollInfo.GetScrollInfo(this.Handle, Orientation.Vertical); int fontHeight = TextRenderer.MeasureText(g, "■", this.Font).Height; int yFrom = this.GetPositionFromCharIndex(0).Y + (info.nPos * FontHeight); int yTo = yFrom + ((int)info.nPage * FontHeight); while (pos >= 0) { //記号表示位置がスクロール表示範囲内のものであれば、記号も描画 Point point = this.GetPositionFromCharIndex(pos); if (point.Y >= yFrom && point.Y < yTo) { TextFormatFlags format = TextFormatFlags.Top | TextFormatFlags.NoPrefix; point.X--; //記号表示位置が右寄りになりすぎるのを是正 TextRenderer.DrawText(g, dispChar.ToString(), this.Font, point, SystemColors.GrayText, format); } pos = text.IndexOf(ch, pos + 1); } } } //タブ幅設定機能------------------------------------------------------- /// <summary> /// タブ表示幅を取得・設定します。 /// </summary> [Category("表示")] [DefaultValue(8)] [Description("タブのインデント文字数です。複数行エディット コントロールだけに適用されます。")] [RefreshProperties(RefreshProperties.Repaint)] public int TabIndent { get { return this._tabIndent; } set { this._tabIndent = value; const int EM_SETTABSTOPS = 0x00CB; const int DIALOG_TEMPLATE_UNITS = 4; //ダイアログ単位:平均文字幅の1/4と定義されている Win32API.SendMessage(this.Handle, EM_SETTABSTOPS, 1, new int[] { _tabIndent * DIALOG_TEMPLATE_UNITS }); this.Invalidate(); //自動では再描画されないので手動再描画する } } private int _tabIndent = 8; //Windowsのデフォルトは8。ちなみにComboBoxや単一行TextBoxではどうやっても幅変更不可 private class Win32API { [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 uMsg, int wParam, int[] lParam); } protected override void OnFontChanged(EventArgs e) { //フォント変更時、そのフォントの文字幅に基づいてタブインデントを再設定 base.OnFontChanged(e); TabIndent = _tabIndent; } protected override void OnHandleCreated(EventArgs e) { //ハンドル再作成時にタブインデント設定が初期化されてしまうようなので対策 base.OnHandleCreated(e); TabIndent = _tabIndent; } //不具合対策各種------------------------------------------------------- // 単一行テキストボックスにLF含む内容のテキストが貼り付けできてしまう不具合の是正を含めた包括対応 protected override void OnTextChanged(EventArgs e) { //改行文字を正規化(Multiline・改行文字入力可能でなければ除去) string originalText = base.Text; string normalizedText = System.Text.RegularExpressions.Regex.Replace( originalText, @"(\r\n|\r(?!\n)|\n|\u2028|\u2029|\u0085|\0)", //改行文字(範囲を広めにとる) (this.Multiline && this.AcceptsReturn) ? "\r\n" : string.Empty); if (originalText != normalizedText) { //改行文字の是正または除去が必要なので、実施する base.Text = normalizedText; } else { //(イベントは、改行是正・除去後のOnTextChanged呼び出しから発動させる) base.OnTextChanged(e); if (this.ShowTab || this.ShowEOL) { //改行マーク等を描画させる base.Invalidate(); } } } } /// <summary> /// Win32API「SCROLLINFO」構造体、および関連定数・API呼び出しメソッド定義 /// </summary> [StructLayout(LayoutKind.Sequential)] public struct ScrollInfo { //各定義項目の詳細は https://msdn.microsoft.com/library/windows/desktop/bb787537 を参照 /// <summary>構造体サイズ</summary> public uint cbSize; /// <summary>スクロールバーの取得/設定パラメータ</summary> public SIF fMask; /// <summary>最小スクロール位置</summary> public int nMin; /// <summary>最大スクロール位置</summary> public int nMax; /// <summary>ページサイズ</summary> public uint nPage; /// <summary>スクロール位置</summary> public int nPos; /// <summary>スクロールボックス(つまみ)の現在の位置</summary> public int nTrackPos; [Flags] public enum SIF : int { /// <summary>スクロール範囲を、lpsi パラメータが指す SCROLLINFO 構造体の nMin と nMax の各メンバに格納/設定します。</summary> RANGE = 0x1, /// <summary>スクロールページを、lpsi パラメータが指す 構造体の nPage メンバに格納/設定します。</summary> PAGE = 0x2, /// <summary>スクロール位置を、lpsi パラメータが指す SCROLLINFO 構造体の nPos メンバに格納/設定します。</summary> POS = 0x4, /// <summary>スクロールバーに対して指定した新しいパラメータを適用した結果、スクロールバーが不要になる場合、そのスクロールバーをる代わりに無効にします。</summary> DISABLENOSCROLL = 0x8, /// <summary>スクロールボックス(つまみ)の現在の位置を、lpsi パラメータが指す SCROLLINFO 構造体の nTrackPos メンバに格納します。ry> TRACKPOS = 0x10, /// <summary></summary> ALL = RANGE | PAGE | POS | DISABLENOSCROLL | TRACKPOS } /// <summary> /// 引数指定handleのコントロールについて、スクロールバーの様々な情報を取得します。 /// (Win32API「GetScrollInfo」を呼び出すラッパです) /// </summary> /// <param name="handle">情報取得対象コントロールのHandle</param> /// <param name="o">スクロールバーのタイプ(方向)</param> /// <returns>SCROLLINFO構造体</returns> public static ScrollInfo GetScrollInfo(IntPtr handle, Orientation o) { ScrollInfo ret = new ScrollInfo(); ret.cbSize = (uint)Marshal.SizeOf(ret); ret.fMask = SIF.PAGE | SIF.POS | SIF.RANGE | SIF.TRACKPOS; Win32API.GetScrollInfo(handle, o, out ret); return ret; } private class Win32API { [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetScrollInfo(IntPtr hWnd, Orientation fnBar, out ScrollInfo lpsi); } }
実物サンプル
このコントロールですが、自作しているgrepツール「TresGrep」の複数行検索キーワード入力欄でいろいろ試行錯誤した結果出来上がりました。
行末に改行がついているのか否か・空白表示されている部分がTabなのかSpaceなのか見分けがつかないと実用上かなり不便だったのですが、このソースでおおむね解消されました。
次バージョン(Ver 0.96)以降のTresGrepに反映される予定です。(それ以前のバージョンでは改行マーク表示のみ不完全に対応しており、一度表示された改行マークが消えないまま残ってしまったりといったおかしな挙動が混じっています)
実のところTresGrepみたいなツールを作っているとこの手の小ネタには事欠ききません。(TresGrepはほぼすべてC#+WinFormsで書かれています。プレビュー表示欄だけわずかにJavaScriptも使用しています)
TresGrepも開発が落ち着いたので、気が向いたら今回みたいな記事を今後も書くかもしれません。(もっとも、WPFのノウハウならともかくいまさらWinFormsについて書き散らしたところでそんなに需要がない気もするのですが・・・・)
TresGrep Ver0.95で一括置換に対応
このところ不具合修正等で頻繁にバージョンアップを繰り返していたTresGrepですが、並行して開発していた一括置換機能があっさりとひととおり動くようになりました。本日公開のバージョンより一括置換機能の提供を開始します。
一括置換機能の使い方
(1)まずはメイン画面(検索画面)にて書き換えたいキーワードで検索を行います。
(2)一覧表示にて、一括置換したいマッチ行あるいはファイルを選択し(Ctrl/Shiftキーを押しながらの操作で複数行を選択できます)、右クリックメニューの「置換」をクリックします。
⇒一括置換画面が表示されます。
(3)置換文字列テキスト欄に、書き換え後のテキスト内容を入力します。
(4)画面下段プレビュー欄の「置換後」タブに、一括置換後のファイル内容のプレビューが表示されます。意図したとおりの置き換えがなされているか確認します。(必要に応じ、「置換前」タブで変更前のテキスト内容と見比べたりもできます)
(5)画面中段マッチ箇所一覧タブで、置換対象とするマッチ箇所を確認します。置換せずもとの文字列のままとしておきたい箇所があれば、チェックを外します。
(6)「置換実行」ボタンをクリックします。実行確認ダイアログが表示されるので「はい」を選択すると置換処理が行われます。
※ファイルに読み取り専用属性がかかっていたり、もともとの文字コードでは保存できないようなUnicode文字が含まれていたり、検索実行後に書き換えられたリ消滅したり読み書きできない状態になったファイルがあれば、都度確認ダイアログが表示されます。その指示に従ってください。
(7)画面中段の結果サマリ/マッチ箇所タブで実行結果を確認します。「置換結果・備考」列に処理結果が表示されます。一括置換成功したファイルの行は薄い青色で、何らかの理由で置換しなかったファイルの行は薄い黄色で、それぞれ表示されます。
TresGrepの一括置換機能の特徴
- 一括置換前後のファイル内容を全行プレビュー表示できます。プレビュー欄が複数タブ構成になっており、表示タブを切り替えて置換後・置換前の内容目視比較ができます。
- マッチ箇所の一覧から、置換する箇所/しない箇所を取捨選択できます。(同一ファイル内でもこの行は置換する/別の行は置換しない、といった設定ができます)
- マッチ箇所の一覧も2タブ構成になっており、置換対象ファイル・置換結果について、マッチ箇所ごとの内容/ファイル単位のサマリ情報をそれぞれ確認できます。
- 正規表現検索した内容に対して、置換正規表現を利用して置換できます。$0で置換前文字列全体、$1以降でグルーピング内容などが指定できます。(詳細はMSDNの正規表現クイックリファレンスを参照)
- いったん置換実行してファイルを書き換えた後でも、他の置換キーワードを指定して置換をやり直すことができ、また逆にファイル内容を検索時点の状態に戻すこともできます。
プレビュー欄についても、現時点(置換実行により書き換え後)のファイル内容/さらに別の置換文字列を指定して置換した場合の想定内容/検索時点における(いっさい置換実行していない状態)のファイル内容をそれぞれ表示して比較できます。 - 検索モード「行検索」で検索した場合は、マッチした行を削除/マッチした行以外をすべて削除する「行削除モード」の置換もできます。
一括置換みたいな操作は、ツールを利用する側にとって(失敗するとファイルを壊してしまうこともあり)相当神経を使う作業なんですよね・・・。置換内容の確認がやりやすいよう置換前/置換後両方の全行プレビューができるようにしてみたり、置換済/未済を一覧表示エリアで視覚的に把握できるようにしてみたり、万一置換ミスしてしまった場合でもある程度はリカバリができるようにしてみたり、と、検索画面以上に使い勝手にはこだわってみました。
使用上の注意
- TresGrep側では一括置換実行時にファイルのバックアップは一切取りません。かならず実行前にファイルのバックアップを確保してください。
(TresGrep側お仕着せのルールで中途半端なバックアップファイルを取得するよりも利用者自身の方針で取ったほうが良いと判断した、というのと、一括置換処理のパフォーマンス/所要時間を高めるうえではバックアップ作成みたいな余計な処理で時間をとられたくない、という2点の理由から、割り切りました) - 一括置換画面使用中は、他のエディタ等での置換対象ファイルの編集は極力控えてください。エディタ等での編集内容と置換箇所がバッティングするとファイルが破損する恐れがあります。(一応TresGrep側でもファイルを書き換えて大丈夫か確認する処理は入れてありますが、万全ではありません)
- 置換内容が妥当かどうかは、置換後プレビュー内容の表示で確認してください。(プレビュー欄に表示されている内容がそのまま置換後ファイルに書き込まれます。ベータ版で置換機能にバグがあるとすれば、おそらくファイル書き込みよりも前にプレビュー表示の時点で内容がおかしくなっているはずです)
- 2017年10月時点のバージョンはベータ版です。不具合がいろいろ残っている可能性がありますので、自己責任でお使いください。(いちおう普通に想定できるような現象については正常パターン/異常パターンともだいたい動作確認したつもりですが、作者のPC以外での動作確認はほとんど行っておらず、さまざまな環境での動作実績がまだありません)
なにか不具合や気になる挙動を見つけた方は、作者まで一報いただけると大変助かります。(このBLOGエントリにでもコメントをつけてもらえればリアクションします)