Example #1
0
		void Process(string file, bool printFileName, Dictionary<ColoredMessage, CaptureResult> ctxGroups = null)
		{
			var output = new ColoredMessage();

			var body = ReadAllText(file, out var encoding);

			var matchLines = new SortedDictionary<int, Line>();

			var replaced = body;
			foreach (var regex in _regexes)
			{
				var matches = regex.Matches(body);

				// var currentlnStart = -2; // initially unknown
				foreach (Match match in matches)
				{
					if (match.Length == 0)
					{
						continue; // ignore zero-length matches and prevent index out of range when index >= length (zero length match at the end of a string)
					}
					// find the start of the line
					var lineStart = body.LastIndexOf('\n', match.Index);
					lineStart++;
					if (!matchLines.TryGetValue(lineStart, out var line))
					{
						matchLines[lineStart] = line = new Line
						{
							Start = lineStart,
						};
					}

					line.Matches.Add(match.Index, new LineMatch(regex, match));
				}

				if (ReplaceTo != null)
				{
					replaced = regex.Replace(replaced, ReplaceTo);
					// var rr = regex.ReplaceBreakout(replaced, ReplaceTo);
				}

			}

			if (ctxGroups == null && printFileName && matchLines.Any())
			{
				PrintFileName(file);
			}

			if (!OutputControlOptions.FilesWithMatches)
			{
				// fill context lines
				if (ContextCaptureOptions.ContextAround != 0
				    || ContextCaptureOptions.Before != 0
				    || ContextCaptureOptions.After != 0)
				{
					foreach (var line in matchLines.Values.ToArray())
					{
						var prev = line.Start;
						var before = Math.Max(ContextCaptureOptions.Before, ContextCaptureOptions.ContextAround);
						for (; before > 0; before--)
						{
							if (prev >= 2)
							{
								prev = body.LastIndexOf('\n', prev - 2);
								prev++;
								if (!matchLines.ContainsKey(prev))
								{
									matchLines[prev] = new Line
									{
										Start = prev,
									};
								}
							}
						}
						prev = line.Start;
						var after = Math.Max(ContextCaptureOptions.After, ContextCaptureOptions.ContextAround);
						for (; after > 0; after--)
						{
							prev = body.IndexOf('\n', prev);
							if (prev > 0)
							{
								prev++;
								if (!matchLines.ContainsKey(prev))
								{
									matchLines[prev] = new Line
									{
										Start = prev,
									};
								}
							}
						}
					}
				}

				foreach (var line in matchLines.Values)
				{
					var eol = body.IndexOf('\n', line.Start);
					if (eol == -1)
					{
						eol = body.Length - 1; // jump to last char
					}
					else
					{
						eol--; // jump to char before \n
					}

					// Windows CR LF file
					if (body[eol] == '\r')
					{
						eol--; // jump one more time
					}

					// var str = body.Substring(line.Key, eol);
					void PrintLine(bool replaceMode = false)
					{
						var printPosition = line.Start;
						foreach (var lineMatch in line.Matches.Values)
						{
							var match = lineMatch.Match;

							if (match.Index > printPosition)
							{
								output.Write(ConsoleColor.Gray,
									body.Substring(printPosition, match.Index - printPosition));
							}

							if (!replaceMode)
							{
								output.Write(ConsoleColor.Red, match.Value);
							}
							else
							{
								output.Write(ConsoleColor.Green,
									GetReplacementString(lineMatch.Regex, match, body, ReplaceTo));
							}

							printPosition = match.Index + match.Length;
						}

						var len = eol + 1 - printPosition;
						if (len >= 0 && printPosition < body.Length && (len - printPosition) < body.Length)
						{
							output.Write(ConsoleColor.Gray, body.Substring(printPosition, len) + Environment.NewLine);
						}
						else
						{
							output.Write(null, Environment.NewLine);
						}
					}

					PrintLine();
					if (ReplaceTo != null)
					{
						PrintLine(true);
					}
				}
			}

			if (Save && matchLines.Any() && body != replaced)
			{
				// open existing file for replace!
				using var fileStream = new FileStream(file,
					FileMode.Open,
					FileAccess.Write,
					FileShare.Read,
					FileBufferSize,
					FileOptions.SequentialScan);

				using var sw = new StreamWriter(fileStream, encoding);
				sw.Write(replaced);
				sw.Flush();
				fileStream.SetLength(fileStream.Position); // truncate!
			}

			if (ctxGroups != null)
			{
				// context grouping... will print later
				if (output.Parts.Count > 0)
				{
					if (!ctxGroups.TryGetValue(output, out var capture))
					{
						ctxGroups[output] = capture = new CaptureResult();
					}
					capture.FileNames.Add(file);
				}
			}
			else
			{
				// no context grouping, print directly now
				if (!OutputControlOptions.FilesWithMatches)
				{
					output.ToConsole();
				}
			}
		}