mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-13 11:29:29 +02:00
SynEdit: added adjusting column selection in shared edit / fixed, prevent column-sel-bounds from becoming invalid (bytepos in middle of utf8 char)
This commit is contained in:
parent
08f140fe19
commit
1bd921e445
@ -2137,6 +2137,18 @@ procedure TSynEditSelection.DoLinesEdited(Sender: TSynEditStrings; aLinePos,
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure AdjustColumnX;
|
||||
var
|
||||
p: TPoint;
|
||||
begin
|
||||
p := AdjustPoint(Point(FStartBytePos, FStartLinePos), True);
|
||||
FStartBytePos := p.x;
|
||||
FStartLinePos := p.y;
|
||||
p := AdjustPoint(Point(FEndBytePos, FEndLinePos), True);
|
||||
FEndBytePos := p.x;
|
||||
FEndLinePos := p.y;
|
||||
end;
|
||||
|
||||
var
|
||||
empty, back: Boolean;
|
||||
begin
|
||||
@ -2146,22 +2158,22 @@ begin
|
||||
if FPersistent or (FPersistentLock > 0) or
|
||||
((FCaret <> nil) and (not FCaret.Locked))
|
||||
then begin
|
||||
if FActiveSelectionMode <> smColumn then begin // TODO: adjust ypos, height in smColumn mode
|
||||
empty := (FStartBytePos = FEndBytePos) and (FStartLinePos = FEndLinePos);
|
||||
back := IsBackwardSel;
|
||||
AdjustStartLineBytePos(AdjustPoint(StartLineBytePos, not back));
|
||||
if empty then
|
||||
EndLineBytePos := StartLineBytePos
|
||||
else
|
||||
EndLineBytePos := AdjustPoint(EndLineBytePos, back);
|
||||
end;
|
||||
// Todo: Change Lines in smColumn
|
||||
empty := (FStartBytePos = FEndBytePos) and (FStartLinePos = FEndLinePos);
|
||||
back := IsBackwardSel;
|
||||
AdjustStartLineBytePos(AdjustPoint(StartLineBytePos, not back));
|
||||
if empty then
|
||||
EndLineBytePos := StartLineBytePos
|
||||
else
|
||||
EndLineBytePos := AdjustPoint(EndLineBytePos, back);
|
||||
end
|
||||
else begin
|
||||
// Change the Selection, if change was made by owning SynEdit (Caret.Locked)
|
||||
// Clear the Selection, if change was made by owning SynEdit (Caret.Locked)
|
||||
// (InternalSelection has no Caret)
|
||||
if (FCaret <> nil) and (FCaret.Locked) then
|
||||
StartLineBytePos := FCaret.LineBytePos;
|
||||
if (FCaret <> nil) and (FCaret.Locked) then begin
|
||||
if FActiveSelectionMode = smColumn then
|
||||
AdjustColumnX; // prevent SelAvail from accessing invalid x in phys/log
|
||||
StartLineBytePos := StartLineBytePos; // caret may not yet be up to date
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -35,6 +35,8 @@ type
|
||||
);
|
||||
procedure SimulatePaintText;
|
||||
procedure InvalidateLines(FirstLine, LastLine: integer); reintroduce;
|
||||
procedure TestDoIncForeignPaintLock(Sender: TObject);
|
||||
procedure TestDoDecForeignPaintLock(Sender: TObject);
|
||||
property ViewedTextBuffer;
|
||||
property TextBuffer;
|
||||
property TextView; // foldedview
|
||||
@ -66,6 +68,7 @@ type
|
||||
procedure SetClipBoardText(const AValue: String);
|
||||
protected
|
||||
FSynEdit : TTestSynEdit;
|
||||
FSharedSynEdit : TTestSynEdit;
|
||||
function LinesToText(Lines: Array of String; Separator: String = LineEnding;
|
||||
SeparatorAtEnd: Boolean = False): String;
|
||||
(* Relpl,must be an alteration of LineNum, LineText+
|
||||
@ -78,6 +81,7 @@ type
|
||||
function LinesReplaceText(Lines: Array of String; Repl: Array of const): String;
|
||||
protected
|
||||
procedure ReCreateEdit;
|
||||
function GetSharedSynEdit: TTestSynEdit;
|
||||
procedure SetSynEditHeight(Lines: Integer; PartLinePixel: Integer = 3);
|
||||
procedure SetSynEditWidth(Chars: Integer; PartCharPixel: Integer = 2);
|
||||
procedure SetLines(Lines: Array of String);
|
||||
@ -107,6 +111,7 @@ type
|
||||
procedure IncFixedBaseTestNames;
|
||||
procedure DecFixedBaseTestNames;
|
||||
property SynEdit: TTestSynEdit read FSynEdit;
|
||||
property SharedSynEdit: TTestSynEdit read GetSharedSynEdit;
|
||||
property Form: TForm read FForm;
|
||||
procedure ClearClipBoard;
|
||||
property ClipBoardText: String read GetClipBoardText write SetClipBoardText;
|
||||
@ -267,6 +272,16 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TTestSynEdit.TestDoIncForeignPaintLock(Sender: TObject);
|
||||
begin
|
||||
DoIncForeignPaintLock(Sender);
|
||||
end;
|
||||
|
||||
procedure TTestSynEdit.TestDoDecForeignPaintLock(Sender: TObject);
|
||||
begin
|
||||
DoDecForeignPaintLock(Sender);
|
||||
end;
|
||||
|
||||
{ TTestBase }
|
||||
|
||||
procedure TTestBase.SetUp;
|
||||
@ -288,6 +303,7 @@ procedure TTestBase.TearDown;
|
||||
begin
|
||||
inherited TearDown;
|
||||
Clipboard.Close;
|
||||
FreeAndNil(FSharedSynEdit);
|
||||
FreeAndNil(FSynEdit);
|
||||
FreeAndNil(FForm);
|
||||
end;
|
||||
@ -603,6 +619,7 @@ end;
|
||||
|
||||
procedure TTestBase.ReCreateEdit;
|
||||
begin
|
||||
FreeAndNil(FSharedSynEdit);
|
||||
FreeAndNil(FSynEdit);
|
||||
FSynEdit := TTestSynEdit.Create(FScroll);
|
||||
FSynEdit.Parent := FForm;
|
||||
@ -612,6 +629,24 @@ begin
|
||||
FSynEdit.Height := 250; // FSynEdit.Font.Height * 20 + 2;
|
||||
end;
|
||||
|
||||
function TTestBase.GetSharedSynEdit: TTestSynEdit;
|
||||
begin
|
||||
Result := FSharedSynEdit;
|
||||
if Result <> nil then
|
||||
exit;
|
||||
|
||||
FSharedSynEdit := TTestSynEdit.Create(FScroll);
|
||||
FSharedSynEdit.Parent := FForm;
|
||||
FSharedSynEdit.Top := 0;
|
||||
FSharedSynEdit.Left := 0;
|
||||
FSharedSynEdit.Width:= 500;
|
||||
FSharedSynEdit.Height := 250; // FSharedSynEdit.Font.Height * 20 + 2;
|
||||
FSharedSynEdit.ShareOptions := [eosShareMarks];
|
||||
FSharedSynEdit.ShareTextBufferFrom(FSynEdit);
|
||||
|
||||
Result := FSharedSynEdit;
|
||||
end;
|
||||
|
||||
procedure TTestBase.SetSynEditHeight(Lines: Integer; PartLinePixel: Integer);
|
||||
begin
|
||||
FSynEdit.Height := FSynEdit.LineHeight * Lines + PartLinePixel +
|
||||
|
@ -1553,11 +1553,18 @@ var
|
||||
|
||||
function GetTheText: TStringArray;
|
||||
begin
|
||||
SetLength(Result, 4);
|
||||
SetLength(Result, 11);
|
||||
Result[0] := ' ABC def';
|
||||
Result[1] := 'XYZ 123';
|
||||
Result[2] := '';
|
||||
Result[3] := '';
|
||||
Result[4] := ' ÄÖÜäöü';
|
||||
Result[5] := ' abcüüü';
|
||||
Result[6] := ' abcde';
|
||||
Result[7] := ' ÄÖÜäöü';
|
||||
Result[8] := ' abcüüü';
|
||||
Result[9] := ' abcde';
|
||||
Result[10] := '';
|
||||
end;
|
||||
|
||||
procedure DoTest(AName: String;
|
||||
@ -1592,35 +1599,60 @@ var
|
||||
SelBX, SelBY, SelEX, SelEY,
|
||||
TextX, TextY, TextX2, TextY2,
|
||||
ExpBx, ExpBy, ExpEx, ExpEy: Integer;
|
||||
aFlags: TSynEditTextFlags = []; aCaretMode: TSynCaretAdjustMode = scamIgnore);
|
||||
aFlags: TSynEditTextFlags = []; aCaretMode: TSynCaretAdjustMode = scamIgnore;
|
||||
ASelMode: TSynSelectionMode = smNormal;
|
||||
AnUseShared: boolean = False // simulate edit from shared editor
|
||||
);
|
||||
var
|
||||
s: Boolean;
|
||||
p, p2: TPoint;
|
||||
Syn: TTestSynEdit;
|
||||
begin
|
||||
PopPushBaseName(AName);
|
||||
SetLines(TheText);
|
||||
if Length(TheText) = 0 then SynEdit.Lines.Clear;
|
||||
|
||||
SetCaretAndSel(SelBx, SelBy, SelEx,SelEy);
|
||||
SetCaretAndSel(SelBx, SelBy, SelEx,SelEy, ASelMode=smColumn, ASelMode);
|
||||
s := SynEdit.SelAvail;
|
||||
p := Point(Textx,TextY);
|
||||
p2 := Point(Textx2,TextY2);
|
||||
SynEdit.SetTextBetweenPoints(p, p2, TheInsert, aFlags, aCaretMode);
|
||||
debugln(['Caret ', dbgs(SynEdit.CaretXY), ' Sel ', dbgs(SynEdit.BlockBegin), ' ',dbgs(SynEdit.BlockEnd)]);
|
||||
if AnUseShared
|
||||
then Syn := SharedSynEdit
|
||||
else Syn := SynEdit;
|
||||
|
||||
TestIsBlock('After Replace', ExpBx,ExpBy, ExpEx,ExpEy);
|
||||
Syn.SetTextBetweenPoints(p, p2, TheInsert, aFlags, aCaretMode);
|
||||
debugln(['Caret ', dbgs(Syn.CaretXY), ' Sel ', dbgs(Syn.BlockBegin), ' ',dbgs(Syn.BlockEnd)]);
|
||||
|
||||
SynEdit.Undo;
|
||||
if ExpBx < 0 then
|
||||
TestIsNoBlock('After Replace - no')
|
||||
else
|
||||
TestIsBlock('After Replace', ExpBx,ExpBy, ExpEx,ExpEy);
|
||||
|
||||
Syn.Undo;
|
||||
if s
|
||||
then TestIsBlock('After Undo', SelBx, SelBy, SelEx,SelEy)
|
||||
else TestIsNoBlock('After Undo');
|
||||
|
||||
SynEdit.Redo;
|
||||
Syn.Redo;
|
||||
TestIsBlock('After Redo', ExpBx,ExpBy, ExpEx,ExpEy);
|
||||
end;
|
||||
|
||||
function IncIf(AVal: Integer; ABool: Boolean): integer;
|
||||
begin
|
||||
Result := AVal;
|
||||
if ABool then inc(Result);
|
||||
end;
|
||||
function DecIf(AVal: Integer; ABool: Boolean): integer;
|
||||
begin
|
||||
Result := AVal;
|
||||
if ABool then dec(Result);
|
||||
end;
|
||||
|
||||
const
|
||||
CL1: array[5..10] of integer = ( 6 {Üä}, 4 {cü}, 5 {b}, 6 {Üä}, 4 {cü}, 5 {b} );
|
||||
CL2: array[5..10] of integer = ( 10 {Üä}, 7 {cü}, 8 {b}, 10 {Üä}, 7 {cü}, 8 {b} );
|
||||
var
|
||||
p: TPoint;
|
||||
y1, y2: Integer;
|
||||
begin
|
||||
PushBaseName('');
|
||||
TheText := GetTheText;
|
||||
@ -1755,6 +1787,39 @@ begin
|
||||
DoTest('setExtendBlock - BlockEnd B', 2,1, 6,1, 6,1, 7,1, 2,1, 6,1, [setExtendBlock], scamAdjust); // so caret will not destroy selection
|
||||
|
||||
|
||||
// Currently selection will be cleared // TODO
|
||||
// ÖÜ bc b
|
||||
for y1 := 5 to 10 do
|
||||
for y2 := 5 to 10 do
|
||||
begin
|
||||
TheInsert := 'X';
|
||||
//DoTest('column ', y1,CL1[y1], y2,CL2[y2], 1,y1, 1,y1, -7,5, 7,7, [setPersistentBlock], scamAdjust, smColumn, sh);
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y1, 1,y1, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y1, 1,y1, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y2, 1,y2, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y2, 1,y2, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y1, 1,y1, IncIf(CL1[y1],y1=y1),y1, IncIf(CL2[y2],y2=y1),y2, [], scamAdjust, smColumn, True);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y1, 1,y1, IncIf(CL2[y1],y1=y1),y1, IncIf(CL1[y2],y2=y1),y2, [], scamAdjust, smColumn, True);
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y2, 1,y2, IncIf(CL1[y1],y1=y2),y1, IncIf(CL2[y2],y2=y2),y2, [], scamAdjust, smColumn, True);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y2, 1,y2, IncIf(CL2[y1],y1=y2),y1, IncIf(CL1[y2],y2=y2),y2, [], scamAdjust, smColumn, True);
|
||||
|
||||
TheInsert := '';
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y1, 2,y1, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y1, 2,y1, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y2, 2,y2, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y2, 2,y2, -7,5, 7,7, [], scamAdjust, smColumn, False);
|
||||
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y1, 2,y1, DecIf(CL1[y1],y1=y1),y1, DecIf(CL2[y2],y2=y1),y2, [], scamAdjust, smColumn, True);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y1, 2,y1, DecIf(CL2[y1],y1=y1),y1, DecIf(CL1[y2],y2=y1),y2, [], scamAdjust, smColumn, True);
|
||||
DoTest('column ', CL1[y1],y1, CL2[y2],y2, 1,y2, 2,y2, DecIf(CL1[y1],y1=y2),y1, DecIf(CL2[y2],y2=y2),y2, [], scamAdjust, smColumn, True);
|
||||
DoTest('column ', CL2[y1],y1, CL1[y2],y2, 1,y2, 2,y2, DecIf(CL2[y1],y1=y2),y1, DecIf(CL1[y2],y2=y2),y2, [], scamAdjust, smColumn, True);
|
||||
|
||||
// no selection / check caret / with without adjust
|
||||
|
||||
end;
|
||||
|
||||
|
||||
TheText := nil; // empty text
|
||||
TheInsert := 'X';
|
||||
PopPushBaseName('syn clear');
|
||||
|
Loading…
Reference in New Issue
Block a user