mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-20 09:59:09 +02:00
SYnEdit: multi caret, paint - fix home key
git-svn-id: trunk@48319 -
This commit is contained in:
parent
d48e548ada
commit
6bb6966509
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user