Vector新着ソフトレビューにTresGrepが掲載されました

先月より公開を始めたTresGrepですが、ベクターのソフトニュース記事で紹介されました。ありがとうございます。

「TresGrep」 - 複数行にまたがる文字列の検索にも対応。正規表現とワイルドカードの併用も可能な高速・高機能grepソフト

http://www.vector.co.jp/magazine/softnews/170926

現在9/25時点でVectorに公開されているバージョンは、細かな不具合が若干混入・残存してしまっています。(詳細はこちら
バグ改修版(Ver 0.92.2017.0925正式版)を本日Vectorへ登録申請しました。反映まで数日かかるため、一時的に http://hp.vector.co.jp/authors/VA055804/TresGrep/#download からダウンロードできるようにしてあります。よろしければこちらをお使いください。

またTresGrepですが、将来的には置換機能を追加したいと考えていまして、現時点では画面仕様と大まかな挙動を練っている状態です。
画面イメージはこんな感じになる予定です。

ひとまず単一ファイルの置換まではできるようになったので、Ver0.92にも機能を組み込んだ状態でリリースします。
最終的にはファイルの一括置換ができるよう、また一度置換した箇所についてやっぱり置換前の状態に戻したりといった操作が柔軟・確実にできるように仕上げたいと思っています。
いつ頃出来上がるかは自分でもさっぱり読めません(作者の集中力と根気がどれだけ続くか次第です・・・・)。気長にお待ちください。

現時点で発覚しているTresGrepの不具合と対応状況(2017年時点)

というわけでTresGrepを公開したわけですが、まだまだ不具合が残っていそうな感じです。
いちおうVer 0.80⇒Ver 0.85へ更新するまでの間に大量にバグつぶしをして、ようやく残りが「一覧に書き出して管理しきれる」くらいの数に落ち着いた(と思われる)ので、以下この記事にて不具合をリストアップし、対応状況・致命的な不具合の場合の回避方法などをつど追記していきたいと思います。
この一覧にない不具合を見つけた方は、ぜひコメント等で報告いただけると助かります。

(Ver 0.85)

  • ファイル一覧タブで行選択しプレビュー表示したファイルについて、プレビュー欄の「≪(先頭へ)」「≫(末尾へ)」ボタンが動かない
    ⇒Ver0.88で修正済
  • 正規表現チェックボタン、「Ctrl+R」「Alt+R」どちらでもON/Offを切り替えられるのにツールヒントでは「Ctrl+R」しか表示されない
    ⇒Ver0.88で修正済
  • 検索中断したファイルを全行プレビューすると、そのファイルが検索実行後に書き換えらたものとみなされてしまう
    ⇒Ver0.88で修正済
  • 判別対象言語≠日本語で検索したファイルが全行プレビュー表示で(日本語ShiftJIS等で読み込もうとしてしまい)文字化けする
    ⇒Ver0.89で修正
  • 正規表現検索キーワードで「\r\n」を指定した場合、プレビュー表示で「CRLF」とその次の行頭文字がマッチしたかのような見た目になってしまう
    ⇒Ver0.89で修正
  • 高DPI環境でのレイアウト崩れ
    ⇒Ver0.89/Ver0.90で修正
  • マッチ箇所一覧「位置」にExcelのシート名等が表示されない
    ⇒Ver0.91で修正
  • バイナリ検索結果プレビューで、UTF16の解読結果がズレて表示される
    ⇒Ver0.91で修正
  • 検索条件入力エラーがあるなどして一覧表示がクリアされた場合でも一覧メニューの「コピー」等の操作ができてしまい、操作によっては例外で異常終了してしまう
    ⇒Ver0.91で修正
  • フィルタプルダウンの概要表示Tooltipについて、誤って他のフィルタの説明が表示される
    ⇒Ver0.92で修正
  • 長さゼロのマッチ箇所について、プレビュー表示で長さ1文字分のマッチ箇所であるかのように表示される
    ⇒Ver0.92で修正
  • 設定画面で全行プレビューしきい値上限に65536以上の値を入力して設定保存すると異常終了する
    ⇒Ver0.92で修正
  • 固定履歴に追加したはずの内容が次回起動時に消失することがある
    ⇒Ver0.92にて修正。
  • 外部ビューアを新規登録しようとしてもエラーとなり登録できない(Ver0.85混入)
    ⇒Ver0.92にて修正。
  • Alt+[→]キーでタブを切り替えた際、ファイル一覧で選択していたファイルについてのマッチ箇所へフォーカス移動しなくなった(Ver 0.91で混入)
    ⇒Ver0.92で修正
  • 画面起動時や検索実行直後などに一覧表示部がちらつく
    ⇒Ver0.92(2017.09.25)で修正
  • リアルタイム検索ONで素早く検索キーワードを打ち込むと、ステータスバーの即時検索結果表示が最新のひとつ手前の状態になってしまうことがある
    ⇒Ver0.92(2017.09.25)で修正
  • 画面最大化状態で終了すると、次回起動時にウィンドウサイズが復元されない
    ⇒Ver0.93で修正
  • ファイル名絞込「階層」について、「|」「;」を含む複雑な対象パス指定で正しくファイルが抽出されない
    ⇒Ver0.93で修正
  • 検索条件保存/プロジェクトファイル作成すると、保存時点での検索条件入力内容ではなく直近に検索実行・完了した際の検索条件がに保存されてしまう。またプロジェクト切り替え時にも同様の挙動となっている
    ⇒Ver0.96で修正
  • 検索条件欄フォントに游書体を指定すると、コンボボックスの枠線が表示されなくなる。
    ⇒Ver0.96で修正
  • 260文字を超えるフォルダ・ファイルを検索するとエラーとなる
    ⇒回避不能、長期的課題とさせてください。

    ⇒Windows10環境のみ、Ver1.00で長いファイル名に対応

grepツール刷新、「TresGrep」リリース

自作のgrepツール「HNXgrep」ですが、しばらく前から全面的な刷新に取り組んでいました。ようやくちゃんと動くものに仕上がってきましたので公開のご報告をさせていただきます。

新ツール名は「TresGrep」です。Vectorからダウンロードできます。
http://www.vector.co.jp/soft/dl/winnt/util/se516431.html

作り直しにあたっては、(微妙なデザインだった)アイコンだけでなく、ツール名そのものも変更することとしました。
検索条件欄3段・検索結果2タブ・プレビュー欄という基本的な画面構成は前作HNXgrepと同じですが、例えば

  • 検索対象とするファイルについて(サイズや更新日時等)エクスプローラと同等以上の細かい条件をつけて絞り込みできるようになった
  • リアルタイムに検索結果が表示されるようになった
  • UIが洗練された(というよりHNXgrepのUIがいろいろちぐはぐ感満載だったので全面的に直した)
    • キーワード等の入力エラーが分かりやすく表示されるようになった
    • 一覧表示項目のカスタマイズもできるようになった
    • 各画面項目のガイドメッセージが大幅に改善され、非表示等のカスタマイズや一覧表示出力もできるようになった
    • いままで検索条件や動作に関わる指定項目のうち一部が設定画面のほうに配置されており指定変更が煩雑で不便だったのを全面手直し
  • 外部ビューアがWindowsの「送る」メニューの設定をそのまま取り込むようになり、「送る」メニューにさまざまなツールを登録している人については外部ビューアの設定がほぼ不要になった

等々、少なくともHNXgrepをいまま利用していた方にとってはかなり使い勝手が向上していると思っております。
もちろんHNXgrep未体験で初めてTresGrepを使われるような方、いままではテキストエディタgrepエクスプローラの検索しか使ったことがない方についても、Grep専用ツールとしてのパワフルさ・便利さを実感していただけるのではと思います。
(あとは作者の個人的な事情としては、作り直しにあたってソースコードの構造を徹底的に見直して改善した結果、ソースコードの見通しが大変良くなりました・・・いままでのソースは整理整頓を後回しにした結果自分でも解読困難なしろものになり果てていたのが、これでようやく普通にメンテナンスできる状態を取り戻せました)

本当は8月下旬時点でVer 0.80をリリースしていたのですが、いざVectorに登録申請をしたあとにいろいろと不具合が見つかってしまい、再修正⇒登録申請⇒またバグが見つかる、というループにはまりこんでいました。
本日反映されたVer 0.85(2017/08/29版)でおおむね実用上困るバグはなくなっている・・はずです。どうぞお試しください。

ReadJEnc NuGetで公開 & 1.3.0へバージョンアップ

大変ご無沙汰しています。
というか記事を書くのもあまりに久々で、今までどんなテンション・文体でBLOGを書いてたかさっぱり思い出せません。
ひとまず周知事項を淡々と書いていくことにします。

お知らせその1:NuGetへ登録

自作の文字コード自動判別ライブラリ「ReadJEnc」ですが、NuGetに登録しました。
VisualStudio等のNuGetパッケージマネージャで「ReadJEnc」で検索すると見つかります。プロジェクトへの組み込みも「インストール」ボタン一発で簡単にできるようになりましたので、気軽にご利用ください。
NuGetギャラリーのURLは、 https://www.nuget.org/packages/ReadJEnc/ です。

お知らせその2:対応言語モード追加・改善

今回のNuGet登録を機に、ReadJEncで判別できる文字エンコーディングを増やしました。
今までのバージョン(Ver1.2.Xまで)では、日本語以外では

  • 欧文(西欧) : (UTF/ASCII/ANSI/ISO2022の判定のみ行い、ShiftJIS/EUC等は無視)
  • 繁体字中国語 : Big5(CP950)/EUC-TW(CP20000)
  • 簡体字中国語 : GB18030(CP54936)、および EUC-CN(CP51936)
  • ハングル   : UHC(CP949)、および EUC-KR(CP51949)

の判別に対応していましたが、今回のバージョンより

の判別モードも追加しました。
といっても判別アルゴリズムはどの言語も共通で、各国語ごとの相違は、
(1)未定義になっているはずの文字コード
(2)アルファベットと混在せず連続して登場すると思われる文字コードの範囲
を各エンコーディングごとそれぞれ設定しただけだったりします。
仕組みは簡単ですが、各国語/UTF-8ANSIの識別精度もそれなりに確保できるのではないかと思います。

また簡体字中国語/ハングルの判別仕様については、GB18030EUC-CNの文字コード範囲を拡張、UHCも同様にEUC-KRの文字コード範囲を拡張したものであり、GB18030EUC-CN、UHCとEUC-KRをそれぞれ別物として取り扱う意義が薄いため、今回のバージョンアップにてEUC-KR/EUC-CNの判定処理および文字コード定義を抹消しました。

その他近況等

ひさびさに開発意欲が戻ってきて、まとまった時間等の開発に必要なリソースが確保できたので、いろいろとソースコードを書いたりして過ごしています。
ReadJEncについてはまえまえからNuGetへ登録したいなぁとは思っていたのですが、やり方を調べるのが面倒くさそうでずっと放置してました。今回本腰を入れてやってみたらあっさりと簡単に登録できてしまい拍子抜けでした・・・。

ComboBoxで右クリックしながら左クリックすると不具合

WinFormsのComboBoxで不可解なバグにぶちあたってしまいました。
ComboBoxStyle=DropDownListの(手入力不可、プルダウンから選択のみ可能な)コンボボックスですが、ソースコードからSelectedIndexなりSelectedItemなりで選択値を指定して画面表示した後、マウス右クリックを押しっぱなしにした状態でマウス左クリックすると、なぜか一瞬だけプルダウンが開かれてすぐ閉じられてしまった挙句、コンボボックスが未選択の状態に戻ってしまいます。

Web上で情報収集してみたところこんな情報があったり。
http://mitsu.three-atmarks.com/archives/9513
またプルダウンの選択値が一切ない状態だと例外が発生しまうようです。
http://okwakatta.net/topic/topic047.html

挙動を調べた限りでは、DropDownClosedイベントが動く時点ではすでにSelectedIndexは-1になってしまっているようで、このような右クリック+左クリック操作を行うとSelectedIndexが初期化されてしまう・・・という仕様というかバグのようです。

デザイナ上でのComboBoxのプロパティや小手先のイベントで回避できるものでもなさそうなので、以下のようにComboBoxを継承して対策してみることにしました。

public class ComboBoxEx : ComboBox
{
 /// <summary>
 /// DropDownListのComboBoxを右クリックしながら左クリックした際の不具合対策
 /// </summary>
 /// <param name="m"></param>
 protected override void WndProc(ref Message m)
 {   //DropDownListのComboBoxを右クリックしながら左クリックすると
     //・SelectedIndex==-1の未選択状態に戻ってしまう(もしくは直近選択値に戻ってしまう)
     //・Itemsが空の場合に例外が発生してしまう
     //という事象が発生してしまうため対策
     const int WM_LBUTTONDOWN = 0x0201;
     if (m.Msg == WM_LBUTTONDOWN && (Control.MouseButtons & MouseButtons.Right) == MouseButtons.Right)
     {   //右クリックされている状態での左クリックメッセージは握りつぶす
         return;
     }
     base.WndProc(ref m);
 }

ComboBoxみたいなごくごく基本的なコントロール部品でも、こんなバグがあったりするんですね・・・・びっくりです。

ToolStripMenuItemにKeyDownイベントを追加する

.NET Framework(WinForms)のメニュー項目コントロールToolStripMenuItemには、KeyDown/KeyUp/KeyPressイベントは用意されていません。
特定のメニュー項目が選ばれてる状態で、何らかのキー、たとえば「Delete」「F2」キーなどが押されたことを検出するのはちょっと面倒くさいです。
(そのメニュー項目の親項目ContextMenuStripにKeyDownイベント等を仕掛け、押されたキー/SelectedになっているToolStripMenuItemの組み合わせに応じた処理を書けばよいのですが・・・メニュー項目ごとに処理が異なる場合などソースコードがかなり煩雑になってしまいます)
ToolStripMenuItemを拡張し、キーをが押されたらKeyDownイベントを発動するようにしてみましょう。こんなソースになります。

ToolStripMenuItemEx.cs ソースコード

/// <summary>
/// 改良版ToolStripMenuItem
/// <para>・KeyDownイベント追加</para>
/// </summary>
public class ToolStripMenuItemEx : ToolStripMenuItem
{
    /// <summary>
    /// 新しいインスタンスを初期化します。(フォームデザイナ向け)
    /// </summary>
    public ToolStripMenuItemEx() : base() { }
    /// <summary>
    /// 新しいインスタンスを初期化します。(Text指定)
    /// </summary>
    public ToolStripMenuItemEx(string text) : base(text) { }
    //ソースコードで動的生成する場合は、適宜便利な形のコンストラクタを追加すると幸せになれます。

    //----------------------------------------------------------------------
    /// <summary>
    /// この項目にフォーカスがあるときにキーが押されると発生します。
    /// (通常Controlと同等のイベントを疑似的に発生させています)
    /// </summary>
    [Category("キー")]
    [Description("キーが最初に押されたときに発生します。")]
    public event KeyEventHandler KeyDown;

    /// <summary>
    /// 疑似的にKeyDownイベントを発動します。
    ///</summary>
    protected override bool ProcessDialogKey(Keys keyData)
    {
        bool ret = base.ProcessDialogKey(keyData);
        if (ret == false && KeyDown != null)
        {   //KeyDownイベントを発生させる
            KeyEventArgs e = new KeyEventArgs(keyData);
            KeyDown(this, e);
            return e.Handled;
        }
        return ret;
    }
}

使い方

いったんビルドしてください。
フォームデザイナでメニュー項目を設定する際に、「MenuItemEx」が選べるようになります。MenuItemの代わりに追加してください。
ソースコードから動的にメニュー項目を生成するのであれば適切なコンストラクタを呼び出してください。

制限事項等

やっていることはソースの通り、押下されたキーを処理するProcessDialogKeyメソッドを上書きして自作KeyDownメソッドを呼び出しているだけです。
KeyDownイベント発動のタイミング/発動のされ方が通常のControlどおりではないため、イベントが発生しないキーがあったり、Handled=trueを設定しても入力がキャンセルされなかったりするかもしれません。動作確認は慎重に行ってください。
もし不具合を見つけたら、教えていただけると助かります。

透かし文字表示機能つきTextBox(WinForms)

Windows Formsのテキストボックスには、プレースホルダー(=ウォーターマーク:入力する値のガイド・ヒントを透かしのように表示する)機能が備わっていません。

こんな風に表示するためには、テキストボックスの継承クラスを実装して使う必要があります。以下、ソース例です。

TextBoxEx.cs ソースコード

public class TextBoxEx : TextBox
{
    /// <summary>
    /// テキストが空の場合に表示する文字列を取得・設定します。
    /// </summary>
    [Category("表示")]
    [DefaultValue("")]
    [Description("テキストが空の場合に表示する文字列です。")]
    [RefreshProperties(RefreshProperties.Repaint)]
    public string WatermarkText
    {
        get { return _watermarkText; }
        set
        {
            _watermarkText = value;
            this.Invalidate();
        }
    }
    private string _watermarkText = ""; //ウォーターマーク表示内容text
    ///<summary>
    ///描画拡張(テキスト未設定時、ウォーターマークを描画)
    ///</summary>
    ///<param name="m"></param>
    protected override void WndProc(ref Message m)
    {
        const int WM_PAINT = 0x000F;
        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);
                TextRenderer.DrawText(g, WatermarkText, this.Font,
                    rect, SystemColors.ControlDark, TextFormatFlags.Top | TextFormatFlags.Left);
            }
        }
    }
}

使い方

・ビルドするとツールボックスに「TextBoxEx」コンポーネントが出てくるようになるので、TextBoxの代わりにフォームデザイナへ貼り付けます。
・表示する透かし文字の文言は、WatermarkTextプロパティで指定します。

実現方法

ウォーターマークの実装ですが、

  1. フォーカスEnter/Leave時にテキストの色と表示内容を差し替えて疑似的に実現する方法
  2. Win32API(EM_SETCUEBANNERメッセージ)により表示する方法
  3. WM_PAINT描画メッセージを受け取ったタイミングで透かし文字文言を書き足す方法

あたりがメジャーなやり方です。

1.についてはComboBoxでの実装をこのblogでも紹介していますが、TextやColorを書き換える手間がかなりかかるのと、書き換えのつど発生してしまうイベントを抑止するのが大変なので、あまりおすすめはできません。

2.はWindowsXP以降の機能を利用するもので、一度EM_SETCUEBANNER(0x1501)メッセージを送りつけてしまえば、あとはWindowsがすべて自動でやってくれます。
実装もシンプルなのですが、Multiline=Trueの複数行TextBoxやRichTextBoxではウォーターマークが表示されなかったり、(今となってはもう利用者もわずかですが)日本含む東アジア版のWindowsXPでは不具合のため動かなかったりと、利用できないシチュエーションがあることに注意が必要です。
なおフォントの変更などを行うと内部的にはコントロールがいったん全破棄(再作成)されるらしく、OnHandleCreatedメソッドをオーバーライドして再度EM_SETCUEBANNERメッセージを送信しなおさないとウォーターマーク設定が復旧しません。

今回のソースは3.のやり方で実現しています。
TextBox(単一行/複数行)、RichTextBoxでは問題なく動作しますが、ComboBoxだとこの方法でテキスト欄にウォーターマークを上書きできなさそうです。(コンボボックス内のHWndItemに対して描画すればうまくいくかも?)

補足・透かし機能の表記

この透かし文字表示機能ですが、ウォーターマーク(Watermark)/プレースホルダー(Place Holder)/キューバナー(Cue Banner)/テキストヒント(Text Hint)などいろいろな呼ばれ方があり、統一されていません。
ウォーターマークといえばテレビ番組の局マーク透かし等、プレースホルダーだとSQL埋め込みパラメータあたりと混同されたりとややこしく、Web上で検索しずらいんですよね・・・・。

おまけ

WinFormsのTextBoxは、Ctrl-Aキーを押してもテキスト全選択ができません。
継承したTextBoxExクラスで以下のようにCtrl-Aを有効にしておくと不便が解消されます。

/// <summary>
/// なぜかTextBoxに実装されていないショートカットキー処理を組み込む
/// </summary>
protected override bool ProcessCmdKey(ref Message m, Keys keyData)
{
    Keys code = keyData & Keys.KeyCode;
    Keys modi = keyData & Keys.Modifiers;
    if ((keyData & Keys.Control) == Keys.Control)
    {   //Ctrlキー単独
        switch (code)
        {
            case Keys.A: //SelectAll
                this.SelectAll();
                return true;
            case Keys.Back: //ごみ文字が挿入されるのであえて握りつぶして無効にする
                return true;
        }
    }
    return base.ProcessCmdKey(ref m, keyData);
}

ついでに、Control+BackSpaceキーを押した際、テキストボックスに0x7Fの制御文字が挿入されてしまう不具合についても、対策も入れるとしたらこんな感じに。