/// <summary> /// Start the searching /// </summary> /// <param name="searchWithInResults">true for searching within current results, false starts a new search</param> /// <history> /// [Curtis_Beard] 10/17/2005 Created /// [Curtis_Beard] 07/03/2006 FIX: 1516775, Remove trim on the search expression /// [Curtis_Beard] 07/12/2006 CHG: moved thread actions to grep class /// [Curtis_Beard] 11/22/2006 CHG: Remove use of browse in combobox /// [Curtis_Beard] 08/07/2007 ADD: 1741735, better search error handling /// [Curtis_Beard] 08/21/2007 FIX: 1778467, make sure file pattern is correct if a '\' is present /// [Curtis_Beard] 01/31/2012 CHG: 3424154/1816655, allow multiple starting directories /// [Curtis_Beard] 02/07/2012 CHG: 1741735, report full error message /// [Curtis_Beard] 02/24/2012 CHG: 3488322, use hand cursor for results view to signal click /// [Curtis_Beard] 10/30/2012 ADD: 28, search within results /// [Curtis_Beard] 12/01/2014 ADD: support for encoding detection event /// [Curtis_Beard] 12/17/2014 ADD: support for Win7+ taskbar progress /// [Curtis_Beard] 02/24/2015 CHG: remove isSearching check so that you can view selected file during a search /// [Curtis_Beard] 05/26/2015 CHG: add stop search messsage to log with time /// </history> private void StartSearch(bool searchWithInResults) { try { string path = cboFilePath.Text.Trim(); string[] filePaths = null; if (searchWithInResults) { // get currently listed file paths from ListView filePaths = new string[lstFileNames.Items.Count]; for (int i = 0; i < lstFileNames.Items.Count; i++) { filePaths[i] = Path.Combine(lstFileNames.Items[i].SubItems[Constants.COLUMN_INDEX_DIRECTORY].Text, lstFileNames.Items[i].SubItems[Constants.COLUMN_INDEX_FILE].Text); } } // update combo selections AddComboSelection(cboSearchForText, cboSearchForText.Text); AddComboSelection(cboFileName, cboFileName.Text); AddComboSelection(cboFilePath, path); SetWindowText(); // disable gui SetSearchState(false); // reset display LogItems.Clear(); SetStatusBarMessage(string.Empty); SetStatusBarEncoding(string.Empty); SetStatusBarTotalCount(0); SetStatusBarFileCount(0); SetStatusBarFilterCount(0); SetStatusBarErrorCount(0); ClearItems(); txtHits.LineNumbers = null; txtHits.Clear(); // setup structs to pass to grep var fileFilterSpec = GetFilterSpecFromUI(); var searchSpec = GetSearchSpecFromUI(path, fileFilterSpec.FileFilter, filePaths); // create new grep instance __Grep = new Grep(searchSpec, fileFilterSpec); // add plugins __Grep.Plugins = Core.PluginManager.Items; // attach events __Grep.FileHit += ReceiveFileHit; __Grep.LineHit += ReceiveLineHit; __Grep.SearchCancel += ReceiveSearchCancel; __Grep.SearchComplete += ReceiveSearchComplete; __Grep.SearchError += ReceiveSearchError; __Grep.SearchingFile += ReceiveSearchingFile; __Grep.FileFiltered += ReceiveFileFiltered; __Grep.DirectoryFiltered += ReceiveDirectoryFiltered; __Grep.SearchingFileByPlugin += ReceiveSearchingFileByPlugin; __Grep.FileEncodingDetected += ReceiveFileEncodingDetected; API.TaskbarProgress.SetState(this.Handle, API.TaskbarProgress.TaskbarStates.Indeterminate); LogItems.Add(new LogItem(LogItem.LogItemTypes.Status, "SearchStarted")); LogStartSearchMessage(searchSpec, fileFilterSpec); StartingTime = Stopwatch.GetTimestamp(); __Grep.BeginExecute(); } catch (Exception ex) { LogStopSearchMessage("error"); RestoreTaskBarProgress(); LogItems.Add(new LogItem(LogItem.LogItemTypes.Error, "SearchGenericError", string.Format("{0}||{1}", string.Empty, ex.Message))); LogClient.Instance.Logger.Error("Unhandled search error: {0}", LogClient.GetAllExceptions(ex)); string message = string.Format(Language.GetGenericText("SearchGenericError"), ex.Message); MessageBox.Show(this, message, ProductInformation.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error); SetStatusBarMessage(message); SetSearchState(true); CalculateTotalCount(); } }
/// <summary> /// Returns the given line with the search text highlighted. /// </summary> /// <param name="line">Line to check</param> /// <param name="grep">Grep Object containing options</param> /// <returns>Line with search text highlighted</returns> /// <history> /// [Curtis_Beard] 09/05/2006 Created /// [Curtis_Beard] 05/18/2006 FIX: 1723815, use correct whole word matching regex /// [Curtis_Beard] 11/11/2014 CHG: escape any html characters /// [Curtis_Beard] 04/13/2015 CHG: code cleanup /// </history> private static string HighlightRegEx(string line, Grep grep) { string tempString = string.Empty; int lastPos = 0; Regex regEx; MatchCollection matchCollection; Match match; StringBuilder newLine = new StringBuilder(); // find all reg ex matches in line string pattern = string.Format("{0}{1}{0}", grep.SearchSpec.UseWholeWordMatching ? "\\b" : string.Empty, grep.SearchSpec.SearchText); RegexOptions options = grep.SearchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase; regEx = new Regex(pattern, options); matchCollection = regEx.Matches(line); // loop through the matches for (int i = 0; i < matchCollection.Count; i++) { match = matchCollection[i]; // check for empty string to prevent assigning nothing to selection text preventing // a system beep tempString = line.Substring(lastPos, match.Index - lastPos); if (!tempString.Equals(string.Empty)) { newLine.Append(WebUtility.HtmlEncode(tempString)); } // set the hit text newLine.AppendFormat("<span class=\"searchtext\">{0}</span>", WebUtility.HtmlEncode(line.Substring(match.Index, match.Length))); // set the end text if (i + 1 >= matchCollection.Count) { // no more hits so just set the rest newLine.Append(WebUtility.HtmlEncode(line.Substring(match.Index + match.Length))); lastPos = match.Index + match.Length; } else { // another hit so just set inbetween newLine.Append(WebUtility.HtmlEncode(line.Substring(match.Index + match.Length, matchCollection[i + 1].Index - (match.Index + match.Length)))); lastPos = matchCollection[i + 1].Index; } } if (matchCollection.Count == 0) { // no match, just a context line newLine.Append(WebUtility.HtmlEncode(line)); } return newLine.ToString(); }
/// <summary> /// Replaces all the search option holders in the given text. /// </summary> /// <param name="text">Text containing holders</param> /// <param name="grep">Grep object containing settings</param> /// <param name="totalHits">Number of total hits</param> /// <param name="showLineNumbers">Determines whether to show line numbers</param> /// <param name="removeLeadingWhiteSpace">Determines whether to remove leading white space</param> /// <returns>Text with holders replaced</returns> /// <history> /// [Curtis_Beard] 09/05/2006 Created /// [Curtis_Beard] 01/31/2012 ADD: display for additional options (skip hidden/system options, search paths, modified dates, file sizes) /// [Curtis_Beard] 10/30/2012 CHG: use year replacement for copyright /// [Curtis_Beard] 10/30/2012 ADD: file hit count, CHG: recurse to Subfolders /// [Curtis_Beard] 02/12/2014 CHG: handle file search only better, add totalHits as parameter /// [Curtis_Beard] 11/11/2014 ADD: export all filteritems /// </history> public static string ReplaceSearchOptions(string text, Grep grep, int totalHits, bool showLineNumbers, bool removeLeadingWhiteSpace) { var spec = grep.SearchSpec; text = text.Replace("%%totalhits%%", totalHits.ToString()); text = text.Replace("%%year%%", DateTime.Now.Year.ToString()); text = text.Replace("%%searchpaths%%", "Search Path(s): " + string.Join(", ", spec.StartDirectories)); text = text.Replace("%%filetypes%%", "File Types: " + grep.FileFilterSpec.FileFilter); text = text.Replace("%%regex%%", "Regular Expressions: " + spec.UseRegularExpressions); text = text.Replace("%%casesen%%", "Case Sensitive: " + spec.UseCaseSensitivity); text = text.Replace("%%wholeword%%", "Whole Word: " + spec.UseWholeWordMatching); text = text.Replace("%%recurse%%", "Subfolders: " + spec.SearchInSubfolders); text = text.Replace("%%filenameonly%%", "Show File Names Only: " + spec.ReturnOnlyFileNames); text = text.Replace("%%negation%%", "Negation: " + spec.UseNegation); text = text.Replace("%%linenumbers%%", "Line Numbers: " + showLineNumbers); text = text.Replace("%%removeleadingwhitespace%%", "Remove Leading White Space: " + removeLeadingWhiteSpace); text = text.Replace("%%contextlines%%", "Context Lines: " + spec.ContextLines); // filter items StringBuilder filterBuilder = new StringBuilder(); if (grep.FileFilterSpec.FilterItems != null) { filterBuilder.Append("Exclusions:<br/>"); foreach (FilterItem item in grep.FileFilterSpec.FilterItems) { string option = item.ValueOption.ToString(); if (item.ValueOption == FilterType.ValueOptions.None) { option = string.Empty; } filterBuilder.AppendFormat("<span class=\"indent\">{0} -> {1}: {2} {3} {4}</span><br/>", item.FilterType.Category, item.FilterType.SubCategory, item.Value, option, !string.IsNullOrEmpty(option) && item.ValueIgnoreCase ? " (ignore case)" : string.Empty ); } } text = text.Replace("%%exclusions%%", filterBuilder.ToString()); // %%searchmessage%% string searchMessage = string.Empty; if (!string.IsNullOrEmpty(grep.SearchSpec.SearchText)) { if (grep.SearchSpec.ReturnOnlyFileNames) { searchMessage = string.Format("{0} was {1}found in {2} file{3}", spec.SearchText, spec.UseNegation ? "not " : "", grep.MatchResults.Count, grep.MatchResults.Count > 1 ? "s" : ""); } else { searchMessage = string.Format("{0} was found {1} time{2} in {3} file{4}", spec.SearchText, totalHits, totalHits > 1 ? "s" : "", grep.MatchResults.Count, grep.MatchResults.Count > 1 ? "s" : ""); } } text = text.Replace("%%searchmessage%%", searchMessage); return text; }
/// <summary> /// Returns the given line with the search text highlighted. /// </summary> /// <param name="line">Line to check</param> /// <param name="grep">Grep Object containing options</param> /// <returns>Line with search text highlighted</returns> /// <history> /// [Curtis_Beard] 09/05/2006 Created /// [Curtis_Beard] 11/11/2014 CHG: escape any html characters /// [Curtis_Beard] 04/13/2015 CHG: code cleanup /// </history> private static string HighlightNormal(string line, Grep grep) { StringBuilder newLine = new StringBuilder(); string searchText = grep.SearchSpec.SearchText; string tempLine = line; // attempt to locate the text in the line int pos = tempLine.IndexOf(searchText, grep.SearchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); if (pos > -1) { while (pos > -1) { //retrieve parts of text var begin = tempLine.Substring(0, pos); var text = tempLine.Substring(pos, searchText.Length); var end = tempLine.Substring(pos + searchText.Length); newLine.Append(WebUtility.HtmlEncode(begin)); // do a check to see if begin and end are valid for wholeword searches bool highlight = true; if (grep.SearchSpec.UseWholeWordMatching) { highlight = Grep.WholeWordOnly(begin, end); } // set highlight color for searched text if (highlight) { newLine.AppendFormat("<span class=\"searchtext\">{0}</span>", WebUtility.HtmlEncode(text)); } else { newLine.Append(WebUtility.HtmlEncode(text)); } // Check remaining string for other hits in same line pos = end.IndexOf(searchText, grep.SearchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); // set default color for end, if no more hits in line tempLine = end; if (pos < 0) { newLine.Append(WebUtility.HtmlEncode(end)); } } } else { newLine.Append(WebUtility.HtmlEncode(tempLine)); } return newLine.ToString(); }
/// <summary> /// Returns the given line with the search text highlighted. /// </summary> /// <param name="line">Line to check</param> /// <param name="grep">Grep Object containing options</param> /// <returns>Line with search text highlighted</returns> /// <history> /// [Curtis_Beard] 09/05/2006 Created /// [Curtis_Beard] 02/12/2014 CHG: handle file search only better /// </history> public static string GetHighlightLine(string line, Grep grep) { string newLine = string.Empty; if (!string.IsNullOrEmpty(grep.SearchSpec.SearchText)) { if (grep.SearchSpec.UseRegularExpressions) newLine = HighlightRegEx(line, grep); else newLine = HighlightNormal(line, grep); } return newLine + "<br />"; }