diff --git a/components/synedit/syneditpointclasses.pas b/components/synedit/syneditpointclasses.pas index 988dd628bc..a4fbe01233 100644 --- a/components/synedit/syneditpointclasses.pas +++ b/components/synedit/syneditpointclasses.pas @@ -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; diff --git a/components/synedit/test/testbase.pas b/components/synedit/test/testbase.pas index 34813c36b3..870d2ad208 100644 --- a/components/synedit/test/testbase.pas +++ b/components/synedit/test/testbase.pas @@ -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 + diff --git a/components/synedit/test/testsynselection.pas b/components/synedit/test/testsynselection.pas index aee7ef6e0b..28d800e6c4 100644 --- a/components/synedit/test/testsynselection.pas +++ b/components/synedit/test/testsynselection.pas @@ -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');