{$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 AX0) 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+1AToY) 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=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;