@@ -38,6 +38,7 @@ public class MainForm : Form
3838 private readonly CheckBox chkContentSingleLine ;
3939 private readonly NumericStepper nudContentTimeout ;
4040 private readonly FilePicker fpSearchPath ;
41+ private readonly ComboBox cboSubdirectories ;
4142 private readonly Button btnStartSearch ;
4243 private readonly FilePicker fpOpenWith ;
4344 private readonly Button btnSelectAll ;
@@ -91,6 +92,9 @@ public class MainForm : Form
9192 private static readonly object _locker = new object ( ) ;
9293 private bool _matchNumberOrdering ;
9394 private DateTime _lastTreeGridViewRefresh = DateTime . UtcNow ;
95+ private int _searchDepth = - 1 ;
96+ private string _contentPattern ;
97+ private string _filenamePattern ;
9498
9599 public MainForm ( )
96100 {
@@ -119,6 +123,7 @@ public MainForm()
119123 chkContentSingleLine = FindChild < CheckBox > ( "chkContentSingleLine" ) ;
120124 nudContentTimeout = FindChild < NumericStepper > ( "nudContentTimeout" ) ;
121125 fpSearchPath = FindChild < FilePicker > ( "fpSearchPath" ) ;
126+ cboSubdirectories = FindChild < ComboBox > ( "cboSubdirectories" ) ;
122127 btnStartSearch = FindChild < Button > ( "btnStartSearch" ) ;
123128 fpOpenWith = FindChild < FilePicker > ( "fpOpenWith" ) ;
124129 btnSelectAll = FindChild < Button > ( "btnSelectAll" ) ;
@@ -131,6 +136,29 @@ public MainForm()
131136 lblStatus = FindChild < Label > ( "lblStatus" ) ;
132137 #endregion // Initialize Controls
133138
139+ AddSubdirectoriesItems ( ) ;
140+ AddTestResultExplorerColumns ( ) ;
141+ }
142+
143+ private void AddSubdirectoriesItems ( )
144+ {
145+ cboSubdirectories . SuspendLayout ( ) ;
146+ cboSubdirectories . Items . Add ( "all (unlimited depth)" , "-1" ) ;
147+ cboSubdirectories . Items . Add ( "current dir only" , "0" ) ;
148+ cboSubdirectories . Items . Add ( "1 level" , "1" ) ;
149+ for ( int i = 2 ; i <= 32 ; i ++ )
150+ {
151+ cboSubdirectories . Items . Add ( $ "{ i } levels", i . ToString ( ) ) ;
152+ }
153+
154+ cboSubdirectories . SelectedKey = "-1" ;
155+ cboSubdirectories . ReadOnly = true ;
156+ cboSubdirectories . ResumeLayout ( ) ;
157+ cboSubdirectories . Invalidate ( ) ;
158+ }
159+
160+ private void AddTestResultExplorerColumns ( )
161+ {
134162 tvwResultExplorer . Columns . Add ( new GridColumn ( )
135163 {
136164 HeaderText = "Select" ,
@@ -197,12 +225,15 @@ private void OpenInEditor(string path)
197225
198226 private async void HandleStartSearch ( object sender , EventArgs e )
199227 {
228+ string searchPath = fpSearchPath . FilePath ? . Trim ( ) ;
229+ if ( string . IsNullOrWhiteSpace ( searchPath ) )
230+ return ;
231+
232+ if ( ! Directory . Exists ( searchPath ) )
233+ return ;
234+
200235 try
201236 {
202- string searchPath = fpSearchPath . FilePath . Trim ( ) ;
203- if ( ! Directory . Exists ( searchPath ) )
204- return ;
205-
206237 lock ( _locker )
207238 {
208239 if ( _isSearching )
@@ -219,6 +250,10 @@ private async void HandleStartSearch(object sender, EventArgs e)
219250 _isSearching = true ;
220251 }
221252
253+ _filenamePattern = txtFilenameRegex . Text ;
254+ _contentPattern = txtContentRegex . Text ;
255+ _searchDepth = int . Parse ( cboSubdirectories . SelectedKey ) ;
256+
222257 _filenameRegex = FilenameRegex ;
223258 _contentRegex = ContentRegex ;
224259
@@ -230,7 +265,7 @@ private async void HandleStartSearch(object sender, EventArgs e)
230265 btnOrderByMatches . Enabled = false ;
231266 _cancellationTokenSource = new CancellationTokenSource ( ) ;
232267 CancellationToken token = _cancellationTokenSource . Token ;
233- await Task . Factory . StartNew ( ( ) => SearchDirectory ( searchPath , treeGridItemCollection ) ,
268+ await Task . Factory . StartNew ( ( ) => SearchDirectory ( 0 , searchPath , treeGridItemCollection ) ,
234269 token ,
235270 TaskCreationOptions . LongRunning ,
236271 TaskScheduler . Default ) ;
@@ -249,19 +284,33 @@ await Task.Factory.StartNew(() => SearchDirectory(searchPath, treeGridItemCollec
249284 }
250285 }
251286
252- private void SearchDirectory ( string path , TreeGridItemCollection treeGridItemCollection )
287+ private void SearchDirectory ( int level , string path , TreeGridItemCollection treeGridItemCollection )
253288 {
254289 if ( _cancellationTokenSource . IsCancellationRequested )
255290 return ;
256291
292+ if ( _searchDepth != - 1 && level > _searchDepth )
293+ return ;
294+
257295 Application . Instance . Invoke ( ( ) => lblStatus . Text = path ) ;
258296 List < string > filePaths = GetMatchingFiles ( path ) ;
259297 foreach ( string filePath in filePaths . OrderBy ( f => f ) )
260298 {
261299 try
262300 {
263- MatchCollection matches = _contentRegex . Matches ( File . ReadAllText ( filePath ) ) ;
264- if ( matches . Count > 0 )
301+ int count = 0 ;
302+ bool add = false ;
303+ if ( string . IsNullOrWhiteSpace ( _contentPattern ) )
304+ {
305+ add = true ;
306+ }
307+ else
308+ {
309+ MatchCollection matches = _contentRegex . Matches ( File . ReadAllText ( filePath ) ) ;
310+ count = matches . Count ;
311+ add = count > 0 ;
312+ }
313+ if ( add )
265314 {
266315 treeGridItemCollection . Add (
267316 new TreeGridItem ( )
@@ -270,7 +319,7 @@ private void SearchDirectory(string path, TreeGridItemCollection treeGridItemCol
270319 {
271320 false , // column 0: Selected checkbox
272321 null , // column 1: Open link
273- matches . Count ,
322+ count ,
274323 filePath
275324 }
276325 } ) ;
@@ -284,29 +333,43 @@ private void SearchDirectory(string path, TreeGridItemCollection treeGridItemCol
284333
285334 UpdateResultExplorer ( ) ;
286335
287- foreach ( string directoryPath in Directory . GetDirectories ( path ) )
336+ try
337+ {
338+ foreach ( string directoryPath in Directory . GetDirectories ( path ) )
339+ {
340+ SearchDirectory ( level + 1 , directoryPath , treeGridItemCollection ) ;
341+ }
342+ }
343+ catch
288344 {
289- SearchDirectory ( directoryPath , treeGridItemCollection ) ;
345+ // No permission to list directories, etc.
290346 }
291347 }
292348
293349 private List < string > GetMatchingFiles ( string path )
294350 {
295351 List < string > filePaths = new List < string > ( ) ;
296- foreach ( string filePath in Directory . GetFiles ( path ) )
352+ try
297353 {
298- string filename = Path . GetFileName ( filePath ) ;
299- try
354+ foreach ( string filePath in Directory . GetFiles ( path ) )
300355 {
301- if ( _filenameRegex . IsMatch ( filename ) )
356+ string filename = Path . GetFileName ( filePath ) ;
357+ try
302358 {
303- filePaths . Add ( filePath ) ;
359+ if ( string . IsNullOrWhiteSpace ( _filenamePattern ) || _filenameRegex . IsMatch ( filename ) )
360+ {
361+ filePaths . Add ( filePath ) ;
362+ }
363+ }
364+ catch
365+ {
366+ // Regex timeout
304367 }
305368 }
306- catch
307- {
308- // Regex timeout
309- }
369+ }
370+ catch
371+ {
372+ // No permission to list files, etc.
310373 }
311374
312375 return filePaths ;
0 commit comments