SynEdit: fixed caret-auto-move for lines with tab. (required by syncro-edit, shared-edit)

git-svn-id: trunk@30087 -
This commit is contained in:
martin 2011-03-30 16:24:10 +00:00
parent 9566d1e771
commit 6b7a173ac3
5 changed files with 93 additions and 4 deletions

View File

@ -176,6 +176,7 @@ type
FLinePos: Integer; // 1 based
FCharPos: Integer; // 1 based
FLastCharPos: Integer; // used by KeepCaretX
FBytePos, FBytePosOffset: Integer; // 1 based
FOldLinePos: Integer; // 1 based
FOldCharPos: Integer; // 1 based
FAdjustToNextChar: Boolean;
@ -185,6 +186,7 @@ type
FTouched: Boolean;
procedure AdjustToChar;
procedure UpdateBytePos;
function GetOldLineBytePos: TPoint;
function GetOldLineCharPos: TPoint;
procedure InternalSetLineCharPos(NewLine, NewCharPos: Integer;
@ -436,6 +438,8 @@ end;
procedure TSynEditCaret.IncAutoMoveOnEdit;
begin
if FAutoMoveOnEdit =0 then
UpdateBytePos;;
inc(FAutoMoveOnEdit);
end;
@ -511,6 +515,11 @@ begin
end;
end;
procedure TSynEditCaret.UpdateBytePos;
begin
FBytePos := FLines.LogPhysConvertor.PhysicalToLogical(FLinePos-1, FCharPos, FBytePosOffset);
end;
function TSynEditCaret.GetOldLineBytePos: TPoint;
begin
Result := FLines.PhysicalToLogicalPos(OldLineCharPos);
@ -589,6 +598,8 @@ begin
AdjustToChar;
if (not KeepLastCharPos) or (not FKeepCaretX) then
FLastCharPos := FCharPos;
if FAutoMoveOnEdit <> 0 then
UpdateBytePos;
end;
finally
Unlock;
@ -703,10 +714,17 @@ procedure TSynEditCaret.DoLinesEdited(Sender: TSynEditStrings; aLinePos, aBytePo
end;
end;
var
p: TPoint;
begin
if FAutoMoveOnEdit > 0 then begin
IncForcePastEOL;
LineBytePos := AdjustPoint(LineBytePos);
p := AdjustPoint(Point(FBytePos, FLinePos));
p.x := FLines.LogPhysConvertor.LogicalToPhysical(p.y-1, p.x, FBytePosOffset);
FBytePos := -1;
LineCharPos := p;
if FBytePos < 0 then
UpdateBytePos;
DecForcePastEOL;
end;
end;

View File

@ -242,6 +242,7 @@ type
function PhysicalToLogicalPos(const p: TPoint): TPoint;
function PhysicalToLogicalCol(const Line: string;
Index, PhysicalPos: integer): integer; virtual;
property LogPhysConvertor :TSynLogicalPhysicalConvertor read FLogPhysConvertor;
public
procedure EditInsert(LogX, LogY: Integer; AText: String); virtual; abstract;
function EditDelete(LogX, LogY, ByteLen: Integer): String; virtual; abstract;
@ -469,11 +470,13 @@ procedure TSynLogicalPhysicalConvertor.PrepareWidthsForLine(AIndex: Integer;
var
LineLen: Integer;
Line: PChar;
//const dbg_cnt: integer = 0;
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)),')']);
//dbg_cnt := dbg_cnt + 1;
exit;
end;
@ -498,6 +501,7 @@ begin
//else begin
// debugln(['**************** COMPUTING widths: ', AIndex,' (',dbgs(Pointer(self)),') alloc=',FCurrentWidthsAlloc]);
end;
//debugln(['**************** NEW for index:: ', AIndex,' (',dbgs(Pointer(self)),') after index: ', FCurrentLine, ' used ', dbg_cnt,' times // old-alloc=', FCurrentWidthsAlloc, ' new-len=',LineLen, ' viewchg:',dbgs(not(FViewChangeStamp=FLines.ViewChangeStamp)),' txtchg:',dbgs(not(FTextChangeStamp=FLines.TextChangeStamp))]); dbg_cnt := 0;
FCurrentWidthsLen := LineLen;
if LineLen > 0 then

View File

@ -587,18 +587,23 @@ 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
if fSpaces <> fLockList[i] then
IncViewChangeStamp;
fSpaces:= fLockList[i];
if (fLineIndex >= 0) and (fLineIndex < fSynStrings.Count) then
fLineText := fSynStrings[fLineIndex];
fLockList.Delete(i);
DoCaretChanged(fCaret);
end;
end
else if fSpaces <> '' then
IncViewChangeStamp;
FIsTrimming := True;
BeginUpdate;
if fLockList.Count > 0 then
IncViewChangeStamp;
try
for i := 0 to fLockList.Count-1 do begin
index := Integer(PtrUInt(Pointer(fLockList.Objects[i])));

View File

@ -7,7 +7,7 @@ interface
uses
Classes, SysUtils, Forms, fpcunit, SynEdit, LCLType, LCLProc, math,
SynEditTypes, Clipbrd;
SynEditTypes, SynEditPointClasses, Clipbrd;
type
@ -24,6 +24,7 @@ type
property ViewedTextBuffer;
property TextBuffer;
property TextView; // foldedview
property CaretObj: TSynEditCaret read GetCaretObj;
end;
{ TTestBase }
@ -318,6 +319,7 @@ end;
procedure TTestBase.TestFail(Name, Func, Expect, Got: String; Result: Boolean = False);
begin
if Result then exit;
DebugLn(DbgStr(SynEdit.Text));
if BaseTestName <> '' then
Fail(Format('%s: %s (%s)%sExpected: %s%s Got: %s', [BaseTestName, Name, Func, LineEnding, Expect, LineEnding, Got]))
else

View File

@ -28,6 +28,7 @@ type
procedure TestEditEmpty;
procedure TestEditTabs;
procedure TestEditPhysicalLogical;
procedure TestCaretAutoMove;
end;
implementation
@ -249,6 +250,65 @@ begin
end;
procedure TTestBasicSynEdit.TestCaretAutoMove;
procedure DoTest(name: string; y, x, insertY, insertX, InsertY2, InsertX2: integer;
txt: string; expY, expX: Integer);
begin
name := name + ' y='+inttostr(y)+' x='+inttostr(x);
if y > 0 then begin
ReCreateEdit;
SynEdit.TabWidth := 6;
SetLines(['x', 'abc', ' ääX', #9'mn', 'abc'#9'de', #9'Xää.']);
SynEdit.CaretXY := Point(x, y);
end;
SynEdit.TextBetweenPointsEx[Point(insertX, insertY), point(insertX2, InsertY2), scamAdjust]
:= txt;
debugln(dbgstr(SynEdit.Text));
TestIsCaretPhys(name, expX, expY);
end;
const
cr = LineEnding;
begin
DoTest('simple insert', 2,2, 2,1, 2,1, 'X', 2,3);
DoTest('simple insert CR', 2,2, 2,1, 2,1, 'X'+cr, 3,2);
DoTest('simple insert CR+', 2,2, 2,1, 2,1, cr+'X', 3,3);
DoTest('simple delete', 2,2, 2,1, 2,2, '', 2,1);
DoTest('simple delete CR', 2,2, 1,2, 2,1, '', 1,3);
DoTest('+simple delete CR', 2,2, 1,1, 2,1, '', 1,2);
DoTest('simple insert (eol)', 2,4, 2,1, 2,1, 'X', 2,5);
DoTest('simple insert (past eol)', 2,7, 2,1, 2,1, 'X', 2,8);
DoTest('insert with tab', 4,8, 4,1, 4,1, 'X', 4,8);
DoTest('insert with tab (cont)', -4,8, 4,2, 4,2, 'Y', 4,8);
DoTest('insert with tab (cont)', -4,8, 4,3, 4,3, 'abc', 4,8);
DoTest('insert with tab (cont)', -4,8, 4,6, 4,6, 'Z', 4,14);
DoTest('insert with tab (cont)', -4,8, 4,7, 4,7, '.', 4,14);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,14);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,8);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,8);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,8);
SynEdit.CaretObj.IncAutoMoveOnEdit;
DoTest('insert with tab (am-block)', 4,8, 4,1, 4,1, 'X', 4,8);
DoTest('insert with tab (am-block) (cont)', -4,8, 4,2, 4,2, 'Y', 4,8);
DoTest('insert with tab (am-block) (cont)', -4,8, 4,3, 4,3, 'abc', 4,8);
DoTest('insert with tab (am-block) (cont)', -4,8, 4,6, 4,6, 'Z', 4,14);
DoTest('insert with tab (am-block) (cont)', -4,8, 4,7, 4,7, '.', 4,14);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,14);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,8);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,8);
DoTest('delete with tab (cont)', -4,8, 4,1, 4,2, '', 4,8);
SynEdit.CaretObj.DecAutoMoveOnEdit;
end;
initialization