/// <summary> /// Applies the specified colors to the given line. /// </summary> /// <param name="line">Current DocumentLine from AvalonEdit</param> protected override void ColorizeLine(DocumentLine line) { int lineStartOffset = line.Offset; string text = CurrentContext.Document.GetText(line); if (matches == null || matches.Count == 0 || string.IsNullOrEmpty(text)) { return; } // find what type of line this is, either the file path or a result line bool isFileName = false; MatchResultLine matchLine = null; foreach (MatchResult result in matches) { if (result.File.FullName.Equals(text, StringComparison.OrdinalIgnoreCase)) { isFileName = true; break; } else { foreach (var matchResultLine in result.Matches) { string lineText = matchResultLine.Line; if (removeWhiteSpace) { lineText = lineText.TrimStart(); } if (lineText.Equals(text)) { matchLine = matchResultLine; break; } } } } try { if (isFileName) { base.ChangeLinePart( lineStartOffset, // startOffset lineStartOffset + line.Length, // endOffset (VisualLineElement element) => { // bold current typeface for file name display Typeface tf = element.TextRunProperties.Typeface; var tfNew = new Typeface(tf.FontFamily, tf.Style, System.Windows.FontWeights.Bold, tf.Stretch); element.TextRunProperties.SetTypeface(tfNew); }); } else { if (matchLine != null && matchLine.HasMatch) { int trimOffset = 0; if (removeWhiteSpace) { trimOffset = matchLine.Line.Length - matchLine.Line.TrimStart().Length; } for (int i = 0; i < matchLine.Matches.Count; i++) { int startPosition = matchLine.Matches[i].StartPosition; int length = matchLine.Matches[i].Length; base.ChangeLinePart( lineStartOffset + (startPosition - trimOffset), // startOffset lineStartOffset + (startPosition - trimOffset) + length, // endOffset (VisualLineElement element) => { // highlight match element.TextRunProperties.SetForegroundBrush(MatchForeground); element.TextRunProperties.SetBackgroundBrush(MatchBackground); }); } } else { base.ChangeLinePart( lineStartOffset, // startOffset lineStartOffset + line.Length, // endOffset (VisualLineElement element) => { // all non-matched lines are grayed out element.TextRunProperties.SetForegroundBrush(NonMatchForeground); }); } } } catch { } }
/// <summary> /// Applies the specified colors to the given line. /// </summary> /// <param name="line">Current DocumentLine from AvalonEdit</param> /// <history> /// [Curtis_Beard] 04/08/2015 ADD: switch from Rich Text Box to AvalonEdit /// </history> protected override void ColorizeLine(DocumentLine line) { int lineStartOffset = line.Offset; string text = CurrentContext.Document.GetText(line); if (match == null || match.Matches == null || match.Matches.Count == 0 || string.IsNullOrEmpty(text)) { return; } int lineNumber = line.LineNumber; // 1 based // lines in grep are 0 based array MatchResultLine matchLine = null; if (showingFullFile) { matchLine = (from m in match.Matches where m.LineNumber == lineNumber select m).FirstOrDefault(); } else { matchLine = lineNumber - 1 < match.Matches.Count ? match.Matches[lineNumber - 1] : null; } string contents = matchLine != null ? matchLine.Line : string.Empty; bool isHit = matchLine != null ? matchLine.HasMatch : false; try { if (isHit && !string.IsNullOrEmpty(contents)) { int trimOffset = 0; if (removeWhiteSpace) { if (matchLine.HasMatch) { trimOffset = Utils.GetValidLeadingSpaces(contents, matchLine.Matches[0].StartPosition); } else { trimOffset = contents.Length - contents.TrimStart().Length; } } for (int i = 0; i < matchLine.Matches.Count; i++) { int startPosition = matchLine.Matches[i].StartPosition; int length = matchLine.Matches[i].Length; base.ChangeLinePart( lineStartOffset + (startPosition - trimOffset), // startOffset lineStartOffset + (startPosition - trimOffset) + length, // endOffset (VisualLineElement element) => { // highlight match element.TextRunProperties.SetForegroundBrush(MatchForeground); element.TextRunProperties.SetBackgroundBrush(MatchBackground); }); } } else if (!isHit && !showingFullFile) { base.ChangeLinePart( lineStartOffset, // startOffset lineStartOffset + line.Length, // endOffset (VisualLineElement element) => { // all non-matched lines are grayed out element.TextRunProperties.SetForegroundBrush(NonMatchForeground); }); } } catch { } }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; MatchResult match = null; if (Parser.IsParseable(file.FullName)) { string fileContent = Parser.Parse(file.FullName); if (!string.IsNullOrEmpty(fileContent)) { string[] lines = fileContent.Split(new char[] { '\n', '\r' }); for (int i = 0; i < lines.Length; i++) { string line = lines[i]; int posInStr = -1; Regex reg = null; MatchCollection regCol = null; if (searchSpec.UseRegularExpressions) { string pattern = string.Format("{0}{1}{0}", searchSpec.UseWholeWordMatching ? "\\b" : string.Empty, searchSpec.SearchText); RegexOptions options = searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase; reg = new Regex(pattern, options); regCol = reg.Matches(line); if (regCol.Count > 0) { posInStr = 1; } } else { // If we are looking for whole worlds only, perform the check. if (searchSpec.UseWholeWordMatching) { reg = new Regex("\\b" + Regex.Escape(searchSpec.SearchText) + "\\b", searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase); // if match is found, also check against our internal line hit count method to be sure they are in sync Match mtc = reg.Match(line); if (mtc != null && mtc.Success && libbSearch.Grep.RetrieveLineMatches(line, searchSpec).Count > 0) { posInStr = mtc.Index; } } else { posInStr = line.IndexOf(searchSpec.SearchText, searchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } } if (posInStr > -1) { if (match == null) { match = new MatchResult(file); // found hit in file so just return if (searchSpec.ReturnOnlyFileNames) { break; } } var matchLineFound = new MatchResultLine() { Line = line, LineNumber = -1, HasMatch = true }; if (searchSpec.UseRegularExpressions) { posInStr = regCol[0].Index; match.SetHitCount(regCol.Count); foreach (Match regExMatch in regCol) { matchLineFound.Matches.Add(new MatchResultLineMatch(regExMatch.Index, regExMatch.Length)); } } else { var lineMatches = libbSearch.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLineFound.Matches = lineMatches; } matchLineFound.ColumnNumber = 1; match.Matches.Add(matchLineFound); } } } } return(match); }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> /// <history> /// [Curtis_Beard] 07/28/2006 Created /// [Curtis_Beard] 05/25/2007 ADD: support for Exception object /// [Curtis_Beard] 03/31/2015 CHG: rework Grep/Matches /// </history> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; if (IsAvailable && IsUsable) { try { if (file.Exists) { //const int MARGINSIZE = 4; int count = 0; MatchResult match = null; int prevLine = 0; int prevPage = 0; //string _spacer = new string(' ', MARGINSIZE); //string _contextSpacer = string.Empty; //if (searchSpec.ContextLines > 0) //{ // _contextSpacer = new string(' ', MARGINSIZE); // _spacer = _contextSpacer.Substring(_contextSpacer.Length - MARGINSIZE - 2) + "> "; //} //else // _spacer = new string(' ', MARGINSIZE); // Open a given Word document as readonly // Note: Word 2003+ requires write mode since reading mode doesn't allow use of home/end keys to select text) object appversion = __WordApplication.GetType().InvokeMember("Version", BindingFlags.GetProperty, null, __WordApplication, null); double version = 0; double.TryParse(appversion.ToString(), out version); bool useReadOnly = version >= 12.00 ? false : true; object wordDocument = OpenDocument(file.FullName, useReadOnly); // Get Selection Property __WordSelection = __WordApplication.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, __WordApplication, null); // create range and find objects object range = GetProperty(wordDocument, "Content"); object find = GetProperty(range, "Find"); // setup find RunRoutine(find, "ClearFormatting", null); SetProperty(find, "Forward", true); SetProperty(find, "Text", searchSpec.SearchText); SetProperty(find, "MatchWholeWord", searchSpec.UseWholeWordMatching); SetProperty(find, "MatchCase", searchSpec.UseCaseSensitivity); // start find FindExecute(find); // keep finding text while ((bool)GetProperty(find, "Found") == true) { count += 1; if (count == 1) { // create hit object match = new MatchResult(file); } // since a hit was found and only displaying file names, quickly exit if (searchSpec.ReturnOnlyFileNames) break; // retrieve find information int start = (int)GetProperty(range, "Start"); int colNum = (int)Information(range, WdInformation.wdFirstCharacterColumnNumber); int lineNum = (int)Information(range, WdInformation.wdFirstCharacterLineNumber); int pageNum = (int)Information(range, WdInformation.wdActiveEndPageNumber); string line = GetFindTextLine(start); // don't add a hit if on same line if (!(prevLine == lineNum && prevPage == pageNum)) { // check for line numbers //if (searchSpec.IncludeLineNumbers) //{ // // setup line header // _spacer = "(" + string.Format("{0},{1}", lineNum, pageNum); // if (_spacer.Length <= 5) // { // _spacer = _spacer + new string(' ', 6 - _spacer.Length); // } // _spacer = _spacer + ") "; // //_contextSpacer = "(" + new string(' ', _spacer.Length - 3) + ") "; //} // remove any odd characters from the text line = RemoveSpecialCharacters(line); // add context lines before // if (__contextLines > 0){ // For i As int = __contextLines To 1 Step -1 // SetProperty(__WordSelection, "Start", start) // SelectionMoveUp(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum - i, 1) // End If // Next // End If // add line MatchResultLine matchLine = new MatchResultLine() { HasMatch = true, ColumnNumber = colNum, LineNumber = lineNum, Line = line }; var lineMatches = libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLine.Matches = lineMatches; match.Matches.Add(matchLine); //match.Add(_spacer, line, lineNum, colNum); // add context lines after // if (__contextLines > 0){ // For i As int = 1 To __contextLines // SetProperty(__WordSelection, "Start", start) // SelectionMoveDown(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum + i, 1) // End If // Next // End If } //match.SetHitCount(); prevLine = lineNum; prevPage = pageNum; // find again FindExecute(find); } ReleaseSelection(); CloseDocument(wordDocument); return match; } else { string msg = string.Format("File does not exist: {0}", file.FullName); ex = new Exception(msg); Trace(msg); } } catch (Exception mainEx) { ex = mainEx; Trace(mainEx.ToString()); } } else { ex = new Exception("Plugin not available or usable."); Trace("Plugin not available or usable."); } return null; }
/// <summary> /// Search a given file for the searchText. /// </summary> /// <param name="file">FileInfo object for file to search for searchText</param> /// <history> /// [Curtis_Beard] 09/08/2005 Created /// [Curtis_Beard] 11/21/2005 ADD: update hit count when actual line added /// [Curtis_Beard] 12/02/2005 CHG: use SearchingFile instead of StatusMessage /// [Curtis_Beard] 04/21/2006 CHG: use a regular expression match collection to get /// correct count of hits in a line when using RegEx /// [Curtis_Beard] 07/03/2006 FIX: 1500174, use a FileStream to open the files readonly /// [Curtis_Beard] 07/07/2006 FIX: 1512029, RegEx use Case Sensitivity and WholeWords, /// also use different whole word matching regex /// [Curtis_Beard] 07/26/2006 ADD: 1512026, column position /// [Curtis_Beard] 07/26/2006 FIX: 1530023, retrieve file with correct encoding /// [Curtis_Beard] 09/12/2006 CHG: Converted to C# /// [Curtis_Beard] 09/28/2006 FIX: check for any plugins before looping through them /// [Curtis_Beard] 05/18/2006 FIX: 1723815, use correct whole word matching regex /// [Curtis_Beard] 06/26/2007 FIX: correctly detect plugin extension support /// [Curtis_Beard] 06/26/2007 FIX: 1779270, increase array size holding context lines /// [Curtis_Beard] 10/09/2012 FIX: don't overwrite position when getting context lines /// [Curtis_Beard] 10/12/2012 FIX: get correct position when using whole word option /// [Curtis_Beard] 10/12/2012 CHG: 32, implement a hit count filter /// [Curtis_Beard] 10/31/2012 CHG: renamed to SearchFileContents, remove parameter searchText /// [Curtis_Beard] 08/19/2014 FIX: 57, escape search text when whole word is enabled but not regular expressions /// [Curtis_Beard] 10/27/2014 CHG: 85, remove leading white space, remove use of newline so each line is in hit object /// [Curtis_Beard] 02/09/2015 CHG: 92, support for specific file encodings /// [Curtis_Beard] 03/05/2015 FIX: 64/35, if whole word doesn't pass our check but does pass regex, make it fail. Code cleanup. /// [Curtis_Beard] 04/02/2015 CHG: remove line number logic and always include line number in MatchResultLine. /// [Curtis_Beard] 05/18/2015 FIX: 72, don't grab file sample when detect encoding option is turned off. /// [Curtis_Beard] 05/18/2015 FIX: 69, use same stream to detect encoding and grep contents /// [Curtis_Beard] 05/26/2015 FIX: 69, add performance setting for file detection /// [Curtis_Beard] 06/02/2015 FIX: 75, use sample size from performance setting /// [theblackbunny] 06/25/2015 FIX: 39, remove context lines that intersect with each other in different MatchResults /// </history> private void SearchFileContents(FileInfo file) { // Raise SearchFile Event OnSearchingFile(file); FileStream _stream = null; StreamReader _reader = null; int _lineNumber = 0; MatchResult match = null; Regex _regularExp; MatchCollection _regularExpCol = null; bool _hitOccurred = false; bool _fileNameDisplayed = false; int _maxContextLines = 0; var _context = new string[11]; int _contextIndex = -1; int _lastHit = 0; int userFilterCount = 0; try { #region Plugin Processing if (Plugins != null) { for (int i = 0; i < Plugins.Count; i++) { // find a valid plugin for this file type if (Plugins[i].Enabled && Plugins[i].Plugin.IsAvailable) { // detect if plugin supports extension bool isFound = Plugins[i].Plugin.IsFileSupported(file); // if extension not supported try another plugin if (!isFound) continue; Exception pluginEx = null; // load plugin and perform grep if (Plugins[i].Plugin.Load()) { OnSearchingFileByPlugin(Plugins[i].Plugin.Name); match = Plugins[i].Plugin.Grep(file, SearchSpec, ref pluginEx); } else { OnSearchError(file, new Exception(string.Format("Plugin {0} failed to load.", Plugins[i].Plugin.Name))); } Plugins[i].Plugin.Unload(); // if the plugin processed successfully if (pluginEx == null) { // check for a hit if (match != null) { match.FromPlugin = true; // only perform is not using negation if (!SearchSpec.UseNegation) { if (DoesPassHitCountCheck(match)) { match.Index = MatchResults.Count; MatchResults.Add(match); OnFileHit(file, match.Index); if (SearchSpec.ReturnOnlyFileNames) match.SetHitCount(); OnLineHit(match, match.Index); } } } else if (SearchSpec.UseNegation) { // no hit but using negation so create one match = new MatchResult(file) { Index = MatchResults.Count, FromPlugin = true }; MatchResults.Add(match); OnFileHit(file, match.Index); } } else { // the plugin had an error OnSearchError(file, pluginEx); } return; } } } #endregion // open stream to file to use in encoding detection if enabled and in grep logic _stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); #region Encoding Detection string usedEncoder = string.Empty; System.Text.Encoding encoding = null; // // User specified file encoding // FileEncoding fileEncoding = SearchSpec.FileEncodings != null && SearchSpec.FileEncodings.Count > 0 ? (from f in SearchSpec.FileEncodings where f.FilePath.Equals(file.FullName, StringComparison.InvariantCultureIgnoreCase) && f.Enabled select f).ToList().FirstOrDefault() : null; if (fileEncoding != null) { usedEncoder = "User"; encoding = fileEncoding.Encoding; } else { // // Detect file encoding if enabled // if (SearchSpec.EncodingDetectionOptions.DetectFileEncoding) { // encoding cache check var key = file.FullName; if (SearchSpec.EncodingDetectionOptions.UseEncodingCache && EncodingCache.Instance.ContainsKey(key)) { var value = EncodingCache.Instance.GetItem(key); usedEncoder = value.DetectorName; encoding = System.Text.Encoding.GetEncoding(value.CodePage); } else { byte[] sampleBytes; //Check if can read first try { int sampleSize = EncodingOptions.GetSampleSizeByPerformance(SearchSpec.EncodingDetectionOptions != null ? SearchSpec.EncodingDetectionOptions.PerformanceSetting : EncodingOptions.Performance.Default); sampleBytes = EncodingTools.ReadFileContentSample(_stream, sampleSize); } catch (Exception ex) { // can't read file for sample bytes OnSearchError(file, ex); return; } // detect encoding based on user set performance level that determines what detectors are used encoding = EncodingDetector.Detect(sampleBytes, out usedEncoder, EncodingOptions.GetEncodingDetectorOptionsByPerformance(SearchSpec.EncodingDetectionOptions != null ? SearchSpec.EncodingDetectionOptions.PerformanceSetting : EncodingOptions.Performance.Default), System.Text.Encoding.Default); // add to cache if enabled if (encoding != null && SearchSpec.EncodingDetectionOptions.UseEncodingCache) { var value = new EncodingCacheItem() { CodePage = encoding.CodePage, DetectorName = usedEncoder }; EncodingCache.Instance.SetItem(key, value); } } } else { // Use original encoding method before detect encoding option availalbe usedEncoder = "Default"; encoding = System.Text.Encoding.Default; } } if (encoding == null) { // Could not detect file encoding OnSearchError(file, new Exception("Could not detect file encoding.")); return; } OnFileEncodingDetected(file, encoding, usedEncoder); // process all encoding detectors and display results to output window //var values = EncodingDetector.DetectAll(sampleBytes); //if (values.Count > 0) //{ // System.Diagnostics.Debug.WriteLine(string.Format("File: {0}", file.FullName)); // foreach (var value in values) // { // System.Diagnostics.Debug.WriteLine(string.Format("Encoding: {0} ({1})", value.Encoding != null ? value.Encoding.EncodingName : "None", value.Option.ToString())); // } // System.Diagnostics.Debug.WriteLine(Environment.NewLine); //} #endregion // could have read some data for the encoding check, seek back to start of file if (_stream.CanSeek) { _stream.Seek(0, SeekOrigin.Begin); } _reader = new StreamReader(_stream, encoding); _maxContextLines = SearchSpec.ContextLines + 1; do { string textLine = _reader.ReadLine(); if (textLine == null) break; else { _lineNumber += 1; int _posInStr = -1; if (SearchSpec.UseRegularExpressions) { if (textLine.Length > 0) { string pattern = string.Format("{0}{1}{0}", SearchSpec.UseWholeWordMatching ? "\\b" : string.Empty, SearchSpec.SearchText); RegexOptions options = SearchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase; _regularExp = new Regex(pattern, options); _regularExpCol = _regularExp.Matches(textLine); if (_regularExpCol.Count > 0) { if (SearchSpec.UseNegation) { _hitOccurred = true; } _posInStr = 1; } } } else { // If we are looking for whole worlds only, perform the check. if (SearchSpec.UseWholeWordMatching) { _regularExp = new Regex("\\b" + Regex.Escape(SearchSpec.SearchText) + "\\b", SearchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase); // if match is found, also check against our internal line hit count method to be sure they are in sync Match mtc = _regularExp.Match(textLine); if (mtc != null && mtc.Success && RetrieveLineMatches(textLine, SearchSpec).Count > 0) { if (SearchSpec.UseNegation) { _hitOccurred = true; } _posInStr = mtc.Index; } } else { _posInStr = textLine.IndexOf(SearchSpec.SearchText, SearchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); if (SearchSpec.UseNegation && _posInStr > -1) { _hitOccurred = true; } } } //******************************************* // We found an occurrence of our search text. //******************************************* if (_posInStr > -1) { //since we have a hit, check to see if negation is checked if (SearchSpec.UseNegation) break; // create new hit and add to collection if (match == null) { match = new MatchResult(file) { Index = MatchResults.Count, DetectedEncoding = encoding }; MatchResults.Add(match); } // don't show until passes count check if (!_fileNameDisplayed && DoesPassHitCountCheck(match)) { OnFileHit(file, match.Index); _fileNameDisplayed = true; } // If we are only showing filenames, go to the next file. if (SearchSpec.ReturnOnlyFileNames) { if (!_fileNameDisplayed) { OnFileHit(file, match.Index); _fileNameDisplayed = true; } //notify that at least 1 hit is in file match.SetHitCount(); OnLineHit(match, match.Index); break; } // Display context lines if applicable. if (SearchSpec.ContextLines > 0 && _lastHit <= 0) { if (match.Matches.Count > 0 && _lastHit < -_maxContextLines) { // Insert a blank space before the context lines. var matchLine = new MatchResultLine() { Line = string.Empty, LineNumber = -1 }; match.Matches.Add(matchLine); int _pos = match.Matches.Count - 1; if (DoesPassHitCountCheck(match)) { OnLineHit(match, _pos); } } // Display preceding n context lines before the hit. int tempContextLines = SearchSpec.ContextLines; // But only output the context lines which are not part of the previous context if(_lastHit >= -_maxContextLines) { tempContextLines = -_lastHit; } // Roll back the context index to get the first context line that needs to be displayed _contextIndex = _contextIndex - tempContextLines; if(_contextIndex < 0) { _contextIndex += _maxContextLines; } for (int tempPosInStr = tempContextLines; tempPosInStr >= 1; tempPosInStr--) { _contextIndex = _contextIndex + 1; if (_contextIndex >= _maxContextLines) _contextIndex = 0; // If there is a match in the first one or two lines, // the entire preceeding context may not be available. if (_lineNumber > tempPosInStr) { // Add the context line. var matchLine = new MatchResultLine() { Line = _context[_contextIndex], LineNumber = _lineNumber - tempPosInStr }; match.Matches.Add(matchLine); int _pos = match.Matches.Count - 1; if (DoesPassHitCountCheck(match)) { OnLineHit(match, _pos); } } } } _lastHit = SearchSpec.ContextLines; // // Add the actual "hit". // var matchLineFound = new MatchResultLine() { Line = textLine, LineNumber = _lineNumber, HasMatch = true }; if (SearchSpec.UseRegularExpressions) { _posInStr = _regularExpCol[0].Index; match.SetHitCount(_regularExpCol.Count); foreach (Match regExMatch in _regularExpCol) { matchLineFound.Matches.Add(new MatchResultLineMatch(regExMatch.Index, regExMatch.Length)); } } else { var lineMatches = RetrieveLineMatches(textLine, SearchSpec); match.SetHitCount(lineMatches.Count); matchLineFound.Matches = lineMatches; } matchLineFound.ColumnNumber = _posInStr + 1; match.Matches.Add(matchLineFound); int _index = match.Matches.Count - 1; if (DoesPassHitCountCheck(match)) { OnLineHit(match, _index); } } else if (SearchSpec.ContextLines > 0) { if(_lastHit > 0) { //*************************************************** // We didn't find a hit, but since lastHit is > 0, we // need to display this context line. //*************************************************** var matchLine = new MatchResultLine() { Line = textLine, LineNumber = _lineNumber }; match.Matches.Add(matchLine); int _index = match.Matches.Count - 1; if (DoesPassHitCountCheck(match)) { OnLineHit(match, _index); } } if(_lastHit >= -_maxContextLines) { //***************************************************** // We continue keeping track of the number of potential // context lines since the last displayed context line // until we pass (-_maxContextLines). //***************************************************** _lastHit -= 1; } } // Found a hit or not. // If we are showing context lines, keep the last n+1 lines. if (SearchSpec.ContextLines > 0) { _contextIndex += 1; if (_contextIndex >= _maxContextLines) _contextIndex = 0; _context[_contextIndex] = textLine; } } } while (true); // send event file/line hit if we haven't yet but it should be if (!_fileNameDisplayed && match != null && DoesPassHitCountCheck(match)) { // need to display it OnFileHit(file, match.Index); OnLineHit(match, match.Index); } // send event for file filtered if it fails the file hit count filter if (!SearchSpec.UseNegation && !SearchSpec.ReturnOnlyFileNames && match != null && !DoesPassHitCountCheck(match)) { // remove from grep collection only if // not negation // not filenames only // actually have a hit // doesn't pass the hit count filter MatchResults.RemoveAt(MatchResults.Count - 1); string filterValue = match.HitCount.ToString(); FilterItem filterItem = new FilterItem(new FilterType(FilterType.Categories.File, FilterType.SubCategories.MinimumHitCount), userFilterCount.ToString(), FilterType.ValueOptions.None, false, true); OnFileFiltered(file, filterItem, filterValue); } // // Check for no hits through out the file // if (SearchSpec.UseNegation && _hitOccurred == false) { //add the file to the hit list if (!_fileNameDisplayed) { match = new MatchResult(file) { Index = MatchResults.Count, DetectedEncoding = encoding }; MatchResults.Add(match); OnFileHit(file, match.Index); } } } finally { if (_reader != null) _reader.Close(); if (_stream != null) _stream.Close(); } }
/// <summary> /// Search the given file. /// </summary> /// <param name="SourceFile">FileInfo object to be searched</param> private void SearchFile(FileInfo SourceFile) { try { // skip any files that are filtered out FilterItem filterItem = null; string filterValue = string.Empty; if (ShouldFilterOut(SourceFile, FileFilterSpec, out filterItem, out filterValue)) { OnFileFiltered(SourceFile, filterItem, filterValue); } else if (string.IsNullOrEmpty(SearchSpec.SearchText)) { // return a 'file hit' if the search text is empty var match = new MatchResult(SourceFile) { Index = MatchResults.Count }; var matchLine = new MatchResultLine(); match.Matches.Add(matchLine); MatchResults.Add(match); OnFileHit(SourceFile, match.Index); } else { SearchFileContents(SourceFile); } } catch (ThreadAbortException) { UnloadPlugins(); } catch (Exception ex) { OnSearchError(SourceFile, ex); } }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> /// <history> /// [Curtis_Beard] 07/28/2006 Created /// [Curtis_Beard] 05/25/2007 ADD: support for Exception object /// [Curtis_Beard] 03/31/2015 CHG: rework Grep/Matches /// </history> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; if (IsAvailable && IsUsable) { try { if (file.Exists) { //const int MARGINSIZE = 4; int count = 0; MatchResult match = null; int prevLine = 0; int prevPage = 0; //string _spacer = new string(' ', MARGINSIZE); //string _contextSpacer = string.Empty; //if (searchSpec.ContextLines > 0) //{ // _contextSpacer = new string(' ', MARGINSIZE); // _spacer = _contextSpacer.Substring(_contextSpacer.Length - MARGINSIZE - 2) + "> "; //} //else // _spacer = new string(' ', MARGINSIZE); // Open a given Word document as readonly // Note: Word 2003+ requires write mode since reading mode doesn't allow use of home/end keys to select text) object appversion = __WordApplication.GetType().InvokeMember("Version", BindingFlags.GetProperty, null, __WordApplication, null); double version = 0; double.TryParse(appversion.ToString(), out version); bool useReadOnly = version >= 12.00 ? false : true; object wordDocument = OpenDocument(file.FullName, useReadOnly); // Get Selection Property __WordSelection = __WordApplication.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, __WordApplication, null); // create range and find objects object range = GetProperty(wordDocument, "Content"); object find = GetProperty(range, "Find"); // setup find RunRoutine(find, "ClearFormatting", null); SetProperty(find, "Forward", true); SetProperty(find, "Text", searchSpec.SearchText); SetProperty(find, "MatchWholeWord", searchSpec.UseWholeWordMatching); SetProperty(find, "MatchCase", searchSpec.UseCaseSensitivity); // start find FindExecute(find); // keep finding text while ((bool)GetProperty(find, "Found") == true) { count += 1; if (count == 1) { // create hit object match = new MatchResult(file); } // since a hit was found and only displaying file names, quickly exit if (searchSpec.ReturnOnlyFileNames) { break; } // retrieve find information int start = (int)GetProperty(range, "Start"); int colNum = (int)Information(range, WdInformation.wdFirstCharacterColumnNumber); int lineNum = (int)Information(range, WdInformation.wdFirstCharacterLineNumber); int pageNum = (int)Information(range, WdInformation.wdActiveEndPageNumber); string line = GetFindTextLine(start); // don't add a hit if on same line if (!(prevLine == lineNum && prevPage == pageNum)) { // check for line numbers //if (searchSpec.IncludeLineNumbers) //{ // // setup line header // _spacer = "(" + string.Format("{0},{1}", lineNum, pageNum); // if (_spacer.Length <= 5) // { // _spacer = _spacer + new string(' ', 6 - _spacer.Length); // } // _spacer = _spacer + ") "; // //_contextSpacer = "(" + new string(' ', _spacer.Length - 3) + ") "; //} // remove any odd characters from the text line = RemoveSpecialCharacters(line); // add context lines before // if (__contextLines > 0){ // For i As int = __contextLines To 1 Step -1 // SetProperty(__WordSelection, "Start", start) // SelectionMoveUp(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum - i, 1) // End If // Next // End If // add line MatchResultLine matchLine = new MatchResultLine() { HasMatch = true, ColumnNumber = colNum, LineNumber = lineNum, Line = line }; var lineMatches = libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLine.Matches = lineMatches; match.Matches.Add(matchLine); //match.Add(_spacer, line, lineNum, colNum); // add context lines after // if (__contextLines > 0){ // For i As int = 1 To __contextLines // SetProperty(__WordSelection, "Start", start) // SelectionMoveDown(WdUnits.wdLine, i, WdMovementType.wdMove) // Dim cxt As string = GetFindTextLine() // cxt = RemoveSpecialCharacters(cxt) // if (Not HitExists(cxt, hit)){ // hit.Add(_contextSpacer & cxt & NEW_LINE, lineNum + i, 1) // End If // Next // End If } //match.SetHitCount(); prevLine = lineNum; prevPage = pageNum; // find again FindExecute(find); } ReleaseSelection(); CloseDocument(wordDocument); return(match); } else { string msg = string.Format("File does not exist: {0}", file.FullName); ex = new Exception(msg); Trace(msg); } } catch (Exception mainEx) { ex = mainEx; Trace(mainEx.ToString()); } } else { ex = new Exception("Plugin not available or usable."); Trace("Plugin not available or usable."); } return(null); }
/// <summary> /// Searches the given file for the given search text. /// </summary> /// <param name="file">FileInfo object</param> /// <param name="searchSpec">ISearchSpec interface value</param> /// <param name="ex">Exception holder if error occurs</param> /// <returns>Hitobject containing grep results, null if on error</returns> /// <history> /// [Curtis_Beard] 10/17/2012 Created /// [Curtis_Beard] 03/31/2015 CHG: rework Grep/Matches /// </history> public MatchResult Grep(FileInfo file, ISearchSpec searchSpec, ref Exception ex) { // initialize Exception object to null ex = null; MatchResult match = null; if (Parser.IsParseable(file.FullName)) { string fileContent = Parser.Parse(file.FullName); if (!string.IsNullOrEmpty(fileContent)) { string[] lines = fileContent.Split(new char[] { '\n', '\r' }); for (int i = 0; i < lines.Length; i++) { string line = lines[i]; int posInStr = -1; Regex reg = null; MatchCollection regCol = null; if (searchSpec.UseRegularExpressions) { string pattern = string.Format("{0}{1}{0}", searchSpec.UseWholeWordMatching ? "\\b" : string.Empty, searchSpec.SearchText); RegexOptions options = searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase; reg = new Regex(pattern, options); regCol = reg.Matches(line); if (regCol.Count > 0) { posInStr = 1; } } else { // If we are looking for whole worlds only, perform the check. if (searchSpec.UseWholeWordMatching) { reg = new Regex("\\b" + Regex.Escape(searchSpec.SearchText) + "\\b", searchSpec.UseCaseSensitivity ? RegexOptions.None : RegexOptions.IgnoreCase); // if match is found, also check against our internal line hit count method to be sure they are in sync Match mtc = reg.Match(line); if (mtc != null && mtc.Success && libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec).Count > 0) { posInStr = mtc.Index; } } else { posInStr = line.IndexOf(searchSpec.SearchText, searchSpec.UseCaseSensitivity ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase); } } if (posInStr > -1) { if (match == null) { match = new MatchResult(file); // found hit in file so just return if (searchSpec.ReturnOnlyFileNames) { break; } } var matchLineFound = new MatchResultLine() { Line = line, LineNumber = -1, HasMatch = true }; if (searchSpec.UseRegularExpressions) { posInStr = regCol[0].Index; match.SetHitCount(regCol.Count); foreach (Match regExMatch in regCol) { matchLineFound.Matches.Add(new MatchResultLineMatch(regExMatch.Index, regExMatch.Length)); } } else { var lineMatches = libAstroGrep.Grep.RetrieveLineMatches(line, searchSpec); match.SetHitCount(lineMatches.Count); matchLineFound.Matches = lineMatches; } matchLineFound.ColumnNumber = 1; match.Matches.Add(matchLineFound); } } } } return match; }