public static void ListMatches(ref Statistics statistics, ThreadData threadData, bool simple, WaitHandle cancelEvent) { if (threadData.Exception != null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Read error of file: {threadData.Filename}"); Console.ForegroundColor = ConsoleColor.Gray; Console.WriteLine($"Exception: {threadData.Exception.Message}"); return; } if (threadData.Matches.Count == 0) { return; } Console.WriteLine(); ++statistics.Files; statistics.TotalMatches += threadData.Matches.Count; Console.BackgroundColor = ConsoleColor.DarkBlue; int x = Console.CursorLeft; int y = Console.CursorTop; for (int i = 0; i < Console.BufferWidth - 1; ++i) { Console.Write(' '); } Console.SetCursorPosition(x, y); Console.ForegroundColor = ConsoleColor.White; Console.Write($" {threadData.Filename}"); Console.ForegroundColor = ConsoleColor.Gray; var results_str = $"{threadData.Matches.Count} result{(threadData.Matches.Count == 1 ? "" : "s")} "; Console.Write(results_str.PadLeft(Console.BufferWidth - threadData.Filename.Length - 1)); Console.BackgroundColor = ConsoleColor.Black; //Console.WriteLine(); Console.WriteLine(); int MaxPrintLength = Console.BufferWidth - 12; var printed_lines_hash = new HashSet <int>(); var match_lines = new HashSet <int>(); foreach (var match in threadData.Matches) { var i = match.Line - 1; match_lines.Add(i); } int previous_line = -1; foreach (var match in threadData.Matches) { if (cancelEvent.WaitOne(0)) { break; } var i = match.Line - 1; if (!simple) { if (previous_line != -1 && previous_line != i) { Console.ForegroundColor = ConsoleColor.DarkGray; for (int j = 0; j < Console.BufferWidth - 1; ++j) { Console.Write('='); } Console.ForegroundColor = ConsoleColor.Gray; Console.WriteLine(); } for (int j = Math.Max(0, i - 5); j < i; ++j) { if (match_lines.Contains(j)) { continue; } if (printed_lines_hash.Contains(j)) { continue; } printed_lines_hash.Add(j); Console.Write($"{(j + 1).ToString().PadLeft(6)}: "); var part = threadData.Lines[j]; if (part.Length > MaxPrintLength - 3) { part = part.Substring(0, MaxPrintLength - 3) + "..."; } Console.WriteLine(part); previous_line = j + 1; } } Console.Write($"{(i + 1).ToString().PadLeft(6)}: "); previous_line = i + 1; var chunk_before = threadData.Lines[i].Substring(0, match.Offset); var chunk = threadData.Lines[i].Substring(match.Offset, match.Length); var chunk_after = threadData.Lines[i].Substring(match.Offset + match.Length); var print_len = MaxPrintLength; print_len -= chunk.Length; if (print_len > 0) { var len = Math.Min(print_len, chunk_before.Length + 3); print_len -= len; if (chunk_before.Length > len) { chunk_before = "..." + chunk_before.Substring(chunk_before.Length - Math.Max(0, (len - 3))); } if (chunk_after.Length > print_len) { chunk_after = chunk_after.Substring(0, Math.Max(0, print_len - 3)) + "..."; } } else { chunk_before = ""; chunk_after = ""; } Console.ForegroundColor = ConsoleColor.Red; Console.Write(chunk_before); Console.BackgroundColor = ConsoleColor.DarkMagenta; Console.ForegroundColor = ConsoleColor.White; Console.Write(chunk); Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(chunk_after); Console.ForegroundColor = ConsoleColor.Gray; if (!simple) { for (int j = i + 1; j < Math.Min(threadData.Lines.Length, i + 6); ++j) { if (match_lines.Contains(j)) { break; } if (printed_lines_hash.Contains(j)) { continue; } printed_lines_hash.Add(j); Console.Write($"{(j + 1).ToString().PadLeft(6)}: "); var part = threadData.Lines[j]; if (part.Length > MaxPrintLength - 3) { part = part.Substring(0, MaxPrintLength - 3) + "..."; } Console.WriteLine(part); previous_line = j + 1; } } } }
static int Main(string[] args) { var searchRegex = string.Empty; var ignoreCase = false; var includeHidden = false; var simple = false; var dirs = new List <string>() { "" }; var findFilesMode = false; for (int i = 0; i < args.Length; ++i) { if (args[i] == "-v" || args[i] == "--version") { Console.WriteLine($"QFind Version {Version}"); return(0); } if (args[i] == "-i") { ignoreCase = true; } else if (args[i] == "-a") { includeHidden = true; } else if (args[i] == "-s") { simple = true; } else if (args[i] == "--ext") { if (i + 1 >= args.Length) { Console.WriteLine("--ext requires an argument that contains a list of comma separated file extensions."); return(1); } var arg = args[++i]; if (arg != "*") { var extensions = Utilities.ReadExtensionsList(arg); Finder.ExtensionRegex = new Regex($"\\.({string.Join("|", extensions)})$", RegexOptions.IgnoreCase); } else { Finder.ExtensionRegex = new Regex(@"\."); } } else if (args[i] == "--exc") { if (i + 1 >= args.Length) { Console.WriteLine("--exc requires an argument that contains a list of comma separated file extensions to exclude."); return(1); } var extensions = Utilities.ReadExtensionsList(args[++i]); Finder.ExtensionExcludeRegex = new Regex($"\\.({string.Join("|", extensions)})$", RegexOptions.IgnoreCase); } else if (args[i] == "--dirs") { if (i + 1 >= args.Length) { Console.WriteLine("--dirs requires an argument that contains a list of comma separated directories to scan."); return(1); } dirs.Clear(); dirs.AddRange(args[++i].Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)); } else if (args[i] == "-f") { findFilesMode = true; } else { searchRegex = args[i]; } } using (var cancelEvent = new ManualResetEvent(false)) { Console.CancelKeyPress += (sender, e) => { e.Cancel = true; cancelEvent.Set(); }; if (string.IsNullOrEmpty(searchRegex)) { Console.Write("Find regex> "); searchRegex = Console.ReadLine(); } if (cancelEvent.WaitOne(0) || searchRegex == null) { return(0); } var stopwatch = Stopwatch.StartNew(); var options = RegexOptions.None; if (ignoreCase) { options |= RegexOptions.IgnoreCase; } Finder.SearchRegex = new Regex(searchRegex, options); var statistics = new Statistics(); if (findFilesMode) { // find files foreach (var dir in dirs) { foreach (var match in FileFinder.Scan(cancelEvent, dir, Finder.SearchRegex, ref statistics)) { if (match.Start > 0) { Console.Write(match.Fullpath.Substring(0, match.Start)); } Console.ForegroundColor = ConsoleColor.Magenta; Console.Write(match.Filename.Substring(0, match.Length)); Console.ForegroundColor = ConsoleColor.Gray; if (match.Start + match.Length < match.Fullpath.Length) { Console.Write(match.Fullpath.Substring(match.Start + match.Length)); } Console.WriteLine(); } } } else { // scan inside files var numberOfThreads = Environment.ProcessorCount; var backlog = new ThreadData[numberOfThreads]; var backlog_threads = new Thread[numberOfThreads]; int backlog_count = 0; for (int i = 0; i < backlog.Length; ++i) { backlog[i] = new ThreadData(cancelEvent); } foreach (var dir in dirs) { Finder.RecursiveFind(cancelEvent, dir, includeHidden, filename => { statistics.TotalFilesScanned++; backlog[backlog_count].Reset(filename); (backlog_threads[backlog_count] = new Thread(Finder.ProcessFileThread)).Start(backlog[backlog_count]); if (++backlog_count == backlog.Length) { for (int i = 0; i < backlog_count; ++i) { backlog_threads[i].Join(); if (!cancelEvent.WaitOne(0)) { Finder.ListMatches(ref statistics, backlog[i], simple, cancelEvent); } } backlog_count = 0; } }); } for (int i = 0; i < backlog_count; ++i) { backlog_threads[i].Join(); if (!cancelEvent.WaitOne(0)) { Finder.ListMatches(ref statistics, backlog[i], simple, cancelEvent); } } } stopwatch.Stop(); var str = ""; var canceled = cancelEvent.WaitOne(0); Console.ForegroundColor = ConsoleColor.White; if (statistics.TotalMatches != 0) { Console.WriteLine(); Console.BackgroundColor = canceled ? ConsoleColor.DarkYellow : ConsoleColor.DarkGreen; if (findFilesMode) { str = $" {statistics.TotalMatches} matches found"; } else { str = $" {statistics.TotalMatches} matches found in {statistics.Files} files"; } } else { Console.BackgroundColor = ConsoleColor.DarkRed; str = $" No matches found"; } str += $" ({statistics.TotalFilesScanned} files scanned - {stopwatch.Elapsed})"; Console.Write(str.PadRight(Console.BufferWidth - 2) + "# "); Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Gray; Console.WriteLine(); if (canceled) { Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("<Operation was canceled prematurely>"); Console.ForegroundColor = ConsoleColor.Gray; } } if (Debugger.IsAttached) { Console.ReadKey(true); } return(0); }