lasarus_compotents/ATSynEdit/atsynedit/atstrings_editing.inc

356 lines
7.6 KiB
PHP

{$ifdef none}begin end;{$endif}
procedure TATStrings.TextInsert(AX, AY: integer; const AText: atString; AOverwrite: boolean; out AShift, APosAfter: TPoint);
var
Str, StrLead, StrTail: atString;
List: TATStrings;
bWithEol, bInsertAtEnd: boolean;
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AX;
APosAfter.Y:= AY;
if not IsIndexValid(AY) then Exit;
if AX<0 then Exit;
if AText='' then Exit;
Str:= Lines[AY];
bInsertAtEnd:= AX>=Length(Str);
if not bInsertAtEnd then
begin
StrLead:= Copy(Str, 1, AX);
StrTail:= Copy(Str, AX+1, MaxInt);
end
else
begin
StrLead:= Str+StringOfChar(' ', AX-Length(Str));
StrTail:= '';
end;
if AOverwrite then
Delete(StrTail, 1, Length(AText));
//------------------
//Insert single line
if not SWithBreaks(AText) then
begin
Lines[AY]:= StrLead+AText+StrTail;
if not AOverwrite then
AShift.X:= Length(AText);
APosAfter.X:= AX+Length(AText);
Exit
end;
//----------------------
//Insert multi-line text
List:= TATStrings.Create;
BeginUndoGroup;
try
List.LoadFromString(StrLead+AText);
List.ActionDeleteFakeLine;
if List.Count=0 then Exit;
if StrTail<>'' then
Lines[AY]:= StrTail
else
if Lines[AY]<>'' then
LineDelete(AY);
bWithEol:= SEndsWith(AText, #10) or
SEndsWith(AText, #13) or
bInsertAtEnd //need for (paste N lines, no final eol, at end of line)
;
LineInsertStrings(AY, List, bWithEol);
if bWithEol then
begin
APosAfter.X:= 0;
APosAfter.Y:= AY+List.Count;
end
else
begin
APosAfter.X:= Length(List.Lines[List.Count-1]);
APosAfter.Y:= AY+List.Count-1;
end;
AShift.Y:= APosAfter.Y-AY;
finally
FreeAndNil(List);
EndUndoGroup;
end;
end;
procedure TATStrings.TextDeleteLeft(AX, AY: integer; ALen: integer; out AShift,
APosAfter: TPoint);
var
Str, StrPrev: atString;
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AX;
APosAfter.Y:= AY;
if not IsIndexValid(AY) then Exit;
Str:= Lines[AY];
//handle spec case: caret on last fake line, BkSp pressed:
//delete fake line,
//delete EOL at prev line
if (AX=0) and (AY=Count-1) and (AY>0) and IsLastLineFake then
begin
LineDelete(AY, false);
LinesEnds[AY-1]:= cEndNone;
AShift.Y:= -1;
APosAfter.X:= Length(Lines[AY-1]);
APosAfter.Y:= AY-1;
exit
end;
if AX>0 then
begin
if AX<=Length(Str) then
begin
System.Delete(Str, Max(1, AX+1-ALen), ALen);
Lines[AY]:= Str;
end;
AShift.X:= -Min(AX, ALen);
APosAfter.X:= Max(0, AX-ALen);
end
else
if AY>0 then
begin
StrPrev:= Lines[AY-1];
Lines[AY-1]:= StrPrev+Str;
LineDelete(AY);
AShift.Y:= -1;
APosAfter.X:= Length(StrPrev);
APosAfter.Y:= AY-1;
end;
end;
procedure TATStrings.TextDeleteRight(AX, AY: integer; ALen: integer; out AShift,
APosAfter: TPoint; ACanDelEol: boolean = true);
var
Str: atString;
DelEol: boolean;
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AX;
APosAfter.Y:= AY;
if not IsIndexValid(AY) then Exit;
Str:= Lines[AY];
//special case: last fake line
if (AY=Count-1) and (Str='') and (LinesEnds[AY]=cEndNone) then
Exit;
DelEol:= false;
if AX<Length(Str) then
begin
System.Delete(Str, AX+1, ALen);
Lines[AY]:= Str;
AShift.X:= -ALen;
end
else
DelEol:= ACanDelEol;
if DelEol then
if Str='' then //handle for simpler line-states
begin
AShift.Y:= -1;
if (AY>0) and (AY=Count-1) then
begin
APosAfter.X:= 0;
APosAfter.Y:= AY-1;
end;
LineDelete(AY);
end
else
begin
//add spaces if we are after eol
if AX>=Length(Str) then
Str:= Str+StringOfChar(' ', AX-Length(Str));
//not last: del next line
if AY+1<Count then
begin
Lines[AY]:= Str+Lines[AY+1];
LineDelete(AY+1, false{not force});
//maybe also eol
if AY=Count-1 then
LinesEnds[AY]:= cEndNone;
end
else
//last line: del eol
LinesEnds[AY]:= cEndNone;
AShift.Y:= -1;
end;
end;
procedure TATStrings.TextDeleteRange(AFromX, AFromY, AToX, AToY: integer;
out AShift, APosAfter: TPoint);
var
Str: atString;
bDelEmpty: boolean;
bNoEol: boolean;
i: integer;
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AFromX;
APosAfter.Y:= AFromY;
if not IsIndexValid(AFromY) then Exit;
if not IsIndexValid(AToY) then Exit;
if (AFromX=AToX) and (AFromY=AToY) then Exit;
if (AFromY>AToY) then Exit;
if AFromY=AToY then
begin
//delete range in one line
Str:= Lines[AFromY];
Delete(Str, AFromX+1, AToX-AFromX);
Lines[AFromY]:= Str;
AShift.X:= -(AToX-AFromX);
end
else
begin
bDelEmpty:= false;
//correct AToX/AToY to not del extra empty line
if (AToX=0) and (Lines[AToY]='') then //for empty last line
begin
AToY:= Max(0, AToY-1);
AToX:= Length(Lines[AToY]);
bDelEmpty:= true;
end;
//remember no final Eol
bNoEol:= (AToY=Count-1) and (LinesEnds[AToY]=cEndNone);
//place ramaining parts of 1st+last lines
Str:= Copy(Lines[AFromY], 1, AFromX) + Copy(Lines[AToY], AToX+1, MaxInt);
Lines[AFromY]:= Str;
//del middle lines
for i:= AToY downto AFromY+1 do
LineDelete(i);
//del empty line?
if bDelEmpty then
if Str='' then
LineDelete(AFromY);
if bNoEol then
begin
ActionDeleteFakeLine;
if Count>0 then
LinesEnds[Count-1]:= cEndNone;
end;
AShift.Y:= -(AToY-AFromY);
end;
end;
procedure TATStrings.TextInsertColumnBlock(AX, AY: integer; ABlock: TATStrings; AOverwrite: boolean);
var
Shift, PosAfter: TPoint;
i: integer;
begin
for i:= 0 to ABlock.Count-1 do
begin
TextInsert(AX, AY+i, ABlock.Lines[i], AOverwrite, Shift, PosAfter);
LinesEnds[AY+i]:= Endings; //force eol
if not IsIndexValid(AY+i+1) then
LineAddRaw('', cEndNone);
end;
end;
procedure TATStrings.TextInsertEol(AX, AY: integer; AKeepCaret: boolean; const AStrIndent: atString; out AShift, APosAfter: TPoint);
var
Str, StrMove: atString;
NewEnd: TATLineEnds;
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AX;
APosAfter.Y:= AY;
if not IsIndexValid(AY) then Exit;
Str:= Lines[AY];
StrMove:= '';
//special case AX=0: just insert empty line
//(less changes in undo)
if AX=0 then
begin
LineInsertRaw(AY, '', Endings);
end
else
begin
BeginUndoGroup;
if (AX<Length(Str)) then
begin
StrMove:= Copy(Str, AX+1, MaxInt);
Delete(Str, AX+1, MaxInt);
Lines[AY]:= Str;
end;
//handle situation when we at non-eol line, this must give
//inserted line also w/o eol
NewEnd:= LinesEnds[AY];
LinesEnds[AY]:= Endings; //force eol to cur line
LineInsertRaw(AY+1, AStrIndent+StrMove, NewEnd);
EndUndoGroup;
end;
if not AKeepCaret then
begin
APosAfter.X:= Length(AStrIndent);
APosAfter.Y:= AY+1;
AShift.Y:= 1;
end;
end;
procedure TATStrings.TextDeleteLine(AX, AY: integer; out AShift, APosAfter: TPoint);
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AX;
APosAfter.Y:= AY;
if not IsIndexValid(AY) then Exit;
AShift.Y:= -1;
APosAfter.X:= 0;
LineDelete(AY);
if AY>=Count then
LineAddEx('', cEndNone);
end;
procedure TATStrings.TextDuplicateLine(AX, AY: integer; out AShift, APosAfter: TPoint);
begin
AShift.X:= 0;
AShift.Y:= 0;
APosAfter.X:= AX;
APosAfter.Y:= AY;
if not IsIndexValid(AY) then Exit;
LineInsert(AY+1, Lines[AY]);
if LinesEnds[AY]<>Endings then
LinesEnds[AY]:= Endings;
LinesEnds[AY+1]:= Endings;
AShift.Y:= 1;
end;