mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-27 15:40:40 +02:00
IDE: More refactoring for DiffPatch dialog
git-svn-id: trunk@33184 -
This commit is contained in:
parent
ba97db223f
commit
1aa09ddc84
@ -64,13 +64,37 @@ type
|
|||||||
NextLineStart: integer;
|
NextLineStart: integer;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TDiffOutput = class;
|
||||||
|
|
||||||
|
{ TDiffPart }
|
||||||
|
|
||||||
TDiffPart = class
|
TDiffPart = class
|
||||||
|
private
|
||||||
|
fOwner: TDiffOutput;
|
||||||
|
fSource: string;
|
||||||
|
fStartLine: integer; // starting at 1
|
||||||
|
fEndLine: integer; // starting at 1
|
||||||
|
fPosition: TLineExtends;
|
||||||
|
fStream: TStream;
|
||||||
public
|
public
|
||||||
StartLine: integer; // starting at 1
|
constructor Create(aOwner: TDiffOutput; const aSource: string);
|
||||||
EndLine: integer; // starting at 1
|
|
||||||
Position: TLineExtends;
|
|
||||||
Stream: TStream;
|
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
procedure Init(StartExt: TLineExtends);
|
||||||
|
procedure Write(const HeaderPrefix, HeaderSuffix: string);
|
||||||
|
procedure Write2(const StartExt, EndExt: TLineExtends;
|
||||||
|
OtherPartHasChangedLines: boolean; CharForInsertDeletion: char);
|
||||||
|
procedure WriteLinesOfText(aStream: TStream; const aPrefix: string;
|
||||||
|
const aStartLine: TLineExtends; aEndPos: integer);
|
||||||
|
function LineExtendsToStr(const LineExtends: TLineExtends): string;
|
||||||
|
procedure GetLineExtends(LineStart: integer; var LineEnd, NextLineStart: integer);
|
||||||
|
procedure GetLineExtends(var LineExtends: TLineExtends);
|
||||||
|
procedure GetPrevLineExtends(LineStart: integer; var PrevLineStart, PrevLineEnd: integer);
|
||||||
|
procedure GetPrevLineExtends(var LineExtends: TLineExtends);
|
||||||
|
function CountLineEnds(StartPos, EndPos: integer): integer;
|
||||||
|
function CountLinesTillEnd(StartPos: integer): integer;
|
||||||
|
function IsEmptyLine(LineStart, LineEnd: integer): boolean;
|
||||||
|
procedure GetNextLineExtends(var LineStart, LineEnd, NextLineStart, LineNumber: integer);
|
||||||
|
procedure GetNextLineExtends(var LineExtends: TLineExtends);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TDiffOutput }
|
{ TDiffOutput }
|
||||||
@ -88,23 +112,16 @@ type
|
|||||||
function LinesAreEqual(Line1Start, Line1End, NextLine1Start: integer;
|
function LinesAreEqual(Line1Start, Line1End, NextLine1Start: integer;
|
||||||
Line2Start, Line2End, NextLine2Start: integer): boolean;
|
Line2Start, Line2End, NextLine2Start: integer): boolean;
|
||||||
function LinesAreEqual(const Line1Extends, Line2Extends: TLineExtends): boolean;
|
function LinesAreEqual(const Line1Extends, Line2Extends: TLineExtends): boolean;
|
||||||
procedure GetNextLineExtends(const s: string;
|
|
||||||
var LineStart, LineEnd, NextLineStart, LineNumber: integer);
|
|
||||||
procedure GetNextLineExtends(const s: string; var LineExtends: TLineExtends);
|
|
||||||
procedure AddDefaultDiff(const Start1, End1, Start2, End2: TLineExtends);
|
procedure AddDefaultDiff(const Start1, End1, Start2, End2: TLineExtends);
|
||||||
procedure AddContextDiff(const Start1, End1, Start2, End2: TLineExtends);
|
procedure AddContextDiff(const Start1, End1, Start2, End2: TLineExtends);
|
||||||
procedure WriteLinesOfText(Stream: TStream; const s, Prefix: string;
|
|
||||||
const StartLine: TLineExtends; EndPos: integer);
|
|
||||||
procedure StartContextBlock(const Start1, Start2: TLineExtends);
|
|
||||||
procedure FinishOldContextBlock;
|
procedure FinishOldContextBlock;
|
||||||
procedure FinishDiff;
|
procedure FinishDiff;
|
||||||
procedure AddRestDiff(const Start1, Start2: TLineExtends);
|
procedure AddRestDiff(const Start1, Start2: TLineExtends);
|
||||||
procedure AddDiff(const Start1, End1, Start2, End2: TLineExtends);
|
procedure AddDiff(const Start1, End1, Start2, End2: TLineExtends);
|
||||||
procedure SaveToString(var s: string);
|
|
||||||
procedure UpdateProgressBar(const Line: TLineExtends);
|
procedure UpdateProgressBar(const Line: TLineExtends);
|
||||||
public
|
public
|
||||||
constructor Create(const AText1, AText2: string;
|
constructor Create(const aText1, aText2: string;
|
||||||
AFlags: TTextDiffFlags; AProgressBar: TProgressBar);
|
aFlags: TTextDiffFlags; aProgressBar: TProgressBar);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
function CreateTextDiff: string;
|
function CreateTextDiff: string;
|
||||||
public
|
public
|
||||||
@ -130,14 +147,6 @@ const
|
|||||||
LineBreak = #10;
|
LineBreak = #10;
|
||||||
ContextLineCount = 3;
|
ContextLineCount = 3;
|
||||||
|
|
||||||
{ TDiffPart }
|
|
||||||
|
|
||||||
destructor TDiffPart.Destroy;
|
|
||||||
begin
|
|
||||||
Stream.Free;
|
|
||||||
inherited Destroy;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
IsSpaceChars: array[char] of boolean;
|
IsSpaceChars: array[char] of boolean;
|
||||||
UpperCaseChars: array[char] of char;
|
UpperCaseChars: array[char] of char;
|
||||||
@ -159,28 +168,144 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function LineExtendsToStr(const LineExtends: TLineExtends;
|
function GotoNextLine(var LineExtends: TLineExtends): boolean;
|
||||||
const s: string): string;
|
begin
|
||||||
|
with LineExtends do begin
|
||||||
|
if LineStart<NextLineStart then begin
|
||||||
|
inc(LineNumber);
|
||||||
|
LineStart:=NextLineStart;
|
||||||
|
Result:=true;
|
||||||
|
end else
|
||||||
|
Result:=false;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure WriteStrToStream(Stream: TStream; const s: string);
|
||||||
|
begin
|
||||||
|
if s='' then exit;
|
||||||
|
Stream.Write(s[1],length(s));
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDiffPart }
|
||||||
|
|
||||||
|
constructor TDiffPart.Create(aOwner: TDiffOutput; const aSource: string);
|
||||||
|
begin
|
||||||
|
fOwner:=aOwner;
|
||||||
|
fSource:=aSource;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TDiffPart.Destroy;
|
||||||
|
begin
|
||||||
|
fStream.Free;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDiffPart.Init(StartExt: TLineExtends);
|
||||||
|
begin
|
||||||
|
if fStream=nil then
|
||||||
|
fStream:=TMemoryStream.Create
|
||||||
|
else
|
||||||
|
fStream.Size:=0;
|
||||||
|
fStartLine:=StartExt.LineNumber-ContextLineCount;
|
||||||
|
if fStartLine<1 then fStartLine:=1;
|
||||||
|
fPosition:=StartExt;
|
||||||
|
while fPosition.LineNumber>fStartLine do
|
||||||
|
GetPrevLineExtends(fPosition);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDiffPart.Write(const HeaderPrefix, HeaderSuffix: string);
|
||||||
|
begin
|
||||||
|
// check if part contains any changed lines
|
||||||
|
if fPosition.LineNumber > fStartLine then begin
|
||||||
|
// part contains changed lines -> append end context
|
||||||
|
while (fPosition.LineNumber <= fEndLine)
|
||||||
|
and (fPosition.LineStart < length(fSource)) do begin
|
||||||
|
WriteLinesOfText(fStream, ' ', fPosition, fPosition.NextLineStart);
|
||||||
|
if not GotoNextLine(fPosition) then
|
||||||
|
break;
|
||||||
|
GetLineExtends(fPosition);
|
||||||
|
end;
|
||||||
|
end else begin
|
||||||
|
// part does not contain changed lines -> skip
|
||||||
|
end;
|
||||||
|
fStream.Position:=0;
|
||||||
|
// write part
|
||||||
|
WriteStrToStream(fOwner.fDiffStream, HeaderPrefix +
|
||||||
|
IntToStr(fStartLine) + ',' + IntToStr(fEndLine) + HeaderSuffix + LineBreak);
|
||||||
|
if fStream.Size<>0 then
|
||||||
|
fOwner.fDiffStream.CopyFrom(fStream, fStream.Size);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDiffPart.Write2(const StartExt, EndExt: TLineExtends;
|
||||||
|
OtherPartHasChangedLines: boolean; CharForInsertDeletion: char);
|
||||||
|
begin
|
||||||
|
// check if there are changed lines
|
||||||
|
if StartExt.LineStart < EndExt.LineStart then begin
|
||||||
|
// write lines
|
||||||
|
while fPosition.LineStart < EndExt.LineStart do begin
|
||||||
|
if fPosition.LineStart < StartExt.LineStart then
|
||||||
|
// this is an unchanged line in front of the changed lines
|
||||||
|
WriteStrToStream(fStream, ' ')
|
||||||
|
else begin
|
||||||
|
// this is a changed line
|
||||||
|
if OtherPartHasChangedLines then
|
||||||
|
WriteStrToStream(fStream, '! ')
|
||||||
|
else
|
||||||
|
WriteStrToStream(fStream, CharForInsertDeletion+' ');
|
||||||
|
end;
|
||||||
|
if fPosition.LineStart <> fPosition.NextLineStart then
|
||||||
|
fStream.Write(fSource[fPosition.LineStart], fPosition.NextLineStart-fPosition.LineStart);
|
||||||
|
if not GotoNextLine(fPosition) then
|
||||||
|
break;
|
||||||
|
GetLineExtends(fPosition);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDiffPart.WriteLinesOfText(aStream: TStream;
|
||||||
|
const aPrefix: string; const aStartLine: TLineExtends; aEndPos: integer);
|
||||||
|
{ Write all lines in front of EndLine, starting with StartLine }
|
||||||
|
var
|
||||||
|
Line: TLineExtends;
|
||||||
|
begin
|
||||||
|
Line:=aStartLine;
|
||||||
|
while (Line.LineStart<aEndPos) do begin
|
||||||
|
WriteStrToStream(aStream,aPrefix);
|
||||||
|
if (Line.LineEnd>Line.LineStart) then
|
||||||
|
aStream.Write(fSource[Line.LineStart],Line.LineEnd-Line.LineStart);
|
||||||
|
if (Line.NextLineStart>Line.LineEnd) then
|
||||||
|
aStream.Write(fSource[Line.LineEnd],Line.NextLineStart-Line.LineEnd)
|
||||||
|
else begin
|
||||||
|
WriteStrToStream(aStream,LineBreak);
|
||||||
|
WriteStrToStream(aStream,'\ No newline at end');
|
||||||
|
WriteStrToStream(aStream,LineBreak);
|
||||||
|
end;
|
||||||
|
if not GotoNextLine(Line) then break;
|
||||||
|
GetLineExtends(Line);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TDiffPart.LineExtendsToStr(const LineExtends: TLineExtends): string;
|
||||||
begin
|
begin
|
||||||
with LineExtends do
|
with LineExtends do
|
||||||
Result:='(Start='+IntToStr(LineStart)+' End='+IntToStr(LineEnd)
|
Result:='(Start='+IntToStr(LineStart)+' End='+IntToStr(LineEnd)
|
||||||
+' Next='+IntToStr(NextLineStart)+' Number='+IntToStr(LineNumber)
|
+' Next='+IntToStr(NextLineStart)+' Number='+IntToStr(LineNumber)
|
||||||
+' Text="'+TextToLine(copy(s,LineStart,NextLineStart-LineStart))+'")';
|
+' Text="'+TextToLine(copy(fSource,LineStart,NextLineStart-LineStart))+'")';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure GetLineExtends(const s: string; LineStart: integer;
|
procedure TDiffPart.GetLineExtends(LineStart: integer; var LineEnd, NextLineStart: integer);
|
||||||
var LineEnd, NextLineStart: integer);
|
var
|
||||||
var Len: integer;
|
Len: integer;
|
||||||
begin
|
begin
|
||||||
Len:=length(s);
|
Len:=length(fSource);
|
||||||
LineEnd:=LineStart;
|
LineEnd:=LineStart;
|
||||||
while (LineEnd<=Len) do begin
|
while LineEnd<=Len do begin
|
||||||
if (not (s[LineEnd] in [#10,#13])) then begin
|
if (not (fSource[LineEnd] in [#10,#13])) then begin
|
||||||
inc(LineEnd);
|
inc(LineEnd);
|
||||||
end else begin
|
end else begin
|
||||||
NextLineStart:=LineEnd+1;
|
NextLineStart:=LineEnd+1;
|
||||||
if (NextLineStart<=Len) and (s[NextLineStart] in [#10,#13])
|
if (NextLineStart<=Len) and (fSource[NextLineStart] in [#10,#13])
|
||||||
and (s[LineEnd]<>s[NextLineStart]) then
|
and (fSource[LineEnd]<>fSource[NextLineStart]) then
|
||||||
inc(NextLineStart);
|
inc(NextLineStart);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -189,74 +314,72 @@ begin
|
|||||||
NextLineStart:=LineEnd;
|
NextLineStart:=LineEnd;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure GetLineExtends(const s: string; var LineExtends: TLineExtends);
|
procedure TDiffPart.GetLineExtends(var LineExtends: TLineExtends);
|
||||||
begin
|
begin
|
||||||
GetLineExtends(s,LineExtends.LineStart,LineExtends.LineEnd,
|
GetLineExtends(LineExtends.LineStart, LineExtends.LineEnd, LineExtends.NextLineStart);
|
||||||
LineExtends.NextLineStart);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure GetPrevLineExtends(const s: string; LineStart: integer;
|
procedure TDiffPart.GetPrevLineExtends(LineStart: integer;
|
||||||
var PrevLineStart, PrevLineEnd: integer);
|
var PrevLineStart, PrevLineEnd: integer);
|
||||||
begin
|
begin
|
||||||
// read line end
|
// read line end
|
||||||
PrevLineEnd:=LineStart;
|
PrevLineEnd:=LineStart;
|
||||||
if (PrevLineEnd>1) and (s[PrevLineEnd-1] in [#10,#13]) then
|
if (PrevLineEnd>1) and (fSource[PrevLineEnd-1] in [#10,#13]) then
|
||||||
dec(PrevLineEnd);
|
dec(PrevLineEnd);
|
||||||
if (PrevLineEnd>1) and (s[PrevLineEnd-1] in [#10,#13])
|
if (PrevLineEnd>1) and (fSource[PrevLineEnd-1] in [#10,#13])
|
||||||
and (s[PrevLineEnd]<>s[PrevLineEnd-1]) then
|
and (fSource[PrevLineEnd]<>fSource[PrevLineEnd-1]) then
|
||||||
dec(PrevLineEnd);
|
dec(PrevLineEnd);
|
||||||
// read line content
|
// read line content
|
||||||
PrevLineStart:=PrevLineEnd;
|
PrevLineStart:=PrevLineEnd;
|
||||||
while (PrevLineStart>1) and (not (s[PrevLineStart-1] in [#10,#13])) do
|
while (PrevLineStart>1) and (not (fSource[PrevLineStart-1] in [#10,#13])) do
|
||||||
dec(PrevLineStart);
|
dec(PrevLineStart);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure GetPrevLineExtends(const s: string; var LineExtends: TLineExtends);
|
procedure TDiffPart.GetPrevLineExtends(var LineExtends: TLineExtends);
|
||||||
begin
|
begin
|
||||||
if LineExtends.LineStart<1 then exit;
|
if LineExtends.LineStart<1 then exit;
|
||||||
LineExtends.NextLineStart:=LineExtends.LineStart;
|
LineExtends.NextLineStart:=LineExtends.LineStart;
|
||||||
GetPrevLineExtends(s,LineExtends.LineStart,LineExtends.LineStart,
|
GetPrevLineExtends(LineExtends.LineStart,LineExtends.LineStart,LineExtends.LineEnd);
|
||||||
LineExtends.LineEnd);
|
|
||||||
dec(LineExtends.LineNumber);
|
dec(LineExtends.LineNumber);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CountLineEnds(const s: string; StartPos, EndPos: integer): integer;
|
function TDiffPart.CountLineEnds(StartPos, EndPos: integer): integer;
|
||||||
begin
|
begin
|
||||||
Result:=0;
|
Result:=0;
|
||||||
while (StartPos<EndPos) do begin
|
while (StartPos<EndPos) do begin
|
||||||
if not (s[StartPos] in [#10,#13]) then begin
|
if not (fSource[StartPos] in [#10,#13]) then begin
|
||||||
inc(StartPos);
|
inc(StartPos);
|
||||||
end else begin
|
end else begin
|
||||||
inc(Result);
|
inc(Result);
|
||||||
inc(StartPos);
|
inc(StartPos);
|
||||||
if (StartPos<EndPos) and (s[StartPos] in [#10,#13])
|
if (StartPos<EndPos) and (fSource[StartPos] in [#10,#13])
|
||||||
and (s[StartPos]<>s[StartPos-1]) then
|
and (fSource[StartPos]<>fSource[StartPos-1]) then
|
||||||
inc(StartPos);
|
inc(StartPos);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function CountLinesTillEnd(const s: string; StartPos: integer): integer;
|
function TDiffPart.CountLinesTillEnd(StartPos: integer): integer;
|
||||||
var Len: integer;
|
var
|
||||||
|
Len: integer;
|
||||||
begin
|
begin
|
||||||
Len:=length(s);
|
Len:=length(fSource);
|
||||||
Result:=CountLineEnds(s,StartPos,Len+1);
|
Result:=CountLineEnds(StartPos,Len+1);
|
||||||
if (StartPos<=Len) and (not (s[Len] in [#10,#13])) then
|
if (StartPos<=Len) and (not (fSource[Len] in [#10,#13])) then
|
||||||
inc(Result);
|
inc(Result);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function IsEmptyLine(const s: string; LineStart, LineEnd: integer;
|
function TDiffPart.IsEmptyLine(LineStart, LineEnd: integer): boolean;
|
||||||
Flags: TTextDiffFlags): boolean;
|
|
||||||
var
|
var
|
||||||
i: integer;
|
i: integer;
|
||||||
begin
|
begin
|
||||||
if LineStart<=length(s) then begin
|
if LineStart<=length(fSource) then begin
|
||||||
if ([tdfIgnoreSpaceCharAmount,tdfIgnoreSpaceChars,tdfIgnoreHeadingSpaces,
|
if ([tdfIgnoreSpaceCharAmount,tdfIgnoreSpaceChars,tdfIgnoreHeadingSpaces,
|
||||||
tdfIgnoreTrailingSpaces]*Flags)<>[] then
|
tdfIgnoreTrailingSpaces]*fOwner.fFlags)<>[] then
|
||||||
begin
|
begin
|
||||||
Result:=true;
|
Result:=true;
|
||||||
for i:=LineStart to LineEnd-1 do begin
|
for i:=LineStart to LineEnd-1 do begin
|
||||||
if not IsSpaceChars[s[i]] then begin
|
if not IsSpaceChars[fSource[i]] then begin
|
||||||
Result:=false;
|
Result:=false;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -270,18 +393,31 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function GotoNextLine(var LineExtends: TLineExtends): boolean;
|
procedure TDiffPart.GetNextLineExtends(var LineStart, LineEnd, NextLineStart, LineNumber: integer);
|
||||||
|
var
|
||||||
|
Len: integer;
|
||||||
begin
|
begin
|
||||||
with LineExtends do begin
|
Len:=length(fSource);
|
||||||
if LineStart<NextLineStart then begin
|
repeat
|
||||||
inc(LineNumber);
|
GetLineExtends(LineStart,LineEnd,NextLineStart);
|
||||||
LineStart:=NextLineStart;
|
if (LineStart>Len)
|
||||||
Result:=true;
|
or (not (tdfIgnoreEmptyLineChanges in fOwner.fFlags))
|
||||||
end else
|
or (not IsEmptyLine(LineStart,LineEnd)) then
|
||||||
Result:=false;
|
break;
|
||||||
end;
|
LineStart:=NextLineStart;
|
||||||
|
inc(LineNumber);
|
||||||
|
until false;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TDiffPart.GetNextLineExtends(var LineExtends: TLineExtends);
|
||||||
|
begin
|
||||||
|
GetNextLineExtends(LineExtends.LineStart, LineExtends.LineEnd,
|
||||||
|
LineExtends.NextLineStart, LineExtends.LineNumber);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TDiffOutput }
|
||||||
|
|
||||||
function TDiffOutput.LinesAreEqual(
|
function TDiffOutput.LinesAreEqual(
|
||||||
Line1Start, Line1End, NextLine1Start: integer;
|
Line1Start, Line1End, NextLine1Start: integer;
|
||||||
Line2Start, Line2End, NextLine2Start: integer): boolean;
|
Line2Start, Line2End, NextLine2Start: integer): boolean;
|
||||||
@ -407,8 +543,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDiffOutput.LinesAreEqual(
|
function TDiffOutput.LinesAreEqual(const Line1Extends, Line2Extends: TLineExtends): boolean;
|
||||||
const Line1Extends, Line2Extends: TLineExtends): boolean;
|
|
||||||
begin
|
begin
|
||||||
Result:=LinesAreEqual(Line1Extends.LineStart, Line1Extends.LineEnd,
|
Result:=LinesAreEqual(Line1Extends.LineStart, Line1Extends.LineEnd,
|
||||||
Line1Extends.NextLineStart,
|
Line1Extends.NextLineStart,
|
||||||
@ -416,42 +551,6 @@ begin
|
|||||||
Line2Extends.NextLineStart);
|
Line2Extends.NextLineStart);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDiffOutput.GetNextLineExtends(const s: string;
|
|
||||||
var LineStart, LineEnd, NextLineStart, LineNumber: integer);
|
|
||||||
var
|
|
||||||
Len: integer;
|
|
||||||
begin
|
|
||||||
Len:=length(s);
|
|
||||||
repeat
|
|
||||||
GetLineExtends(s,LineStart,LineEnd,NextLineStart);
|
|
||||||
if (LineStart>Len)
|
|
||||||
or (not (tdfIgnoreEmptyLineChanges in fFlags))
|
|
||||||
or (not IsEmptyLine(s,LineStart,LineEnd,fFlags)) then
|
|
||||||
break;
|
|
||||||
LineStart:=NextLineStart;
|
|
||||||
inc(LineNumber);
|
|
||||||
until false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDiffOutput.GetNextLineExtends(const s: string; var LineExtends: TLineExtends);
|
|
||||||
begin
|
|
||||||
GetNextLineExtends(s,LineExtends.LineStart,LineExtends.LineEnd,
|
|
||||||
LineExtends.NextLineStart,LineExtends.LineNumber);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure WriteStrToStream(Stream: TStream; const s: string);
|
|
||||||
begin
|
|
||||||
if s='' then exit;
|
|
||||||
Stream.Write(s[1],length(s));
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure WriteLineToStream(Stream: TStream; const Source: string;
|
|
||||||
const Line: TLineExtends);
|
|
||||||
begin
|
|
||||||
if (Source='') or (Line.LineStart=Line.NextLineStart) then exit;
|
|
||||||
Stream.Write(Source[Line.LineStart],Line.NextLineStart-Line.LineStart);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDiffOutput.FindNextEqualLine(const Start1, Start2: TLineExtends;
|
procedure TDiffOutput.FindNextEqualLine(const Start1, Start2: TLineExtends;
|
||||||
out EqualLine1, EqualLine2: TLineExtends);
|
out EqualLine1, EqualLine2: TLineExtends);
|
||||||
var
|
var
|
||||||
@ -463,43 +562,43 @@ begin
|
|||||||
Cur2:=Start2;
|
Cur2:=Start2;
|
||||||
try
|
try
|
||||||
if LinesAreEqual(Cur1,Cur2)
|
if LinesAreEqual(Cur1,Cur2)
|
||||||
and (not IsEmptyLine(fText1,Cur1.LineStart,Cur1.LineEnd,fFlags)) then
|
and (not fPart1.IsEmptyLine(Cur1.LineStart, Cur1.LineEnd)) then
|
||||||
exit;
|
exit;
|
||||||
repeat
|
repeat
|
||||||
// increase Max1
|
// increase Max1
|
||||||
if GotoNextLine(Max1) then begin
|
if GotoNextLine(Max1) then begin
|
||||||
GetLineExtends(fText1,Max1);
|
fPart1.GetLineExtends(Max1);
|
||||||
// search Max1 Line in fText2
|
// search Max1 Line in fText2
|
||||||
if Max1.LineStart<Max1.NextLineStart then begin
|
if Max1.LineStart<Max1.NextLineStart then begin
|
||||||
Cur1:=Max1;
|
Cur1:=Max1;
|
||||||
Cur2:=Start2;
|
Cur2:=Start2;
|
||||||
repeat
|
repeat
|
||||||
if LinesAreEqual(Cur1,Cur2)
|
if LinesAreEqual(Cur1,Cur2)
|
||||||
and (not IsEmptyLine(fText1,Cur1.LineStart,Cur1.LineEnd,fFlags)) then
|
and (not fPart1.IsEmptyLine(Cur1.LineStart, Cur1.LineEnd)) then
|
||||||
exit;
|
exit;
|
||||||
if Cur2.LineStart>=Max2.LineStart then break;
|
if Cur2.LineStart>=Max2.LineStart then break;
|
||||||
Cur2.LineStart:=Cur2.NextLineStart;
|
Cur2.LineStart:=Cur2.NextLineStart;
|
||||||
inc(Cur2.LineNumber);
|
inc(Cur2.LineNumber);
|
||||||
GetLineExtends(fText2,Cur2);
|
fPart2.GetLineExtends(Cur2);
|
||||||
until false;
|
until false;
|
||||||
end;
|
end;
|
||||||
UpdateProgressBar(Max1);
|
UpdateProgressBar(Max1);
|
||||||
end;
|
end;
|
||||||
// increase Max2
|
// increase Max2
|
||||||
if GotoNextLine(Max2) then begin
|
if GotoNextLine(Max2) then begin
|
||||||
GetLineExtends(fText2,Max2);
|
fPart2.GetLineExtends(Max2);
|
||||||
// search Max2 Line in fText1
|
// search Max2 Line in fText1
|
||||||
if Max2.LineStart<Max2.NextLineStart then begin
|
if Max2.LineStart<Max2.NextLineStart then begin
|
||||||
Cur1:=Start1;
|
Cur1:=Start1;
|
||||||
Cur2:=Max2;
|
Cur2:=Max2;
|
||||||
repeat
|
repeat
|
||||||
if LinesAreEqual(Cur1,Cur2)
|
if LinesAreEqual(Cur1,Cur2)
|
||||||
and (not IsEmptyLine(fText1,Cur1.LineStart,Cur1.LineEnd,fFlags)) then
|
and (not fPart1.IsEmptyLine(Cur1.LineStart,Cur1.LineEnd)) then
|
||||||
exit;
|
exit;
|
||||||
if Cur1.LineStart>=Max1.LineStart then break;
|
if Cur1.LineStart>=Max1.LineStart then break;
|
||||||
Cur1.LineStart:=Cur1.NextLineStart;
|
Cur1.LineStart:=Cur1.NextLineStart;
|
||||||
inc(Cur1.LineNumber);
|
inc(Cur1.LineNumber);
|
||||||
GetLineExtends(fText1,Cur1);
|
fPart1.GetLineExtends(Cur1);
|
||||||
until false;
|
until false;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -513,14 +612,12 @@ begin
|
|||||||
EqualLine1:=Cur1;
|
EqualLine1:=Cur1;
|
||||||
EqualLine2:=Cur2;
|
EqualLine2:=Cur2;
|
||||||
// chomp empty lines at end
|
// chomp empty lines at end
|
||||||
GetPrevLineExtends(fText1,Cur1);
|
fPart1.GetPrevLineExtends(Cur1);
|
||||||
GetPrevLineExtends(fText2,Cur2);
|
fPart2.GetPrevLineExtends(Cur2);
|
||||||
until not LinesAreEqual(Cur1,Cur2);
|
until not LinesAreEqual(Cur1,Cur2);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TDiffOutput }
|
|
||||||
|
|
||||||
function TDiffOutput.CreateTextDiff: string;
|
function TDiffOutput.CreateTextDiff: string;
|
||||||
var
|
var
|
||||||
Line1, Line2, EqualLine1, EqualLine2: TLineExtends;
|
Line1, Line2, EqualLine1, EqualLine2: TLineExtends;
|
||||||
@ -539,9 +636,9 @@ begin
|
|||||||
// search for a difference line ...
|
// search for a difference line ...
|
||||||
repeat
|
repeat
|
||||||
// skip empty lines in fText1 and get line1 extends ...
|
// skip empty lines in fText1 and get line1 extends ...
|
||||||
GetNextLineExtends(fText1,Line1);
|
fPart1.GetNextLineExtends(Line1);
|
||||||
// skip empty lines in fText2 and get line2 extends ...
|
// skip empty lines in fText2 and get line2 extends ...
|
||||||
GetNextLineExtends(fText2,Line2);
|
fPart2.GetNextLineExtends(Line2);
|
||||||
// skip equal lines ...
|
// skip equal lines ...
|
||||||
if (Line1.LineStart<=Len1) and (Line2.LineStart<=Len2) then begin
|
if (Line1.LineStart<=Len1) and (Line2.LineStart<=Len2) then begin
|
||||||
if not LinesAreEqual(Line1,Line2) then
|
if not LinesAreEqual(Line1,Line2) then
|
||||||
@ -577,7 +674,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
SaveToString(Result);
|
FinishDiff;
|
||||||
|
SetLength(Result,fDiffStream.Size);
|
||||||
|
fDiffStream.Position:=0;
|
||||||
|
if Result<>'' then
|
||||||
|
fDiffStream.Read(Result[1],length(Result));
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -588,11 +689,11 @@ begin
|
|||||||
End1.LineStart:=length(fText1)+1;
|
End1.LineStart:=length(fText1)+1;
|
||||||
End1.LineEnd:=End1.LineStart;
|
End1.LineEnd:=End1.LineStart;
|
||||||
End1.NextLineStart:=End1.LineStart;
|
End1.NextLineStart:=End1.LineStart;
|
||||||
End1.LineNumber:=Start1.LineNumber+CountLinesTillEnd(fText1,Start1.LineStart);
|
End1.LineNumber:=Start1.LineNumber+fPart1.CountLinesTillEnd(Start1.LineStart);
|
||||||
End2.LineStart:=length(fText2)+1;
|
End2.LineStart:=length(fText2)+1;
|
||||||
End2.LineEnd:=End2.LineStart;
|
End2.LineEnd:=End2.LineStart;
|
||||||
End2.NextLineStart:=End2.LineStart;
|
End2.NextLineStart:=End2.LineStart;
|
||||||
End2.LineNumber:=Start2.LineNumber+CountLinesTillEnd(fText2,Start2.LineStart);
|
End2.LineNumber:=Start2.LineNumber+fPart2.CountLinesTillEnd(Start2.LineStart);
|
||||||
AddDiff(Start1,End1, Start2,End2);
|
AddDiff(Start1,End1, Start2,End2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -608,15 +709,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDiffOutput.SaveToString(var s: string);
|
|
||||||
begin
|
|
||||||
FinishDiff;
|
|
||||||
SetLength(s,fDiffStream.Size);
|
|
||||||
fDiffStream.Position:=0;
|
|
||||||
if s<>'' then
|
|
||||||
fDiffStream.Read(s[1],length(s));
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDiffOutput.UpdateProgressBar(const Line: TLineExtends);
|
procedure TDiffOutput.UpdateProgressBar(const Line: TLineExtends);
|
||||||
begin
|
begin
|
||||||
if Assigned(fProgressBar) then begin
|
if Assigned(fProgressBar) then begin
|
||||||
@ -625,87 +717,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDiffOutput.WriteLinesOfText(Stream: TStream;
|
|
||||||
const s, Prefix: string;
|
|
||||||
const StartLine: TLineExtends; EndPos: integer);
|
|
||||||
{ Write all lines in front of EndLine, starting with StartLine }
|
|
||||||
var
|
|
||||||
Line: TLineExtends;
|
|
||||||
begin
|
|
||||||
Line:=StartLine;
|
|
||||||
while (Line.LineStart<EndPos) do begin
|
|
||||||
WriteStrToStream(Stream,Prefix);
|
|
||||||
if (Line.LineEnd>Line.LineStart) then
|
|
||||||
Stream.Write(s[Line.LineStart],Line.LineEnd-Line.LineStart);
|
|
||||||
if (Line.NextLineStart>Line.LineEnd) then
|
|
||||||
Stream.Write(s[Line.LineEnd],Line.NextLineStart-Line.LineEnd)
|
|
||||||
else begin
|
|
||||||
WriteStrToStream(Stream,LineBreak);
|
|
||||||
WriteStrToStream(Stream,'\ No newline at end');
|
|
||||||
WriteStrToStream(Stream,LineBreak);
|
|
||||||
end;
|
|
||||||
if not GotoNextLine(Line) then break;
|
|
||||||
GetLineExtends(s,Line);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDiffOutput.StartContextBlock(const Start1, Start2: TLineExtends);
|
|
||||||
|
|
||||||
procedure InitPart(const Part: TDiffPart; const Source: string;
|
|
||||||
StartExt: TLineExtends);
|
|
||||||
begin
|
|
||||||
if Part.Stream=nil then
|
|
||||||
Part.Stream:=TMemoryStream.Create
|
|
||||||
else
|
|
||||||
Part.Stream.Size:=0;
|
|
||||||
Part.StartLine:=StartExt.LineNumber-ContextLineCount;
|
|
||||||
if Part.StartLine<1 then Part.StartLine:=1;
|
|
||||||
Part.Position:=StartExt;
|
|
||||||
while Part.Position.LineNumber>Part.StartLine do
|
|
||||||
GetPrevLineExtends(Source,Part.Position);
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
|
||||||
FinishOldContextBlock;
|
|
||||||
WriteStrToStream(fDiffStream,'***************'+LineBreak);
|
|
||||||
InitPart(fPart1,fText1,Start1);
|
|
||||||
InitPart(fPart2,fText2,Start2);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TDiffOutput.FinishOldContextBlock;
|
procedure TDiffOutput.FinishOldContextBlock;
|
||||||
|
|
||||||
procedure WritePart(const Part: TDiffPart;
|
|
||||||
const Source, HeaderPrefix, HeaderSuffix: string);
|
|
||||||
begin
|
|
||||||
// check if part contains any changed lines
|
|
||||||
if Part.Position.LineNumber>Part.StartLine then begin
|
|
||||||
// part contains changed lines -> append end context
|
|
||||||
while (Part.Position.LineNumber<=Part.EndLine)
|
|
||||||
and (Part.Position.LineStart<length(Source)) do begin
|
|
||||||
WriteLinesOfText(Part.Stream,Source,' ',Part.Position,
|
|
||||||
Part.Position.NextLineStart);
|
|
||||||
if not GotoNextLine(Part.Position) then break;
|
|
||||||
GetLineExtends(Source,Part.Position);
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
// part does not contain changed lines -> skip
|
|
||||||
end;
|
|
||||||
|
|
||||||
Part.Stream.Position:=0;
|
|
||||||
|
|
||||||
// write part
|
|
||||||
WriteStrToStream(fDiffStream,
|
|
||||||
HeaderPrefix
|
|
||||||
+IntToStr(Part.StartLine)+','+IntToStr(Part.EndLine)
|
|
||||||
+HeaderSuffix+LineBreak);
|
|
||||||
if Part.Stream.Size<>0 then
|
|
||||||
fDiffStream.CopyFrom(Part.Stream,Part.Stream.Size);
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if fPart1.Stream<>nil then begin
|
if fPart1.fStream <> nil then begin
|
||||||
WritePart(fPart1,fText1,'*** ',' ****');
|
fPart1.Write('*** ',' ****');
|
||||||
WritePart(fPart2,fText2,'--- ',' ----');
|
fPart2.Write('--- ',' ----');
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -789,12 +805,12 @@ begin
|
|||||||
if DiffStartLine2>DiffEndLine2 then
|
if DiffStartLine2>DiffEndLine2 then
|
||||||
DiffStartLine2:=DiffEndLine2;
|
DiffStartLine2:=DiffEndLine2;
|
||||||
WriteActionLine;
|
WriteActionLine;
|
||||||
WriteLinesOfText(fDiffStream,fText1,'< ',Start1,End1.LineStart);
|
fPart1.WriteLinesOfText(fDiffStream,'< ',Start1,End1.LineStart);
|
||||||
if ActionChar='c' then begin
|
if ActionChar='c' then begin
|
||||||
WriteStrToStream(fDiffStream,'---');
|
WriteStrToStream(fDiffStream,'---');
|
||||||
WriteStrToStream(fDiffStream,LineBreak);
|
WriteStrToStream(fDiffStream,LineBreak);
|
||||||
end;
|
end;
|
||||||
WriteLinesOfText(fDiffStream,fText2,'> ',Start2,End2.LineStart);
|
fPart2.WriteLinesOfText(fDiffStream,'> ',Start2,End2.LineStart);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDiffOutput.AddContextDiff(const Start1, End1, Start2, End2: TLineExtends);
|
procedure TDiffOutput.AddContextDiff(const Start1, End1, Start2, End2: TLineExtends);
|
||||||
@ -819,86 +835,65 @@ procedure TDiffOutput.AddContextDiff(const Start1, End1, Start2, End2: TLineExte
|
|||||||
- If a part contains no changed lines, its lines can be left out
|
- If a part contains no changed lines, its lines can be left out
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure WritePart(Part: TDiffPart; const Source: string;
|
|
||||||
const StartExt, EndExt: TLineExtends; OtherPartHasChangedLines: boolean;
|
|
||||||
CharForInsertDeletion: char);
|
|
||||||
begin
|
|
||||||
// check if there are changed lines
|
|
||||||
if StartExt.LineStart<EndExt.LineStart then begin
|
|
||||||
// write lines
|
|
||||||
while Part.Position.LineStart<EndExt.LineStart do begin
|
|
||||||
if Part.Position.LineStart<StartExt.LineStart then
|
|
||||||
// this is an unchanged line in front of the changed lines
|
|
||||||
WriteStrToStream(Part.Stream,' ')
|
|
||||||
else begin
|
|
||||||
// this is a changed line
|
|
||||||
if OtherPartHasChangedLines then
|
|
||||||
WriteStrToStream(Part.Stream,'! ')
|
|
||||||
else
|
|
||||||
WriteStrToStream(Part.Stream,CharForInsertDeletion+' ');
|
|
||||||
end;
|
|
||||||
WriteLineToStream(Part.Stream,Source,Part.Position);
|
|
||||||
if not GotoNextLine(Part.Position) then break;
|
|
||||||
GetLineExtends(Source,Part.Position);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
Part1HasChangedLines: boolean;
|
Part1HasChangedLines: boolean;
|
||||||
Part2HasChangedLines: boolean;
|
Part2HasChangedLines: boolean;
|
||||||
begin
|
begin
|
||||||
if (fPart1.Stream<>nil)
|
if (fPart1.fStream<>nil)
|
||||||
and (Start1.LineNumber-ContextLineCount<=fPart1.EndLine-1)
|
and (Start1.LineNumber-ContextLineCount<=fPart1.fEndLine-1)
|
||||||
and (Start2.LineNumber-ContextLineCount<=fPart2.EndLine-1) then begin
|
and (Start2.LineNumber-ContextLineCount<=fPart2.fEndLine-1) then begin
|
||||||
// append the new difference
|
// append the new difference
|
||||||
end else begin
|
end else begin
|
||||||
// start a new block
|
// start a new block // StartContextBlock(Start1,Start2);
|
||||||
StartContextBlock(Start1,Start2);
|
FinishOldContextBlock;
|
||||||
|
WriteStrToStream(fDiffStream,'***************'+LineBreak);
|
||||||
|
fPart1.Init(Start1);
|
||||||
|
fPart2.Init(Start2);
|
||||||
end;
|
end;
|
||||||
fPart1.EndLine:=End1.LineNumber+ContextLineCount-1;
|
fPart1.fEndLine:=End1.LineNumber+ContextLineCount-1;
|
||||||
fPart2.EndLine:=End2.LineNumber+ContextLineCount-1;
|
fPart2.fEndLine:=End2.LineNumber+ContextLineCount-1;
|
||||||
Part1HasChangedLines:=End1.LineStart>Start1.LineStart;
|
Part1HasChangedLines:=End1.LineStart>Start1.LineStart;
|
||||||
Part2HasChangedLines:=End2.LineStart>Start2.LineStart;
|
Part2HasChangedLines:=End2.LineStart>Start2.LineStart;
|
||||||
WritePart(fPart1,fText1,Start1,End1,Part2HasChangedLines,'-');
|
fPart1.Write2(Start1,End1,Part2HasChangedLines,'-');
|
||||||
WritePart(fPart2,fText2,Start2,End2,Part1HasChangedLines,'+');
|
fPart2.Write2(Start2,End2,Part1HasChangedLines,'+');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
constructor TDiffOutput.Create(const AText1, AText2: string;
|
constructor TDiffOutput.Create(const aText1, aText2: string;
|
||||||
AFlags: TTextDiffFlags; AProgressBar: TProgressBar);
|
aFlags: TTextDiffFlags; aProgressBar: TProgressBar);
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
fText1:=AText1;
|
fText1:=aText1;
|
||||||
fText2:=AText2;
|
fText2:=aText2;
|
||||||
fFlags:=AFlags;
|
fFlags:=aFlags;
|
||||||
fProgressBar:=AProgressBar;
|
fProgressBar:=aProgressBar;
|
||||||
if Assigned(fProgressBar) then begin
|
if Assigned(fProgressBar) then begin
|
||||||
i := Length(AText1); // + Length(AText2);
|
i := Length(aText1); // + Length(aText2);
|
||||||
fProgressBar.Max := i;
|
fProgressBar.Max := i;
|
||||||
fProgressBar.Step := i;
|
fProgressBar.Step := i;
|
||||||
fProgressBar.Position := 0;
|
fProgressBar.Position := 0;
|
||||||
end;
|
end;
|
||||||
fOutputType:=tdoContext; // Default OutputType, can be changed later
|
fOutputType:=tdoContext; // Default OutputType, can be changed later
|
||||||
fDiffStream:=TMemoryStream.Create;
|
fDiffStream:=TMemoryStream.Create;
|
||||||
fPart1:=TDiffPart.Create;
|
fPart1:=TDiffPart.Create(Self, fText1);
|
||||||
fPart2:=TDiffPart.Create;
|
fPart2:=TDiffPart.Create(Self, fText2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TDiffOutput.Destroy;
|
destructor TDiffOutput.Destroy;
|
||||||
begin
|
begin
|
||||||
if Assigned(fProgressBar) then
|
if Assigned(fProgressBar) then
|
||||||
fProgressBar.Position := 0;
|
fProgressBar.Position := 0;
|
||||||
fDiffStream.Free;
|
|
||||||
fPart1.Free;
|
|
||||||
fPart2.Free;
|
fPart2.Free;
|
||||||
|
fPart1.Free;
|
||||||
|
fDiffStream.Free;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
procedure InternalInit;
|
procedure InternalInit;
|
||||||
var c: char;
|
var
|
||||||
|
c: char;
|
||||||
begin
|
begin
|
||||||
for c:=Low(char) to High(char) do begin
|
for c:=Low(char) to High(char) do begin
|
||||||
IsSpaceChars[c]:=c in [' ',#9];
|
IsSpaceChars[c]:=c in [' ',#9];
|
||||||
|
Loading…
Reference in New Issue
Block a user