Subversion Repositories fastphp

Rev

Rev 15 | Rev 17 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
8 daniel-mar 1
unit EditorMain;
2 daniel-mar 2
 
4 daniel-mar 3
(*
4
  This program requires
5
  - Microsoft Internet Controls (TWebBrowser)
6
    If you are using Delphi 10.1 Starter Edition, please import the ActiveX TLB
7
    "Microsoft Internet Controls"
8
  - SynEdit
9
    You can obtain SynEdit via Embarcadero GetIt
10
*)
11
 
2 daniel-mar 12
// TODO: localize
13
// TODO: wieso geht copy paste im twebbrowser nicht???
14
// Wieso dauert webbrowser1 erste kompilierung so lange???
5 daniel-mar 15
// TODO: wieso kommt syntax fehler zweimal? einmal stderr einmal stdout?
16
// TODO: Browser titlebar (link preview)
2 daniel-mar 17
 
18
// Future ideas
19
// - ToDo list
20
// - verschiedene php versionen?
21
// - webbrowser1 nur laden, wenn man den tab anwählt?
22
// - doppelklick auf tab soll diesen schließen
5 daniel-mar 23
// - Onlinehelp (www) aufrufen
13 daniel-mar 24
// - Let all colors be adjustable
25
// - code in bildschirmmitte?
2 daniel-mar 26
 
27
interface
28
 
29
uses
30
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
4 daniel-mar 31
  Dialogs, StdCtrls, OleCtrls, ComCtrls, ExtCtrls, ToolWin, IniFiles,
13 daniel-mar 32
  SynEditHighlighter, SynHighlighterPHP, SynEdit, SHDocVw_TLB, FindReplace,
33
  System.Actions, Vcl.ActnList;
2 daniel-mar 34
 
35
type
36
  TForm1 = class(TForm)
37
    PageControl1: TPageControl;
38
    PlaintextTabSheet: TTabSheet;
39
    HtmlTabSheet: TTabSheet;
40
    Memo2: TMemo;
41
    WebBrowser1: TWebBrowser;
42
    Splitter1: TSplitter;
43
    PageControl2: TPageControl;
44
    TabSheet3: TTabSheet;
45
    HelpTabsheet: TTabSheet;
46
    WebBrowser2: TWebBrowser;
47
    OpenDialog1: TOpenDialog;
48
    Panel1: TPanel;
49
    OpenDialog3: TOpenDialog;
4 daniel-mar 50
    SynEdit1: TSynEdit;
51
    SynPHPSyn1: TSynPHPSyn;
5 daniel-mar 52
    Panel2: TPanel;
53
    SynEditFocusTimer: TTimer;
54
    Button1: TButton;
55
    Button2: TButton;
56
    Button3: TButton;
13 daniel-mar 57
    Button4: TButton;
58
    Button5: TButton;
59
    Button6: TButton;
60
    ActionList: TActionList;
61
    ActionFind: TAction;
62
    ActionReplace: TAction;
63
    ActionFindNext: TAction;
64
    ActionGoto: TAction;
65
    ActionSave: TAction;
66
    ActionHelp: TAction;
67
    ActionRun: TAction;
68
    ActionESC: TAction;
69
    Button7: TButton;
15 daniel-mar 70
    ActionOpen: TAction;
71
    Button8: TButton;
2 daniel-mar 72
    procedure Run(Sender: TObject);
73
    procedure FormShow(Sender: TObject);
74
    procedure FormCreate(Sender: TObject);
75
    procedure FormDestroy(Sender: TObject);
76
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
77
    procedure PageControl2Changing(Sender: TObject; var AllowChange: Boolean);
5 daniel-mar 78
    procedure Memo2DblClick(Sender: TObject);
79
    procedure WebBrowser1BeforeNavigate2(ASender: TObject;
80
      const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
81
      Headers: OleVariant; var Cancel: WordBool);
82
    procedure SynEditFocusTimerTimer(Sender: TObject);
13 daniel-mar 83
    procedure ActionFindExecute(Sender: TObject);
84
    procedure ActionReplaceExecute(Sender: TObject);
85
    procedure ActionFindNextExecute(Sender: TObject);
86
    procedure ActionGotoExecute(Sender: TObject);
87
    procedure ActionSaveExecute(Sender: TObject);
88
    procedure ActionHelpExecute(Sender: TObject);
89
    procedure ActionRunExecute(Sender: TObject);
90
    procedure ActionESCExecute(Sender: TObject);
91
    procedure SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
92
      MousePos: TPoint; var Handled: Boolean);
93
    procedure SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
94
      MousePos: TPoint; var Handled: Boolean);
15 daniel-mar 95
    procedure ActionOpenExecute(Sender: TObject);
96
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
2 daniel-mar 97
  private
98
    CurSearchTerm: string;
99
    HlpPrevPageIndex: integer;
13 daniel-mar 100
    SrcRep: TFindReplace;
2 daniel-mar 101
    procedure Help;
5 daniel-mar 102
    function MarkUpLineReference(cont: string): string;
2 daniel-mar 103
  protected
104
    ChmIndex: TMemIniFile;
5 daniel-mar 105
    procedure GotoLineNo(LineNo:integer);
2 daniel-mar 106
    function GetScrapFile: string;
107
  end;
108
 
109
var
110
  Form1: TForm1;
111
 
112
implementation
113
 
114
{$R *.dfm}
115
 
116
uses
15 daniel-mar 117
  Functions, StrUtils, WebBrowserUtils, FastPHPUtils, Math, ShellAPI;
2 daniel-mar 118
 
13 daniel-mar 119
// TODO: FindPrev ?
120
procedure TForm1.ActionFindNextExecute(Sender: TObject);
121
begin
122
  SrcRep.FindNext;
123
end;
124
 
125
procedure TForm1.ActionGotoExecute(Sender: TObject);
5 daniel-mar 126
var
127
  val: string;
128
  lineno: integer;
129
begin
13 daniel-mar 130
  // TODO: VK_LMENU does not work! only works with AltGr but not Alt
131
  // http://stackoverflow.com/questions/16828250/delphi-xe2-how-to-prevent-the-alt-key-stealing-focus ?
5 daniel-mar 132
 
13 daniel-mar 133
  InputQuery('Go to', 'Line number:', val);
134
  if not TryStrToInt(val, lineno) then
135
  begin
136
    if SynEdit1.CanFocus then SynEdit1.SetFocus;
137
    exit;
138
  end;
139
  GotoLineNo(lineno);
140
end;
5 daniel-mar 141
 
13 daniel-mar 142
procedure TForm1.ActionHelpExecute(Sender: TObject);
143
begin
144
  Help;
145
  if PageControl2.ActivePage = HelpTabsheet then
146
    WebBrowser2.SetFocus
147
  else if PageControl2.ActivePage = TabSheet3{Scrap} then
148
    SynEdit1.SetFocus;
149
end;
8 daniel-mar 150
 
15 daniel-mar 151
procedure TForm1.ActionOpenExecute(Sender: TObject);
152
begin
153
  If OpenDialog3.Execute then
154
  begin
155
    ShellExecute(0, 'open', PChar(ParamStr(0)), PChar(OpenDialog3.FileName), '', SW_NORMAL);
156
  end;
157
end;
158
 
13 daniel-mar 159
procedure TForm1.ActionReplaceExecute(Sender: TObject);
160
begin
161
  SrcRep.ReplaceExecute;
162
end;
5 daniel-mar 163
 
13 daniel-mar 164
procedure TForm1.ActionRunExecute(Sender: TObject);
165
begin
166
  Run(Sender);
167
  SynEdit1.SetFocus;
168
end;
5 daniel-mar 169
 
13 daniel-mar 170
procedure TForm1.ActionSaveExecute(Sender: TObject);
171
begin
172
  SynEdit1.Lines.SaveToFile(GetScrapFile);
16 daniel-mar 173
  SynEdit1.Modified := false;
13 daniel-mar 174
end;
175
 
176
procedure TForm1.ActionESCExecute(Sender: TObject);
177
begin
178
  if (HlpPrevPageIndex <> -1) and (PageControl2.ActivePage = HelpTabSheet) and
179
     (HelpTabsheet.TabVisible) then
180
  begin
181
    PageControl2.ActivePageIndex := HlpPrevPageIndex;
182
    HelpTabsheet.TabVisible := false;
2 daniel-mar 183
  end;
13 daniel-mar 184
 
185
  // Dirty hack...
186
  SrcRep._FindDialog.CloseDialog;
187
  SrcRep._ReplaceDialog.CloseDialog;
2 daniel-mar 188
end;
189
 
13 daniel-mar 190
procedure TForm1.ActionFindExecute(Sender: TObject);
191
begin
192
  SrcRep.FindExecute;
193
end;
194
 
16 daniel-mar 195
var
196
  firstTimeBrowserLoad: boolean = true;
2 daniel-mar 197
procedure TForm1.Run(Sender: TObject);
16 daniel-mar 198
var
199
  bakTS: TTabSheet;
2 daniel-mar 200
begin
5 daniel-mar 201
  memo2.Lines.Text := '';
16 daniel-mar 202
 
203
  if firstTimeBrowserLoad then
204
  begin
205
    bakTS := PageControl1.ActivePage;
206
    try
207
      PageControl1.ActivePage := HtmlTabSheet; // Required for the first time, otherwise, WebBrowser1.Clear will hang
208
      Webbrowser1.Clear;
209
    finally
210
      PageControl1.ActivePage := bakTS;
211
    end;
212
    firstTimeBrowserLoad := false;
213
  end
214
  else
215
    Webbrowser1.Clear;
216
 
5 daniel-mar 217
  Screen.Cursor := crHourGlass;
218
  Application.ProcessMessages;
219
 
220
  try
221
    SynEdit1.Lines.SaveToFile(GetScrapFile);
222
 
8 daniel-mar 223
    memo2.Lines.Text := RunPHPScript(GetScrapFile);
5 daniel-mar 224
 
8 daniel-mar 225
    Webbrowser1.LoadHTML(MarkUpLineReference(memo2.Lines.Text), GetScrapFile);
5 daniel-mar 226
 
227
    if IsTextHTML(memo2.lines.text) then
228
      PageControl1.ActivePage := HtmlTabSheet
229
    else
230
      PageControl1.ActivePage := PlaintextTabSheet;
231
  finally
232
    Screen.Cursor := crDefault;
2 daniel-mar 233
  end;
5 daniel-mar 234
end;
2 daniel-mar 235
 
13 daniel-mar 236
procedure TForm1.SynEdit1MouseWheelDown(Sender: TObject; Shift: TShiftState;
237
  MousePos: TPoint; var Handled: Boolean);
238
begin
239
  if ssCtrl in Shift then
240
  begin
241
    SynEdit1.Font.Size := Max(SynEdit1.Font.Size - 1, 5);
242
  end;
243
end;
244
 
245
procedure TForm1.SynEdit1MouseWheelUp(Sender: TObject; Shift: TShiftState;
246
  MousePos: TPoint; var Handled: Boolean);
247
begin
248
  if ssCtrl in Shift then
249
  begin
250
    SynEdit1.Font.Size := SynEdit1.Font.Size + 1;
251
  end;
252
end;
253
 
5 daniel-mar 254
procedure TForm1.SynEditFocusTimerTimer(Sender: TObject);
255
begin
256
  SynEditFocusTimer.Enabled := false;
257
  Button1.SetFocus; // Workaround for weird bug... This (and the timer) is necessary to get the focus to SynEdit1
258
  SynEdit1.SetFocus;
259
end;
2 daniel-mar 260
 
5 daniel-mar 261
procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject;
262
  const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData,
263
  Headers: OleVariant; var Cancel: WordBool);
264
var
8 daniel-mar 265
  s, myURL: string;
5 daniel-mar 266
  lineno: integer;
7 daniel-mar 267
  p: integer;
5 daniel-mar 268
begin
7 daniel-mar 269
  {$REGION 'Line number references (PHP errors and warnings)'}
8 daniel-mar 270
  if Copy(URL, 1, length(FASTPHP_GOTO_URI_PREFIX)) = FASTPHP_GOTO_URI_PREFIX then
5 daniel-mar 271
  begin
272
    try
8 daniel-mar 273
      s := copy(URL, length(FASTPHP_GOTO_URI_PREFIX)+1, 99);
5 daniel-mar 274
      if not TryStrToInt(s, lineno) then exit;
275
      GotoLineNo(lineno);
276
      SynEditFocusTimer.Enabled := true;
277
    finally
278
      Cancel := true;
279
    end;
8 daniel-mar 280
    Exit;
5 daniel-mar 281
  end;
7 daniel-mar 282
  {$ENDREGION}
283
 
8 daniel-mar 284
  {$REGION 'Intelligent browser (executes PHP scripts)'}
7 daniel-mar 285
  if URL <> 'about:blank' then
286
  begin
287
    myUrl := URL;
288
 
8 daniel-mar 289
    p := Pos('?', myUrl);
290
    if p >= 1 then myURL := copy(myURL, 1, p-1);
7 daniel-mar 291
 
8 daniel-mar 292
    // TODO: myURL urldecode
293
    // TODO: maybe we could even open that file in the editor!
7 daniel-mar 294
 
8 daniel-mar 295
    if FileExists(myURL) and (EndsText('.php', myURL) or EndsText('.php3', myURL) or EndsText('.php4', myURL) or EndsText('.php5', myURL) or EndsText('.phps', myURL)) then
7 daniel-mar 296
    begin
8 daniel-mar 297
      WebBrowser1.LoadHTML(GetDosOutput('"'+GetPHPExe+'" "'+myURL+'"', ExtractFileDir(Application.ExeName)), myUrl);
7 daniel-mar 298
      Cancel := true;
299
    end;
300
  end;
301
  {$ENDREGION}
5 daniel-mar 302
end;
2 daniel-mar 303
 
304
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
305
begin
13 daniel-mar 306
  FastPHPConfig.WriteInteger('User', 'FontSize', SynEdit1.Font.Size);
2 daniel-mar 307
end;
308
 
15 daniel-mar 309
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
310
var
311
  r: integer;
312
begin
313
  if SynEdit1.Modified then
314
  begin
315
    if ParamStr(1) <> '' then
316
    begin
317
      r := MessageDlg('Do you want to save?', mtConfirmation, mbYesNoCancel, 0);
318
      if r = mrCancel then
319
      begin
320
        CanClose := false;
321
        Exit;
322
      end
323
      else if r = mrYes then
324
      begin
325
        SynEdit1.Lines.SaveToFile(GetScrapFile);
326
        CanClose := true;
327
      end;
328
    end
329
    else
330
    begin
331
      SynEdit1.Lines.SaveToFile(GetScrapFile);
332
      CanClose := true;
333
    end;
334
  end;
335
end;
336
 
2 daniel-mar 337
procedure TForm1.FormCreate(Sender: TObject);
338
begin
339
  HlpPrevPageIndex := -1;
340
  CurSearchTerm := '';
13 daniel-mar 341
  Caption := Caption + ' - ' + GetScrapFile;
342
  SrcRep := TFindReplace.Create(self);
343
  SrcRep.Editor := SynEdit1;
2 daniel-mar 344
end;
345
 
346
procedure TForm1.FormDestroy(Sender: TObject);
347
begin
348
  if Assigned(ChmIndex) then
349
  begin
350
    FreeAndNil(ChmIndex);
351
  end;
13 daniel-mar 352
  FreeAndNil(SrcRep);
2 daniel-mar 353
end;
354
 
355
procedure TForm1.FormShow(Sender: TObject);
356
var
357
  ScrapFile: string;
358
begin
359
  ScrapFile := GetScrapFile;
360
  if ScrapFile = '' then
361
  begin
10 daniel-mar 362
    Application.Terminate; // Close;
2 daniel-mar 363
    exit;
364
  end;
15 daniel-mar 365
  if FileExists(ScrapFile) then
366
    SynEdit1.Lines.LoadFromFile(ScrapFile)
367
  else
368
    SynEdit1.Lines.Clear;
2 daniel-mar 369
 
370
  PageControl1.ActivePage := PlaintextTabSheet;
371
 
372
  PageControl2.ActivePageIndex := 0; // Scraps
373
  HelpTabsheet.TabVisible := false;
5 daniel-mar 374
 
13 daniel-mar 375
  SynEdit1.Font.Size := FastPHPConfig.ReadInteger('User', 'FontSize', SynEdit1.Font.Size);
5 daniel-mar 376
  SynEdit1.SetFocus;
2 daniel-mar 377
end;
378
 
379
function TForm1.GetScrapFile: string;
380
begin
15 daniel-mar 381
  if ParamStr(1) <> '' then
13 daniel-mar 382
    result := ParamStr(1)
383
  else
384
    result := FastPHPConfig.ReadString('Paths', 'ScrapFile', '');
2 daniel-mar 385
  if not FileExists(result) then
386
  begin
387
    if not OpenDialog3.Execute then
388
    begin
389
      result := '';
390
      exit;
15 daniel-mar 391
    end
392
    else
393
      result := OpenDialog3.FileName;
2 daniel-mar 394
 
395
    if not DirectoryExists(ExtractFilePath(result)) then
396
    begin
397
      ShowMessage('Path does not exist!');
398
      result := '';
399
      exit;
400
    end;
401
 
4 daniel-mar 402
    SynEdit1.Lines.Clear;
403
    SynEdit1.Lines.SaveToFile(result);
2 daniel-mar 404
 
405
    FastPHPConfig.WriteString('Paths', 'ScrapFile', result);
406
  end;
407
end;
408
 
409
procedure TForm1.Help;
410
var
411
  IndexFile, chmFile, w, url: string;
412
  internalHtmlFile: string;
413
begin
414
  if not Assigned(ChmIndex) then
415
  begin
416
    IndexFile := FastPHPConfig.ReadString('Paths', 'HelpIndex', '');
417
    IndexFile := ChangeFileExt(IndexFile, '.ini'); // Just to be sure. Maybe someone wrote manually the ".chm" file in there
418
    if FileExists(IndexFile) then
419
    begin
420
      ChmIndex := TMemIniFile.Create(IndexFile);
421
    end;
422
  end;
423
 
424
  if Assigned(ChmIndex) then
425
  begin
426
    IndexFile := FastPHPConfig.ReadString('Paths', 'HelpIndex', '');
427
    // We don't check if IndexFile still exists. It is not important since we have ChmIndex pre-loaded in memory
428
 
429
    chmFile := ChangeFileExt(IndexFile, '.chm');
430
    if not FileExists(chmFile) then
431
    begin
432
      FreeAndNil(ChmIndex);
433
    end;
434
  end;
435
 
436
  if not Assigned(ChmIndex) then
437
  begin
438
    if not OpenDialog1.Execute then exit;
439
 
440
    chmFile := OpenDialog1.FileName;
441
    if not FileExists(chmFile) then exit;
442
 
443
    IndexFile := ChangeFileExt(chmFile, '.ini');
444
 
445
    if not FileExists(IndexFile) then
446
    begin
447
      Panel1.Align := alClient;
448
      Panel1.Visible := true;
449
      Panel1.BringToFront;
450
      Screen.Cursor := crHourGlass;
451
      Application.ProcessMessages;
452
      try
453
        if not ParseCHM(chmFile) then
454
        begin
455
          ShowMessage('The CHM file is not a valid PHP documentation. Cannot use help.');
456
          exit;
457
        end;
458
      finally
459
        Screen.Cursor := crDefault;
460
        Panel1.Visible := false;
461
      end;
462
 
463
      if not FileExists(IndexFile) then
464
      begin
465
        ShowMessage('Unknown error. Cannot use help.');
466
        exit;
467
      end;
468
    end;
469
 
470
    FastPHPConfig.WriteString('Paths', 'HelpIndex', IndexFile);
471
    FastPHPConfig.UpdateFile;
472
 
473
    ChmIndex := TMemIniFile.Create(IndexFile);
474
  end;
475
 
4 daniel-mar 476
  w := GetWordUnderCaret(SynEdit1);
2 daniel-mar 477
  if w = '' then exit;
8 daniel-mar 478
  if CharInSet(w[1], ['0'..'9']) then exit;
2 daniel-mar 479
  w := StringReplace(w, '_', '-', [rfReplaceAll]);
480
  w := LowerCase(w);
481
  CurSearchTerm := w;
482
 
483
  internalHtmlFile := ChmIndex.ReadString('_HelpWords_', CurSearchTerm, '');
484
  if internalHtmlFile = '' then
485
  begin
486
    HelpTabsheet.TabVisible := false;
487
    HlpPrevPageIndex := -1;
488
    ShowMessage('No help for "'+CurSearchTerm+'" available');
489
    Exit;
490
  end;
491
 
492
  url := 'mk:@MSITStore:'+ChmFile+'::'+internalHtmlFile;
493
 
494
  HlpPrevPageIndex := PageControl2.ActivePageIndex; // Return by pressing ESC
495
  HelpTabsheet.TabVisible := true;
496
  PageControl2.ActivePage := HelpTabsheet;
8 daniel-mar 497
  WebBrowser2.Navigate(url);
498
  WebBrowser2.Wait;
2 daniel-mar 499
end;
500
 
5 daniel-mar 501
procedure TForm1.GotoLineNo(LineNo:integer);
502
var
503
  line: string;
504
  i: integer;
2 daniel-mar 505
begin
5 daniel-mar 506
  SynEdit1.GotoLineAndCenter(LineNo);
507
 
508
  // Skip indent
509
  line := SynEdit1.Lines[SynEdit1.CaretY];
510
  for i := 1 to Length(line) do
511
  begin
8 daniel-mar 512
    if not CharInSet(line[i], [' ', #9]) then
5 daniel-mar 513
    begin
514
      SynEdit1.CaretX := i-1;
515
      break;
516
    end;
517
  end;
518
 
519
  PageControl2.ActivePage := TabSheet3{Scrap};
520
  if SynEdit1.CanFocus then SynEdit1.SetFocus;
2 daniel-mar 521
end;
522
 
8 daniel-mar 523
procedure TForm1.PageControl2Changing(Sender: TObject;
524
  var AllowChange: Boolean);
525
begin
526
  if PageControl2.ActivePage = HelpTabsheet then
527
    HlpPrevPageIndex := -1
528
  else
529
    HlpPrevPageIndex := PageControl2.ActivePageIndex;
530
 
531
  AllowChange := true;
532
end;
533
 
5 daniel-mar 534
procedure TForm1.Memo2DblClick(Sender: TObject);
535
var
16 daniel-mar 536
  pfx, line: string;
5 daniel-mar 537
  p, lineno: integer;
538
begin
539
  line := memo2.Lines.Strings[Memo2.CaretPos.Y];
16 daniel-mar 540
 
541
  pfx := ExtractFileName(GetScrapFile)+':';
542
  p := Pos(pfx, line);
543
  if p <> 0 then
544
  begin
545
    line := copy(line, p+length(pfx), 99);
546
    if not TryStrToInt(line, lineno) then exit;
547
    GotoLineNo(lineno);
548
  end;
549
 
550
  pfx := ' on line ';
551
  p := Pos(pfx, line);
552
  if p <> 0 then
553
  begin
554
    line := copy(line, p+length(pfx), 99);
555
    if not TryStrToInt(line, lineno) then exit;
556
    GotoLineNo(lineno);
557
  end;
5 daniel-mar 558
end;
559
 
560
function TForm1.MarkUpLineReference(cont: string): string;
561
var
562
  p, a, b: integer;
563
  num: integer;
564
  insert_a, insert_b: string;
565
begin
566
  // TODO: make it more specific to PHP error messages. "on line" is too broad.
567
  p := Pos(' on line ', cont);
568
  while p >= 1 do
569
  begin
570
    a := p+1;
571
    b := p+length(' on line ');
572
    num := 0;
8 daniel-mar 573
    while CharInSet(cont[b], ['0'..'9']) do
5 daniel-mar 574
    begin
575
      num := num*10 + StrToInt(cont[b]);
576
      inc(b);
577
    end;
578
 
579
    insert_b := '</a>';
8 daniel-mar 580
    insert_a := '<a href="'+FASTPHP_GOTO_URI_PREFIX+IntToStr(num)+'">';
5 daniel-mar 581
 
582
    insert(insert_b, cont, b);
583
    insert(insert_a, cont, a);
584
 
585
    p := b + Length(insert_a) + Length(insert_b);
586
 
587
    p := PosEx(' on line ', cont, p+1);
588
  end;
589
 
590
  result := cont;
591
end;
592
 
2 daniel-mar 593
end.