SYnEdit: multi caret, paint - fix home key

git-svn-id: trunk@48319 -
This commit is contained in:
martin 2015-03-12 23:34:59 +00:00
parent d48e548ada
commit 6bb6966509
2 changed files with 306 additions and 80 deletions

View File

@ -8,7 +8,7 @@ unit SynPluginMultiCaret;
{$IfDef SynMultiCaretAssert} {$IfDef SynMultiCaretAssert}
{$ASSERTIONS on} {$ASSERTIONS on}
{$ENDIF} {$ENDIF}
{ $INLINE off}
interface interface
uses uses
@ -74,7 +74,7 @@ type
property ScreenCaret[Index: Integer]: TSynPluginMultiCaretVisual read GetScreenCaret; default; property ScreenCaret[Index: Integer]: TSynPluginMultiCaretVisual read GetScreenCaret; default;
end; end;
TCaretFlag = (cfMainCaret, cfNoneVisual, cfAddDuplicate); TCaretFlag = (cfMainCaret, cfNoneVisual, cfAddDuplicate, cfIterationDone);
TCaretFlags = set of TCaretFlag; TCaretFlags = set of TCaretFlag;
{ TSynPluginMultiCaretList } { TSynPluginMultiCaretList }
@ -89,6 +89,7 @@ type
Flags: TCaretFlags; Flags: TCaretFlags;
Visual: TSynPluginMultiCaretVisual; Visual: TSynPluginMultiCaretVisual;
end; end;
PCaretData = ^TCaretData;
private private
FLowIndex, FHighIndex: Integer; FLowIndex, FHighIndex: Integer;
FMainCaretIndex: Integer; FMainCaretIndex: Integer;
@ -114,7 +115,7 @@ type
function InternalRemoveCaretEx(RawIndex: Integer; AlternativeRawIndex: Integer = -1): Integer; function InternalRemoveCaretEx(RawIndex: Integer; AlternativeRawIndex: Integer = -1): Integer;
function InternalRemoveCaret(RawIndex: Integer): integer; function InternalRemoveCaret(RawIndex: Integer): integer;
procedure AdjustAfterChange(RawIndex: Integer); procedure AdjustAfterChange(RawIndex: Integer); inline;
public public
constructor Create; constructor Create;
function AddCaret(X, Y, Offs: Integer; flags: TCaretFlags = []; PhysX: Integer = -1): Integer; function AddCaret(X, Y, Offs: Integer; flags: TCaretFlags = []; PhysX: Integer = -1): Integer;
@ -137,6 +138,32 @@ type
property Visual[Index: Integer]: TSynPluginMultiCaretVisual read GetVisual write SetVisual; property Visual[Index: Integer]: TSynPluginMultiCaretVisual read GetVisual write SetVisual;
property Flags[Index: Integer]: TCaretFlags read GetFlags; property Flags[Index: Integer]: TCaretFlags read GetFlags;
property MainCaretIndex: Integer read GetMainCaretIndex; property MainCaretIndex: Integer read GetMainCaretIndex;
private
FCurrenCaret, FBeforeNextCaret: PCaretData;
FIterationDoneCount: Integer;
FLowCaret, FHighCaret: PCaretData; // used in AdjustAfterChange
FIteratoreMode: (mciNone, mciUp, mciDown);
function GetCurrentCaretFull: TLogCaretPoint; inline;
function GetCurrentCaretKeepX: Integer; inline;
procedure SetCurrentCaretFull(AValue: TLogCaretPoint); inline;
procedure SetCurrentCaretKeepX(AValue: Integer); inline;
procedure AdjustAfterChange(ACaret: PCaretData);
public
// During iteration no calls to add/remove are allowed
procedure StartIteratorAtFirst; // valid after first call to IterateNextUp
function IterateNextUp: Boolean; inline;
procedure StartIteratorAtLast;
function IterateNextDown: Boolean; inline;
//procedure AbortIterator;
property CurrentCaretFull: TLogCaretPoint read GetCurrentCaretFull write SetCurrentCaretFull;
property CurrentCaretKeepX: Integer read GetCurrentCaretKeepX write SetCurrentCaretKeepX;
//property CurrentCaret: TPoint read GetCurrentCaret write SetCurrentCaret;
//property CurrentCaretX: Integer read GetCurrentCaretX write SetCurrentCaretX;
//property CurrentCaretOffs: Integer read GetCurrentCaretOffs write SetCurrentCaretOffs;
//property CurrentCaretY: Integer read GetCurrentCaretY write SetCurrentCaretY;
end; end;
{ TSynPluginMultiCaretBase } { TSynPluginMultiCaretBase }
@ -705,6 +732,7 @@ end;
function TSynPluginMultiCaretList.InternalRemoveCaret(RawIndex: Integer): integer; function TSynPluginMultiCaretList.InternalRemoveCaret(RawIndex: Integer): integer;
begin begin
assert(FIteratoreMode=mciNone, 'TSynPluginMultiCaretList.AddCaret: FIteratoreMode=mciNone');
assert((RawIndex>=FLowIndex) and (RawIndex <= FHighIndex), 'TSynPluginMultiCaretList.InternalRemoveCaret: (RawIndex>=FLowIndex) and (RawIndex <= FHighIndex)'); assert((RawIndex>=FLowIndex) and (RawIndex <= FHighIndex), 'TSynPluginMultiCaretList.InternalRemoveCaret: (RawIndex>=FLowIndex) and (RawIndex <= FHighIndex)');
Result := 0; // change to LowCaret .. RawIndex Result := 0; // change to LowCaret .. RawIndex
@ -726,7 +754,7 @@ begin
inc(FLowIndex); inc(FLowIndex);
if RawIndex > FMainCaretIndex then if RawIndex > FMainCaretIndex then
inc(FMainCaretIndex); inc(FMainCaretIndex);
Result := 1; Result := 1; // FLowIndex was increasde by 1;
end; end;
//debugln(SynMCaretDebug, ['TSynPluginMultiCaretList.InternalRemoveCaret ', RawIndex, ' , ', count]); //debugln(SynMCaretDebug, ['TSynPluginMultiCaretList.InternalRemoveCaret ', RawIndex, ' , ', count]);
@ -734,58 +762,13 @@ end;
procedure TSynPluginMultiCaretList.AdjustAfterChange(RawIndex: Integer); procedure TSynPluginMultiCaretList.AdjustAfterChange(RawIndex: Integer);
var var
NewIdx, y, x: Integer; NewIdx, y, x, o: Integer;
v: TCaretData; v: TCaretData;
begin begin
assert((RawIndex>=FLowIndex) and (RawIndex <= FHighIndex), 'TSynPluginMultiCaretList.AdjustAfterChange: (Index>=FLowIndex) and (Index <= FHighIndex)'); assert(FIteratoreMode=mciNone, 'TSynPluginMultiCaretList.AddCaret: FIteratoreMode=mciNone');
NewIdx := RawIndex; FLowCaret := @FCarets[FLowIndex];
y := FCarets[RawIndex].y; FHighCaret := @FCarets[FHighIndex];
x := FCarets[RawIndex].x; AdjustAfterChange(@FCarets[RawIndex]);
if (RawIndex > FLowIndex) and
((y < FCarets[RawIndex-1].y) or ((y = FCarets[RawIndex-1].y) and (x <= FCarets[RawIndex-1].x)))
then begin
if (RawIndex-1 > FLowIndex) and
((y < FCarets[RawIndex-2].y) or ((y = FCarets[RawIndex-2].y) and (x < FCarets[RawIndex-2].x)))
then
NewIdx := FindEqOrNextCaretRawIdx(x,y, FLowIndex, RawIndex - 2)
else
NewIdx := RawIndex-1;
if (y = FCarets[NewIdx].y) and (x = FCarets[NewIdx].x) then begin
if FMergeLock = 0 then
InternalRemoveCaretEx(RawIndex, NewIdx);
exit;
end;
v := FCarets[RawIndex];
{$IfDef SynMultiCaretDebug}
debugln(SynMCaretDebug, ['TSynPluginMultiCaretList.AdjustAfterChange ', NewIdx, ' ',RawIndex]);
{$EndIf}
Move(FCarets[NewIdx], FCarets[NewIdx+1], (RawIndex-NewIdx) * SizeOf(FCarets[0]));
FCarets[NewIdx] := v;
end
else
if (RawIndex < FHighIndex) and
((y > FCarets[RawIndex+1].y) or ((y = FCarets[RawIndex+1].y) and (x >= FCarets[RawIndex+1].x)))
then begin
if (RawIndex+1 < FHighIndex) and
((y > FCarets[RawIndex+2].y) or ((y = FCarets[RawIndex+2].y) and (x > FCarets[RawIndex+2].x)))
then
NewIdx := FindEqOrNextCaretRawIdx(x,y, RawIndex + 2, FHighIndex)
else
NewIdx := RawIndex+1;
if (y = FCarets[NewIdx].y) and (x = FCarets[NewIdx].x) then begin
if FMergeLock = 0 then
InternalRemoveCaretEx(RawIndex, NewIdx);
exit;
end;
v := FCarets[RawIndex];
{$IfDef SynMultiCaretDebug}
debugln(SynMCaretDebug, ['TSynPluginMultiCaretList.AdjustAfterChange ', NewIdx, ' ',RawIndex]);
{$EndIf}
Move(FCarets[RawIndex+1], FCarets[RawIndex], (NewIdx-RawIndex) * SizeOf(FCarets[0]));
FCarets[NewIdx] := v;
end;
end; end;
constructor TSynPluginMultiCaretList.Create; constructor TSynPluginMultiCaretList.Create;
@ -801,6 +784,7 @@ var
NewCarets: Array of TCaretData; NewCarets: Array of TCaretData;
Len, AddLen, i, Middle: Integer; Len, AddLen, i, Middle: Integer;
begin begin
assert(FIteratoreMode=mciNone, 'TSynPluginMultiCaretList.AddCaret: FIteratoreMode=mciNone');
Result := FindEqOrNextCaretRawIdx(x, y, Offs); Result := FindEqOrNextCaretRawIdx(x, y, Offs);
if Result < FLowIndex then if Result < FLowIndex then
Result := FLowIndex; Result := FLowIndex;
@ -882,6 +866,7 @@ end;
procedure TSynPluginMultiCaretList.RemoveCaret(Index: Integer); procedure TSynPluginMultiCaretList.RemoveCaret(Index: Integer);
begin begin
assert(FIteratoreMode=mciNone, 'TSynPluginMultiCaretList.RemoveCaret: FIteratoreMode=mciNone');
InternalRemoveCaret(Index+FLowIndex); InternalRemoveCaret(Index+FLowIndex);
end; end;
@ -889,6 +874,7 @@ procedure TSynPluginMultiCaretList.Clear(AFreeVisual: Boolean);
var var
i: Integer; i: Integer;
begin begin
assert(FIteratoreMode=mciNone, 'TSynPluginMultiCaretList.Clear: FIteratoreMode=mciNone');
if AFreeVisual then if AFreeVisual then
begin begin
for i := FLowIndex to FHighIndex do for i := FLowIndex to FHighIndex do
@ -1047,6 +1033,208 @@ begin
dec(FMergeLock); dec(FMergeLock);
end; end;
function TSynPluginMultiCaretList.GetCurrentCaretFull: TLogCaretPoint;
begin
Result.X := FCurrenCaret^.x;
Result.Y := FCurrenCaret^.y;
Result.Offs := FCurrenCaret^.offs;
end;
function TSynPluginMultiCaretList.GetCurrentCaretKeepX: Integer;
begin
Result := FCurrenCaret^.KeepX;
end;
procedure TSynPluginMultiCaretList.SetCurrentCaretFull(AValue: TLogCaretPoint);
begin
FCurrenCaret^.x := AValue.X;
FCurrenCaret^.y := AValue.Y;
FCurrenCaret^.offs := AValue.Offs;
AdjustAfterChange(FCurrenCaret);
end;
procedure TSynPluginMultiCaretList.SetCurrentCaretKeepX(AValue: Integer);
begin
FCurrenCaret^.KeepX := AValue;
AdjustAfterChange(FCurrenCaret);
end;
procedure TSynPluginMultiCaretList.AdjustAfterChange(ACaret: PCaretData);
function ToRawIndex(C: PCaretData): Integer;
begin
Result := (C - @FCarets[0]) div SizeOf(FCarets[0]);
end;
var
NewCaretPos, HelpCaretPos: PCaretData;
NewCaretIdx, y, x, o: Integer;
v: TCaretData;
begin
assert((ACaret>=FLowCaret) and (ACaret <= FHighCaret) and (ACaret <> nil), 'TSynPluginMultiCaretList.AdjustAfterChange: (ACaret>=FLowCaret) and (ACaret <= FHighCaret)');
// if iterating then this must only be called with fcurrentcaret
assert((FIteratoreMode=mciNone) or ((ACaret = FCurrenCaret)), 'TSynPluginMultiCaretList.AdjustAfterChange: (FIteratoreMode=mciNone) or (ACaret = FCurrenCaret)');
y := ACaret^.y;
x := ACaret^.x;
o := ACaret^.offs;
if (ACaret > FLowCaret) then begin
NewCaretPos := ACaret - 1;
if (y < NewCaretPos^.y) or
( (y = NewCaretPos^.y) and
( (x < NewCaretPos^.x) or ( (x = NewCaretPos^.x) and (o <= NewCaretPos^.offs) ) )
)
then begin
HelpCaretPos := NewCaretPos - 1;
if (HelpCaretPos >= FLowCaret) and
( (y < HelpCaretPos^.y) or
( (y = HelpCaretPos^.y) and
( (x < HelpCaretPos^.x) or ( (x = HelpCaretPos^.x) and (o < HelpCaretPos^.offs) ) )
) )
then begin
NewCaretIdx := FindEqOrNextCaretRawIdx(x,y,o, FLowIndex, ToRawIndex(HelpCaretPos));
NewCaretPos := @FCarets[NewCaretIdx];
end;
if (y = NewCaretPos^.y) and (x = NewCaretPos^.x) and (o = NewCaretPos^.offs) then begin
if FMergeLock = 0 then
InternalRemoveCaretEx(ToRawIndex(ACaret), ToRawIndex(NewCaretPos));
exit;
end;
v := ACaret^;
{$IfDef SynMultiCaretDebug}
debugln(SynMCaretDebug, ['TSynPluginMultiCaretList.AdjustAfterChange ', ToRawIndex(NewCaretPos), ' ',ToRawIndex(ACaret)]);
{$EndIf}
Move(NewCaretPos^, (NewCaretPos+1)^, Pointer(ACaret)-Pointer(NewCaretPos));
NewCaretPos^ := v;
assert(FBeforeNextCaret=nil, 'TSynPluginMultiCaretList.AdjustAfterChange: FBeforeNextCaret=nil');
FCurrenCaret := NewCaretPos; // move down
case FIteratoreMode of
mciUp: FBeforeNextCaret := ACaret; // continue at ACaret+1;
mciDown: begin
FBeforeNextCaret := ACaret + 1; // continue at ACaret;
Include(FCurrenCaret^.Flags, cfIterationDone);
inc(FIterationDoneCount);
end;
end;
end
end
else
if (ACaret < FHighCaret) then begin
NewCaretPos := ACaret + 1;
if (y > NewCaretPos^.y) or
( (y = NewCaretPos^.y) and
( (x > NewCaretPos^.x) or ( (x = NewCaretPos^.x) and (o >= NewCaretPos^.offs) ) )
)
then begin
HelpCaretPos := NewCaretPos + 1;
if (HelpCaretPos <= FHighCaret) and
( (y > HelpCaretPos^.y) or
( (y = HelpCaretPos^.y) and
( (x > HelpCaretPos^.x) or ( (x = HelpCaretPos^.x) and (o > HelpCaretPos^.offs) ) )
) )
then begin
NewCaretIdx := FindEqOrNextCaretRawIdx(x,y,o, ToRawIndex(HelpCaretPos), FHighIndex);
NewCaretPos := @FCarets[NewCaretIdx];
end;
if (y = NewCaretPos^.y) and (x = NewCaretPos^.x) and (o = NewCaretPos^.offs) then begin
if FMergeLock = 0 then
InternalRemoveCaretEx(ToRawIndex(ACaret), ToRawIndex(NewCaretPos));
exit;
end;
v := ACaret^;
{$IfDef SynMultiCaretDebug}
debugln(SynMCaretDebug, ['TSynPluginMultiCaretList.AdjustAfterChange ', ToRawIndex(NewCaretPos), ' ',ToRawIndex(ACaret)]);
{$EndIf}
Move((ACaret+1)^, ACaret^, Pointer(NewCaretPos)-Pointer(ACaret));
NewCaretPos^ := v;
assert(FBeforeNextCaret=nil, 'TSynPluginMultiCaretList.AdjustAfterChange: FBeforeNextCaret=nil');
FCurrenCaret := NewCaretPos; // move down
case FIteratoreMode of
mciDown: FBeforeNextCaret := ACaret; // continue at ACaret-1;
mciUp: begin
FBeforeNextCaret := ACaret - 1; // continue at ACaret;
Include(FCurrenCaret^.Flags, cfIterationDone);
inc(FIterationDoneCount);
end;
end;
end;
end;
end;
procedure TSynPluginMultiCaretList.StartIteratorAtFirst;
begin
FBeforeNextCaret := nil;
if Length(FCarets) = 0 then begin
FLowCaret := nil;
FHighCaret := nil;
FCurrenCaret := nil;
exit;
end;
FLowCaret := @FCarets[FLowIndex];
FHighCaret := @FCarets[FHighIndex];
FCurrenCaret := FLowCaret - 1;
FIteratoreMode := mciUp;
end;
function TSynPluginMultiCaretList.IterateNextUp: Boolean;
begin
if FBeforeNextCaret <> nil then begin
FCurrenCaret := FBeforeNextCaret;
FBeforeNextCaret := nil;
end;
repeat
Result := FCurrenCaret < FHighCaret;
if not Result then begin
FIteratoreMode := mciNone;
assert(FIterationDoneCount = 0, 'TSynPluginMultiCaretList.IterateNextUp: FIterationDoneCount = 0');
exit;
end;
inc(FCurrenCaret);
if not(cfIterationDone in FCurrenCaret^.Flags) then
break;
Exclude(FCurrenCaret^.Flags, cfIterationDone);
dec(FIterationDoneCount);
until False;
end;
procedure TSynPluginMultiCaretList.StartIteratorAtLast;
begin
FBeforeNextCaret := nil;
if Length(FCarets) = 0 then begin
FLowCaret := nil;
FHighCaret := nil;
FCurrenCaret := nil;
exit;
end;
FLowCaret := @FCarets[FLowIndex];
FHighCaret := @FCarets[FHighIndex];
FCurrenCaret := FHighCaret + 1;
FIteratoreMode := mciDown;
end;
function TSynPluginMultiCaretList.IterateNextDown: Boolean;
begin
if FBeforeNextCaret <> nil then begin
FCurrenCaret := FBeforeNextCaret;
FBeforeNextCaret := nil;
end;
repeat
Result := FCurrenCaret > FLowCaret;
if not Result then begin
FIteratoreMode := mciNone;
assert(FIterationDoneCount = 0, 'TSynPluginMultiCaretList.IterateNextDown: FIterationDoneCount = 0');
exit;
end;
dec(FCurrenCaret);
if not(cfIterationDone in FCurrenCaret^.Flags) then
break;
Exclude(FCurrenCaret^.Flags, cfIterationDone);
dec(FIterationDoneCount);
until False;
end;
{ TSynPluginMultiCaretBase } { TSynPluginMultiCaretBase }
procedure TSynPluginMultiCaretBase.DoBoundsChanged(Sender: TObject); procedure TSynPluginMultiCaretBase.DoBoundsChanged(Sender: TObject);
@ -1271,9 +1459,7 @@ begin
exit; exit;
end; end;
if (eoNoCaret in Editor.Options) or if (eoNoCaret in Editor.Options) then begin
not((eoPersistentCaret in Editor.Options) or Editor.Focused)
then begin
Carets.Visual[Result] := nil; Carets.Visual[Result] := nil;
exit; exit;
end; end;
@ -1289,7 +1475,7 @@ begin
Carets.Visual[Result] := GetVisual; Carets.Visual[Result] := GetVisual;
x := ViewedTextBuffer.LogPhysConvertor.LogicalToPhysical(ToIdx(y), x, Offs); // TODO: check if offs was adjusted? But should not happen for NEW caret x := ViewedTextBuffer.LogPhysConvertor.LogicalToPhysical(ToIdx(y), x, Offs); // TODO: check if offs was adjusted? But should not happen for NEW caret
Carets.Visual[Result].DisplayPos := TextArea.RowColumnToPixels(Point(x, y1)); Carets.Visual[Result].DisplayPos := TextArea.RowColumnToPixels(Point(x, y1));
Carets.Visual[Result].Visible := True; Carets.Visual[Result].Visible := (eoPersistentCaret in Editor.Options) or Editor.Focused;
end end
else else
Carets.Visual[Result] := nil; Carets.Visual[Result] := nil;
@ -1304,20 +1490,21 @@ procedure TSynPluginMultiCaretBase.UpdateCaretsPos;
var var
i, x, y, o, w: Integer; i, x, y, o, w: Integer;
y1, y2: Integer; y1, y2: Integer;
vis: Boolean;
begin begin
if plfDeferUpdateCaretsPos in FPaintLockFlags then exit; if plfDeferUpdateCaretsPos in FPaintLockFlags then exit;
if FPaintLock > 0 then begin if FPaintLock > 0 then begin
include(FPaintLockFlags, plfUpdateCaretsPos); include(FPaintLockFlags, plfUpdateCaretsPos);
exit; exit;
end; end;
if (eoNoCaret in Editor.Options) or if (eoNoCaret in Editor.Options) then begin
not((eoPersistentCaret in Editor.Options) or Editor.Focused) for i := 0 to CaretsCount - 1 do
then begin Carets.Visual[i] := nil;
for i := 0 to FUsedList.Count - 1 do
FUsedList[i].Visible := False;
exit; exit;
end; end;
vis := (eoPersistentCaret in Editor.Options) or Editor.Focused;
w := Editor.LinesInWindow + 1; w := Editor.LinesInWindow + 1;
for i := 0 to CaretsCount - 1 do begin for i := 0 to CaretsCount - 1 do begin
if cfNoneVisual in Carets.Flags[i] then continue; if cfNoneVisual in Carets.Flags[i] then continue;
@ -1339,7 +1526,7 @@ begin
Carets.Visual[i] := GetVisual; Carets.Visual[i] := GetVisual;
x := ViewedTextBuffer.LogPhysConvertor.LogicalToPhysical(ToIdx(y), x, o); x := ViewedTextBuffer.LogPhysConvertor.LogicalToPhysical(ToIdx(y), x, o);
Carets.Visual[i].DisplayPos := TextArea.RowColumnToPixels(Point(x, y1)); Carets.Visual[i].DisplayPos := TextArea.RowColumnToPixels(Point(x, y1));
Carets.Visual[i].Visible := True; Carets.Visual[i].Visible := vis;
//todo: remove if duplicate //todo: remove if duplicate
// check if offs was adjusted // check if offs was adjusted
//if o <> Carets.CaretOffs[i] then //if o <> Carets.CaretOffs[i] then
@ -1963,33 +2150,30 @@ procedure TSynCustomPluginMultiCaret.ProcessAllSynCommand(Sender: TObject; After
case Command of case Command of
ecLeft, ecUp, ecWordLeft, ecLineStart, ecPageUp, ecPageLeft, ecLeft, ecUp, ecWordLeft, ecLineStart, ecPageUp, ecPageLeft,
ecPageTop, ecLineTextStart, ecWordEndLeft, ecHalfWordLeft: ecPageTop, ecLineTextStart, ecWordEndLeft, ecHalfWordLeft:
begin; begin
i := 0; Carets.StartIteratorAtFirst;
j := CaretsCount; while Carets.IterateNextUp do begin
while i < j do begin CaretObj.FullLogicalPos := Carets.CurrentCaretFull;
CaretObj.FullLogicalPos := Carets.CaretFull[i]; k := Carets.CurrentCaretKeepX;
k := Carets.CaretKeepX[i];
if k > 0 then if k > 0 then
CaretObj.KeepCaretXPos := k; CaretObj.KeepCaretXPos := k;
Editor.CommandProcessor(Command, AChar, nil, [hcfInit, hcfFinish]); Editor.CommandProcessor(Command, AChar, nil, [hcfInit, hcfFinish]);
Carets.CaretFull[i] := CaretObj.FullLogicalPos; Carets.CurrentCaretFull := CaretObj.FullLogicalPos;
Carets.CaretKeepX[i] := CaretObj.KeepCaretXPos; Carets.CurrentCaretKeepX := CaretObj.KeepCaretXPos;
inc(i);
end; end;
end; end;
ecEditorTop, ecEditorBottom: ClearCarets; ecEditorTop, ecEditorBottom: ClearCarets;
else else
begin begin
i := CaretsCount; Carets.StartIteratorAtLast;
while i > 0 do begin while Carets.IterateNextDown do begin
dec(i); CaretObj.FullLogicalPos := Carets.CurrentCaretFull;
CaretObj.FullLogicalPos := Carets.CaretFull[i]; k := Carets.CurrentCaretKeepX;
k := Carets.CaretKeepX[i];
if k > 0 then if k > 0 then
CaretObj.KeepCaretXPos := k; CaretObj.KeepCaretXPos := k;
Editor.CommandProcessor(Command, AChar, nil, [hcfInit, hcfFinish]); Editor.CommandProcessor(Command, AChar, nil, [hcfInit, hcfFinish]);
Carets.CaretFull[i] := CaretObj.FullLogicalPos; Carets.CurrentCaretFull := CaretObj.FullLogicalPos;
Carets.CaretKeepX[i] := CaretObj.KeepCaretXPos; Carets.CurrentCaretKeepX := CaretObj.KeepCaretXPos;
end; end;
end; end;
end; end;

View File

@ -37,6 +37,9 @@ type
procedure TestExtraCaretPos(AName: String; ExpCount: Integer; ExpPos: array of integer); // x,y procedure TestExtraCaretPos(AName: String; ExpCount: Integer; ExpPos: array of integer); // x,y
procedure TestExtraCaretPosAndOffs(AName: String; ExpCount: Integer; ExpPos: array of integer); // x,y,offs procedure TestExtraCaretPosAndOffs(AName: String; ExpCount: Integer; ExpPos: array of integer); // x,y,offs
procedure TestExtraCaretPos(AName: String; X, Y: Integer; ExpCount: Integer; ExpPos: array of integer); // x,y
procedure TestExtraCaretPosAndOffs(AName: String; X, Y, Offs: Integer; ExpCount: Integer; ExpPos: array of integer); // x,y,offs
procedure RunAndTest(AName: String; procedure RunAndTest(AName: String;
cmds: Array of TSynEditorCommand; chars: array of String; cmds: Array of TSynEditorCommand; chars: array of String;
X, Y: Integer; ExpLines: Array of String X, Y: Integer; ExpLines: Array of String
@ -206,6 +209,20 @@ begin
end end
end; end;
procedure TTestMultiCaret.TestExtraCaretPos(AName: String; X, Y: Integer; ExpCount: Integer;
ExpPos: array of integer);
begin
TestIsCaret(AName, X, Y);
TestExtraCaretPos(AName, ExpCount, ExpPos);
end;
procedure TTestMultiCaret.TestExtraCaretPosAndOffs(AName: String; X, Y, Offs: Integer;
ExpCount: Integer; ExpPos: array of integer);
begin
TestIsCaret(AName, X, Y, Offs);
TestExtraCaretPosAndOffs(AName, ExpCount, ExpPos);
end;
procedure TTestMultiCaret.RunAndTest(AName: String; cmds: array of TSynEditorCommand; procedure TTestMultiCaret.RunAndTest(AName: String; cmds: array of TSynEditorCommand;
chars: array of String; X, Y: Integer; ExpLines: array of String); chars: array of String; X, Y: Integer; ExpLines: array of String);
begin begin
@ -537,6 +554,14 @@ begin
end; end;
procedure TTestMultiCaret.CursorMove; procedure TTestMultiCaret.CursorMove;
function LocalText1: TStringArray;
begin
SetLength(Result, 4);
Result[0] := ' 123 ';
Result[1] := ' abc ';
Result[2] := ' abc ';
Result[3] := '';
end;
begin begin
PushBaseName('eoScrollPastEol, eoCaretSkipTab'); PushBaseName('eoScrollPastEol, eoCaretSkipTab');
FOptAdd := [eoScrollPastEol]; FOptAdd := [eoScrollPastEol];
@ -630,6 +655,23 @@ begin
PopBaseName; PopBaseName;
PopBaseName; PopBaseName;
// move through tab, but not double-widths
PushBaseName('ecLineStart swap to carets');
FOptAdd := [eoScrollPastEol, eoEnhanceHomeKey];
FOptRemove := [eoTrimTrailingSpaces];
FOpt2Add := [eoEnhanceEndKey];
FOpt2Remove := [];
ReCreateEdit(LocalText1);
SetCaretsByKey(1,1, [2,0, 0,1], mcmMoveAllCarets);
TestExtraCaretPosAndOffs('', 3,2,0, 2, [1,1,0, 3,1,0]);
RunAndTest('3 carets', [ecLineStart], 1,2,0, LocalText1, 2, [1,1,0, 5,1,0]);
RunAndTest('3 carets Right', [ecRight], 2,2,0, LocalText1, 2, [2,1,0, 6,1,0]);
RunAndTest('3 carets', [ecLineStart], 1,2,0, LocalText1, 2, [1,1,0, 5,1,0]);
RunAndTest('3 carets', [ecLineStart], 7,2,0, LocalText1, 2, [1,1,0, 5,1,0]);
PopBaseName;
end; end;
procedure TTestMultiCaret.Edit; procedure TTestMultiCaret.Edit;