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; L: String;
begin begin
L := LineText; L := LineText;
CharWidths := FLines.GetPhysicalCharWidths(L, FLinePos-1); CharWidths := FLines.GetPhysicalCharWidths(Pchar(L), length(L), FLinePos-1);
LogLen := Length(CharWidths); LogLen := Length(CharWidths);
ScreenPos := 1; ScreenPos := 1;
LogPos := 0; LogPos := 0;

View File

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

View File

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

View File

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

View File

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