mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-04 12:18:17 +02:00
SynEdit: Cache char-width info (Logical<>Physical) / Cleanup
git-svn-id: trunk@30074 -
This commit is contained in:
parent
c3ace57233
commit
86a71bfe1e
@ -1593,7 +1593,7 @@ begin
|
||||
with TCustomSynEdit(F.CurrentEditor) do begin
|
||||
BeginUndoBlock;
|
||||
BeginUpdate;
|
||||
LogCaret:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaret := LogicalCaretXY;
|
||||
NewBlockBegin:=LogCaret;
|
||||
CurLine:=Lines[NewBlockBegin.Y - 1];
|
||||
while (NewBlockBegin.X>1) and (NewBlockBegin.X-1<=length(CurLine))
|
||||
|
@ -344,9 +344,9 @@ type
|
||||
FBlockIndent: integer;
|
||||
FCaret: TSynEditCaret;
|
||||
FInternalCaret: TSynEditCaret;
|
||||
FScreenCaret: TSynEditScreenCaret;
|
||||
FInternalBlockSelection: TSynEditSelection;
|
||||
FOnChangeUpdating: TChangeUpdatingEvent;
|
||||
FScreenCaret: TSynEditScreenCaret;
|
||||
FMouseSelectionMode: TSynSelectionMode;
|
||||
fCtrlMouseActive: boolean; // deprecated since 0.9.29
|
||||
fMarkupManager : TSynEditMarkupManager;
|
||||
@ -866,6 +866,7 @@ type
|
||||
property CaretX: Integer read GetCaretX write SetCaretX;
|
||||
property CaretY: Integer read GetCaretY write SetCaretY;
|
||||
property CaretXY: TPoint read GetCaretXY write SetCaretXY;// screen position
|
||||
property LogicalCaretXY: TPoint read GetLogicalCaretXY write SetLogicalCaretXY;
|
||||
property CharsInWindow: Integer read fCharsInWindow;
|
||||
property CharWidth: integer read fCharWidth;
|
||||
property Color default clWhite;
|
||||
@ -873,7 +874,6 @@ type
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
property CtrlMouseActive: boolean read fCtrlMouseActive; deprecated; // deprecated in 0.9.29
|
||||
{$ENDIF}
|
||||
property LogicalCaretXY: TPoint read GetLogicalCaretXY write SetLogicalCaretXY;
|
||||
{$IFDEF SYN_LAZARUS}
|
||||
property SelStart: Integer read GetSelStart write SetSelStart;
|
||||
property SelEnd: Integer read GetSelEnd write SetSelEnd;
|
||||
@ -2169,12 +2169,13 @@ end;
|
||||
|
||||
function TCustomSynEdit.GetLogicalCaretXY: TPoint;
|
||||
begin
|
||||
Result:=PhysicalToLogicalPos(CaretXY);
|
||||
Result := FCaret.LineBytePos;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.SetLogicalCaretXY(const NewLogCaretXY: TPoint);
|
||||
begin
|
||||
CaretXY:=LogicalToPhysicalPos(NewLogCaretXY);
|
||||
FCaret.ChangeOnTouch;
|
||||
FCaret.LineBytePos := NewLogCaretXY;
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.SetBeautifier(NewBeautifier: TSynCustomBeautifier);
|
||||
@ -2935,7 +2936,7 @@ begin
|
||||
Inc(X, CharsInWindow);
|
||||
FCaret.LineCharPos := Point(X, C.Y);
|
||||
if (not(sfIsDragging in fStateFlags)) then
|
||||
SetBlockEnd(PhysicalToLogicalPos(CaretXY));
|
||||
SetBlockEnd(LogicalCaretXY);
|
||||
end;
|
||||
if fScrollDeltaY <> 0 then begin
|
||||
if GetKeyState(VK_SHIFT) < 0 then
|
||||
@ -2947,7 +2948,7 @@ begin
|
||||
else Y := TopLine; // scrolling up
|
||||
FCaret.LineCharPos := Point(C.X, Y);
|
||||
if (not(sfIsDragging in fStateFlags)) then
|
||||
SetBlockEnd(PhysicalToLogicalPos(CaretXY));
|
||||
SetBlockEnd(LogicalCaretXY);
|
||||
end;
|
||||
finally
|
||||
DoDecPaintLock(Self);
|
||||
@ -3003,8 +3004,8 @@ begin
|
||||
if sfWaitForDragging in fStateFlags then
|
||||
begin
|
||||
ComputeCaret(X, Y);
|
||||
SetBlockBegin(PhysicalToLogicalPos(CaretXY));
|
||||
SetBlockEnd(PhysicalToLogicalPos(CaretXY));
|
||||
SetBlockBegin(LogicalCaretXY);
|
||||
SetBlockEnd(LogicalCaretXY);
|
||||
Exclude(fStateFlags, sfWaitForDragging);
|
||||
end;
|
||||
|
||||
@ -4117,7 +4118,7 @@ end;
|
||||
|
||||
procedure TCustomSynEdit.SelectWord;
|
||||
begin
|
||||
SetWordBlock(PhysicalToLogicalPos(CaretXY));
|
||||
SetWordBlock(LogicalCaretXY);
|
||||
end;
|
||||
|
||||
procedure TCustomSynEdit.SelectLine(WithLeadSpaces: Boolean = True);
|
||||
@ -4153,12 +4154,12 @@ end;
|
||||
|
||||
function TCustomSynEdit.GetCaretX : Integer;
|
||||
begin
|
||||
Result:= fCaret.CharPos;
|
||||
Result:= FCaret.CharPos;
|
||||
end;
|
||||
|
||||
function TCustomSynEdit.GetCaretY : Integer;
|
||||
begin
|
||||
Result:= fCaret.LinePos;
|
||||
Result:= FCaret.LinePos;
|
||||
end;
|
||||
|
||||
function TCustomSynEdit.GetCaretUndo: TSynEditUndoItem;
|
||||
@ -4188,7 +4189,7 @@ end;
|
||||
|
||||
function TCustomSynEdit.GetCaretXY: TPoint;
|
||||
begin
|
||||
Result := Point(CaretX, CaretY);
|
||||
Result := FCaret.LineCharPos;
|
||||
end;
|
||||
|
||||
function TCustomSynEdit.GetFoldedCodeColor: TSynSelectedColor;
|
||||
@ -4994,7 +4995,7 @@ begin
|
||||
FBlockSelection.EndLineBytePos := Point(x2, MinMax(Value.y, 1, FTheLinesView.Count));
|
||||
end;
|
||||
FBlockSelection.ActiveSelectionMode := smNormal;
|
||||
CaretXY := FTheLinesView.LogicalToPhysicalPos(FBlockSelection.EndLineBytePos);
|
||||
LogicalCaretXY := FBlockSelection.EndLineBytePos;
|
||||
//DebugLn(' FFF2 ',Value.X,',',Value.Y,' BlockBegin=',BlockBegin.X,',',BlockBegin.Y,' BlockEnd=',BlockEnd.X,',',BlockEnd.Y);
|
||||
DoDecPaintLock(Self);
|
||||
end;
|
||||
@ -5748,10 +5749,8 @@ begin
|
||||
FCaret.DecForcePastEOL;
|
||||
end;
|
||||
FCaret.LineCharPos := NewCaret;
|
||||
BlockBegin := {$IFDEF SYN_LAZARUS}PhysicalToLogicalPos(NewCaret)
|
||||
{$ELSE}NewCaret{$ENDIF};
|
||||
BlockEnd := {$IFDEF SYN_LAZARUS}PhysicalToLogicalPos(CaretXY)
|
||||
{$ELSE}CaretXY{$ENDIF};
|
||||
BlockBegin := PhysicalToLogicalPos(NewCaret);
|
||||
BlockEnd := LogicalCaretXY;
|
||||
finally
|
||||
InternalEndUndoBlock;
|
||||
end;
|
||||
@ -6211,9 +6210,9 @@ begin
|
||||
CaretNew := PrevWordPos;
|
||||
if FFoldedLinesView.FoldedAtTextIndex[CaretNew.Y - 1] then begin
|
||||
CY := FindNextUnfoldedLine(CaretNew.Y, False);
|
||||
CaretNew := LogicalToPhysicalPos(Point(1 + Length(FTheLinesView[CY-1]), CY));
|
||||
CaretNew := Point(1 + Length(FTheLinesView[CY-1]), CY);
|
||||
end;
|
||||
FCaret.LineCharPos := CaretNew;
|
||||
FCaret.LineBytePos := CaretNew;
|
||||
end;
|
||||
ecWordRight, ecSelWordRight, ecColSelWordRight:
|
||||
begin
|
||||
@ -6235,7 +6234,7 @@ begin
|
||||
else begin
|
||||
Temp := LineText;
|
||||
Len := Length(Temp);
|
||||
LogCaretXY:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaretXY:=LogicalCaretXY;
|
||||
Caret := CaretXY;
|
||||
//debugln('ecDeleteLastChar B Temp="',DbgStr(Temp),'" CaretX=',dbgs(CaretX),' LogCaretXY=',dbgs(LogCaretXY));
|
||||
if LogCaretXY.X > Len +1
|
||||
@ -6275,7 +6274,7 @@ begin
|
||||
else begin
|
||||
Temp := LineText;
|
||||
Len := Length(Temp);
|
||||
LogCaretXY:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaretXY:=LogicalCaretXY;
|
||||
if LogCaretXY.X <= Len then
|
||||
begin
|
||||
// delete char
|
||||
@ -6306,7 +6305,7 @@ begin
|
||||
WP := Point(Len + 1, CaretY);
|
||||
if (WP.X <> CaretX) or (WP.Y <> CaretY) then begin
|
||||
FInternalBlockSelection.StartLineBytePos := PhysicalToLogicalPos(WP);
|
||||
FInternalBlockSelection.EndLineBytePos := PhysicalToLogicalPos(CaretXY);
|
||||
FInternalBlockSelection.EndLineBytePos := LogicalCaretXY;
|
||||
FInternalBlockSelection.ActiveSelectionMode := smNormal;
|
||||
FInternalBlockSelection.SetSelTextPrimitive(smNormal, nil);
|
||||
if Helper <> '' then
|
||||
@ -6322,7 +6321,7 @@ begin
|
||||
WP := Point(1, CaretY);
|
||||
if (WP.X <> CaretX) or (WP.Y <> CaretY) then begin
|
||||
FInternalBlockSelection.StartLineBytePos := PhysicalToLogicalPos(WP);
|
||||
FInternalBlockSelection.EndLineBytePos := PhysicalToLogicalPos(CaretXY);
|
||||
FInternalBlockSelection.EndLineBytePos := LogicalCaretXY;
|
||||
FInternalBlockSelection.ActiveSelectionMode := smNormal;
|
||||
FInternalBlockSelection.SetSelTextPrimitive(smNormal, nil);
|
||||
CaretXY := WP;
|
||||
@ -6348,7 +6347,7 @@ begin
|
||||
if SelAvail and (not FBlockSelection.Persistent) and (eoOverwriteBlock in fOptions2) then
|
||||
SetSelTextExternal('');
|
||||
Temp := LineText;
|
||||
LogCaretXY:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaretXY:=LogicalCaretXY;
|
||||
Len := Length(Temp);
|
||||
if LogCaretXY.X > Len + 1 then
|
||||
LogCaretXY.X := Len + 1;
|
||||
@ -6424,7 +6423,7 @@ begin
|
||||
// Insert a linebreak, but do not apply any other functionality (such as indent)
|
||||
if SelAvail and (not FBlockSelection.Persistent) and (eoOverwriteBlock in fOptions2) then
|
||||
SetSelTextExternal('');
|
||||
LogCaretXY:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaretXY:=LogicalCaretXY;
|
||||
FTheLinesView.EditLineBreak(LogCaretXY.X, LogCaretXY.Y);
|
||||
CaretXY := Point(1, CaretY + 1);
|
||||
EnsureCursorPosVisible;
|
||||
@ -6611,7 +6610,7 @@ begin
|
||||
if fInserting then
|
||||
Helper := '';
|
||||
fUndoList.AddChange(crInsert, StartOfBlock,
|
||||
PhysicalToLogicalPos(CaretXY),
|
||||
LogicalCaretXY,
|
||||
Helper, smNormal);
|
||||
if CaretX >= LeftChar + fCharsInWindow then
|
||||
LeftChar := LeftChar + min(25, fCharsInWindow - 1);
|
||||
@ -8266,8 +8265,9 @@ var
|
||||
end;
|
||||
inc(EndPt.X);
|
||||
SetCaretAndSelection(CaretXY, StartPt, EndPt);
|
||||
end else if MoveCaret then
|
||||
CaretXY := LogicalToPhysicalPos(Result)
|
||||
end
|
||||
else if MoveCaret then
|
||||
LogicalCaretXY := Result;
|
||||
end;
|
||||
|
||||
procedure DoFindMatchingQuote(q: char);
|
||||
@ -8543,7 +8543,7 @@ var
|
||||
end;
|
||||
|
||||
begin
|
||||
LogCaret:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaret:=LogicalCaretXY;
|
||||
CX := LogCaret.X;
|
||||
CY := LogCaret.Y;
|
||||
// valid line?
|
||||
@ -8596,7 +8596,7 @@ var
|
||||
LogCaret: TPoint;
|
||||
DelSpaces : Boolean;
|
||||
begin
|
||||
LogCaret:=PhysicalToLogicalPos(CaretXY);
|
||||
LogCaret:=LogicalCaretXY;
|
||||
CX := LogCaret.X;
|
||||
CY := LogCaret.Y;
|
||||
// valid line?
|
||||
|
@ -716,7 +716,7 @@ end;
|
||||
constructor TSynEditSelection.Create(ALines : TSynEditStrings; aActOnLineChanges: Boolean);
|
||||
begin
|
||||
Inherited Create(ALines);
|
||||
FInternalCaret := TSynEditCaret.Create;
|
||||
FInternalCaret := TSynEditCaret.Create; // TODO: does not need FLines.AddEditHandler
|
||||
FInternalCaret.Lines := FLines;
|
||||
|
||||
FActiveSelectionMode := smNormal;
|
||||
|
@ -129,6 +129,30 @@ type
|
||||
read GetStorageMems write SetStorageMems; default;
|
||||
end;
|
||||
|
||||
{ TSynLogicalPhysicalConvertor }
|
||||
const
|
||||
SYN_LP_MIN_ALLOC = 1024; // Keep at least n*SizeOf(TPhysicalCharWidths) allocated
|
||||
type
|
||||
TSynLogicalPhysicalConvertor = class
|
||||
private
|
||||
FLines: TSynEditStrings;
|
||||
FCurrentWidths: TPhysicalCharWidths;
|
||||
FCurrentWidthsLen, FCurrentWidthsAlloc: Integer;
|
||||
FCurrentLine: Integer;
|
||||
FTextChangeStamp, FViewChangeStamp: Int64;
|
||||
// TODOtab-width
|
||||
procedure PrepareWidthsForLine(AIndex: Integer; AForce: Boolean = False);
|
||||
public
|
||||
constructor Create(ALines: TSynEditStrings);
|
||||
destructor Destroy; override;
|
||||
// Line is 0-based // Column is 1-based
|
||||
function PhysicalToLogical(AIndex, AColumn: Integer): Integer;
|
||||
function PhysicalToLogical(AIndex, AColumn: Integer; out AColOffset: Integer): Integer;
|
||||
// ACharPos 1=before 1st char
|
||||
function LogicalToPhysical(AIndex, ABytePos: Integer): Integer;
|
||||
function LogicalToPhysical(AIndex, ABytePos: Integer; var AColOffset: Integer): Integer;
|
||||
end;
|
||||
|
||||
{ TSynEditStringsBase }
|
||||
|
||||
TSynEditStringsBase = class(TStrings)
|
||||
@ -147,6 +171,7 @@ type
|
||||
TSynEditStrings = class(TSynEditStringsBase)
|
||||
private
|
||||
FSenderUpdateCount: Integer;
|
||||
FLogPhysConvertor :TSynLogicalPhysicalConvertor;
|
||||
protected
|
||||
FIsUtf8: Boolean;
|
||||
function GetIsUtf8 : Boolean; virtual;
|
||||
@ -155,6 +180,8 @@ type
|
||||
function GetExpandedString(Index: integer): string; virtual; abstract;
|
||||
function GetLengthOfLongestLine: integer; virtual; abstract;
|
||||
procedure SetTextStr(const Value: string); override;
|
||||
function GetTextChangeStamp: int64; virtual; abstract;
|
||||
function GetViewChangeStamp: int64; virtual;
|
||||
|
||||
function GetUndoList: TSynEditUndoList; virtual; abstract;
|
||||
function GetRedoList: TSynEditUndoList; virtual; abstract;
|
||||
@ -172,6 +199,7 @@ type
|
||||
procedure DoGetPhysicalCharWidths(Line: PChar; LineLen, Index: Integer; PWidths: PPhysicalCharWidth); virtual; abstract;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure BeginUpdate(Sender: TObject); overload;
|
||||
procedure EndUpdate(Sender: TObject); overload;
|
||||
function IsUpdating: Boolean;
|
||||
@ -229,6 +257,8 @@ type
|
||||
property IsUndoing: Boolean read GetIsUndoing write SetIsUndoing;
|
||||
property IsRedoing: Boolean read GetIsRedoing write SetIsRedoing;
|
||||
public
|
||||
property TextChangeStamp: int64 read GetTextChangeStamp;
|
||||
property ViewChangeStamp: int64 read GetViewChangeStamp; // tabs-size, trailing-spaces, ...
|
||||
property ExpandedStrings[Index: integer]: string read GetExpandedString;
|
||||
property LengthOfLongestLine: integer read GetLengthOfLongestLine;
|
||||
property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8;
|
||||
@ -242,6 +272,8 @@ type
|
||||
|
||||
function GetIsUtf8 : Boolean; override;
|
||||
procedure SetIsUtf8(const AValue : Boolean); override;
|
||||
function GetTextChangeStamp: int64; override;
|
||||
function GetViewChangeStamp: int64; override;
|
||||
|
||||
function GetRange(Index: Pointer): TSynManagedStorageMem; override;
|
||||
procedure PutRange(Index: Pointer; const ARange: TSynManagedStorageMem); override;
|
||||
@ -430,6 +462,130 @@ begin
|
||||
raise ESynEditStorageMem.CreateFmt(SListIndexOutOfBounds, [Index]);
|
||||
end;
|
||||
|
||||
{ TSynLogicalPhysicalConvertor }
|
||||
|
||||
procedure TSynLogicalPhysicalConvertor.PrepareWidthsForLine(AIndex: Integer;
|
||||
AForce: Boolean);
|
||||
var
|
||||
LineLen: Integer;
|
||||
Line: PChar;
|
||||
begin
|
||||
if (not AForce) and (FCurrentLine = AIndex) and
|
||||
(FLines.TextChangeStamp = FTextChangeStamp) and (FLines.ViewChangeStamp = FViewChangeStamp)
|
||||
then begin
|
||||
//debugln(['**************** RE-USING widths: ', AIndex,' (',dbgs(Pointer(self)),')']);
|
||||
exit;
|
||||
end;
|
||||
|
||||
if (AIndex < 0) or (AIndex >= FLines.Count) then begin
|
||||
FCurrentWidthsLen := 0;
|
||||
FViewChangeStamp := FLines.ViewChangeStamp;
|
||||
FTextChangeStamp := FLines.TextChangeStamp;
|
||||
exit;
|
||||
end;
|
||||
|
||||
Line := FLines.GetPChar(AIndex, LineLen);
|
||||
if LineLen > FCurrentWidthsAlloc then begin
|
||||
//debugln(['**************** COMPUTING widths (grow): ', AIndex,' (',dbgs(Pointer(self)),') old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen]);
|
||||
SetLength(FCurrentWidths, LineLen * SizeOf(TPhysicalCharWidth));
|
||||
FCurrentWidthsAlloc := LineLen;
|
||||
end
|
||||
else if FCurrentWidthsAlloc > Max(Max(LineLen, FCurrentWidthsLen)*4, SYN_LP_MIN_ALLOC) then begin
|
||||
//debugln(['**************** COMPUTING widths (shrink): ', AIndex,' (',dbgs(Pointer(self)),') old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen]);
|
||||
FCurrentWidthsAlloc := Max(Max(LineLen, FCurrentWidthsLen), SYN_LP_MIN_ALLOC) ;
|
||||
SetLength(FCurrentWidths, FCurrentWidthsAlloc * SizeOf(TPhysicalCharWidth));
|
||||
//end
|
||||
//else begin
|
||||
// debugln(['**************** COMPUTING widths: ', AIndex,' (',dbgs(Pointer(self)),') alloc=',FCurrentWidthsAlloc]);
|
||||
end;
|
||||
|
||||
FCurrentWidthsLen := LineLen;
|
||||
if LineLen > 0 then
|
||||
FLines.DoGetPhysicalCharWidths(Line, LineLen, AIndex, @FCurrentWidths[0]);
|
||||
FViewChangeStamp := FLines.ViewChangeStamp;
|
||||
FTextChangeStamp := FLines.TextChangeStamp;
|
||||
FCurrentLine := AIndex;
|
||||
end;
|
||||
|
||||
constructor TSynLogicalPhysicalConvertor.Create(ALines: TSynEditStrings);
|
||||
begin
|
||||
FLines := ALines;
|
||||
FCurrentLine := -1;
|
||||
FCurrentWidths := nil;
|
||||
FCurrentWidthsLen := 0;
|
||||
FCurrentWidthsAlloc := 0;
|
||||
end;
|
||||
|
||||
destructor TSynLogicalPhysicalConvertor.Destroy;
|
||||
begin
|
||||
SetLength(FCurrentWidths, 0);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TSynLogicalPhysicalConvertor.PhysicalToLogical(AIndex,
|
||||
AColumn: Integer): Integer;
|
||||
var
|
||||
ColOffs: Integer;
|
||||
begin
|
||||
Result := PhysicalToLogical(AIndex, AColumn, ColOffs);
|
||||
end;
|
||||
|
||||
function TSynLogicalPhysicalConvertor.PhysicalToLogical(AIndex, AColumn: Integer;
|
||||
out AColOffset: Integer): Integer;
|
||||
var
|
||||
BytePos, ScreenPos, ScreenPosOld: integer;
|
||||
begin
|
||||
PrepareWidthsForLine(AIndex);
|
||||
|
||||
ScreenPos := 1;
|
||||
BytePos := 0;
|
||||
while BytePos < FCurrentWidthsLen do begin
|
||||
ScreenPosOld := ScreenPos;
|
||||
ScreenPos := ScreenPos + FCurrentWidths[BytePos];
|
||||
inc(BytePos);
|
||||
if ScreenPos > AColumn then begin
|
||||
AColOffset := AColumn - ScreenPosOld;
|
||||
exit(BytePos);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Column at/past end of line
|
||||
AColOffset := 0;
|
||||
Result := BytePos + 1 + AColumn - ScreenPos;
|
||||
end;
|
||||
|
||||
function TSynLogicalPhysicalConvertor.LogicalToPhysical(AIndex,
|
||||
ABytePos: Integer): Integer;
|
||||
var
|
||||
ColOffs: Integer;
|
||||
begin
|
||||
ColOffs := 0;
|
||||
Result := LogicalToPhysical(AIndex, ABytePos, ColOffs);
|
||||
end;
|
||||
|
||||
function TSynLogicalPhysicalConvertor.LogicalToPhysical(AIndex, ABytePos: Integer;
|
||||
var AColOffset: Integer): Integer;
|
||||
var
|
||||
i: integer;
|
||||
CharWidths: TPhysicalCharWidths;
|
||||
begin
|
||||
PrepareWidthsForLine(AIndex);
|
||||
|
||||
dec(ABytePos);
|
||||
if ABytePos >= FCurrentWidthsLen then begin
|
||||
Result := 1 + ABytePos - FCurrentWidthsLen;
|
||||
ABytePos := FCurrentWidthsLen;
|
||||
AColOffset := 0;
|
||||
end
|
||||
else begin
|
||||
AColOffset := Min(AColOffset, FCurrentWidths[ABytePos]-1);
|
||||
Result := 1 + AColOffset;
|
||||
end;
|
||||
|
||||
for i := 0 to ABytePos - 1 do
|
||||
Result := Result + FCurrentWidths[i];
|
||||
end;
|
||||
|
||||
{ TSynEditStringsBase }
|
||||
|
||||
function TSynEditStringsBase.GetPChar(ALineIndex: Integer): PChar;
|
||||
@ -443,10 +599,17 @@ end;
|
||||
|
||||
constructor TSynEditStrings.Create;
|
||||
begin
|
||||
FLogPhysConvertor := TSynLogicalPhysicalConvertor.Create(self);
|
||||
inherited Create;
|
||||
IsUtf8 := True;
|
||||
end;
|
||||
|
||||
destructor TSynEditStrings.Destroy;
|
||||
begin
|
||||
FreeAndNil(FLogPhysConvertor);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TSynEditStrings.BeginUpdate(Sender: TObject);
|
||||
begin
|
||||
if FSenderUpdateCount = 0 then
|
||||
@ -579,6 +742,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSynEditStrings.GetViewChangeStamp: int64;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
procedure TSynEditStrings.SetUpdateState(Updating: Boolean);
|
||||
begin
|
||||
// Update/check "FSenderUpdateCount", to avoid extra locking/unlocking
|
||||
@ -591,8 +759,9 @@ end;
|
||||
function TSynEditStrings.LogicalToPhysicalPos(const p : TPoint) : TPoint;
|
||||
begin
|
||||
Result := p;
|
||||
if Result.Y - 1 < Count then
|
||||
Result.X:=LogicalToPhysicalCol(self[Result.Y - 1], Result.Y, Result.X);
|
||||
Result.X := FLogPhysConvertor.LogicalToPhysical(p.y - 1, p.x);
|
||||
// if Result.Y - 1 < Count then
|
||||
// Result.X:=LogicalToPhysicalCol(self[Result.Y - 1], Result.Y, Result.X);
|
||||
end;
|
||||
|
||||
function TSynEditStrings.LogicalToPhysicalCol(const Line : String;
|
||||
@ -619,8 +788,9 @@ end;
|
||||
function TSynEditStrings.PhysicalToLogicalPos(const p : TPoint) : TPoint;
|
||||
begin
|
||||
Result := p;
|
||||
if (Result.Y>=1) and (Result.Y <= Count) then
|
||||
Result.X:=PhysicalToLogicalCol(self[Result.Y - 1], Result.Y - 1, Result.X);
|
||||
Result.X := FLogPhysConvertor.PhysicalToLogical(p.y - 1, p.x);
|
||||
// if (Result.Y>=1) and (Result.Y <= Count) then
|
||||
// Result.X:=PhysicalToLogicalCol(self[Result.Y - 1], Result.Y - 1, Result.X);
|
||||
end;
|
||||
|
||||
function TSynEditStrings.PhysicalToLogicalCol(const Line : string;
|
||||
@ -728,6 +898,16 @@ begin
|
||||
FSynStrings.IsUtf8 := AValue;
|
||||
end;
|
||||
|
||||
function TSynEditStringsLinked.GetTextChangeStamp: int64;
|
||||
begin
|
||||
Result := fSynStrings.GetTextChangeStamp;
|
||||
end;
|
||||
|
||||
function TSynEditStringsLinked.GetViewChangeStamp: int64;
|
||||
begin
|
||||
Result := fSynStrings.GetViewChangeStamp;
|
||||
end;
|
||||
|
||||
//Ranges
|
||||
function TSynEditStringsLinked.GetRange(Index: Pointer): TSynManagedStorageMem;
|
||||
begin
|
||||
|
@ -136,6 +136,7 @@ type
|
||||
protected
|
||||
function GetExpandedString(Index: integer): string; override;
|
||||
function GetLengthOfLongestLine: integer; override;
|
||||
function GetTextChangeStamp: int64; override;
|
||||
|
||||
function GetRedoList: TSynEditUndoList; override;
|
||||
function GetUndoList: TSynEditUndoList; override;
|
||||
@ -201,7 +202,6 @@ type
|
||||
property Flags[Index: Integer]: TSynEditStringFlags read GetFlags
|
||||
write SetFlags;
|
||||
property Modified: Boolean read FModified write SetModified;
|
||||
property TextChangeStamp: int64 read FTextChangeStamp;
|
||||
public
|
||||
property UndoList: TSynEditUndoList read GetUndoList write fUndoList;
|
||||
property RedoList: TSynEditUndoList read GetRedoList write fRedoList;
|
||||
@ -642,6 +642,11 @@ begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
function TSynEditStringList.GetTextChangeStamp: int64;
|
||||
begin
|
||||
Result := FTextChangeStamp;
|
||||
end;
|
||||
|
||||
function TSynEditStringList.GetRedoList: TSynEditUndoList;
|
||||
begin
|
||||
Result := fRedoList;
|
||||
|
@ -58,11 +58,13 @@ type
|
||||
FTabData: TSynEditStringTabData;
|
||||
FLastLineHasTab: Boolean; // Last line, parsed by GetPhysicalCharWidths
|
||||
FLastLinePhysLen: Integer;
|
||||
FViewChangeStamp: int64;
|
||||
procedure TextBufferChanged(Sender: TObject);
|
||||
procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
|
||||
function ExpandedString(Index: integer): string;
|
||||
function ExpandedStringLength(Index: integer): Integer;
|
||||
protected
|
||||
function GetViewChangeStamp: int64; override;
|
||||
function GetTabWidth : integer;
|
||||
procedure SetTabWidth(const AValue : integer);
|
||||
function GetExpandedString(Index: integer): string; override;
|
||||
@ -170,6 +172,10 @@ var
|
||||
begin
|
||||
if FTabWidth = AValue then exit;
|
||||
|
||||
{$PUSH}{$Q-}{$R-}
|
||||
FViewChangeStamp := FViewChangeStamp + 1;
|
||||
{$POP}
|
||||
|
||||
FTabWidth := AValue;
|
||||
FIndexOfLongestLine := -1;
|
||||
for i := 0 to Count - 1 do
|
||||
@ -177,6 +183,14 @@ begin
|
||||
FTabData[i] := LINE_LEN_UNKNOWN;
|
||||
end;
|
||||
|
||||
function TSynEditStringTabExpander.GetViewChangeStamp: int64;
|
||||
begin
|
||||
Result := inherited GetViewChangeStamp;
|
||||
{$PUSH}{$Q-}{$R-}
|
||||
Result := Result + FViewChangeStamp;
|
||||
{$POP}
|
||||
end;
|
||||
|
||||
procedure TSynEditStringTabExpander.TextBufferChanged(Sender: TObject);
|
||||
var
|
||||
Data: TSynEditStringTabData;
|
||||
|
@ -52,6 +52,7 @@ type
|
||||
fLockList : TStringList;
|
||||
FLineEdited: Boolean;
|
||||
FTempLineStringForPChar: String; // experimental; used by GetPChar;
|
||||
FViewChangeStamp: int64;
|
||||
procedure DoCaretChanged(Sender : TObject);
|
||||
procedure ListCleared(Sender: TObject);
|
||||
Procedure LinesChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
|
||||
@ -68,7 +69,9 @@ type
|
||||
procedure EditMoveToTrim(LogY, Len: Integer);
|
||||
procedure EditMoveFromTrim(LogY, Len: Integer);
|
||||
procedure UpdateLineText(LogY: Integer);
|
||||
procedure IncViewChangeStamp;
|
||||
protected
|
||||
function GetViewChangeStamp: int64; override;
|
||||
function GetExpandedString(Index: integer): string; override;
|
||||
function GetLengthOfLongestLine: integer; override;
|
||||
function Get(Index: integer): string; override;
|
||||
@ -378,6 +381,7 @@ begin
|
||||
then begin
|
||||
if (fLineIndex <> TSynEditCaret(Sender).LinePos - 1) then begin
|
||||
{$IFDEF SynTrimDebug}debugln(['--- Trimmer -- CarteChnaged - Clearing 1 ', ' fLineIndex=', fLineIndex, ' fSpaces=',length(fSpaces), 'newCaretYPos=',TSynEditCaret(Sender).LinePos]);{$ENDIF}
|
||||
if fSpaces <> '' then IncViewChangeStamp;
|
||||
fLineIndex := TSynEditCaret(Sender).LinePos - 1;
|
||||
fSpaces := '';
|
||||
end;
|
||||
@ -385,7 +389,7 @@ begin
|
||||
end;
|
||||
|
||||
FIsTrimming := True;
|
||||
SendNotification(senrLineChange, self, fLineIndex, 1);
|
||||
IncViewChangeStamp;
|
||||
if (fLineIndex <> TSynEditCaret(Sender).LinePos - 1) or
|
||||
(FTrimType = settIgnoreAll) then
|
||||
begin
|
||||
@ -393,6 +397,7 @@ begin
|
||||
CurUndoList.AppendToLastChange(TSynEditUndoTrimForget.Create(FLineIndex+1, FSpaces));
|
||||
i := length(FSpaces);
|
||||
fSpaces := '';
|
||||
SendNotification(senrLineChange, self, fLineIndex, 1);
|
||||
SendNotification(senrEditAction, self, FLineIndex+1, 0,
|
||||
1+length(fSynStrings[FLineIndex]), -i, '');
|
||||
end else begin
|
||||
@ -408,6 +413,7 @@ begin
|
||||
FSpaces := copy(FSpaces, 1, j);
|
||||
i := length(s);
|
||||
CurUndoList.AppendToLastChange(TSynEditUndoTrimForget.Create(FLineIndex+1, s));
|
||||
SendNotification(senrLineChange, self, fLineIndex, 1);
|
||||
SendNotification(senrEditAction, self, FLineIndex+1, 0,
|
||||
1+length(fSynStrings[FLineIndex]) + length(FSpaces), -i, '');
|
||||
end;
|
||||
@ -419,6 +425,7 @@ end;
|
||||
procedure TSynEditStringTrimmingList.ListCleared(Sender: TObject);
|
||||
begin
|
||||
{$IFDEF SynTrimDebug}debugln(['--- Trimmer -- LIST CLEARED ', ' fLineIndex=', fLineIndex, ' fSpaces=',length(fSpaces) ]);{$ENDIF}
|
||||
if fSpaces <> '' then IncViewChangeStamp;
|
||||
fLockList.Clear;
|
||||
fLineIndex:= -1;
|
||||
fSpaces := '';
|
||||
@ -445,6 +452,7 @@ var
|
||||
i, j: Integer;
|
||||
begin
|
||||
if (not fEnabled) then exit;
|
||||
IncViewChangeStamp;
|
||||
if fLockCount > 0 then begin
|
||||
{$IFDEF SynTrimDebug}debugln(['--- Trimmer -- Lines Changed (ins/del) locked ', ' fLineIndex=', fLineIndex, ' fSpaces=',length(fSpaces) ]);{$ENDIF}
|
||||
for i := fLockList.Count-1 downto 0 do begin
|
||||
@ -549,6 +557,7 @@ begin
|
||||
if Index <> fLineIndex then exit('');
|
||||
if (fLineIndex < 0) or (fLineIndex >= fSynStrings.Count)
|
||||
or (fLineText <> fSynStrings[fLineIndex]) then begin
|
||||
if fSpaces <> '' then IncViewChangeStamp;
|
||||
fSpaces:='';
|
||||
fLineText:='';
|
||||
end;
|
||||
@ -578,6 +587,7 @@ var
|
||||
begin
|
||||
if (not fEnabled) then exit;
|
||||
FIsTrimming := True;
|
||||
IncViewChangeStamp;
|
||||
{$IFDEF SynTrimDebug}debugln(['--- Trimmer -- TrimAfterLock', ' fLineIndex=', fLineIndex, ' fSpaces=',length(fSpaces), ' Index=', Index, ' LockList=',fLockList.CommaText]);{$ENDIF}
|
||||
i := fLockList.IndexOfObject(TObject(Pointer(PtrUInt(fLineIndex))));
|
||||
if i >= 0 then begin
|
||||
@ -760,6 +770,7 @@ begin
|
||||
copy(s,1, LogX - 1) + AText + copy(s, LogX, length(s)),
|
||||
fSynStrings.Strings[LogY - 1]);
|
||||
CurUndoList.AddChange(TSynEditUndoTrimInsert.Create(LogX, LogY, Length(AText)));
|
||||
IncViewChangeStamp;
|
||||
end;
|
||||
|
||||
function TSynEditStringTrimmingList.EditDeleteTrim(LogX, LogY, ByteLen:
|
||||
@ -777,6 +788,7 @@ begin
|
||||
fSynStrings.Strings[LogY - 1]);
|
||||
if Result <> '' then
|
||||
CurUndoList.AddChange(TSynEditUndoTrimDelete.Create(LogX, LogY, Result));
|
||||
IncViewChangeStamp;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringTrimmingList.EditMoveToTrim(LogY, Len: Integer);
|
||||
@ -792,6 +804,7 @@ begin
|
||||
StoreSpacesForLine(LogY - 1, s, t);
|
||||
fSynStrings[LogY - 1] := t;
|
||||
CurUndoList.AddChange(TSynEditUndoTrimMoveTo.Create(LogY, Len));
|
||||
IncViewChangeStamp;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringTrimmingList.EditMoveFromTrim(LogY, Len: Integer);
|
||||
@ -807,6 +820,7 @@ begin
|
||||
StoreSpacesForLine(LogY - 1, s, t);
|
||||
fSynStrings[LogY - 1] := t;
|
||||
CurUndoList.AddChange(TSynEditUndoTrimMoveFrom.Create(LogY, Len));
|
||||
IncViewChangeStamp;
|
||||
end;
|
||||
|
||||
procedure TSynEditStringTrimmingList.UpdateLineText(LogY: Integer);
|
||||
@ -815,6 +829,21 @@ begin
|
||||
fLineText := fSynStrings[LogY - 1];
|
||||
end;
|
||||
|
||||
procedure TSynEditStringTrimmingList.IncViewChangeStamp;
|
||||
begin
|
||||
{$PUSH}{$Q-}{$R-}
|
||||
FViewChangeStamp := FViewChangeStamp + 1;
|
||||
{$POP}
|
||||
end;
|
||||
|
||||
function TSynEditStringTrimmingList.GetViewChangeStamp: int64;
|
||||
begin
|
||||
Result := inherited GetViewChangeStamp;
|
||||
{$PUSH}{$Q-}{$R-}
|
||||
Result := Result + FViewChangeStamp;
|
||||
{$POP}
|
||||
end;
|
||||
|
||||
procedure TSynEditStringTrimmingList.EditInsert(LogX, LogY: Integer; AText: String);
|
||||
var
|
||||
t: String;
|
||||
|
@ -27,6 +27,7 @@ type
|
||||
published
|
||||
procedure TestEditEmpty;
|
||||
procedure TestEditTabs;
|
||||
procedure TestEditPhysicalLogical;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -173,6 +174,81 @@ begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TTestBasicSynEdit.TestEditPhysicalLogical;
|
||||
|
||||
procedure TestPhysLog(name: string; y, x, expX: integer);
|
||||
var gotX: Integer;
|
||||
begin
|
||||
name := name + ' y='+inttostr(y)+' x='+inttostr(x);
|
||||
gotX := SynEdit.PhysicalToLogicalPos(Point(x, y)).x;
|
||||
AssertEquals(name+' PhysicalToLogicalPos', expX, gotX);
|
||||
gotX := SynEdit.PhysicalToLogicalCol(SynEdit.Lines[y-1], y-1, x);
|
||||
AssertEquals(name+' PhysicalToLogicalCol', expX, gotX);
|
||||
end;
|
||||
|
||||
procedure TestLogPhys(name: string; y, x, expX: integer);
|
||||
var gotX: Integer;
|
||||
begin
|
||||
name := name + ' y='+inttostr(y)+' x='+inttostr(x);
|
||||
gotX := SynEdit.LogicalToPhysicalPos(Point(x, y)).x;
|
||||
AssertEquals(name+' LogicalToPhysicalPos', expX, gotX);
|
||||
gotX := SynEdit.LogicalToPhysicalCol(SynEdit.Lines[y-1], y-1, x);
|
||||
AssertEquals(name+' LogicalToPhysicalCol', expX, gotX);
|
||||
end;
|
||||
|
||||
begin
|
||||
ReCreateEdit;
|
||||
SynEdit.TabWidth := 6;
|
||||
|
||||
SetLines(['abc', ' ääX', #9'mn', 'abc'#9'de', #9'Xää.']);
|
||||
|
||||
TestLogPhys('simple line (abc)', 1, 1, 1);
|
||||
TestLogPhys('simple line (abc)', 1, 2, 2);
|
||||
TestLogPhys('simple line (abc)', 1, 4, 4);
|
||||
TestLogPhys('simple line (abc)', 1, 5, 5);
|
||||
TestLogPhys('simple line (abc)', 1, 6, 6);
|
||||
TestLogPhys('line with 2byte-char', 2, 1, 1);
|
||||
TestLogPhys('line with 2byte-char', 2, 2, 2);
|
||||
TestLogPhys('line with 2byte-char', 2, 4, 3); // after ae
|
||||
TestLogPhys('line with 2byte-char', 2, 6, 4);
|
||||
TestLogPhys('line with 2byte-char', 2, 7, 5);
|
||||
TestLogPhys('line with 2byte-char', 2, 8, 6);
|
||||
TestLogPhys('line with 2byte-char', 2, 11, 9);
|
||||
TestLogPhys('line with tab (start)', 3, 1, 1);
|
||||
TestLogPhys('line with tab (start)', 3, 2, 7);
|
||||
TestLogPhys('line with tab (middle)', 4, 3, 3);
|
||||
TestLogPhys('line with tab (middle)', 4, 4, 4); // before tab
|
||||
TestLogPhys('line with tab (middle)', 4, 5, 7); // after tab
|
||||
TestLogPhys('line with tab (middle)', 4, 6, 8);
|
||||
TestLogPhys('line with tab (middle)', 4, 9, 11);
|
||||
TestLogPhys('line with tab (start) + 2bc', 5, 1, 1);
|
||||
TestLogPhys('line with tab (start) + 2bc', 5, 2, 7);
|
||||
TestLogPhys('line with tab (start) + 2bc', 5, 3, 8);
|
||||
TestLogPhys('line with tab (start) + 2bc', 5, 5, 9);
|
||||
|
||||
TestPhysLog('simple line (abc)', 1, 1, 1);
|
||||
TestPhysLog('simple line (abc)', 1, 2, 2);
|
||||
TestPhysLog('simple line (abc)', 1, 4, 4);
|
||||
TestPhysLog('simple line (abc)', 1, 5, 5);
|
||||
TestPhysLog('simple line (abc)', 1, 6, 6);
|
||||
TestPhysLog('line with 2byte-char', 2, 1, 1);
|
||||
TestPhysLog('line with 2byte-char', 2, 2, 2);
|
||||
TestPhysLog('line with 2byte-char', 2, 3, 4);
|
||||
TestPhysLog('line with 2byte-char', 2, 4, 6);
|
||||
TestPhysLog('line with 2byte-char', 2, 5, 7);
|
||||
TestPhysLog('line with 2byte-char', 2, 6, 8);
|
||||
TestPhysLog('line with 2byte-char', 2, 7, 9);
|
||||
TestPhysLog('line with tab (start)', 3, 1, 1);
|
||||
TestPhysLog('line with tab (start)', 3, 2, 1);
|
||||
TestPhysLog('line with tab (start)', 3, 5, 1);
|
||||
TestPhysLog('line with tab (start)', 3, 6, 1);
|
||||
TestPhysLog('line with tab (start)', 3, 7, 2);
|
||||
TestPhysLog('line with tab (start)', 3, 8, 3);
|
||||
TestPhysLog('line with tab (start)', 3, 9, 4);
|
||||
TestPhysLog('line with tab (start)', 3, 11, 6);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
initialization
|
||||
|
Loading…
Reference in New Issue
Block a user