IDE, SynEdit: Add column-selection-shift (shift inside selection only) Issue #40978

This commit is contained in:
Martin 2024-10-04 23:55:02 +02:00
parent 1451c33dd9
commit 277a8f0a31
7 changed files with 214 additions and 110 deletions

View File

@ -647,9 +647,9 @@ type
procedure SurrenderPrimarySelection; procedure SurrenderPrimarySelection;
procedure ComputeCaret(X, Y: Integer); procedure ComputeCaret(X, Y: Integer);
procedure DoBlockIndent(AColumnIndentOutside: Boolean = False); procedure DoBlockIndent(AColumnIndentOutside: Boolean = False);
procedure DoBlockIndentColSel(AnIndentOutside: Boolean = False); procedure DoBlockIndentColSel(AnIndentOutside: Boolean = False; ADeleteAtRightBound: Boolean = False);
procedure DoBlockUnindent(AColumnIndentOutside: Boolean = False); procedure DoBlockUnindent(AColumnIndentOutside: Boolean = False);
procedure DoBlockUnindentColSel(AnIndentOutside: Boolean = False); procedure DoBlockUnindentColSel(AnIndentOutside: Boolean = False; ADeleteAtLeftBound: Boolean = False);
procedure DoHomeKey(aMode: TSynHomeMode = synhmDefault); procedure DoHomeKey(aMode: TSynHomeMode = synhmDefault);
procedure DoEndKey; procedure DoEndKey;
procedure DoTabKey; procedure DoTabKey;
@ -7739,6 +7739,10 @@ begin
if not ReadOnly then DoBlockIndent(Command = ecBlockIndentMove); if not ReadOnly then DoBlockIndent(Command = ecBlockIndentMove);
ecBlockUnindent, ecBlockUnindentMove: ecBlockUnindent, ecBlockUnindentMove:
if not ReadOnly then DoBlockUnindent(Command = ecBlockUnindentMove); if not ReadOnly then DoBlockUnindent(Command = ecBlockUnindentMove);
ecColumnBlockShiftRight, ecColumnBlockMoveRight:
if not ReadOnly then DoBlockIndentColSel(Command = ecColumnBlockMoveRight, True);
ecColumnBlockShiftLeft, ecColumnBlockMoveLeft:
if not ReadOnly then DoBlockUnindentColSel(Command = ecColumnBlockMoveLeft, True);
ecNormalSelect, ecNormalSelect,
ecColumnSelect, ecColumnSelect,
ecLineSelect: ecLineSelect:
@ -9037,8 +9041,10 @@ begin
if i = 0 then i := TabWidth; if i = 0 then i := TabWidth;
end; end;
// i now contains the needed spaces // i now contains the needed spaces
Spaces := CreateTabsAndSpaces(CaretX,i,TabWidth, if eoTabsToSpaces in Options then
not (eoTabsToSpaces in Options)); Spaces := CreateTabsAndSpaces(CaretX,i,TabWidth, 0)
else
Spaces := CreateTabsAndSpaces(CaretX,i,TabWidth, MaxInt);
if SelAvail and (not FBlockSelection.Persistent) and (eoOverwriteBlock in fOptions2) then begin if SelAvail and (not FBlockSelection.Persistent) and (eoOverwriteBlock in fOptions2) then begin
SetSelTextExternal(Spaces); SetSelTextExternal(Spaces);
@ -9114,7 +9120,7 @@ var
Spaces, Tabs: String; Spaces, Tabs: String;
begin begin
if SelAvail and (SelectionMode = smColumn) then begin if SelAvail and (SelectionMode = smColumn) then begin
DoBlockIndentColSel(AColumnIndentOutside); DoBlockIndentColSel(AColumnIndentOutside, False);
exit; exit;
end; end;
@ -9160,10 +9166,11 @@ begin
end; end;
end; end;
procedure TCustomSynEdit.DoBlockIndentColSel(AnIndentOutside: Boolean); procedure TCustomSynEdit.DoBlockIndentColSel(AnIndentOutside: Boolean; ADeleteAtRightBound: Boolean
);
var var
BB,BE, BB2, BE2: TPoint; BB,BE, BB2, BE2: TPoint;
Len, y, LeftBytePos, RightBytePos: integer; Len, y, LeftBytePos, RightCharPos, RightBytePos, DelPos, DelLen: integer;
LineStr, TabStr, SpaceStr: String; LineStr, TabStr, SpaceStr: String;
Bounds: array of record Bounds: array of record
LeftByte, RightByte: integer; LeftByte, RightByte: integer;
@ -9187,16 +9194,18 @@ begin
Bounds[y-BB.y].LeftByte := FBlockSelection.ColumnStartBytePos[y]; Bounds[y-BB.y].LeftByte := FBlockSelection.ColumnStartBytePos[y];
Bounds[y-BB.y].RightByte := FBlockSelection.ColumnEndBytePos[y]; Bounds[y-BB.y].RightByte := FBlockSelection.ColumnEndBytePos[y];
end; end;
FBlockSelection.Clear;
SpaceStr := StringOfChar(#32, FBlockIndent); SpaceStr := StringOfChar(#32, FBlockIndent);
TabStr := StringOfChar( #9, FBlockTabIndent); TabStr := StringOfChar( #9, FBlockTabIndent);
RightCharPos := FBlockSelection.ColumnRightCharPos;
FBlockSelection.Clear;
for y := BB.Y to BE.y do begin for y := BB.Y to BE.y do begin
LineStr := FTheLinesView[y - 1]; LineStr := FTheLinesView[y - 1];
LeftBytePos := Bounds[y-BB.y].LeftByte; LeftBytePos := Bounds[y-BB.y].LeftByte;
if AnIndentOutside then begin if AnIndentOutside then begin
Len := CountBackwardWhiteSpace(PChar(LineStr), LeftBytePos-1); Len := CountBackwardWhiteSpace(PChar(LineStr), LeftBytePos-1);
RightBytePos := LeftBytePos; if ADeleteAtRightBound then
RightBytePos := Bounds[y-BB.y].RightByte;
LeftBytePos := LeftBytePos - Len; LeftBytePos := LeftBytePos - Len;
if FBlockIndent = 0 then if FBlockIndent = 0 then
Len := 0; Len := 0;
@ -9205,7 +9214,7 @@ begin
if FBlockIndent > 0 if FBlockIndent > 0
then Len := CountLeadWhiteSpace(PChar(LineStr)+LeftBytePos-1) then Len := CountLeadWhiteSpace(PChar(LineStr)+LeftBytePos-1)
else Len := 0; else Len := 0;
if (Len > 0) then if ADeleteAtRightBound or (Len > 0) then
RightBytePos := Bounds[y-BB.y].RightByte; RightBytePos := Bounds[y-BB.y].RightByte;
if (Len > 0) and (LeftBytePos + Len > RightBytePos) then if (Len > 0) and (LeftBytePos + Len > RightBytePos) then
Len := Max(0, RightBytePos - LeftBytePos); Len := Max(0, RightBytePos - LeftBytePos);
@ -9215,23 +9224,44 @@ begin
FTheLinesView.EditInsert(LeftBytePos, y, TabStr+SpaceStr); FTheLinesView.EditInsert(LeftBytePos, y, TabStr+SpaceStr);
end end
else begin else begin
FTheLinesView.EditInsert(LeftBytePos + Len, y, SpaceStr); if SpaceStr <> '' then
FTheLinesView.EditInsert(LeftBytePos + Len, y, SpaceStr);
if TabStr <> '' then if TabStr <> '' then
FTheLinesView.EditInsert(LeftBytePos, y, TabStr); FTheLinesView.EditInsert(LeftBytePos, y, TabStr);
end; end;
if ADeleteAtRightBound then begin
FInternalCaret.Invalidate;
if AnIndentOutside then begin
DelPos := RightBytePos + Length(TabStr) + Length(SpaceStr);
FInternalCaret.LineBytePos := Point(DelPos, y);
DelLen := FInternalCaret.CharPos - RightCharPos; // Phys-Columns
FInternalCaret.CharPos := FInternalCaret.CharPos + DelLen;
DelLen := FInternalCaret.BytePos - DelPos;
end
else begin
FInternalCaret.LineCharPos := Point(RightCharPos, y);
DelPos := FInternalCaret.BytePos;
DelLen := RightBytePos + Length(TabStr) + Length(SpaceStr) - DelPos;
end;
if DelLen > 0 then
FTheLinesView.EditDelete(DelPos, y, DelLen);
end;
end; end;
finally finally
FTrimmedLinesView.ForceTrim; // Otherwise it may reset the block FTrimmedLinesView.ForceTrim; // Otherwise it may reset the block
if AnIndentOutside then begin if (not ADeleteAtRightBound) or AnIndentOutside then begin
BB2.X := BB2.X + Length(TabStr) + Length(SpaceStr); if AnIndentOutside then begin
BE2.X := BE2.X + Length(TabStr) + Length(SpaceStr); BB2.X := BB2.X + Length(TabStr) + Length(SpaceStr);
end
else begin
if BB2.X > BE2.X then
BB2.X := BB2.X + Length(TabStr) + Length(SpaceStr)
else
BE2.X := BE2.X + Length(TabStr) + Length(SpaceStr); BE2.X := BE2.X + Length(TabStr) + Length(SpaceStr);
end
else begin
if BB2.X > BE2.X then
BB2.X := BB2.X + Length(TabStr) + Length(SpaceStr)
else
BE2.X := BE2.X + Length(TabStr) + Length(SpaceStr);
end;
end; end;
FBlockSelection.StartLineBytePos := BB2; FBlockSelection.StartLineBytePos := BB2;
FBlockSelection.EndLineBytePos := BE2; FBlockSelection.EndLineBytePos := BE2;
@ -9254,7 +9284,7 @@ var
HasTab: Boolean; HasTab: Boolean;
begin begin
if SelAvail and (SelectionMode = smColumn) then begin if SelAvail and (SelectionMode = smColumn) then begin
DoBlockUnindentColSel(AColumnIndentOutside); DoBlockUnindentColSel(AColumnIndentOutside, False);
exit; exit;
end; end;
@ -9368,16 +9398,16 @@ begin
end; end;
end; end;
procedure TCustomSynEdit.DoBlockUnindentColSel(AnIndentOutside: Boolean); procedure TCustomSynEdit.DoBlockUnindentColSel(AnIndentOutside: Boolean;
ADeleteAtLeftBound: Boolean);
var var
BB,BE, BB2, BE2: TPoint; BB,BE, BB2, BE2: TPoint;
Len, y, LeftBytePos, TabW, TabDel, CurTabDel, CurTabSpaceAdd, Len, y, LeftBytePos, RightBytePos, RightCharPos, LeftCharPos, TabW: integer;
SpaceStartCharPos, CurSpaceSpaceAdd, CurSpaceDel, CurSpaceDelPos: integer; CurSpaceSpaceAdd, CurSpaceDel, CurSpaceDelPos, SpaceStartCharPos: integer;
CurTabDel, CurTabDelPhysWidth, CurTabSpaceAdd, TabEndBytePos, TmpCharPos, t: integer;
LineStr: String; LineStr: String;
LeftCharPos, RightBytePos, TabEndBytePos: LongInt;
Bounds: array of record Bounds: array of record
LeftByte, RightByte: integer; LeftByte, RightByte: integer;
// LeftChar, RightchByte: integer;
end; end;
LPC: TSynLogicalPhysicalConvertor; LPC: TSynLogicalPhysicalConvertor;
BbIsRight: Boolean; BbIsRight: Boolean;
@ -9404,7 +9434,6 @@ begin
IncPaintLock; IncPaintLock;
try try
TabW := TabWidth; TabW := TabWidth;
TabDel := TabW * FBlockTabIndent;
BB := BlockBegin; BB := BlockBegin;
BE := BlockEnd; BE := BlockEnd;
BB2 := FBlockSelection.StartLineBytePos; BB2 := FBlockSelection.StartLineBytePos;
@ -9416,81 +9445,101 @@ begin
Bounds[y-BB.y].LeftByte := FBlockSelection.ColumnStartBytePos[y]; Bounds[y-BB.y].LeftByte := FBlockSelection.ColumnStartBytePos[y];
Bounds[y-BB.y].RightByte := FBlockSelection.ColumnEndBytePos[y]; Bounds[y-BB.y].RightByte := FBlockSelection.ColumnEndBytePos[y];
end; end;
FBlockSelection.Clear;
LPC := FTheLinesView.LogPhysConvertor; LPC := FTheLinesView.LogPhysConvertor;
RightCharPos := FBlockSelection.ColumnRightCharPos;
FBlockSelection.Clear;
for y := BB.Y to BE.y do begin for y := BB.Y to BE.y do begin
LineStr := FTheLinesView[y - 1]; LineStr := FTheLinesView[y - 1];
LeftBytePos := Bounds[y-BB.y].LeftByte; LeftBytePos := Bounds[y-BB.y].LeftByte;
RightBytePos := Bounds[y-BB.y].RightByte; RightBytePos := Bounds[y-BB.y].RightByte;
if AnIndentOutside then begin
Len := CountBackwardWhiteSpace(PChar(LineStr), LeftBytePos-1);
RightBytePos := LeftBytePos;
LeftBytePos := LeftBytePos - Len;
//if FBlockIndent = 0 then
// Len := 0;
end
else begin
Len := Min(CountLeadWhiteSpace(PChar(LineStr)+LeftBytePos-1), RightBytePos - LeftBytePos);
if Len > Length(LineStr) - LeftBytePos then
Len := Length(LineStr) - LeftBytePos;
end;
if Len = 0 then
Continue;
CurSpaceDel := 0; CurSpaceDel := 0;
CurSpaceDelPos := LeftBytePos + Len; // used as end for tab // pretend zero spaces
CurSpaceSpaceAdd := 0; CurSpaceSpaceAdd := 0;
CurTabDel := 0; CurTabDel := 0;
CurTabSpaceAdd := 0;
if FBlockIndent > 0 then begin if ADeleteAtLeftBound then begin
//SpaceStartCharPos := LogToPhys(Max(LeftBytePos, CurSpaceDelPos - FBlockIndent)); if AnIndentOutside then begin
SpaceStartCharPos := Max( LogToPhys(CurSpaceDelPos) - FBlockIndent, LeftCharPos := Max(1, LogToPhys(LeftBytePos) - FBlockIndent);
LogToPhys(LeftBytePos) if FBlockTabIndent > 0 then
); LeftCharPos := LeftCharPos - Max(0, FBlockTabIndent-1)*TabW - (LeftCharPos-1) mod TabW;
CurSpaceDelPos := PhysToLog(SpaceStartCharPos, CurSpaceSpaceAdd); CurSpaceDelPos := PhysToLog(LeftCharPos, CurSpaceSpaceAdd);
CurSpaceDel := LeftBytePos + Len - CurSpaceDelPos; CurSpaceDel := LeftBytePos - CurSpaceDelPos;
end; end
else begin
if (CurSpaceDel > Len) or TmpCharPos := LogToPhys(LeftBytePos) + FBlockIndent;
( (CurSpaceDel = Len) and (CurSpaceSpaceAdd = 0) ) if FBlockTabIndent > 0 then
then begin TmpCharPos := TmpCharPos + Max(0, FBlockTabIndent-1)*TabW + (TabW - (TmpCharPos-1) mod TabW);
CurSpaceDelPos := LeftBytePos; CurSpaceDelPos := LeftBytePos;
CurSpaceDel := Len; CurSpaceDel := PhysToLog(TmpCharPos, CurSpaceSpaceAdd) - CurSpaceDelPos;
CurSpaceSpaceAdd := 0; if CurSpaceDel > RightBytePos - LeftBytePos then begin
CurSpaceDel := RightBytePos - LeftBytePos;
CurSpaceSpaceAdd := 0;
end;
end;
end end
else else begin
begin if AnIndentOutside then begin
Len := CurSpaceDelPos - LeftBytePos; Len := CountBackwardWhiteSpace(PChar(LineStr), LeftBytePos-1);
if TabDel > 0 then begin RightBytePos := LeftBytePos;
LeftCharPos := LogToPhys(LeftBytePos); LeftBytePos := LeftBytePos - Len;
CurTabDel := TabDel - (LeftCharPos-1) mod TabW; end
if CurTabDel > 0 then begin else begin
TabEndBytePos := PhysToLog(LeftCharPos+CurTabDel, CurTabSpaceAdd); Len := Min(CountLeadWhiteSpace(PChar(LineStr)+LeftBytePos-1), RightBytePos - LeftBytePos);
CurTabDel := TabEndBytePos - LeftBytePos; if Len > Length(LineStr) - LeftBytePos then
if CurTabSpaceAdd > 0 then Len := Length(LineStr) - LeftBytePos;
inc(CurTabDel); end;
if (CurTabDel > Len) or if Len = 0 then
( (CurTabDel=Len) and (CurTabSpaceAdd >= CurSpaceSpaceAdd) ) Continue;
then begin
CurTabDel := 0; CurSpaceDelPos := LeftBytePos + Len; // used as end for tab // pretend zero spaces
CurTabSpaceAdd := 0;
CurSpaceDelPos := LeftBytePos; (* find spaces to delete *)
CurSpaceDel := Len; if FBlockIndent > 0 then begin
CurSpaceSpaceAdd := 0; SpaceStartCharPos := Max( LogToPhys(CurSpaceDelPos) - FBlockIndent,
LogToPhys(LeftBytePos)
);
CurSpaceDelPos := PhysToLog(SpaceStartCharPos, CurSpaceSpaceAdd);
CurSpaceDel := LeftBytePos + Len - CurSpaceDelPos;
if (CurSpaceDel > Len) then begin
CurSpaceDelPos := LeftBytePos;
CurSpaceDel := Len;
CurSpaceSpaceAdd := 0;
end;
Len := CurSpaceDelPos - LeftBytePos;
end;
(* find tabs to delete *)
if (FBlockTabIndent > 0) and
( (Len > 0) or (CurSpaceSpaceAdd > 0) )
then begin
(* actual tabs / only at very start of gap *)
while (CurTabDel < FBlockTabIndent) and (LineStr[LeftBytePos+CurTabDel] = #9) do
inc(CurTabDel);
(* Take spaces/tab mix instead / ending at a tabstop *)
if CurTabDel < FBlockTabIndent then begin
LeftCharPos := LogToPhys(LeftBytePos+CurTabDel);
CurTabDelPhysWidth := (FBlockTabIndent-CurTabDel)*TabW - (LeftCharPos-1) mod TabW;
if CurTabDelPhysWidth > 0 then begin
TabEndBytePos := PhysToLog(LeftCharPos+CurTabDelPhysWidth, CurTabSpaceAdd);
assert(CurTabSpaceAdd=0, 'TCustomSynEdit.DoBlockUnindentColSel: CurTabSpaceAdd=0');
CurTabDel := CurTabDel + TabEndBytePos - (LeftBytePos+CurTabDel);
end; end;
end end;
else
CurTabDel := 0; if (CurTabDel > Len - CurSpaceDel) then begin
CurSpaceSpaceAdd := Max(0, CurSpaceSpaceAdd - Max(0, LogToPhys(LeftBytePos+CurTabDel) - LogToPhys(CurSpaceDelPos)));
CurTabDel := 0;
CurSpaceDelPos := LeftBytePos;
CurSpaceDel := Len;
end;
end; end;
end; end;
if CurSpaceDel > 0 then begin if CurSpaceDel > 0 then begin
FTheLinesView.EditDelete(CurSpaceDelPos, y, CurSpaceDel); FTheLinesView.EditDelete(CurSpaceDelPos, y, CurSpaceDel);
if CurSpaceSpaceAdd > 0 then if CurSpaceSpaceAdd > 0 then
@ -9498,21 +9547,28 @@ begin
end; end;
if CurTabDel > 0 then begin if CurTabDel > 0 then begin
FTheLinesView.EditDelete(LeftBytePos, y, CurTabDel); FTheLinesView.EditDelete(LeftBytePos, y, CurTabDel);
if CurTabSpaceAdd > 0 then
FTheLinesView.EditInsert(LeftBytePos, y, StringOfChar(' ', CurTabSpaceAdd));
end; end;
if AnIndentOutside then begin if ADeleteAtLeftBound then begin
if (y = BB2.y) then RightBytePos := RightBytePos - CurSpaceDel;
BB2.X := BB2.X + CurSpaceSpaceAdd + CurTabSpaceAdd - CurSpaceDel - CurTabDel; TmpCharPos := LogToPhys(RightBytePos);
if (y = BE2.y) then t := Max(0, (RightCharPos-TmpCharPos));
BE2.X := BE2.X + CurSpaceSpaceAdd + CurTabSpaceAdd - CurSpaceDel - CurTabDel; FTheLinesView.EditInsert(RightBytePos, y, CreateTabsAndSpaces(RightBytePos, t, TabW, FBlockTabIndent));
end end;
else begin
if (y = BB2.y) and (BbIsRight) then if (not ADeleteAtLeftBound) or AnIndentOutside then begin
BB2.X := BB2.X + CurSpaceSpaceAdd + CurTabSpaceAdd - CurSpaceDel - CurTabDel; if AnIndentOutside then begin
if (y = BE2.y) and (not BbIsRight) then if (y = BB2.y) then
BE2.X := BE2.X + CurSpaceSpaceAdd + CurTabSpaceAdd - CurSpaceDel - CurTabDel; BB2.X := BB2.X + CurSpaceSpaceAdd - CurSpaceDel - CurTabDel;
if (y = BE2.y) then
BE2.X := BE2.X + CurSpaceSpaceAdd - CurSpaceDel - CurTabDel;
end
else begin
if (y = BB2.y) and (BbIsRight) then
BB2.X := BB2.X + CurSpaceSpaceAdd - CurSpaceDel - CurTabDel;
if (y = BE2.y) and (not BbIsRight) then
BE2.X := BE2.X + CurSpaceSpaceAdd - CurSpaceDel - CurTabDel;
end;
end; end;
end; end;

View File

@ -299,6 +299,11 @@ const
ecBlockIndentMove = 651; // Indent selection (indent before column-sel, therefore moving the column-sel) ecBlockIndentMove = 651; // Indent selection (indent before column-sel, therefore moving the column-sel)
ecBlockUnindentMove = 652; // Unindent selection (indent before column-sel, therefore moving the column-sel) ecBlockUnindentMove = 652; // Unindent selection (indent before column-sel, therefore moving the column-sel)
ecColumnBlockShiftRight = 653; // Right Shift (Indent) column selection and delete right side inside selectio
ecColumnBlockMoveRight = 654; // Right Shift (Indent) column selection and overwrite text behind it
ecColumnBlockShiftLeft = 655; // Left Shift (Unindent) column selection and delete left side inside selectio
ecColumnBlockMoveLeft = 656; // Left Shift (Unindent) column selection and overwrite text at start of it
ecGotFocus = 700 deprecated 'Not used / To be removed in Lazarus 5.99'; ecGotFocus = 700 deprecated 'Not used / To be removed in Lazarus 5.99';
ecLostFocus = 701 deprecated 'Not used / To be removed in Lazarus 5.99'; ecLostFocus = 701 deprecated 'Not used / To be removed in Lazarus 5.99';
@ -431,7 +436,7 @@ implementation
{ Command mapping routines } { Command mapping routines }
const const
EditorCommandStrs: array[0..179] of TIdentMapEntry = ( EditorCommandStrs: array[0..183] of TIdentMapEntry = (
(Value: ecNone; Name: 'ecNone'), (Value: ecNone; Name: 'ecNone'),
(Value: ecLeft; Name: 'ecLeft'), (Value: ecLeft; Name: 'ecLeft'),
(Value: ecRight; Name: 'ecRight'), (Value: ecRight; Name: 'ecRight'),
@ -547,6 +552,10 @@ const
(Value: ecBlockUnindent; Name: 'ecBlockUnindent'), (Value: ecBlockUnindent; Name: 'ecBlockUnindent'),
(Value: ecBlockIndentMove; Name: 'ecBlockIndentMove'), (Value: ecBlockIndentMove; Name: 'ecBlockIndentMove'),
(Value: ecBlockUnindentMove; Name: 'ecBlockUnindentMove'), (Value: ecBlockUnindentMove; Name: 'ecBlockUnindentMove'),
(Value: ecColumnBlockShiftRight; Name: 'ecColumnBlockShiftRight'),
(Value: ecColumnBlockMoveRight; Name: 'ecColumnBlockMoveRight'),
(Value: ecColumnBlockShiftLeft; Name: 'ecColumnBlockShiftLeft'),
(Value: ecColumnBlockMoveLeft; Name: 'ecColumnBlockMoveLeft'),
(Value: ecTab; Name: 'ecTab'), (Value: ecTab; Name: 'ecTab'),
(Value: ecShiftTab; Name: 'ecShiftTab'), (Value: ecShiftTab; Name: 'ecShiftTab'),
(Value: ecMatchBracket; Name: 'ecMatchBracket'), (Value: ecMatchBracket; Name: 'ecMatchBracket'),

View File

@ -72,7 +72,7 @@ function fsNot (s : TFontStyles) : TFontStyles; inline;
function fsXor (s1,s2 : TFontStyles) : TFontStyles; inline; function fsXor (s1,s2 : TFontStyles) : TFontStyles; inline;
function CreateTabsAndSpaces(StartPos, SpaceLen, TabWidth: integer; function CreateTabsAndSpaces(StartPos, SpaceLen, TabWidth: integer;
UseTabs: boolean): string; MaxTabs: integer): string;
procedure SynAssert(Condition: Boolean; Msg: String); procedure SynAssert(Condition: Boolean; Msg: String);
procedure SynAssert(Condition: Boolean; Msg: String; Args: Array of Const); procedure SynAssert(Condition: Boolean; Msg: String; Args: Array of Const);
@ -227,29 +227,30 @@ begin
Result:=0; Result:=0;
end; end;
function CreateTabsAndSpaces(StartPos, SpaceLen, TabWidth: integer; function CreateTabsAndSpaces(StartPos, SpaceLen, TabWidth: integer; MaxTabs: integer): string;
UseTabs: boolean): string;
var var
TabCount: Integer; TabCount: Integer;
EndPos: Integer; EndPos: Integer;
PosPlusOneTab: Integer; PosPlusOneTab: Integer;
begin begin
Result:=''; Result:='';
if not UseTabs then begin if MaxTabs = 0 then begin
Result:=StringOfChar(' ',SpaceLen); Result:=StringOfChar(' ',SpaceLen);
exit; exit;
end; end;
TabCount:=0; TabCount:=0;
EndPos:=StartPos+SpaceLen; EndPos:=StartPos+SpaceLen;
while StartPos<EndPos do begin while StartPos<EndPos do begin
PosPlusOneTab:=StartPos+TabWidth-((StartPos-1) mod TabWidth); if TabCount < MaxTabs then begin
if PosPlusOneTab<=EndPos then begin PosPlusOneTab:=StartPos+TabWidth-((StartPos-1) mod TabWidth);
inc(TabCount); if PosPlusOneTab<=EndPos then begin
StartPos:=PosPlusOneTab; inc(TabCount);
end else begin StartPos:=PosPlusOneTab;
Result:=StringOfChar(' ',EndPos-StartPos); Continue;
break; end;
end; end;
Result:=StringOfChar(' ',EndPos-StartPos);
break;
end; end;
if TabCount>0 then if TabCount>0 then
Result:=StringOfChar(#9,TabCount)+Result; Result:=StringOfChar(#9,TabCount)+Result;

View File

@ -2583,6 +2583,7 @@ begin
(SelectionObj.ActiveSelectionMode = smColumn) (SelectionObj.ActiveSelectionMode = smColumn)
then then
ClearCarets; ClearCarets;
ecColumnBlockShiftRight, ecColumnBlockMoveRight, ecColumnBlockShiftLeft, ecColumnBlockMoveLeft,
ecBlockIndent, ecBlockUnindent, ecBlockIndentMove, ecBlockUnindentMove: ecBlockIndent, ecBlockUnindent, ecBlockIndentMove, ecBlockUnindentMove:
if (not Editor.ReadOnly) and Editor.SelAvail and (SelectionObj.ActiveSelectionMode = smColumn) if (not Editor.ReadOnly) and Editor.SelAvail and (SelectionObj.ActiveSelectionMode = smColumn)
then then
@ -2706,6 +2707,7 @@ begin
else else
ExecCommandRepeated; ExecCommandRepeated;
end; end;
ecColumnBlockShiftRight, ecColumnBlockMoveRight, ecColumnBlockShiftLeft, ecColumnBlockMoveLeft,
ecBlockIndent, ecBlockUnindent, ecBlockIndentMove, ecBlockUnindentMove: ecBlockIndent, ecBlockUnindent, ecBlockIndentMove, ecBlockUnindentMove:
begin begin
StartEditing; StartEditing;

View File

@ -6,7 +6,9 @@ interface
uses uses
SysUtils, testregistry, TestBase, math, Types, SysUtils, testregistry, TestBase, math, Types,
SynEdit, SynEditKeyCmds, SynEditTypes; SynEdit, SynEditKeyCmds, SynEditTypes, Forms,
LazLoggerDummy;
//LazLogger;
type type
@ -681,7 +683,11 @@ var
PushBaseName(''); PushBaseName('');
SetSelect(x1,y1, x2,y2); SetSelect(x1,y1, x2,y2);
DebugLn();
DebugLn('#############################################');
DebugLn(MyDbg(SynEdit.Text, True));Application.ProcessMessages;
SynEdit.CommandProcessor(TheCommand, '', nil); SynEdit.CommandProcessor(TheCommand, '', nil);
DebugLn(MyDbg(SynEdit.Text, True));Application.ProcessMessages;
TestColSelAndText('indend', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub ); TestColSelAndText('indend', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub );
if ATestUndoRedo = 0 then exit; if ATestUndoRedo = 0 then exit;
@ -715,6 +721,7 @@ var
DoTest(AName, x1, y1, x2, y2, ExpectSelStartX1, ExpCaretX1, AnInsText, AnXPos1, undo); DoTest(AName, x1, y1, x2, y2, ExpectSelStartX1, ExpCaretX1, AnInsText, AnXPos1, undo);
SynEdit.CommandProcessor(TheCommand, '', nil); SynEdit.CommandProcessor(TheCommand, '', nil);
DebugLn(MyDbg(SynEdit.Text, True)); Application.ProcessMessages;
TestColSelAndText('indend 2', ExpectSelStartX2,y1, ExpCaretX2,y2, TestTextSub2 ); TestColSelAndText('indend 2', ExpectSelStartX2,y1, ExpCaretX2,y2, TestTextSub2 );
SynEdit.CommandProcessor(ecUndo, '', nil); SynEdit.CommandProcessor(ecUndo, '', nil);
@ -928,19 +935,27 @@ var
PushBaseName(''); PushBaseName('');
SetSelect(x1,y1, x2,y2); SetSelect(x1,y1, x2,y2);
DebugLn();
DebugLn('#############################################');
DebugLn(MyDbg(SynEdit.Text, True));Application.ProcessMessages;
SynEdit.CommandProcessor(TheCommand, '', nil); SynEdit.CommandProcessor(TheCommand, '', nil);
DebugLn(MyDbg(SynEdit.Text, True));Application.ProcessMessages;
TestColSelAndText('unindend', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub ); TestColSelAndText('unindend', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub );
if ATestUndoRedo = 0 then exit; if ATestUndoRedo = 0 then exit;
SynEdit.CommandProcessor(ecUndo, '', nil); SynEdit.CommandProcessor(ecUndo, '', nil);
Application.ProcessMessages;
TestColSelAndText('undo 1', x1,y1, x2,y2, TestTextColumn2 ); TestColSelAndText('undo 1', x1,y1, x2,y2, TestTextColumn2 );
SynEdit.CommandProcessor(ecRedo, '', nil); SynEdit.CommandProcessor(ecRedo, '', nil);
Application.ProcessMessages;
TestColSelAndText('redo 1', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub ); TestColSelAndText('redo 1', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub );
if ATestUndoRedo = 1 then exit; if ATestUndoRedo = 1 then exit;
SynEdit.CommandProcessor(ecUndo, '', nil); SynEdit.CommandProcessor(ecUndo, '', nil);
Application.ProcessMessages;
TestColSelAndText('undo 2', x1,y1, x2,y2, TestTextColumn2 ); TestColSelAndText('undo 2', x1,y1, x2,y2, TestTextColumn2 );
SynEdit.CommandProcessor(ecRedo, '', nil); SynEdit.CommandProcessor(ecRedo, '', nil);
Application.ProcessMessages;
TestColSelAndText('redo 2', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub ); TestColSelAndText('redo 2', ExpectSelStartX,y1, ExpCaretX,y2, TestTextSub );
PopBaseName; PopBaseName;
@ -968,6 +983,7 @@ var
DoTest(AName, x1, y1, x2, y2, ExpectSelStartX1, ExpCaretX1, AnXDelPos1, AnInsText1, AnXPos1, undo); DoTest(AName, x1, y1, x2, y2, ExpectSelStartX1, ExpCaretX1, AnXDelPos1, AnInsText1, AnXPos1, undo);
SynEdit.CommandProcessor(TheCommand, '', nil); SynEdit.CommandProcessor(TheCommand, '', nil);
DebugLn(MyDbg(SynEdit.Text, True)); Application.ProcessMessages;
TestColSelAndText('unindend 2', ExpectSelStartX2,y1, ExpCaretX2,y2, TestTextSub2 ); TestColSelAndText('unindend 2', ExpectSelStartX2,y1, ExpCaretX2,y2, TestTextSub2 );
SynEdit.CommandProcessor(ecUndo, '', nil); SynEdit.CommandProcessor(ecUndo, '', nil);
@ -1034,8 +1050,16 @@ ABCDEFGHIJKLMNOPQRSTUABCDEFGHIJKLMNOPQRSTU';
SynEdit.BlockTabIndent := 1; SynEdit.BlockTabIndent := 1;
DoTest2('', 15,2, 4,3, 12, 4, 9, 4, [0,0, 11,3, 4,4], [0,0, 8,3, 4,2], #9'',[0,0,4], '',[], False); DoTest2('', 15,2, 4,3, 12, 4, 9, 4, [0,0, 11,3, 4,4], [0,0, 8,3, 4,2], #9'',[0,0,4], '',[], False);
SynEdit.TabWidth := 1;
SynEdit.BlockIndent := 0;
SynEdit.BlockTabIndent := 2;
DoTest2('', 11,3, 4,3, 9, 4, 7, 4, [0,0, 0,0, 4,2], [0,0, 0,0, 4,2], '',[], '',[], False);
SynEdit.BlockTabIndent := 3;
DoTest2('', 11,3, 4,3, 8, 4, 5, 4, [0,0, 0,0, 4,3], [0,0, 0,0, 4,3], '',[], '',[], False);
SynEdit.Options := SynEdit.Options + [eoGroupUndo] + [eoShowSpecialChars]; SynEdit.Options := SynEdit.Options + [eoGroupUndo] + [eoShowSpecialChars];
SynEdit.TabWidth := 5;
SynEdit.BlockIndent := 2; SynEdit.BlockIndent := 2;
SynEdit.BlockTabIndent := 0; SynEdit.BlockTabIndent := 0;

View File

@ -554,6 +554,10 @@ begin
ecBlockUnindent : Result:= srkmecBlockUnindent; ecBlockUnindent : Result:= srkmecBlockUnindent;
ecBlockIndentMove : Result:= srkmecBlockIndentMove; ecBlockIndentMove : Result:= srkmecBlockIndentMove;
ecBlockUnindentMove : Result:= srkmecBlockUnindentMove; ecBlockUnindentMove : Result:= srkmecBlockUnindentMove;
ecColumnBlockShiftRight : Result:= srkmecColumnBlockShiftRight;
ecColumnBlockMoveRight : Result:= srkmecColumnBlockMoveRight;
ecColumnBlockShiftLeft : Result:= srkmecColumnBlockShiftLeft;
ecColumnBlockMoveLeft : Result:= srkmecColumnBlockMoveLeft;
ecTab : Result:= lisTab; ecTab : Result:= lisTab;
ecShiftTab : Result:= srkmecShiftTab; ecShiftTab : Result:= srkmecShiftTab;
ecMatchBracket : Result:= srkmecMatchBracket; ecMatchBracket : Result:= srkmecMatchBracket;
@ -2882,6 +2886,10 @@ begin
AddDefault(C, 'Unindent block', srkmecBlockUnindent, ecBlockUnindent); AddDefault(C, 'Unindent block', srkmecBlockUnindent, ecBlockUnindent);
AddDefault(C, 'Indent block move', srkmecBlockIndentMove, ecBlockIndentMove); AddDefault(C, 'Indent block move', srkmecBlockIndentMove, ecBlockIndentMove);
AddDefault(C, 'Unindent block move', srkmecBlockUnindentMove, ecBlockUnindentMove); AddDefault(C, 'Unindent block move', srkmecBlockUnindentMove, ecBlockUnindentMove);
AddDefault(C, 'Shift right column block', srkmecColumnBlockShiftRight, ecColumnBlockShiftRight);
AddDefault(C, 'Move right column block', srkmecColumnBlockMoveRight, ecColumnBlockMoveRight);
AddDefault(C, 'Shift left column block', srkmecColumnBlockShiftLeft, ecColumnBlockShiftLeft);
AddDefault(C, 'Move left column block', srkmecColumnBlockMoveLeft, ecColumnBlockMoveLeft);
AddDefault(C, 'Uppercase selection', lisMenuUpperCaseSelection, ecSelectionUpperCase); AddDefault(C, 'Uppercase selection', lisMenuUpperCaseSelection, ecSelectionUpperCase);
AddDefault(C, 'Lowercase selection', lisMenuLowerCaseSelection, ecSelectionLowerCase); AddDefault(C, 'Lowercase selection', lisMenuLowerCaseSelection, ecSelectionLowerCase);
AddDefault(C, 'Swap case in selection', lisMenuSwapCaseSelection, ecSelectionSwapCase); AddDefault(C, 'Swap case in selection', lisMenuSwapCaseSelection, ecSelectionSwapCase);

View File

@ -3123,6 +3123,10 @@ resourcestring
srkmecBlockUnindent = 'Unindent line/block'; srkmecBlockUnindent = 'Unindent line/block';
srkmecBlockIndentMove = 'Indent line/block (move columns)'; srkmecBlockIndentMove = 'Indent line/block (move columns)';
srkmecBlockUnindentMove = 'Unindent line/block (move columns)'; srkmecBlockUnindentMove = 'Unindent line/block (move columns)';
srkmecColumnBlockShiftRight = 'Shift right column-block (delete in columns)';
srkmecColumnBlockMoveRight = 'Move right column-block (delete after columns)';
srkmecColumnBlockShiftLeft = 'Shift left column-block (delete in columns)';
srkmecColumnBlockMoveLeft = 'Move left column-block (delete before columns)';
srkmecPluginMultiCaretSetCaret = 'Add extra caret'; srkmecPluginMultiCaretSetCaret = 'Add extra caret';
srkmecPluginMultiCaretUnsetCaret = 'Remove extra caret'; srkmecPluginMultiCaretUnsetCaret = 'Remove extra caret';
srkmecPluginMultiCaretToggleCaret = 'Toggle extra caret'; srkmecPluginMultiCaretToggleCaret = 'Toggle extra caret';