procedure TRichEditStrings.Insert(Index: Integer; const S: string);
function CountLineBreaks(const S: string): Integer;
const
LB = #13#10;
var
P: Integer;
begin
Result := 0;
P := Pos(LB, S);
while P <> 0 do
begin
Inc(Result);
P := PosEx(LB, S, P + 2);
end;
end;
const
CRLF = #13;
var
L: Integer;
Selection: TCharRange;
Fmt, Str: string;
begin
if Index >= 0 then
begin
Selection.cpMin := SendMessage(RichEdit.Handle, EM_LINEINDEX, Index, 0);
if Selection.cpMin >= 0 then
Fmt := '%s' + CRLF
else
begin
Selection.cpMin := SendMessage(RichEdit.Handle, EM_LINEINDEX, Index - 1, 0);
if Selection.cpMin < 0 then Exit;
L := SendMessage(RichEdit.Handle, EM_LINELENGTH, Selection.cpMin, 0);
if L = 0 then Exit;
Inc(Selection.cpMin, L);
Fmt := CRLF + '%s';
end;
Selection.cpMax := Selection.cpMin;
SendStructMessage(RichEdit.Handle, EM_EXSETSEL, 0, Selection);
Str := Format(Fmt, [S]);
SendTextMessage(RichEdit.Handle, EM_REPLACESEL, 0, Str);
// RichEdit 2.0 replaces CRLF pairs with CR. We need to account for that when
// verifying that the insertion succeeded in case S contains a CRLF pair.
if RichEdit.SelStart <> (Selection.cpMax + Length(Str) - CountLineBreaks(Str)) then
raise EOutOfResources.Create(sRichEditInsertError);
end;
end;