unit UWriter; {$mode objfpc}{$H+} interface uses Classes, SysUtils, UFilter, Math, crt, fgl; type TWriter = class public procedure WriteContent(AContent: String; AFilters: TFilterList; AGroupRanges: TGroupRanges); virtual; abstract; end; TWriterList = specialize TFPGObjectList; { TConsoleWriter } TConsoleWriter = class(TWriter) public procedure WriteContent(AContent: String; AFilters: TFilterList; AGroupRanges: TGroupRanges); override; end; implementation { TConsoleWriter } procedure TConsoleWriter.WriteContent(AContent: String; AFilters: TFilterList; AGroupRanges: TGroupRanges); var i: Integer; matchPos, offset, lastPos: Integer; highlights: THighlights; highlight: THighlight; group: Byte; begin highlights := THighlights.Create; offset := 0; lastPos := 1; for i := 0 to AFilters.Count - 1 do begin if AFilters[i].Expression.Exec(AContent) then begin repeat // We need these values anyway. matchPos := AFilters[i].Expression.MatchPos[0]; offset := AFilters[i].Expression.MatchLen[0]; group := AFilters[i].Group; if group < Length(AGroupRanges) then begin if (matchPos + offset < AGroupRanges[group].StartIdx) or (matchPos > AGroupRanges[group].EndIdx) then continue; //Pointless; nothing we can do here highlight.Start := Max(AGroupRanges[group].StartIdx, matchPos); highlight.Length := Min(AGroupRanges[group].EndIdx - highlight.Start, highlight.Start + offset - matchPos); {$ifdef debugmatches} writeln(' Highlight: ', highlight.Start, ', ', highlight.Length); writeln(' MatchPos: ', matchPos, ', StartIdx: ', AGroupRanges[group].StartIdx); writeln(' Offset: ', offset, ', EndIdx: ', AGroupRanges[group].EndIdx); {$endif} end else begin highlight.Start := matchPos; highlight.Length := offset; end; highlight.FGColor := AFilters[i].FGColor; highlight.BGColor := AFilters[i].BGColor; highlights.Add(highlight); until not AFilters[i].Expression.ExecNext; end; end; highlights.Sort(@CompareHighlights); // Sanitize highlights for i := 0 to highlights.Count - 2 do begin if (highlights[i].Start + highlights[i].Length) > highlights[i+1].Start then begin highlight := highlights[i]; highlight.Length := highlights[i+1].Start - highlights[i].Start; highlights[i] := highlight; end; end; for highlight in highlights do begin matchPos := highlight.Start; offset := highlight.Length; write(Copy(AContent, lastPos, matchPos - lastPos)); if highlight.FGColor < $FF then TextColor(highlight.FGColor); if highlight.BGColor < $FF then TextBackground(highlight.BGColor); write(Copy(AContent, matchPos, offset)); NormVideo; lastPos := matchPos + offset; end; writeln(Copy(AContent, lastPos, Length(AContent))); highlights.Free; end; end.