SynEdit: improved keeping track of longest line

git-svn-id: trunk@49084 -
This commit is contained in:
martin 2015-05-18 18:39:46 +00:00
parent 3de4e18d3f
commit f06680177d

View File

@ -26,7 +26,7 @@ unit SynEditTextTabExpander;
interface interface
uses uses
LCLProc, Classes, SysUtils, LazSynEditText, SynEditTextBase; LCLProc, Classes, SysUtils, math, LazSynEditText, SynEditTextBase;
type type
@ -55,11 +55,13 @@ type
private private
FTabWidth: integer; FTabWidth: integer;
FIndexOfLongestLine: Integer; FIndexOfLongestLine: Integer;
FFirstUnknownLongestLine, FLastUnknownLongestLine: Integer;
FTabData: TSynEditStringTabData; FTabData: TSynEditStringTabData;
FLastLineHasTab: Boolean; // Last line, parsed by GetPhysicalCharWidths FLastLineHasTab: Boolean; // Last line, parsed by GetPhysicalCharWidths
FLastLinePhysLen: Integer; FLastLinePhysLen: Integer;
FViewChangeStamp: int64; FViewChangeStamp: int64;
procedure TextBufferChanged(Sender: TObject); procedure TextBufferChanged(Sender: TObject);
procedure LineTextChanged(Sender: TSynEditStrings; aIndex, aCount: Integer);
procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer); procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
function ExpandedString(Index: integer): string; function ExpandedString(Index: integer): string;
function ExpandedStringLength(Index: integer): Integer; function ExpandedStringLength(Index: integer): Integer;
@ -135,6 +137,8 @@ end;
constructor TSynEditStringTabExpander.Create(ASynStringSource: TSynEditStrings); constructor TSynEditStringTabExpander.Create(ASynStringSource: TSynEditStrings);
begin begin
FIndexOfLongestLine := -1; FIndexOfLongestLine := -1;
FFirstUnknownLongestLine := -1;
FLastUnknownLongestLine := -1;
inherited Create(ASynStringSource); inherited Create(ASynStringSource);
TextBufferChanged(nil); TextBufferChanged(nil);
TabWidth := 8; TabWidth := 8;
@ -155,7 +159,7 @@ begin
Data.Free; Data.Free;
end; end;
end; end;
fSynStrings.RemoveChangeHandler(senrLineChange, @LineCountChanged); fSynStrings.RemoveChangeHandler(senrLineChange, @LineTextChanged);
fSynStrings.RemoveChangeHandler(senrLineCount, @LineCountChanged); fSynStrings.RemoveChangeHandler(senrLineCount, @LineCountChanged);
fSynStrings.RemoveNotifyHandler(senrTextBufferChanged, @TextBufferChanged); fSynStrings.RemoveNotifyHandler(senrTextBufferChanged, @TextBufferChanged);
inherited Destroy; inherited Destroy;
@ -178,6 +182,8 @@ begin
FTabWidth := AValue; FTabWidth := AValue;
FIndexOfLongestLine := -1; FIndexOfLongestLine := -1;
FFirstUnknownLongestLine := -1;
FLastUnknownLongestLine := -1;
for i := 0 to Count - 1 do for i := 0 to Count - 1 do
if not(FTabData[i] >= NO_TAB_IN_LINE_OFFSET) then if not(FTabData[i] >= NO_TAB_IN_LINE_OFFSET) then
FTabData[i] := LINE_LEN_UNKNOWN; FTabData[i] := LINE_LEN_UNKNOWN;
@ -219,14 +225,47 @@ begin
end end
else else
FTabData.IncRefCount; FTabData.IncRefCount;
LineCountChanged(TSynEditStrings(Sender), 0, Count); LineTextChanged(TSynEditStrings(Sender), 0, Count);
end;
procedure TSynEditStringTabExpander.LineTextChanged(Sender: TSynEditStrings; aIndex,
aCount: Integer);
var
i: integer;
begin
if (FIndexOfLongestLine >= AIndex) and (FIndexOfLongestLine < AIndex+ACount) then
FIndexOfLongestLine := -1;
if (FFirstUnknownLongestLine < 0) or (AIndex < FFirstUnknownLongestLine) then
FFirstUnknownLongestLine := AIndex;
if AIndex+ACount-1 > FLastUnknownLongestLine then
FLastUnknownLongestLine := AIndex+ACount-1;
for i := AIndex to AIndex + ACount - 1 do
FTabData[i] := LINE_LEN_UNKNOWN;
end; end;
procedure TSynEditStringTabExpander.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer); procedure TSynEditStringTabExpander.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer);
var var
i: integer; i: integer;
begin begin
if ACount < 0 then begin
if (FIndexOfLongestLine >= AIndex) and (FIndexOfLongestLine < AIndex-ACount) then
FIndexOfLongestLine := -1; FIndexOfLongestLine := -1;
if (FFirstUnknownLongestLine >= 0) then begin
if (AIndex < FFirstUnknownLongestLine) then
FFirstUnknownLongestLine := Max(AIndex, FFirstUnknownLongestLine + ACount);
if (AIndex < FLastUnknownLongestLine) then
FLastUnknownLongestLine := Max(AIndex, FLastUnknownLongestLine + ACount);
end;
exit;
end;
if (FIndexOfLongestLine >= AIndex) then
FIndexOfLongestLine := FIndexOfLongestLine + ACount;
if (FFirstUnknownLongestLine < 0) or (AIndex < FFirstUnknownLongestLine) then
FFirstUnknownLongestLine := AIndex;
if (AIndex < FLastUnknownLongestLine) or (FLastUnknownLongestLine < 0) then
FLastUnknownLongestLine := Max(AIndex, FLastUnknownLongestLine) +ACount;
for i := AIndex to AIndex + ACount - 1 do for i := AIndex to AIndex + ACount - 1 do
FTabData[i] := LINE_LEN_UNKNOWN; FTabData[i] := LINE_LEN_UNKNOWN;
end; end;
@ -334,20 +373,40 @@ var
i, j, m: Integer; i, j, m: Integer;
Line1, Line2: Integer; Line1, Line2: Integer;
begin begin
Result := 0;
Line1 := 0; Line1 := 0;
Line2 := Count - 1; Line2 := Count - 1;
if (fIndexOfLongestLine >= 0) and (fIndexOfLongestLine < Count) then begin if (fIndexOfLongestLine >= 0) and (fIndexOfLongestLine < Count) then begin
Result := FTabData[fIndexOfLongestLine]; Result := FTabData[fIndexOfLongestLine];
if Result <> LINE_LEN_UNKNOWN then begin if Result <> LINE_LEN_UNKNOWN then begin
if Result >= NO_TAB_IN_LINE_OFFSET then Result := Result - NO_TAB_IN_LINE_OFFSET; if Result >= NO_TAB_IN_LINE_OFFSET then Result := Result - NO_TAB_IN_LINE_OFFSET;
if (FFirstUnknownLongestLine < 0) then
exit; exit;
end; // Result has the value from index
Line1 := FFirstUnknownLongestLine;
if (FLastUnknownLongestLine < Line2) then
Line2 := FLastUnknownLongestLine;
end
else begin
Result := 0;
if (FFirstUnknownLongestLine < 0) then begin
Line1 := fIndexOfLongestLine; Line1 := fIndexOfLongestLine;
Line2 := fIndexOfLongestLine; Line2 := fIndexOfLongestLine;
end
else begin // TODO: Calculate for fIndexOfLongestLine, instead of extending the range
Line1 := Min(fIndexOfLongestLine, FFirstUnknownLongestLine);
if (FLastUnknownLongestLine < Line2) then
Line2 := Max(fIndexOfLongestLine, FLastUnknownLongestLine);
end;
end;
end; end;
FFirstUnknownLongestLine := -1;
FLastUnknownLongestLine := -1;
try try
Result := 0; //Result := 0;
m := 0; m := 0;
CharWidths := nil; CharWidths := nil;
for i := Line1 to Line2 do begin for i := Line1 to Line2 do begin