SynEdit: Refactor, LengthOfLongestLine

git-svn-id: trunk@25787 -
This commit is contained in:
martin 2010-05-31 00:03:31 +00:00
parent 569641d81d
commit a305372d19
5 changed files with 147 additions and 94 deletions

View File

@ -419,7 +419,7 @@ var
L: String;
begin
L := LineText;
CharWidths := FLines.GetPhysicalCharWidths(L, FLinePos-1);
CharWidths := FLines.GetPhysicalCharWidths(Pchar(L), length(L), FLinePos-1);
LogLen := Length(CharWidths);
ScreenPos := 1;
LogPos := 0;

View File

@ -58,6 +58,8 @@ type
);
TPhysicalCharWidths = Array of Shortint;
TPhysicalCharWidth = ShortInt;
PPhysicalCharWidth = ^TPhysicalCharWidth;
TSynEditUndoList = class;
TSynEditUndoItem = class;
@ -163,6 +165,8 @@ type
procedure SetUpdateState(Updating: Boolean); override;
procedure SetUpdateState(Updating: Boolean; Sender: TObject); virtual; abstract;
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); virtual; abstract;
public
constructor Create;
procedure BeginUpdate(Sender: TObject); overload;
@ -198,7 +202,7 @@ type
procedure FlushNotificationCache; virtual; abstract;
public
function GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths;
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; virtual; abstract;
function GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths;
// Byte to Char
function LogicalToPhysicalPos(const p: TPoint): TPoint;
function LogicalToPhysicalCol(const Line: String;
@ -263,6 +267,7 @@ type
procedure PutObject(Index: integer; AObject: TObject); override;
procedure SetUpdateState(Updating: Boolean; Sender: TObject); override;
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override;
public
constructor Create(ASynStringSource: TSynEditStrings);
@ -287,7 +292,7 @@ type
ASender: TObject); override;
procedure FlushNotificationCache; override;
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
//function GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths; override;
property NextLines: TSynEditStrings read fSynStrings write fSynStrings;
public
// LogX, LogY are 1-based
@ -489,8 +494,20 @@ begin
end;
function TSynEditStrings.GetPhysicalCharWidths(Index: Integer): TPhysicalCharWidths;
var
s: string;
begin
Result := GetPhysicalCharWidths(Strings[Index], Index);
s := Strings[Index];
Result := GetPhysicalCharWidths(PChar(s), length(s), Index);
end;
function TSynEditStrings.GetPhysicalCharWidths(Line: PChar; LineLen,
Index: Integer): TPhysicalCharWidths;
begin
SetLength(Result, LineLen);
if LineLen = 0 then
exit;
DoGetPhysicalCharWidths(Line, LineLen, Index, @Result[0]);
end;
function TSynEditStrings.GetIsUtf8 : Boolean;
@ -571,7 +588,7 @@ var
i, ByteLen: integer;
CharWidths: TPhysicalCharWidths;
begin
CharWidths := GetPhysicalCharWidths(Line, Index);
CharWidths := GetPhysicalCharWidths(Pchar(Line), length(Line), Index);
ByteLen := length(Line);
dec(LogicalPos);
@ -600,7 +617,7 @@ var
ScreenPos: integer;
CharWidths: TPhysicalCharWidths;
begin
CharWidths := GetPhysicalCharWidths(Line, Index);
CharWidths := GetPhysicalCharWidths(PChar(Line), length(Line), Index);
ByteLen := Length(Line);
ScreenPos := 1;
BytePos := 0;
@ -775,10 +792,10 @@ begin
fSynStrings.PutObject(Index, AObject);
end;
function TSynEditStringsLinked.GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths;
begin
Result := fSynStrings.GetPhysicalCharWidths(Line, Index);
end;
//function TSynEditStringsLinked.GetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer): TPhysicalCharWidths;
//begin
// Result := fSynStrings.GetPhysicalCharWidths(Line, LineLen, Index);
//end;
procedure TSynEditStringsLinked.SetUpdateState(Updating: Boolean; Sender: TObject);
begin
@ -789,6 +806,12 @@ begin
fSynStrings.EndUpdate(Sender);
end;
procedure TSynEditStringsLinked.DoGetPhysicalCharWidths(Line: PChar;
LineLen, Index: Integer; PWidths: PPhysicalCharWidth);
begin
fSynStrings.DoGetPhysicalCharWidths(Line, LineLen, Index, PWidths);
end;
procedure TSynEditStringsLinked.EditInsert(LogX, LogY: Integer; AText: String);
begin
fSynStrings.EditInsert(LogX, LogY, AText);

View File

@ -166,6 +166,7 @@ type
procedure UndoEditLinesDelete(LogY, ACount: Integer);
procedure IncreaseTextChangeStamp;
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override;
public
constructor Create;
destructor Destroy; override;
@ -188,9 +189,7 @@ type
aBytePos: Integer = -1; aLen: Integer = 0; aTxt: String = ''); override;
procedure SendNotification(AReason: TSynEditNotifyReason;
ASender: TObject); override;
procedure FlushNotificationCache; override;
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
// For Textbuffersharing
procedure FlushNotificationCache; override;
procedure AttachSynEdit(AEdit: TSynEditBase);
procedure DetachSynEdit(AEdit: TSynEditBase);
function AttachedSynEditCount: Integer;
@ -700,24 +699,27 @@ end;
// Maps the Physical Width (ScreenCells) to each character
// Multibyte Chars have thw width on the first byte, and a 0 Width for all other bytes
function TSynEditStringList.GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths;
procedure TSynEditStringList.DoGetPhysicalCharWidths(Line: PChar;
LineLen, Index: Integer; PWidths: PPhysicalCharWidth);
var
i, j: Integer;
p: PChar;
begin
SetLength(Result, Length(Line));
if not IsUtf8 then begin
for i := 0 to LineLen-1 do
PWidths[i] := 1;
exit;
end;
j := 0;
p := PChar(line);
for i := 0 to length(Line)-1 do begin
for i := 0 to LineLen-1 do begin
if j > 0 then begin
Result[i] := 0;
PWidths^ := 0;
dec(j);
end else begin
Result[i] := 1;
if IsUtf8 then
j := UTF8CharacterLength(p) - 1;
PWidths^ := 1;
j := UTF8CharacterLength(Line) - 1;
end;
inc(p);
inc(Line);
inc(PWidths);
end;
end;

View File

@ -40,8 +40,8 @@ type
{ SynEditTextDoubleWidthChars }
SynEditStringDoubleWidthChars = class(TSynEditStringsLinked)
public
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
protected
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override;
end;
@ -49,114 +49,116 @@ implementation
{ SynEditTextDoubleWidthChars }
function SynEditStringDoubleWidthChars.GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths;
procedure SynEditStringDoubleWidthChars.DoGetPhysicalCharWidths(Line: PChar;
LineLen, Index: Integer; PWidths: PPhysicalCharWidth);
var
i: Integer;
p: PChar;
begin
Result := inherited GetPhysicalCharWidths(Line, Index);
inherited DoGetPhysicalCharWidths(Line, LineLen, Index, PWidths);
if not IsUtf8 then
exit;
p := Pchar(Line)-1;
for i := 0 to length(Line) -1 do begin
inc(p);
if Result[i] = 0 then continue;
case p[0] of
dec(Line);
dec(PWidths);
for i := 0 to LineLen - 1 do begin
inc(Line);
inc(PWidths);
if PWidths^ = 0 then continue;
case Line[0] of
#$e1:
case p[1] of
case Line[1] of
#$84:
if (p[2] >= #$80) then Result[i] := 2;
if (Line[2] >= #$80) then PWidths^ := 2;
#$85:
if (p[2] <= #$9f) then Result[i] := 2;
if (Line[2] <= #$9f) then PWidths^ := 2;
end;
#$e2:
case p[1] of
case Line[1] of
#$8c:
if (p[2] = #$a9) or (p[2] = #$aa) then Result[i] := 2;
if (Line[2] = #$a9) or (Line[2] = #$aa) then PWidths^ := 2;
#$ba:
if (p[2] >= #$80) then Result[i] := 2;
if (Line[2] >= #$80) then PWidths^ := 2;
#$bb..#$ff:
Result[i] := 2;
PWidths^ := 2;
end;
#$e3:
case p[1] of
case Line[1] of
#$81:
if (p[2] >= #$81) then Result[i] := 2;
if (Line[2] >= #$81) then PWidths^ := 2;
#$82..#$8e:
Result[i] := 2;
PWidths^ := 2;
#$8f:
if (p[2] <= #$bf) then Result[i] := 2;
if (Line[2] <= #$bf) then PWidths^ := 2;
#$90:
if (p[2] >= #$80) then Result[i] := 2;
if (Line[2] >= #$80) then PWidths^ := 2;
#$91..#$FF:
Result[i] := 2;
PWidths^ := 2;
end;
#$e4:
case p[1] of
case Line[1] of
#$00..#$b5:
Result[i] := 2;
PWidths^ := 2;
#$b6:
if (p[2] <= #$b5) then Result[i] := 2;
if (Line[2] <= #$b5) then PWidths^ := 2;
#$b8:
if (p[2] >= #$80) then Result[i] := 2;
if (Line[2] >= #$80) then PWidths^ := 2;
#$b9..#$ff:
Result[i] := 2;
PWidths^ := 2;
end;
#$e5..#$e8:
Result[i] := 2;
PWidths^ := 2;
#$e9:
if (p[1] <= #$bf) or (p[2] <= #$83) then Result[i] := 2;
if (Line[1] <= #$bf) or (Line[2] <= #$83) then PWidths^ := 2;
#$ea:
case p[1] of
case Line[1] of
#$80, #$b0:
if (p[2] >= #$80) then Result[i] := 2;
if (Line[2] >= #$80) then PWidths^ := 2;
#$81..#$92, #$b1..#$ff:
Result[i] := 2;
PWidths^ := 2;
#$93:
if (p[2] <= #$86) then Result[i] := 2;
if (Line[2] <= #$86) then PWidths^ := 2;
end;
#$eb..#$ec:
Result[i] := 2;
PWidths^ := 2;
#$ed:
if (p[1] <= #$9e) or (p[2] <= #$a3) then Result[i] := 2;
if (Line[1] <= #$9e) or (Line[2] <= #$a3) then PWidths^ := 2;
#$ef:
case p[1] of
case Line[1] of
#$a4:
if (p[2] >= #$80) then Result[i] := 2;
if (Line[2] >= #$80) then PWidths^ := 2;
#$a5..#$aa:
Result[i] := 2;
PWidths^ := 2;
#$ab:
if (p[2] <= #$99) then Result[i] := 2;
if (Line[2] <= #$99) then PWidths^ := 2;
#$b8:
if (p[2] in [#$90..#$99,#$b0..#$ff]) then Result[i] := 2;
if (Line[2] in [#$90..#$99,#$b0..#$ff]) then PWidths^ := 2;
#$b9:
if (p[2] <= #$ab) then Result[i] := 2;
if (Line[2] <= #$ab) then PWidths^ := 2;
#$bc:
if (p[2] >= #$81) then Result[i] := 2;
if (Line[2] >= #$81) then PWidths^ := 2;
#$bd:
if (p[2] <= #$a0) then Result[i] := 2;
if (Line[2] <= #$a0) then PWidths^ := 2;
#$bf:
if (p[2] >= #$a0) and (p[2] <= #$a6) then Result[i] := 2;
if (Line[2] >= #$a0) and (Line[2] <= #$a6) then PWidths^ := 2;
end;
#$f0:
case p[1] of
case Line[1] of
#$a0, #$b0:
case p[2] of
case Line[2] of
#$80:
if (p[3] >= #$80) then Result[i] := 2;
if (Line[3] >= #$80) then PWidths^ := 2;
#$81..#$ff:
Result[i] := 2;
PWidths^ := 2;
end;
#$a1..#$ae, #$b1..#$be:
Result[i] := 2;
PWidths^ := 2;
#$af, #$bf:
case p[2] of
case Line[2] of
#$00..#$be:
Result[i] := 2;
PWidths^ := 2;
#$bf:
if (p[3] <= #$bd) then Result[i] := 2;
if (Line[3] <= #$bd) then PWidths^ := 2;
end;
end
end;

View File

@ -26,8 +26,7 @@ unit SynEditTextTabExpander;
interface
uses
LCLProc,
Classes, SysUtils, SynEditTextBase;
LCLProc, Classes, SysUtils, SynEditTextBase;
type
@ -67,10 +66,10 @@ type
procedure SetTabWidth(const AValue : integer);
function GetExpandedString(Index: integer): string; override;
function GetLengthOfLongestLine: integer; override;
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); override;
public
constructor Create(ASynStringSource: TSynEditStrings);
destructor Destroy; override;
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
public
@ -228,7 +227,7 @@ begin
// xxx wrong double width // none latin ...
//FTabData[Index] := length(Result) + NO_TAB_IN_LINE_OFFSET;
end else begin
CharWidths := GetPhysicalCharWidths(Line, Index);
CharWidths := GetPhysicalCharWidths(Pchar(Line), length(Line), Index);
l := 0;
for i := 0 to length(CharWidths)-1 do
l := l + CharWidths[i];
@ -261,7 +260,9 @@ begin
Result := 0;
FTabData[Index] := Result + NO_TAB_IN_LINE_OFFSET;
end else begin
CharWidths := GetPhysicalCharWidths(Line, Index);
i := length(Line);
SetLength(CharWidths, i);
DoGetPhysicalCharWidths(Pchar(Line), i, Index, @CharWidths[0]);
Result := 0;
for i := 0 to length(CharWidths)-1 do
Result := Result + CharWidths[i];
@ -284,32 +285,35 @@ begin
Result := '';
end;
function TSynEditStringTabExpander.GetPhysicalCharWidths(const Line: String;
Index: Integer): TPhysicalCharWidths;
procedure TSynEditStringTabExpander.DoGetPhysicalCharWidths(Line: PChar;
LineLen, Index: Integer; PWidths: PPhysicalCharWidth);
var
p: PChar;
HasTab: Boolean;
i, j: Integer;
begin
Result := inherited GetPhysicalCharWidths(Line, Index);
inherited DoGetPhysicalCharWidths(Line, LineLen, Index, PWidths);
HasTab := False;
p := PChar(Line);
j := 0;
for i := 0 to length(Line) -1 do begin
if Result[i] <> 0 then begin
if p^ = #9 then begin
Result[i] := FTabWidth - (j mod FTabWidth);
for i := 0 to LineLen - 1 do begin
if PWidths^ <> 0 then begin
if Line^ = #9 then begin
PWidths^ := FTabWidth - (j mod FTabWidth);
HasTab := True;
end;
j := j + Result[i];
j := j + PWidths^;
end;
inc(p);
inc(Line);
inc(PWidths);
end;
FLastLineHasTab := HasTab;
end;
function TSynEditStringTabExpander.GetLengthOfLongestLine: integer;
var
Line: String;
CharWidths: TPhysicalCharWidths;
n, m: Integer;
//var
i, j: integer;
begin
if (fIndexOfLongestLine >= 0) and (fIndexOfLongestLine < Count) then begin
@ -319,10 +323,32 @@ begin
end;
Result := 0;
m := 0;
for i := 0 to Count - 1 do begin
j := FTabData[i];
if j = LINE_LEN_UNKNOWN then
j := ExpandedStringLength(i)
if j = LINE_LEN_UNKNOWN then begin
// embedd a copy of ExpandedStringLength
// allows to re-use CharWidths
Line := fSynStrings[i];
j := 0;
if (Line = '') then begin
FTabData[i] := j + NO_TAB_IN_LINE_OFFSET;
end else begin
n := length(Line);
if n > m then begin
SetLength(CharWidths, n);
m := n;
end;
DoGetPhysicalCharWidths(Pchar(Line), n, i, @CharWidths[0]);
for m := 0 to n-1 do
j := j + CharWidths[m];
if FLastLineHasTab then // FLastLineHasTab is set by GetPhysicalCharWidths
FTabData[i] := j
else
FTabData[i] := j + NO_TAB_IN_LINE_OFFSET;
end;
end
else
if j >= NO_TAB_IN_LINE_OFFSET then
j := j - NO_TAB_IN_LINE_OFFSET;