1{
2/***************************************************************************
3                               SourceEditor.pp
4                             -------------------
5
6 ***************************************************************************/
7
8 ***************************************************************************
9 *                                                                         *
10 *   This source is free software; you can redistribute it and/or modify   *
11 *   it under the terms of the GNU General Public License as published by  *
12 *   the Free Software Foundation; either version 2 of the License, or     *
13 *   (at your option) any later version.                                   *
14 *                                                                         *
15 *   This code is distributed in the hope that it will be useful, but      *
16 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
17 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
18 *   General Public License for more details.                              *
19 *                                                                         *
20 *   A copy of the GNU General Public License is available on the World    *
21 *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
22 *   obtain it by writing to the Free Software Foundation,                 *
23 *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
24 *                                                                         *
25 ***************************************************************************
26}
27{ This unit builds the TSourceNotebook that the editors are held on.
28  It also has a class that controls the editors (TSourceEditor)
29}
30unit SourceEditor;
31
32{$mode objfpc}
33{$H+}
34
35interface
36
37{$I ide.inc}
38
39{ $DEFINE VerboseIDECompletionBox}
40
41uses
42  {$IFDEF IDE_MEM_CHECK}
43  MemCheck,
44  {$ENDIF}
45  SynEditMouseCmds,
46  // RTL + FCL
47  Classes, SysUtils, StrUtils, Types, Contnrs, Math, RegExpr, Laz_AVL_Tree,
48  // LCL
49  Controls, Forms, ComCtrls, StdCtrls, Graphics, Dialogs, Extctrls, Menus,
50  LCLProc, LCLType, LCLIntf, ClipBrd, HelpIntfs, Messages, LMessages,
51  // LazControls
52  ExtendedNotebook,
53  // LazUtils
54  LConvEncoding, FileUtil, LazFileUtils, LazFileCache, LazUTF8,
55  LazMethodList, LazLoggerBase, LazLogger, Translations, LazUtilities, LazTracer,
56  LazStringUtils,
57  // codetools
58  BasicCodeTools, CodeBeautifier, CodeToolManager, CodeCache, SourceLog,
59  LinkScanner, CodeTree, SourceChanger, IdentCompletionTool,
60  // synedit
61  SynEditLines, SynEditStrConst, SynEditTypes, SynEdit,
62  SynEditHighlighter, SynEditAutoComplete, SynEditKeyCmds, SynCompletion,
63  SynEditMiscClasses, SynEditMarkupHighAll, SynEditMarks,
64  SynBeautifier, SynPluginMultiCaret,
65  SynPluginSyncronizedEditBase, SourceSynEditor,
66  SynExportHTML, SynHighlighterPas, SynEditMarkup, SynEditMarkupIfDef, SynBeautifierPascal,
67  // IdeIntf
68  SrcEditorIntf, MenuIntf, LazIDEIntf, PackageIntf, IDEHelpIntf, IDEImagesIntf,
69  IDEWindowIntf, ProjectIntf, MacroDefIntf, ToolBarIntf, IDEDialogs, IDECommands,
70  EditorSyntaxHighlighterDef,
71  // DebuggerIntf
72  DbgIntfDebuggerBase,
73  // IDE units
74  IDECmdLine, LazarusIDEStrConsts, EditorOptions,
75  EnvironmentOpts, WordCompletion, FindReplaceDialog, IDEProcs, IDEOptionDefs,
76  IDEHelpManager, MacroPromptDlg, TransferMacros, CodeContextForm,
77  SrcEditHintFrm, etMessagesWnd, etSrcEditMarks, CodeMacroPrompt,
78  CodeTemplatesDlg, CodeToolsOptions, editor_general_options, SortSelectionDlg,
79  EncloseSelectionDlg, EncloseIfDef, InvertAssignTool, SourceEditProcs,
80  SourceMarks, CharacterMapDlg, SearchFrm, MultiPasteDlg, EditorMacroListViewer,
81  EditorToolbarStatic, editortoolbar_options, InputhistoryWithSearchOpt,
82  FPDocHints, MainIntf, GotoFrm, BaseDebugManager, Debugger;
83
84type
85  TSourceNotebook = class;
86  TSourceEditorManager = class;
87  TSourceEditor = class;
88
89  TNotifyFileEvent = procedure(Sender: TObject; Filename : AnsiString) of object;
90
91  TOnProcessUserCommand = procedure(Sender: TObject;
92            Command: word; var Handled: boolean) of object;
93  TOnUserCommandProcessed = procedure(Sender: TObject;
94            Command: word; var Handled: boolean) of object;
95
96  TPackageForSourceEditorEvent = function(out APackage: TIDEPackage;
97    ASrcEdit: TObject): TLazPackageFile of object;
98
99  TPlaceBookMarkEvent = procedure(Sender: TObject; var Mark: TSynEditMark) of object;
100  TPlaceBookMarkIdEvent = procedure(Sender: TObject; ID: Integer) of object;
101  TBookMarkActionEvent = procedure(Sender: TObject; ID: Integer; Toggle: Boolean) of object;
102
103  TUpdateProjectFileEvent = procedure(Sender: TObject; AnUpdates: TSrcEditProjectUpdatesNeeded) of object;
104
105  TCharSet = set of Char;
106
107  // for TSourcEditor.CenterCursorHoriz
108  TSourceEditHCenterMode =
109  ( hcmCenter,          // Center X-Caret to exact middle of Screen
110    hcmCenterKeepEOL,   // Center X-Caret to middle of Screen, but keep EOL at right border
111    hcmSoft,            // Soft Center (distance to screen edge) Caret
112    hcmSoftKeepEOL      // Soft Center (distance to screen edge) Caret, but keep EOL at right border
113  );
114
115  TSourceEditCompletionForm = class(TSynCompletionForm)
116  private
117    FTextHighLightColor: TColor;
118  public
119    property TextHighLightColor: TColor read FTextHighLightColor write FTextHighLightColor;
120  end;
121
122  { TSourceEditCompletion }
123
124  TSourceEditCompletion=class(TSynCompletion)
125  private
126    FIdentCompletionJumpToError: boolean;
127    ccSelection: String;
128    // colors for the completion form (popup form, e.g. word completion)
129
130    FActiveEditBackgroundColor: TColor;
131    FActiveEditBackgroundSelectedColor: TColor;
132    FActiveEditBorderColor: TColor;
133    FActiveEditTextColor: TColor;
134    FActiveEditTextSelectedColor: TColor;
135    FActiveEditTextHighLightColor: TColor;
136
137    procedure ccExecute(Sender: TObject);
138    procedure ccCancel(Sender: TObject);
139    procedure ccComplete(var Value: string; SourceValue: string;
140                         var SourceStart, SourceEnd: TPoint;
141                         KeyChar: TUTF8Char; Shift: TShiftState);
142    function OnSynCompletionPaintItem(const AKey: string; ACanvas: TCanvas;
143                 X, Y: integer; ItemSelected: boolean; Index: integer): boolean;
144    function OnSynCompletionMeasureItem(const AKey: string; ACanvas: TCanvas;
145                                 ItemSelected: boolean; Index: integer): TPoint;
146    procedure OnSynCompletionSearchPosition(var APosition: integer);
147    procedure OnSynCompletionCompletePrefix(Sender: TObject);
148    procedure OnSynCompletionNextChar(Sender: TObject);
149    procedure OnSynCompletionPrevChar(Sender: TObject);
150    procedure OnSynCompletionKeyPress(Sender: TObject; var Key: Char);
151    procedure OnSynCompletionUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
152    procedure OnSynCompletionPositionChanged(Sender: TObject);
153
154    function InitIdentCompletionValues(S: TStrings): boolean;
155    procedure StartShowCodeHelp;
156    procedure CompletionFormResized(Sender: TObject);
157  protected
158    CurrentCompletionType: TCompletionType;
159    function Manager: TSourceEditorManager;
160    function GetCompletionFormClass: TSynBaseCompletionFormClass; override;
161  public
162    constructor Create(AOwner: TComponent); override;
163    property IdentCompletionJumpToError: Boolean
164      read FIdentCompletionJumpToError write FIdentCompletionJumpToError;
165  end;
166
167  { TSourceEditorSharedValues }
168
169  TSourceEditorSharedValues = class(TSourceEditorSharedValuesBase)
170  private
171    FSharedEditorList: TFPList; // list of TSourceEditor sharing one TSynEdit
172    function GetOtherSharedEditors(Caller: TSourceEditor; Index: Integer): TSourceEditor;
173    function GetSharedEditors(Index: Integer): TSourceEditor;
174    function SynEditor: TIDESynEditor;
175  protected
176    function GetSharedEditorsBase(Index: Integer): TSourceEditorBase; override;
177  public
178    procedure AddSharedEditor(AnEditor: TSourceEditor);
179    procedure RemoveSharedEditor(AnEditor: TSourceEditor);
180    procedure SetActiveSharedEditor(AnEditor: TSourceEditor);
181    function  SharedEditorCount: Integer; override;
182    function  OtherSharedEditorCount: Integer;
183    property  SharedEditors[Index: Integer]: TSourceEditor read GetSharedEditors;
184    property  OtherSharedEditors[Caller: TSourceEditor; Index: Integer]: TSourceEditor
185              read GetOtherSharedEditors;
186  private
187    FExecutionMark: TSourceMark;
188    FMarksRequested: Boolean;
189    FMarklingsValid: boolean;
190    FMarksRequestedForFile: String;
191    function GetExecutionLine: Integer;
192  public
193    UpdatingExecutionMark: Integer;
194    procedure CreateExecutionMark;
195    property ExecutionLine: Integer read GetExecutionLine;// write FExecutionLine;
196    property ExecutionMark: TSourceMark read FExecutionMark write FExecutionMark;
197    procedure SetExecutionLine(NewLine: integer);
198    property MarksRequested: Boolean read FMarksRequested write FMarksRequested;
199    property MarksRequestedForFile: String read FMarksRequestedForFile write FMarksRequestedForFile;
200  private
201    FInGlobalUpdate: Integer;
202    FModified: boolean;
203    FIgnoreCodeBufferLock: integer;
204    FEditorStampCommitedToCodetools: int64;
205    FCodeBuffer: TCodeBuffer;
206    FLinkScanners: TFPList; // list of TLinkScanner
207    FMainLinkScanner: TLinkScanner;
208    FLastWarnedMainLinkFilename: string;
209    function GetModified: Boolean;
210    procedure SetCodeBuffer(const AValue: TCodeBuffer);
211    procedure SetModified(const AValue: Boolean);
212    procedure OnCodeBufferChanged(Sender: TSourceLog; SrcLogEntry: TSourceLogEntry);
213  public
214    procedure BeginGlobalUpdate;
215    procedure EndGlobalUpdate;
216    property Modified: Boolean read GetModified write SetModified;
217    property  IgnoreCodeBufferLock: Integer read FIgnoreCodeBufferLock;
218    procedure IncreaseIgnoreCodeBufferLock;
219    procedure DecreaseIgnoreCodeBufferLock;
220    function NeedsUpdateCodeBuffer: boolean;
221    procedure UpdateCodeBuffer;
222    property CodeBuffer: TCodeBuffer read FCodeBuffer write SetCodeBuffer;
223    // IfDef nodes
224    procedure ConnectScanner(Scanner: TLinkScanner);
225    procedure DisconnectScanner(Scanner: TLinkScanner);
226    function GetMainLinkScanner(Scan: boolean): TLinkScanner;
227  public
228    constructor Create;
229    destructor Destroy; override;
230    function Filename: string; override;
231  end;
232
233{ TSourceEditor ---
234  TSourceEditor is the class that controls access for a single source editor,
235  which is part of TSourceNotebook. }
236
237  TSourceEditor = class(TSourceEditorBase)
238  private
239    //FAOwner is normally a TSourceNotebook.  This is set in the Create constructor.
240    FAOwner: TComponent;
241    FIsLocked: Boolean;
242    FProjectFileUpdatesNeeded: TSrcEditProjectUpdatesNeeded;
243    FSharedValues: TSourceEditorSharedValues;
244    FEditor: TIDESynEditor;
245    FTempCaret: TPoint;
246    FTempTopLine: Integer;
247    FEditPlugin: TETSynPlugin; // used to update the "Messages Window"
248                               // when text is inserted/deleted
249    FOnIfdefNodeStateRequest: TSynMarkupIfdefStateRequest;
250    FLastIfDefNodeScannerStep: integer;
251    FCodeCompletionState: record
252      State: (ccsReady, ccsCancelled, ccsDot, ccsOnTyping, ccsOnTypingScheduled);
253      LastTokenStartPos: TPoint;
254    end;
255
256    FSyncroLockCount: Integer;
257    FPageName: string;
258
259    FPopUpMenu: TPopupMenu;
260    FMouseActionPopUpMenu: TPopupMenu;
261    FSyntaxHighlighterType: TLazSyntaxHighlighter;
262    FErrorLine: integer;
263    FErrorColumn: integer;
264    FLineInfoNotification: TIDELineInfoNotification;
265    FInEditorChangedUpdating: Boolean;
266
267    FOnEditorChange: TStatusChangeEvent;
268    FVisible: Boolean;
269    FOnMouseMove: TMouseMoveEvent;
270    FOnMouseDown: TMouseEvent;
271    FOnMouseWheel : TMouseWheelEvent;
272    FOnKeyDown: TKeyEvent;
273    FOnKeyUp: TKeyEvent;
274
275    FSourceNoteBook: TSourceNotebook;
276    procedure EditorMouseMoved(Sender: TObject; Shift: TShiftState; X,Y:Integer);
277    procedure EditorMouseDown(Sender: TObject; Button: TMouseButton;
278          Shift: TShiftState; X,Y: Integer);
279    procedure EditorMouseUp(Sender: TObject; Button: TMouseButton;
280      Shift: TShiftState; X, Y: Integer);
281    procedure EditorMouseWheel(Sender: TObject; Shift: TShiftState;
282         WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
283    procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
284    procedure EditorKeyUp({%H-}Sender: TObject; var {%H-}Key: Word; {%H-}Shift: TShiftState);
285    procedure EditorStatusChanged(Sender: TObject; {%H-}Changes: TSynStatusChanges);
286    procedure EditorPaste(Sender: TObject; var AText: String;
287         var AMode: TSynSelectionMode; ALogStartPos: TPoint;
288         var AnAction: TSynCopyPasteAction);
289    procedure EditorPlaceBookmark(Sender: TObject; var Mark: TSynEditMark);
290    procedure EditorClearBookmark(Sender: TObject; var Mark: TSynEditMark);
291    procedure EditorEnter(Sender: TObject);
292    procedure EditorActivateSyncro(Sender: TObject);
293    procedure EditorDeactivateSyncro(Sender: TObject);
294    procedure EditorChangeUpdating({%H-}ASender: TObject; AnUpdating: Boolean);
295    function  EditorHandleMouseAction(AnAction: TSynEditMouseAction;
296                                      var {%H-}AnInfo: TSynEditMouseActionInfo): Boolean;
297    function GetCodeBuffer: TCodeBuffer;
298    function GetExecutionLine: integer;
299    function GetHasExecutionMarks: Boolean;
300    function GetSharedEditors(Index: Integer): TSourceEditor;
301    procedure SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
302    function GetSource: TStrings;
303    procedure SetIsLocked(const AValue: Boolean);
304    procedure UpdateExecutionSourceMark;
305    procedure UpdatePageName;
306    procedure SetSource(Value: TStrings);
307    function GetCurrentCursorXLine: Integer;
308    procedure SetCurrentCursorXLine(num : Integer);
309    function GetCurrentCursorYLine: Integer;
310    procedure SetCurrentCursorYLine(num: Integer);
311    Function GetInsertMode: Boolean;
312    procedure SetPopupMenu(NewPopupMenu: TPopupMenu);
313
314    function GotoLine(Value: Integer): Integer;
315
316    procedure CreateEditor(AOwner: TComponent; AParent: TWinControl);
317    procedure UpdateNoteBook(const ANewNoteBook: TSourceNotebook; ANewPage: TTabSheet);
318    procedure SetVisible(Value: boolean);
319    procedure UnbindEditor;
320
321    procedure UpdateIfDefNodeStates(Force: Boolean = False);
322  protected
323    function GetPageCaption: string; override;
324    function GetPageName: string; override;
325    procedure SetPageName(const AValue: string);
326  protected
327    procedure DoMultiCaretBeforeCommand(Sender: TObject; ACommand: TSynEditorCommand;
328      var AnAction: TSynMultiCaretCommandAction; var {%H-}AFlags: TSynMultiCaretCommandFlags);
329    procedure ProcessCommand(Sender: TObject;
330       var Command: TSynEditorCommand; var AChar: TUTF8Char; {%H-}Data: pointer);
331    procedure ProcessUserCommand(Sender: TObject;
332       var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
333    procedure UserCommandProcessed(Sender: TObject;
334       var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
335    function AutoCompleteChar(Char: TUTF8Char; var AddChar: boolean;
336       Category: TAutoCompleteOption): boolean;
337    function AutoBlockCompleteChar({%H-}Char: TUTF8Char; var {%H-}AddChar: boolean;
338       Category: TAutoCompleteOption; aTextPos: TPoint; Line: string): boolean;
339    function AutoBlockCompleteChar({%H-}Char: TUTF8Char): boolean;
340    procedure AutoCompleteBlock;
341
342    procedure FocusEditor;// called by TSourceNotebook when the Notebook page
343                          // changes so the editor is focused
344    procedure OnGutterClick(Sender: TObject; {%H-}X, {%H-}Y, Line: integer;
345         {%H-}Mark: TSynEditMark);
346    procedure OnEditorSpecialLineColor(Sender: TObject; Line: integer;
347         var Special: boolean; Markup: TSynSelectedColor);
348    function RefreshEditorSettings: Boolean;
349    function GetModified: Boolean; override;
350    procedure SetModified(const NewValue: Boolean); override;
351    procedure SetSyntaxHighlighterType(AHighlighterType: TLazSyntaxHighlighter);
352    procedure SetErrorLine(NewLine: integer);
353    procedure SetExecutionLine(NewLine: integer);
354    procedure StartIdentCompletionBox(JumpToError, CanAutoComplete: boolean);
355    procedure StartWordCompletionBox;
356
357    function IsFirstShared(Sender: TObject): boolean;
358
359    function GetFilename: string; override;
360    function GetEditorControl: TWinControl; override;
361    function GetCodeToolsBuffer: TObject; override;
362    Function GetReadOnly: Boolean; override;
363    procedure SetReadOnly(const NewValue: boolean); override;
364
365    function Manager: TSourceEditorManager;
366    property Visible: Boolean read FVisible write SetVisible default False;
367    function GetSharedValues: TSourceEditorSharedValuesBase; override;
368    function IsSharedWith(AnOtherEditor: TSourceEditor): Boolean;
369    procedure BeforeCodeBufferReplace;
370    procedure AfterCodeBufferReplace;
371    function Close: Boolean;
372  public
373    constructor Create(AOwner: TComponent; AParent: TWinControl; ASharedEditor: TSourceEditor = nil);
374    destructor Destroy; override;
375
376    // codebuffer
377    procedure BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF}; override;
378    procedure EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF}; override;
379    procedure BeginUpdate; override;
380    procedure EndUpdate; override;
381    procedure BeginGlobalUpdate;
382    procedure EndGlobalUpdate;
383    procedure IncreaseIgnoreCodeBufferLock; override;
384    procedure DecreaseIgnoreCodeBufferLock; override;
385    procedure UpdateCodeBuffer; override;// copy the source from EditorComponent
386    function NeedsUpdateCodeBuffer: boolean; override;
387    procedure ConnectScanner(Scanner: TLinkScanner);
388
389    // find
390    procedure StartFindAndReplace(Replace:boolean);
391    procedure AskReplace(Sender: TObject; const ASearch, AReplace:
392       string; Line, Column: integer; out Action: TSrcEditReplaceAction); override;
393    procedure OnReplace(Sender: TObject; const ASearch, AReplace:
394       string; {%H-}Line, {%H-}Column: integer; var Action: TSynReplaceAction);
395    function  DoFindAndReplace(aFindText, aReplaceText: String; anOptions: TSynSearchOptions): Integer;
396    procedure FindNextUTF8;
397    procedure FindPrevious;
398    procedure FindNextWordOccurrence(DirectionForward: boolean);
399    procedure ShowGotoLineDialog;
400
401    // dialogs
402    procedure GetDialogPosition(Width, Height: integer; out Left, Top: integer);
403    procedure ActivateHint(const ClientPos: TPoint; const ABaseURL, AHint: string;
404      AAutoShown: Boolean = True); overload;
405    procedure ActivateHint(ClientRect: TRect; const ABaseURL, AHint: string;
406      AAutoShown: Boolean; AMouseOffset: Boolean = True); overload;
407
408    // selections
409    function SelectionAvailable: boolean; override;
410    function GetText(OnlySelection: boolean): string; override;
411    procedure SelectText(const StartPos, EndPos: TPoint); override;
412    procedure InsertLine(StartLine: Integer; const NewText: String; aKeepMarks: Boolean = False); override;
413    procedure ReplaceLines(StartLine, EndLine: integer; const NewText: string; aKeepMarks: Boolean = False); override;
414    procedure EncloseSelection;
415    procedure UpperCaseSelection;
416    procedure LowerCaseSelection;
417    procedure SwapCaseSelection;
418    procedure TabsToSpacesInSelection;
419    procedure CommentSelection;
420    procedure UncommentSelection;
421    procedure ToggleCommentSelection;
422    procedure UpdateCommentSelection(CommentOn, Toggle: Boolean);
423    procedure ConditionalSelection;
424    procedure SortSelection;
425    procedure BreakLinesInSelection;
426    procedure InvertAssignment;
427    procedure SelectToBrace;
428    procedure SelectWord;
429    procedure SelectLine;
430    procedure SelectParagraph;
431    function CommentText(const Txt: string; CommentType: TCommentType): string;
432    procedure InsertCharacterFromMap;
433    procedure InsertLicenseNotice(const Notice: string; CommentType: TCommentType);
434    procedure InsertGPLNotice(CommentType: TCommentType; Translated: boolean);
435    procedure InsertLGPLNotice(CommentType: TCommentType; Translated: boolean);
436    procedure InsertModifiedLGPLNotice(CommentType: TCommentType; Translated: boolean);
437    procedure InsertMITNotice(CommentType: TCommentType; Translated: boolean);
438    procedure InsertUsername;
439    procedure InsertDateTime;
440    procedure InsertChangeLogEntry;
441    procedure InsertCVSKeyword(const AKeyWord: string);
442    procedure InsertGUID;
443    procedure InsertFilename;
444    function GetSelEnd: Integer; override;
445    function GetSelStart: Integer; override;
446    procedure SetSelEnd(const AValue: Integer); override;
447    procedure SetSelStart(const AValue: Integer); override;
448    function GetSelection: string; override;
449    procedure SetSelection(const AValue: string); override;
450    procedure CopyToClipboard; override;
451    procedure CutToClipboard; override;
452    function GetBookMark(BookMark: Integer; out X, Y: Integer): Boolean; override;
453    procedure SetBookMark(BookMark: Integer; X, Y: Integer); override;
454
455    procedure ExportAsHtml(AFileName: String);
456
457    // context help
458    procedure FindHelpForSourceAtCursor;
459    //Smart hint
460    procedure ShowSmartHintForSourceAtCursor;
461
462    // editor commands
463    procedure DoEditorExecuteCommand(EditorCommand: word); override;
464    procedure MoveToWindow(AWindowIndex: Integer); override;
465    procedure CopyToWindow(AWindowIndex: Integer); override;
466
467    function GetCodeAttributeName(LogXY: TPoint): String;
468
469    // used to get the word at the mouse cursor
470    function CurrentWordLogStartOrCaret: TPoint;
471    function GetWordFromCaret(const ACaretPos: TPoint): String;
472    function GetWordAtCurrentCaret: String;
473    function GetOperandFromCaret(const ACaretPos: TPoint): String;
474    function GetOperandAtCurrentCaret: String;
475    function CaretInSelection(const ACaretPos: TPoint): Boolean;
476
477    // cursor
478    procedure CenterCursor(SoftCenter: Boolean = False); // vertical
479    procedure CenterCursorHoriz(HCMode: TSourceEditHCenterMode); // horiz
480    function TextToScreenPosition(const Position: TPoint): TPoint; override;
481    function ScreenToTextPosition(const Position: TPoint): TPoint; override;
482    function ScreenToPixelPosition(const Position: TPoint): TPoint; override;
483    function GetCursorScreenXY: TPoint; override;
484    function GetCursorTextXY: TPoint; override;
485    procedure SetCursorScreenXY(const AValue: TPoint); override;
486    procedure SetCursorTextXY(const AValue: TPoint); override;
487    function GetBlockBegin: TPoint; override;
488    function GetBlockEnd: TPoint; override;
489    procedure SetBlockBegin(const AValue: TPoint); override;
490    procedure SetBlockEnd(const AValue: TPoint); override;
491    function GetLinesInWindow: Integer; override;
492    function GetTopLine: Integer; override;
493    procedure SetTopLine(const AValue: Integer); override;
494    function CursorInPixel: TPoint; override;
495    function IsCaretOnScreen(ACaret: TPoint; UseSoftCenter: Boolean = False): Boolean;
496
497    // text
498    procedure MultiPasteText;
499    function SearchReplace(const ASearch, AReplace: string;
500                           SearchOptions: TSrcEditSearchOptions): integer; override;
501    function GetSourceText: string; override;
502    procedure SetSourceText(const AValue: string); override;
503    function LineCount: Integer; override;
504    function WidthInChars: Integer; override;
505    function HeightInLines: Integer; override;
506    function CharWidth: integer; override;
507    function GetLineText: string; override;
508    procedure SetLineText(const AValue: string); override;
509    function GetLines: TStrings; override;
510    procedure SetLines(const AValue: TStrings); override;
511
512    // context
513    function GetProjectFile: TLazProjectFile; override;
514    procedure UpdateProjectFile(AnUpdates: TSrcEditProjectUpdatesNeeded = []); override;
515    function GetDesigner(LoadForm: boolean): TIDesigner; override;
516
517    // notebook
518    procedure Activate;
519    function PageIndex: integer;
520    function IsActiveOnNoteBook: boolean;
521    procedure CheckActiveWindow;
522
523    // debugging
524    procedure DoRequestExecutionMarks({%H-}Data: PtrInt);
525    procedure FillExecutionMarks;
526    procedure ClearExecutionMarks;
527    procedure LineInfoNotificationChange(const {%H-}ASender: TObject; const ASource: String);
528    function  SourceToDebugLine(aLinePos: Integer): Integer;
529    function  DebugToSourceLine(aLinePos: Integer): Integer;
530
531    procedure InvalidateAllIfdefNodes;
532    procedure SetIfdefNodeState(ALinePos, AstartPos: Integer; AState: TSynMarkupIfdefNodeState);
533    property OnIfdefNodeStateRequest: TSynMarkupIfdefStateRequest read FOnIfdefNodeStateRequest write FOnIfdefNodeStateRequest;
534  public
535    // properties
536    property CodeBuffer: TCodeBuffer read GetCodeBuffer write SetCodeBuffer;
537    property CurrentCursorXLine: Integer
538       read GetCurrentCursorXLine write SetCurrentCursorXLine;
539    property CurrentCursorYLine: Integer
540       read GetCurrentCursorYLine write SetCurrentCursorYLine;
541    property EditorComponent: TIDESynEditor read FEditor;
542    property ErrorLine: integer read FErrorLine write SetErrorLine;
543    property ExecutionLine: integer read GetExecutionLine write SetExecutionLine;
544    property HasExecutionMarks: Boolean read GetHasExecutionMarks;
545    property InsertMode: Boolean read GetInsertmode;
546    property OnEditorChange: TStatusChangeEvent read FOnEditorChange
547                                                write FOnEditorChange;
548    property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
549    property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
550    property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel write FOnMouseWheel;
551    property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
552    property OnKeyUp: TKeyEvent read FOnKeyUp write FOnKeyUp;
553    property Owner: TComponent read FAOwner;
554    property PageName: string read GetPageName write SetPageName;
555    property PopupMenu: TPopupMenu read FPopUpMenu write SetPopUpMenu;
556    property ReadOnly: Boolean read GetReadOnly write SetReadOnly;
557    property Source: TStrings read GetSource write SetSource;
558    property SourceNotebook: TSourceNotebook read FSourceNoteBook;
559    property SyntaxHighlighterType: TLazSyntaxHighlighter
560       read fSyntaxHighlighterType write SetSyntaxHighlighterType;
561    property SyncroLockCount: Integer read FSyncroLockCount;
562    function SharedEditorCount: Integer;
563    property SharedEditors[Index: Integer]: TSourceEditor read GetSharedEditors;
564    property SharedValues: TSourceEditorSharedValues read FSharedValues;
565    property IsLocked: Boolean read FIsLocked write SetIsLocked;
566  end;
567
568  //============================================================================
569
570  { TSourceNotebook }
571
572  TJumpHistoryAction = (jhaBack, jhaForward, jhaViewWindow);
573  TCloseSrcEditorOption = (ceoCloseOthers, ceoCloseOthersOnRightSide);
574  TCloseSrcEditorOptions = set of TCloseSrcEditorOption;
575
576  TOnJumpToHistoryPoint = procedure(out NewCaretXY: TPoint;
577                                    out NewTopLine: integer;
578                                    out DestEditor: TSourceEditor;
579                                    Action: TJumpHistoryAction) of object;
580  TOnAddJumpPoint = procedure(ACaretXY: TPoint; ATopLine: integer;
581                  AEditor: TSourceEditor; DeleteForwardHistory: boolean) of object;
582  TOnMovingPage = procedure(Sender: TObject;
583                            OldPageIndex, NewPageIndex: integer) of object;
584  TOnCloseSrcEditor = procedure(Sender: TObject; ACloseOptions: TCloseSrcEditorOptions) of object;
585  TOnShowHintForSource = procedure(SrcEdit: TSourceEditor;
586                                   CaretPos: TPoint; AutoShown: Boolean) of object;
587  TOnInitIdentCompletion = procedure(Sender: TObject; JumpToError: boolean;
588                                     out Handled, Abort: boolean) of object;
589  TSrcEditPopupMenuEvent = procedure(const AddMenuItemProc: TAddMenuItemProc
590                                     ) of object;
591  TOnShowCodeContext = procedure(JumpToError: boolean;
592                                 out Abort: boolean) of object;
593  TOnGetIndentEvent = function(Sender: TObject; Editor: TSourceEditor;
594      LogCaret, OldLogCaret: TPoint; FirstLinePos, LinesCount: Integer;
595      Reason: TSynEditorCommand; SetIndentProc: TSynBeautifierSetIndentProc
596     ): boolean of object;
597
598  TSourceNotebookState = (
599    snIncrementalFind,
600    snWarnedFont,
601    snUpdateStatusBarNeeded,
602    snNotebookPageChangedNeeded
603    );
604  TSourceNotebookStates = set of TSourceNotebookState;
605
606  TSourceNotebookUpdateFlag = (
607    ufPageNames,
608    ufTabsAndPage,
609    ufStatusBar,
610    ufProjectFiles,
611    ufFocusEditor,
612    ufActiveEditorChanged,
613    ufPageIndexChanged
614  );
615  TSourceNotebookUpdateFlags = set of TSourceNotebookUpdateFlag;
616
617  TBrowseEditorTabHistoryDialog = class;
618
619  { TSourceNotebook }
620
621  TSourceNotebook = class(TSourceEditorWindowInterface)
622    GoToLineMenuItem: TMenuItem;
623    OpenFolderMenuItem: TMenuItem;
624    StatusPopUpMenu: TPopupMenu;
625    StatusBar: TStatusBar;
626    procedure CompleteCodeMenuItemClick(Sender: TObject);
627    procedure DbgPopUpMenuPopup(Sender: TObject);
628    procedure EditorLockClicked(Sender: TObject);
629    procedure EncodingClicked(Sender: TObject);
630    procedure ExtractProcMenuItemClick(Sender: TObject);
631    procedure FindOverloadsMenuItemClick(Sender: TObject);
632    procedure FormMouseUp(Sender: TObject; {%H-}Button: TMouseButton;
633      {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
634    procedure GoToLineMenuItemClick(Sender: TObject);
635    procedure HighlighterClicked(Sender: TObject);
636    procedure InsertCharacter(const C: TUTF8Char);
637    procedure InvertAssignmentMenuItemClick(Sender: TObject);
638    procedure LineEndingClicked(Sender: TObject);
639    procedure MakeResourceStringMenuItemClick(Sender: TObject);
640    procedure NotebookPageChanged(Sender: TObject);
641    procedure NotebookShowTabHint(Sender: TObject; HintInfo: PHintInfo);
642    procedure OnPopupMenuOpenFile(Sender: TObject);
643    procedure OnPopupOpenPackageFile(Sender: TObject);
644    procedure OnPopupOpenProjectInsp(Sender: TObject);
645    procedure OpenAtCursorClicked(Sender: TObject);
646    procedure OpenFolderMenuItemClick(Sender: TObject);
647    procedure RenameIdentifierMenuItemClick(Sender: TObject);
648    procedure ShowAbstractMethodsMenuItemClick(Sender: TObject);
649    procedure ShowEmptyMethodsMenuItemClick(Sender: TObject);
650    procedure ShowUnusedUnitsMenuItemClick(Sender: TObject);
651    procedure SourceNotebookDropFiles(Sender: TObject;
652      const FileNames: array of String);
653    procedure SrcEditMenuCopyToExistingWindowClicked(Sender: TObject);
654    procedure SrcEditMenuFindInWindowClicked(Sender: TObject);
655    procedure SrcEditMenuMoveToExistingWindowClicked(Sender: TObject);
656    procedure SrcPopUpMenuPopup(Sender: TObject);
657    procedure StatusBarClick(Sender: TObject);
658    procedure StatusBarDblClick(Sender: TObject);
659    procedure StatusBarContextPopup(Sender: TObject; MousePos: TPoint;
660      var {%H-}Handled: Boolean);
661    procedure StatusBarDrawPanel({%H-}AStatusBar: TStatusBar; APanel: TStatusPanel;
662      const ARect: TRect);
663    procedure TabPopUpMenuPopup(Sender: TObject);
664  private
665    FNotebook: TExtendedNotebook;
666    FBaseCaption: String;
667    FIsClosing: Boolean;
668    FSrcEditsSortedForFilenames: TAvlTree; // TSourceEditorInterface sorted for Filename
669    TabPopUpMenu, SrcPopUpMenu, DbgPopUpMenu: TPopupMenu;
670    procedure ApplyPageIndex;
671    procedure ExecuteEditorItemClick(Sender: TObject);
672  public
673    procedure DeleteBreakpointClicked(Sender: TObject);
674    procedure ToggleBreakpointClicked(Sender: TObject);
675    procedure ToggleBreakpointEnabledClicked(Sender: TObject);
676  private
677    FManager: TSourceEditorManager;
678    FUpdateLock, FFocusLock, fAutoFocusLock: Integer;
679    FUpdateFlags: TSourceNotebookUpdateFlags;
680    FPageIndex: Integer;
681    FIncrementalSearchPos: TPoint; // last set position
682    fIncrementalSearchStartPos: TPoint; // position where to start searching
683    FIncrementalSearchStr, FIncrementalFoundStr: string;
684    FIncrementalSearchBackwards : Boolean;
685    FIncrementalSearchEditor: TSourceEditor; // editor with active search (MWE:shouldnt all FIncrementalSearch vars go to that editor ?)
686    FLastCodeBuffer: TCodeBuffer;
687    FProcessingCommand: boolean;
688    FSourceEditorList: TFPList; // list of TSourceEditor
689    FHistoryList: TFPList; // list of TSourceEditor page order for when a window closes
690    FHistoryDlg: TBrowseEditorTabHistoryDialog;
691    FStopBtnIdx: Integer;
692    FOnEditorPageCaptionUpdate: TMethodList;
693  private
694    FUpdateTabAndPageTimer: TTimer;
695    FWindowID: Integer;
696    // PopupMenu
697    procedure BuildPopupMenu;
698    //forwarders to FNoteBook
699    function GetNoteBookPage(Index: Integer): TTabSheet;
700    function GetNotebookPages: TStrings;
701    function GetPageCount: Integer;
702    function GetPageIndex: Integer;
703    procedure SetPageIndex(AValue: Integer);
704
705    procedure UpdateHighlightMenuItems(SrcEdit: TSourceEditor);
706    procedure UpdateLineEndingMenuItems(SrcEdit: TSourceEditor);
707    procedure UpdateEncodingMenuItems(SrcEdit: TSourceEditor);
708    procedure RemoveUserDefinedMenuItems;
709    function AddUserDefinedPopupMenuItem(const NewCaption: string;
710                                     const NewEnabled: boolean;
711                                     const NewOnClick: TNotifyEvent): TIDEMenuItem;
712    procedure RemoveContextMenuItems;
713    function AddContextPopupMenuItem(const NewCaption: string;
714                                     const NewEnabled: boolean;
715                                     const NewOnClick: TNotifyEvent): TIDEMenuItem;
716
717    // Incremental Search
718    procedure UpdateActiveEditColors(AEditor: TSynEdit);
719    procedure SetIncrementalSearchStr(const AValue: string);
720    procedure IncrementalSearch(ANext, ABackward: Boolean);
721    procedure UpdatePageNames;
722    procedure UpdateProjectFiles(ACurrentEditor: TSourceEditor = nil);
723
724    property NoteBookPage[Index: Integer]: TTabSheet read GetNoteBookPage;
725    procedure NoteBookInsertPage(Index: Integer; const S: string);
726    procedure NoteBookDeletePage(APageIndex: Integer);
727    procedure UpdateTabsAndPageTitle;
728    procedure UpdateTabsAndPageTimeReached(Sender: TObject);
729    procedure CallOnEditorPageCaptionUpdate(Sender: TObject);
730  protected
731    function NoteBookIndexOfPage(APage: TTabSheet): Integer;
732    procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState;
733      var Accept: Boolean); override;
734    procedure DragCanceled; override;
735    procedure DoActiveEditorChanged;
736  protected
737    States: TSourceNotebookStates;
738    procedure Activate; override;
739    procedure CreateNotebook;
740    function NewSE(Pagenum: Integer; NewPagenum: Integer = -1;
741                   ASharedEditor: TSourceEditor = nil;
742                   ATabCaption: String = ''): TSourceEditor;
743    procedure AcceptEditor(AnEditor: TSourceEditor; SendEvent: Boolean = False);
744    procedure ReleaseEditor(AnEditor: TSourceEditor; SendEvent: Boolean = False);
745    procedure EditorChanged(Sender: TObject; Changes: TSynStatusChanges);
746    procedure DoClose(var CloseAction: TCloseAction); override;
747    procedure DoShow; override;
748    procedure DoHide; override;
749    function GetWindowID: Integer; override;
750  protected
751    function GetActiveCompletionPlugin: TSourceEditorCompletionPlugin; override;
752    function GetBaseCaption: String; override;
753    function GetCompletionPlugins(Index: integer): TSourceEditorCompletionPlugin; override;
754
755    procedure EditorMouseMove(Sender: TObject; {%H-}Shift: TShiftstate;
756                              {%H-}X,{%H-}Y: Integer);
757    procedure EditorMouseDown(Sender: TObject; {%H-}Button: TMouseButton;
758                              {%H-}Shift: TShiftstate; {%H-}X,{%H-}Y: Integer);
759    function EditorGetIndent(Sender: TObject; Editor: TObject;
760             LogCaret, OldLogCaret: TPoint; FirstLinePos, LastLinePos: Integer;
761             Reason: TSynEditorCommand;
762             SetIndentProc: TSynBeautifierSetIndentProc): Boolean;
763    procedure EditorKeyDown(Sender: TObject; var {%H-}Key: Word; {%H-}Shift: TShiftState);
764    procedure EditorKeyUp(Sender: TObject; var {%H-}Key: Word; {%H-}Shift: TShiftState);
765    procedure EditorMouseWheel(Sender: TObject; {%H-}Shift: TShiftState;
766         {%H-}WheelDelta: Integer; {%H-}MousePos: TPoint; var {%H-}Handled: Boolean);
767
768    procedure NotebookMouseDown(Sender: TObject; Button: TMouseButton;
769          {%H-}Shift: TShiftState; X,Y: Integer);
770    procedure NotebookMouseUp(Sender: TObject; Button: TMouseButton;
771          {%H-}Shift: TShiftState; X,Y: Integer);
772    procedure NotebookDragDropEx(Sender, Source: TObject;
773                                  OldIndex, NewIndex: Integer; CopyDrag: Boolean;
774                                  var Done: Boolean);
775    procedure NotebookDragOverEx(Sender, Source: TObject;
776                                  OldIndex, NewIndex: Integer; CopyDrag: Boolean;
777                                  var Accept: Boolean);
778    procedure NotebookDragOver(Sender, Source: TObject;
779                               {%H-}X,{%H-}Y: Integer; State: TDragState; var Accept: Boolean);
780    procedure NotebookEndDrag(Sender, {%H-}Target: TObject; {%H-}X,{%H-}Y: Integer);
781
782    procedure OnApplicationDeactivate(Sender: TObject);
783    procedure ShowSynEditHint(const MousePos: TPoint);
784
785    procedure NextEditor;
786    procedure PrevEditor;
787    procedure MoveEditorLeft(CurrentPageIndex: integer);
788    procedure MoveEditorRight(CurrentPageIndex: integer);
789    procedure MoveActivePageLeft;
790    procedure MoveActivePageRight;
791    procedure MoveEditorFirst(CurrentPageIndex: integer);
792    procedure MoveEditorLast(CurrentPageIndex: integer);
793    procedure MoveActivePageFirst;
794    procedure MoveActivePageLast;
795    procedure GotoNextWindow(Backward: Boolean = False);
796    procedure GotoNextSharedEditor(Backward: Boolean = False);
797    procedure MoveEditorNextWindow(Backward: Boolean = False; Copy: Boolean = False);
798    procedure CopyEditor(OldPageIndex, NewWindowIndex, NewPageIndex: integer; Focus: Boolean = False);
799
800    function GetActiveEditor: TSourceEditorInterface; override;
801    procedure SetActiveEditor(const AValue: TSourceEditorInterface); override;
802    procedure SetBaseCaption(AValue: String); override;
803    function GetItems(Index: integer): TSourceEditorInterface; override;
804    function GetEditors(Index:integer): TSourceEditor;
805
806    property Manager: TSourceEditorManager read FManager;
807
808    procedure BeginAutoFocusLock;
809    procedure EndAutoFocusLock;
810  protected
811    procedure CloseTabClicked(Sender: TObject);
812    procedure CloseClicked(Sender: TObject; CloseOptions: TCloseSrcEditorOptions = []);
813    procedure ToggleFormUnitClicked(Sender: TObject);
814    procedure ToggleObjectInspClicked(Sender: TObject);
815
816    procedure IncUpdateLockInternal;
817    procedure DecUpdateLockInternal;
818
819    // editor page history
820    procedure HistorySetMostRecent(APage: TTabSheet);
821    procedure HistoryRemove(APage: TTabSheet);
822    function  HistoryGetTopPageIndex: Integer;
823
824    // incremental find
825    procedure BeginIncrementalFind;
826    procedure EndIncrementalFind;
827    property IncrementalSearchStr: string
828      read FIncrementalSearchStr write SetIncrementalSearchStr;
829
830    procedure StartShowCodeContext(JumpToError: boolean);
831
832    // paste and copy
833    procedure CutClicked(Sender: TObject);
834    procedure CopyClicked(Sender: TObject);
835    procedure PasteClicked(Sender: TObject);
836
837    procedure ReloadEditorOptions;
838    procedure CheckFont;
839
840  public
841    procedure AddUpdateEditorPageCaptionHandler(AEvent: TNotifyEvent; const AsLast: Boolean = True); override;
842    procedure RemoveUpdateEditorPageCaptionHandler(AEvent: TNotifyEvent); override;
843
844    procedure ProcessParentCommand(Sender: TObject;
845       var Command: TSynEditorCommand; var {%H-}AChar: TUTF8Char; {%H-}Data: pointer;
846       var Handled: boolean);
847    procedure ParentCommandProcessed(Sender: TObject;
848       var Command: TSynEditorCommand; var {%H-}AChar: TUTF8Char; {%H-}Data: pointer;
849       var Handled: boolean);
850  public
851    constructor Create(AOwner: TComponent); override; overload;
852    constructor Create(AOwner: TComponent; AWindowID: Integer); overload;
853    destructor Destroy; override;
854
855    function EditorCount: integer;
856    function IndexOfEditor(aEditor: TSourceEditorInterface): integer;
857    function Count: integer; override;
858
859    function SourceEditorIntfWithFilename(const Filename: string
860      ): TSourceEditorInterface; override;
861    function FindSourceEditorWithPageIndex(APageIndex:integer):TSourceEditor;
862    function FindPageWithEditor(ASourceEditor: TSourceEditor):integer;
863    function FindSourceEditorWithEditorComponent(EditorComp: TComponent): TSourceEditor;
864    function GetActiveSE: TSourceEditor; { $note deprecate and use SetActiveEditor}
865    procedure CheckCurrentCodeBufferChanged;
866    function IndexOfEditorInShareWith(AnOtherEditor: TSourceEditorInterface): Integer; override;
867    procedure MoveEditor(OldPageIndex, NewPageIndex: integer);
868    procedure MoveEditor(OldPageIndex, NewWindowIndex, NewPageIndex: integer);
869
870    procedure UpdateStatusBar;
871    procedure ClearExecutionLines;
872    procedure ClearExecutionMarks;
873
874    // new, close, focus
875    function NewFile(const NewShortName: String; ASource: TCodeBuffer;
876                      FocusIt: boolean; AShareEditor: TSourceEditor = nil): TSourceEditor;
877    procedure CloseFile(APageIndex:integer);
878    procedure FocusEditor;
879    function GetCapabilities: TCTabControlCapabilities;
880    procedure IncUpdateLock; override;
881    procedure DecUpdateLock; override;
882  public
883    property Editors[Index:integer]:TSourceEditor read GetEditors; // !!! not ordered for PageIndex
884    // forwarders to the FNotebook
885    property PageIndex: Integer read GetPageIndex write SetPageIndex;
886    property PageCount: Integer read GetPageCount;
887    property NotebookPages: TStrings read GetNotebookPages;
888  end;
889
890  { TBrowseEditorTabHistoryDialog }
891
892  TBrowseEditorTabHistoryDialog = class(TForm)
893  private
894    FNotebook: TSourceNotebook;
895    FEditorList: TListBox;
896
897    procedure MoveInList(aForward: Boolean);
898  protected
899    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
900    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
901    procedure DoCreate; override;
902  public
903    procedure Show(aForward: Boolean); reintroduce;
904  end;
905
906  TSrcEditMangerHandlerType = (
907    semhtCopyPaste
908    );
909  TSrcEditManagerUpdateFlag = (
910    ufMgrActiveEditorChanged,
911    ufShowWindowOnTop,
912    ufShowWindowOnTopFocus);
913  TSrcEditManagerUpdateFlags = set of TSrcEditManagerUpdateFlag;
914
915  { TSourceEditorManagerBase }
916  (* Implement all Methods with the Interface types *)
917
918  TSourceEditorManagerBase = class(TSourceEditorManagerInterface)
919  private
920    FActiveWindow: TSourceNotebook;
921    FSourceWindowList: TFPList;
922    FSourceWindowByFocusList: TFPList;
923    FUpdateLock: Integer;
924    FActiveEditorLock: Integer;
925    FAutoFocusLock: Integer;
926    FUpdateFlags: TSrcEditManagerUpdateFlags;
927    FShowTabs: Boolean;
928    procedure FreeSourceWindows;
929    function GetActiveSourceWindowIndex: integer;
930    function GetSourceWindowByLastFocused(Index: Integer): TSourceEditorWindowInterface;
931    procedure SetActiveSourceWindowIndex(const AValue: integer);
932  protected
933    fProducers: TFPList; // list of TSourceMarklingProducer
934    FChangeNotifyLists: Array [TsemChangeReason] of TMethodList;
935    FHandlers: array[TSrcEditMangerHandlerType] of TMethodList;
936    FChangesQueuedForMsgWnd: TETMultiSrcChanges;// source editor changes waiting to be applied to the Messages window
937    function  GetActiveSourceWindow: TSourceEditorWindowInterface; override;
938    procedure SetActiveSourceWindow(const AValue: TSourceEditorWindowInterface); override;
939    function  GetSourceWindows(Index: integer): TSourceEditorWindowInterface; override;
940    procedure DoWindowFocused({%H-}AWindow: TSourceNotebook);  // Includes Focus to ChildControl (aka Activated)
941    function  GetActiveEditor: TSourceEditorInterface; override;
942    procedure SetActiveEditor(const AValue: TSourceEditorInterface); override;
943    procedure DoActiveEditorChanged;
944    procedure DoEditorStatusChanged(AEditor: TSourceEditor);
945    function  GetSourceEditors(Index: integer): TSourceEditorInterface; override;
946    function  GetUniqueSourceEditors(Index: integer): TSourceEditorInterface; override;
947    function GetMarklingProducers(Index: integer): TSourceMarklingProducer; override;
948    procedure SyncMessageWnd(Sender: TObject);
949    procedure DoWindowShow(AWindow: TSourceNotebook);
950    procedure DoWindowHide(AWindow: TSourceNotebook);
951    function GetShowTabs: Boolean; override;
952    procedure SetShowTabs(const AShowTabs: Boolean); override;
953  public
954    procedure BeginAutoFocusLock;
955    procedure EndAutoFocusLock;
956    function  HasAutoFocusLock: Boolean;
957    // Windows
958    function SourceWindowWithEditor(const AEditor: TSourceEditorInterface): TSourceEditorWindowInterface;
959              override;
960    function  SourceWindowCount: integer; override;
961    function  IndexOfSourceWindow(AWindow: TSourceEditorWindowInterface): integer;
962    property  ActiveSourceWindowIndex: integer
963              read GetActiveSourceWindowIndex write SetActiveSourceWindowIndex;
964    function  IndexOfSourceWindowByLastFocused(AWindow: TSourceEditorWindowInterface): integer;
965    property  SourceWindowByLastFocused[Index: Integer]: TSourceEditorWindowInterface
966              read GetSourceWindowByLastFocused;
967    // Editors
968    function  SourceEditorIntfWithFilename(const Filename: string): TSourceEditorInterface;
969              override;
970    function  SourceEditorCount: integer; override;
971    function  UniqueSourceEditorCount: integer; override;
972    // Settings
973    function  GetEditorControlSettings(EditControl: TControl): boolean; override;
974    function  GetHighlighterSettings(Highlighter: TObject): boolean; override;
975  private
976    // Completion Plugins
977    FCompletionPlugins: TFPList;
978    FDefaultCompletionForm: TSourceEditCompletion;
979    FActiveCompletionPlugin: TSourceEditorCompletionPlugin;
980    function  GetDefaultCompletionForm: TSourceEditCompletion;
981    procedure FreeCompletionPlugins;
982    function  GetScreenRectForToken(AnEditor: TCustomSynEdit; PhysColumn, PhysRow, EndColumn: Integer): TRect;
983  protected
984    CodeToolsToSrcEditTimer: TTimer;
985    function  GetActiveCompletionPlugin: TSourceEditorCompletionPlugin; override;
986    function  GetCompletionBoxPosition: integer; override;
987    function  GetCompletionPlugins(Index: integer): TSourceEditorCompletionPlugin; override;
988    function  GetDefaultSynCompletionForm: TCustomForm; override;
989    function  GetSynCompletionLinesInWindow: integer; override;
990    procedure SetSynCompletionLinesInWindow(LineCnt: integer); override;
991    function FindIdentCompletionPlugin(SrcEdit: TSourceEditor; JumpToError: boolean;
992                               var s: string; var BoxX, BoxY: integer;
993                               var UseWordCompletion: boolean): boolean;
994    property DefaultCompletionForm: TSourceEditCompletion
995      read GetDefaultCompletionForm;
996  public
997    // Completion Plugins
998    function  CompletionPluginCount: integer; override;
999    procedure DeactivateCompletionForm; override;
1000    procedure RegisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
1001    procedure UnregisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
1002  protected
1003    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
1004    procedure IncUpdateLockInternal;
1005    procedure DecUpdateLockInternal;
1006  public
1007    constructor Create(AOwner: TComponent); override;
1008    destructor Destroy; override;
1009    procedure RegisterChangeEvent(AReason: TsemChangeReason; AHandler: TNotifyEvent); override;
1010    procedure UnRegisterChangeEvent(AReason: TsemChangeReason; AHandler: TNotifyEvent); override;
1011    procedure RegisterCopyPasteEvent(AHandler: TSemCopyPasteEvent); override;
1012    procedure UnRegisterCopyPasteEvent(AHandler: TSemCopyPasteEvent); override;
1013    // producers
1014    function MarklingProducerCount: integer; override;
1015    procedure RegisterMarklingProducer(aProducer: TSourceMarklingProducer); override;
1016    procedure UnregisterMarklingProducer(aProducer: TSourceMarklingProducer); override;
1017    procedure InvalidateMarklingsOfAllFiles(aProducer: TSourceMarklingProducer); override;
1018    procedure InvalidateMarklings(aProducer: TSourceMarklingProducer; aFilename: string); override;
1019  public
1020    procedure IncUpdateLock;
1021    procedure DecUpdateLock;
1022    procedure ShowActiveWindowOnTop(Focus: Boolean = False); override;
1023  private
1024    FMacroRecorder: TIdeEditorMacro;
1025    FOnCurrentCodeBufferChanged: TNotifyEvent;
1026    procedure DoMacroRecorderState(Sender: TObject);
1027  public
1028    // codetools
1029    property OnCurrentCodeBufferChanged: TNotifyEvent
1030             read FOnCurrentCodeBufferChanged write FOnCurrentCodeBufferChanged;
1031  end;
1032
1033  TJumpToSectionType = (
1034    jmpInterface, jmpInterfaceUses,
1035    jmpImplementation, jmpImplementationUses,
1036    jmpInitialization);
1037  TJumpToProcedureType = (jmpHeader, jmpBegin);
1038
1039  TSourceEditorHintWindowManager = class(TIDEHintWindowManager)
1040  private
1041    FManager: TSourceEditorManager;
1042    FAutoShown: Boolean;
1043    FAutoHintMousePos: TPoint;
1044    FAutoHintTimer: TIdleTimer;
1045    FAutoHideHintTimer: TTimer;
1046    FLastHint: string;
1047    FScreenRect: TRect;
1048
1049    procedure HintTimer(Sender: TObject);
1050    procedure HideHintTimer(Sender: TObject);
1051  public
1052    procedure ActivateHint(const ScreenRect: TRect; const ABaseURL, AHint: string;
1053      AAutoShown: Boolean = True; AMouseOffset: Boolean = True); overload;
1054    procedure ActivateHint(const ScreenPos: TPoint; const ABaseURL, AHint: string;
1055      AAutoShown: Boolean = True; AMouseOffset: Boolean = True); overload;
1056    procedure HideAutoHintAfterMouseMoved;
1057    procedure HideAutoHint;
1058    procedure UpdateHintTimer;
1059  public
1060    constructor Create(AManager: TSourceEditorManager);
1061    destructor Destroy; override;
1062  public
1063    property AutoHintTimer: TIdleTimer read FAutoHintTimer;
1064  end;
1065
1066  { TSourceEditorManager }
1067  (* Reintroduce all Methods with the final types *)
1068
1069  TSourceEditorManager = class(TSourceEditorManagerBase)
1070  private
1071    procedure DoConfigureEditorToolbar(Sender: TObject);
1072    function GetActiveSourceNotebook: TSourceNotebook;
1073    function GetActiveSrcEditor: TSourceEditor;
1074    function GetSourceEditorsByPage(WindowIndex, PageIndex: integer): TSourceEditor;
1075    function GetSourceNbByLastFocused(Index: Integer): TSourceNotebook;
1076    function GetSrcEditors(Index: integer): TSourceEditor;
1077    procedure SetActiveSourceNotebook(const AValue: TSourceNotebook);
1078    function GetSourceNotebook(Index: integer): TSourceNotebook;
1079    procedure SetActiveSrcEditor(const AValue: TSourceEditor);
1080    procedure SrcEditMenuProcedureJumpGetCaption(Sender: TObject; var ACaption,
1081      {%H-}AHint: string);
1082  public
1083    // Windows
1084    function  SourceWindowWithEditor(const AEditor: TSourceEditorInterface): TSourceNotebook;
1085              reintroduce;
1086    property  SourceWindows[Index: integer]: TSourceNotebook read GetSourceNotebook; // reintroduce
1087    property  ActiveSourceWindow: TSourceNotebook
1088              read GetActiveSourceNotebook write SetActiveSourceNotebook;       // reintroduce
1089    function  ActiveOrNewSourceWindow: TSourceNotebook;
1090    function  NewSourceWindow: TSourceNotebook;
1091    procedure CreateSourceWindow(Sender: TObject; aFormName: string;
1092                          var AForm: TCustomForm; DoDisableAutoSizing: boolean);
1093    procedure GetDefaultLayout(Sender: TObject; aFormName: string;
1094             out aBounds: TRect; out DockSibling: string; out DockAlign: TAlign);
1095    function  SourceWindowWithPage(const APage: TTabSheet): TSourceNotebook;
1096    property  SourceWindowByLastFocused[Index: Integer]: TSourceNotebook
1097              read GetSourceNbByLastFocused;
1098    function  IndexOfSourceWindowWithID(const AnID: Integer): Integer; override;
1099    function  SourceWindowWithID(const AnID: Integer): TSourceNotebook;
1100    // Editors
1101    function  SourceEditorCount: integer; override;
1102    function  GetActiveSE: TSourceEditor;                                       { $note deprecate and use ActiveEditor}
1103    property  ActiveEditor: TSourceEditor read GetActiveSrcEditor  write SetActiveSrcEditor; // reintroduced
1104    property SourceEditors[Index: integer]: TSourceEditor read GetSrcEditors;   // reintroduced
1105    property  SourceEditorsByPage[WindowIndex, PageIndex: integer]: TSourceEditor
1106              read GetSourceEditorsByPage;
1107    procedure SetWindowByIDAndPage(AWindowID, APageIndex: integer);
1108    function  SourceEditorIntfWithFilename(const Filename: string): TSourceEditor; reintroduce;
1109    function FindSourceEditorWithEditorComponent(EditorComp: TComponent): TSourceEditor; // With SynEdit
1110  protected
1111    procedure NewEditorCreated(AEditor: TSourceEditor);
1112    procedure EditorRemoved(AEditor: TSourceEditor);
1113    procedure SendEditorCreated(AEditor: TSourceEditor);
1114    procedure SendEditorDestroyed(AEditor: TSourceEditor);
1115    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
1116    procedure RemoveWindow(AWindow: TSourceNotebook);
1117  public
1118    // Forward to all windows
1119    procedure ClearErrorLines; override;
1120    procedure ClearExecutionLines;
1121    procedure ClearExecutionMarks;
1122    procedure FillExecutionMarks;
1123    procedure ReloadEditorOptions;
1124    function Beautify(const Src: string; const Flags: TSemBeautyFlags = []): string; override;
1125    // find / replace text
1126    procedure FindClicked(Sender: TObject);
1127    procedure FindNextClicked(Sender: TObject);
1128    procedure FindPreviousClicked(Sender: TObject);
1129    procedure ReplaceClicked(Sender: TObject);
1130    procedure IncrementalFindClicked(Sender: TObject);
1131    procedure GotoLineClicked(Sender: TObject);
1132    procedure JumpBackClicked(Sender: TObject);
1133    procedure JumpForwardClicked(Sender: TObject);
1134    procedure JumpToNextErrorClicked(Sender: TObject);
1135    procedure JumpToPrevErrorClicked(Sender: TObject);
1136    procedure AddJumpPointClicked(Sender: TObject);
1137    procedure AddCustomJumpPoint(ACaretXY: TPoint; ATopLine: integer;
1138                  AEditor: TSourceEditor; DeleteForwardHistory: boolean);
1139    procedure DeleteLastJumpPointClicked(Sender: TObject);
1140    procedure ViewJumpHistoryClicked(Sender: TObject);
1141  protected
1142    // Bookmarks
1143    procedure BookMarkToggleClicked(Sender: TObject);
1144    procedure BookMarkGotoClicked(Sender: TObject);
1145  public
1146    procedure BookMarkNextClicked(Sender: TObject);
1147    procedure BookMarkPrevClicked(Sender: TObject);
1148    procedure JumpToPos(FileName: string; Pos: TCodeXYPosition; TopLine: Integer);
1149    procedure JumpToPos(FileName: string; Pos: TCodeXYPosition; TopLine, BlockTopLine, BlockBottomLine: Integer);
1150    procedure JumpToSection(JumpType: TJumpToSectionType);
1151    procedure JumpToInterfaceClicked(Sender: TObject);
1152    procedure JumpToInterfaceUsesClicked(Sender: TObject);
1153    procedure JumpToImplementationClicked(Sender: TObject);
1154    procedure JumpToImplementationUsesClicked(Sender: TObject);
1155    procedure JumpToInitializationClicked(Sender: TObject);
1156    procedure JumpToProcedure(const JumpType: TJumpToProcedureType);
1157    procedure JumpToProcedureHeaderClicked(Sender: TObject);
1158    procedure JumpToProcedureBeginClicked(Sender: TObject);
1159  protected
1160    // macros
1161    function MacroFuncCol(const {%H-}s:string; const {%H-}Data: PtrInt;
1162                          var {%H-}Abort: boolean): string;
1163    function MacroFuncRow(const {%H-}s:string; const {%H-}Data: PtrInt;
1164                          var {%H-}Abort: boolean): string;
1165    function MacroFuncEdFile(const {%H-}s:string; const {%H-}Data: PtrInt;
1166                             var {%H-}Abort: boolean): string;
1167    function MacroFuncCurToken(const {%H-}s:string; const {%H-}Data: PtrInt;
1168                               var {%H-}Abort: boolean): string;
1169    function MacroFuncConfirm(const s:string; const {%H-}Data: PtrInt;
1170                               var Abort: boolean): string;
1171    function MacroFuncPrompt(const s:string; const {%H-}Data: PtrInt;
1172                             var Abort: boolean): string;
1173    function MacroFuncSave(const {%H-}s:string; const {%H-}Data: PtrInt;
1174                           var Abort: boolean): string;
1175    function MacroFuncSaveAll(const {%H-}s:string; const {%H-}Data: PtrInt;
1176                              var Abort: boolean): string;
1177  public
1178    procedure InitMacros(AMacroList: TTransferMacroList);
1179    procedure SetupShortCuts;
1180
1181    function FindUniquePageName(FileName:string; IgnoreEditor: TSourceEditor):string;
1182    function SomethingModified(Verbose: boolean = false): boolean;
1183    procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean);
1184    procedure OnUserInput(Sender: TObject; Msg: Cardinal);
1185    procedure LockAllEditorsInSourceChangeCache;
1186    procedure UnlockAllEditorsInSourceChangeCache;
1187    procedure BeginGlobalUpdate;
1188    procedure EndGlobalUpdate;
1189    procedure CloseFile(AEditor: TSourceEditorInterface);
1190    procedure HideHint;
1191    // history jumping
1192    procedure HistoryJump(Sender: TObject; JumpAction: TJumpHistoryAction);
1193  private
1194    // Hints
1195    FHints: TSourceEditorHintWindowManager;
1196    procedure ActivateHint(const ScreenRect: TRect; const BaseURL, TheHint: string;
1197      AutoShown: Boolean = True; AMouseOffset: Boolean = True); overload;
1198    procedure ActivateHint(const ScreenPos: TPoint; const BaseURL, TheHint: string;
1199      AutoShown: Boolean = True; AMouseOffset: Boolean = True); overload;
1200  private
1201    FCodeTemplateModul: TSynEditAutoComplete;
1202    FGotoDialog: TfrmGoto;
1203    procedure OnCodeTemplateTokenNotFound(Sender: TObject; AToken: string;
1204                                   AnEditor: TCustomSynEdit; var Index:integer);
1205    procedure OnCodeTemplateExecuteCompletion(
1206                                       ASynAutoComplete: TCustomSynAutoComplete;
1207                                       Index: integer);
1208  protected
1209    procedure CodeToolsToSrcEditTimerTimer(Sender: TObject);
1210    procedure OnSourceCompletionTimer(Sender: TObject);
1211    // marks
1212    procedure OnSourceMarksAction(AMark: TSourceMark; {%H-}AAction: TMarksAction);
1213    procedure OnSourceMarksGetSynEdit(Sender: TObject; aFilename: string;
1214      var aSynEdit: TSynEdit);
1215    // goto dialog
1216    function GotoDialog: TfrmGoto;
1217  public
1218    constructor Create(AOwner: TComponent); override;
1219    destructor Destroy; override;
1220    function CreateNewWindow(Activate: Boolean= False;
1221                             DoDisableAutoSizing: boolean = False;
1222                             AnID: Integer = -1
1223                            ): TSourceNotebook;
1224    function SenderToEditor(Sender: TObject): TSourceEditor;
1225    property CodeTemplateModul: TSynEditAutoComplete
1226                               read FCodeTemplateModul write FCodeTemplateModul;
1227  private
1228    // Context-Menu
1229    procedure CloseOtherPagesClicked(Sender: TObject);
1230    procedure CloseOtherPagesClickedAsync(Sender: PtrInt);
1231    procedure CloseRightPagesClicked(Sender: TObject);
1232    procedure CloseRightPagesClickedAsync(Sender: PtrInt);
1233    procedure ReadOnlyClicked(Sender: TObject);
1234    procedure ToggleLineNumbersClicked(Sender: TObject);
1235    procedure ToggleI18NForLFMClicked(Sender: TObject);
1236    procedure ShowUnitInfo(Sender: TObject);
1237    procedure CopyFilenameClicked(Sender: TObject);
1238    procedure EditorPropertiesClicked(Sender: TObject);
1239  private
1240    FOnAddJumpPoint: TOnAddJumpPoint;
1241    FOnClearBookmark: TPlaceBookMarkEvent;
1242    FOnClearBookmarkId: TPlaceBookMarkIdEvent;
1243    FOnClickLink: TMouseEvent;
1244    FOnCloseClicked: TOnCloseSrcEditor;
1245    FOnDeleteLastJumpPoint: TNotifyEvent;
1246    FOnUpdateProjectFile: TUpdateProjectFileEvent;
1247    FOnFindDeclarationClicked: TNotifyEvent;
1248    FOnGetIndent: TOnGetIndentEvent;
1249    FOnGotoBookmark: TBookMarkActionEvent;
1250    FOnInitIdentCompletion: TOnInitIdentCompletion;
1251    FOnJumpToHistoryPoint: TOnJumpToHistoryPoint;
1252    FOnMouseLink: TSynMouseLinkEvent;
1253    FOnNoteBookCloseQuery: TCloseEvent;
1254    FOnOpenFileAtCursorClicked: TNotifyEvent;
1255    FOnPackageForSourceEditor: TPackageForSourceEditorEvent;
1256    FOnPlaceMark: TPlaceBookMarkEvent;
1257    FOnPopupMenu: TSrcEditPopupMenuEvent;
1258    FOnProcessUserCommand: TOnProcessUserCommand;
1259    fOnReadOnlyChanged: TNotifyEvent;
1260    FOnSetBookmark: TBookMarkActionEvent;
1261    FOnShowCodeContext: TOnShowCodeContext;
1262    FOnShowHintForSource: TOnShowHintForSource;
1263    FOnShowUnitInfo: TNotifyEvent;
1264    FOnToggleFormUnitClicked: TNotifyEvent;
1265    FOnToggleObjectInspClicked: TNotifyEvent;
1266    FOnUserCommandProcessed: TOnUserCommandProcessed;
1267    FOnViewJumpHistory: TNotifyEvent;
1268  public
1269    property OnAddJumpPoint: TOnAddJumpPoint
1270             read FOnAddJumpPoint write FOnAddJumpPoint;
1271    property OnCloseClicked: TOnCloseSrcEditor
1272             read FOnCloseClicked write FOnCloseClicked;
1273    property OnClickLink: TMouseEvent read FOnClickLink write FOnClickLink;
1274    property OnMouseLink: TSynMouseLinkEvent read FOnMouseLink write FOnMouseLink;
1275    property OnGetIndent: TOnGetIndentEvent
1276             read FOnGetIndent write FOnGetIndent;
1277    property OnDeleteLastJumpPoint: TNotifyEvent
1278             read FOnDeleteLastJumpPoint write FOnDeleteLastJumpPoint;
1279    property OnUpdateProjectFile: TUpdateProjectFileEvent
1280             read FOnUpdateProjectFile write FOnUpdateProjectFile;
1281    property OnFindDeclarationClicked: TNotifyEvent
1282             read FOnFindDeclarationClicked write FOnFindDeclarationClicked;
1283    property OnInitIdentCompletion: TOnInitIdentCompletion
1284             read FOnInitIdentCompletion write FOnInitIdentCompletion;
1285    property OnShowCodeContext: TOnShowCodeContext
1286             read FOnShowCodeContext write FOnShowCodeContext;
1287    property OnJumpToHistoryPoint: TOnJumpToHistoryPoint
1288             read FOnJumpToHistoryPoint write FOnJumpToHistoryPoint;
1289    property OnPlaceBookmark: TPlaceBookMarkEvent  // Bookmark was placed by SynEdit
1290             read FOnPlaceMark write FOnPlaceMark;
1291    property OnClearBookmark: TPlaceBookMarkEvent  // Bookmark was cleared by SynEdit
1292             read FOnClearBookmark write FOnClearBookmark;
1293    property OnClearBookmarkId: TPlaceBookMarkIdEvent
1294             read FOnClearBookmarkId write FOnClearBookmarkId;
1295    property OnSetBookmark: TBookMarkActionEvent  // request to set a Bookmark
1296             read FOnSetBookmark write FOnSetBookmark;
1297    property OnGotoBookmark: TBookMarkActionEvent  // request to go to a Bookmark
1298             read FOnGotoBookmark write FOnGotoBookmark;
1299    property OnOpenFileAtCursorClicked: TNotifyEvent
1300             read FOnOpenFileAtCursorClicked write FOnOpenFileAtCursorClicked;
1301    property OnProcessUserCommand: TOnProcessUserCommand
1302             read FOnProcessUserCommand write FOnProcessUserCommand;
1303    property OnUserCommandProcessed: TOnUserCommandProcessed
1304             read FOnUserCommandProcessed write FOnUserCommandProcessed;
1305    property OnReadOnlyChanged: TNotifyEvent
1306             read fOnReadOnlyChanged write fOnReadOnlyChanged;
1307    property OnShowHintForSource: TOnShowHintForSource
1308             read FOnShowHintForSource write FOnShowHintForSource;
1309    property OnShowUnitInfo: TNotifyEvent
1310             read FOnShowUnitInfo write FOnShowUnitInfo;
1311    property OnToggleFormUnitClicked: TNotifyEvent
1312             read FOnToggleFormUnitClicked write FOnToggleFormUnitClicked;
1313    property OnToggleObjectInspClicked: TNotifyEvent
1314             read FOnToggleObjectInspClicked write FOnToggleObjectInspClicked;
1315    property OnViewJumpHistory: TNotifyEvent
1316             read FOnViewJumpHistory write FOnViewJumpHistory;
1317    property OnPopupMenu: TSrcEditPopupMenuEvent read FOnPopupMenu write FOnPopupMenu;
1318    property OnNoteBookCloseQuery: TCloseEvent
1319             read FOnNoteBookCloseQuery write FOnNoteBookCloseQuery;
1320    property OnPackageForSourceEditor: TPackageForSourceEditorEvent
1321             read FOnPackageForSourceEditor write FOnPackageForSourceEditor;
1322  end;
1323
1324  TSourceEditorWordCompletion = class(TWordCompletion)
1325  private type
1326    TSourceListItem = class
1327      Source: TStrings;
1328      IgnoreWordPos: TPoint;
1329    end;
1330  private
1331    FIncludeWords: TIdentComplIncludeWords;
1332    FSourceList: TObjectList;
1333    procedure ReloadSourceList;
1334  protected
1335    procedure DoGetSource(var Source: TStrings; var {%H-}TopLine,
1336      {%H-}BottomLine: Integer; var IgnoreWordPos: TPoint; SourceIndex: integer); override;
1337  public
1338    constructor Create;
1339    destructor Destroy; override;
1340  public
1341    property IncludeWords: TIdentComplIncludeWords read FIncludeWords write FIncludeWords;
1342  end;
1343
1344function SourceEditorManager: TSourceEditorManager; inline;
1345
1346
1347  //=============================================================================
1348
1349const
1350  SourceTabMenuRootName = 'SourceTab';
1351  SourceEditorMenuRootName = 'SourceEditor';
1352
1353var
1354  // Clipboard
1355  SrcEditMenuCut: TIDEMenuCommand;
1356  SrcEditMenuCopy: TIDEMenuCommand;
1357  SrcEditMenuPaste: TIDEMenuCommand;
1358  SrcEditMenuMultiPaste: TIDEMenuCommand;
1359  SrcEditMenuCopyFilename: TIDEMenuCommand;
1360  SrcEditMenuFindDeclaration: TIDEMenuCommand;
1361  SrcEditMenuSelectAll: TIDEMenuCommand;
1362    // finding / jumping
1363    SrcEditMenuProcedureJump: TIDEMenuCommand;
1364    SrcEditMenuFindNextWordOccurrence: TIDEMenuCommand;
1365    SrcEditMenuFindPrevWordOccurrence: TIDEMenuCommand;
1366    SrcEditMenuFindinFiles: TIDEMenuCommand;
1367    SrcEditMenuFindIdentifierReferences: TIDEMenuCommand;
1368    SrcEditMenuFindUsedUnitReferences: TIDEMenuCommand;
1369    // open file
1370    SrcEditMenuOpenFileAtCursor: TIDEMenuCommand;
1371  SrcEditMenuClosePage: TIDEMenuCommand;
1372  SrcEditMenuCloseOtherPages: TIDEMenuCommand;
1373  SrcEditMenuCloseOtherPagesToRight: TIDEMenuCommand;
1374    // bookmarks
1375    SrcEditMenuNextBookmark: TIDEMenuCommand;
1376    SrcEditMenuPrevBookmark: TIDEMenuCommand;
1377    SrcEditMenuSetFreeBookmark: TIDEMenuCommand;
1378    SrcEditMenuClearFileBookmark: TIDEMenuCommand;
1379    SrcEditMenuClearAllBookmark: TIDEMenuCommand;
1380    SrcEditMenuGotoBookmark: array [TBookmarkNumRange] of TIDEMenuCommand;
1381    SrcEditMenuToggleBookmark: array [TBookmarkNumRange] of TIDEMenuCommand;
1382    // debugging
1383    SrcEditMenuToggleBreakpoint: TIDEMenuCommand;
1384    SrcEditMenuStepToCursor: TIDEMenuCommand;
1385    SrcEditMenuRunToCursor: TIDEMenuCommand;
1386    SrcEditMenuEvaluateModify: TIDEMenuCommand;
1387    SrcEditMenuAddWatchAtCursor: TIDEMenuCommand;
1388    SrcEditMenuAddWatchPointAtCursor: TIDEMenuCommand;
1389    SrcEditMenuInspect: TIDEMenuCommand;
1390    SrcEditMenuViewCallStack: TIDEMenuCommand;
1391    // source
1392    SrcEditMenuEncloseSelection: TIDEMenuCommand;
1393    SrcEditMenuEncloseInIFDEF: TIDEMenuCommand;
1394    SrcEditMenuCompleteCode: TIDEMenuCommand;
1395    SrcEditMenuUseUnit: TIDEMenuCommand;
1396    SrcEditMenuShowUnitInfo: TIDEMenuCommand;
1397    // refactoring
1398    SrcEditMenuRenameIdentifier: TIDEMenuCommand;
1399    SrcEditMenuExtractProc: TIDEMenuCommand;
1400    SrcEditMenuInvertAssignment: TIDEMenuCommand;
1401    SrcEditMenuShowAbstractMethods: TIDEMenuCommand;
1402    SrcEditMenuShowEmptyMethods: TIDEMenuCommand;
1403    SrcEditMenuShowUnusedUnits: TIDEMenuCommand;
1404    SrcEditMenuFindOverloads: TIDEMenuCommand;
1405    SrcEditMenuMakeResourceString: TIDEMenuCommand;
1406  SrcEditMenuMoveEditorLeft: TIDEMenuCommand;
1407  SrcEditMenuMoveEditorRight: TIDEMenuCommand;
1408  SrcEditMenuMoveEditorFirst: TIDEMenuCommand;
1409  SrcEditMenuMoveEditorLast: TIDEMenuCommand;
1410  SrcEditMenuReadOnly: TIDEMenuCommand;
1411  SrcEditMenuShowLineNumbers: TIDEMenuCommand;
1412  SrcEditMenuDisableI18NForLFM: TIDEMenuCommand;
1413  SrcEditMenuEditorProperties: TIDEMenuCommand;
1414  {$IFnDEF SingleSrcWindow}
1415  // Multi Window
1416  SrcEditMenuMoveToNewWindow: TIDEMenuCommand;
1417  SrcEditMenuMoveToOtherWindow: TIDEMenuSection;
1418  SrcEditMenuMoveToOtherWindowNew: TIDEMenuCommand;
1419  SrcEditMenuMoveToOtherWindowList: TIDEMenuSection;
1420  SrcEditMenuCopyToNewWindow: TIDEMenuCommand;
1421  SrcEditMenuCopyToOtherWindow: TIDEMenuSection;
1422  SrcEditMenuCopyToOtherWindowNew: TIDEMenuCommand;
1423  SrcEditMenuCopyToOtherWindowList: TIDEMenuSection;
1424  SrcEditMenuFindInOtherWindow: TIDEMenuSection;
1425  SrcEditMenuFindInOtherWindowList: TIDEMenuSection;
1426  // EditorLocks
1427  SrcEditMenuEditorLock: TIDEMenuCommand;
1428  {$ENDIF}
1429
1430
1431function GetIdeCmdAndToolBtn(ACommand: word; out ToolButton: TIDEButtonCommand): TIDECommand;
1432function GetIdeCmdRegToolBtn(ACommand: word): TIDECommand;
1433procedure RegisterStandardSourceTabMenuItems;
1434procedure RegisterStandardSourceEditorMenuItems;
1435function dbgSourceNoteBook(snb: TSourceNotebook): string;
1436function CompareSrcEditIntfWithFilename(SrcEdit1, SrcEdit2: Pointer): integer;
1437function CompareFilenameWithSrcEditIntf(FilenameStr, SrcEdit: Pointer): integer;
1438
1439var
1440  Highlighters: array[TLazSyntaxHighlighter] of TSynCustomHighlighter;
1441  EnglishGPLNotice: string;
1442  EnglishLGPLNotice: string;
1443  EnglishModifiedLGPLNotice: string;
1444  EnglishMITNotice: string;
1445
1446
1447implementation
1448
1449{$R *.lfm}
1450{$R ../images/bookmark.res}
1451
1452var
1453  AWordCompletion: TWordCompletion = nil;
1454
1455var
1456  SRCED_LOCK, SRCED_OPEN, SRCED_CLOSE, SRCED_PAGES: PLazLoggerLogGroup;
1457
1458const
1459  (* SoftCenter are the visible Lines in the Editor where the caret can be located,
1460     without CenterCursor adjusting the topline.
1461     SoftCenter is defined by the amount of lines on the top/bottom of the editor,
1462     which are *not* part of it.
1463  *)
1464  SoftCenterFactor  = 5;  // One fifth of the "LinesInWindow"on each side (top/bottom)
1465  SoftCenterMinimum = 1;
1466  SoftCenterMaximum = 8;
1467
1468var
1469  AutoStartCompletionBoxTimer: TIdleTimer = nil;
1470  SourceCompletionCaretXY: TPoint;
1471  PasBeautifier: TSynBeautifierPascal;
1472
1473function dbgs(AFlag: TSourceNotebookUpdateFlag): string; overload;
1474begin
1475  WriteStr(Result, AFlag);
1476end;
1477
1478function dbgs(AFlags: TSourceNotebookUpdateFlags): string; overload;
1479var
1480  i: TSourceNotebookUpdateFlag;
1481begin
1482  Result := '';
1483  for i := low(TSourceNotebookUpdateFlags) to high(TSourceNotebookUpdateFlags) do
1484    if i in AFlags then begin
1485      if Result <> '' then Result := Result + ',';
1486      Result := Result + dbgs(i);
1487    end;
1488  Result := '['+ Result + ']';
1489end;
1490
1491function GetIdeCmdAndToolBtn(ACommand: word; out ToolButton: TIDEButtonCommand): TIDECommand;
1492// Find and return IDECommand.
1493// Register IDEButtonCommand for it, also returned in out param.
1494begin
1495  Result:=IDECommandList.FindIDECommand(ACommand);
1496  if Result<>nil then
1497    ToolButton := RegisterIDEButtonCommand(Result)
1498  else
1499    ToolButton := nil;
1500end;
1501
1502function GetIdeCmdRegToolBtn(ACommand: word): TIDECommand;
1503// Find and return IDECommand. Register IDEButtonCommand for it.
1504begin
1505  Result:=IDECommandList.FindIDECommand(ACommand);
1506  if Result<>nil then
1507    RegisterIDEButtonCommand(Result);
1508end;
1509
1510function SourceEditorManager: TSourceEditorManager;
1511begin
1512  Result := TSourceEditorManager(SourceEditorManagerIntf);
1513end;
1514
1515procedure ExecuteIdeMenuClick(Sender: TObject);
1516var
1517  ActEdit: TSourceEditor;
1518  r: Boolean;
1519begin
1520  if SourceEditorManager = nil then exit;
1521  if not (Sender is TIDESpecialCommand) then exit;
1522  if TIDESpecialCommand(Sender).Command = nil then exit;
1523  ActEdit := SourceEditorManager.ActiveEditor;
1524  if ActEdit = nil then
1525  begin
1526    TIDESpecialCommand(Sender).Command.Execute(Sender);
1527    exit;
1528  end;
1529  r := TIDESpecialCommand(Sender).Command.OnExecuteProc = @ExecuteIdeMenuClick;
1530  if r then
1531    TIDESpecialCommand(Sender).Command.OnExecuteProc := nil;
1532  // Commands may not work without focusing when anchordocking is installed
1533  ActEdit.FocusEditor;
1534  ActEdit.DoEditorExecuteCommand(TIDESpecialCommand(Sender).Command.Command);
1535  if r then
1536    TIDESpecialCommand(Sender).Command.OnExecuteProc := @ExecuteIdeMenuClick;
1537end;
1538
1539procedure RegisterStandardSourceTabMenuItems;
1540var
1541  AParent: TIDEMenuSection;
1542begin
1543  SourceTabMenuRoot:=RegisterIDEMenuRoot(SourceTabMenuRootName);
1544
1545  {%region *** Pages section ***}
1546  SrcEditMenuSectionPages:=RegisterIDEMenuSection(SourceTabMenuRoot, 'Pages');
1547  AParent:=SrcEditMenuSectionPages;
1548
1549    SrcEditMenuClosePage := RegisterIDEMenuCommand(AParent,
1550        'Close Page', uemClosePage, nil, @ExecuteIdeMenuClick, nil, 'menu_close');
1551    SrcEditMenuCloseOtherPages := RegisterIDEMenuCommand(AParent,
1552        'Close All Other Pages',uemCloseOtherPages, nil, @ExecuteIdeMenuClick);
1553    SrcEditMenuCloseOtherPagesToRight := RegisterIDEMenuCommand(AParent,
1554        'Close Pages To the Right',uemCloseOtherPagesRight, nil, @ExecuteIdeMenuClick);
1555
1556    {$IFnDEF SingleSrcWindow}
1557    // Lock Editor
1558    SrcEditMenuEditorLock := RegisterIDEMenuCommand(AParent,
1559        'LockEditor', uemLockPage, nil, @ExecuteIdeMenuClick);
1560    SrcEditMenuEditorLock.ShowAlwaysCheckable := True;
1561    // Move to other Window
1562    SrcEditMenuMoveToNewWindow := RegisterIDEMenuCommand(AParent,
1563        'MoveToNewWindow', uemMoveToNewWindow, nil, @ExecuteIdeMenuClick);
1564
1565    {%region * Move To Other *}
1566      SrcEditMenuMoveToOtherWindow := RegisterIDESubMenu(AParent,
1567          'MoveToOtherWindow', uemMoveToOtherWindow);
1568      SrcEditMenuMoveToOtherWindowNew := RegisterIDEMenuCommand(SrcEditMenuMoveToOtherWindow,
1569          'MoveToOtherWindowNew', uemMoveToOtherWindowNew, nil, @ExecuteIdeMenuClick);
1570      // Section for dynamically created targets
1571      SrcEditMenuMoveToOtherWindowList := RegisterIDEMenuSection(SrcEditMenuMoveToOtherWindow,
1572          'MoveToOtherWindowList Section');
1573    {%endregion}
1574
1575    SrcEditMenuCopyToNewWindow := RegisterIDEMenuCommand(AParent,
1576        'CopyToNewWindow', uemCopyToNewWindow, nil, @ExecuteIdeMenuClick);
1577
1578    {%region * Copy To Other *}
1579      SrcEditMenuCopyToOtherWindow := RegisterIDESubMenu(AParent,
1580          'CopyToOtherWindow', uemCopyToOtherWindow);
1581      SrcEditMenuCopyToOtherWindowNew := RegisterIDEMenuCommand(SrcEditMenuCopyToOtherWindow,
1582          'CopyToOtherWindowNew', uemCopyToOtherWindowNew, nil, @ExecuteIdeMenuClick);
1583      // Section for dynamically created targets
1584      SrcEditMenuCopyToOtherWindowList := RegisterIDEMenuSection(SrcEditMenuCopyToOtherWindow,
1585          'CopyToOtherWindowList Section');
1586    {%endregion}
1587
1588    SrcEditMenuFindInOtherWindow := RegisterIDESubMenu(AParent,
1589      'FindInOtherWindow', uemFindInOtherWindow);
1590    // Section for dynamically created targets
1591    SrcEditMenuFindInOtherWindowList := RegisterIDEMenuSection(SrcEditMenuFindInOtherWindow,
1592        'FindInOtherWindowList Section');
1593    {$ENDIF}
1594
1595    {%region * Move Page (left/right) *}
1596      SrcEditSubMenuMovePage:=RegisterIDESubMenu(AParent, 'Move Page', lisMovePage);
1597      AParent:=SrcEditSubMenuMovePage;
1598
1599      SrcEditMenuMoveEditorLeft := RegisterIDEMenuCommand(AParent,
1600          'MoveEditorLeft', uemMovePageLeft, nil, @ExecuteIdeMenuClick);
1601      SrcEditMenuMoveEditorRight := RegisterIDEMenuCommand(AParent,
1602          'MoveEditorRight', uemMovePageRight, nil, @ExecuteIdeMenuClick);
1603      SrcEditMenuMoveEditorFirst := RegisterIDEMenuCommand(AParent,
1604          'MoveEditorLeftmost', uemMovePageLeftmost, nil, @ExecuteIdeMenuClick);
1605      SrcEditMenuMoveEditorLast := RegisterIDEMenuCommand(AParent,
1606          'MoveEditorRightmost', uemMovePageRightmost, nil, @ExecuteIdeMenuClick);
1607    {%endregion}
1608  {%endregion}
1609
1610  {%region *** Editors section ***}
1611  SrcEditMenuSectionEditors:=RegisterIDEMenuSection(SourceTabMenuRoot, 'Editors');
1612  {%endregion}
1613end;
1614
1615procedure RegisterStandardSourceEditorMenuItems;
1616var
1617  AParent: TIDEMenuSection;
1618  I: Integer;
1619begin
1620  SourceEditorMenuRoot:=RegisterIDEMenuRoot(SourceEditorMenuRootName);
1621  AParent:=SourceEditorMenuRoot;
1622
1623  // register the first dynamic section for often used context sensitive stuff
1624  SrcEditMenuSectionFirstDynamic:=RegisterIDEMenuSection(SourceEditorMenuRoot, 'First dynamic section');
1625
1626  // Felipe: Please keep "Find Declaration" as the first item
1627  {%region *** first static section *** }
1628    SrcEditMenuSectionFirstStatic:=RegisterIDEMenuSection(SourceEditorMenuRoot, 'First static section');
1629    AParent:=SrcEditMenuSectionFirstStatic;
1630
1631    SrcEditMenuFindDeclaration := RegisterIDEMenuCommand
1632        (AParent, 'Find Declaration', uemFindDeclaration, nil, @ExecuteIdeMenuClick);
1633
1634    {%region *** Submenu: Find Section *** }
1635      SrcEditSubMenuFind := RegisterIDESubMenu(AParent,
1636          'Find section', lisMenuFind, nil, nil, 'menu_search_find');
1637      AParent:=SrcEditSubMenuFind;
1638
1639      SrcEditMenuProcedureJump := RegisterIDEMenuCommand(AParent,
1640          'Procedure Jump', uemProcedureJump, nil,
1641          @ExecuteIdeMenuClick);
1642      SrcEditMenuFindNextWordOccurrence := RegisterIDEMenuCommand(AParent,
1643          'Find next word occurrence', srkmecFindNextWordOccurrence, nil,
1644          @ExecuteIdeMenuClick, nil, 'next_word');
1645      SrcEditMenuFindPrevWordOccurrence := RegisterIDEMenuCommand(AParent,
1646          'Find previous word occurrence', srkmecFindPrevWordOccurrence, nil,
1647          @ExecuteIdeMenuClick, nil, 'previous_word');
1648      SrcEditMenuFindInFiles := RegisterIDEMenuCommand(AParent,
1649          'Find in files', srkmecFindInFiles + ' ...', nil,
1650          @ExecuteIdeMenuClick, nil, 'menu_search_files');
1651      SrcEditMenuFindIdentifierReferences := RegisterIDEMenuCommand(AParent,
1652          'FindIdentifierReferences',lisMenuFindIdentifierRefs, nil,
1653          @ExecuteIdeMenuClick);
1654      SrcEditMenuFindUsedUnitReferences := RegisterIDEMenuCommand(AParent,
1655          'FindUsedUnitReferences', lisMenuFindReferencesOfUsedUnit, nil,
1656          @ExecuteIdeMenuClick);
1657    {%endregion}
1658  {%endregion}
1659
1660  {%region *** Clipboard section ***}
1661    SrcEditMenuSectionClipboard:=RegisterIDEMenuSection(SourceEditorMenuRoot, 'Clipboard');
1662    AParent:=SrcEditMenuSectionClipboard;
1663
1664    SrcEditMenuCut:=RegisterIDEMenuCommand(AParent,'Cut',lisCut, nil, nil, nil, 'laz_cut');
1665    SrcEditMenuCopy:=RegisterIDEMenuCommand(AParent,'Copy',lisCopy, nil, nil, nil, 'laz_copy');
1666    SrcEditMenuPaste:=RegisterIDEMenuCommand(AParent,'Paste',lisPaste, nil, nil, nil, 'laz_paste');
1667    SrcEditMenuMultiPaste:=RegisterIDEMenuCommand(AParent,'MultiPaste',lisMenuMultiPaste);
1668    SrcEditMenuSelectAll:=RegisterIDEMenuCommand(AParent,'SelectAll',lisMenuSelectAll);
1669    SrcEditMenuCopyFilename:=RegisterIDEMenuCommand(AParent,'Copy filename', uemCopyFilename);
1670  {%endregion}
1671
1672  {%region *** Files section ***}
1673    SrcEditMenuSectionFiles:=RegisterIDEMenuSection(SourceEditorMenuRoot, 'Files');
1674
1675    {%region * sub menu Open File *}
1676      SrcEditSubMenuOpenFile:=RegisterIDESubMenu(SrcEditMenuSectionFiles,
1677          'Open File',lisOpenFile, nil, nil, 'laz_open');
1678      AParent:=SrcEditSubMenuOpenFile;
1679
1680      SrcEditMenuOpenFileAtCursor:=RegisterIDEMenuCommand(AParent, 'Open File At Cursor',
1681          uemOpenFileAtCursor, nil, @ExecuteIdeMenuClick, nil, 'menu_search_openfile_atcursor');
1682      // register the File Specific dynamic section
1683      SrcEditMenuSectionFileDynamic:=RegisterIDEMenuSection(AParent, 'File dynamic section');
1684    {%endregion}
1685
1686    {%region * sub menu Flags section *}
1687      SrcEditSubMenuFlags:=RegisterIDESubMenu(SrcEditMenuSectionFiles,'Flags section',lisFileSettings);
1688      AParent:=SrcEditSubMenuFlags;
1689
1690      SrcEditMenuReadOnly := RegisterIDEMenuCommand(AParent,'ReadOnly',uemReadOnly);
1691      SrcEditMenuReadOnly.ShowAlwaysCheckable:=true;
1692      SrcEditMenuShowLineNumbers := RegisterIDEMenuCommand(AParent, 'ShowLineNumbers',uemShowLineNumbers);
1693      SrcEditMenuShowLineNumbers.ShowAlwaysCheckable:=true;
1694      SrcEditMenuDisableI18NForLFM := RegisterIDEMenuCommand(AParent, 'DisableI18NForLFM',lisDisableI18NForLFM);
1695      SrcEditSubMenuHighlighter := RegisterIDESubMenu(AParent,'Highlighter', uemHighlighter);
1696      SrcEditSubMenuEncoding := RegisterIDESubMenu(AParent,'Encoding', uemEncoding);
1697      SrcEditSubMenuLineEnding := RegisterIDESubMenu(AParent,'LineEnding', uemLineEnding);
1698    {%endregion}
1699  {%endregion}
1700
1701  {%region *** Goto Marks section ***}
1702  SrcEditMenuSectionMarks:=RegisterIDEMenuSection(SourceEditorMenuRoot, 'Marks section');
1703    // register the Goto Bookmarks Submenu
1704    SrcEditSubMenuGotoBookmarks:=RegisterIDESubMenu(SrcEditMenuSectionMarks,
1705                                   'Goto bookmarks submenu', uemGotoBookmark, nil, nil, 'menu_goto_bookmarks');
1706    AParent:=SrcEditSubMenuGotoBookmarks;
1707      for I in TBookmarkNumRange do
1708        SrcEditMenuGotoBookmark[I]:=RegisterIDEMenuCommand(AParent,
1709            'GotoBookmark'+IntToStr(I), Format(uemBookmarkNUnSet, [IntToStr(I)]),
1710            nil, @ExecuteIdeMenuClick, nil,
1711            'menu_goto_bookmark'+IntToStr(I));
1712
1713      AParent:=RegisterIDEMenuSection(AParent, 'Next/Prev Bookmark section');
1714      SrcEditMenuNextBookmark:=RegisterIDEMenuCommand(AParent,
1715          'Goto next Bookmark',uemNextBookmark, nil,
1716          @ExecuteIdeMenuClick, nil, 'menu_search_next_bookmark');
1717      SrcEditMenuPrevBookmark:=RegisterIDEMenuCommand(AParent,
1718          'Goto previous Bookmark',uemPrevBookmark, nil,
1719          @ExecuteIdeMenuClick, nil, 'menu_search_previous_bookmark');
1720  {%endregion}
1721
1722  {%region *** Toggle Bookmarks Submenu ***}
1723    SrcEditSubMenuToggleBookmarks:=RegisterIDESubMenu(SrcEditMenuSectionMarks,
1724                                     'Toggle bookmarks submenu', uemToggleBookmark, nil, nil, 'menu_toggle_bookmarks');
1725    AParent:=SrcEditSubMenuToggleBookmarks;
1726      for I in TBookmarkNumRange do
1727        SrcEditMenuToggleBookmark[I]:=RegisterIDEMenuCommand(AParent,
1728            'ToggleBookmark'+IntToStr(I), Format(uemToggleBookmarkNUnset, [IntToStr(I)]),
1729            nil, @ExecuteIdeMenuClick, nil,
1730            'menu_toggle_bookmark'+IntToStr(I));
1731
1732      AParent:=RegisterIDEMenuSection(AParent, 'Set Free Bookmark section');
1733      SrcEditMenuSetFreeBookmark:=RegisterIDEMenuCommand(AParent,
1734          'Set a free Bookmark',uemSetFreeBookmark, nil, @ExecuteIdeMenuClick, nil, 'menu_set_free_bookmark');
1735
1736      AParent:=RegisterIDEMenuSection(AParent, 'Clear Bookmarks section');
1737      SrcEditMenuClearFileBookmark:=RegisterIDEMenuCommand(AParent,
1738          'Clear Bookmark for current file',srkmecClearBookmarkForFile, nil, @ExecuteIdeMenuClick, nil, 'menu_clear_file_bookmarks');
1739      SrcEditMenuClearAllBookmark:=RegisterIDEMenuCommand(AParent,
1740          'Clear all Bookmark',srkmecClearAllBookmark, nil, @ExecuteIdeMenuClick, nil, 'menu_clear_all_bookmarks');
1741  {%endregion}
1742
1743  {%region *** Debug Section ***}
1744    // Commands will be assigned by DebugManager
1745    SrcEditMenuSectionDebug:=RegisterIDEMenuSection(SourceEditorMenuRoot, 'Debug section');
1746    // register the Debug submenu
1747    SrcEditSubMenuDebug:=RegisterIDESubMenu(SrcEditMenuSectionDebug,
1748                                            'Debug', uemDebugWord, nil, nil, 'debugger');
1749    AParent:=SrcEditSubMenuDebug;
1750
1751      // register the Debug submenu items
1752      SrcEditMenuToggleBreakpoint:=RegisterIDEMenuCommand(AParent,
1753          'Toggle Breakpoint', uemToggleBreakpoint, nil, @ExecuteIdeMenuClick);
1754      SrcEditMenuEvaluateModify:=RegisterIDEMenuCommand(AParent,
1755          'Evaluate/Modify...', uemEvaluateModify, nil, nil, nil, 'debugger_modify');
1756      SrcEditMenuEvaluateModify.Enabled:=False;
1757      SrcEditMenuAddWatchAtCursor:=RegisterIDEMenuCommand(AParent,
1758          'Add Watch at Cursor', uemAddWatchAtCursor);
1759      SrcEditMenuAddWatchPointAtCursor:=RegisterIDEMenuCommand(AParent,
1760          'Add Watch at Cursor', uemAddWatchPointAtCursor);
1761      SrcEditMenuInspect:=RegisterIDEMenuCommand(AParent,
1762          'Inspect...', uemInspect, nil, nil, nil, 'debugger_inspect');
1763      SrcEditMenuInspect.Enabled:=False;
1764      SrcEditMenuStepToCursor:=RegisterIDEMenuCommand(AParent,
1765          'Run to cursor', lisMenuStepToCursor, nil, nil, nil, 'menu_step_cursor');
1766      SrcEditMenuRunToCursor:=RegisterIDEMenuCommand(AParent,
1767          'Run to cursor', lisMenuRunToCursor, nil, nil, nil, 'menu_run_cursor');
1768      SrcEditMenuViewCallStack:=RegisterIDEMenuCommand(AParent,
1769          'View Call Stack', uemViewCallStack, nil, @ExecuteIdeMenuClick, nil, 'debugger_call_stack');
1770  {%endregion}
1771
1772  {%region *** Source Section ***}
1773    SrcEditSubMenuSource := RegisterIDESubMenu(SourceEditorMenuRoot,
1774        'Source', uemSource, nil, nil, 'item_unit');
1775    AParent:=SrcEditSubMenuSource;
1776    SrcEditMenuEncloseSelection := RegisterIDEMenuCommand(AParent,
1777        'EncloseSelection', lisMenuEncloseSelection);
1778    SrcEditMenuEncloseInIFDEF := RegisterIDEMenuCommand(AParent,
1779        'itmSourceEncloseInIFDEF', lisMenuEncloseInIFDEF);
1780    SrcEditMenuCompleteCode := RegisterIDEMenuCommand(AParent,
1781        'CompleteCode', lisMenuCompleteCode, nil, @ExecuteIdeMenuClick);
1782    SrcEditMenuInvertAssignment := RegisterIDEMenuCommand(AParent,
1783        'InvertAssignment', uemInvertAssignment, nil, @ExecuteIdeMenuClick);
1784    SrcEditMenuUseUnit := RegisterIDEMenuCommand(AParent,
1785        'UseUnit', lisMenuUseUnit, nil, @ExecuteIdeMenuClick);
1786    SrcEditMenuShowUnitInfo := RegisterIDEMenuCommand(AParent,
1787        'ShowUnitInfo', lisMenuViewUnitInfo , nil, nil, nil, 'menu_view_unit_info');
1788  {%endregion}
1789
1790  {%region *** Refactoring Section ***}
1791    SrcEditSubMenuRefactor:=RegisterIDESubMenu(SourceEditorMenuRoot,
1792                                               'Refactoring',uemRefactor);
1793    AParent:=SrcEditSubMenuRefactor;
1794    SrcEditMenuRenameIdentifier := RegisterIDEMenuCommand(AParent,
1795        'RenameIdentifier', lisMenuRenameIdentifier, nil, @ExecuteIdeMenuClick);
1796    SrcEditMenuExtractProc := RegisterIDEMenuCommand(AParent,
1797        'ExtractProc', lisMenuExtractProc, nil, @ExecuteIdeMenuClick);
1798    SrcEditMenuShowAbstractMethods := RegisterIDEMenuCommand(AParent,
1799        'ShowAbstractMethods', srkmecAbstractMethods, nil, @ExecuteIdeMenuClick);
1800    SrcEditMenuShowEmptyMethods := RegisterIDEMenuCommand(AParent,
1801        'ShowEmptyMethods', srkmecEmptyMethods, nil, @ExecuteIdeMenuClick);
1802    SrcEditMenuShowUnusedUnits := RegisterIDEMenuCommand(AParent,
1803        'ShowUnusedUnits', srkmecUnusedUnits, nil, @ExecuteIdeMenuClick);
1804    SrcEditMenuFindOverloads := RegisterIDEMenuCommand(AParent,
1805        'FindOverloads', srkmecFindOverloadsCapt, nil, @ExecuteIdeMenuClick);
1806    {$IFnDEF EnableFindOverloads}
1807    SrcEditMenuFindOverloads.Visible := false;
1808    {$ENDIF}
1809    SrcEditMenuMakeResourceString := RegisterIDEMenuCommand(AParent,
1810        'MakeResourceString', lisMenuMakeResourceString, nil, @ExecuteIdeMenuClick);
1811  {%endregion}
1812
1813  SrcEditMenuEditorProperties:=RegisterIDEMenuCommand(SourceEditorMenuRoot,
1814    'EditorProperties', lisMenuGeneralOptions, nil, nil, nil, 'menu_environment_options');
1815end;
1816
1817function dbgSourceNoteBook(snb: TSourceNotebook): string;
1818var
1819  i: Integer;
1820begin
1821  Result:='';
1822  if snb=nil then begin
1823    Result:='nil';
1824  end else if snb.Count=0 then begin
1825    Result:='empty';
1826  end else begin
1827    for i:=0 to 4 do begin
1828      if i>=snb.Count then break;
1829      Result+='"'+ExtractFilename(snb.Items[i].FileName)+'",';
1830    end;
1831  end;
1832  if RightStr(Result,1)=',' then Result:=LeftStr(Result,length(Result)-1);
1833  Result:='['+Result+']';
1834end;
1835
1836function CompareSrcEditIntfWithFilename(SrcEdit1, SrcEdit2: Pointer): integer;
1837var
1838  SE1: TSourceEditorInterface absolute SrcEdit1;
1839  SE2: TSourceEditorInterface absolute SrcEdit2;
1840begin
1841  Result:=CompareFilenames(SE1.FileName,SE2.FileName);
1842end;
1843
1844function CompareFilenameWithSrcEditIntf(FilenameStr, SrcEdit: Pointer): integer;
1845var
1846  SE1: TSourceEditorInterface absolute SrcEdit;
1847begin
1848  Result:=CompareFilenames(AnsiString(FileNameStr),SE1.FileName);
1849end;
1850
1851{ TSourceEditorWordCompletion }
1852
1853constructor TSourceEditorWordCompletion.Create;
1854begin
1855  inherited Create;
1856
1857  FSourceList := TObjectList.Create;
1858  FIncludeWords := icwIncludeFromAllUnits;
1859end;
1860
1861destructor TSourceEditorWordCompletion.Destroy;
1862begin
1863  FSourceList.Free;
1864
1865  inherited Destroy;
1866end;
1867
1868procedure TSourceEditorWordCompletion.DoGetSource(var Source: TStrings;
1869  var TopLine, BottomLine: Integer; var IgnoreWordPos: TPoint;
1870  SourceIndex: integer);
1871var
1872  SourceItem: TSourceListItem;
1873begin
1874  if SourceIndex=0 then
1875    ReloadSourceList;
1876
1877  if SourceIndex>=FSourceList.Count then
1878    Exit;
1879
1880  SourceItem := FSourceList[SourceIndex] as TSourceListItem;
1881  Source := SourceItem.Source;
1882  IgnoreWordPos := SourceItem.IgnoreWordPos;
1883end;
1884
1885procedure TSourceEditorWordCompletion.ReloadSourceList;
1886var
1887  CurEditor, TempEditor: TSourceEditor;
1888  I: integer;
1889  Mng: TSourceEditorManager;
1890  New: TSourceListItem;
1891  AddedFileNames: TStringListUTF8Fast;
1892begin
1893  FSourceList.Clear;
1894  if FIncludeWords=icwDontInclude then
1895    Exit;
1896
1897  Mng := SourceEditorManager;
1898  CurEditor:=Mng.GetActiveSE;
1899  if (CurEditor<>nil) then
1900  begin
1901    New := TSourceListItem.Create;
1902    New.Source:=CurEditor.EditorComponent.Lines;
1903    New.IgnoreWordPos:=CurEditor.EditorComponent.LogicalCaretXY;
1904    Dec(New.IgnoreWordPos.Y); // LogicalCaretXY starts with 1 as top line
1905    FSourceList.Add(New);
1906  end;
1907
1908  if FIncludeWords=icwIncludeFromAllUnits then
1909  begin
1910    AddedFileNames := TStringListUTF8Fast.Create;
1911    try
1912      AddedFileNames.Sorted := True;
1913      AddedFileNames.Duplicates := dupIgnore;
1914      for I := 0 to Mng.SourceEditorCount-1 do
1915      begin
1916        TempEditor := Mng.SourceEditors[I];
1917        if ( TempEditor<>CurEditor)
1918        and (TempEditor.FileName<>CurEditor.FileName)
1919        and (AddedFileNames.IndexOf(TempEditor.FileName)=-1) then
1920        begin
1921          New := TSourceListItem.Create;
1922          New.Source:=TempEditor.EditorComponent.Lines;
1923          New.IgnoreWordPos:=Point(-1,-1);
1924          FSourceList.Add(New);
1925          AddedFileNames.Add(TempEditor.FileName);
1926        end;
1927      end;
1928    finally
1929      AddedFileNames.Free;
1930    end;
1931  end;
1932end;
1933
1934{ TBrowseEditorTabHistoryDialog }
1935
1936procedure TBrowseEditorTabHistoryDialog.DoCreate;
1937begin
1938  inherited DoCreate;
1939
1940  Assert(Owner is TSourceNotebook);
1941  FNotebook := TSourceNotebook(Owner);
1942
1943  Caption := lisCoolbarSourceTab;
1944  BorderIcons:=[];
1945  BorderStyle:=bsSizeable;
1946  KeyPreview := True;
1947
1948  FEditorList := TListBox.Create(Self);
1949  FEditorList.Parent := Self;
1950  FEditorList.Align := alClient;
1951  {$IFDEF MSWINDOWS}//bsNone seems to work on Windows only
1952  FEditorList.BorderStyle := bsNone;
1953  {$ENDIF}
1954end;
1955
1956procedure TBrowseEditorTabHistoryDialog.KeyDown(var Key: Word;
1957  Shift: TShiftState);
1958  function CommandUsed(Command: TIDECommand): Boolean;
1959  begin
1960    Result :=
1961     ((Command.ShortcutA.Key1 = Key) and (Command.ShortcutA.Shift1 = Shift)) or
1962     ((Command.ShortcutA.Key2 = Key) and (Command.ShortcutA.Shift2 = Shift));
1963  end;
1964var
1965  xPrev, xNext: TIDECommand;
1966begin
1967  xPrev := IDECommandList.FindIDECommand(ecPrevEditorInHistory);
1968  if CommandUsed(xPrev) then
1969  begin
1970    MoveInList(True);
1971    Key := 0;
1972  end else
1973  begin
1974    xNext := IDECommandList.FindIDECommand(ecNextEditorInHistory);
1975    if CommandUsed(xNext) then
1976    begin
1977      MoveInList(False);
1978      Key := 0;
1979    end;
1980  end;
1981  inherited KeyDown(Key, Shift);
1982end;
1983
1984procedure TBrowseEditorTabHistoryDialog.MoveInList(aForward: Boolean);
1985begin
1986  if aForward then
1987  begin
1988    if FEditorList.ItemIndex < FEditorList.Items.Count-1 then
1989      FEditorList.ItemIndex := FEditorList.ItemIndex + 1
1990    else
1991      FEditorList.ItemIndex := 0;
1992  end else
1993  begin
1994    if FEditorList.ItemIndex > 0 then
1995      FEditorList.ItemIndex := FEditorList.ItemIndex - 1
1996    else
1997      FEditorList.ItemIndex := FEditorList.Items.Count - 1;
1998  end;
1999end;
2000
2001procedure TBrowseEditorTabHistoryDialog.KeyUp(var Key: Word; Shift: TShiftState);
2002begin
2003  if Key = VK_CONTROL then
2004  begin
2005    Close;
2006    if FEditorList.ItemIndex >= 0 then
2007      FNotebook.PageIndex := TCustomPage(FEditorList.Items.Objects[FEditorList.ItemIndex]).PageIndex;
2008    if (FNotebook.ActiveEditor<>nil) and
2009      FNotebook.ActiveEditor.EditorControl.CanSetFocus
2010    then
2011      FNotebook.ActiveEditor.EditorControl.SetFocus;
2012    Key := 0;
2013  end;
2014
2015  inherited KeyUp(Key, Shift);
2016end;
2017
2018procedure TBrowseEditorTabHistoryDialog.Show(aForward: Boolean);
2019  procedure PlaceMe;
2020  var
2021    xWidth, xHeight: Integer;
2022    xTopLeft, xRightBottom: TPoint;
2023  begin
2024    xWidth := Canvas.TextWidth('m')*20;
2025    if FEditorList.ItemHeight>0 then//ItemHeight can be 0 the first time
2026      xHeight := Min(10, FEditorList.Items.Count)*FEditorList.ItemHeight
2027    else
2028      xHeight := 200;
2029    {$IFNDEF MSWINDOWS}
2030    xHeight := xHeight + GetSystemMetrics(SM_CYBORDER)*2;
2031    {$ENDIF}
2032
2033    xTopLeft := FNotebook.ClientToScreen(Point(0, 0));
2034    xRightBottom := FNotebook.ClientToScreen(FNotebook.ClientRect.BottomRight);
2035    SetBounds(
2036      (xTopLeft.x+xRightBottom.x-xWidth) div 2,
2037      (xTopLeft.y+xRightBottom.y-xHeight) div 2,
2038      xWidth,
2039      xHeight);
2040  end;
2041
2042var
2043  I: Integer;
2044  xPage: TCustomPage;
2045  xIndex: TAvlTree;
2046begin
2047  if FNotebook.PageCount <= 1 then
2048    Exit;
2049
2050  FEditorList.Items.BeginUpdate;
2051  xIndex := TAvlTree.Create;
2052  try
2053    FEditorList.Items.Clear;
2054    for I := 0 to FNotebook.FHistoryList.Count-1 do
2055    begin
2056      xPage := TCustomPage(FNotebook.FHistoryList[I]);
2057      FEditorList.Items.AddObject(xPage.Caption, xPage);
2058      xIndex.Add(xPage);
2059    end;
2060
2061    //add pages not in history to the right of the active page
2062    for I := FNotebook.PageIndex+1 to FNotebook.PageCount-1 do
2063    begin
2064      xPage := FNotebook.NoteBookPage[I];
2065      if xIndex.Find(xPage)=nil then
2066        FEditorList.Items.AddObject(xPage.Caption, xPage);
2067    end;
2068    //add pages not in history to the left of the active page
2069    for I := 0 to FNotebook.PageIndex-1 do
2070    begin
2071      xPage := FNotebook.NoteBookPage[I];
2072      if xIndex.Find(xPage)=nil then
2073        FEditorList.Items.AddObject(xPage.Caption, xPage);
2074    end;
2075  finally
2076    xIndex.Free;
2077    FEditorList.Items.EndUpdate;
2078  end;
2079
2080  if aForward then
2081    FEditorList.ItemIndex := 1
2082  else
2083    FEditorList.ItemIndex := FEditorList.Count-1;
2084
2085  PlaceMe;
2086  Visible := True;
2087  PlaceMe;
2088  BringToFront;
2089end;
2090
2091{ TSourceEditorHintWindowManager }
2092
2093procedure TSourceEditorHintWindowManager.ActivateHint(const ScreenPos: TPoint;
2094  const ABaseURL, AHint: string; AAutoShown: Boolean; AMouseOffset: Boolean);
2095begin
2096  ActivateHint(Rect(ScreenPos.x, ScreenPos.y, ScreenPos.x, ScreenPos.y), ABaseURL, AHint, AAutoShown, AMouseOffset);
2097end;
2098
2099procedure TSourceEditorHintWindowManager.ActivateHint(const ScreenRect: TRect;
2100  const ABaseURL, AHint: string; AAutoShown: Boolean; AMouseOffset: Boolean);
2101begin
2102  FAutoShown := AAutoShown;
2103  BaseURL := ABaseURL;
2104  FLastHint := AHint;
2105  FScreenRect := ScreenRect;
2106  if AAutoShown then
2107  begin
2108    FAutoHintMousePos := Mouse.CursorPos;
2109    if not(HintIsVisible and (FLastHint = AHint)) then
2110      ShowHint(Point(ScreenRect.Left, ScreenRect.Bottom),AHint,AMouseOffset);
2111  end else
2112  begin
2113    if HintIsVisible and (FLastHint = AHint) then
2114      HideIfVisible
2115    else
2116      ShowHint(Point(ScreenRect.Left, ScreenRect.Bottom),AHint,AMouseOffset);
2117  end;
2118  FAutoHideHintTimer.Enabled := AAutoShown;
2119end;
2120
2121constructor TSourceEditorHintWindowManager.Create(AManager: TSourceEditorManager);
2122begin
2123  inherited Create;
2124
2125  FManager := AManager;
2126  // HintTimer
2127  FAutoHintTimer := TIdleTimer.Create(nil);
2128  with FAutoHintTimer do begin
2129    Interval := EditorOpts.AutoHintDelayInMSec;
2130    Enabled := False;
2131    AutoEnabled := False;
2132    OnTimer := @HintTimer;
2133  end;
2134  // Track mouse movements outside the IDE, if hint is visible
2135  FAutoHideHintTimer := TTimer.Create(nil);
2136  with FAutoHideHintTimer do begin
2137    Interval := 500;
2138    Enabled := False;
2139    OnTimer := @HideHintTimer;
2140  end;
2141end;
2142
2143destructor TSourceEditorHintWindowManager.Destroy;
2144begin
2145  FAutoHintTimer.Free;
2146  FAutoHideHintTimer.Free;
2147
2148  inherited Destroy;
2149end;
2150
2151procedure TSourceEditorHintWindowManager.HideAutoHint;
2152begin
2153  if FAutoHintTimer<>nil then
2154  begin
2155    FAutoHintTimer.AutoEnabled := false;
2156    FAutoHintTimer.Enabled:=false;
2157  end;
2158  if FAutoHideHintTimer <> nil then
2159    FAutoHideHintTimer.Enabled := False;
2160  if AutoStartCompletionBoxTimer<>nil then
2161    AutoStartCompletionBoxTimer.Enabled:=false;
2162  if (FManager.ActiveEditor <> nil) and
2163     (FManager.ActiveEditor.FCodeCompletionState.State in [ccsDot, ccsOnTyping])
2164  then
2165    FManager.ActiveEditor.FCodeCompletionState.State := ccsReady;
2166  if FAutoShown then
2167    HideHint;
2168end;
2169
2170procedure TSourceEditorHintWindowManager.HideHintTimer(Sender: TObject);
2171begin
2172  if HintIsVisible and FAutoShown then begin
2173    if ComparePoints(FAutoHintMousePos, Mouse.CursorPos) <> 0 then begin
2174      // TODO: introduce property, to indicate if hint is interactive
2175      if HintIsComplex or not IsRectEmpty(FScreenRect) then
2176        HideAutoHintAfterMouseMoved
2177      else
2178        HideAutoHint;
2179    end;
2180  end
2181  else
2182    FAutoHideHintTimer.Enabled := false;
2183end;
2184
2185procedure TSourceEditorHintWindowManager.HintTimer(Sender: TObject);
2186var
2187  MousePos: TPoint;
2188  AControl: TControl;
2189begin
2190  FAutoHintTimer.Enabled := False;
2191  FAutoHintTimer.AutoEnabled := False;
2192  if not FManager.ActiveSourceWindow.IsVisible then exit;
2193  MousePos := Mouse.CursorPos;
2194  AControl:=FindLCLControl(MousePos);
2195  if (AControl=nil) or (not FManager.ActiveSourceWindow.ContainsControl(AControl)) then exit;
2196  if AControl is TSynEdit then
2197    FManager.ActiveSourceWindow.ShowSynEditHint(MousePos);
2198end;
2199
2200procedure TSourceEditorHintWindowManager.HideAutoHintAfterMouseMoved;
2201const
2202  MaxJitter = 3;
2203var
2204  Cur: TPoint;
2205  OkX, OkY: Boolean;
2206  hw: THintWindow;
2207begin
2208  if HintIsVisible and not FAutoShown then Exit;
2209  FAutoHideHintTimer.Enabled := False;
2210  if HintIsVisible then begin
2211    Cur := Mouse.CursorPos; // Desktop coordinates
2212    if (not IsRectEmpty(FScreenRect)) then
2213    begin
2214      // Do not close, if mouse still over the same word, that triggered the hint
2215      if PtInRect(FScreenRect, Cur) then
2216        Exit;
2217    end else
2218    begin
2219      // Fallback if FScreenRect is empty (for legacy calls)
2220      hw := CurHintWindow;
2221      OkX := ( (FAutoHintMousePos.x <= hw.Left) and
2222               (Cur.x > FAutoHintMousePos.x) and (Cur.x <= hw.Left + hw.Width)
2223             ) or
2224             ( (FAutoHintMousePos.x >= hw.Left + hw.Width) and
2225               (Cur.x < FAutoHintMousePos.x) and (Cur.x >= hw.Left)
2226             ) or
2227             ( (Cur.x >= hw.Left) and (Cur.x <= hw.Left + hw.Width) );
2228      OkY := ( (FAutoHintMousePos.y <= hw.Top) and
2229               (Cur.y > FAutoHintMousePos.y) and (Cur.y <= hw.Top + hw.Height)
2230             ) or
2231             ( (FAutoHintMousePos.y >= hw.Top + hw.Height) and
2232               (Cur.y < FAutoHintMousePos.y) and (Cur.y >= hw.Top)
2233             ) or
2234             ( (Cur.y >= hw.Top) and (Cur.y <= hw.Top + hw.Height) );
2235
2236      if OkX then FAutoHintMousePos.x := Cur.x;
2237      if OkY then FAutoHintMousePos.y := Cur.y;
2238
2239      OkX := OkX or
2240             ( (FAutoHintMousePos.x <= hw.Left + MaxJitter) and
2241               (Cur.x > FAutoHintMousePos.x - MaxJitter) and (Cur.x <= hw.Left + hw.Width + MaxJitter)
2242             ) or
2243             ( (FAutoHintMousePos.x >= hw.Left + hw.Width - MaxJitter) and
2244               (Cur.x < FAutoHintMousePos.x + MaxJitter) and (Cur.x >= hw.Left - MaxJitter)
2245             );
2246      OkY := OkY or
2247             ( (FAutoHintMousePos.y <= hw.Top + MaxJitter) and
2248               (Cur.y > FAutoHintMousePos.y - MaxJitter) and (Cur.y <= hw.Top + hw.Height + MaxJitter)
2249             ) or
2250             ( (FAutoHintMousePos.y >= hw.Top + hw.Height - MaxJitter) and
2251               (Cur.y < FAutoHintMousePos.y + MaxJitter) and (Cur.y >= hw.Top - MaxJitter)
2252             );
2253
2254      if (OkX and OkY) then begin
2255        FAutoHideHintTimer.Enabled := True;
2256        exit;
2257      end;
2258    end;
2259  end;
2260  HideHint;
2261end;
2262
2263procedure TSourceEditorHintWindowManager.UpdateHintTimer;
2264begin
2265  with EditorOpts do
2266    if (MainIDEInterface.ToolStatus=itDebugger) then
2267      FAutoHintTimer.AutoEnabled := AutoToolTipExprEval or AutoToolTipSymbTools
2268    else
2269      FAutoHintTimer.AutoEnabled := AutoToolTipSymbTools;
2270end;
2271
2272
2273{ TSourceEditCompletion }
2274
2275procedure TSourceEditCompletion.CompletionFormResized(Sender: TObject);
2276begin
2277  EnvironmentOptions.Desktop.CompletionWindowWidth  := TheForm.Width;
2278  EnvironmentOptions.Desktop.CompletionWindowHeight := TheForm.NbLinesInWindow;
2279end;
2280
2281function TSourceEditCompletion.GetCompletionFormClass: TSynBaseCompletionFormClass;
2282begin
2283  Result := TSourceEditCompletionForm;
2284end;
2285
2286procedure TSourceEditCompletion.ccExecute(Sender: TObject);
2287// init completion form
2288// called by OnExecute just before showing
2289var
2290  SL: TStrings;
2291  Prefix: String;
2292  I: Integer;
2293  NewStr: String;
2294  SynEditor: TIDESynEditor;
2295Begin
2296  {$IFDEF VerboseIDECompletionBox}
2297  debugln(['TSourceEditCompletion.ccExecute START']);
2298  {$ENDIF}
2299  TheForm.Font := Editor.Font;
2300
2301  FActiveEditTextColor := Editor.Font.Color;
2302  FActiveEditBorderColor := RGBToColor(200, 200, 200);
2303  FActiveEditBackgroundColor := Editor.Color;
2304  FActiveEditTextSelectedColor := TSynEdit(Editor).SelectedColor.Foreground;
2305  FActiveEditBackgroundSelectedColor := TSynEdit(Editor).SelectedColor.Background;
2306  FActiveEditTextHighLightColor := clNone;
2307
2308  if Editor.Highlighter<>nil
2309  then begin
2310    with Editor.Highlighter do begin
2311      if IdentifierAttribute<>nil
2312      then begin
2313        if IdentifierAttribute.ForeGround<>clNone then
2314          FActiveEditTextColor:=IdentifierAttribute.ForeGround;
2315        if IdentifierAttribute.BackGround<>clNone then
2316          FActiveEditBackgroundColor:=IdentifierAttribute.BackGround;
2317      end;
2318    end;
2319  end;
2320
2321  if Editor is TIDESynEditor then
2322  begin
2323    SynEditor := TIDESynEditor(Editor);
2324    if SynEditor.MarkupIdentComplWindow.TextColor<>clNone then
2325      FActiveEditTextColor := SynEditor.MarkupIdentComplWindow.TextColor;
2326    if SynEditor.MarkupIdentComplWindow.BorderColor<>clNone then
2327      FActiveEditBorderColor := SynEditor.MarkupIdentComplWindow.BorderColor;
2328    if SynEditor.MarkupIdentComplWindow.WindowColor<>clNone then
2329      FActiveEditBackgroundColor := SynEditor.MarkupIdentComplWindow.WindowColor;
2330    if SynEditor.MarkupIdentComplWindow.TextSelectedColor<>clNone then
2331      FActiveEditTextSelectedColor := SynEditor.MarkupIdentComplWindow.TextSelectedColor;
2332    if SynEditor.MarkupIdentComplWindow.BackgroundSelectedColor<>clNone then
2333      FActiveEditBackgroundSelectedColor := SynEditor.MarkupIdentComplWindow.BackgroundSelectedColor;
2334    if SynEditor.MarkupIdentComplWindow.HighlightColor<>clNone then
2335      FActiveEditTextHighLightColor := SynEditor.MarkupIdentComplWindow.HighlightColor;
2336  end;
2337
2338  SL := TStringList.Create;
2339  try
2340    Prefix := CurrentString;
2341    case CurrentCompletionType of
2342     ctIdentCompletion:
2343       if InitIdentCompletionValues(SL) then begin
2344         ToggleReplaceWhole:=not CodeToolsOpts.IdentComplReplaceIdentifier;
2345       end else begin
2346         ItemList.Clear;
2347         exit;
2348       end;
2349
2350     ctWordCompletion:
2351       begin
2352         ToggleReplaceWhole:=not CodeToolsOpts.IdentComplReplaceIdentifier;
2353         ccSelection := '';
2354       end;
2355
2356     ctTemplateCompletion:
2357       begin
2358         ccSelection:='';
2359         for I := 0 to Manager.CodeTemplateModul.Completions.Count-1 do begin
2360           NewStr := Manager.CodeTemplateModul.Completions[I];
2361           if NewStr<>'' then begin
2362             NewStr:=#3'B'+NewStr+#3'b';
2363             while length(NewStr)<10+4 do NewStr:=NewStr+' ';
2364             NewStr:=NewStr+' '+Manager.CodeTemplateModul.CompletionComments[I];
2365             SL.Add(NewStr);
2366           end;
2367         end;
2368       end;
2369
2370    end;
2371
2372    ItemList := SL;
2373  finally
2374    SL.Free;
2375  end;
2376  CurrentString:=Prefix;
2377  // set colors
2378  if (Editor<>nil) and (TheForm<>nil) then begin
2379    with TheForm as TSourceEditCompletionForm do begin
2380      DrawBorderColor   := FActiveEditBorderColor;
2381      BackgroundColor   := FActiveEditBackgroundColor;
2382      clSelect          := FActiveEditBackgroundSelectedColor;
2383      TextColor         := FActiveEditTextColor;
2384      TextSelectedColor := FActiveEditTextSelectedColor;
2385      TextHighLightColor:= FActiveEditTextHighLightColor;
2386      //debugln('TSourceEditCompletion.ccExecute A Color=',DbgS(Color),
2387      // ' clSelect=',DbgS(clSelect),
2388      // ' TextColor=',DbgS(TextColor),
2389      // ' TextSelectedColor=',DbgS(TextSelectedColor),
2390      // '');
2391    end;
2392    debugln(['TSourceEditCompletion.ccExecute ',DbgSName(SourceEditorManager.ActiveCompletionPlugin)]);
2393    if (CurrentCompletionType=ctIdentCompletion)
2394    and (SourceEditorManager.ActiveCompletionPlugin=nil)
2395    then
2396      StartShowCodeHelp
2397    else if SrcEditHintWindow<>nil then
2398    begin
2399      SrcEditHintWindow.HelpEnabled:=false;
2400      TheForm.LongLineHintType := EditorOpts.CompletionLongLineHintType;
2401    end;
2402  end;
2403end;
2404
2405procedure TSourceEditCompletion.ccCancel(Sender: TObject);
2406// user cancels completion form
2407begin
2408  {$IFDEF VerboseIDECompletionBox}
2409  DebugLnEnter(['TSourceNotebook.ccCancel START']);
2410  try
2411  //debugln(GetStackTrace(true));
2412  {$ENDIF}
2413  Manager.DeactivateCompletionForm;
2414  {$IFDEF VerboseIDECompletionBox}
2415  finally
2416    DebugLnExit(['TSourceNotebook.ccCancel END']);
2417  end;
2418  //debugln(GetStackTrace(true));
2419  {$ENDIF}
2420
2421  with Manager.ActiveEditor do begin
2422    FCodeCompletionState.LastTokenStartPos := CurrentWordLogStartOrCaret;
2423    FCodeCompletionState.State := ccsCancelled;
2424  end;
2425end;
2426
2427procedure TSourceEditCompletion.ccComplete(var Value: string;
2428  SourceValue: string; var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char;
2429  Shift: TShiftState);
2430// completion selected -> deactivate completion form
2431// Called when user has selected a completion item
2432
2433  function CharBehindIdent(const Line: string; StartPos: integer): char;
2434  begin
2435    while (StartPos<=length(Line))
2436    and (Line[StartPos] in ['_','A'..'Z','a'..'z']) do
2437      inc(StartPos);
2438    while (StartPos<=length(Line)) and (Line[StartPos] in [' ',#9]) do
2439      inc(StartPos);
2440    if StartPos<=length(Line) then
2441      Result:=Line[StartPos]
2442    else
2443      Result:=#0;
2444  end;
2445
2446  function CharInFrontOfIdent(const Line: string; StartPos: integer): char;
2447  begin
2448    while (StartPos>=1)
2449    and (Line[StartPos] in ['_','A'..'Z','a'..'z']) do
2450      dec(StartPos);
2451    while (StartPos>=1) and (Line[StartPos] in [' ',#9]) do
2452      dec(StartPos);
2453    if StartPos>=1 then
2454      Result:=Line[StartPos]
2455    else
2456      Result:=#0;
2457  end;
2458
2459var
2460  p1, p2: integer;
2461  ValueType: TIdentComplValue;
2462  NewCaretXY: TPoint;
2463  CursorToLeft: integer;
2464  NewValue: String;
2465  OldCompletionType: TCompletionType;
2466  prototypeAdded: boolean;
2467  SourceNoteBook: TSourceNotebook;
2468  IdentItem: TIdentifierListItem;
2469Begin
2470  {$IFDEF VerboseIDECompletionBox}
2471  DebugLnEnter(['TSourceNotebook.ccComplete START']);
2472  try
2473  {$ENDIF}
2474  prototypeAdded := false;
2475  OldCompletionType:=CurrentCompletionType;
2476  case CurrentCompletionType of
2477
2478    ctIdentCompletion:
2479      begin
2480        if Manager.ActiveCompletionPlugin<>nil then
2481        begin
2482          Manager.ActiveCompletionPlugin.Complete(Value,SourceValue,
2483             SourceStart,SourceEnd,KeyChar,Shift);
2484          Manager.FActiveCompletionPlugin:=nil;
2485        end else begin
2486          IdentItem:=CodeToolBoss.IdentifierList.FilteredItems[Position];
2487          // add to history
2488          CodeToolBoss.IdentifierHistory.Add(IdentItem);
2489          if IdentItem is TCodeTemplateIdentifierListItem then
2490          begin
2491            if IdentItem.Identifier<>'' then
2492              Manager.CodeTemplateModul.ExecuteCompletion(IdentItem.Identifier, Editor);
2493          end else
2494          begin
2495            // get value
2496            NewValue:=GetIdentCompletionValue(Self, KeyChar, ValueType, CursorToLeft);
2497            if ValueType=icvIdentifier then ;
2498            // insert value plus special chars like brackets, semicolons, ...
2499            if ValueType <> icvNone then
2500              Editor.TextBetweenPointsEx[SourceStart, SourceEnd, scamEnd] := NewValue;
2501            if ValueType in [icvProcWithParams,icvIndexedProp] then
2502              prototypeAdded := true;
2503            if CursorToLeft>0 then
2504            begin
2505              NewCaretXY:=Editor.CaretXY;
2506              dec(NewCaretXY.X,CursorToLeft);
2507              Editor.CaretXY:=NewCaretXY;
2508            end;
2509          end;
2510          ccSelection := '';
2511          Value:='';
2512          SourceEnd := SourceStart;
2513        end;
2514      end;
2515
2516    ctTemplateCompletion:
2517      begin
2518        // the completion is the bold text between #3'B' and #3'b'
2519        p1:=Pos(#3,Value);
2520        if p1>=0 then begin
2521          p2:=p1+2;
2522          while (p2<=length(Value)) and (Value[p2]<>#3) do inc(p2);
2523          Value:=copy(Value,p1+2,p2-p1-2);
2524          // keep parent identifier (in front of '.')
2525          p1:=length(ccSelection);
2526          while (p1>=1) and (ccSelection[p1]<>'.') do dec(p1);
2527          if p1>=1 then
2528            Value:=copy(ccSelection,1,p1)+Value;
2529        end;
2530        ccSelection := '';
2531        if Value<>'' then
2532          Manager.CodeTemplateModul.ExecuteCompletion(Value, Editor);
2533        SourceEnd := SourceStart;
2534        Value:='';
2535      end;
2536
2537    ctWordCompletion:
2538      // the completion is already in Value
2539      begin
2540        ccSelection := '';
2541        if Value<>'' then AWordCompletion.AddWord(Value);
2542      end;
2543
2544    else begin
2545      Value:='';
2546    end;
2547  end;
2548
2549  Manager.DeactivateCompletionForm;
2550
2551  //DebugLn(['TSourceNotebook.ccComplete ',KeyChar,' ',OldCompletionType=ctIdentCompletion]);
2552  Manager.ActiveEditor.FCodeCompletionState.State := ccsReady;
2553  if (KeyChar='.') and (OldCompletionType=ctIdentCompletion) then
2554  begin
2555    SourceCompletionCaretXY:=Editor.LogicalCaretXY;
2556    AutoStartCompletionBoxTimer.AutoEnabled:=true;
2557    Manager.ActiveEditor.FCodeCompletionState.State := ccsDot;
2558  end
2559  else if prototypeAdded and EditorOpts.AutoDisplayFunctionPrototypes then
2560  begin
2561     if Editor.Owner is TSourceNoteBook then
2562     begin
2563        SourceNoteBook := Editor.Owner as TSourceNoteBook;
2564        SourceNotebook.StartShowCodeContext(CodeToolsOpts.IdentComplJumpToError);
2565     end;
2566  end;
2567
2568  {$IFDEF VerboseIDECompletionBox}
2569  finally
2570    DebugLnExit(['TSourceNotebook.ccComplete END']);
2571  end;
2572  {$ENDIF}
2573end;
2574
2575function TSourceEditCompletion.OnSynCompletionPaintItem(const AKey: string;
2576  ACanvas: TCanvas; X, Y: integer; ItemSelected: boolean; Index: integer): boolean;
2577var
2578  MaxX: Integer;
2579  t: TCompletionType;
2580  hl: TSynCustomHighlighter;
2581  Colors: TPaintCompletionItemColors;
2582begin
2583  try
2584    with ACanvas do begin
2585      if (Editor<>nil) then
2586        Font := Editor.Font
2587      else begin
2588        Font.Size:=EditorOpts.EditorFontSize; // set Size before name for XLFD !
2589        Font.Name:=EditorOpts.EditorFont;
2590      end;
2591      Font.Style:=[];
2592    end;
2593    Colors.BackgroundColor := FActiveEditBackgroundColor;
2594    Colors.BackgroundSelectedColor := FActiveEditBackgroundSelectedColor;
2595    Colors.TextColor := FActiveEditTextColor;
2596    Colors.TextSelectedColor := FActiveEditTextSelectedColor;
2597    Colors.TextHilightColor := FActiveEditTextHighLightColor;
2598    MaxX:=TheForm.ClientWidth;
2599    t:=CurrentCompletionType;
2600    if Manager.ActiveCompletionPlugin<>nil then
2601    begin
2602      if Manager.ActiveCompletionPlugin.HasCustomPaint then
2603      begin
2604        Manager.ActiveCompletionPlugin.PaintItem(AKey,ACanvas,X,Y,ItemSelected,Index);
2605      end else begin
2606        t:=ctWordCompletion;
2607      end;
2608    end;
2609    hl := nil;
2610    if Editor <> nil then
2611      hl := Editor.Highlighter;
2612    PaintCompletionItem(AKey, ACanvas, X, Y, MaxX, ItemSelected, Index, self, t, hl, @Colors);
2613    Result:=true;
2614  except
2615    DebugLn('OnSynCompletionPaintItem failed');
2616    DumpStack;
2617    Result := false;
2618  end;
2619end;
2620
2621function TSourceEditCompletion.OnSynCompletionMeasureItem(const AKey: string;
2622  ACanvas: TCanvas; ItemSelected: boolean; Index: integer): TPoint;
2623var
2624  MaxX: Integer;
2625  t: TCompletionType;
2626begin
2627  try
2628  with ACanvas do begin
2629    if (Editor<>nil) then
2630      Font:=Editor.Font
2631    else begin
2632      Font.Size:=EditorOpts.EditorFontSize; // set Size before name of XLFD !
2633      Font.Name:=EditorOpts.EditorFont;
2634    end;
2635    Font.Style:=[];
2636  end;
2637  MaxX := Screen.Width-20;
2638  t:=CurrentCompletionType;
2639  if Manager.ActiveCompletionPlugin<>nil then
2640  begin
2641    if Manager.ActiveCompletionPlugin.HasCustomPaint then
2642    begin
2643      Manager.ActiveCompletionPlugin.MeasureItem(AKey,ACanvas,ItemSelected,Index);
2644    end else begin
2645      t:=ctWordCompletion;
2646    end;
2647  end;
2648  Result := PaintCompletionItem(AKey,ACanvas,0,0,MaxX,ItemSelected,Index,
2649                                self,t,nil,nil,True);
2650  Result.Y:=FontHeight;
2651  except
2652    DebugLn('OnSynCompletionMeasureItem failed');
2653    DumpStack;
2654    Result := Point(FontHeight * length(AKey), FontHeight);
2655  end;
2656end;
2657
2658procedure TSourceEditCompletion.OnSynCompletionSearchPosition(
2659  var APosition: integer);
2660// prefix changed -> filter list
2661var
2662  i,x:integer;
2663  CurStr,s:Ansistring;
2664  SL: TStrings;
2665  ItemCnt: Integer;
2666begin
2667  case CurrentCompletionType of
2668
2669    ctIdentCompletion:
2670      if Manager.ActiveCompletionPlugin<>nil then
2671      begin
2672        // let plugin rebuild completion list
2673        SL:=TStringList.Create;
2674        try
2675          Manager.ActiveCompletionPlugin.PrefixChanged(CurrentString,APosition,sl);
2676          ItemList:=SL;
2677        finally
2678          SL.Free;
2679        end;
2680      end else begin
2681        // rebuild completion list
2682        APosition:=0;
2683        CurStr:=CurrentString;
2684        CodeToolBoss.IdentifierList.ContainsFilter := CodeToolsOpts.IdentComplUseContainsFilter;
2685        CodeToolBoss.IdentifierList.Prefix:=CurStr;
2686        ItemCnt:=CodeToolBoss.IdentifierList.GetFilteredCount;
2687        SL:=TStringList.Create;
2688        try
2689          sl.Capacity:=ItemCnt;
2690          for i:=0 to ItemCnt-1 do
2691            SL.Add('Dummy'); // these entries are not shown
2692          ItemList:=SL;
2693        finally
2694          SL.Free;
2695        end;
2696      end;
2697
2698    ctTemplateCompletion:
2699      begin
2700        // search CurrentString in bold words (words after #3'B')
2701        CurStr:=CurrentString;
2702        i:=0;
2703        while i<ItemList.Count do begin
2704          s:=ItemList[i];
2705          x:=1;
2706          while (x<=length(s)) and (s[x]<>#3) do inc(x);
2707          if x<length(s) then begin
2708            inc(x,2);
2709            if UTF8CompareLatinTextFast(CurStr,copy(s,x,length(CurStr)))=0 then begin
2710              APosition:=i;
2711              break;
2712            end;
2713          end;
2714          inc(i);
2715        end;
2716      end;
2717
2718    ctWordCompletion:
2719      begin
2720        // rebuild completion list
2721        APosition:=0;
2722        CurStr:=CurrentString;
2723        SL:=TStringList.Create;
2724        try
2725          aWordCompletion.GetWordList(SL, CurStr, CodeToolBoss.IdentifierList.ContainsFilter, false, 100);
2726          ItemList:=SL;
2727        finally
2728          SL.Free;
2729        end;
2730      end;
2731
2732  end;
2733  if SrcEditHintWindow<>nil then
2734    SrcEditHintWindow.UpdateHints;
2735end;
2736
2737procedure TSourceEditCompletion.OnSynCompletionCompletePrefix(Sender: TObject);
2738var
2739  OldPrefix: String;
2740  NewPrefix: String;
2741  SL: TStringList;
2742  AddPrefix: String;
2743begin
2744  OldPrefix:=CurrentString;
2745  NewPrefix:=OldPrefix;
2746
2747  case CurrentCompletionType of
2748
2749  ctIdentCompletion:
2750    if Manager.ActiveCompletionPlugin<>nil then
2751    begin
2752      Manager.ActiveCompletionPlugin.CompletePrefix(NewPrefix);
2753    end else begin
2754      NewPrefix:=CodeToolBoss.IdentifierList.CompletePrefix(OldPrefix);
2755    end;
2756
2757  ctWordCompletion:
2758    begin
2759      aWordCompletion.CompletePrefix(OldPrefix,NewPrefix,false);
2760    end;
2761
2762  end;
2763
2764  if NewPrefix<>OldPrefix then begin
2765    AddPrefix:=copy(NewPrefix,length(OldPrefix)+1,length(NewPrefix));
2766    Editor.InsertTextAtCaret(AddPrefix);
2767    if CurrentCompletionType=ctWordCompletion then begin
2768      SL:=TStringList.Create;
2769      try
2770        aWordCompletion.GetWordList(SL, NewPrefix, CodeToolBoss.IdentifierList.ContainsFilter, false, 100);
2771        ItemList:=SL;
2772      finally
2773        SL.Free;
2774      end;
2775    end;
2776    CurrentString:=NewPrefix;
2777  end;
2778end;
2779
2780procedure TSourceEditCompletion.OnSynCompletionNextChar(Sender: TObject);
2781var
2782  NewPrefix: String;
2783  Line: String;
2784  LogCaret: TPoint;
2785  CharLen: LongInt;
2786  AddPrefix: String;
2787begin
2788  if Editor=nil then exit;
2789  LogCaret:=Editor.LogicalCaretXY;
2790  if LogCaret.Y>=Editor.Lines.Count then exit;
2791  Line:=Editor.Lines[LogCaret.Y-1];
2792  if LogCaret.X>length(Line) then exit;
2793  CharLen:=UTF8CodepointSize(@Line[LogCaret.X]);
2794  AddPrefix:=copy(Line,LogCaret.X,CharLen);
2795  if not Editor.IsIdentChar(AddPrefix) then exit;
2796  NewPrefix:=CurrentString+AddPrefix;
2797  //debugln('TSourceNotebook.OnSynCompletionNextChar NewPrefix="',NewPrefix,'" LogCaret.X=',dbgs(LogCaret.X));
2798  inc(LogCaret.X);
2799  Editor.LogicalCaretXY:=LogCaret;
2800  CurrentString:=NewPrefix;
2801end;
2802
2803procedure TSourceEditCompletion.OnSynCompletionPrevChar(Sender: TObject);
2804var
2805  NewPrefix: String;
2806  NewLen: LongInt;
2807begin
2808  NewPrefix:=CurrentString;
2809  if NewPrefix='' then exit;
2810  if Editor=nil then exit;
2811  Editor.CaretX:=Editor.CaretX-1;
2812  NewLen:=UTF8FindNearestCharStart(PChar(NewPrefix),length(NewPrefix),
2813                                   length(NewPrefix)-1);
2814  NewPrefix:=copy(NewPrefix,1,NewLen);
2815  CurrentString:=NewPrefix;
2816end;
2817
2818procedure TSourceEditCompletion.OnSynCompletionKeyPress(Sender: TObject;
2819  var Key: Char);
2820begin
2821  if (System.Pos(Key,EndOfTokenChr)>0) then begin
2822    // identifier completed
2823    //debugln('TSourceNotebook.OnSynCompletionKeyPress A');
2824    TheForm.OnValidate(Sender,Key,[]);
2825    //debugln('TSourceNotebook.OnSynCompletionKeyPress B');
2826    Key:=#0;
2827  end;
2828end;
2829
2830procedure TSourceEditCompletion.OnSynCompletionUTF8KeyPress(Sender: TObject;
2831  var UTF8Key: TUTF8Char);
2832begin
2833  if (length(UTF8Key)=1)
2834  and (System.Pos(UTF8Key[1],EndOfTokenChr)>0) then begin
2835    // identifier completed
2836    //debugln('TSourceNotebook.OnSynCompletionUTF8KeyPress A');
2837    TheForm.OnValidate(Sender,UTF8Key,[]);
2838    //debugln('TSourceNotebook.OnSynCompletionKeyPress B');
2839    UTF8Key:='';
2840  end;
2841  //debugln('TSourceNotebook.OnSynCompletionKeyPress B UTF8Key=',dbgstr(UTF8Key));
2842end;
2843
2844procedure TSourceEditCompletion.OnSynCompletionPositionChanged(Sender: TObject);
2845begin
2846  if Manager.ActiveCompletionPlugin<>nil then
2847    Manager.ActiveCompletionPlugin.IndexChanged(Position);
2848  if SrcEditHintWindow<>nil then
2849    SrcEditHintWindow.UpdateHints;
2850end;
2851
2852function TSourceEditCompletion.InitIdentCompletionValues(S: TStrings): boolean;
2853var
2854  i: integer;
2855  Handled: boolean;
2856  Abort: boolean;
2857  Prefix: string;
2858  ItemCnt: Integer;
2859begin
2860  Result:=false;
2861  Prefix := CurrentString;
2862  if Manager.ActiveCompletionPlugin<>nil then
2863  begin
2864    Result := Manager.ActiveCompletionPlugin.Collect(S);
2865  end
2866  else if Assigned(Manager.OnInitIdentCompletion) then
2867  begin
2868    Manager.OnInitIdentCompletion(Self, FIdentCompletionJumpToError, Handled, Abort);
2869    if Handled then begin
2870      if Abort then exit;
2871      // add one entry per item
2872      CodeToolBoss.IdentifierList.Prefix:=Prefix;
2873      ItemCnt:=CodeToolBoss.IdentifierList.GetFilteredCount;
2874      //DebugLn('InitIdentCompletion B Prefix=',Prefix,' ItemCnt=',IntToStr(ItemCnt));
2875      Position:=0;
2876      for i:=0 to ItemCnt-1 do
2877        s.Add('Dummy');
2878      Result:=true;
2879      exit;
2880    end;
2881  end;
2882end;
2883
2884procedure TSourceEditCompletion.StartShowCodeHelp;
2885begin
2886  if SrcEditHintWindow = nil then begin
2887    SrcEditHintWindow := TSrcEditHintWindow.Create(Manager);
2888    SrcEditHintWindow.Name:='TSourceNotebook_SrcEditHintWindow';
2889    SrcEditHintWindow.Provider:=TFPDocHintProvider.Create(SrcEditHintWindow);
2890  end;
2891  SrcEditHintWindow.AnchorForm := TheForm;
2892  //debugln(['TSourceEditCompletion.StartShowCodeHelp ',CodeToolsOpts.IdentComplShowHelp]);
2893  if CodeToolsOpts.IdentComplShowHelp then begin
2894    TheForm.LongLineHintType:=sclpNone;
2895    SrcEditHintWindow.HelpEnabled:=true;
2896  end else begin
2897    TheForm.LongLineHintType:=EditorOpts.CompletionLongLineHintType;
2898    SrcEditHintWindow.HelpEnabled:=false;
2899  end;
2900end;
2901
2902function TSourceEditCompletion.Manager: TSourceEditorManager;
2903begin
2904  Result := SourceEditorManager;
2905end;
2906
2907constructor TSourceEditCompletion.Create(AOwner: TComponent);
2908begin
2909  inherited;
2910  EndOfTokenChr:='()[].,;:-+=^*<>/';
2911  Width:=400;
2912  OnExecute := @ccExecute;
2913  OnCancel := @ccCancel;
2914  OnCodeCompletion := @ccComplete;
2915  OnPaintItem:=@OnSynCompletionPaintItem;
2916  OnMeasureItem := @OnSynCompletionMeasureItem;
2917  OnSearchPosition:=@OnSynCompletionSearchPosition;
2918  OnKeyCompletePrefix:=@OnSynCompletionCompletePrefix;
2919  OnKeyNextChar:=@OnSynCompletionNextChar;
2920  OnKeyPrevChar:=@OnSynCompletionPrevChar;
2921  OnKeyPress:=@OnSynCompletionKeyPress;
2922  OnUTF8KeyPress:=@OnSynCompletionUTF8KeyPress;
2923  OnPositionChanged:=@OnSynCompletionPositionChanged;
2924  ShortCut:=Menus.ShortCut(VK_UNKNOWN,[]);
2925  TheForm.ShowSizeDrag := True;
2926  TheForm.Width := Max(50, EnvironmentOptions.Desktop.CompletionWindowWidth);
2927  TheForm.NbLinesInWindow := Max(3, EnvironmentOptions.Desktop.CompletionWindowHeight);
2928  TheForm.OnDragResized  := @CompletionFormResized;
2929end;
2930
2931{ TSourceEditorSharedValues }
2932
2933function TSourceEditorSharedValues.GetSharedEditors(Index: Integer): TSourceEditor;
2934begin
2935  Result := TSourceEditor(FSharedEditorList[Index]);
2936end;
2937
2938function TSourceEditorSharedValues.GetOtherSharedEditors(Caller: TSourceEditor;
2939  Index: Integer): TSourceEditor;
2940begin
2941  if Index >= FSharedEditorList.IndexOf(Caller) then
2942    inc(Index);
2943  Result := TSourceEditor(FSharedEditorList[Index]);
2944end;
2945
2946function TSourceEditorSharedValues.SynEditor: TIDESynEditor;
2947begin
2948  Result := SharedEditors[0].FEditor;
2949end;
2950
2951function TSourceEditorSharedValues.GetSharedEditorsBase(Index: Integer): TSourceEditorBase;
2952begin
2953  Result := TSourceEditorBase(FSharedEditorList[Index]);
2954end;
2955
2956procedure TSourceEditorSharedValues.SetCodeBuffer(const AValue: TCodeBuffer);
2957var
2958  i: Integer;
2959  SrcEdit: TSourceEditor;
2960  SharedEdit: TSourceEditor;
2961  ETChanges: TETSingleSrcChanges;
2962begin
2963  if FCodeBuffer = AValue then exit;
2964  if FCodeBuffer<>nil then begin
2965    for i := 0 to FSharedEditorList.Count - 1 do begin
2966      SharedEdit := SharedEditors[i];
2967      if SharedEdit.FEditPlugin<>nil then
2968        SharedEdit.FEditPlugin.Changes:=nil;
2969    end;
2970    FCodeBuffer.RemoveChangeHook(@OnCodeBufferChanged);
2971    if FCodeBuffer.Scanner<>nil then
2972      DisconnectScanner(FCodeBuffer.Scanner);
2973    if FMainLinkScanner<>nil then begin
2974      DisconnectScanner(FMainLinkScanner);
2975      FMainLinkScanner:=nil;
2976    end;
2977  end;
2978
2979  for i := 0 to FSharedEditorList.Count - 1 do begin
2980    SrcEdit:=SharedEditors[i];
2981    SrcEdit.SourceNotebook.FSrcEditsSortedForFilenames.RemovePointer(SrcEdit);
2982  end;
2983
2984  FCodeBuffer := AValue;
2985
2986  for i := 0 to FSharedEditorList.Count - 1 do begin
2987    SrcEdit:=SharedEditors[i];
2988    SrcEdit.SourceNotebook.FSrcEditsSortedForFilenames.Add(SrcEdit);
2989  end;
2990
2991  if FCodeBuffer <> nil then
2992  begin
2993    DebugBoss.LockCommandProcessing;
2994    try
2995      for i := 0 to FSharedEditorList.Count - 1 do begin
2996        // HasExecutionMarks is shared through synedit => this is only needed once
2997        // but HasExecutionMarks must be called on each synedit, so each synedit is notified
2998        SharedEditors[i].ClearExecutionMarks;
2999      end;
3000      FCodeBuffer.AddChangeHook(@OnCodeBufferChanged);
3001      if FCodeBuffer.Scanner<>nil then
3002        ConnectScanner(FCodeBuffer.Scanner);
3003      ETChanges := SourceEditorManager.FChangesQueuedForMsgWnd.GetChanges(
3004                                                     FCodeBuffer.Filename,true);
3005      for i := 0 to FSharedEditorList.Count - 1 do begin
3006        SharedEdit:=SharedEditors[i];
3007        if assigned(SharedEdit.FEditPlugin) then
3008          SharedEdit.FEditPlugin.Changes := ETChanges;
3009      end;
3010      if MessagesView<>nil then
3011        MessagesView.MessagesFrame1.CreateMarksForFile(SynEditor,FCodeBuffer.Filename,true);
3012      if (FIgnoreCodeBufferLock <= 0) and (not FCodeBuffer.IsEqual(SynEditor.Lines))
3013      then begin
3014        {$IFDEF IDE_DEBUG}
3015        debugln(' *** WARNING *** : TSourceEditor.SetCodeBuffer - loosing marks: ',FCodeBuffer.Filename);
3016        {$ENDIF}
3017        for i := 0 to FSharedEditorList.Count - 1 do begin
3018          SharedEdit:=SharedEditors[i];
3019          if assigned(SharedEdit.FEditPlugin) then
3020            SharedEdit.FEditPlugin.Enabled := False;
3021        end;
3022        SynEditor.BeginUpdate;
3023        SynEditor.InvalidateAllIfdefNodes;
3024        FCodeBuffer.AssignTo(SynEditor.Lines, false);
3025        FEditorStampCommitedToCodetools:=(SynEditor.Lines as TSynEditLines).TextChangeStamp;
3026        SynEditor.EndUpdate;
3027        for i := 0 to FSharedEditorList.Count - 1 do begin
3028          SharedEdit:=SharedEditors[i];
3029          if assigned(SharedEdit.FEditPlugin) then
3030            SharedEdit.FEditPlugin.Enabled := True;
3031          if SharedEdit.Visible then
3032            SharedEdit.UpdateIfDefNodeStates(True);
3033        end;
3034      end;
3035      for i := 0 to FSharedEditorList.Count - 1 do begin
3036        SharedEdit:=SharedEditors[i];
3037        if SharedEdit.IsActiveOnNoteBook then
3038          SharedEdit.SourceNotebook.UpdateStatusBar;
3039        // HasExecutionMarks is shared through synedit => this is only needed once
3040        // but HasExecutionMarks must be called on each synedit, so each synedit is notified
3041        if (DebugBoss.State in [dsPause, dsRun]) and
3042           not SharedEdit.HasExecutionMarks and (FCodeBuffer.FileName <> '')
3043        then
3044          SharedEdit.FillExecutionMarks;
3045      end;
3046    finally
3047      DebugBoss.UnLockCommandProcessing;
3048    end;
3049  end;
3050end;
3051
3052function TSourceEditorSharedValues.GetModified: Boolean;
3053begin
3054  Result := FModified or SynEditor.Modified;
3055end;
3056
3057procedure TSourceEditorSharedValues.SetModified(const AValue: Boolean);
3058var
3059  OldModified: Boolean;
3060  i: Integer;
3061begin
3062  OldModified := Modified; // Include SynEdit
3063  FModified := AValue;
3064  if not FModified then
3065  begin
3066    SynEditor.Modified := False; // All shared SynEdits share this value
3067    FEditorStampCommitedToCodetools := TSynEditLines(SynEditor.Lines).TextChangeStamp;
3068    for i := 0 to FSharedEditorList.Count - 1 do
3069      SharedEditors[i].FEditor.MarkTextAsSaved; // Todo: centralize in SynEdit
3070  end;
3071  if OldModified <> Modified then
3072    for i := 0 to FSharedEditorList.Count - 1 do begin
3073      SharedEditors[i].UpdatePageName;
3074      SharedEditors[i].SourceNotebook.UpdateStatusBar;
3075    end;
3076end;
3077
3078procedure TSourceEditorSharedValues.OnCodeBufferChanged(Sender: TSourceLog;
3079  SrcLogEntry: TSourceLogEntry);
3080
3081  procedure MoveTxt(const StartPos, EndPos, MoveToPos: TPoint;
3082    DirectionForward: boolean);
3083  var Txt: string;
3084  begin
3085    if DirectionForward then begin
3086      SynEditor.TextBetweenPointsEx[MoveToPos, MoveToPos, scamAdjust] :=
3087        SynEditor.TextBetweenPoints[StartPos, EndPos];
3088      SynEditor.TextBetweenPointsEx[StartPos, EndPos, scamAdjust] := '';
3089    end else begin
3090      Txt := SynEditor.TextBetweenPoints[StartPos, EndPos];
3091      SynEditor.TextBetweenPointsEx[StartPos, EndPos, scamAdjust] := '';
3092      SynEditor.TextBetweenPointsEx[MoveToPos, MoveToPos, scamAdjust] := Txt;;
3093    end;
3094  end;
3095
3096var
3097  StartPos, EndPos, MoveToPos: TPoint;
3098  CodeToolsInSync: Boolean;
3099  i: Integer;
3100begin
3101  {$IFDEF IDE_DEBUG}
3102  debugln(['[TSourceEditor.OnCodeBufferChanged] A ',FIgnoreCodeBufferLock,' ',SrcLogEntry<>nil]);
3103  {$ENDIF}
3104  if FIgnoreCodeBufferLock>0 then exit;
3105  DebugBoss.LockCommandProcessing;
3106  SynEditor.BeginUpdate;
3107  try
3108    CodeToolsInSync:=not NeedsUpdateCodeBuffer;
3109    if SrcLogEntry<>nil then begin
3110      SynEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditorSharedValues.OnCodeBufferChanged'){$ENDIF};
3111      SynEditor.BeginUpdate;
3112      SynEditor.TemplateEdit.IncExternalEditLock;
3113      SynEditor.SyncroEdit.IncExternalEditLock;
3114      try
3115        case SrcLogEntry.Operation of
3116          sleoInsert:
3117            begin
3118              Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
3119              if StartPos.Y>=1 then
3120                SynEditor.TextBetweenPointsEx[StartPos, StartPos, scamAdjust] := SrcLogEntry.Txt;
3121            end;
3122          sleoDelete:
3123            begin
3124              Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
3125              Sender.AbsoluteToLineCol(SrcLogEntry.Position+SrcLogEntry.Len,
3126                EndPos.Y,EndPos.X);
3127              if (StartPos.Y>=1) and (EndPos.Y>=1) then
3128                SynEditor.TextBetweenPointsEx[StartPos, EndPos, scamAdjust] := '';
3129            end;
3130          sleoMove:
3131            begin
3132              Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
3133              Sender.AbsoluteToLineCol(SrcLogEntry.Position+SrcLogEntry.Len,
3134                EndPos.Y,EndPos.X);
3135              Sender.AbsoluteToLineCol(SrcLogEntry.MoveTo,MoveToPos.Y,MoveToPos.X);
3136              if (StartPos.Y>=1) and (EndPos.Y>=1) and (MoveToPos.Y>=1) then
3137                MoveTxt(StartPos, EndPos, MoveToPos,
3138                  SrcLogEntry.Position<SrcLogEntry.MoveTo);
3139            end;
3140        end;
3141      finally
3142        SynEditor.SyncroEdit.DecExternalEditLock;
3143        SynEditor.TemplateEdit.DecExternalEditLock;
3144        SynEditor.EndUpdate;
3145        SynEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditorSharedValues.OnCodeBufferChanged'){$ENDIF};
3146      end;
3147    end else begin
3148      {$IFDEF VerboseSrcEditBufClean}
3149      debugln(['TSourceEditor.OnCodeBufferChanged clean up ',TCodeBuffer(Sender).FileName,' ',Sender=CodeBuffer,' ',Filename]);
3150      DumpStack;
3151      {$ENDIF}
3152      // HasExecutionMarks is shared through synedit => this is only needed once // but HasExecutionMarks must be called on each synedit, so each synedit is notified
3153      for i := 0 to FSharedEditorList.Count - 1 do
3154        SharedEditors[i].ClearExecutionMarks;
3155      for i := 0 to SharedEditorCount-1 do
3156        SharedEditors[i].BeforeCodeBufferReplace;
3157
3158      SynEditor.InvalidateAllIfdefNodes;
3159      Sender.AssignTo(SynEditor.Lines,false);
3160
3161      for i := 0 to SharedEditorCount-1 do
3162        SharedEditors[i].AfterCodeBufferReplace;
3163      // HasExecutionMarks is shared through synedit => this is only needed once // but HasExecutionMarks must be called on each synedit, so each synedit is notified
3164      for i := 0 to FSharedEditorList.Count - 1 do begin
3165        SharedEditors[i].FillExecutionMarks;
3166        if SharedEditors[i].Visible then
3167          SharedEditors[i].UpdateIfDefNodeStates(True);
3168      end;
3169    end;
3170    if CodeToolsInSync then begin
3171      // synedit and codetools were in sync -> mark as still in sync
3172      FEditorStampCommitedToCodetools:=TSynEditLines(SynEditor.Lines).TextChangeStamp;
3173    end;
3174  finally
3175    SynEditor.EndUpdate;
3176    DebugBoss.UnLockCommandProcessing;
3177  end;
3178end;
3179
3180procedure TSourceEditorSharedValues.BeginGlobalUpdate;
3181begin
3182  inc(FInGlobalUpdate);
3183  if FInGlobalUpdate > 1 then exit;
3184  SynEditor.BeginUpdate;  // locks all shared SynEdits too
3185  SynEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditorSharedValues.BeginGlobalUpdate'){$ENDIF};
3186end;
3187
3188procedure TSourceEditorSharedValues.EndGlobalUpdate;
3189begin
3190  dec(FInGlobalUpdate);
3191  if FInGlobalUpdate > 0 then exit;
3192  SynEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditorSharedValues.EndGlobalUpdate'){$ENDIF};
3193  SynEditor.EndUpdate;
3194end;
3195
3196procedure TSourceEditorSharedValues.AddSharedEditor(AnEditor: TSourceEditor);
3197begin
3198  if FSharedEditorList.IndexOf(AnEditor) < 0 then
3199    FSharedEditorList.Add(AnEditor);
3200end;
3201
3202procedure TSourceEditorSharedValues.RemoveSharedEditor(AnEditor: TSourceEditor);
3203begin
3204  FSharedEditorList.Remove(AnEditor);
3205end;
3206
3207procedure TSourceEditorSharedValues.SetActiveSharedEditor(AnEditor: TSourceEditor);
3208begin
3209  if FInGlobalUpdate > 0 then exit;
3210  // Move to the front, for UpdateCodetools (get undo-caret from correct synedit)
3211  FSharedEditorList.Remove(AnEditor);
3212  FSharedEditorList.Insert(0, AnEditor);
3213end;
3214
3215function TSourceEditorSharedValues.SharedEditorCount: Integer;
3216begin
3217  Result := FSharedEditorList.Count;
3218end;
3219
3220function TSourceEditorSharedValues.OtherSharedEditorCount: Integer;
3221begin
3222  Result := FSharedEditorList.Count - 1;
3223end;
3224
3225function TSourceEditorSharedValues.GetExecutionLine: Integer;
3226begin
3227  if (FExecutionMark = nil) or (not FExecutionMark.Visible) then
3228    Result := -1
3229  else
3230    Result := FExecutionMark.Line;
3231end;
3232
3233procedure TSourceEditorSharedValues.CreateExecutionMark;
3234begin
3235  FExecutionMark := TSourceMark.Create(SharedEditors[0], nil);
3236  SourceEditorMarks.Add(FExecutionMark);
3237  FExecutionMark.LineColorAttrib := ahaExecutionPoint;
3238  FExecutionMark.Priority := 1;
3239end;
3240
3241procedure TSourceEditorSharedValues.SetExecutionLine(NewLine: integer);
3242var
3243  BrkMark: TSourceMark;
3244  CurELine: Integer;
3245begin
3246  CurELine := ExecutionLine;
3247  if CurELine = NewLine then
3248    exit;
3249
3250  inc(UpdatingExecutionMark);
3251  try
3252    if CurELine >= 0 then begin
3253      BrkMark := SourceEditorMarks.FindBreakPointMark(SharedEditors[0], CurELine);
3254      if BrkMark <> nil then
3255        BrkMark.Visible := True;
3256    end;
3257
3258    if (FExecutionMark = nil) then
3259      CreateExecutionMark;
3260
3261    FExecutionMark.Visible := NewLine <> -1;
3262
3263    if NewLine >= 0 then begin
3264      BrkMark := SourceEditorMarks.FindBreakPointMark(SharedEditors[0], NewLine);
3265      if BrkMark <> nil then
3266        BrkMark.Visible := False;
3267    end;
3268
3269    FExecutionMark.Line := NewLine;
3270  finally
3271    dec(UpdatingExecutionMark);
3272  end;
3273end;
3274
3275procedure TSourceEditorSharedValues.IncreaseIgnoreCodeBufferLock;
3276begin
3277  inc(FIgnoreCodeBufferLock);
3278end;
3279
3280procedure TSourceEditorSharedValues.DecreaseIgnoreCodeBufferLock;
3281begin
3282  if FIgnoreCodeBufferLock<=0 then raise Exception.Create('unbalanced calls');
3283  dec(FIgnoreCodeBufferLock);
3284end;
3285
3286function TSourceEditorSharedValues.NeedsUpdateCodeBuffer: boolean;
3287begin
3288  Result := TSynEditLines(SharedEditors[0].FEditor.Lines).TextChangeStamp
3289            <> FEditorStampCommitedToCodetools;
3290end;
3291
3292procedure TSourceEditorSharedValues.UpdateCodeBuffer;
3293begin
3294  if not NeedsUpdateCodeBuffer then exit;
3295  {$IFDEF IDE_DEBUG}
3296  if FCodeBuffer=nil then begin
3297    debugln('*********** Oh, no: UpdateCodeBuffer ************ ');
3298  end;
3299  {$ENDIF}
3300  if FCodeBuffer=nil then exit;
3301  //DebugLn(['TSourceEditor.UpdateCodeBuffer ',FCodeBuffer.FileName]);
3302  IncreaseIgnoreCodeBufferLock;
3303  SynEditor.BeginUpdate(False);
3304  try
3305    FCodeBuffer.Assign(SynEditor.Lines);
3306    FEditorStampCommitedToCodetools:=(SynEditor.Lines as TSynEditLines).TextChangeStamp;
3307  finally
3308    SynEditor.EndUpdate;
3309    DecreaseIgnoreCodeBufferLock;
3310  end;
3311end;
3312
3313function TSourceEditorSharedValues.Filename: string;
3314begin
3315  Result:=FCodeBuffer.Filename;
3316end;
3317
3318procedure TSourceEditorSharedValues.ConnectScanner(Scanner: TLinkScanner);
3319// If this is an include file, several scanners might use this file
3320// all of them should store directives
3321begin
3322  if Scanner=nil then exit;
3323  if FLinkScanners.IndexOf(Scanner)>=0 then exit;
3324  //debugln(['TSourceEditorSharedValues.ConnectScanner ',Filename,' ',Scanner.MainFilename]);
3325  FLinkScanners.Add(Scanner);
3326  Scanner.DemandStoreDirectives;
3327end;
3328
3329procedure TSourceEditorSharedValues.DisconnectScanner(Scanner: TLinkScanner);
3330var
3331  i: Integer;
3332begin
3333  if Scanner=nil then exit;
3334  i:=FLinkScanners.IndexOf(Scanner);
3335  if i<0 then exit;
3336  FLinkScanners.Delete(i);
3337  Scanner.ReleaseStoreDirectives;
3338  if Scanner=FMainLinkScanner then
3339    FMainLinkScanner:=nil;
3340end;
3341
3342function TSourceEditorSharedValues.GetMainLinkScanner(Scan: boolean): TLinkScanner;
3343// Note: if this is an include file, the main scanner may change
3344var
3345  SrcEdit: TIDESynEditor;
3346begin
3347  Result:=FMainLinkScanner;
3348  if Result=nil then
3349  begin
3350    // create main scanner
3351    //debugln(['TSourceEditorSharedValues.GetMainLinkScanner fetching unit codebuffer ...']);
3352    if CodeBuffer=nil then begin
3353      // file is currently creating
3354      //debugln(['TSourceEditorSharedValues.GetMainLinkScanner CodeBuffer=nil']);
3355      exit;
3356    end;
3357    if SharedEditorCount=0 then exit;
3358    SrcEdit:=SharedEditors[0].EditorComponent;
3359    if SrcEdit=nil then exit;
3360    if not (SrcEdit.Highlighter is TSynPasSyn) then
3361    begin
3362      if Filename<>FLastWarnedMainLinkFilename then
3363      begin
3364        if FilenameIsPascalSource(Filename) then
3365          if ConsoleVerbosity>1 then
3366            debugln(['TSourceEditorSharedValues.GetMainLinkScanner not Pascal highlighted: ',Filename,' Highligther=',DbgSName(SrcEdit.Highlighter)]);
3367      end;
3368      FLastWarnedMainLinkFilename:=Filename;
3369      exit;
3370    end;
3371    if not CodeToolBoss.InitCurCodeTool(CodeBuffer) then
3372    begin
3373      if Filename<>FLastWarnedMainLinkFilename then
3374        debugln(['TSourceEditorSharedValues.GetMainLinkScanner failed to find the unit of ',Filename]);
3375      FLastWarnedMainLinkFilename:=Filename;
3376      exit;
3377    end;
3378    Result:=CodeToolBoss.CurCodeTool.Scanner;
3379    ConnectScanner(Result);
3380    FMainLinkScanner:=Result;
3381  end;
3382  if Scan and (FMainLinkScanner<>nil) then
3383  begin
3384    try
3385      FMainLinkScanner.Scan(lsrEnd,false);
3386    except
3387      on E: Exception do begin
3388        //CodeToolBoss.HandleException(e);
3389      end;
3390    end;
3391  end;
3392end;
3393
3394constructor TSourceEditorSharedValues.Create;
3395begin
3396  FSharedEditorList := TFPList.Create;
3397  FExecutionMark := nil;
3398  FMarksRequested := False;
3399  FInGlobalUpdate := 0;
3400  FLinkScanners := TFPList.Create;
3401end;
3402
3403destructor TSourceEditorSharedValues.Destroy;
3404var
3405  i: integer;
3406begin
3407  SourceEditorMarks.DeleteAllForEditorID(Self);
3408  CodeBuffer := nil;
3409  FreeAndNil(FSharedEditorList);
3410  if FLinkScanners<>nil then begin
3411    for i:=0 to FLinkScanners.Count-1 do
3412      TLinkScanner(FLinkScanners[i]).ReleaseStoreDirectives;
3413    FreeAndNil(FLinkScanners);
3414  end;
3415  // no need to care about ExecutionMark, it is removed with all other marks,
3416  // if the last SynEdit is destroyed (TSynEditMark.Destroy will free the SourceMark)
3417  inherited Destroy;
3418end;
3419
3420{ TSourceEditor }
3421
3422{ The constructor for @link(TSourceEditor).
3423  AOwner is the @link(TSourceNotebook)
3424  and the AParent is usually a page of a @link(TPageControl) }
3425constructor TSourceEditor.Create(AOwner: TComponent; AParent: TWinControl;
3426  ASharedEditor: TSourceEditor = nil);
3427Begin
3428  FInEditorChangedUpdating := False;
3429
3430  if ASharedEditor = nil then
3431    FSharedValues := TSourceEditorSharedValues.Create
3432  else
3433    FSharedValues := ASharedEditor.FSharedValues;
3434  FSharedValues.AddSharedEditor(Self);
3435
3436  inherited Create;
3437  FAOwner := AOwner;
3438  if FAOwner is TSourceNotebook then
3439    FSourceNoteBook:=TSourceNotebook(FAOwner)
3440  else
3441    FSourceNoteBook:=nil;
3442
3443  FSyntaxHighlighterType:=lshNone;
3444  FErrorLine:=-1;
3445  FErrorColumn:=-1;
3446  FSyncroLockCount := 0;
3447  FLineInfoNotification := TIDELineInfoNotification.Create;
3448  FLineInfoNotification.AddReference;
3449  FLineInfoNotification.OnChange := @LineInfoNotificationChange;
3450
3451  CreateEditor(AOwner,AParent);
3452  FProjectFileUpdatesNeeded := [];
3453  if ASharedEditor <> nil then begin
3454    PageName := ASharedEditor.PageName;
3455    FEditor.ShareTextBufferFrom(ASharedEditor.EditorComponent);
3456    FEditor.Highlighter := ASharedEditor.EditorComponent.Highlighter;
3457    if ASharedEditor.EditorComponent.Beautifier is TSynBeautifierPascal then
3458      FEditor.Beautifier := ASharedEditor.EditorComponent.Beautifier;
3459  end;
3460
3461  FEditPlugin := TETSynPlugin.Create(FEditor);
3462  FEditPlugin.OnIsEnabled:=@IsFirstShared;
3463end;
3464
3465destructor TSourceEditor.Destroy;
3466begin
3467  DebugLnEnter(SRCED_CLOSE, ['TSourceEditor.Destroy ']);
3468  Application.RemoveAsyncCalls(Self);
3469  if FInEditorChangedUpdating then begin
3470    debugln(['***** TSourceEditor.Destroy: FInEditorChangedUpdating was true']);
3471    DebugBoss.UnLockCommandProcessing;
3472    FInEditorChangedUpdating := False;
3473  end;
3474  PopupMenu := nil;
3475  if (FAOwner<>nil) and (FEditor<>nil) then begin
3476    UnbindEditor;
3477    FEditor.Visible:=false;
3478    FEditor.Parent:=nil;
3479    TSourceNotebook(FAOwner).ReleaseEditor(self, True);
3480    // free the synedit control after processing the events
3481    EditorComponent.Owner.RemoveComponent(EditorComponent);
3482    Application.ReleaseComponent(FEditor);
3483  end;
3484  FEditor:=nil;
3485  if (DebugBoss <> nil) and (DebugBoss.LineInfo <> nil) then
3486    DebugBoss.LineInfo.RemoveNotification(FLineInfoNotification);
3487  FLineInfoNotification.ReleaseReference;
3488  inherited Destroy;
3489  FSharedValues.RemoveSharedEditor(Self);
3490  if FSharedValues.SharedEditorCount = 0 then begin
3491    if FSharedValues.MarksRequested and (FSharedValues.MarksRequestedForFile <> '') then
3492      DebugBoss.LineInfo.Cancel(FSharedValues.MarksRequestedForFile);
3493    FreeAndNil(FSharedValues);
3494  end;
3495  DebugLnExit(SRCED_CLOSE, ['TSourceEditor.Destroy ']);
3496end;
3497
3498{------------------------------G O T O   L I N E  -----------------------------}
3499function TSourceEditor.GotoLine(Value: Integer): Integer;
3500Var
3501  P: TPoint;
3502  NewTopLine: integer;
3503Begin
3504  Manager.AddJumpPointClicked(Self);
3505  P.X := 1;
3506  P.Y := Value;
3507  NewTopLine := P.Y - (FEditor.LinesInWindow div 2);
3508  if NewTopLine < 1 then NewTopLine:=1;
3509  FEditor.CaretXY := P;
3510  FEditor.TopLine := NewTopLine;
3511  Result:=FEditor.CaretY;
3512end;
3513
3514procedure TSourceEditor.ShowGotoLineDialog;
3515var
3516  NewLeft: integer;
3517  NewTop: integer;
3518  dlg: TfrmGoto;
3519begin
3520  dlg := Manager.GotoDialog;
3521  dlg.Edit1.Text:='';
3522  GetDialogPosition(dlg.Width, dlg.Height, NewLeft, NewTop);
3523  dlg.SetBounds(NewLeft, NewTop, dlg.Width, dlg.Height);
3524  if (dlg.ShowModal = mrOK) then
3525    GotoLine(StrToIntDef(dlg.Edit1.Text,1));
3526  Self.FocusEditor;
3527end;
3528
3529procedure TSourceEditor.ShowSmartHintForSourceAtCursor;
3530begin
3531  if Assigned(Manager) and Assigned(Manager.OnShowHintForSource) then
3532    Manager.OnShowHintForSource(Self,FEditor.LogicalCaretXY, False);
3533end;
3534
3535procedure TSourceEditor.GetDialogPosition(Width, Height: integer;
3536  out Left, Top: integer);
3537var
3538  P: TPoint;
3539  ABounds: TRect;
3540begin
3541  with EditorComponent do
3542    P := ClientToScreen(Point(CaretXPix, CaretYPix));
3543  ABounds := Screen.MonitorFromPoint(P).WorkareaRect;
3544  Left := EditorComponent.ClientOrigin.X + (EditorComponent.Width - Width) div 2;
3545  Top := P.Y - Height - 3 * EditorComponent.LineHeight;
3546  if Top < ABounds.Top + 10 then
3547    Top := P.Y + 2 * EditorComponent.LineHeight;
3548  if Top + Height > ABounds.Bottom then
3549    Top := (ABounds.Bottom + ABounds.Top - Height) div 2;
3550  if Top < ABounds.Top then Top := ABounds.Top;
3551end;
3552
3553procedure TSourceEditor.ActivateHint(ClientRect: TRect; const ABaseURL,
3554  AHint: string; AAutoShown: Boolean; AMouseOffset: Boolean);
3555var
3556  ScreenRect: TRect;
3557begin
3558  if SourceNotebook=nil then exit;
3559  ScreenRect.TopLeft:=EditorComponent.ClientToScreen(ClientRect.TopLeft);
3560  ScreenRect.BottomRight:=EditorComponent.ClientToScreen(ClientRect.BottomRight);
3561  Manager.ActivateHint(ScreenRect,ABaseURL,AHint,AAutoShown,AMouseOffset);
3562end;
3563
3564{------------------------------S T A R T  F I N D-----------------------------}
3565procedure TSourceEditor.StartFindAndReplace(Replace:boolean);
3566var
3567  NewOptions: TSynSearchOptions;
3568  ALeft,ATop:integer;
3569  DlgResult: TModalResult;
3570  AState: TLazFindReplaceState;
3571begin
3572  LazFindReplaceDialog.SaveState(AState);
3573  LazFindReplaceDialog.ResetUserHistory;
3574  //debugln('TSourceEditor.StartFindAndReplace A LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'"');
3575  if ReadOnly then Replace := False;
3576  NewOptions:=LazFindReplaceDialog.Options;
3577  if Replace then
3578    NewOptions := NewOptions + [ssoReplace, ssoReplaceAll]
3579  else
3580    NewOptions := NewOptions - [ssoReplace, ssoReplaceAll];
3581  NewOptions:=NewOptions-InputHistoriesSO.SaveOptions
3582    +InputHistoriesSO.FindOptions[EditorComponent.SelAvail];
3583
3584  // Fill in history items
3585  LazFindReplaceDialog.TextToFindComboBox.Items.Assign(InputHistoriesSO.FindHistory);
3586  LazFindReplaceDialog.ReplaceTextComboBox.Items.Assign(InputHistoriesSO.ReplaceHistory);
3587
3588  with EditorComponent do begin
3589    if EditorOpts.FindTextAtCursor then begin
3590      if SelAvail and (BlockBegin.Y = BlockEnd.Y) and
3591         (  ((ComparePoints(BlockBegin, LogicalCaretXY) <= 0) and
3592             (ComparePoints(BlockEnd, LogicalCaretXY) >= 0))  or
3593            ((ComparePoints(BlockBegin, LogicalCaretXY) >= 0) and
3594             (ComparePoints(BlockEnd, LogicalCaretXY) <= 0))
3595         )
3596      then begin
3597        //debugln('TSourceEditor.StartFindAndReplace B FindTextAtCursor SelAvail');
3598        LazFindReplaceDialog.FindText := SelText;
3599      end else begin
3600        //debugln('TSourceEditor.StartFindAndReplace B FindTextAtCursor not SelAvail');
3601        LazFindReplaceDialog.FindText := GetWordAtRowCol(LogicalCaretXY);
3602      end;
3603    end else begin
3604      //debugln('TSourceEditor.StartFindAndReplace B not FindTextAtCursor');
3605      LazFindReplaceDialog.FindText:='';
3606    end;
3607  end;
3608  LazFindReplaceDialog.EnableAutoComplete:=InputHistoriesSO.FindAutoComplete;
3609  // if there is no FindText, use the most recently used FindText
3610  if (LazFindReplaceDialog.FindText='') and (InputHistoriesSO.FindHistory.Count > 0) then
3611    LazFindReplaceDialog.FindText:=InputHistoriesSO.FindHistory[0];
3612
3613  GetDialogPosition(LazFindReplaceDialog.Width,LazFindReplaceDialog.Height,ALeft,ATop);
3614  LazFindReplaceDialog.Left:=ALeft;
3615  LazFindReplaceDialog.Top:=ATop;
3616
3617  LazFindReplaceDialog.Options := NewOptions;
3618  DlgResult:=LazFindReplaceDialog.ShowModal;
3619  InputHistoriesSO.FindOptions[EditorComponent.SelAvail]:=LazFindReplaceDialog.Options;
3620  InputHistoriesSO.FindAutoComplete:=LazFindReplaceDialog.EnableAutoComplete;
3621  if DlgResult = mrCancel then
3622  begin
3623    LazFindReplaceDialog.RestoreState(AState);
3624    exit;
3625  end;
3626  //debugln('TSourceEditor.StartFindAndReplace B LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'"');
3627
3628  Replace:=ssoReplace in LazFindReplaceDialog.Options;
3629  if Replace then
3630    InputHistoriesSO.AddToReplaceHistory(LazFindReplaceDialog.ReplaceText);
3631  InputHistoriesSO.AddToFindHistory(LazFindReplaceDialog.FindText);
3632  InputHistoriesSO.Save;
3633  DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
3634    LazFindReplaceDialog.Options);
3635end;
3636
3637procedure TSourceEditor.AskReplace(Sender: TObject; const ASearch,
3638  AReplace: string; Line, Column: integer; out Action: TSrcEditReplaceAction);
3639var
3640  SynAction: TSynReplaceAction;
3641begin
3642  SynAction:=raCancel;
3643  SourceNotebook.BringToFront;
3644  OnReplace(Sender, ASearch, AReplace, Line, Column, SynAction);
3645  case SynAction of
3646  raSkip: Action:=seraSkip;
3647  raReplaceAll: Action:=seraReplaceAll;
3648  raReplace: Action:=seraReplace;
3649  raCancel: Action:=seraCancel;
3650  else
3651    RaiseGDBException('TSourceEditor.AskReplace: inconsistency');
3652  end;
3653end;
3654
3655{------------------------------F I N D  A G A I N ----------------------------}
3656procedure TSourceEditor.FindNextUTF8;
3657begin
3658  if snIncrementalFind in FSourceNoteBook.States then begin
3659    FSourceNoteBook.IncrementalSearch(True, False);
3660  end
3661  else if LazFindReplaceDialog.FindText = '' then begin
3662    StartFindAndReplace(False)
3663  end
3664  else begin
3665    DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
3666      LazFindReplaceDialog.Options - [ssoEntireScope, ssoSelectedOnly]
3667                                   + [ssoFindContinue]);
3668  end;
3669End;
3670
3671{---------------------------F I N D   P R E V I O U S ------------------------}
3672procedure TSourceEditor.FindPrevious;
3673var
3674  SrchOptions: TSynSearchOptions;
3675begin
3676  if snIncrementalFind in FSourceNoteBook.States then begin
3677    FSourceNoteBook.IncrementalSearch(True, True);
3678  end
3679  else if LazFindReplaceDialog.FindText = '' then begin
3680    // TODO: maybe start with default set to backwards direction? But StartFindAndReplace replaces it with input-history
3681    StartFindAndReplace(False);
3682  end else begin
3683    SrchOptions:=LazFindReplaceDialog.Options - [ssoEntireScope, ssoSelectedOnly]
3684                                              + [ssoFindContinue];
3685    if ssoBackwards in SrchOptions then
3686      SrchOptions := SrchOptions - [ssoBackwards]
3687    else
3688      SrchOptions := SrchOptions + [ssoBackwards];
3689    DoFindAndReplace(LazFindReplaceDialog.FindText, LazFindReplaceDialog.ReplaceText,
3690      SrchOptions);
3691  end;
3692end;
3693
3694procedure TSourceEditor.FindNextWordOccurrence(DirectionForward: boolean);
3695var
3696  StartX, EndX: Integer;
3697  Flags: TSynSearchOptions;
3698  LogCaret: TPoint;
3699begin
3700  LogCaret:=EditorComponent.LogicalCaretXY;
3701  EditorComponent.GetWordBoundsAtRowCol(LogCaret,StartX,EndX);
3702  if EndX<=StartX then exit;
3703  Flags:=[ssoWholeWord];
3704  if DirectionForward then begin
3705    LogCaret.X:=EndX;
3706  end else begin
3707    LogCaret.X:=StartX;
3708    Include(Flags,ssoBackwards);
3709  end;
3710  EditorComponent.BeginUpdate(False);
3711  try
3712    EditorComponent.LogicalCaretXY:=LogCaret;
3713    EditorComponent.SearchReplace(EditorComponent.GetWordAtRowCol(LogCaret),
3714                                  '',Flags);
3715    CenterCursor(True);
3716  finally
3717    EditorComponent.EndUpdate;
3718  end;
3719end;
3720
3721function TSourceEditor.DoFindAndReplace(aFindText, aReplaceText: String;
3722  anOptions: TSynSearchOptions): Integer;
3723var
3724  AText, ACaption: String;
3725  OldEntireScope, Again: Boolean;
3726begin
3727  Result:=0;
3728  if (ssoReplace in anOptions) and ReadOnly then begin
3729    DebugLn(['TSourceEditor.DoFindAndReplace Read only']);
3730    exit;
3731  end;
3732  if SourceNotebook<>nil then
3733    Manager.AddJumpPointClicked(Self);
3734
3735  OldEntireScope := ssoEntireScope in anOptions;
3736  //do not show lisUESearchStringContinueBeg/lisUESearchStringContinueEnd if the caret is in the beginning/end
3737  if ssoBackwards in anOptions then
3738    Again := ((FEditor.CaretY >= FEditor.Lines.Count) and (FEditor.CaretX > Length(FEditor.LineText)))//caret in the last line and last character
3739  else
3740    Again := ((FEditor.CaretY = 1) and (FEditor.CaretX = 1));//caret at the top/left
3741  repeat
3742    try
3743      Result:=EditorComponent.SearchReplace(aFindText, aReplaceText, anOptions);
3744    except
3745      on E: ERegExpr do begin
3746        IDEMessageDialog(lisUEErrorInRegularExpression, E.Message,mtError,[mbCancel]);
3747        exit;
3748      end;
3749    end;
3750    if (Result = 0) and not (ssoReplaceAll in anOptions) then begin
3751      ACaption:=lisUENotFound;
3752      AText:=Format(lisUESearchStringNotFound, [Utf8EscapeControlChars(aFindText, emPascal)]);
3753      if not (Again or OldEntireScope) then begin
3754        if ssoBackwards in anOptions then
3755          AText:=AText+' '+lisUESearchStringContinueEnd
3756        else
3757          AText:=AText+' '+lisUESearchStringContinueBeg;
3758        Again:=MessageDlg(ACaption, AText, mtConfirmation, [mbYes,mbNo], 0) = mrYes;
3759        anOptions:=anOptions + [ssoEntireScope];
3760      end
3761      else begin
3762        Again := False;
3763        IDEMessageDialog(ACaption, AText, mtInformation, [mbOK]);
3764      end;
3765      if not Again then
3766        Manager.DeleteLastJumpPointClicked(Self);
3767    end
3768    else begin
3769      Again := False;
3770      CenterCursor(True);
3771    end;
3772  until not Again;
3773end;
3774
3775procedure TSourceEditor.OnReplace(Sender: TObject; const ASearch, AReplace:
3776  string; Line, Column: integer; var Action: TSynReplaceAction);
3777
3778  function Shorten(const s: string): string;
3779  const
3780    MAX_LEN=300;
3781  begin
3782    Result:=s;
3783    if Length(Result)>MAX_LEN then
3784      Result:=LeftStr(Result, MAX_LEN)+'...';
3785  end;
3786
3787var a,x,y:integer;
3788  AText:AnsiString;
3789begin
3790  if FAOwner<>nil then
3791    TSourceNotebook(FAOwner).UpdateStatusBar;
3792
3793  CenterCursor(True);
3794  CenterCursorHoriz(hcmSoftKeepEOL);
3795
3796  AText:=Format(lisUEReplaceThisOccurrenceOfWith,[Shorten(ASearch),LineEnding,Shorten(AReplace)]);
3797
3798  GetDialogPosition(FEditor.Scale96ToFont(300), FEditor.Scale96ToFont(150), X, Y);
3799  a:=MessageDlgPos(AText,mtconfirmation,
3800            [mbYes,mbYesToAll,mbNo,mbCancel],0,X,Y);
3801
3802  case a of
3803    mrYes:Action:=raReplace;
3804    mrNo :Action:=raSkip;
3805    mrAll,mrYesToAll:Action:=raReplaceAll;
3806  else
3807    Action:=raCancel;
3808  end;
3809end;
3810
3811//-----------------------------------------------------------------------------
3812
3813procedure TSourceEditor.FocusEditor;
3814Begin
3815  DebugLnEnter(SRCED_PAGES, ['>> TSourceEditor.FocusEditor A ',PageName,' ',FEditor.Name]);
3816  IDEWindowCreators.ShowForm(SourceNotebook, true, vmOnlyMoveOffScreenToVisible);
3817  if FEditor.IsVisible then begin
3818    FEditor.SetFocus; // TODO: will cal EditorEnter, which does self.Activate  => maybe lock, and do here?
3819    FSharedValues.SetActiveSharedEditor(Self);
3820  end else begin
3821    debugln(SRCED_PAGES, ['TSourceEditor.FocusEditor not IsVisible: ',PageName,' ',FEditor.Name]);
3822  end;
3823  //DebugLn('TSourceEditor.FocusEditor ',dbgsName(FindOwnerControl(GetFocus)),' ',dbgs(GetFocus));
3824  DebugLnExit(SRCED_PAGES, ['<< TSourceEditor.FocusEditor END ',PageName,' ',FEditor.Name]);
3825end;
3826
3827function TSourceEditor.GetReadOnly: Boolean;
3828Begin
3829  Result:=FEditor.ReadOnly;
3830End;
3831
3832procedure TSourceEditor.SetReadOnly(const NewValue: boolean);
3833begin
3834  FEditor.ReadOnly:=NewValue;
3835end;
3836
3837function TSourceEditor.Manager: TSourceEditorManager;
3838begin
3839  if FSourceNoteBook <> nil then
3840    Result := FSourceNoteBook.Manager
3841  else
3842    Result := nil;
3843end;
3844
3845procedure TSourceEditor.MoveToWindow(AWindowIndex: Integer);
3846begin
3847  SourceNotebook.MoveEditor(PageIndex, AWindowIndex, -1)
3848end;
3849
3850function TSourceEditor.GetSharedValues: TSourceEditorSharedValuesBase;
3851begin
3852  Result := FSharedValues;
3853end;
3854
3855function TSourceEditor.IsSharedWith(AnOtherEditor: TSourceEditor): Boolean;
3856begin
3857  Result := (AnOtherEditor <> nil) and
3858            (AnOtherEditor.FSharedValues = FSharedValues);
3859end;
3860
3861procedure TSourceEditor.BeforeCodeBufferReplace;
3862begin
3863  FTempTopLine := FEditor.TopLine;
3864  FTempCaret := FEditor.CaretXY;
3865end;
3866
3867procedure TSourceEditor.AfterCodeBufferReplace;
3868begin
3869  if (FTempTopLine > FEditor.Lines.Count) or(FTempCaret.Y > FEditor.Lines.Count)
3870  then
3871    exit;
3872  FEditor.TopLine := FTempTopLine;
3873  FEditor.CaretXY := FTempCaret;
3874end;
3875
3876procedure TSourceEditor.DoMultiCaretBeforeCommand(Sender: TObject;
3877  ACommand: TSynEditorCommand; var AnAction: TSynMultiCaretCommandAction;
3878  var AFlags: TSynMultiCaretCommandFlags);
3879begin
3880  if (FSourceNoteBook<>nil) and (snIncrementalFind in FSourceNoteBook.States) then begin
3881    AnAction := ccaClearCarets;
3882  end;
3883
3884  case ACommand of
3885    ecToggleComment:
3886      if FEditor.SelAvail then
3887        AnAction := ccaAdjustCarets
3888      else
3889        AnAction := ccaRepeatCommandPerLine; // one per line
3890    ecInsertUserName,
3891    ecInsertDateTime,
3892    ecInsertChangeLogEntry,
3893    ecInsertCVSAuthor,
3894    ecInsertCVSDate,
3895    ecInsertCVSHeader,
3896    ecInsertCVSID,
3897    ecInsertCVSLog,
3898    ecInsertCVSName,
3899    ecInsertCVSRevision,
3900    ecInsertCVSSource,
3901    ecInsertGUID,
3902    ecInsertFilename:
3903      AnAction := ccaRepeatCommand;
3904  end;
3905end;
3906
3907procedure TSourceEditor.ProcessCommand(Sender: TObject;
3908  var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
3909// these are normal commands for synedit (lower than ecUserFirst),
3910// define extra actions here
3911// for non synedit keys (bigger than ecUserFirst) use ProcessUserCommand
3912var
3913  AddChar, IsIdent, ok: Boolean;
3914  s, AttrName: String;
3915  i, WordStart, WordEnd: Integer;
3916  p: TPoint;
3917begin
3918  //DebugLn('TSourceEditor.ProcessCommand Command=',dbgs(Command));
3919  FSharedValues.SetActiveSharedEditor(Self);
3920  AutoStartCompletionBoxTimer.AutoEnabled:=false;
3921  if FCodeCompletionState.State in [ccsDot, ccsOnTyping] then
3922    FCodeCompletionState.State := ccsReady;
3923
3924  if (Command=ecChar) and (AChar=#27) then begin
3925    // close hint windows
3926    if (CodeContextFrm<>nil) then
3927      CodeContextFrm.Hide;
3928    if (SrcEditHintWindow<>nil) then
3929      SrcEditHintWindow.Hide;
3930  end;
3931  Manager.HideHint;
3932
3933  if (FSourceNoteBook<>nil)
3934  and (snIncrementalFind in FSourceNoteBook.States) then begin
3935    case Command of
3936    ecChar:
3937      begin
3938        if AChar=#27 then begin
3939          if (CodeContextFrm<>nil) then
3940            CodeContextFrm.Hide;
3941
3942          FSourceNoteBook.IncrementalSearchStr:='';
3943        end else
3944          FSourceNoteBook.IncrementalSearchStr:=
3945            FSourceNoteBook.IncrementalSearchStr+AChar;
3946        Command:=ecNone;
3947      end;
3948
3949    ecDeleteLastChar:
3950      begin
3951        i := length(FSourceNoteBook.IncrementalSearchStr);
3952        i := UTF8FindNearestCharStart(PChar(FSourceNoteBook.IncrementalSearchStr), i, i-1);
3953        FSourceNoteBook.IncrementalSearchStr:= LeftStr(FSourceNoteBook.IncrementalSearchStr, i);
3954        Command:=ecNone;
3955      end;
3956
3957    ecLineBreak:
3958      begin
3959        FSourceNoteBook.EndIncrementalFind;
3960        Command:=ecNone;
3961      end;
3962
3963    ecPaste:
3964      begin
3965        s:=Clipboard.AsText;
3966        s:=copy(s,1,EditorOpts.RightMargin);
3967        FSourceNoteBook.IncrementalSearchStr:=
3968          FSourceNoteBook.IncrementalSearchStr+s;
3969        Command:=ecNone;
3970      end;
3971
3972    ecScrollUp, ecScrollDown, ecScrollLeft, ecScrollRight: ; // ignore
3973
3974    else
3975      FSourceNoteBook.EndIncrementalFind;
3976    end;
3977  end;
3978
3979  case Command of
3980
3981  ecSelEditorTop, ecSelEditorBottom, ecEditorTop, ecEditorBottom:
3982    begin
3983      if (FaOwner<>nil) and (not FEditor.IsInMultiCaretRepeatExecution) then
3984        Manager.AddJumpPointClicked(Self);
3985    end;
3986
3987  ecCopy,ecCut,ecCopyAdd,ecCutAdd:
3988    begin
3989      if (not FEditor.SelAvail) then begin
3990        // nothing selected
3991        if EditorOpts.CopyWordAtCursorOnCopyNone then begin
3992          FEditor.SelectWord;
3993        end;
3994      end;
3995    end;
3996
3997  ecTab:
3998    begin
3999      AddChar:=true;
4000      if AutoCompleteChar(aChar,AddChar,acoTab) then begin
4001        // completed
4002      end;
4003      if not AddChar then Command:=ecNone;
4004    end;
4005
4006  ecChar:
4007    begin
4008      AddChar:=true;
4009      IsIdent:=FEditor.IsIdentChar(aChar);
4010      //debugln(['TSourceEditor.ProcessCommand AChar="',AChar,'" AutoIdentifierCompletion=',dbgs(EditorOpts.AutoIdentifierCompletion),' Interval=',AutoStartCompletionBoxTimer.Interval,' ',Dbgs(FEditor.CaretXY),' ',FEditor.IsIdentChar(aChar)]);
4011      if (aChar=' ') and AutoCompleteChar(aChar,AddChar,acoSpace) then begin
4012        // completed
4013      end
4014      else
4015      if (not IsIdent)
4016      and AutoCompleteChar(aChar,AddChar,acoWordEnd) then begin
4017        // completed
4018      end
4019      else
4020      if CodeToolsOpts.IdentComplAutoInvokeOnType and
4021         ( IsIdent or (AChar='.') ) and
4022         (ActiveEditorMacro = nil)
4023      then begin
4024        // store caret position to detect caret changes // add the char
4025        p := FEditor.LogicalCaretXY;
4026        SourceCompletionCaretXY:=p;
4027        inc(SourceCompletionCaretXY.x,length(AChar));
4028
4029        AttrName := GetCodeAttributeName(p);
4030        ok := (FCodeCompletionState.State <> ccsCancelled) and
4031              (FEditor.MultiCaret.CaretsCount = 0) and
4032              (AttrName <> SYNS_XML_AttrComment) and
4033              (AttrName <> SYNS_XML_AttrDirective) and
4034              (AttrName <> SYNS_XML_AttrString);
4035        if ok then begin
4036          if AChar = '.' then begin
4037            ok := CodeToolsOpts.IdentComplAutoStartAfterPoint;
4038          end
4039          else
4040          if (CodeToolsOpts.IdentComplOnTypeMinLength > 1) or CodeToolsOpts.IdentComplOnTypeOnlyWordEnd
4041          then begin
4042            FEditor.GetWordBoundsAtRowCol(p, WordStart, WordEnd);
4043            ok := (p.x <= WordEnd) and  // inside word
4044                  ((not CodeToolsOpts.IdentComplOnTypeOnlyWordEnd) or (p.x = WordEnd)) and  // at word end?
4045                  ((WordEnd-WordStart+1) >= CodeToolsOpts.IdentComplOnTypeMinLength);
4046          end;
4047        end;
4048
4049        if ok then begin
4050          if CodeToolsOpts.IdentComplOnTypeUseTimer then begin
4051            AutoStartCompletionBoxTimer.AutoEnabled:=true;
4052            FCodeCompletionState.State := ccsOnTyping;
4053          end
4054          else begin
4055            FCodeCompletionState.State := ccsOnTypingScheduled;
4056          end;
4057        end;
4058      end
4059      else
4060      if CodeToolsOpts.IdentComplAutoStartAfterPoint and
4061         (AChar='.') and (ActiveEditorMacro = nil)
4062      then begin
4063        // store caret position to detect caret changes // add the char
4064        SourceCompletionCaretXY:=FEditor.LogicalCaretXY;
4065        inc(SourceCompletionCaretXY.x,length(AChar));
4066        AutoStartCompletionBoxTimer.AutoEnabled:=true;
4067        FCodeCompletionState.State := ccsDot;
4068      end;
4069      //DebugLn(['TSourceEditor.ProcessCommand ecChar AddChar=',AddChar]);
4070      if not AddChar then Command:=ecNone;
4071    end;
4072
4073  ecLineBreak:
4074    begin
4075      AddChar:=true;
4076      if AutoCompleteChar(aChar,AddChar,acoLineBreak) then ;
4077      //DebugLn(['TSourceEditor.ProcessCommand ecLineBreak AddChar=',AddChar,' EditorOpts.AutoBlockCompletion=',EditorOpts.AutoBlockCompletion]);
4078      if not AddChar then Command:=ecNone;
4079      if EditorOpts.AutoBlockCompletion then
4080        AutoCompleteBlock;
4081    end;
4082
4083  ecPrevBookmark: // Note: book mark commands lower than ecUserFirst must be handled here
4084    if Assigned(Manager.OnGotoBookmark) then
4085      Manager.OnGotoBookmark(Self, -1, True);
4086
4087  ecNextBookmark:
4088    if Assigned(Manager.OnGotoBookmark) then
4089      Manager.OnGotoBookmark(Self, -1, False);
4090
4091  ecGotoMarker0..ecGotoMarker9:
4092    if Assigned(Manager.OnGotoBookmark) then
4093      Manager.OnGotoBookmark(Self, Command - ecGotoMarker0, False);
4094
4095  ecSetMarker0..ecSetMarker9:
4096    if Assigned(Manager.OnSetBookmark) then
4097      Manager.OnSetBookmark(Self, Command - ecSetMarker0, False);
4098
4099  ecToggleMarker0..ecToggleMarker9:
4100    if Assigned(Manager.OnSetBookmark) then
4101      Manager.OnSetBookmark(Self, Command - ecToggleMarker0, True);
4102
4103  ecSelectAll:
4104    Manager.AddJumpPointClicked(Self);
4105
4106  end;
4107  //debugln('TSourceEditor.ProcessCommand B IdentCompletionTimer.AutoEnabled=',dbgs(AutoStartCompletionBoxTimer.AutoEnabled));
4108end;
4109
4110procedure TSourceEditor.ProcessUserCommand(Sender: TObject;
4111  var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
4112// these are the keys above ecUserFirst
4113// define all extra keys here, that should not be handled by synedit
4114var
4115  Handled: boolean;
4116  i,x,y: Integer;
4117Begin
4118  //debugln('TSourceEditor.ProcessUserCommand A ',dbgs(Command));
4119  FSharedValues.SetActiveSharedEditor(Self);
4120  Handled:=true;
4121  CheckActiveWindow;
4122
4123  case Command of
4124  ecMultiPaste:                MultiPasteText;
4125  ecContextHelp:               FindHelpForSourceAtCursor;
4126  ecSmartHint:                 ShowSmartHintForSourceAtCursor;
4127  ecIdentCompletion: StartIdentCompletionBox(CodeToolsOpts.IdentComplJumpToError,true);
4128  ecShowCodeContext: SourceNotebook.StartShowCodeContext(CodeToolsOpts.IdentComplJumpToError);
4129  ecWordCompletion:            StartWordCompletionBox;
4130  ecFind:                      StartFindAndReplace(false);
4131  ecFindNext:                  FindNextUTF8;
4132  ecFindPrevious:              FindPrevious;
4133  ecIncrementalFind: if FSourceNoteBook<>nil then FSourceNoteBook.BeginIncrementalFind;
4134  ecReplace:                   StartFindAndReplace(true);
4135  ecGotoLineNumber:            ShowGotoLineDialog;
4136  ecFindNextWordOccurrence:    FindNextWordOccurrence(true);
4137  ecFindPrevWordOccurrence:    FindNextWordOccurrence(false);
4138  ecSelectionEnclose:          EncloseSelection;
4139  ecSelectionUpperCase:        UpperCaseSelection;
4140  ecSelectionLowerCase:        LowerCaseSelection;
4141  ecSelectionSwapCase:         SwapCaseSelection;
4142  ecSelectionTabs2Spaces:      TabsToSpacesInSelection;
4143  ecSelectionComment:          CommentSelection;
4144  ecSelectionUnComment:        UncommentSelection;
4145  ecToggleComment:             ToggleCommentSelection;
4146  ecSelectionEncloseIFDEF:     ConditionalSelection;
4147  ecSelectionSort:             SortSelection;
4148  ecSelectionBreakLines:       BreakLinesInSelection;
4149  ecInvertAssignment:          InvertAssignment;
4150  ecSelectToBrace:             SelectToBrace;
4151  ecSelectLine:                SelectLine;
4152  ecSelectWord:                SelectWord;
4153  ecSelectParagraph:           SelectParagraph;
4154  ecInsertCharacter:           InsertCharacterFromMap;
4155  ecInsertGPLNotice:           InsertGPLNotice(comtDefault,false);
4156  ecInsertGPLNoticeTranslated: InsertGPLNotice(comtDefault,true);
4157  ecInsertLGPLNotice:          InsertLGPLNotice(comtDefault,false);
4158  ecInsertLGPLNoticeTranslated:InsertLGPLNotice(comtDefault,true);
4159  ecInsertModifiedLGPLNotice:  InsertModifiedLGPLNotice(comtDefault,false);
4160  ecInsertModifiedLGPLNoticeTranslated: InsertModifiedLGPLNotice(comtDefault,true);
4161  ecInsertMITNotice:           InsertMITNotice(comtDefault,false);
4162  ecInsertMITNoticeTranslated: InsertMITNotice(comtDefault,true);
4163  ecInsertUserName:            InsertUsername;
4164  ecInsertDateTime:            InsertDateTime;
4165  ecInsertChangeLogEntry:      InsertChangeLogEntry;
4166  ecInsertCVSAuthor:           InsertCVSKeyword('Author');
4167  ecInsertCVSDate:             InsertCVSKeyword('Date');
4168  ecInsertCVSHeader:           InsertCVSKeyword('Header');
4169  ecInsertCVSID:               InsertCVSKeyword('ID');
4170  ecInsertCVSLog:              InsertCVSKeyword('Log');
4171  ecInsertCVSName:             InsertCVSKeyword('Name');
4172  ecInsertCVSRevision:         InsertCVSKeyword('Revision');
4173  ecInsertCVSSource:           InsertCVSKeyword('Source');
4174  ecInsertGUID:                InsertGUID;
4175  ecInsertFilename:            InsertFilename;
4176  ecLockEditor:                IsLocked := not IsLocked;
4177  ecSynMacroPlay: begin
4178      If ActiveEditorMacro = EditorMacroForRecording then begin
4179        if EditorMacroForRecording.State = emRecording
4180        then EditorMacroForRecording.Pause
4181        else EditorMacroForRecording.Resume;
4182      end
4183      else
4184        if (SelectedEditorMacro <> nil) and
4185           (SelectedEditorMacro.State = emStopped)
4186        then
4187          SelectedEditorMacro.PlaybackMacro(FEditor);
4188    end;
4189  ecSynMacroRecord: begin
4190      If ActiveEditorMacro = nil then
4191        EditorMacroForRecording.RecordMacro(FEditor)
4192      else
4193      If ActiveEditorMacro = EditorMacroForRecording then
4194        EditorMacroForRecording.Stop;
4195    end;
4196  ecClearBookmarkForFile: begin
4197      if Assigned(Manager) and Assigned(Manager.OnClearBookmarkId) then
4198        for i in TBookmarkNumRange do
4199          if EditorComponent.GetBookMark(i,x{%H-},y{%H-}) then
4200            Manager.OnClearBookmarkId(Self, i);
4201    end;
4202
4203  ecCloseOtherTabs: Application.QueueAsyncCall(@Manager.CloseOtherPagesClickedAsync, PtrInt(SourceNotebook.GetNoteBookPage(SourceNotebook.FindPageWithEditor(Self))));
4204  ecCloseRightTabs: Application.QueueAsyncCall(@Manager.CloseRightPagesClickedAsync, PtrInt(SourceNotebook.GetNoteBookPage(SourceNotebook.FindPageWithEditor(Self))));
4205
4206  else
4207    begin
4208      Handled:=false;
4209      if FaOwner<>nil then
4210        TSourceNotebook(FaOwner).ProcessParentCommand(self,Command,aChar,Data,
4211                        Handled);
4212    end;
4213  end;  //case
4214  if Handled then Command:=ecNone;
4215end;
4216
4217procedure TSourceEditor.UserCommandProcessed(Sender: TObject;
4218  var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
4219// called after the source editor processed a key
4220var Handled: boolean;
4221begin
4222  Handled:=true;
4223
4224  if (Command <> ecCompleteCode) and (Command <> ecCompleteCodeInteractive) and
4225     (FCodeCompletionState.State = ccsCancelled)
4226  then begin
4227    if CompareCaret(FCodeCompletionState.LastTokenStartPos, CurrentWordLogStartOrCaret) <> 0 then
4228      FCodeCompletionState.State := ccsReady;
4229  end;
4230
4231  case Command of
4232  ecNone: ;
4233
4234  ecChar:
4235    begin
4236      if AutoBlockCompleteChar(AChar) then
4237        Handled:=true;
4238      if EditorOpts.AutoDisplayFunctionPrototypes then
4239         if (aChar = '(') or (aChar = ',') then
4240            SourceNotebook.StartShowCodeContext(False);
4241
4242      if FCodeCompletionState.State = ccsOnTypingScheduled then begin
4243        FCodeCompletionState.State := ccsOnTyping;
4244        StartIdentCompletionBox(false,false);
4245      end;
4246    end;
4247
4248  else
4249    begin
4250      Handled:=false;
4251      if FaOwner<>nil then
4252        TSourceNotebook(FaOwner).ParentCommandProcessed(Self,Command,aChar,Data,
4253                                                        Handled);
4254    end;
4255  end;
4256  if Handled then Command:=ecNone;
4257end;
4258
4259procedure TSourceEditor.EditorStatusChanged(Sender: TObject;
4260  Changes: TSynStatusChanges);
4261Begin
4262  If Assigned(OnEditorChange) then
4263    OnEditorChange(Sender, Changes);
4264  UpdatePageName;
4265  if Changes * [scCaretX, scCaretY, scSelection] <> [] then
4266    IDECommandList.PostponeUpdateEvents;
4267end;
4268
4269function TSourceEditor.SelectionAvailable: boolean;
4270begin
4271  Result := EditorComponent.SelAvail;
4272end;
4273
4274function TSourceEditor.GetText(OnlySelection: boolean): string;
4275begin
4276  if OnlySelection then
4277    Result:=EditorComponent.SelText
4278  else
4279    Result:=EditorComponent.Lines.Text;
4280end;
4281
4282procedure TSourceEditor.UpperCaseSelection;
4283// Turns current text selection uppercase.
4284begin
4285  if ReadOnly then exit;
4286  if not EditorComponent.SelAvail then exit;
4287  FEditor.SetTextBetweenPoints(FEditor.BlockBegin, FEditor.BlockEnd,
4288                               UTF8UpperCase(EditorComponent.SelText),
4289                               [setSelect], scamIgnore, smaKeep, smCurrent
4290                              );
4291end;
4292
4293procedure TSourceEditor.LowerCaseSelection;
4294// Turns current text selection lowercase.
4295begin
4296  if ReadOnly then exit;
4297  if not EditorComponent.SelAvail then exit;
4298  FEditor.SetTextBetweenPoints(FEditor.BlockBegin, FEditor.BlockEnd,
4299                               UTF8LowerCase(EditorComponent.SelText),
4300                               [setSelect], scamIgnore, smaKeep, smCurrent
4301                              );
4302end;
4303
4304procedure TSourceEditor.SwapCaseSelection;
4305begin
4306  if ReadOnly then exit;
4307  if not EditorComponent.SelAvail then exit;
4308  FEditor.SetTextBetweenPoints(FEditor.BlockBegin, FEditor.BlockEnd,
4309                               UTF8SwapCase(EditorComponent.SelText),
4310                               [setSelect], scamIgnore, smaKeep, smCurrent
4311                              );
4312end;
4313
4314{-------------------------------------------------------------------------------
4315  method TSourceEditor.TabsToSpacesInSelection
4316
4317  Convert all tabs into spaces in current text selection.
4318-------------------------------------------------------------------------------}
4319procedure TSourceEditor.TabsToSpacesInSelection;
4320begin
4321  if ReadOnly then exit;
4322  if not EditorComponent.SelAvail then exit;
4323  FEditor.SetTextBetweenPoints(FEditor.BlockBegin, FEditor.BlockEnd,
4324                               TabsToSpaces(EditorComponent.SelText, EditorComponent.TabWidth, FEditor.UseUTF8),
4325                               [setSelect], scamAdjust, smaKeep, smCurrent
4326                              );
4327end;
4328
4329procedure TSourceEditor.CommentSelection;
4330begin
4331  UpdateCommentSelection(True, False);
4332end;
4333
4334procedure TSourceEditor.UncommentSelection;
4335begin
4336  UpdateCommentSelection(False, False);
4337end;
4338
4339procedure TSourceEditor.ToggleCommentSelection;
4340begin
4341  UpdateCommentSelection(False, True);
4342end;
4343
4344procedure TSourceEditor.UpdateCommentSelection(CommentOn, Toggle: Boolean);
4345var
4346  OldCaretPos, OldBlockStart, OldBlockEnd: TPoint;
4347  WasSelAvail: Boolean;
4348  WasSelMode: TSynSelectionMode;
4349  BlockBeginLine: Integer;
4350  BlockEndLine: Integer;
4351  CommonIndent: Integer;
4352
4353  function FirstNonBlankPos(const Text: String; Start: Integer = 1): Integer;
4354  var
4355    i: Integer;
4356  begin
4357    for i := Start to Length(Text) do
4358      if (Text[i] <> #32) and (Text[i] <> #9) then
4359        exit(i);
4360    Result := -1;
4361  end;
4362
4363  function MinCommonIndent: Integer;
4364  var
4365    i, j: Integer;
4366  begin
4367    If CommonIndent = 0 then begin
4368      CommonIndent := Max(FirstNonBlankPos(FEditor.Lines[BlockBeginLine - 1]), 1);
4369      for i := BlockBeginLine + 1 to BlockEndLine do begin
4370        j := FirstNonBlankPos(FEditor.Lines[i - 1]);
4371        if (j < CommonIndent) and (j > 0) then
4372          CommonIndent := j;
4373      end;
4374    end;
4375    Result := CommonIndent;
4376  end;
4377
4378  function InsertPos(ALine: Integer): Integer;
4379  begin
4380    if not WasSelAvail then
4381      Result := MinCommonIndent
4382    else case WasSelMode of
4383      smColumn: // CommonIndent is not used otherwise
4384        begin
4385          if CommonIndent = 0 then
4386            CommonIndent := Min(FEditor.LogicalToPhysicalPos(OldBlockStart).X,
4387                                FEditor.LogicalToPhysicalPos(OldBlockEnd).X);
4388          Result := FEditor.PhysicalToLogicalPos(Point(CommonIndent, ALine)).X;
4389        end;
4390      smNormal:
4391        begin
4392          Result := MinCommonIndent;
4393        end;
4394       else
4395         Result := 1;
4396    end;
4397  end;
4398
4399  function DeletePos(ALine: Integer): Integer;
4400  var
4401    line: String;
4402  begin
4403    line := FEditor.Lines[ALine - 1];
4404    Result := FirstNonBlankPos(line, InsertPos(ALine));
4405    if (WasSelMode = smColumn) and((Result < 1) or (Result > length(line) - 1))
4406    then
4407      Result := length(line) - 1;
4408    Result := Max(1, Result);
4409    if (Length(line) < Result +1) or
4410       (line[Result] <> '/') or (line[Result+1] <> '/') then
4411      Result := -1;
4412  end;
4413
4414var
4415  i: Integer;
4416  NonBlankStart: Integer;
4417begin
4418  if ReadOnly then exit;
4419  OldCaretPos   := FEditor.CaretXY;
4420  OldBlockStart := FEditor.BlockBegin;
4421  OldBlockEnd   := FEditor.BlockEnd;
4422  WasSelAvail := FEditor.SelAvail;
4423  WasSelMode  := FEditor.SelectionMode;
4424  CommonIndent := 0;
4425
4426  BlockBeginLine := OldBlockStart.Y;
4427  BlockEndLine := OldBlockEnd.Y;
4428  if (OldBlockEnd.X = 1) and (BlockEndLine > BlockBeginLine) and (FEditor.SelectionMode <> smLine) then
4429    Dec(BlockEndLine);
4430
4431  if Toggle then begin
4432    CommentOn := False;
4433    for i := BlockBeginLine to BlockEndLine do
4434      if DeletePos(i) < 0 then begin
4435        CommentOn := True;
4436        break;
4437      end;
4438  end;
4439
4440  BeginUpdate;
4441  BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.UpdateCommentSelection'){$ENDIF};
4442  FEditor.SelectionMode := smNormal;
4443
4444  if CommentOn then begin
4445    for i := BlockEndLine downto BlockBeginLine do
4446      FEditor.TextBetweenPoints[Point(InsertPos(i), i), Point(InsertPos(i), i)] := '//';
4447    if OldCaretPos.X > InsertPos(OldCaretPos.Y) then
4448      OldCaretPos.x := OldCaretPos.X + 2;
4449    if OldBlockStart.X > InsertPos(OldBlockStart.Y) then
4450      OldBlockStart.X := OldBlockStart.X + 2;
4451    if OldBlockEnd.X > InsertPos(OldBlockEnd.Y) then
4452      OldBlockEnd.X := OldBlockEnd.X + 2;
4453  end
4454  else begin
4455    for i := BlockEndLine downto BlockBeginLine do
4456    begin
4457      NonBlankStart := DeletePos(i);
4458      if NonBlankStart < 1 then continue;
4459      FEditor.TextBetweenPoints[Point(NonBlankStart, i), Point(NonBlankStart + 2, i)] := '';
4460      if (OldCaretPos.Y = i) and (OldCaretPos.X > NonBlankStart) then
4461        OldCaretPos.x := Max(OldCaretPos.X - 2, NonBlankStart);
4462      if (OldBlockStart.Y = i) and (OldBlockStart.X > NonBlankStart) then
4463        OldBlockStart.X := Max(OldBlockStart.X - 2, NonBlankStart);
4464      if (OldBlockEnd.Y = i) and (OldBlockEnd.X > NonBlankStart) then
4465        OldBlockEnd.X := Max(OldBlockEnd.X - 2, NonBlankStart);
4466    end;
4467  end;
4468
4469  EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.UpdateCommentSelection'){$ENDIF};
4470  EndUpdate;
4471
4472  FEditor.CaretXY := OldCaretPos;
4473  FEditor.BlockBegin := OldBlockStart;
4474  FEditor.BlockEnd := OldBlockEnd;
4475  FEditor.SelectionMode := WasSelMode;
4476end;
4477
4478procedure TSourceEditor.ConditionalSelection;
4479var
4480  IsPascal: Boolean;
4481  i: Integer;
4482  P: TPoint;
4483begin
4484  if ReadOnly then exit;
4485  FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.ConditionalSelection'){$ENDIF};
4486  try
4487    if not EditorComponent.SelAvail then begin
4488      P.Y := FEditor.CaretY;
4489      P.X := 1;
4490      FEditor.BlockBegin := P;
4491      Inc(P.Y);
4492      FEditor.BlockEnd := P;
4493    end;
4494    // ToDo: replace step by step to keep bookmarks and breakpoints
4495    IsPascal := True;
4496    i:=EditorOpts.HighlighterList.FindByHighlighter(FEditor.Highlighter);
4497    if i>=0 then
4498      IsPascal := EditorOpts.HighlighterList[i].DefaultCommentType <> comtCPP;
4499    // will show modal dialog - must not be in Editor.BeginUpdate block, or painting will not work
4500    FEditor.SelText:=EncloseInsideIFDEF(EditorComponent.SelText,IsPascal);
4501  finally
4502    FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.ConditionalSelection'){$ENDIF};
4503  end;
4504end;
4505
4506procedure TSourceEditor.SortSelection;
4507var
4508  OldSelText, NewSortedText: string;
4509begin
4510  if ReadOnly then exit;
4511  OldSelText:=EditorComponent.SelText;
4512  if OldSelText='' then exit;
4513  if ShowSortSelectionDialog(OldSelText,EditorComponent.Highlighter,
4514                             NewSortedText)=mrOk
4515  then
4516    EditorComponent.SelText:=NewSortedText;
4517end;
4518
4519procedure TSourceEditor.BreakLinesInSelection;
4520var
4521  OldSelection: String;
4522begin
4523  if ReadOnly then exit;
4524  if not EditorComponent.SelAvail then exit;
4525  FEditor.BeginUpdate;
4526  FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.BreakLinesInSelection'){$ENDIF};
4527  // ToDo: replace step by step to keep bookmarks and breakpoints
4528  try
4529    OldSelection:=EditorComponent.SelText;
4530    FEditor.SelText:=BreakLinesInText(OldSelection,FEditor.RightEdge);
4531  finally
4532    FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.BreakLinesInSelection'){$ENDIF};
4533    FEditor.EndUpdate;
4534  end;
4535end;
4536
4537procedure TSourceEditor.InvertAssignment;
4538begin
4539  if ReadOnly then exit;
4540  if not EditorComponent.SelAvail then exit;
4541  FEditor.BeginUpdate;
4542  FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.InvertAssignment'){$ENDIF};
4543  try
4544    // ToDo: replace step by step to keep bookmarks and breakpoints
4545    FEditor.SelText := InvertAssignTool.InvertAssignment(FEditor.SelText);
4546  finally
4547    FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.InvertAssignment'){$ENDIF};
4548    FEditor.EndUpdate;
4549  end;
4550end;
4551
4552procedure TSourceEditor.SelectToBrace;
4553begin
4554  EditorComponent.SelectToBrace;
4555end;
4556
4557procedure TSourceEditor.SelectWord;
4558begin
4559  EditorComponent.SelectWord;
4560end;
4561
4562procedure TSourceEditor.SelectLine;
4563begin
4564  EditorComponent.SelectLine;
4565end;
4566
4567procedure TSourceEditor.SelectParagraph;
4568begin
4569  EditorComponent.SelectParagraph;
4570end;
4571
4572function TSourceEditor.CommentText(const Txt: string; CommentType: TCommentType
4573  ): string;
4574var
4575  i: integer;
4576begin
4577  Result:=Txt;
4578  case CommentType of
4579    comtNone: exit;
4580    comtDefault:
4581      begin
4582        i:=EditorOpts.HighlighterList.FindByHighlighter(FEditor.Highlighter);
4583        if i>=0 then
4584          CommentType:=EditorOpts.HighlighterList[i].DefaultCommentType;
4585      end;
4586  end;
4587  Result:=LazStringUtils.CommentText(Txt,CommentType);
4588end;
4589
4590procedure TSourceEditor.InsertCharacterFromMap;
4591begin
4592  ShowCharacterMap(@SourceNotebook.InsertCharacter);
4593end;
4594
4595procedure TSourceEditor.InsertLicenseNotice(const Notice: string;
4596  CommentType: TCommentType);
4597var
4598  Txt: string;
4599begin
4600  if ReadOnly then Exit;
4601  Txt:=CommentText(BreakString(Notice, FEditor.RightEdge-2,0),CommentType);
4602  FEditor.InsertTextAtCaret(Txt);
4603end;
4604
4605procedure TSourceEditor.InsertGPLNotice(CommentType: TCommentType;
4606  Translated: boolean);
4607var
4608  s: String;
4609begin
4610  if Translated then
4611    s:=lisGPLNotice
4612  else
4613    s:=EnglishGPLNotice;
4614  InsertLicenseNotice(s, CommentType);
4615end;
4616
4617procedure TSourceEditor.InsertLGPLNotice(CommentType: TCommentType;
4618  Translated: boolean);
4619var
4620  s: String;
4621begin
4622  if Translated then
4623    s:=lisLGPLNotice
4624  else
4625    s:=EnglishLGPLNotice;
4626  InsertLicenseNotice(s, CommentType);
4627end;
4628
4629procedure TSourceEditor.InsertModifiedLGPLNotice(CommentType: TCommentType;
4630  Translated: boolean);
4631var
4632  s: String;
4633begin
4634  if Translated then
4635    s:=lisModifiedLGPLNotice
4636  else
4637    s:=EnglishModifiedLGPLNotice;
4638  InsertLicenseNotice(s, CommentType);
4639end;
4640
4641procedure TSourceEditor.InsertMITNotice(CommentType: TCommentType;
4642  Translated: boolean);
4643var
4644  s: String;
4645begin
4646  if Translated then
4647    s:=lisMITNotice
4648  else
4649    s:=EnglishMITNotice;
4650  InsertLicenseNotice(s, CommentType);
4651end;
4652
4653procedure TSourceEditor.InsertUsername;
4654begin
4655  if ReadOnly then Exit;
4656  FEditor.InsertTextAtCaret(GetCurrentUserName);
4657end;
4658
4659procedure TSourceEditor.InsertDateTime;
4660begin
4661  if ReadOnly then Exit;
4662  FEditor.InsertTextAtCaret(DateTimeToStr(now));
4663end;
4664
4665procedure TSourceEditor.InsertChangeLogEntry;
4666var s: string;
4667begin
4668  if ReadOnly then Exit;
4669  s:=DateToStr(now)+'   '+GetCurrentUserName+' '+GetCurrentChangeLog;
4670  FEditor.InsertTextAtCaret(s);
4671end;
4672
4673procedure TSourceEditor.InsertCVSKeyword(const AKeyWord: string);
4674begin
4675  if ReadOnly then Exit;
4676  FEditor.InsertTextAtCaret('$'+AKeyWord+'$'+LineEnding);
4677end;
4678
4679procedure TSourceEditor.InsertGUID;
4680const
4681  cGUID = '[''%s'']'; // The format of the GUID used for Interfaces
4682var
4683  lGUID: TGUID;
4684begin
4685  if ReadOnly then Exit;
4686  CreateGUID(lGUID);
4687  FEditor.InsertTextAtCaret(Format(cGUID, [GUIDToString(lGUID)]));
4688end;
4689
4690procedure TSourceEditor.InsertFilename;
4691var
4692  Dlg: TIDEOpenDialog;
4693begin
4694  if ReadOnly then Exit;
4695  Dlg:=IDEOpenDialogClass.Create(nil);
4696  try
4697    InitIDEFileDialog(Dlg);
4698    Dlg.Title:=lisSelectFile;
4699    if not Dlg.Execute then exit;
4700    FEditor.InsertTextAtCaret(Dlg.FileName);
4701  finally
4702    Dlg.Free;
4703  end;
4704end;
4705
4706function TSourceEditor.GetSelEnd: Integer;
4707begin
4708  Result:=FEditor.SelEnd;
4709end;
4710
4711function TSourceEditor.GetSelStart: Integer;
4712begin
4713  Result:=FEditor.SelStart;
4714end;
4715
4716procedure TSourceEditor.SetSelEnd(const AValue: Integer);
4717begin
4718  FEditor.SelEnd:=AValue;
4719end;
4720
4721procedure TSourceEditor.SetSelStart(const AValue: Integer);
4722begin
4723  FEditor.SelStart:=AValue;
4724end;
4725
4726function TSourceEditor.GetSelection: string;
4727begin
4728  Result:=FEditor.SelText;
4729end;
4730
4731procedure TSourceEditor.SetSelection(const AValue: string);
4732begin
4733  FEditor.SelText:=AValue;
4734end;
4735
4736procedure TSourceEditor.CopyToClipboard;
4737begin
4738  FEditor.CopyToClipboard;
4739end;
4740
4741procedure TSourceEditor.CutToClipboard;
4742begin
4743  FEditor.CutToClipboard;
4744end;
4745
4746function TSourceEditor.GetBookMark(BookMark: Integer; out X, Y: Integer): Boolean;
4747begin
4748  X := 0; Y := 0;
4749  Result := FEditor.GetBookMark(BookMark, X, Y);
4750end;
4751
4752procedure TSourceEditor.SetBookMark(BookMark: Integer; X, Y: Integer);
4753begin
4754  FEditor.SetBookMark(BookMark, X, Y);
4755end;
4756
4757procedure TSourceEditor.ExportAsHtml(AFileName: String);
4758var
4759  Html: TSynExporterHTML;
4760begin
4761  Html := TSynExporterHTML.Create(nil);
4762  try
4763    Html.Clear;
4764    Html.ExportAsText := True;
4765    Html.Highlighter := FEditor.Highlighter;
4766    Html.Title := PageName;
4767    Html.ExportAll(FEditor.Lines);
4768    Html.SaveToFile(AFileName);
4769  finally
4770    Html.Free;
4771  end;
4772end;
4773
4774procedure TSourceEditor.FindHelpForSourceAtCursor;
4775begin
4776  //DebugLn('TSourceEditor.FindHelpForSourceAtCursor A');
4777  ShowHelpOrErrorForSourcePosition(Filename,FEditor.LogicalCaretXY);
4778end;
4779
4780procedure TSourceEditor.OnGutterClick(Sender: TObject; X, Y, Line: integer;
4781  Mark: TSynEditMark);
4782var
4783  Marks: PSourceMark;
4784  i, MarkCount: Integer;
4785  BreakFound: Boolean;
4786  Ctrl: Boolean;
4787  ABrkPoint: TIDEBreakPoint;
4788  Mrk: TSourceMark;
4789begin
4790  // create or delete breakpoint
4791  // find breakpoint Mark at line
4792  Marks := nil;
4793  Ctrl := SYNEDIT_LINK_MODIFIER in GetKeyShiftState;
4794  try
4795    SourceEditorMarks.GetMarksForLine(Self, Line, Marks, MarkCount);
4796    BreakFound := False;
4797    for i := 0 to MarkCount - 1 do
4798    begin
4799      Mrk := Marks[i];
4800      if Mrk.IsBreakPoint and
4801        (Mrk.Data <> nil) and (Mrk.Data is TIDEBreakPoint)
4802      then begin
4803        BreakFound := True;
4804        if Ctrl then
4805          TIDEBreakPoint(Mrk.Data).Enabled := not TIDEBreakPoint(Mrk.Data).Enabled
4806        else
4807          DebugBoss.DoDeleteBreakPointAtMark(Mrk)
4808      end;
4809    end;
4810  finally
4811    FreeMem(Marks);
4812  end;
4813
4814  if not BreakFound then begin
4815    DebugBoss.LockCommandProcessing;
4816    try
4817      DebugBoss.DoCreateBreakPoint(Filename, Line, True, ABrkPoint, True);
4818      if Ctrl and (ABrkPoint <> nil)
4819      then ABrkPoint.Enabled := False;
4820    finally
4821      if ABrkPoint <> nil then
4822        ABrkPoint.EndUpdate;
4823      DebugBoss.UnLockCommandProcessing;
4824    end;
4825  end;
4826end;
4827
4828procedure TSourceEditor.OnEditorSpecialLineColor(Sender: TObject; Line: integer;
4829  var Special: boolean; Markup: TSynSelectedColor);
4830var
4831  i:integer;
4832  aha: TAdditionalHilightAttribute;
4833  CurMarks: PSourceMark;
4834  CurMarkCount: integer;
4835  CurFG: TColor;
4836  CurBG: TColor;
4837begin
4838  aha := ahaNone;
4839  Special := False;
4840
4841  if ErrorLine = Line
4842  then begin
4843    aha := ahaErrorLine
4844  end
4845  else begin
4846    SourceEditorMarks.GetMarksForLine(Self, Line, CurMarks, CurMarkCount);
4847    if CurMarkCount > 0 then
4848    begin
4849      for i := 0 to CurMarkCount - 1 do
4850      begin
4851        if not CurMarks[i].Visible then
4852          Continue;
4853        // check highlight attribute
4854        aha := CurMarks[i].LineColorAttrib;
4855        if aha <> ahaNone then Break;
4856
4857        // check custom colors
4858        CurFG := CurMarks[i].LineColorForeGround;
4859        CurBG := CurMarks[i].LineColorBackGround;
4860        if (CurFG <> clNone) or (CurBG <> clNone) then
4861        begin
4862          Markup.Foreground := CurFG;
4863          Markup.Background := CurBG;
4864          Special := True;
4865          break;
4866        end;
4867      end;
4868      // clean up
4869      FreeMem(CurMarks);
4870    end;
4871  end;
4872
4873  if aha <> ahaNone
4874  then begin
4875    Special := True;
4876    EditorOpts.SetMarkupColor(TCustomSynEdit(Sender).Highlighter, aha, Markup);
4877  end;
4878end;
4879
4880procedure TSourceEditor.SetSyntaxHighlighterType(AHighlighterType: TLazSyntaxHighlighter);
4881var
4882  HlIsPas, OldHlIsPas: Boolean;
4883begin
4884  if (AHighlighterType=fSyntaxHighlighterType)
4885  and ((FEditor.Highlighter<>nil) = EditorOpts.UseSyntaxHighlight) then exit;
4886
4887  OldHlIsPas := FEditor.Highlighter is TSynPasSyn;
4888  HlIsPas := False;
4889  if EditorOpts.UseSyntaxHighlight then begin
4890    if Highlighters[AHighlighterType]=nil then
4891      Highlighters[AHighlighterType]:=EditorOpts.CreateSyn(AHighlighterType);
4892    FEditor.Highlighter:=Highlighters[AHighlighterType];
4893    HlIsPas := FEditor.Highlighter is TSynPasSyn;
4894  end
4895  else
4896    FEditor.Highlighter:=nil;
4897
4898  if (OldHlIsPas <>  HlIsPas) then begin
4899    if HlIsPas then
4900      FEditor.Beautifier := PasBeautifier
4901    else
4902      FEditor.Beautifier := nil; // use default
4903    EditorOpts.GetSynEditSettings(FEditor, nil);
4904  end;
4905
4906  FSyntaxHighlighterType:=AHighlighterType;
4907  SourceNotebook.UpdateActiveEditColors(FEditor);
4908end;
4909
4910procedure TSourceEditor.SetErrorLine(NewLine: integer);
4911begin
4912  if fErrorLine=NewLine then exit;
4913  fErrorLine:=NewLine;
4914  fErrorColumn:=EditorComponent.CaretX;
4915  EditorComponent.Invalidate;
4916end;
4917
4918procedure TSourceEditor.UpdateExecutionSourceMark;
4919var
4920  BreakPoint: TIDEBreakPoint;
4921  ExecutionMark: TSourceMark;
4922  BrkMark: TSourceMark;
4923begin
4924  if FSharedValues.UpdatingExecutionMark > 0 then exit;
4925  ExecutionMark := FSharedValues.ExecutionMark;
4926  if ExecutionMark = nil then exit;
4927
4928  inc(FSharedValues.UpdatingExecutionMark);
4929  try
4930    if ExecutionMark.Visible then
4931    begin
4932      BrkMark := SourceEditorMarks.FindBreakPointMark(Self, ExecutionLine);
4933      if BrkMark <> nil then begin
4934        BrkMark.Visible := False;
4935        BreakPoint := DebugBoss.BreakPoints.Find(Self.FileName, ExecutionLine);
4936        if (BreakPoint <> nil) and (not BreakPoint.Enabled) then
4937          ExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineDisabledBreakPointImg
4938        else
4939          ExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineBreakPointImg;
4940      end
4941      else
4942        ExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineImg;
4943    end;
4944  finally
4945    dec(FSharedValues.UpdatingExecutionMark);
4946  end;
4947end;
4948
4949procedure TSourceEditor.SetExecutionLine(NewLine: integer);
4950begin
4951  if ExecutionLine=NewLine then exit;
4952  FSharedValues.SetExecutionLine(NewLine);
4953  UpdateExecutionSourceMark;
4954end;
4955
4956function TSourceEditor.RefreshEditorSettings: Boolean;
4957var
4958  SimilarEditor: TSynEdit;
4959Begin
4960  Result:=true;
4961  SetSyntaxHighlighterType(fSyntaxHighlighterType);
4962
4963  // try to copy settings from an editor to the left
4964  SimilarEditor:=nil;
4965  if (SourceNotebook.EditorCount>0) and (SourceNotebook.Editors[0]<>Self) then
4966    SimilarEditor:=SourceNotebook.Editors[0].EditorComponent;
4967  EditorOpts.GetSynEditSettings(FEditor,SimilarEditor);
4968
4969  SourceNotebook.UpdateActiveEditColors(FEditor);
4970  if Visible then
4971    UpdateIfDefNodeStates(True);
4972end;
4973
4974function TSourceEditor.AutoCompleteChar(Char: TUTF8Char; var AddChar: boolean;
4975  Category: TAutoCompleteOption): boolean;
4976// returns true if handled
4977var
4978  AToken: String;
4979  i, x1, x2: Integer;
4980  p: TPoint;
4981  Line: String;
4982  CatName: String;
4983  SrcToken: String;
4984  IdChars: TSynIdentChars;
4985  WordToken: String;
4986begin
4987  Result:=false;
4988  Line:=GetLineText;
4989  p:=GetCursorTextXY;
4990  if (p.x>length(Line)+1) or (Line='') then exit;
4991  CatName:=AutoCompleteOptionNames[Category];
4992
4993  FEditor.GetWordBoundsAtRowCol(p, x1, x2);
4994  // use the token left of the caret
4995  x2 := Min(x2, p.x);
4996  WordToken := copy(Line, x1, x2-x1);
4997  IdChars := FEditor.IdentChars;
4998  for i:=0 to Manager.CodeTemplateModul.Completions.Count-1 do begin
4999    AToken:=Manager.CodeTemplateModul.Completions[i];
5000    if AToken='' then continue;
5001    if AToken[1] in IdChars then
5002      SrcToken:=WordToken
5003    else
5004      SrcToken:=copy(Line,length(Line)-length(AToken)+1,length(AToken));
5005    //DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
5006    if (UTF8CompareLatinTextFast(AToken,SrcToken)=0)
5007    and (Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)>=0)
5008    and ( (not FEditor.SelAvail) or
5009          (Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(
5010             AutoCompleteOptionNames[acoIgnoreForSelection]) < 0)  )
5011    then begin
5012      Result:=true;
5013      //DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
5014      Manager.CodeTemplateModul.ExecuteCompletion(AToken,FEditor);
5015      AddChar:=not Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(
5016                                     AutoCompleteOptionNames[acoRemoveChar])>=0;
5017      exit;
5018    end;
5019  end;
5020
5021  if EditorOpts.AutoBlockCompletion
5022  and (SyntaxHighlighterType in [lshFreePascal,lshDelphi]) then
5023    Result:=AutoBlockCompleteChar(Char,AddChar,Category,p,Line);
5024end;
5025
5026function TSourceEditor.AutoBlockCompleteChar(Char: TUTF8Char;
5027  var AddChar: boolean; Category: TAutoCompleteOption; aTextPos: TPoint;
5028  Line: string): boolean;
5029// returns true if handled
5030var
5031  x1: integer;
5032  x2: integer;
5033  WordToken: String;
5034  p: LongInt;
5035  StartPos: integer;
5036  s: String;
5037begin
5038  Result:=false;
5039  if (not EditorOpts.AutoBlockCompletion)
5040  or (not (SyntaxHighlighterType in [lshFreePascal,lshDelphi])) then
5041    exit;
5042  FEditor.GetWordBoundsAtRowCol(aTextPos, x1, x2);
5043  // use the token left of the caret
5044  x2 := Min(x2, aTextPos.x);
5045  WordToken := copy(Line, x1, x2-x1);
5046  if (Category in [acoSpace])
5047  and ((SysUtils.CompareText(WordToken,'if')=0)
5048    or (SysUtils.CompareText(WordToken,'while')=0)
5049    or (SysUtils.CompareText(WordToken,'for')=0)
5050    )
5051  then begin
5052    p:=x2;
5053    ReadRawNextPascalAtom(Line,p,StartPos);
5054    if SysUtils.CompareText(copy(Line,StartPos,p-StartPos),'begin')=0 then begin
5055      // 'if begin' => insert 'then'
5056      // 'while begin' => insert 'do'
5057      // 'for begin' => insert 'do'
5058      Result:=true;
5059      if (SysUtils.CompareText(WordToken,'if')=0) then
5060        s:='then'
5061      else
5062        s:='do';
5063      s:=' '+CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.BeautifyKeyWord(s);
5064      if not (Line[x2] in [' ',#9]) then
5065        s:=s+' ';
5066      FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.AutoBlockCompleteChar'){$ENDIF};
5067      try
5068        FEditor.InsertTextAtCaret(s);
5069        FEditor.LogicalCaretXY:=aTextPos;
5070      finally
5071        FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.AutoBlockCompleteChar'){$ENDIF};
5072      end;
5073    end;
5074  end;
5075end;
5076
5077function TSourceEditor.AutoBlockCompleteChar(Char: TUTF8Char): boolean;
5078var
5079  p: TPoint;
5080  x1: integer;
5081  x2: integer;
5082  Line: String;
5083  WordToken: String;
5084begin
5085  Result:=false;
5086  if (not EditorOpts.AutoBlockCompletion)
5087  or (not (SyntaxHighlighterType in [lshFreePascal,lshDelphi])) then
5088    exit;
5089  p:=GetCursorTextXY;
5090  FEditor.GetWordBoundsAtRowCol(p, x1, x2);
5091  Line:=GetLineText;
5092  WordToken := copy(Line, x1, x2-x1);
5093  if (SysUtils.CompareText(WordToken,'begin')=0)
5094  then begin
5095    debugln(['TSourceEditor.AutoBlockCompleteChar ']);
5096    // user typed 'begin'
5097    LazarusIDE.SaveSourceEditorChangesToCodeCache(self);
5098    FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.AutoBlockCompleteChar (2)'){$ENDIF};
5099    FEditor.BeginUpdate;
5100    try
5101      if not CodeToolBoss.CompleteBlock(CodeBuffer,p.X,p.Y,true) then exit;
5102    finally
5103      FEditor.EndUpdate;
5104      FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.AutoBlockCompleteChar (2)'){$ENDIF};
5105    end;
5106  end;
5107end;
5108
5109procedure TSourceEditor.AutoCompleteBlock;
5110var
5111  XY: TPoint;
5112  NewCode: TCodeBuffer;
5113  NewX, NewY, NewTopLine: integer;
5114begin
5115  LazarusIDE.SaveSourceEditorChangesToCodeCache(Self);
5116  XY:=FEditor.LogicalCaretXY;
5117  FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.AutoCompleteBlock'){$ENDIF};
5118  FEditor.BeginUpdate;
5119  try
5120    if not CodeToolBoss.CompleteBlock(CodeBuffer,XY.X,XY.Y,false,
5121                                      NewCode,NewX,NewY,NewTopLine) then exit;
5122    XY:=FEditor.LogicalCaretXY;
5123    //DebugLn(['TSourceEditor.AutoCompleteBlock XY=',dbgs(XY),' NewX=',NewX,' NewY=',NewY]);
5124    if (NewCode<>CodeBuffer) or (NewX<>XY.X) or (NewY<>XY.Y) or (NewTopLine>0)
5125    then begin
5126      XY.X:=NewX;
5127      XY.Y:=NewY;
5128      FEditor.LogicalCaretXY:=XY;
5129    end;
5130  finally
5131    FEditor.EndUpdate;
5132    FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.AutoCompleteBlock'){$ENDIF};
5133  end;
5134end;
5135
5136procedure TSourceEditor.UpdateNoteBook(const ANewNoteBook: TSourceNotebook; ANewPage: TTabSheet);
5137begin
5138  if FSourceNoteBook = ANewNoteBook then exit;
5139
5140  FSourceNoteBook := ANewNoteBook;
5141  FAOwner := ANewNoteBook;
5142  FPageName := ANewNoteBook.NoteBookPages[ANewNoteBook.NoteBookIndexOfPage(ANewPage)];
5143
5144  EditorComponent.Parent := nil;
5145  // Change the Owner of the SynEdit
5146  EditorComponent.Owner.RemoveComponent(EditorComponent);
5147  FSourceNoteBook.InsertComponent(EditorComponent);
5148  // And the Parent
5149  EditorComponent.Parent := ANewPage;
5150end;
5151
5152{ AOwner is the TSourceNotebook
5153  AParent is a page of the TPageControl }
5154procedure TSourceEditor.CreateEditor(AOwner: TComponent; AParent: TWinControl);
5155var
5156  NewName: string;
5157  i: integer;
5158  bmp: TCustomBitmap;
5159Begin
5160  {$IFDEF IDE_DEBUG}
5161  debugln('TSourceEditor.CreateEditor  A ');
5162  {$ENDIF}
5163  if not assigned(FEditor) then Begin
5164    FVisible := False;
5165    i:=0;
5166    repeat
5167      inc(i);
5168      NewName:='SynEdit'+IntToStr(i);
5169    until (AOwner.FindComponent(NewName)=nil);
5170    FEditor := TIDESynEditor.Create(AOwner);
5171    FEditor.BeginUpdate;
5172    with FEditor do begin
5173      Name:=NewName;
5174      Text:='';
5175      Align := alClient;
5176      Visible := False;
5177      BookMarkOptions.EnableKeys := false;
5178      BookMarkOptions.LeftMargin:=1;
5179      BookMarkOptions.BookmarkImages := SourceEditorMarks.ImgList;
5180      Gutter.MarksPart.DebugMarksImageIndex := SourceEditorMarks.SourceLineImg;
5181      WantTabs := true;
5182      ScrollBars := ssAutoBoth;
5183
5184      // IMPORTANT: when you change below, don't forget updating UnbindEditor
5185      OnStatusChange := @EditorStatusChanged;
5186      OnProcessCommand := @ProcessCommand;
5187      OnProcessUserCommand := @ProcessUserCommand;
5188      OnCommandProcessed := @UserCommandProcessed;
5189      OnReplaceText := @OnReplace;
5190      OnGutterClick := @Self.OnGutterClick;
5191      OnSpecialLineMarkup := @OnEditorSpecialLineColor;
5192      OnMouseMove := @EditorMouseMoved;
5193      OnMouseWheel := @EditorMouseWheel;
5194      OnMouseDown := @EditorMouseDown;
5195      OnMouseUp := @EditorMouseUp;
5196      OnClickLink := Manager.OnClickLink;
5197      OnMouseLink := Manager.OnMouseLink;
5198      OnKeyDown := @EditorKeyDown;
5199      OnKeyUp := @EditorKeyUp;
5200      OnPaste:=@EditorPaste;
5201      OnEnter:=@EditorEnter;
5202      OnPlaceBookmark := @EditorPlaceBookmark;
5203      OnClearBookmark := @EditorClearBookmark;
5204      OnChangeUpdating  := @EditorChangeUpdating;
5205      OnMultiCaretBeforeCommand := @DoMultiCaretBeforeCommand;
5206      RegisterMouseActionExecHandler(@EditorHandleMouseAction);
5207      // IMPORTANT: when you change above, don't forget updating UnbindEditor
5208      Parent := AParent;
5209      if AParent.Font.PixelsPerInch<>96 then
5210        AutoAdjustLayout(lapAutoAdjustForDPI, 96, AParent.Font.PixelsPerInch, 0, 0);
5211    end;
5212    Manager.CodeTemplateModul.AddEditor(FEditor);
5213    Manager.FMacroRecorder.AddEditor(FEditor);
5214    Manager.NewEditorCreated(self);
5215    FEditor.TemplateEdit.OnActivate := @EditorActivateSyncro;
5216    FEditor.TemplateEdit.OnDeactivate := @EditorDeactivateSyncro;
5217    bmp := CreateBitmapFromResourceName(HInstance, 'tsynsyncroedit');
5218    FEditor.SyncroEdit.GutterGlyph.Assign(bmp);
5219    bmp.Free;
5220    FEditor.SyncroEdit.OnBeginEdit := @EditorActivateSyncro;
5221    FEditor.SyncroEdit.OnEndEdit := @EditorDeactivateSyncro;
5222
5223    RefreshEditorSettings;
5224    FEditor.EndUpdate;
5225  end else begin
5226    FEditor.Parent:=AParent;
5227  end;
5228end;
5229
5230procedure TSourceEditor.SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
5231begin
5232  FSharedValues.CodeBuffer := NewCodeBuffer;
5233end;
5234
5235procedure TSourceEditor.StartIdentCompletionBox(JumpToError,
5236  CanAutoComplete: boolean);
5237var
5238  I: Integer;
5239  TextS, TextS2: String;
5240  LogCaret: TPoint;
5241  UseWordCompletion: Boolean;
5242  Completion: TSourceEditCompletion;
5243  CompletionRect: TRect;
5244begin
5245  {$IFDEF VerboseIDECompletionBox}
5246  debugln(['TSourceEditor.StartIdentCompletionBox JumpToError: ',JumpToError]);
5247  {$ENDIF}
5248  if (FEditor.ReadOnly) then exit;
5249  Completion := Manager.DefaultCompletionForm;
5250  if (Completion.CurrentCompletionType<>ctNone) then exit;
5251  Completion.IdentCompletionJumpToError := JumpToError;
5252  Completion.CurrentCompletionType:=ctIdentCompletion;
5253  TextS := FEditor.LineText;
5254  LogCaret:=FEditor.LogicalCaretXY;
5255  Completion.Editor:=FEditor;
5256  i := LogCaret.X - 1;
5257  if i > length(TextS) then
5258    TextS2 := ''
5259  else begin
5260    while (i > 0) and (TextS[i] in ['a'..'z','A'..'Z','0'..'9','_']) do
5261      dec(i);
5262    TextS2 := Trim(copy(TextS, i + 1, LogCaret.X - i - 1));
5263  end;
5264  UseWordCompletion:=false;
5265  CompletionRect := Manager.GetScreenRectForToken(FEditor, FEditor.CaretX-length(TextS2), FEditor.CaretY, FEditor.CaretX-1);
5266
5267  if not Manager.FindIdentCompletionPlugin
5268    (Self, JumpToError, TextS2, CompletionRect.Top, CompletionRect.Left, UseWordCompletion)
5269  then
5270    exit;
5271  if UseWordCompletion then
5272    Completion.CurrentCompletionType:=ctWordCompletion;
5273
5274  Completion.AutoUseSingleIdent := CanAutoComplete and
5275    (FCodeCompletionState.State = ccsDot) and
5276    CodeToolsOpts.IdentComplAutoUseSingleIdent;
5277  Completion.Execute(TextS2, CompletionRect);
5278  {$IFDEF VerboseIDECompletionBox}
5279  debugln(['TSourceEditor.StartIdentCompletionBox END Completion.TheForm.Visible=',Completion.TheForm.Visible]);
5280  {$ENDIF}
5281end;
5282
5283procedure TSourceEditor.StartWordCompletionBox;
5284var
5285  TextS: String;
5286  LogCaret: TPoint;
5287  i: Integer;
5288  TextS2: String;
5289  Completion: TSourceEditCompletion;
5290begin
5291  if (FEditor.ReadOnly) then exit;
5292  Completion := Manager.DefaultCompletionForm;
5293  if (Completion.CurrentCompletionType<>ctNone) then exit;
5294  Completion.CurrentCompletionType:=ctWordCompletion;
5295  TextS := FEditor.LineText;
5296  LogCaret:=FEditor.LogicalCaretXY;
5297  Completion.Editor:=FEditor;
5298  i := LogCaret.X - 1;
5299  if i > length(TextS) then
5300    TextS2 := ''
5301  else begin
5302    while (i > 0) and (TextS[i] in ['a'..'z','A'..'Z','0'..'9','_']) do
5303      dec(i);
5304    TextS2 := Trim(copy(TextS, i + 1, LogCaret.X - i - 1));
5305  end;
5306  Completion.Execute
5307    (TextS2, Manager.GetScreenRectForToken(FEditor, FEditor.CaretX-length(TextS2), FEditor.CaretY, FEditor.CaretX-1));
5308end;
5309
5310procedure TSourceEditor.IncreaseIgnoreCodeBufferLock;
5311begin
5312  FSharedValues.IncreaseIgnoreCodeBufferLock;
5313end;
5314
5315procedure TSourceEditor.DecreaseIgnoreCodeBufferLock;
5316begin
5317  FSharedValues.DecreaseIgnoreCodeBufferLock;
5318end;
5319
5320procedure TSourceEditor.UpdateCodeBuffer;
5321// copy the source from EditorComponent to codetools
5322begin
5323  FSharedValues.UpdateCodeBuffer;
5324end;
5325
5326function TSourceEditor.NeedsUpdateCodeBuffer: boolean;
5327begin
5328  Result := FSharedValues.NeedsUpdateCodeBuffer;
5329end;
5330
5331procedure TSourceEditor.ConnectScanner(Scanner: TLinkScanner);
5332begin
5333  FSharedValues.ConnectScanner(Scanner);
5334end;
5335
5336function TSourceEditor.GetSource: TStrings;
5337Begin
5338  //return synedit's source.
5339  Result := FEditor.Lines;
5340end;
5341
5342procedure TSourceEditor.SetIsLocked(const AValue: Boolean);
5343begin
5344  if FIsLocked = AValue then exit;
5345  FIsLocked := AValue;
5346  UpdatePageName;
5347  SourceNotebook.UpdateStatusBar;
5348  UpdateProjectFile;
5349end;
5350
5351procedure TSourceEditor.SetPageName(const AValue: string);
5352begin
5353  if FPageName=AValue then exit;
5354  FPageName:=AValue;
5355  UpdatePageName;
5356end;
5357
5358procedure TSourceEditor.UpdatePageName;
5359var
5360  p: Integer;
5361  NewPageCaption: String;
5362begin
5363  if SourceNotebook.FUpdateLock > 0 then begin
5364    include(SourceNotebook.FUpdateFlags, ufPageNames);
5365    exit;
5366  end;
5367  p:=SourceNotebook.FindPageWithEditor(Self);
5368  if EditorOpts.ShowTabNumbers and (p < 10) then
5369    // Number pages 1, ..., 9, 0 -- according to Alt+N hotkeys.
5370    NewPageCaption:=Format('%s:%d', [FPageName, (p+1) mod 10])
5371  else
5372    NewPageCaption:=FPageName;
5373  if IsLocked then NewPageCaption:='#'+NewPageCaption;
5374  if Modified then NewPageCaption:='*'+NewPageCaption;
5375  if SourceNotebook.NoteBookPages[p] <> NewPageCaption then begin
5376    SourceNotebook.NoteBookPages[p] := NewPageCaption;
5377    SourceNotebook.UpdateTabsAndPageTitle;
5378    SourceNotebook.CallOnEditorPageCaptionUpdate(Self);
5379  end;
5380end;
5381
5382procedure TSourceEditor.SetSource(Value: TStrings);
5383Begin
5384  FEditor.Lines.Assign(Value);
5385end;
5386
5387function TSourceEditor.GetCurrentCursorXLine: Integer;
5388Begin
5389  Result := FEditor.CaretX
5390end;
5391
5392procedure TSourceEditor.SetCurrentCursorXLine(num: Integer);
5393Begin
5394  FEditor.CaretX := Num;
5395end;
5396
5397function TSourceEditor.GetCurrentCursorYLine: Integer;
5398Begin
5399  Result := FEditor.CaretY;
5400end;
5401
5402procedure TSourceEditor.SetCurrentCursorYLine(num: Integer);
5403Begin
5404  FEditor.CaretY := Num;
5405end;
5406
5407procedure TSourceEditor.SelectText(const StartPos, EndPos: TPoint);
5408Begin
5409  FEditor.BlockBegin := StartPos;
5410  FEditor.BlockEnd := EndPos;
5411end;
5412
5413procedure TSourceEditor.InsertLine(StartLine: Integer; const NewText: String;
5414  aKeepMarks: Boolean);
5415const
5416  MarksMode: array[Boolean] of TSynMarksAdjustMode = (smaMoveUp, smaKeep);
5417var
5418  Pt: TPoint;
5419begin
5420  if not ReadOnly then
5421  begin
5422    if StartLine > 1 then
5423      Pt := Point(Length(FEditor.Lines[StartLine - 2]) + 1, StartLine - 1)
5424    else
5425      Pt := Point(1, 1);
5426    FEditor.SetTextBetweenPoints(Pt, Pt,
5427      LineEnding + NewText, [], scamEnd, MarksMode[aKeepMarks]);
5428  end;
5429end;
5430
5431procedure TSourceEditor.ReplaceLines(StartLine, EndLine: integer;
5432  const NewText: string; aKeepMarks: Boolean = False);
5433const
5434  MarksMode: array[Boolean] of TSynMarksAdjustMode = (smaMoveUp, smaKeep);
5435begin
5436  if not ReadOnly then
5437    FEditor.SetTextBetweenPoints(
5438      Point(1, StartLine),
5439      Point(Length(FEditor.Lines[Endline - 1]) + 1, EndLine),
5440      NewText, [], scamEnd, MarksMode[aKeepMarks]);
5441end;
5442
5443procedure TSourceEditor.EncloseSelection;
5444var
5445  EncloseType: TEncloseSelectionType;
5446  EncloseTemplate: string;
5447  NewSelection: string;
5448  NewCaretXY: TPoint;
5449begin
5450  if ReadOnly then exit;
5451  if not FEditor.SelAvail then
5452    exit;
5453  if ShowEncloseSelectionDialog(EncloseType)<>mrOk then exit;
5454  GetEncloseSelectionParams(EncloseType,EncloseTemplate);
5455  EncloseTextSelection(EncloseTemplate,FEditor.Lines,
5456                       FEditor.BlockBegin,FEditor.BlockEnd,
5457                       NewSelection,NewCaretXY);
5458  //debugln(['TSourceEditor.EncloseSelection A NewCaretXY=',NewCaretXY.X,',',NewCaretXY.Y,' "',NewSelection,'"']);
5459  FEditor.SelText:=NewSelection;
5460  FEditor.LogicalCaretXY:=NewCaretXY;
5461end;
5462
5463function TSourceEditor.GetModified: Boolean;
5464Begin
5465  Result := FSharedValues.Modified;
5466end;
5467
5468procedure TSourceEditor.SetModified(const NewValue: Boolean);
5469begin
5470  FSharedValues.SetModified(NewValue);
5471end;
5472
5473function TSourceEditor.GetInsertMode: Boolean;
5474Begin
5475  Result := FEditor.Insertmode;
5476end;
5477
5478function TSourceEditor.Close: Boolean;
5479Begin
5480  DebugLnEnter(SRCED_CLOSE, ['TSourceEditor.Close ShareCount=', FSharedValues.SharedEditorCount]);
5481  Result := True;
5482  Visible := False;
5483  Manager.EditorRemoved(Self);
5484  UnbindEditor;
5485  FEditor.Parent:=nil;
5486  if FSharedValues.SharedEditorCount = 1 then
5487    CodeBuffer := nil;
5488  DebugLnExit(SRCED_CLOSE, ['TSourceEditor.Close ']);
5489end;
5490
5491procedure TSourceEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF};
5492begin
5493  FEditor.BeginUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.BeginUndoBlock ' + ACaller){$ENDIF};
5494end;
5495
5496procedure TSourceEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}(ACaller: String = ''){$ENDIF};
5497begin
5498  FEditor.EndUndoBlock{$IFDEF SynUndoDebugBeginEnd}('TSourceEditor.EndUndoBlock ' + ACaller){$ENDIF};
5499end;
5500
5501procedure TSourceEditor.BeginUpdate;
5502begin
5503  FEditor.BeginUpdate;
5504end;
5505
5506procedure TSourceEditor.EndUpdate;
5507begin
5508  FEditor.EndUpdate;
5509end;
5510
5511procedure TSourceEditor.BeginGlobalUpdate;
5512begin
5513  FSharedValues.BeginGlobalUpdate;
5514end;
5515
5516procedure TSourceEditor.EndGlobalUpdate;
5517begin
5518  FSharedValues.EndGlobalUpdate;
5519end;
5520
5521procedure TSourceEditor.SetPopupMenu(NewPopupMenu: TPopupMenu);
5522begin
5523  if NewPopupMenu<>FPopupMenu then begin
5524    FPopupMenu:=NewPopupMenu;
5525    if FEditor<>nil then begin
5526      if FEditor.PopupMenu <> nil then // Todo: why?
5527        FEditor.PopupMenu.RemoveFreeNotification(FEditor);
5528      FEditor.PopupMenu:=NewPopupMenu;
5529    end;
5530  end;
5531end;
5532
5533function TSourceEditor.GetFilename: string;
5534begin
5535  if CodeBuffer <> nil then
5536    Result := CodeBuffer.Filename
5537  else
5538    Result := '';
5539end;
5540
5541function TSourceEditor.GetEditorControl: TWinControl;
5542begin
5543  Result:=FEditor;
5544end;
5545
5546function TSourceEditor.GetCodeToolsBuffer: TObject;
5547begin
5548  Result:=CodeBuffer;
5549end;
5550
5551procedure TSourceEditor.EditorPaste(Sender: TObject; var AText: String;
5552  var AMode: TSynSelectionMode; ALogStartPos: TPoint;
5553  var AnAction: TSynCopyPasteAction);
5554var
5555  p: integer;
5556  NestedComments: Boolean;
5557  NewIndent: TFABIndentationPolicy;
5558  Indent: LongInt;
5559  NewSrc: string;
5560  i: Integer;
5561  SemMode: TSemSelectionMode;
5562  SemAction: TSemCopyPasteAction;
5563begin
5564  if Assigned(Manager) then begin
5565    // call handlers
5566    i:=Manager.FHandlers[semhtCopyPaste].Count;
5567    while Manager.FHandlers[semhtCopyPaste].NextDownIndex(i) do begin
5568      SemMode:=TSemSelectionMode(AMode);
5569      SemAction:=TSemCopyPasteAction(AnAction);
5570      TSemCopyPasteEvent(Manager.FHandlers[semhtCopyPaste][i])(Self,AText,
5571        SemMode,ALogStartPos,SemAction);
5572      AMode:=TSynSelectionMode(SemMode);
5573      AnAction:=TSynCopyPasteAction(SemAction);
5574      if AnAction=scaAbort then exit;
5575    end;
5576  end;
5577
5578  if AMode<>smNormal then exit;
5579  if SyncroLockCount > 0 then exit;
5580  if not CodeToolsOpts.IndentOnPaste then exit;
5581  if not (SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
5582    exit;
5583  {$IFDEF VerboseIndenter}
5584  debugln(['TSourceEditor.EditorPaste LogCaret=',dbgs(ALogStartPos)]);
5585  {$ENDIF}
5586  if ALogStartPos.X>1 then exit;
5587  UpdateCodeBuffer;
5588  CodeBuffer.LineColToPosition(ALogStartPos.Y,ALogStartPos.X,p);
5589  if p<1 then exit;
5590  {$IFDEF VerboseIndenter}
5591  if ALogStartPos.Y>1 then
5592    DebugLn(['TSourceEditor.EditorPaste Y-1=',Lines[ALogStartPos.Y-2]]);
5593  DebugLn(['TSourceEditor.EditorPaste Y+0=',Lines[ALogStartPos.Y-1]]);
5594  if ALogStartPos.Y<LineCount then
5595    DebugLn(['TSourceEditor.EditorPaste Y+1=',Lines[ALogStartPos.Y+0]]);
5596  {$ENDIF}
5597  NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuffer.Filename);
5598  if not CodeToolBoss.Indenter.GetIndent(CodeBuffer.Source,p,NestedComments,
5599    true,NewIndent,CodeToolsOpts.IndentContextSensitive,AText)
5600  then exit;
5601  if not NewIndent.IndentValid then exit;
5602  Indent:=NewIndent.Indent-GetLineIndentWithTabs(AText,1,EditorComponent.TabWidth);
5603  {$IFDEF VerboseIndenter}
5604  debugln(AText);
5605  DebugLn(['TSourceEditor.EditorPaste Indent=',Indent]);
5606  {$ENDIF}
5607  IndentText(AText,Indent,EditorComponent.TabWidth,NewSrc);
5608  AText:=NewSrc;
5609  {$IFDEF VerboseIndenter}
5610  debugln(AText);
5611  DebugLn(['TSourceEditor.EditorPaste END']);
5612  {$ENDIF}
5613end;
5614
5615procedure TSourceEditor.EditorPlaceBookmark(Sender: TObject;
5616  var Mark: TSynEditMark);
5617begin
5618  if Assigned(Manager) and Assigned(Manager.OnPlaceBookmark) then
5619    Manager.OnPlaceBookmark(Self, Mark);
5620end;
5621
5622procedure TSourceEditor.EditorClearBookmark(Sender: TObject;
5623  var Mark: TSynEditMark);
5624begin
5625  if Assigned(Manager) and Assigned(Manager.OnClearBookmark) then
5626    Manager.OnClearBookmark(Self, Mark);
5627end;
5628
5629procedure TSourceEditor.EditorEnter(Sender: TObject);
5630var
5631  SrcEdit: TSourceEditor;
5632begin
5633  debugln(SRCED_PAGES, ['TSourceEditor.EditorEnter ']);
5634  if (FSourceNoteBook.FUpdateLock <> 0) or
5635     (FSourceNoteBook.FFocusLock <> 0)
5636  then exit;
5637  if (FSourceNoteBook.PageIndex = PageIndex) then
5638    Activate
5639  else begin
5640    SrcEdit:=SourceNotebook.GetActiveSE;
5641    if SrcEdit<>nil then
5642      SrcEdit.FocusEditor;
5643    // Navigating with mousebuttons between editors (eg jump history on btn 4/5)
5644    // can trigger the old editor to be refocused (while not visible)
5645  end;
5646end;
5647
5648procedure TSourceEditor.EditorActivateSyncro(Sender: TObject);
5649begin
5650  inc(FSyncroLockCount);
5651end;
5652
5653procedure TSourceEditor.EditorDeactivateSyncro(Sender: TObject);
5654begin
5655  dec(FSyncroLockCount);
5656end;
5657
5658function TSourceEditor.GetCodeBuffer: TCodeBuffer;
5659begin
5660  Result := FSharedValues.CodeBuffer;
5661end;
5662
5663function TSourceEditor.GetExecutionLine: integer;
5664begin
5665  Result := FSharedValues.ExecutionLine;
5666end;
5667
5668function TSourceEditor.GetHasExecutionMarks: Boolean;
5669begin
5670  Result := EditorComponent.IDEGutterMarks.HasDebugMarks;
5671end;
5672
5673function TSourceEditor.GetSharedEditors(Index: Integer): TSourceEditor;
5674begin
5675  Result := FSharedValues.SharedEditors[Index];
5676end;
5677
5678procedure TSourceEditor.EditorChangeUpdating(ASender: TObject; AnUpdating: Boolean);
5679begin
5680  // Calls may be unbalanced, because the event handler may not be assigned to the event on the first BeginUpdate
5681  If AnUpdating then begin
5682    //if FInEditorChangedUpdating then
5683    //  debugln(['***** TSourceEditor.EditorChangeUpdating: Updating=True, but FInEditorChangedUpdating was true already']);
5684    if not FInEditorChangedUpdating then begin
5685      FInEditorChangedUpdating := True;
5686      DebugBoss.LockCommandProcessing;
5687    end;
5688    FMouseActionPopUpMenu := nil;
5689  end else
5690  begin
5691    //if not FInEditorChangedUpdating then
5692    //  debugln(['***** TSourceEditor.EditorChangeUpdating: Updating=False, but FInEditorChangedUpdating was false already']);
5693    if FInEditorChangedUpdating then begin
5694      FInEditorChangedUpdating := False;  // set before unlocking
5695      DebugBoss.UnLockCommandProcessing;  // may lead to recursion
5696    end;
5697    //FMouseActionPopUpMenu :=
5698    if (FMouseActionPopUpMenu <> nil) then begin
5699      FMouseActionPopUpMenu.PopupComponent := FEditor;
5700      FMouseActionPopUpMenu.PopUp;
5701      FMouseActionPopUpMenu := nil;
5702    end;
5703  end;
5704end;
5705
5706function TSourceEditor.EditorHandleMouseAction(AnAction: TSynEditMouseAction;
5707  var AnInfo: TSynEditMouseActionInfo): Boolean;
5708begin
5709  Result := AnAction.Command = emcContextMenu;
5710  if not Result then exit;
5711
5712  case AnAction.Option2 of
5713    1: FMouseActionPopUpMenu := SourceNotebook.DbgPopUpMenu;
5714    2: FMouseActionPopUpMenu := SourceNotebook.TabPopUpMenu;
5715    else
5716      FMouseActionPopUpMenu := PopupMenu;
5717  end;
5718
5719  if (not FInEditorChangedUpdating) and (FMouseActionPopUpMenu <> nil) then begin
5720    FMouseActionPopUpMenu.PopupComponent := FEditor;
5721    FMouseActionPopUpMenu.PopUp;
5722    FMouseActionPopUpMenu := nil;
5723  end;
5724end;
5725
5726procedure TSourceEditor.EditorMouseMoved(Sender: TObject; Shift: TShiftState;
5727  X, Y: Integer);
5728begin
5729//  debugln('MouseMove in Editor',X,',',Y);
5730  if Assigned(OnMouseMove) then
5731    OnMouseMove(Self,Shift,X,Y);
5732end;
5733
5734procedure TSourceEditor.EditorMouseWheel(Sender: TObject; Shift: TShiftState;
5735  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
5736begin
5737//  debugln('MouseWheel in Editor');
5738  if Assigned(OnMouseWheel) then
5739    OnMouseWheel(Self, Shift, WheelDelta, MousePos, Handled)
5740end;
5741
5742procedure TSourceEditor.EditorMouseDown(Sender: TObject; Button: TMouseButton;
5743   Shift: TShiftState; X, Y: Integer);
5744begin
5745  CheckActiveWindow;
5746  if Assigned(OnMouseDown) then
5747    OnMouseDown(Sender, Button, Shift, X,Y);
5748
5749  if (Manager <> nil) then
5750    Manager.FChangeNotifyLists[semEditorMouseDown].CallNotifyEvents(Self);
5751end;
5752
5753procedure TSourceEditor.EditorMouseUp(Sender: TObject; Button: TMouseButton;
5754  Shift: TShiftState; X, Y: Integer);
5755begin
5756  if (Manager <> nil) then
5757    Manager.FChangeNotifyLists[semEditorMouseUp].CallNotifyEvents(Self);
5758end;
5759
5760procedure TSourceEditor.EditorKeyDown(Sender: TObject; var Key: Word;
5761  Shift: TShiftState);
5762begin
5763  //DebugLn(['TSourceEditor.EditorKeyDown A ',dbgsName(Sender),' Key=',IntToStr(Key),' File=',ExtractFileName(Filename),' Wnd=',dbgSourceNoteBook(SourceNotebook)]);
5764  CheckActiveWindow;
5765  if Assigned(OnKeyDown) then
5766    OnKeyDown(Sender, Key, Shift);
5767
5768  IDECommandList.PostponeUpdateEvents;
5769end;
5770
5771procedure TSourceEditor.EditorKeyUp(Sender: TObject; var Key: Word;
5772  Shift: TShiftState);
5773begin
5774  CheckActiveWindow;
5775  if Assigned(OnKeyUp) then
5776    OnKeyUp(Sender, Key, Shift);
5777
5778  IDECommandList.PostponeUpdateEvents;
5779end;
5780
5781{-------------------------------------------------------------------------------
5782  method TSourceEditor.CenterCursor
5783  Params: none
5784  Result: none
5785
5786  Center the current cursor line in editor.
5787-------------------------------------------------------------------------------}
5788procedure TSourceEditor.CenterCursor(SoftCenter: Boolean = False);
5789var
5790  Y, CurTopLine, LinesInWin, MinLines, NewTopLine: Integer;
5791begin
5792  LinesInWin := EditorComponent.LinesInWindow;
5793  CurTopLine := EditorComponent.TopView;
5794  Y := EditorComponent.TextIndexToViewPos(EditorComponent.CaretY);
5795
5796  if SoftCenter then begin
5797    MinLines := Min(
5798      Min( Max(LinesInWin div SoftCenterFactor, SoftCenterMinimum),
5799           SoftCenterMaximum),
5800      Max(LinesInWin div 2 - 1, 0) // make sure there is at least one line in the soft center
5801      );
5802
5803    if (Y <= CurTopLine) or (Y >= CurTopLine + LinesInWin) then
5804      // Caret not yet visible => hard-center
5805      NewTopLine := Max(1, Y - (LinesInWin div 2))
5806    else
5807    if Y < CurTopLine + MinLines then
5808      NewTopLine := Max(1, Y - MinLines)
5809    else
5810    if Y > CurTopLine + LinesInWin - MinLines then
5811      NewTopLine := Max(1, Y - LinesInWin + MinLines)
5812    else
5813      NewTopLine := CurTopLine;
5814  end
5815  else
5816    // not using SoftCenter
5817    NewTopLine := Max(1, Y - (LinesInWin div 2));
5818
5819  if NewTopLine < 1 then NewTopLine := 1;
5820  EditorComponent.TopView := NewTopLine;
5821end;
5822
5823procedure TSourceEditor.CenterCursorHoriz(HCMode: TSourceEditHCenterMode);
5824var
5825  i: Integer;
5826begin
5827  case HCMode of
5828    hcmCenter:
5829      with EditorComponent do begin
5830        LeftChar:=Max(LogicalCaretXY.X - (CharsInWindow div 2), 1);
5831      end;
5832    hcmCenterKeepEOL:
5833      with EditorComponent do begin
5834        i := LogicalToPhysicalPos(Point(Length(Lines[CaretY-1]) + 1, CaretY)).X;
5835        LeftChar:=Max(Min(LogicalCaretXY.X - (CharsInWindow div 2),
5836                          i - CharsInWindow
5837                         ), 1);
5838      end;
5839    hcmSoft:
5840      // TODO: offset on left side
5841      with EditorComponent do begin
5842        LeftChar:=Max(LogicalCaretXY.X - (CharsInWindow * 4 div 5), 1);
5843      end;
5844    hcmSoftKeepEOL:
5845      // TODO: offset on left side
5846      with EditorComponent do begin
5847        i := LogicalToPhysicalPos(Point(Length(Lines[CaretY-1]) + 1, CaretY)).X;
5848        LeftChar:=Max(Min(LogicalCaretXY.X - (CharsInWindow * 4 div 5),
5849                          i - CharsInWindow
5850                         ), 1);
5851      end;
5852  end;
5853end;
5854
5855function TSourceEditor.TextToScreenPosition(const Position: TPoint): TPoint;
5856begin
5857  Result:=FEditor.LogicalToPhysicalPos(Position);
5858end;
5859
5860function TSourceEditor.ScreenToTextPosition(const Position: TPoint): TPoint;
5861begin
5862  Result:=FEditor.PhysicalToLogicalPos(Position);
5863end;
5864
5865function TSourceEditor.ScreenToPixelPosition(const Position: TPoint): TPoint;
5866begin
5867  Result:=FEditor.ScreenXYToPixels(FEditor.TextXYToScreenXY(Position));
5868end;
5869
5870function TSourceEditor.LineCount: Integer;
5871begin
5872  Result:=FEditor.Lines.Count;
5873end;
5874
5875function TSourceEditor.WidthInChars: Integer;
5876begin
5877  Result:=FEditor.CharsInWindow;
5878end;
5879
5880function TSourceEditor.HeightInLines: Integer;
5881begin
5882  Result:=FEditor.LinesInWindow;
5883end;
5884
5885function TSourceEditor.CharWidth: integer;
5886begin
5887  Result:=FEditor.CharWidth;
5888end;
5889
5890function TSourceEditor.GetLineText: string;
5891begin
5892  Result:=FEditor.LineText;
5893end;
5894
5895procedure TSourceEditor.SetLineText(const AValue: string);
5896begin
5897  FEditor.LineText:=AValue;
5898end;
5899
5900function TSourceEditor.GetLines: TStrings;
5901begin
5902  Result:=FEditor.Lines;
5903end;
5904
5905function TSourceEditor.GetLinesInWindow: Integer;
5906begin
5907  Result := FEditor.LinesInWindow;
5908end;
5909
5910procedure TSourceEditor.SetLines(const AValue: TStrings);
5911begin
5912  FEditor.Lines:=AValue;
5913end;
5914
5915function TSourceEditor.CurrentWordLogStartOrCaret: TPoint;
5916var
5917  StartX, EndX: integer;
5918begin
5919  Result := FEditor.LogicalCaretXY;
5920  FEditor.GetWordBoundsAtRowCol(Result, StartX, EndX);
5921  if (Result.x >= StartX) and (Result.x <= EndX) then
5922    Result.x := StartX;
5923end;
5924
5925function TSourceEditor.GetProjectFile: TLazProjectFile;
5926begin
5927  Result:=LazarusIDE.GetProjectFileForProjectEditor(Self);
5928end;
5929
5930procedure TSourceEditor.UpdateProjectFile(AnUpdates: TSrcEditProjectUpdatesNeeded);
5931begin
5932  AnUpdates := AnUpdates + FProjectFileUpdatesNeeded;
5933  FProjectFileUpdatesNeeded := [];
5934  if Assigned(Manager) and Assigned(Manager.OnUpdateProjectFile)
5935    then Manager.OnUpdateProjectFile(self, AnUpdates);
5936end;
5937
5938function TSourceEditor.GetDesigner(LoadForm: boolean): TIDesigner;
5939begin
5940  Result:=LazarusIDE.GetDesignerForProjectEditor(Self, LoadForm)
5941end;
5942
5943function TSourceEditor.GetCursorScreenXY: TPoint;
5944begin
5945  Result:=FEditor.CaretXY;
5946end;
5947
5948function TSourceEditor.GetCursorTextXY: TPoint;
5949begin
5950  Result:=FEditor.LogicalCaretXY;
5951end;
5952
5953procedure TSourceEditor.SetCursorScreenXY(const AValue: TPoint);
5954begin
5955  FEditor.CaretXY:=AValue;
5956end;
5957
5958procedure TSourceEditor.SetCursorTextXY(const AValue: TPoint);
5959begin
5960  FEditor.LogicalCaretXY:=AValue;
5961end;
5962
5963function TSourceEditor.GetBlockBegin: TPoint;
5964begin
5965  Result:=FEditor.BlockBegin;
5966end;
5967
5968function TSourceEditor.GetBlockEnd: TPoint;
5969begin
5970  Result:=FEditor.BlockEnd;
5971end;
5972
5973procedure TSourceEditor.SetBlockBegin(const AValue: TPoint);
5974begin
5975  FEditor.BlockBegin:=AValue;
5976end;
5977
5978procedure TSourceEditor.SetBlockEnd(const AValue: TPoint);
5979begin
5980  FEditor.BlockEnd:=AValue;
5981end;
5982
5983function TSourceEditor.GetTopLine: Integer;
5984begin
5985  Result:=FEditor.TopLine;
5986end;
5987
5988procedure TSourceEditor.SetTopLine(const AValue: Integer);
5989begin
5990  FEditor.TopLine:=AValue;
5991end;
5992
5993function TSourceEditor.CursorInPixel: TPoint;
5994begin
5995  Result:=Point(FEditor.CaretXPix,FEditor.CaretYPix);
5996end;
5997
5998function TSourceEditor.IsCaretOnScreen(ACaret: TPoint; UseSoftCenter: Boolean = False): Boolean;
5999var
6000  LinesInWin, MinLines, CurTopLine, Y: Integer;
6001begin
6002  LinesInWin := EditorComponent.LinesInWindow;
6003  CurTopLine := EditorComponent.TopView;
6004  Y := EditorComponent.TextIndexToViewPos(ACaret.Y);
6005  if UsesoftCenter then begin
6006    MinLines := Min(
6007      Min( Max(LinesInWin div SoftCenterFactor, SoftCenterMinimum),
6008           SoftCenterMaximum),
6009      Max(LinesInWin div 2 - 1, 0) // make sure there is at least one line in the soft center
6010      );
6011  end
6012  else
6013    MinLines := 0;
6014
6015  Result := (Y >= CurTopLine + MinLines) and
6016            (Y <= CurTopLine + LinesInWin - MinLines) and
6017            (ACaret.X >= FEditor.LeftChar) and
6018            (ACaret.X <= FEditor.LeftChar + FEditor.CharsInWindow);
6019end;
6020
6021procedure TSourceEditor.MultiPasteText;
6022var
6023  I, CaretX: Integer;
6024  Content: TStringList;
6025  Dialog: TMultiPasteDialog;
6026begin
6027  if ReadOnly then Exit;
6028  Dialog := TMultiPasteDialog.Create(nil);
6029  try
6030    if Dialog.ShowModal <> mrOK then Exit;
6031    CaretX := FEditor.CaretX;
6032    if CaretX > 1 then
6033    begin
6034      Content := TStringList.Create;
6035      try
6036        Content.Text := Dialog.Content.Text;
6037        for I := 0 to Pred(Content.Count) do
6038          if I > 0 then
6039            Content[I] := Concat(DupeString(' ', Pred(CaretX)), Content[I]);
6040        FEditor.InsertTextAtCaret(Content.Text);
6041      finally
6042        Content.Free;
6043      end;
6044    end
6045    else
6046      FEditor.InsertTextAtCaret(Dialog.Content.Text);
6047  finally
6048    Dialog.Free;
6049  end;
6050end;
6051
6052function TSourceEditor.SearchReplace(const ASearch, AReplace: string;
6053  SearchOptions: TSrcEditSearchOptions): integer;
6054const
6055  SrcEdit2SynEditSearchOption: array[TSrcEditSearchOption] of TSynSearchOption =(
6056    ssoMatchCase,
6057    ssoWholeWord,
6058    ssoBackwards,
6059    ssoEntireScope,
6060    ssoSelectedOnly,
6061    ssoReplace,
6062    ssoReplaceAll,
6063    ssoPrompt,
6064    ssoRegExpr,
6065    ssoRegExprMultiLine
6066  );
6067var
6068  NewOptions: TSynSearchOptions;
6069  o: TSrcEditSearchOption;
6070begin
6071  NewOptions:=[];
6072  for o:=Low(TSrcEditSearchOption) to High(TSrcEditSearchOption) do
6073    if o in SearchOptions then
6074      Include(NewOptions,SrcEdit2SynEditSearchOption[o]);
6075  Result:=DoFindAndReplace(ASearch, AReplace, NewOptions);
6076end;
6077
6078function TSourceEditor.GetSourceText: string;
6079begin
6080  Result:=FEditor.Text;
6081end;
6082
6083procedure TSourceEditor.SetSourceText(const AValue: string);
6084begin
6085  FEditor.Text:=AValue;
6086end;
6087
6088procedure TSourceEditor.Activate;
6089begin
6090  { $note: avoid this if FSourceNoteBook.FUpdateLock > 0 / e.g. debugger calls ProcessMessages, and the internall Index is lost/undone}
6091  if (FSourceNoteBook=nil) then exit;
6092  if (FSourceNoteBook.FUpdateLock = 0) then
6093    FSourceNoteBook.ActiveEditor := Self;
6094end;
6095
6096procedure TSourceEditor.ActivateHint(const ClientPos: TPoint; const ABaseURL,
6097  AHint: string; AAutoShown: Boolean);
6098var
6099  ScreenPos: TPoint;
6100begin
6101  if SourceNotebook=nil then exit;
6102  ScreenPos:=EditorComponent.ClientToScreen(ClientPos);
6103  Manager.ActivateHint(ScreenPos,ABaseURL,AHint,AAutoShown);
6104end;
6105
6106function TSourceEditor.PageIndex: integer;
6107begin
6108  if FSourceNoteBook<>nil then
6109    Result:=FSourceNoteBook.FindPageWithEditor(Self)
6110  else
6111    Result:=-1;
6112end;
6113
6114function TSourceEditor.CaretInSelection(const ACaretPos: TPoint): Boolean;
6115begin
6116  Result := (CompareCaret(EditorComponent.BlockBegin, ACaretpos) >= 0)
6117        and (CompareCaret(ACaretPos, EditorComponent.BlockEnd) >= 0);
6118end;
6119
6120function TSourceEditor.IsActiveOnNoteBook: boolean;
6121begin
6122  if FSourceNoteBook<>nil then
6123    Result:=(FSourceNoteBook.GetActiveSE=Self)
6124  else
6125    Result:=false;
6126end;
6127
6128procedure TSourceEditor.CheckActiveWindow;
6129begin
6130  if Manager.ActiveSourceWindow = SourceNotebook then exit;
6131  debugln('Warning: ActiveSourceWindow is set incorrectly Active=',dbgSourceNoteBook(Manager.ActiveSourceWindow),' Me=',dbgSourceNoteBook(SourceNotebook));
6132  Manager.ActiveSourceWindow := SourceNotebook;
6133end;
6134
6135procedure TSourceEditor.DoRequestExecutionMarks(Data: PtrInt);
6136begin
6137  DebugBoss.LineInfo.Request(FSharedValues.MarksRequestedForFile);
6138end;
6139
6140procedure TSourceEditor.FillExecutionMarks;
6141var
6142  ASource: String;
6143  i, idx: integer;
6144  HasAddr: Boolean;
6145  j: Integer;
6146begin
6147  if EditorComponent.IDEGutterMarks.HasDebugMarks then Exit;
6148
6149  ASource := FileName;
6150  idx := DebugBoss.LineInfo.IndexOf(ASource);
6151  if (idx = -1) then
6152  begin
6153    if not FSharedValues.MarksRequested then
6154    begin
6155      FSharedValues.MarksRequested := True;
6156      FSharedValues.MarksRequestedForFile := ASource;
6157      DebugBoss.LineInfo.AddNotification(FLineInfoNotification);
6158      Application.QueueAsyncCall(@DoRequestExecutionMarks, 0);
6159    end;
6160    Exit;
6161  end;
6162
6163  FSharedValues.MarksRequestedForFile := '';
6164  j := -1;
6165  EditorComponent.IDEGutterMarks.BeginSetDebugMarks;
6166  try
6167    for i := 1 to EditorComponent.Lines.Count do
6168    begin
6169      HasAddr := DebugBoss.LineInfo.HasAddress(idx, i);
6170      if (HasAddr) and (j < 0) then
6171        j := i;
6172      if (not HasAddr) and (j >= 0) then begin
6173        EditorComponent.IDEGutterMarks.SetDebugMarks(j, i-1);
6174        j := -1;
6175      end;
6176    end;
6177    if (HasAddr) and (j >= 0) then
6178      EditorComponent.IDEGutterMarks.SetDebugMarks(j, EditorComponent.Lines.Count);
6179  finally
6180    EditorComponent.IDEGutterMarks.EndSetDebugMarks;
6181  end;
6182
6183  // TODO: move to SourceSyneditor
6184  for i := 0 to SharedEditorCount - 1 do
6185    SharedEditors[i].EditorComponent.IDEGutterMarks.HasDebugMarks; // update all shared editors
6186end;
6187
6188procedure TSourceEditor.ClearExecutionMarks;
6189var
6190  i: Integer;
6191begin
6192  if FSharedValues.MarksRequested and (FSharedValues.MarksRequestedForFile <> '') then
6193    DebugBoss.LineInfo.Cancel(FSharedValues.MarksRequestedForFile);
6194  FSharedValues.MarksRequestedForFile := '';
6195
6196  EditorComponent.IDEGutterMarks.ClearDebugMarks;
6197  FSharedValues.MarksRequested := False;
6198  for i := 0 to SharedEditorCount - 1 do
6199    SharedEditors[i].EditorComponent.IDEGutterMarks.ClearDebugMarks; // update all shared editors
6200  if (FLineInfoNotification <> nil) and (DebugBoss <> nil) and (DebugBoss.LineInfo <> nil) then
6201    DebugBoss.LineInfo.RemoveNotification(FLineInfoNotification);
6202end;
6203
6204procedure TSourceEditor.CopyToWindow(AWindowIndex: Integer);
6205begin
6206  SourceNotebook.CopyEditor(PageIndex, AWindowIndex, -1)
6207end;
6208
6209function TSourceEditor.GetCodeAttributeName(LogXY: TPoint): String;
6210var
6211  Token: string;
6212  Attri: TSynHighlighterAttributes;
6213begin
6214    Result := '';
6215    if EditorComponent.GetHighlighterAttriAtRowCol(LogXY,Token,Attri)
6216    and (Attri<>nil) then
6217    begin
6218      Result := Attri.StoredName;
6219    end;
6220end;
6221
6222procedure TSourceEditor.LineInfoNotificationChange(const ASender: TObject; const ASource: String);
6223begin
6224  if ASource = FileName then begin
6225    Application.RemoveAsyncCalls(Self);
6226    FillExecutionMarks;
6227  end;
6228end;
6229
6230function TSourceEditor.SourceToDebugLine(aLinePos: Integer): Integer;
6231begin
6232  Result := FEditor.IDEGutterMarks.SourceLineToDebugLine(aLinePos, True);
6233end;
6234
6235function TSourceEditor.DebugToSourceLine(aLinePos: Integer): Integer;
6236begin
6237  Result := FEditor.IDEGutterMarks.DebugLineToSourceLine(aLinePos);
6238end;
6239
6240procedure TSourceEditor.InvalidateAllIfdefNodes;
6241begin
6242  FEditor.InvalidateAllIfdefNodes;
6243end;
6244
6245procedure TSourceEditor.SetIfdefNodeState(ALinePos, AstartPos: Integer;
6246  AState: TSynMarkupIfdefNodeState);
6247begin
6248  FEditor.SetIfdefNodeState(ALinePos, AstartPos, AState);
6249end;
6250
6251procedure TSourceEditor.UpdateIfDefNodeStates(Force: Boolean = False);
6252{off $DEFINE VerboseUpdateIfDefNodeStates}
6253{$IFDEF VerboseUpdateIfDefNodeStates}
6254const
6255  VFilePattern='blaunit';
6256  VMinY=1;
6257  VMaxY=70;
6258{$ENDIF}
6259var
6260  Scanner: TLinkScanner;
6261  i: Integer;
6262  aDirective: PLSDirective;
6263  Code: TCodeBuffer;
6264  Y: integer;
6265  X: integer;
6266  SynState: TSynMarkupIfdefNodeStateEx;
6267  SrcPos: Integer;
6268  ActiveCnt: Integer;
6269  InactiveCnt: Integer;
6270  SkippedCnt: Integer;
6271begin
6272  //debugln(['TSourceEditor.UpdateIfDefNodeStates START ',Filename]);
6273  if not EditorComponent.IsIfdefMarkupActive then
6274    exit;
6275  //debugln(['TSourceEditor.UpdateIfDefNodeStates CHECK ',Filename]);
6276  UpdateCodeBuffer;
6277  Scanner:=SharedValues.GetMainLinkScanner(true);
6278  if Scanner=nil then exit;
6279  if (Scanner.ChangeStep=FLastIfDefNodeScannerStep) and (not Force) then exit;
6280  //debugln(['TSourceEditor.UpdateIfDefNodeStates UPDATING ',Filename]);
6281  FLastIfDefNodeScannerStep:=Scanner.ChangeStep;
6282  EditorComponent.BeginUpdate;
6283  try
6284    //EditorComponent.InvalidateAllIfdefNodes;
6285    Code:=CodeBuffer;
6286    i:=0;
6287    while i<Scanner.DirectiveCount do
6288    begin
6289      aDirective:=Scanner.DirectivesSorted[i];
6290      //if (Pos(VFilePattern,Code.Filename)>0) then
6291      //  debugln(['TSourceEditor.UpdateIfDefNodeStates ',i+1,'/',Scanner.DirectiveCount,' ',dbgs(aDirective^.Kind)]);
6292      inc(i);
6293      if TCodeBuffer(aDirective^.Code)<>Code then continue;
6294      if not (aDirective^.Kind in (lsdkAllIf+lsdkAllElse)) then continue;
6295      Code.AbsoluteToLineCol(aDirective^.SrcPos,Y,X);
6296      if Y<1 then continue;
6297      SynState:=idnInvalid;
6298      // a directive can be scanned multiple times (multi included include files)
6299      // => show it enabled if it was active at least once
6300      {$IFDEF VerboseUpdateIfDefNodeStates}
6301      if (Pos(VFilePattern,Code.Filename)>0) and (Y>=VMinY) and (Y<=VMaxY) then
6302        debugln(['TSourceEditor.UpdateIfDefNodeStates ',i,'/',Scanner.DirectiveCount,' ',dbgs(Pointer(Code)),' ',Code.Filename,' X=',X,' Y=',Y,' SrcPos=',aDirective^.SrcPos,' State=',dbgs(aDirective^.State)]);
6303      {$ENDIF}
6304      SrcPos:=aDirective^.SrcPos;
6305      ActiveCnt:=0;
6306      InactiveCnt:=0;
6307      SkippedCnt:=0;
6308      repeat
6309        case aDirective^.State of
6310        lsdsActive: inc(ActiveCnt);
6311        lsdsInactive: inc(InactiveCnt);
6312        lsdsSkipped: inc(SkippedCnt);
6313        end;
6314        if i < Scanner.DirectiveCount then begin
6315          ADirective:=Scanner.DirectivesSorted[i];
6316          {$IFDEF VerboseUpdateIfDefNodeStates}
6317          if (Pos(VFilePattern,Code.Filename)>0) and (Y>=VMinY) and (Y<=VMaxY) and (ADirective^.SrcPos=SrcPos) then
6318            debugln(['TSourceEditor.UpdateIfDefNodeStates ',i,'/',Scanner.DirectiveCount,' MERGING ',dbgs(ADirective^.Code),' ',Code.Filename,' X=',X,' Y=',Y,' SrcPos=',aDirective^.SrcPos,' State=',dbgs(aDirective^.State)]);
6319          {$ENDIF}
6320        end;
6321        inc(i);
6322      until (ADirective^.SrcPos<>SrcPos) or (TCodeBuffer(ADirective^.Code)<>Code)
6323        or (i > Scanner.DirectiveCount);
6324      dec(i);
6325      if (ActiveCnt>0) and (InactiveCnt=0) and (SkippedCnt=0) then
6326        SynState:=idnEnabled
6327      else if (ActiveCnt=0) and (InactiveCnt+SkippedCnt>0) then
6328        SynState:=idnDisabled
6329      else if (ActiveCnt>0) then
6330        SynState:=idnTempEnabled
6331      else
6332        SynState:=idnInvalid;
6333      {$IFDEF VerboseUpdateIfDefNodeStates}
6334      if (Pos(VFilePattern,Code.Filename)>0) and (Y>=VMinY) and (Y<=VMaxY) then
6335        debugln(['TSourceEditor.UpdateIfDefNodeStates y=',y,' x=',x,' Counts:Inactive=',InactiveCnt,' Active=',ActiveCnt,' Skipped=',SkippedCnt,' SET SynState=',dbgs(SynState)]);
6336      {$ENDIF}
6337      EditorComponent.SetIfdefNodeState(Y,X,SynState);
6338    end;
6339  finally
6340    EditorComponent.EndUpdate;
6341  end;
6342end;
6343
6344function TSourceEditor.SharedEditorCount: Integer;
6345begin
6346  Result := FSharedValues.SharedEditorCount;
6347  if Result = 1 then
6348    Result := 0; // not a sharing editor
6349end;
6350
6351function TSourceEditor.GetWordAtCurrentCaret: String;
6352var
6353  CaretPos: TPoint;
6354begin
6355  CaretPos.Y := CurrentCursorYLine;
6356  CaretPos.X := CurrentCursorXLine;
6357  Result := GetWordFromCaret(ScreenToTextPosition(CaretPos));
6358end;
6359
6360function TSourceEditor.GetOperandFromCaret(const ACaretPos: TPoint): String;
6361begin
6362  UpdateCodeBuffer;
6363  if not CodeToolBoss.GetExpandedOperand(CodeBuffer, ACaretPos.X, ACaretPos.Y,
6364    Result, False)
6365  then
6366  if not CodeToolBoss.ExtractOperand(CodeBuffer, ACaretPos.X, ACaretPos.Y,
6367    Result, False, False, true)
6368  then
6369    Result := GetWordFromCaret(ACaretPos);
6370end;
6371
6372function TSourceEditor.GetPageCaption: string;
6373var
6374  I: Integer;
6375begin
6376  I := SourceNotebook.FindPageWithEditor(Self);
6377  if I >= 0 then
6378    Result := SourceNotebook.NoteBookPages[I]
6379  else
6380    Result := FPageName;
6381end;
6382
6383function TSourceEditor.GetPageName: string;
6384begin
6385  Result := FPageName;
6386end;
6387
6388function TSourceEditor.GetOperandAtCurrentCaret: String;
6389var
6390  CaretPos: TPoint;
6391begin
6392  CaretPos.Y := CurrentCursorYLine;
6393  CaretPos.X := CurrentCursorXLine;
6394  Result := GetOperandFromCaret(ScreenToTextPosition(CaretPos));
6395end;
6396
6397function TSourceEditor.GetWordFromCaret(const ACaretPos: TPoint): String;
6398begin
6399  Result := FEditor.GetWordAtRowCol(ACaretPos);
6400end;
6401
6402function TSourceEditor.IsFirstShared(Sender: TObject): boolean;
6403begin
6404  Result:=SharedEditors[0]=Self;
6405end;
6406
6407procedure TSourceEditor.SetVisible(Value: boolean);
6408begin
6409  if FVisible=Value then exit;
6410  if FEditor<>nil then FEditor.Visible:=Value;
6411  FVisible:=Value;
6412end;
6413
6414procedure TSourceEditor.UnbindEditor;
6415// disconnect all events
6416var
6417  i: Integer;
6418begin
6419  with EditorComponent do begin
6420    OnStatusChange := nil;
6421    OnProcessCommand := nil;
6422    OnProcessUserCommand := nil;
6423    OnCommandProcessed := nil;
6424    OnReplaceText := nil;
6425    OnGutterClick := nil;
6426    OnSpecialLineMarkup := nil;
6427    OnMouseMove := nil;
6428    OnMouseWheel := nil;
6429    OnMouseDown := nil;
6430    OnClickLink := nil;
6431    OnMouseLink := nil;
6432    OnKeyDown := nil;
6433    OnKeyUp := nil;
6434    OnEnter := nil;
6435    OnPlaceBookmark := nil;
6436    OnClearBookmark := nil;
6437    OnChangeUpdating := nil;
6438    OnIfdefNodeStateRequest := nil;
6439    UnregisterMouseActionExecHandler(@EditorHandleMouseAction);
6440  end;
6441  for i := 0 to EditorComponent.PluginCount - 1 do
6442    if EditorComponent.Plugin[i] is TSynPluginSyncronizedEditBase then begin
6443      TSynPluginSyncronizedEditBase(EditorComponent.Plugin[i]).OnActivate := nil;
6444      TSynPluginSyncronizedEditBase(EditorComponent.Plugin[i]).OnDeactivate := nil;
6445    end;
6446  if FEditPlugin<>nil then begin
6447    FEditPlugin.Enabled:=false;
6448  end;
6449end;
6450
6451procedure TSourceEditor.DoEditorExecuteCommand(EditorCommand: word);
6452begin
6453  EditorComponent.CommandProcessor(TSynEditorCommand(EditorCommand),' ',nil);
6454end;
6455
6456{------------------------------------------------------------------------}
6457                      { TSourceNotebook }
6458
6459constructor TSourceNotebook.Create(AOwner: TComponent);
6460var
6461  i: Integer;
6462  n: TComponent;
6463begin
6464  FPageIndex := -1;
6465  i := 1;
6466  n := AOwner.FindComponent(NonModalIDEWindowNames[nmiwSourceNoteBook]);
6467  while (n <> nil) do begin
6468    inc(i);
6469    n := AOwner.FindComponent(NonModalIDEWindowNames[nmiwSourceNoteBook]+IntToStr(i));
6470  end;
6471
6472  Create(AOwner, i-1);
6473end;
6474
6475constructor TSourceNotebook.Create(AOwner: TComponent; AWindowID: Integer);
6476begin
6477  inherited Create(AOwner);
6478  FManager := TSourceEditorManager(AOwner);
6479  FUpdateLock := 0;
6480  FFocusLock := 0;
6481  Visible := false;
6482  FIsClosing := False;
6483  FWindowID := AWindowID;
6484  if AWindowID > 0 then
6485    Name := NonModalIDEWindowNames[nmiwSourceNoteBook] + IntToStr(AWindowID+1)
6486  else
6487    Name := NonModalIDEWindowNames[nmiwSourceNoteBook];
6488
6489  if AWindowID > 0 then
6490    BaseCaption := locWndSrcEditor + ' (' + IntToStr(AWindowID+1) + ')'
6491  else
6492    BaseCaption := locWndSrcEditor;
6493  Caption := BaseCaption;
6494  KeyPreview := true;
6495  FProcessingCommand := false;
6496
6497  FSourceEditorList := TFPList.Create;
6498  FHistoryList := TFPList.Create;
6499  FSrcEditsSortedForFilenames := TAvlTree.Create(@CompareSrcEditIntfWithFilename);
6500
6501  FHistoryDlg := TBrowseEditorTabHistoryDialog.CreateNew(Self);
6502  FOnEditorPageCaptionUpdate := TMethodList.Create;
6503
6504  OnDropFiles := @SourceNotebookDropFiles;
6505  AllowDropFiles:=true;
6506
6507  // popup menu
6508  BuildPopupMenu;
6509
6510  FUpdateTabAndPageTimer := TTimer.Create(Self);
6511  FUpdateTabAndPageTimer.Interval := 500;
6512  FUpdateTabAndPageTimer.OnTimer := @UpdateTabsAndPageTimeReached;
6513
6514  CreateNotebook;
6515
6516  Application.AddOnDeactivateHandler(@OnApplicationDeactivate);
6517  Application.AddOnMinimizeHandler(@OnApplicationDeactivate);
6518
6519  FStopBtnIdx := IDEImages.LoadImage('menu_stop');
6520
6521  {$IFNDEF LCLGtk2}
6522  try
6523    Icon.LoadFromResourceName(HInstance, 'WIN_SOURCEEDITOR');
6524  except
6525  end;
6526  {$ENDIF}
6527end;
6528
6529destructor TSourceNotebook.Destroy;
6530var
6531  i: integer;
6532begin
6533  DebugLnEnter(SRCED_CLOSE, ['TSourceNotebook.Destroy ']);
6534  if assigned(Manager) then
6535    Manager.RemoveWindow(Self);
6536  DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.Destroy'){$ENDIF};
6537  FProcessingCommand:=false;
6538
6539  for i:=FSourceEditorList.Count-1 downto 0 do
6540    Editors[i].Free;
6541  FreeAndNil(FSourceEditorList);
6542  FreeAndNil(FHistoryList);
6543  FreeAndNil(FOnEditorPageCaptionUpdate);
6544  FreeAndNil(FSrcEditsSortedForFilenames);
6545
6546  Application.RemoveOnDeactivateHandler(@OnApplicationDeactivate);
6547  Application.RemoveOnMinimizeHandler(@OnApplicationDeactivate);
6548  FreeAndNil(FNotebook);
6549
6550  inherited Destroy;
6551  DebugLnExit(SRCED_CLOSE, ['TSourceNotebook.Destroy ']);
6552end;
6553
6554procedure TSourceNotebook.CreateNotebook;
6555var
6556  APage: TTabSheet;
6557Begin
6558  {$IFDEF IDE_DEBUG}
6559  debugln('[TSourceNotebook.CreateNotebook] START');
6560  {$ENDIF}
6561  {$IFDEF IDE_MEM_CHECK}
6562  CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] A ');
6563  {$ENDIF}
6564  FNotebook := TExtendedNotebook.Create(self);
6565  {$IFDEF IDE_DEBUG}
6566  debugln('[TSourceNotebook.CreateNotebook] B');
6567  {$ENDIF}
6568  {$IFDEF IDE_MEM_CHECK}
6569  CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] B ');
6570  {$ENDIF}
6571  FPageIndex := -1;
6572  with FNotebook do Begin
6573    Name:='SrcEditNotebook';
6574    Parent := Self;
6575    {$IFDEF IDE_DEBUG}
6576    debugln('[TSourceNotebook.CreateNotebook] C');
6577    {$ENDIF}
6578    Align := alClient;
6579    APage:=TTabSheet.Create(FNotebook);
6580    APage.Caption:='unit1';
6581    APage.Parent:=FNotebook;
6582    PageIndex := 0;   // Set it to the first page
6583    Options:=Options+[nboHidePageListPopup]; // hide default popup menu, we show custom in mouse up
6584    if EditorOpts.ShowTabCloseButtons then
6585      Options:=Options+[nboShowCloseButtons]
6586    else
6587      Options:=Options-[nboShowCloseButtons];
6588    MultiLine := EditorOpts.MultiLineTab;
6589    if Manager<>nil then
6590      ShowTabs := Manager.ShowTabs
6591    else
6592      ShowTabs := True;
6593    if ShowTabs then
6594      TabPosition := EditorOpts.TabPosition;
6595    OnChange := @NotebookPageChanged;
6596    OnCloseTabClicked  := @CloseTabClicked;
6597    OnMouseDown:=@NotebookMouseDown;
6598    OnMouseUp:=@NotebookMouseUp;
6599    TabDragMode := dmAutomatic;
6600    OnTabDragOverEx  := @NotebookDragOverEx;
6601    OnTabDragDropEx  := @NotebookDragDropEx;
6602    OnTabDragOver    := @NotebookDragOver;
6603    OnTabEndDrag     := @NotebookEndDrag;
6604    ShowHint:=true;
6605    OnShowHint:=@NotebookShowTabHint;
6606    {$IFDEF IDE_DEBUG}
6607    debugln('[TSourceNotebook.CreateNotebook] D');
6608    {$ENDIF}
6609    Visible := False;
6610  end; //with
6611  {$IFDEF IDE_DEBUG}
6612  debugln('[TSourceNotebook.CreateNotebook] END');
6613  {$ENDIF}
6614  {$IFDEF IDE_MEM_CHECK}
6615  CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] END ');
6616  {$ENDIF}
6617End;
6618
6619type
6620  TLineEnding = (leLF, leCR, leCRLF);
6621const
6622  LE_Strs : array [TLineEnding] of String = (#10, #13, #13#10);
6623
6624procedure TSourceNotebook.LineEndingClicked(Sender: TObject);
6625var
6626  IDEMenuItem: TIDEMenuItem;
6627  SrcEdit: TSourceEditor;
6628  NewLineEnding: String;
6629  OldLineEnding: String;
6630begin
6631  SrcEdit:=GetActiveSE;
6632  if SrcEdit=nil then exit;
6633  if not (Sender is TIDEMenuItem) then exit;
6634  if SrcEdit.CodeBuffer=nil then exit;
6635
6636  IDEMenuItem:=TIDEMenuItem(Sender);
6637  NewLineEnding:=LE_Strs[TLineEnding(IDEMenuItem.Tag)];
6638  DebugLn(['TSourceNotebook.LineEndingClicked NewLineEnding=',NewLineEnding]);
6639  OldLineEnding:=SrcEdit.CodeBuffer.DiskLineEnding;
6640  if OldLineEnding='' then
6641    OldLineEnding:=LineEnding;
6642  if NewLineEnding<>SrcEdit.CodeBuffer.DiskLineEnding then begin
6643    DebugLn(['TSourceNotebook.LineEndingClicked Old=',dbgstr(OldLineEnding),' New=',dbgstr(NewLineEnding)]);
6644    // change file
6645    SrcEdit.CodeBuffer.DiskLineEnding:=NewLineEnding;
6646    SrcEdit.CodeBuffer.Source:=
6647                    ChangeLineEndings(SrcEdit.CodeBuffer.Source,NewLineEnding);
6648    SrcEdit.CodeBuffer.Modified:=true;
6649    SrcEdit.Modified:=true;
6650  end;
6651end;
6652
6653procedure TSourceNotebook.EncodingClicked(Sender: TObject);
6654var
6655  IDEMenuItem: TIDEMenuItem;
6656  SrcEdit: TSourceEditor;
6657  NewEncoding: String;
6658  OldEncoding: String;
6659  CurResult: TModalResult;
6660begin
6661  SrcEdit:=GetActiveSE;
6662  if SrcEdit=nil then exit;
6663  if Sender is TIDEMenuItem then begin
6664    IDEMenuItem:=TIDEMenuItem(Sender);
6665    NewEncoding:=IDEMenuItem.Caption;
6666    if SysUtils.CompareText(copy(NewEncoding,1,length(EncodingAnsi)+2),EncodingAnsi+' (')=0
6667    then begin
6668      // the ansi encoding is shown as 'ansi (system encoding)' -> cut
6669      NewEncoding:=EncodingAnsi;
6670    end else if NewEncoding=lisUtf8WithBOM then begin
6671      NewEncoding:=EncodingUTF8BOM;
6672    end;
6673    DebugLn(['Hint: (lazarus) TSourceNotebook.EncodingClicked NewEncoding=',NewEncoding]);
6674    if SrcEdit.CodeBuffer<>nil then begin
6675      OldEncoding:=NormalizeEncoding(SrcEdit.CodeBuffer.DiskEncoding);
6676      if OldEncoding='' then
6677        OldEncoding:=GetDefaultTextEncoding;
6678      if NewEncoding<>SrcEdit.CodeBuffer.DiskEncoding then begin
6679        DebugLn(['Hint: (lazarus) TSourceNotebook.EncodingClicked Old=',OldEncoding,' New=',NewEncoding]);
6680        if SrcEdit.ReadOnly then begin
6681          if SrcEdit.CodeBuffer.IsVirtual then
6682            CurResult:=mrCancel
6683          else
6684            CurResult:=IDEQuestionDialog(lisChangeEncoding,
6685              Format(lisEncodingOfFileOnDiskIsNewEncodingIs,
6686                     [SrcEdit.CodeBuffer.Filename, LineEnding, OldEncoding, NewEncoding]),
6687              mtConfirmation, [mrOk, lisReopenWithAnotherEncoding, mrCancel]);
6688        end else begin
6689          if SrcEdit.CodeBuffer.IsVirtual then
6690            CurResult:=IDEQuestionDialog(lisChangeEncoding,
6691              Format(lisEncodingOfFileOnDiskIsNewEncodingIs,
6692                     [SrcEdit.CodeBuffer.Filename, LineEnding, OldEncoding, NewEncoding]),
6693              mtConfirmation, [mrYes, lisChangeFile, mrCancel])
6694          else
6695            CurResult:=IDEQuestionDialog(lisChangeEncoding,
6696              Format(lisEncodingOfFileOnDiskIsNewEncodingIs,
6697                     [SrcEdit.CodeBuffer.Filename, LineEnding, OldEncoding, NewEncoding]),
6698              mtConfirmation, [mrYes,lisChangeFile,mrOk,lisReopenWithAnotherEncoding,mrCancel]);
6699        end;
6700        if CurResult=mrYes then begin
6701          // change file
6702          SrcEdit.CodeBuffer.DiskEncoding:=NewEncoding;
6703          SrcEdit.CodeBuffer.Modified:=true;
6704          // set override
6705          InputHistoriesSO.FileEncodings[SrcEdit.CodeBuffer.Filename]:=NewEncoding;
6706          DebugLn(['Hint: (lazarus) TSourceNotebook.EncodingClicked Change file to ',SrcEdit.CodeBuffer.DiskEncoding]);
6707          if (not SrcEdit.CodeBuffer.IsVirtual)
6708          and (LazarusIDE.DoSaveEditorFile(SrcEdit, []) <> mrOk)
6709          then begin
6710            DebugLn(['Hint: (lazarus) TSourceNotebook.EncodingClicked LazarusIDE.DoSaveEditorFile failed']);
6711          end;
6712        end else if CurResult=mrOK then begin
6713          // reopen with another encoding
6714          if SrcEdit.Modified then begin
6715            if IDEQuestionDialog(lisAbandonChanges,
6716              Format(lisAllYourModificationsToWillBeLostAndTheFileReopened,
6717                     [SrcEdit.CodeBuffer.Filename, LineEnding]),
6718              mtConfirmation,[mbOk,mbAbort],'')<>mrOk
6719            then begin
6720              exit;
6721            end;
6722          end;
6723          // set override
6724          InputHistoriesSO.FileEncodings[SrcEdit.CodeBuffer.Filename]:=NewEncoding;
6725          if not SrcEdit.CodeBuffer.Revert then begin
6726            IDEMessageDialog(lisCodeToolsDefsReadError,
6727              Format(lisUnableToRead, [SrcEdit.CodeBuffer.Filename]),
6728              mtError,[mbCancel],'');
6729            exit;
6730          end;
6731          SrcEdit.EditorComponent.BeginUpdate;
6732          SrcEdit.CodeBuffer.AssignTo(SrcEdit.EditorComponent.Lines,False);
6733          SrcEdit.EditorComponent.EndUpdate;
6734        end;
6735      end;
6736    end;
6737  end;
6738end;
6739
6740procedure TSourceNotebook.HighlighterClicked(Sender: TObject);
6741var
6742  IDEMenuItem: TIDEMenuItem;
6743  i: LongInt;
6744  SrcEdit: TSourceEditor;
6745  h: TLazSyntaxHighlighter;
6746begin
6747  SrcEdit:=GetActiveSE;
6748  if SrcEdit=nil then exit;
6749  if Sender is TIDEMenuItem then begin
6750    IDEMenuItem:=TIDEMenuItem(Sender);
6751    i:=IDEMenuItem.SectionIndex;
6752    if (i>=ord(Low(TLazSyntaxHighlighter)))
6753    and (i<=ord(High(TLazSyntaxHighlighter))) then begin
6754      h:=TLazSyntaxHighlighter(i);
6755      SrcEdit.SyntaxHighlighterType:=h;
6756      SrcEdit.UpdateProjectFile([sepuChangedHighlighter]);
6757    end;
6758  end;
6759end;
6760
6761procedure TSourceNotebook.TabPopUpMenuPopup(Sender: TObject);
6762var
6763  ASrcEdit: TSourceEditor;
6764
6765  {$IFnDEF SingleSrcWindow}
6766  function ToWindow(ASection: TIDEMenuSection; const OpName: string;
6767                    const OnClickMethod: TNotifyEvent; WinForFind: Boolean = False): Boolean;
6768  var
6769    i, ThisWin, SharedEditor: Integer;
6770    nb: TSourceNotebook;
6771  begin
6772    Result := False;
6773    ASection.Clear;
6774    ThisWin := Manager.IndexOfSourceWindow(self);
6775    for i := 0 to Manager.SourceWindowCount - 1 do begin
6776      nb:=Manager.SourceWindows[i];
6777      SharedEditor:=nb.IndexOfEditorInShareWith(ASrcEdit);
6778      if (i <> ThisWin) and ((SharedEditor < 0) <> WinForFind) then begin
6779        Result := True;
6780        with RegisterIDEMenuCommand(ASection,OpName+IntToStr(i),nb.Caption,OnClickMethod) do
6781          Tag := i;
6782      end;
6783    end;
6784  end;
6785  {$ENDIF}
6786  procedure AddEditorToMenuSection(AEditor: TSourceEditor; AMenu: TIDEMenuSection; AIndex: Integer);
6787  var
6788    S: String;
6789  begin
6790    S := AEditor.PageName;
6791    if AEditor.Modified then
6792      S := '*'+S;
6793
6794    RegisterIDEMenuCommand(AMenu, 'File'+IntToStr(AIndex),
6795             S, @ExecuteEditorItemClick, nil, nil, '', PtrUInt(AEditor));
6796  end;
6797
6798var
6799  PageCtrl: TPageControl;
6800  PopM: TPopupMenu;
6801  PageI: integer;
6802  i: Integer;
6803  S: String;
6804  EditorCur: TSourceEditor;
6805  P: TIDEPackage;
6806  RecMenu, ProjMenu, M: TIDEMenuSection;
6807  EdList: TStringListUTF8Fast;
6808begin
6809  PopM:=TPopupMenu(Sender);
6810  SourceTabMenuRoot.MenuItem:=PopM.Items;
6811  // Get the tab that was clicked
6812  if PopM.PopupComponent is TPageControl then begin
6813    PageCtrl:=TPageControl(PopM.PopupComponent);
6814    PageI:=PageCtrl.IndexOfPageAt(PageCtrl.ScreenToClient(PopM.PopupPoint));
6815    if (PageI>=0) and (PageI<PageCtrl.PageCount) then
6816      PageIndex := PageI  // Todo: This should be in MouseDown / or both, whichever is first
6817    else
6818      DebugLn(['TSourceNotebook.TabPopUpMenuPopup: Popup PageIndex=', PageI]);
6819  end;
6820  ASrcEdit:=ActiveEditor as TSourceEditor;
6821
6822  {$IFnDEF SingleSrcWindow}
6823  // Multi win
6824  ToWindow(SrcEditMenuMoveToOtherWindowList, 'MoveToWindow',
6825                     @SrcEditMenuMoveToExistingWindowClicked);
6826  ToWindow(SrcEditMenuCopyToOtherWindowList, 'CopyToWindow',
6827                     @SrcEditMenuCopyToExistingWindowClicked);
6828  ToWindow(SrcEditMenuFindInOtherWindowList, 'FindInWindow',
6829                     @SrcEditMenuFindInWindowClicked, True);
6830  {$ENDIF}
6831
6832  SrcEditMenuSectionEditors.Clear;
6833  if Manager <> nil then begin
6834    EdList := TStringListUTF8Fast.Create;
6835    EdList.OwnsObjects := False;
6836    for i := 0 to EditorCount - 1 do
6837      EdList.AddObject(Editors[i].PageName+' '+Editors[i].FileName, Editors[i]);
6838    EdList.Sorted := True;
6839
6840    RecMenu := RegisterIDESubMenu(SrcEditMenuSectionEditors, lisRecentTabs, lisRecentTabs);
6841    RecMenu.Visible := False;
6842    ProjMenu := RegisterIDESubMenu(SrcEditMenuSectionEditors, dlgEnvProject, dlgEnvProject);
6843    ProjMenu.Visible := False;
6844    RegisterIDESubMenu(SrcEditMenuSectionEditors, lisMEOther, lisMEOther).Visible := False;
6845
6846    //first add all pages in the correct order since the editor order can be different from the tab order
6847    for i := 0 to EdList.Count - 1 do
6848    begin
6849      EditorCur := TSourceEditor(EdList.Objects[i]);
6850      s := lisMEOther;
6851      P := nil;
6852      if (EditorCur.GetProjectFile <> nil) and (EditorCur.GetProjectFile.IsPartOfProject) then
6853        s := dlgEnvProject
6854      else begin
6855        Manager.OnPackageForSourceEditor(P, EditorCur);
6856        if P <> nil then
6857          s := Format(lisTabsFor, [p.Name]);
6858      end;
6859
6860      if SrcEditMenuSectionEditors.FindByName(S) is TIDEMenuSection then begin
6861        M := TIDEMenuSection(SrcEditMenuSectionEditors.FindByName(S))
6862      end else begin
6863        M := RegisterIDESubMenu(SrcEditMenuSectionEditors, S, S);
6864        M.UserTag := PtrUInt(P);
6865      end;
6866      M.Visible := True;
6867
6868      AddEditorToMenuSection(EditorCur, M, i);
6869      // use tag to count modified
6870      if EditorCur.Modified then M.Tag := m.Tag + 1;
6871    end;
6872
6873    EdList.Free;
6874
6875    // add recent tabs. skip 0 since that is the active tab
6876    for i := 1 to Min(10, FHistoryList.Count-1) do
6877    begin
6878      EditorCur := FindSourceEditorWithPageIndex(FNotebook.IndexOf(TCustomPage(FHistoryList[i])));
6879      if (EditorCur = nil) or (not EditorCur.FEditor.HandleAllocated) then continue; // show only if it was visited
6880      AddEditorToMenuSection(EditorCur, RecMenu, i);
6881      RecMenu.Visible := True;
6882    end;
6883
6884    for i := 0 to SrcEditMenuSectionEditors.Count - 1 do begin
6885      if SrcEditMenuSectionEditors.Items[i] is TIDEMenuSection then begin
6886        M := SrcEditMenuSectionEditors.Items[i] as TIDEMenuSection;
6887
6888        if M.Tag = 0 then
6889          M.Caption := M.Caption +  Format(' (%d)', [M.Count])
6890        else
6891          M.Caption := M.Caption +  Format(' (*%d/%d)', [M.Tag, M.Count]);
6892
6893        if M.UserTag <> 0 then
6894          RegisterIDEMenuCommand(
6895                  RegisterIDEMenuSection(M as TIDEMenuSection, 'Open lpk sect '+TIDEPackage(M.UserTag).Filename),
6896                 'Open lpk '+TIDEPackage(M.UserTag).Filename,
6897                 lisCompPalOpenPackage, @OnPopupOpenPackageFile, nil, nil, '', M.UserTag);
6898      end;
6899    end;
6900
6901    if ProjMenu.Visible then begin
6902      RegisterIDEMenuCommand(
6903              RegisterIDEMenuSection(ProjMenu, 'Open proj sect '),
6904             'Open proj', lisOpenProject2, @OnPopupOpenProjectInsp);
6905    end;
6906
6907  end;
6908end;
6909
6910procedure TSourceNotebook.SrcPopUpMenuPopup(Sender: TObject);
6911var
6912  ASrcEdit: TSourceEditor;
6913  CurFilename: String;
6914
6915  function MaybeAddPopup(const ASuffix: String; ANewOnClick: TNotifyEvent = nil;
6916    Filename: string = ''): TIDEMenuItem;
6917  begin
6918    Result:=nil;
6919    if ANewOnClick=nil then
6920      ANewOnClick:=@OnPopupMenuOpenFile;
6921    if Filename='' then
6922      Filename:=CurFilename;
6923    Filename:=ChangeFileExt(Filename,ASuffix);
6924    if FileExistsCached(Filename) then begin
6925      Filename:=CreateRelativePath(Filename,ExtractFilePath(ASrcEdit.FileName));
6926      Result:=AddContextPopupMenuItem(Format(lisOpenLfm,[Filename]), true, ANewOnClick);
6927    end;
6928  end;
6929
6930var
6931  FPDocSrc, ShortFileName: String;
6932  EditorComp: TSynEdit;
6933  MainCodeBuf: TCodeBuffer;
6934  AnOwner: TObject;
6935  Marks: PSourceMark;
6936  i, MarkCount: integer;
6937  EditorPopupPoint, EditorCaret: TPoint;
6938begin
6939  IDECommandList.ExecuteUpdateEvents;
6940
6941  SourceEditorMenuRoot.MenuItem:=SrcPopupMenu.Items;
6942  RemoveUserDefinedMenuItems;
6943  RemoveContextMenuItems;
6944
6945  ASrcEdit:=FindSourceEditorWithEditorComponent(TPopupMenu(Sender).PopupComponent);
6946  Assert(Assigned(ASrcEdit), 'TSourceNotebook.SrcPopUpMenuPopup: ASrcEdit=nil');
6947  Assert((ASrcEdit=GetActiveSE), 'TSourceNotebook.SrcPopUpMenuPopup: ASrcEdit<>GetActiveSE');
6948  EditorComp:=ASrcEdit.EditorComponent;
6949
6950  SrcEditMenuReadOnly.Checked:=ASrcEdit.ReadOnly;
6951  SrcEditMenuShowLineNumbers.Checked := ASrcEdit.EditorComponent.Gutter.LineNumberPart.Visible;
6952  SrcEditMenuDisableI18NForLFM.Visible:=false;
6953
6954  UpdateHighlightMenuItems(ASrcEdit);
6955  UpdateEncodingMenuItems(ASrcEdit);
6956  UpdateLineEndingMenuItems(ASrcEdit);
6957
6958  // ask Codetools
6959  CurFilename:=ASrcEdit.FileName;
6960  ShortFileName:=ExtractFileName(CurFilename);
6961  MainCodeBuf:=nil;
6962  if FilenameHasPascalExt(ShortFileName) or FilenameExtIs(ShortFileName,'inc') then
6963    MainCodeBuf:=CodeToolBoss.GetMainCode(ASrcEdit.CodeBuffer)
6964  else if FilenameIsPascalSource(ShortFileName) then
6965    MainCodeBuf:=ASrcEdit.CodeBuffer;
6966
6967  if (FilenameIsAbsolute(CurFilename)) then begin
6968    if (MainCodeBuf<>nil) and (MainCodeBuf<>ASrcEdit.CodeBuffer)
6969    and (not MainCodeBuf.IsVirtual) then begin
6970      // this is an include file => add link to open unit
6971      CurFilename:=MainCodeBuf.Filename;
6972      ShortFileName:=ExtractFileName(CurFilename);
6973      AddContextPopupMenuItem(
6974        Format(lisOpenLfm,
6975               [CreateRelativePath(CurFilename,ExtractFilePath(ASrcEdit.Filename))]),
6976        true,@OnPopupMenuOpenFile);
6977    end;
6978    if FilenameHasPascalExt(ShortFileName) then begin
6979      MaybeAddPopup('.lfm');
6980      MaybeAddPopup('.dfm');
6981      MaybeAddPopup('.lrs');
6982      MaybeAddPopup('.s');
6983    end;
6984    // ToDo: unit resources
6985    if FilenameExtIs(ShortFileName,'lfm',true)
6986    or FilenameExtIs(ShortFileName,'dfm') then begin
6987      MaybeAddPopup('.pas');
6988      MaybeAddPopup('.pp');
6989      MaybeAddPopup('.p');
6990    end;
6991    if FilenameExtIn(ShortFileName, ['lpi','lpk'], true) then begin
6992      AddContextPopupMenuItem(Format(lisOpenLfm,[ShortFileName]),true,@OnPopupMenuOpenFile);
6993    end;
6994    FPDocSrc:=LazarusHelp.GetFPDocFilenameForSource(CurFilename,false,AnOwner);
6995    if FPDocSrc<>'' then
6996      AddContextPopupMenuItem(
6997        Format(lisOpenLfm,
6998               [CreateRelativePath(FPDocSrc,ExtractFilePath(CurFilename))]),
6999        true,@OnPopupMenuOpenFile);
7000  end;
7001
7002  EditorPopupPoint:=EditorComp.ScreenToClient(SrcPopUpMenu.PopupPoint);
7003  if EditorPopupPoint.X<=EditorComp.Gutter.Width then begin
7004    EditorCaret := EditorComp.PhysicalToLogicalPos(EditorComp.PixelsToRowColumn(EditorPopupPoint));
7005    // user clicked on gutter
7006    SourceEditorMarks.GetMarksForLine(ASrcEdit, EditorCaret.y, Marks, MarkCount);
7007    if Marks <> nil then begin
7008      for i := 0 to MarkCount-1 do
7009        Marks[i].CreatePopupMenuItems(@AddUserDefinedPopupMenuItem);
7010      FreeMem(Marks);
7011    end;
7012    if (EditorCaret.Y<=EditorComp.Lines.Count)
7013    and (MessagesView<>nil) then
7014      MessagesView.SourceEditorPopup(EditorComp.Marks.Line[EditorCaret.Y],
7015        EditorComp.LogicalCaretXY);
7016  end;
7017
7018  if Assigned(Manager.OnPopupMenu) then
7019    Manager.OnPopupMenu(@AddContextPopupMenuItem);
7020  SourceEditorMenuRoot.NotifySubSectionOnShow(Self);
7021  //SrcPopupMenu.Items.WriteDebugReport('TSourceNotebook.SrcPopUpMenuPopup() ');
7022end;
7023
7024procedure TSourceNotebook.DbgPopUpMenuPopup(Sender: TObject);
7025begin
7026  SrcEditSubMenuDebug.MenuItem:=DbgPopUpMenu.Items;
7027end;
7028
7029procedure TSourceNotebook.NotebookShowTabHint(Sender: TObject;
7030  HintInfo: PHintInfo);
7031var
7032  Tabindex: integer;
7033  ASrcEdit: TSourceEditor;
7034begin
7035  if (PageCount=0) or (HintInfo=nil) then exit;
7036  TabIndex:=FNoteBook.IndexOfPageAt(FNotebook.ScreenToClient(Mouse.CursorPos));
7037  if TabIndex<0 then exit;
7038  ASrcEdit:=FindSourceEditorWithPageIndex(TabIndex);
7039  if ASrcEdit=nil then exit;
7040  if ASrcEdit.CodeBuffer<>nil then begin
7041    HintInfo^.HintStr:=ASrcEdit.CodeBuffer.Filename;
7042  end;
7043end;
7044
7045function TSourceNotebook.GetItems(Index: integer): TSourceEditorInterface;
7046begin
7047  Result:=TSourceEditorInterface(FSourceEditorList[Index]);
7048end;
7049
7050procedure TSourceNotebook.BuildPopupMenu;
7051begin
7052  //debugln('TSourceNotebook.BuildPopupMenu');
7053
7054  TabPopUpMenu := TPopupMenu.Create(Self);
7055  with TabPopupMenu do
7056  begin
7057    AutoPopup := True;
7058    OnPopup :=@TabPopupMenuPopup;
7059    Images := IDEImages.Images_16;
7060  end;
7061
7062  SrcPopupMenu := TPopupMenu.Create(Self);
7063  with SrcPopupMenu do
7064  begin
7065    AutoPopup := True;
7066    OnPopup :=@SrcPopupMenuPopup;
7067    Images := IDEImages.Images_16;
7068  end;
7069
7070  DbgPopUpMenu := TPopupMenu.Create(Self);
7071  with DbgPopupMenu do
7072  begin
7073    AutoPopup := True;
7074    OnPopup :=@DbgPopupMenuPopup;
7075    Images := IDEImages.Images_16;
7076  end;
7077
7078  GoToLineMenuItem.Caption := lisMenuGotoLine;
7079  OpenFolderMenuItem.Caption := lisMenuOpenFolder;
7080  {$IFDEF VerboseMenuIntf}
7081  SrcPopupMenu.Items.WriteDebugReport('TSourceNotebook.BuildPopupMenu ');
7082  SourceTabMenuRoot.ConsistencyCheck;
7083  SourceEditorMenuRoot.ConsistencyCheck;
7084  {$ENDIF}
7085end;
7086
7087procedure TSourceNotebook.CallOnEditorPageCaptionUpdate(Sender: TObject);
7088begin
7089  FOnEditorPageCaptionUpdate.CallNotifyEvents(Sender);
7090end;
7091
7092function TSourceNotebook.GetNoteBookPage(Index: Integer): TTabSheet;
7093begin
7094  if FNotebook.Visible then
7095    Result := FNotebook.Pages[Index]
7096  else
7097    Result := nil;
7098end;
7099
7100function TSourceNotebook.GetNotebookPages: TStrings;
7101begin
7102  if FNotebook.Visible then
7103    Result := TCustomTabControl(FNotebook).Pages
7104  else
7105    Result := nil;
7106end;
7107
7108function TSourceNotebook.GetPageCount: Integer;
7109begin
7110  If FNotebook.Visible then
7111    Result := FNotebook.PageCount
7112  else
7113    Result := 0;
7114end;
7115
7116function TSourceNotebook.GetPageIndex: Integer;
7117begin
7118  if FUpdateLock > 0 then
7119    Result := FPageIndex
7120  else
7121  if FNotebook.Visible then
7122    Result := FNotebook.PageIndex
7123  else
7124    Result := -1
7125end;
7126
7127function TSourceNotebook.GetWindowID: Integer;
7128begin
7129  Result := FWindowID;
7130end;
7131
7132procedure TSourceNotebook.SetPageIndex(AValue: Integer);
7133begin
7134  if (fPageIndex = AValue) and (FNotebook.PageIndex = AValue) then begin
7135    //debugln(['>> TSourceNotebook.SetPageIndex PageIndex=', PageIndex, ' FPageIndex=', FPageIndex, ' Value=', AValue, ' FUpdateLock=', FUpdateLock]);
7136    //DumpStack;
7137    exit;
7138  end;
7139  DebugLnEnter(SRCED_PAGES, ['>> TSourceNotebook.SetPageIndex Cur-PgIdx=', PageIndex, ' FPageIndex=', FPageIndex, ' Value=', AValue, ' FUpdateLock=', FUpdateLock]);
7140  //debugln(['>> TSourceNotebook.SetPageIndex CHANGE PageIndex=', PageIndex, ' FPageIndex=', FPageIndex, ' Value=', AValue, ' FUpdateLock=', FUpdateLock]);
7141  FPageIndex := AValue;
7142  if FUpdateLock = 0 then
7143    ApplyPageIndex
7144  else
7145    Include(FUpdateFlags,ufPageIndexChanged);
7146  DebugLnExit(SRCED_PAGES, ['<< TSourceNotebook.SetPageIndex ']);
7147end;
7148
7149procedure TSourceNotebook.UpdateHighlightMenuItems(SrcEdit: TSourceEditor);
7150var
7151  h: TLazSyntaxHighlighter;
7152  i: Integer;
7153  CurName: String;
7154  CurCaption: String;
7155  IDEMenuItem: TIDEMenuItem;
7156begin
7157  SrcEditSubMenuHighlighter.ChildrenAsSubMenu:=true;
7158  i:=0;
7159  for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do begin
7160    CurName:='Highlighter'+IntToStr(i);
7161    CurCaption:=GetSyntaxHighlighterCaption(h);
7162    if SrcEditSubMenuHighlighter.Count=i then begin
7163      // add new item
7164      IDEMenuItem:=RegisterIDEMenuCommand(SrcEditSubMenuHighlighter,
7165                             CurName,CurCaption,@HighlighterClicked);
7166    end else begin
7167      IDEMenuItem:=SrcEditSubMenuHighlighter[i];
7168      IDEMenuItem.Caption:=CurCaption;
7169      IDEMenuItem.OnClick:=@HighlighterClicked;
7170    end;
7171    if IDEMenuItem is TIDEMenuCommand then
7172      TIDEMenuCommand(IDEMenuItem).Checked:=(SrcEdit<>nil)
7173                                          and (SrcEdit.SyntaxHighlighterType=h);
7174    inc(i);
7175  end;
7176end;
7177
7178procedure TSourceNotebook.UpdateLineEndingMenuItems(SrcEdit: TSourceEditor);
7179var
7180  le: TLineEnding;
7181  FileEndings: String;
7182  IDEMenuItem: TIDEMenuCommand;
7183const
7184  LE_Names : array [TLineEnding] of String =(
7185    'LF (Unix, Linux)',
7186    'CR (Classic Mac)',
7187    'CRLF (Win, DOS)'
7188  );
7189begin
7190  SrcEditSubMenuLineEnding.ChildrenAsSubMenu:=true;
7191  if (SrcEdit<>nil) and (SrcEdit.CodeBuffer<>nil) then
7192    FileEndings:=SrcEdit.CodeBuffer.DiskLineEnding
7193  else
7194    FileEndings:=LineEnding;
7195  //DebugLn(['TSourceNotebook.UpdateEncodingMenuItems ',Encoding]);
7196  for le:=low(TLineEnding) to High(TLineEnding) do begin
7197    if SrcEditSubMenuLineEnding.Count=Ord(le) then begin
7198      // add new item
7199      IDEMenuItem:=RegisterIDEMenuCommand(SrcEditSubMenuLineEnding,
7200        'LineEnding'+IntToStr(Ord(le)),LE_Names[le],@LineEndingClicked);
7201    end else begin
7202      IDEMenuItem:=SrcEditSubMenuLineEnding[Ord(le)] as TIDEMenuCommand;
7203      IDEMenuItem.Caption:=LE_Names[le];
7204      IDEMenuItem.OnClick:=@LineEndingClicked;
7205    end;
7206    IDEMenuItem.Tag:=Ord(le);
7207    IDEMenuItem.Checked:=(FileEndings=LE_Strs[le]);
7208  end;
7209end;
7210
7211procedure TSourceNotebook.UpdatePageNames;
7212var
7213  i: Integer;
7214begin
7215  if FUpdateLock > 0 then begin
7216    include(FUpdateFlags, ufPageNames);
7217    exit;
7218  end;
7219  for i := 0 to EditorCount - 1 do
7220    Editors[i].UpdatePageName;
7221  UpdateTabsAndPageTitle;
7222end;
7223
7224procedure TSourceNotebook.UpdateProjectFiles(ACurrentEditor: TSourceEditor = nil);
7225var
7226  i: Integer;
7227begin
7228  if FUpdateLock > 0 then begin
7229    if ACurrentEditor <> nil then
7230      ACurrentEditor.UpdateProjectFile;
7231    include(FUpdateFlags, ufProjectFiles);
7232    exit;
7233  end;
7234  for i := 0 to EditorCount - 1 do
7235    Editors[i].UpdateProjectFile;
7236end;
7237
7238procedure TSourceNotebook.UpdateEncodingMenuItems(SrcEdit: TSourceEditor);
7239var
7240  List: TStringList;
7241  i: Integer;
7242  Encoding: String;
7243  CurEncoding: string;
7244  CurName: String;
7245  CurCaption: String;
7246  IDEMenuItem: TIDEMenuItem;
7247  SysEncoding: String;
7248begin
7249  SrcEditSubMenuEncoding.ChildrenAsSubMenu:=true;
7250  Encoding:='';
7251  if SrcEdit<>nil then begin
7252    if SrcEdit.CodeBuffer<>nil then
7253      Encoding:=NormalizeEncoding(SrcEdit.CodeBuffer.DiskEncoding);
7254  end;
7255  if Encoding='' then
7256    Encoding:=GetDefaultTextEncoding;
7257  //DebugLn(['TSourceNotebook.UpdateEncodingMenuItems ',Encoding]);
7258  List:=TStringList.Create;
7259  GetSupportedEncodings(List);
7260  for i:=0 to List.Count-1 do begin
7261    CurName:='Encoding'+IntToStr(i);
7262    CurEncoding:=List[i];
7263    CurCaption:=CurEncoding;
7264    if SysUtils.CompareText(CurEncoding,EncodingAnsi)=0 then begin
7265      SysEncoding:=GetDefaultTextEncoding;
7266      if (SysEncoding<>'') and (SysUtils.CompareText(SysEncoding,EncodingAnsi)<>0)
7267      then
7268        CurCaption:=CurCaption+' ('+GetDefaultTextEncoding+')';
7269    end;
7270    if CurEncoding='UTF-8BOM' then begin
7271      CurCaption:=lisUtf8WithBOM;
7272    end;
7273    if SrcEditSubMenuEncoding.Count=i then begin
7274      // add new item
7275      IDEMenuItem:=RegisterIDEMenuCommand(SrcEditSubMenuEncoding,
7276                             CurName,CurCaption,@EncodingClicked);
7277    end else begin
7278      IDEMenuItem:=SrcEditSubMenuEncoding[i];
7279      IDEMenuItem.Caption:=CurCaption;
7280      IDEMenuItem.OnClick:=@EncodingClicked;
7281    end;
7282    if IDEMenuItem is TIDEMenuCommand then
7283      TIDEMenuCommand(IDEMenuItem).Checked:=
7284        Encoding=NormalizeEncoding(CurEncoding);
7285  end;
7286  List.Free;
7287end;
7288
7289procedure TSourceNotebook.RemoveUserDefinedMenuItems;
7290begin
7291  SrcEditMenuSectionFirstDynamic.Clear;
7292end;
7293
7294function TSourceNotebook.AddUserDefinedPopupMenuItem(const NewCaption: string;
7295  const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TIDEMenuItem;
7296begin
7297  Result:=RegisterIDEMenuCommand(SrcEditMenuSectionFirstDynamic.GetPath,
7298    'Dynamic',NewCaption,NewOnClick);
7299  Result.Enabled:=NewEnabled;
7300end;
7301
7302procedure TSourceNotebook.RemoveContextMenuItems;
7303begin
7304  SrcEditMenuSectionFileDynamic.Clear;
7305  {$IFDEF VerboseMenuIntf}
7306  SrcEditMenuSectionFileDynamic.WriteDebugReport('TSourceNotebook.RemoveContextMenuItems ', true);
7307  {$ENDIF}
7308end;
7309
7310procedure TSourceNotebook.RemoveUpdateEditorPageCaptionHandler(
7311  AEvent: TNotifyEvent);
7312begin
7313  FOnEditorPageCaptionUpdate.Remove(TMethod(AEvent));
7314end;
7315
7316function TSourceNotebook.AddContextPopupMenuItem(const NewCaption: string;
7317  const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TIDEMenuItem;
7318begin
7319  Result:=RegisterIDEMenuCommand(SrcEditMenuSectionFileDynamic.GetPath,
7320                                 'FileDynamic',NewCaption,NewOnClick);
7321  Result.Enabled:=NewEnabled;
7322end;
7323
7324procedure TSourceNotebook.AddUpdateEditorPageCaptionHandler(
7325  AEvent: TNotifyEvent; const AsLast: Boolean);
7326begin
7327  FOnEditorPageCaptionUpdate.Add(TMethod(AEvent), AsLast);
7328end;
7329
7330{-------------------------------------------------------------------------------
7331  Procedure TSourceNotebook.EditorChanged
7332  Params: Sender: TObject
7333  Result: none
7334
7335  Called whenever an editor status changes. Sender is normally a TSynEdit.
7336-------------------------------------------------------------------------------}
7337procedure TSourceNotebook.EditorChanged(Sender: TObject;
7338  Changes: TSynStatusChanges);
7339var SenderDeleted: boolean;
7340Begin
7341  SenderDeleted:=(Sender as TControl).Parent=nil;
7342  if SenderDeleted then exit;
7343  UpdateStatusBar;
7344  if Assigned(Manager) then begin
7345    if not(Changes=[scFocus]) then // has to be here because of issue #29726
7346      Manager.FHints.HideIfVisible;
7347    Manager.DoEditorStatusChanged(FindSourceEditorWithEditorComponent(TSynEdit(Sender)));
7348  end;
7349End;
7350
7351procedure TSourceNotebook.DoClose(var CloseAction: TCloseAction);
7352var
7353  Layout: TSimpleWindowLayout;
7354begin
7355  DebugLnEnter(SRCED_CLOSE, ['TSourceNotebook.DoClose ', DbgSName(self)]);
7356  inherited DoClose(CloseAction);
7357  CloseAction := caHide;
7358  {$IFnDEF SingleSrcWindow}
7359  if (PageCount = 0) and (Parent=nil) then begin { $NOTE maybe keep the last one}
7360    // Make the name unique, because it may not immediately be released
7361    // => disconnect first
7362    Layout:=IDEWindowCreators.SimpleLayoutStorage.ItemByForm(Self);
7363    if Layout<>nil then
7364      Layout.Form:=nil;
7365    Name := Name + '___' + IntToStr({%H-}PtrUInt(Pointer(Self)));
7366    CloseAction := caFree;
7367  end
7368  else begin
7369    FIsClosing := True;
7370    try
7371      if Assigned(Manager) and Assigned(Manager.OnNoteBookCloseQuery) then
7372        Manager.OnNoteBookCloseQuery(Self, CloseAction);
7373    finally
7374      FIsClosing := False;
7375    end;
7376  end;
7377  {$ENDIF}
7378  DebugLnExit(SRCED_CLOSE, ['TSourceNotebook.DoClose ']);
7379end;
7380
7381procedure TSourceNotebook.DoShow;
7382begin
7383  inherited DoShow;
7384  // statusbar was not updated when visible=false, update now
7385  if snUpdateStatusBarNeeded in States then
7386    UpdateStatusBar;
7387  if Assigned(Manager) and (Parent <> nil) then
7388    Manager.DoWindowShow(Self);
7389end;
7390
7391procedure TSourceNotebook.DoHide;
7392begin
7393  inherited DoHide;
7394  if Assigned(Manager) and (Parent <> nil) then
7395    Manager.DoWindowHide(Self);
7396end;
7397
7398function TSourceNotebook.IndexOfEditorInShareWith(
7399  AnOtherEditor: TSourceEditorInterface): Integer;
7400var
7401  i: Integer;
7402begin
7403  for i := 0 to EditorCount - 1 do
7404    if Editors[i].IsSharedWith(AnOtherEditor as TSourceEditor) then
7405      exit(i);
7406  Result := -1;
7407end;
7408
7409function TSourceNotebook.GetActiveCompletionPlugin: TSourceEditorCompletionPlugin;
7410begin
7411  Result := Manager.ActiveCompletionPlugin;
7412end;
7413
7414function TSourceNotebook.GetBaseCaption: String;
7415begin
7416  Result := FBaseCaption;
7417end;
7418
7419function TSourceNotebook.GetCompletionPlugins(Index: integer
7420  ): TSourceEditorCompletionPlugin;
7421begin
7422  Result := SourceEditorManager.CompletionPlugins[Index];
7423end;
7424
7425function TSourceNotebook.NewSE(Pagenum: Integer; NewPagenum: Integer;
7426  ASharedEditor: TSourceEditor; ATabCaption: String): TSourceEditor;
7427begin
7428  {$IFDEF IDE_DEBUG}
7429  debugln('TSourceNotebook.NewSE A ');
7430  {$ENDIF}
7431  if Pagenum < 0 then begin
7432    // add a new page right to the current
7433    if NewPageNum >= 0 then
7434      PageNum := NewPageNum
7435    else
7436      Pagenum := PageIndex+1;
7437    Pagenum := Max(0,Min(PageNum, PageCount));
7438    if ATabCaption = '' then
7439      ATabCaption := Manager.FindUniquePageName('', nil);
7440    NoteBookInsertPage(PageNum, ATabCaption);
7441    NotebookPage[PageNum].ReAlign;
7442  end;
7443  {$IFDEF IDE_DEBUG}
7444  debugln(['TSourceNotebook.NewSE B  ', PageIndex,',',PageCount]);
7445  {$ENDIF}
7446  Result := TSourceEditor.Create(Self, NotebookPage[PageNum], ASharedEditor);
7447  Result.FPageName := NoteBookPages[Pagenum];
7448  AcceptEditor(Result);
7449  PageIndex := Pagenum;
7450  {$IFDEF IDE_DEBUG}
7451  debugln('TSourceNotebook.NewSE end ');
7452  {$ENDIF}
7453end;
7454
7455procedure TSourceNotebook.AcceptEditor(AnEditor: TSourceEditor; SendEvent: Boolean);
7456begin
7457  FSourceEditorList.Add(AnEditor);
7458  FSrcEditsSortedForFilenames.Add(AnEditor);
7459
7460  AnEditor.EditorComponent.BeginUpdate;
7461  AnEditor.PopupMenu := SrcPopupMenu;
7462  AnEditor.OnEditorChange := @EditorChanged;
7463  AnEditor.OnMouseMove := @EditorMouseMove;
7464  AnEditor.OnMouseDown := @EditorMouseDown;
7465  AnEditor.OnMouseWheel := @EditorMouseWheel;
7466  AnEditor.OnKeyDown := @EditorKeyDown;
7467  AnEditor.OnKeyUp := @EditorKeyUp;
7468  AnEditor.EditorComponent.Beautifier.OnGetDesiredIndent := @EditorGetIndent;
7469  AnEditor.EditorComponent.EndUpdate;
7470
7471  if SendEvent then
7472    Manager.SendEditorCreated(AnEditor);
7473end;
7474
7475procedure TSourceNotebook.ReleaseEditor(AnEditor: TSourceEditor; SendEvent: Boolean);
7476begin
7477  FSourceEditorList.Remove(AnEditor);
7478  FSrcEditsSortedForFilenames.RemovePointer(AnEditor);
7479  if SendEvent then
7480    Manager.SendEditorDestroyed(AnEditor);
7481end;
7482
7483function TSourceNotebook.FindSourceEditorWithPageIndex(APageIndex: integer): TSourceEditor;
7484var
7485  I: integer;
7486  TempEditor: TControl;
7487
7488  function FindSynEdit(AControl: TWinControl): TControl;
7489  var
7490    I: Integer;
7491  begin
7492    Result := nil;
7493
7494    with AControl do
7495      for I := 0 to ControlCount - 1 do
7496      begin
7497        if Controls[I] is TIDESynEditor then
7498          Exit(Controls[I])
7499        else
7500        if Controls[I] is TWinControl then
7501        begin
7502          Result := FindSynEdit(TWinControl(Controls[I]));
7503          if Result <> nil then
7504            Exit;
7505        end;
7506      end;
7507  end;
7508
7509begin
7510  Result := nil;
7511  if (FSourceEditorList=nil)
7512    or (APageIndex < 0) or (APageIndex >= PageCount) then exit;
7513
7514  TempEditor := FindSynEdit(NotebookPage[APageIndex]);
7515  {
7516  TempEditor:=nil;
7517  with NotebookPage[APageIndex] do
7518    for I := 0 to ControlCount-1 do
7519      if Controls[I] is TSynEdit then
7520        Begin
7521          TempEditor := Controls[I];
7522          Break;
7523        end;
7524  }
7525  if TempEditor=nil then exit;
7526  I := FSourceEditorList.Count-1;
7527  while (I>=0) and (TSourceEditor(FSourceEditorList[I]).EditorComponent <> TempEditor) do
7528    dec(i);
7529  if i<0 then exit;
7530  Result := TSourceEditor(FSourceEditorList[i]);
7531end;
7532
7533function TSourceNotebook.GetActiveSE: TSourceEditor;
7534Begin
7535  Result := nil;
7536  if (FSourceEditorList=nil) or (FSourceEditorList.Count=0) or (PageIndex<0) then
7537    exit;
7538  Result:=FindSourceEditorWithPageIndex(PageIndex);
7539end;
7540
7541function TSourceNotebook.GetActiveEditor: TSourceEditorInterface;
7542begin
7543  Result:=GetActiveSE;
7544end;
7545
7546procedure TSourceNotebook.SetActiveEditor(const AValue: TSourceEditorInterface);
7547var
7548  i: integer;
7549begin
7550  i := FindPageWithEditor(AValue as TSourceEditor);
7551  inc(FFocusLock);
7552  if i>= 0 then
7553    PageIndex := i;
7554  dec(FFocusLock);
7555  SourceEditorManager.ActiveSourceWindow := Self;
7556  if EditorOpts.ShowFileNameInCaption then
7557  begin
7558    if ActiveEditor<>nil then
7559      Caption := BaseCaption+' - '+ActiveEditor.FileName
7560    else
7561      Caption := BaseCaption;
7562  end;
7563end;
7564
7565procedure TSourceNotebook.SetBaseCaption(AValue: String);
7566begin
7567  FBaseCaption := AValue;
7568end;
7569
7570procedure TSourceNotebook.CheckCurrentCodeBufferChanged;
7571var
7572  SrcEdit: TSourceEditor;
7573begin
7574  // Todo: Move to manager, include window changes
7575  SrcEdit:=GetActiveSE;
7576  if SrcEdit <> nil then
7577  begin
7578    if FLastCodeBuffer=SrcEdit.CodeBuffer then exit;
7579    FLastCodeBuffer:=SrcEdit.CodeBuffer;
7580  end else if FLastCodeBuffer=nil then
7581    exit;
7582  if assigned(Manager) and Assigned(Manager.OnCurrentCodeBufferChanged) then
7583    Manager.OnCurrentCodeBufferChanged(Self);
7584end;
7585
7586function TSourceNotebook.GetCapabilities: TCTabControlCapabilities;
7587begin
7588  Result := FNotebook.GetCapabilities
7589end;
7590
7591procedure TSourceNotebook.IncUpdateLockInternal;
7592begin
7593  if FUpdateLock = 0 then begin
7594    FUpdateFlags := [];
7595    DebugLn(SRCED_LOCK, ['TSourceNotebook.IncUpdateLockInternal']);
7596    FPageIndex := PageIndex;
7597  end;
7598  inc(FUpdateLock);
7599end;
7600
7601procedure TSourceNotebook.DecUpdateLockInternal;
7602begin
7603  dec(FUpdateLock);
7604  if FUpdateLock = 0 then begin
7605    DebugLnEnter(SRCED_LOCK, ['>> TSourceNotebook.DecUpdateLockInternal UpdateFlags=', dbgs(FUpdateFlags), ' PageIndex=', FPageIndex]);
7606    if (ufPageIndexChanged in FUpdateFlags) or (PageIndex<>FPageIndex) then ApplyPageIndex;
7607    if (ufPageNames in FUpdateFlags)    then UpdatePageNames;
7608    if (ufTabsAndPage in FUpdateFlags)  then UpdateTabsAndPageTitle;
7609    if (ufStatusBar in FUpdateFlags)    then UpdateStatusBar;
7610    if (ufProjectFiles in FUpdateFlags) then UpdateProjectFiles;
7611    if (ufFocusEditor in FUpdateFlags)  then FocusEditor;
7612    if (ufActiveEditorChanged in FUpdateFlags) then DoActiveEditorChanged;
7613    FUpdateFlags := [];
7614    DebugLnExit(SRCED_LOCK, ['<< TSourceNotebook.DecUpdateLockInternal']);
7615  end;
7616end;
7617
7618procedure TSourceNotebook.IncUpdateLock;
7619begin
7620  Manager.IncUpdateLockInternal; // ensure mgr holds ActiveEditorChanged notificationback // TODO: make sure they are hlod in SourceNotebook instead, including SetAciveEditor....
7621  IncUpdateLockInternal;
7622end;
7623
7624procedure TSourceNotebook.DecUpdateLock;
7625begin
7626  try
7627    DecUpdateLockInternal;
7628  finally
7629    Manager.DecUpdateLockInternal;
7630  end;
7631end;
7632
7633procedure TSourceNotebook.NoteBookInsertPage(Index: Integer; const S: string);
7634begin
7635  if FNotebook.Visible then
7636    NotebookPages.Insert(Index, S)
7637  else begin
7638    if Index<>0 then
7639      RaiseGDBException('');
7640    IDEWindowCreators.ShowForm(Self,false);
7641    FNotebook.Visible := True;
7642    NotebookPages[Index] := S;
7643    FPageIndex := -1;
7644  end;
7645  UpdateTabsAndPageTitle;
7646end;
7647
7648procedure TSourceNotebook.NoteBookDeletePage(APageIndex: Integer);
7649begin
7650  DebugLnEnter(SRCED_PAGES, ['TSourceNotebook.NoteBookDeletePage ', APageIndex]);
7651  HistoryRemove(FNotebook.Pages[APageIndex]);
7652  //debugln(['TSourceNotebook.NoteBookDeletePage APageIndex=',APageIndex,' PageIndex=',PageIndex,' PageCount=',PageCount]);
7653  if PageCount > 1 then begin
7654    // make sure to select another page in the NoteBook, otherwise the
7655    // widgetset will choose one and will send a message
7656    // if this is the current page, switch to right APageIndex (if possible)
7657    if PageIndex = APageIndex then begin
7658      if EditorOpts.UseTabHistory then
7659        FPageIndex := HistoryGetTopPageIndex
7660      else
7661        FPageIndex := -1;
7662      // default if not in history or not using history
7663      if FPageIndex = -1 then
7664        if APageIndex < PageCount - 1 then
7665          FPageIndex := APageIndex + 1
7666        else
7667          FPageIndex := APageIndex - 1;
7668      if FUpdateLock = 0 then
7669        ApplyPageIndex
7670      else
7671        Include(FUpdateFlags,ufPageIndexChanged);
7672    end;
7673    NotebookPages.Delete(APageIndex);
7674  end else begin
7675    FPageIndex := -1;
7676    FNotebook.Visible := False;
7677  end;
7678  //debugln(['TSourceNotebook.NoteBookDeletePage END PageIndex=',PageIndex,' FPageIndex=',FPageIndex]);
7679  UpdateTabsAndPageTitle;
7680  DebugLnExit(SRCED_PAGES, ['TSourceNotebook.NoteBookDeletePage ']);
7681end;
7682
7683procedure TSourceNotebook.UpdateTabsAndPageTitle;
7684begin
7685  if FUpdateLock > 0 then begin
7686    include(FUpdateFlags, ufTabsAndPage);
7687    exit;
7688  end;
7689  if (PageCount = 1) and (EditorOpts.HideSingleTabInWindow) then begin
7690    if not EditorOpts.ShowFileNameInCaption then
7691      Caption := BaseCaption + ': ' + NotebookPages[0];
7692    FNotebook.ShowTabs := False;
7693  end else begin
7694    if not EditorOpts.ShowFileNameInCaption then
7695      Caption := BaseCaption;
7696    FNotebook.ShowTabs := (Manager=nil) or Manager.ShowTabs;
7697  end;
7698end;
7699
7700procedure TSourceNotebook.UpdateTabsAndPageTimeReached(Sender: TObject);
7701begin
7702  FUpdateTabAndPageTimer.Enabled := False;
7703  UpdateTabsAndPageTitle;
7704end;
7705
7706function TSourceNotebook.NoteBookIndexOfPage(APage: TTabSheet): Integer;
7707begin
7708  Result := FNoteBook.IndexOf(APage);
7709end;
7710
7711procedure TSourceNotebook.DragOver(Source: TObject; X, Y: Integer; State: TDragState;
7712  var Accept: Boolean);
7713begin
7714  FUpdateTabAndPageTimer.Enabled := False;
7715  inherited DragOver(Source, X, Y, State, Accept);
7716  if State = dsDragLeave then
7717    FUpdateTabAndPageTimer.Enabled := True
7718  else if Source is TExtendedNotebook then
7719    FNotebook.ShowTabs := (Manager=nil) or Manager.ShowTabs;
7720end;
7721
7722procedure TSourceNotebook.DragCanceled;
7723begin
7724  inherited DragCanceled;
7725  FUpdateTabAndPageTimer.Enabled := True;
7726end;
7727
7728procedure TSourceNotebook.DoActiveEditorChanged;
7729begin
7730  if FUpdateLock > 0 then begin
7731    DebugLn(SRCED_PAGES, ['TSourceNotebook.DoActiveEditorChanged LOCKED']);
7732    include(FUpdateFlags, ufActiveEditorChanged);
7733    exit;
7734  end;
7735  exclude(FUpdateFlags, ufActiveEditorChanged);
7736  DebugLnEnter(SRCED_PAGES, ['>> TSourceNotebook.DoActiveEditorChanged ']);
7737  Manager.DoActiveEditorChanged;
7738  DebugLnExit(SRCED_PAGES, ['<< TSourceNotebook.DoActiveEditorChanged ']);
7739end;
7740
7741procedure TSourceNotebook.BeginIncrementalFind;
7742var
7743  TempEditor: TSourceEditor;
7744begin
7745  if (snIncrementalFind in States)AND not(FIncrementalSearchEditor = nil)
7746  then begin
7747    if (IncrementalSearchStr=  '') then begin
7748      FIncrementalSearchStr := FIncrementalFoundStr;
7749      IncrementalSearch(False, FIncrementalSearchBackwards);
7750    end
7751    else IncrementalSearch(True, FIncrementalSearchBackwards);
7752    exit;
7753  end;
7754
7755  TempEditor:=GetActiveSE;
7756  if TempEditor = nil then exit;
7757  Include(States, snIncrementalFind);
7758  fIncrementalSearchStartPos:=TempEditor.EditorComponent.LogicalCaretXY;
7759  FIncrementalSearchPos:=fIncrementalSearchStartPos;
7760  FIncrementalSearchEditor := TempEditor;
7761  if assigned(FIncrementalSearchEditor.EditorComponent) then
7762    with FIncrementalSearchEditor.EditorComponent do begin
7763      UseIncrementalColor:= true;
7764      if assigned(MarkupByClass[TSynEditMarkupHighlightAllCaret]) then
7765        MarkupByClass[TSynEditMarkupHighlightAllCaret].TempDisable;
7766    end;
7767
7768  IncrementalSearchStr:='';
7769
7770  UpdateStatusBar;
7771end;
7772
7773procedure TSourceNotebook.EndIncrementalFind;
7774begin
7775  if not (snIncrementalFind in States) then exit;
7776
7777  Exclude(States,snIncrementalFind);
7778
7779  if FIncrementalSearchEditor <> nil
7780  then begin
7781    if assigned(FIncrementalSearchEditor.EditorComponent) then
7782      with FIncrementalSearchEditor.EditorComponent do begin
7783        UseIncrementalColor:= False;
7784        if assigned(MarkupByClass[TSynEditMarkupHighlightAllCaret]) then
7785          MarkupByClass[TSynEditMarkupHighlightAllCaret].TempEnable;
7786      end;
7787    FIncrementalSearchEditor.EditorComponent.SetHighlightSearch('', []);
7788    FIncrementalSearchEditor := nil;
7789  end;
7790
7791  LazFindReplaceDialog.FindText:=fIncrementalSearchStr;
7792  LazFindReplaceDialog.Options:=[];
7793  UpdateStatusBar;
7794end;
7795
7796procedure TSourceNotebook.NextEditor;
7797Begin
7798  if PageIndex < PageCount-1 then
7799    PageIndex := PageIndex+1
7800  else
7801    PageIndex := 0;
7802End;
7803
7804procedure TSourceNotebook.PrevEditor;
7805Begin
7806  if PageIndex > 0 then
7807    PageIndex := PageIndex-1
7808  else
7809    PageIndex := PageCount-1;
7810End;
7811
7812procedure TSourceNotebook.MoveEditor(OldPageIndex, NewPageIndex: integer);
7813begin
7814  if (PageCount<=1)
7815  or (OldPageIndex=NewPageIndex)
7816  or (OldPageIndex<0) or (OldPageIndex>=PageCount)
7817  or (NewPageIndex<0) or (NewPageIndex>=PageCount)
7818  then
7819    exit;
7820  NoteBookPages.Move(OldPageIndex,NewPageIndex);
7821  UpdatePageNames;
7822  UpdateProjectFiles;
7823end;
7824
7825procedure TSourceNotebook.MoveEditorLeft(CurrentPageIndex: integer);
7826begin
7827  if (PageCount<=1) then exit;
7828  if CurrentPageIndex>0 then
7829    MoveEditor(CurrentPageIndex, CurrentPageIndex-1)
7830  else
7831    MoveEditor(CurrentPageIndex, PageCount-1);
7832end;
7833
7834procedure TSourceNotebook.MoveEditorRight(CurrentPageIndex: integer);
7835begin
7836  if (PageCount<=1) then exit;
7837  if CurrentPageIndex < PageCount-1 then
7838    MoveEditor(CurrentPageIndex, CurrentPageIndex+1)
7839  else
7840    MoveEditor(CurrentPageIndex, 0);
7841end;
7842
7843procedure TSourceNotebook.MoveEditorFirst(CurrentPageIndex: integer);
7844begin
7845  if (PageCount<=1) then exit;
7846  MoveEditor(CurrentPageIndex, 0)
7847end;
7848
7849procedure TSourceNotebook.MoveEditorLast(CurrentPageIndex: integer);
7850begin
7851  if (PageCount<=1) then exit;
7852  MoveEditor(CurrentPageIndex, PageCount-1);
7853end;
7854
7855procedure TSourceNotebook.MoveActivePageLeft;
7856begin
7857  MoveEditorLeft(PageIndex);
7858end;
7859
7860procedure TSourceNotebook.MoveActivePageRight;
7861begin
7862  MoveEditorRight(PageIndex);
7863end;
7864
7865procedure TSourceNotebook.MoveActivePageFirst;
7866begin
7867  MoveEditorFirst(PageIndex);
7868end;
7869
7870procedure TSourceNotebook.MoveActivePageLast;
7871begin
7872  MoveEditorLast(PageIndex);
7873end;
7874
7875procedure TSourceNotebook.GotoNextWindow(Backward: Boolean);
7876begin
7877  if Backward then begin
7878    if Manager.IndexOfSourceWindow(Self) > 0 then
7879      Manager.ActiveSourceWindow := Manager.SourceWindows[Manager.IndexOfSourceWindow(Self)-1]
7880    else
7881      Manager.ActiveSourceWindow := Manager.SourceWindows[Manager.SourceWindowCount-1];
7882  end else begin
7883    if Manager.IndexOfSourceWindow(Self) < Manager.SourceWindowCount - 1 then
7884      Manager.ActiveSourceWindow := Manager.SourceWindows[Manager.IndexOfSourceWindow(Self)+1]
7885    else
7886      Manager.ActiveSourceWindow := Manager.SourceWindows[0];
7887  end;
7888  Manager.ShowActiveWindowOnTop(True);
7889end;
7890
7891procedure TSourceNotebook.GotoNextSharedEditor(Backward: Boolean = False);
7892var
7893  SrcEd: TSourceEditor;
7894  i, j: Integer;
7895begin
7896  i := Manager.IndexOfSourceWindow(Self);
7897  SrcEd := GetActiveSE;
7898  repeat
7899    if Backward then dec(i)
7900    else inc(i);
7901    if i < 0 then
7902      i := Manager.SourceWindowCount - 1;
7903    if i = Manager.SourceWindowCount then
7904      i := 0;
7905    j := Manager.SourceWindows[i].IndexOfEditorInShareWith(SrcEd);
7906    if j >= 0 then begin
7907      Manager.ActiveEditor := Manager.SourceWindows[i].Editors[j];
7908      Manager.ShowActiveWindowOnTop(True);
7909      exit;
7910    end;
7911  until Manager.SourceWindows[i] = Self;
7912end;
7913
7914procedure TSourceNotebook.MoveEditorNextWindow(Backward: Boolean; Copy: Boolean);
7915var
7916  SrcEd: TSourceEditor;
7917  i: Integer;
7918begin
7919  i := Manager.IndexOfSourceWindow(Self);
7920  SrcEd := GetActiveSE;
7921  repeat
7922    if Backward then dec(i)
7923    else inc(i);
7924    if i < 0 then
7925      i := Manager.SourceWindowCount - 1;
7926    if i = Manager.SourceWindowCount then
7927      i := 0;
7928    if Manager.SourceWindows[i].IndexOfEditorInShareWith(SrcEd) < 0 then
7929      break;
7930  until Manager.SourceWindows[i] = Self;
7931  if Manager.SourceWindows[i] = Self then exit;
7932
7933  if Copy then
7934    CopyEditor(FindPageWithEditor(GetActiveSE), i, -1)
7935  else
7936    MoveEditor(FindPageWithEditor(GetActiveSE), i, -1);
7937
7938  Manager.ActiveSourceWindowIndex := i;
7939  Manager.ShowActiveWindowOnTop(True);
7940end;
7941
7942procedure TSourceNotebook.MoveEditor(OldPageIndex, NewWindowIndex,
7943  NewPageIndex: integer);
7944var
7945  DestWin: TSourceNotebook;
7946  Edit: TSourceEditor;
7947begin
7948  if (NewWindowIndex < 0) or (NewWindowIndex >= Manager.SourceWindowCount) then
7949    exit;
7950  DestWin := Manager.SourceWindows[NewWindowIndex];
7951  if DestWin = self then begin
7952    MoveEditor(OldPageIndex, NewPageIndex);
7953    exit
7954  end;
7955
7956  if NewPageIndex < 0 then
7957    NewPageIndex := DestWin.PageCount;
7958  if (OldPageIndex<0) or (OldPageIndex>=PageCount) or
7959     (NewPageIndex<0) or (NewPageIndex>DestWin.PageCount)
7960  then
7961    exit;
7962
7963  DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.MoveEditor'){$ENDIF};
7964  IncUpdateLock;
7965  try
7966    DestWin.DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.MoveEdito DestWinr'){$ENDIF};
7967    DestWin.IncUpdateLock;
7968    try
7969      Edit := FindSourceEditorWithPageIndex(OldPageIndex);
7970      DestWin.NoteBookInsertPage(NewPageIndex, Edit.PageName);
7971      DestWin.PageIndex := NewPageIndex;
7972
7973      ReleaseEditor(Edit);
7974      Edit.UpdateNoteBook(DestWin, DestWin.NoteBookPage[NewPageIndex]);
7975      DestWin.AcceptEditor(Edit);
7976      DestWin.NotebookPage[NewPageIndex].ReAlign;
7977
7978      NoteBookDeletePage(OldPageIndex);
7979      UpdatePageNames;
7980      UpdateProjectFiles;
7981      DestWin.UpdatePageNames;
7982      DestWin.UpdateProjectFiles(Edit);
7983      DestWin.UpdateActiveEditColors(Edit.EditorComponent);
7984      DestWin.UpdateStatusBar;
7985      DestWin.NotebookPageChanged(nil); // make sure page SynEdit willl be visible
7986    finally
7987      DestWin.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.MoveEdito DestWinr'){$ENDIF};
7988      DestWin.DecUpdateLock;
7989    end;
7990  finally
7991    EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.MoveEditor'){$ENDIF};
7992    DecUpdateLock
7993  end;
7994
7995  if (PageCount = 0) and (Parent=nil) and not FIsClosing then
7996    Close;
7997
7998  DoActiveEditorChanged;
7999  Manager.ActiveEditor := Edit;
8000end;
8001
8002procedure TSourceNotebook.CopyEditor(OldPageIndex, NewWindowIndex,
8003  NewPageIndex: integer; Focus: Boolean = False);
8004var
8005  DestWin: TSourceNotebook;
8006  SrcEdit, NewEdit: TSourceEditor;
8007  i: Integer;
8008begin
8009  if (NewWindowIndex < 0) or (NewWindowIndex >= Manager.SourceWindowCount) then
8010    exit;
8011  DestWin := Manager.SourceWindows[NewWindowIndex];
8012  if DestWin = self then exit;
8013
8014  if (OldPageIndex<0) or (OldPageIndex>=PageCount) or (NewPageIndex>DestWin.PageCount)
8015  then
8016    exit;
8017
8018  SrcEdit := FindSourceEditorWithPageIndex(OldPageIndex);
8019  NewEdit := DestWin.NewSE(-1, NewPageIndex, SrcEdit, SrcEdit.PageName);
8020  Include(NewEdit.FProjectFileUpdatesNeeded, sepuNewShared);
8021
8022  NewEdit.PageName := SrcEdit.PageName;
8023  NewEdit.SyntaxHighlighterType := SrcEdit.SyntaxHighlighterType;
8024  NewEdit.EditorComponent.TopLine := SrcEdit.EditorComponent.TopLine;
8025  NewEdit.EditorComponent.CaretXY := SrcEdit.EditorComponent.CaretXY;
8026
8027  UpdatePageNames;
8028  UpdateProjectFiles;
8029  DestWin.UpdateProjectFiles(NewEdit);
8030  // Creating a shared edit invalidates the tree in SynMarkup. Force setting it for all editors
8031  for i := 0 to SrcEdit.SharedEditorCount - 1 do
8032    SrcEdit.SharedEditors[i].UpdateIfDefNodeStates(True);
8033  // Update IsVisibleTab; needs UnitEditorInfo created in DestWin.UpdateProjectFiles
8034  if Focus then begin
8035    Manager.ActiveEditor := NewEdit;
8036    Manager.ShowActiveWindowOnTop(True);
8037  end;
8038  DestWin.NotebookPageChanged(nil); // make sure page SynEdit willl be visible
8039  DoActiveEditorChanged;
8040end;
8041
8042procedure TSourceNotebook.StartShowCodeContext(JumpToError: boolean);
8043var
8044  Abort: boolean;
8045begin
8046  if assigned(Manager) and (Manager.OnShowCodeContext<>nil) then begin
8047    Manager.OnShowCodeContext(JumpToError,Abort);
8048    if Abort then ;
8049  end;
8050end;
8051
8052procedure TSourceNotebook.OnPopupMenuOpenFile(Sender: TObject);
8053var
8054  ResStr: String;
8055  p: SizeInt;
8056  aFilename: TTranslateString;
8057begin
8058  // open the filename of the caption
8059  // the caption was created by the resourcestring lisOpenLFM, with the
8060  // placeholder %s
8061  // => cut the surrounding caption to the get the filename
8062  aFilename:=(Sender as TIDEMenuItem).Caption;
8063  ResStr:=lisOpenLfm;
8064  p:=System.Pos('%s',ResStr);
8065  aFilename:=copy(aFilename,p,length(aFilename)-(length(ResStr)-2));
8066  if not FilenameIsAbsolute(aFilename) then
8067    aFilename:=TrimFilename(ExtractFilePath(GetActiveSE.Filename)+aFilename);
8068  if FilenameExtIs(aFilename,'lpi',true) then
8069    MainIDEInterface.DoOpenProjectFile(aFilename,[ofOnlyIfExists,ofAddToRecent,ofUseCache])
8070  else if FilenameExtIs(aFilename,'lpk',true) then
8071    PackageEditingInterface.DoOpenPackageFile(aFilename,[pofAddToRecent],false)
8072  else
8073    MainIDEInterface.DoOpenEditorFile(aFilename,
8074      PageIndex+1, Manager.IndexOfSourceWindow(self),
8075      [ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
8076end;
8077
8078procedure TSourceNotebook.OnPopupOpenPackageFile(Sender: TObject);
8079begin
8080  if (Sender as TIDEMenuItem).UserTag <> 0 then begin
8081    PackageEditingInterface.DoOpenPackageFile
8082      (TIDEPackage((Sender as TIDEMenuItem).UserTag).Filename,[pofAddToRecent],false)
8083  end;
8084end;
8085
8086procedure TSourceNotebook.OnPopupOpenProjectInsp(Sender: TObject);
8087begin
8088  MainIDEInterface.DoShowProjectInspector;
8089end;
8090
8091procedure TSourceNotebook.OpenAtCursorClicked(Sender: TObject);
8092begin
8093  if Assigned(Manager) and Assigned(Manager.OnOpenFileAtCursorClicked) then
8094    Manager.OnOpenFileAtCursorClicked(Sender);
8095end;
8096
8097procedure TSourceNotebook.CutClicked(Sender: TObject);
8098var ActSE: TSourceEditor;
8099begin
8100  ActSE := GetActiveSE;
8101  if ActSE <> nil then
8102    ActSE.DoEditorExecuteCommand(ecCut);
8103end;
8104
8105procedure TSourceNotebook.CopyClicked(Sender: TObject);
8106var ActSE: TSourceEditor;
8107begin
8108  ActSE := GetActiveSE;
8109  if ActSE <> nil then
8110    ActSE.DoEditorExecuteCommand(ecCopy);
8111end;
8112
8113procedure TSourceNotebook.PasteClicked(Sender: TObject);
8114var ActSE: TSourceEditor;
8115begin
8116  ActSE := GetActiveSE;
8117  if ActSE <> nil then
8118    ActSE.DoEditorExecuteCommand(ecPaste);
8119end;
8120
8121procedure TSourceNotebook.StatusBarClick(Sender: TObject);
8122var
8123  P: TPoint;
8124begin
8125  P := StatusBar.ScreenToClient(Mouse.CursorPos);
8126  if StatusBar.GetPanelIndexAt(P.X, P.Y) = 1  then
8127    EditorMacroForRecording.Stop;
8128end;
8129
8130procedure TSourceNotebook.StatusBarDblClick(Sender: TObject);
8131var
8132  P: TPoint;
8133begin
8134  P := StatusBar.ScreenToClient(Mouse.CursorPos);
8135  case StatusBar.GetPanelIndexAt(P.X, P.Y) of  // Based on panel:
8136    0: GoToLineMenuItemClick(Nil);    // Show "Goto Line" dialog.
8137    4: OpenFolderMenuItemClick(Nil);  // Show system file manager on file's folder.
8138  end;
8139end;
8140
8141procedure TSourceNotebook.StatusBarContextPopup(Sender: TObject; MousePos: TPoint;
8142  var Handled: Boolean);
8143var
8144  Pnl: Integer;
8145begin
8146  Pnl := StatusBar.GetPanelIndexAt(MousePos.X, MousePos.Y);
8147  GoToLineMenuItem.Visible := Pnl=0;
8148  OpenFolderMenuItem.Visible := Pnl=4;
8149  if Pnl in [0, 4] then
8150    StatusPopUpMenu.PopUp;
8151end;
8152
8153procedure TSourceNotebook.StatusBarDrawPanel(AStatusBar: TStatusBar; APanel: TStatusPanel;
8154  const ARect: TRect);
8155begin
8156  if APanel = StatusBar.Panels[1] then begin
8157    IDEImages.Images_16.ResolutionForControl[16, AStatusBar]
8158      .Draw(StatusBar.Canvas, ARect.Left,  ARect.Top, FStopBtnIdx);
8159  end;
8160end;
8161
8162procedure TSourceNotebook.ToggleBreakpointClicked(Sender: TObject);
8163var
8164  ASrcEdit: TSourceEditor;
8165  Line: LongInt;
8166  BreakPtMark: TSourceMark;
8167begin
8168  ASrcEdit:=GetActiveSE;
8169  if ASrcEdit=nil then exit;
8170  // create or delete breakpoint
8171  // find breakpoint mark at line
8172  Line:=ASrcEdit.EditorComponent.CaretY;
8173  BreakPtMark := SourceEditorMarks.FindBreakPointMark(ASrcEdit, Line);
8174  if BreakPtMark = nil then
8175    DebugBoss.DoCreateBreakPoint(ASrcEdit.Filename,Line,true)
8176  else
8177    DebugBoss.DoDeleteBreakPointAtMark(BreakPtMark);
8178end;
8179
8180procedure TSourceNotebook.ToggleBreakpointEnabledClicked(Sender: TObject);
8181var
8182  ASrcEdit: TSourceEditor;
8183  Line: LongInt;
8184  BreakPtMark: TSourceMark;
8185  BreakPoint: TIDEBreakPoint;
8186begin
8187  ASrcEdit:=GetActiveSE;
8188  if ASrcEdit=nil then exit;
8189  // create or delete breakpoint
8190  // find breakpoint mark at line
8191  Line:=ASrcEdit.EditorComponent.CaretY;
8192  BreakPtMark := SourceEditorMarks.FindBreakPointMark(ASrcEdit, Line);
8193  if BreakPtMark = nil then begin
8194    DebugBoss.DoCreateBreakPoint(ASrcEdit.Filename,Line,true, BreakPoint, True);
8195    if BreakPoint <> nil then begin
8196      BreakPoint.Enabled := False;
8197      BreakPoint.EndUpdate;
8198    end;
8199  end
8200  else
8201  begin
8202    BreakPoint := DebugBoss.BreakPoints.Find(ASrcEdit.FileName, Line);
8203    BreakPoint.Enabled := not BreakPoint.Enabled;
8204  end;
8205end;
8206
8207procedure TSourceNotebook.CompleteCodeMenuItemClick(Sender: TObject);
8208begin
8209  MainIDEInterface.DoCommand(ecCompleteCode);
8210end;
8211
8212procedure TSourceNotebook.DeleteBreakpointClicked(Sender: TObject);
8213var
8214  ASrcEdit: TSourceEditor;
8215begin
8216  ASrcEdit:=GetActiveSE;
8217  if ASrcEdit=nil then exit;
8218  DebugBoss.DoDeleteBreakPoint(ASrcEdit.Filename,
8219                               ASrcEdit.EditorComponent.CaretY);
8220end;
8221
8222procedure TSourceNotebook.ExtractProcMenuItemClick(Sender: TObject);
8223begin
8224  MainIDEInterface.DoCommand(ecExtractProc);
8225end;
8226
8227procedure TSourceNotebook.InvertAssignmentMenuItemClick(Sender: TObject);
8228var
8229  ASrcEdit: TSourceEditor;
8230begin
8231  ASrcEdit:=GetActiveSE;
8232  if ASrcEdit=nil then exit;
8233  ASrcEdit.InvertAssignment;
8234end;
8235
8236procedure TSourceNotebook.RenameIdentifierMenuItemClick(Sender: TObject);
8237begin
8238  MainIDEInterface.DoCommand(ecRenameIdentifier);
8239end;
8240
8241procedure TSourceNotebook.ShowAbstractMethodsMenuItemClick(Sender: TObject);
8242begin
8243  MainIDEInterface.DoCommand(ecShowAbstractMethods);
8244end;
8245
8246procedure TSourceNotebook.ShowEmptyMethodsMenuItemClick(Sender: TObject);
8247begin
8248  MainIDEInterface.DoCommand(ecRemoveEmptyMethods);
8249end;
8250
8251procedure TSourceNotebook.ShowUnusedUnitsMenuItemClick(Sender: TObject);
8252begin
8253  MainIDEInterface.DoCommand(ecRemoveUnusedUnits);
8254end;
8255
8256procedure TSourceNotebook.SourceNotebookDropFiles(Sender: TObject;
8257  const FileNames: array of String);
8258begin
8259  FManager.ActiveSourceWindow := Self;
8260  LazarusIDE.DoDropFiles(Sender,Filenames,WindowID);
8261end;
8262
8263procedure TSourceNotebook.FindOverloadsMenuItemClick(Sender: TObject);
8264begin
8265  MainIDEInterface.DoCommand(ecFindOverloads);
8266end;
8267
8268procedure TSourceNotebook.MakeResourceStringMenuItemClick(Sender: TObject);
8269begin
8270  MainIDEInterface.DoCommand(ecMakeResourceString);
8271end;
8272
8273function TSourceNotebook.NewFile(const NewShortName: String;
8274  ASource: TCodeBuffer; FocusIt: boolean; AShareEditor: TSourceEditor = nil): TSourceEditor;
8275var
8276  s: String;
8277Begin
8278  //create a new page
8279  debugln(SRCED_OPEN, '[TSourceNotebook.NewFile] A ');
8280  // Debugger cause ProcessMessages, which could lead to entering methods in unexpected order
8281  DebugBoss.LockCommandProcessing;
8282  try
8283    DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.NewFile'){$ENDIF};
8284    try
8285      IDEWindowCreators.ShowForm(Self,false);
8286      s := Manager.FindUniquePageName(NewShortName, AShareEditor);
8287      Result := NewSE(-1, -1, AShareEditor, s);
8288      debugln(SRCED_OPEN, '[TSourceNotebook.NewFile] B ');
8289      Result.CodeBuffer:=ASource;
8290      debugln(SRCED_OPEN, '[TSourceNotebook.NewFile] D ');
8291      //debugln(['TSourceNotebook.NewFile ',NewShortName,' ',ASource.Filename]);
8292      Result.PageName:= s;
8293      UpdatePageNames;
8294      UpdateProjectFiles(Result);
8295      UpdateStatusBar;
8296      Manager.SendEditorCreated(Result);
8297    finally
8298      EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.NewFile'){$ENDIF};
8299    end;
8300    if FocusIt then FocusEditor;
8301  finally
8302    DebugBoss.UnLockCommandProcessing;
8303  end;
8304  debugln(SRCED_OPEN, '[TSourceNotebook.NewFile] end');
8305  CheckFont;
8306end;
8307
8308procedure TSourceNotebook.CloseFile(APageIndex:integer);
8309var
8310  TempEditor: TSourceEditor;
8311  WasSelected: Boolean;
8312begin
8313  (* Do not use DisableAutoSizing in here, if a new Editor is focused it needs immediate autosize (during handle creation) *)
8314  // Inc/DecUpdateLockInternal does currently noth work, since a tab will be removed
8315  DebugLnEnter(SRCED_CLOSE, ['>> TSourceNotebook.CloseFile A  APageIndex=',APageIndex, ' Cur-Page=', PageIndex]);
8316  DebugBoss.LockCommandProcessing;
8317  try
8318    TempEditor:=FindSourceEditorWithPageIndex(APageIndex);
8319    if TempEditor=nil then exit;
8320    WasSelected:=PageIndex=APageIndex;
8321    debugln(SRCED_CLOSE, ['TSourceNotebook.CloseFile ', DbgSName(TempEditor), ' ', TempEditor.FileName]);
8322    EndIncrementalFind;
8323    TempEditor.Close;
8324    NoteBookDeletePage(APageIndex); // delete page before sending notification senEditorDestroyed
8325    TempEditor.Free;    // sends semEditorDestroy
8326    TempEditor:=nil;
8327    // delete the page
8328    UpdateProjectFiles;
8329    UpdatePageNames;
8330    if WasSelected then
8331      UpdateStatusBar;
8332    // set focus to new editor
8333    if (PageCount = 0) and (Parent=nil) then begin
8334      {$IFnDEF SingleSrcWindow}
8335      Manager.RemoveWindow(self);
8336      FManager := nil;
8337      {$ENDIF}
8338      if not FIsClosing then
8339        Close;
8340    end;
8341    // Move focus from Notebook-tabs to editor
8342    TempEditor:=FindSourceEditorWithPageIndex(PageIndex);
8343    if IsVisible and (TempEditor <> nil) and (FUpdateLock = 0) then
8344      // this line raises exception when editor is in other tab (for example - focused is designer)
8345      ;// TempEditor.EditorComponent.SetFocus;
8346  finally
8347    debugln(SRCED_CLOSE, ['TSourceNotebook.CloseFile UnLock']);
8348    DebugBoss.UnLockCommandProcessing;
8349    DebugLnExit(SRCED_CLOSE, ['<< TSourceNotebook.CloseFile']);
8350  end;
8351end;
8352
8353procedure TSourceNotebook.FocusEditor;
8354var
8355  SrcEdit: TSourceEditor;
8356begin
8357  if FUpdateLock > 0 then begin
8358    include(FUpdateFlags, ufFocusEditor);
8359    exit;
8360  end;
8361  if (fAutoFocusLock>0) then exit;
8362  SrcEdit:=GetActiveSE;
8363  if SrcEdit=nil then exit;
8364  SrcEdit.FocusEditor;
8365end;
8366
8367procedure TSourceNotebook.FormMouseUp(Sender: TObject; Button: TMouseButton;
8368  Shift: TShiftState; X, Y: Integer);
8369begin
8370  Cursor:=crDefault;
8371end;
8372
8373// Two Popup menu handlers:
8374procedure TSourceNotebook.GoToLineMenuItemClick(Sender: TObject);
8375begin
8376  if Assigned(Manager) then
8377    Manager.GotoLineClicked(nil);
8378end;
8379
8380procedure TSourceNotebook.OpenFolderMenuItemClick(Sender: TObject);
8381begin
8382  OpenDocument(ExtractFilePath(Statusbar.Panels[4].Text));
8383end;
8384
8385procedure TSourceNotebook.ExecuteEditorItemClick(Sender: TObject);
8386var
8387  Editor: TSourceEditor;
8388begin
8389  if SourceEditorManager = nil then exit;
8390
8391  Editor := TSourceEditor((sender as TIDEMenuCommand).UserTag);
8392  SourceEditorManager.ActiveEditor :=Editor;
8393  SourceEditorManager.ShowActiveWindowOnTop(True);
8394end;
8395
8396procedure TSourceNotebook.ApplyPageIndex;
8397begin
8398  Exclude(FUpdateFlags,ufPageIndexChanged);
8399  DebugBoss.LockCommandProcessing;
8400  try
8401    //debugln(['TSourceNotebook.ApplyPageIndex FPageIndex=',FPageIndex]);
8402    FPageIndex := Max(0,Min(FPageIndex,FNotebook.PageCount-1));
8403    if Assigned(Manager) and (FNotebook.PageIndex = FPageIndex) then
8404      DoActiveEditorChanged;
8405    // make sure the statusbar is updated
8406    Include(States, snNotebookPageChangedNeeded);
8407    FNotebook.PageIndex := FPageIndex;
8408    if snNotebookPageChangedNeeded in States then begin
8409      DebugLn(SRCED_PAGES, ['TSourceNotebook.ApplyPageIndex calling NotebookPageChanged']);
8410      NotebookPageChanged(nil);
8411    end;
8412    HistorySetMostRecent(FNotebook.Pages[FPageIndex]);
8413  finally
8414    DebugBoss.UnLockCommandProcessing;
8415  end;
8416end;
8417
8418procedure TSourceNotebook.CloseTabClicked(Sender: TObject);
8419begin
8420  if (GetKeyShiftState * [ssShift, ssCtrl, ssAlt] = EditorOpts.MiddleTabClickClosesOthersModifier) and
8421     (EditorOpts.MiddleTabClickClosesOthersModifier <> [])
8422  then
8423    CloseClicked(Sender, [ceoCloseOthers])
8424  else
8425  if (GetKeyShiftState * [ssShift, ssCtrl, ssAlt] = EditorOpts.MiddleTabClickClosesToRightModifier) and
8426     (EditorOpts.MiddleTabClickClosesToRightModifier <> [])
8427  then
8428    CloseClicked(Sender, [ceoCloseOthersOnRightSide])
8429  else
8430    CloseClicked(Sender, []);
8431end;
8432
8433function TSourceNotebook.GetEditors(Index:integer):TSourceEditor;
8434begin
8435  Result:=TSourceEditor(FSourceEditorList[Index]);
8436end;
8437
8438function TSourceNotebook.EditorCount:integer;
8439begin
8440  Result:=FSourceEditorList.Count;
8441end;
8442
8443function TSourceNotebook.IndexOfEditor(aEditor: TSourceEditorInterface): integer;
8444begin
8445  Result := FSourceEditorList.IndexOf(aEditor);
8446end;
8447
8448function TSourceNotebook.Count: integer;
8449begin
8450  Result:=FSourceEditorList.Count;
8451end;
8452
8453function TSourceNotebook.SourceEditorIntfWithFilename(const Filename: string
8454  ): TSourceEditorInterface;
8455var
8456  Node: TAvlTreeNode;
8457begin
8458  Node:=FSrcEditsSortedForFilenames.FindKey(Pointer(Filename),@CompareFilenameWithSrcEditIntf);
8459  if Node<>nil then
8460    Result:=TSourceEditorInterface(Node.Data)
8461  else
8462    Result:=nil;
8463end;
8464
8465procedure TSourceNotebook.CloseClicked(Sender: TObject;
8466  CloseOptions: TCloseSrcEditorOptions);
8467Begin
8468  if assigned(Manager) and Assigned(Manager.OnCloseClicked) then
8469    Manager.OnCloseClicked(Sender, CloseOptions);
8470end;
8471
8472procedure TSourceNotebook.ToggleFormUnitClicked(Sender: TObject);
8473begin
8474  if assigned(Manager) and Assigned(Manager.OnToggleFormUnitClicked) then
8475    Manager.OnToggleFormUnitClicked(Sender);
8476end;
8477
8478procedure TSourceNotebook.ToggleObjectInspClicked(Sender: TObject);
8479begin
8480  if assigned(Manager) and Assigned(Manager.OnToggleObjectInspClicked) then
8481    Manager.OnToggleObjectInspClicked(Sender);
8482end;
8483
8484procedure TSourceNotebook.HistorySetMostRecent(APage: TTabSheet);
8485var
8486  Index: Integer;
8487begin
8488   if APage = nil then
8489     Exit;
8490   Index := FHistoryList.IndexOf(APage);
8491   if Index <> -1 then
8492     FHistoryList.Delete(Index);
8493   FHistoryList.Insert(0, APage);
8494end;
8495
8496procedure TSourceNotebook.HistoryRemove(APage: TTabSheet);
8497var
8498  Index: Integer;
8499begin
8500  Index := FHistoryList.IndexOf(APage);
8501   if Index <> -1 then
8502     FHistoryList.Delete(Index);
8503end;
8504
8505function TSourceNotebook.HistoryGetTopPageIndex: Integer;
8506begin
8507  Result := -1;
8508  if FHistoryList.Count = 0 then
8509    Exit;
8510  Result := FNotebook.IndexOf(TCustomPage(FHistoryList.Items[0]));
8511end;
8512
8513procedure TSourceNotebook.InsertCharacter(const C: TUTF8Char);
8514var
8515  FActiveEdit: TSourceEditor;
8516begin
8517  FActiveEdit := GetActiveSE;
8518  if FActiveEdit <> nil then
8519  begin
8520    if FActiveEdit.ReadOnly then Exit;
8521    FActiveEdit.EditorComponent.InsertTextAtCaret(C);
8522  end;
8523end;
8524
8525procedure TSourceNotebook.SrcEditMenuCopyToExistingWindowClicked(Sender: TObject);
8526begin
8527  inc(FFocusLock);
8528  try
8529    CopyEditor(PageIndex, (Sender as TIDEMenuItem).Tag, -1);
8530  finally
8531    dec(FFocusLock);
8532  end;
8533end;
8534
8535procedure TSourceNotebook.SrcEditMenuMoveToExistingWindowClicked(Sender: TObject);
8536begin
8537  MoveEditor(PageIndex, (Sender as TIDEMenuItem).Tag, -1)
8538end;
8539
8540procedure TSourceNotebook.SrcEditMenuFindInWindowClicked(Sender: TObject);
8541var
8542  TargetIndex: Integer;
8543  DestWin: TSourceNotebook;
8544  Edit: TSourceEditor;
8545  SharedEditorIdx: Integer;
8546begin
8547  TargetIndex := (Sender as TIDEMenuItem).Tag;
8548  if (TargetIndex < 0) or (TargetIndex >= Manager.SourceWindowCount) then
8549    exit;
8550  DestWin := Manager.SourceWindows[TargetIndex];
8551  Edit := FindSourceEditorWithPageIndex(PageIndex);
8552  SharedEditorIdx := DestWin.IndexOfEditorInShareWith(Edit);
8553  If SharedEditorIdx < 0 then
8554    exit;
8555  Manager.ActiveEditor := DestWin.Editors[SharedEditorIdx];
8556  Manager.ShowActiveWindowOnTop(True);
8557end;
8558
8559procedure TSourceNotebook.EditorLockClicked(Sender: TObject);
8560begin
8561  GetActiveSE.IsLocked := not GetActiveSE.IsLocked;
8562end;
8563
8564procedure TSourceNotebook.UpdateStatusBar;
8565var
8566  tempEditor: TSourceEditor;
8567  PanelFilename: String;
8568  PanelCharMode: string;
8569  PanelXY: string;
8570  PanelFileMode: string;
8571  CurEditor: TSynEdit;
8572begin
8573  if FUpdateLock > 0 then begin
8574    include(FUpdateFlags, ufStatusBar);
8575    exit;
8576  end;
8577  if (not IsVisible) or (FUpdateLock > 0) then
8578  begin
8579    Include(States,snUpdateStatusBarNeeded);
8580    exit;
8581  end;
8582  Exclude(States,snUpdateStatusBarNeeded);
8583  TempEditor := GetActiveSE;
8584  if TempEditor = nil then Exit;
8585  CurEditor:=TempEditor.EditorComponent;
8586  //debugln(['TSourceNotebook.UpdateStatusBar ',tempEditor.FileName,' ',PageIndex]);
8587
8588  if (snIncrementalFind in States)
8589  and (CompareCaret(CurEditor.LogicalCaretXY,FIncrementalSearchPos)<>0) then
8590  begin
8591    // some action has changed the cursor during incremental search
8592    // -> end incremental search
8593    EndIncrementalFind;
8594    // this called UpdateStatusBar -> exit
8595    exit;
8596  end;
8597
8598  if (CurEditor.CaretY<>TempEditor.ErrorLine)
8599  or (CurEditor.CaretX<>TempEditor.fErrorColumn) then
8600    TempEditor.ErrorLine:=-1;
8601  Statusbar.BeginUpdate;
8602
8603  if snIncrementalFind in States then begin
8604    Statusbar.SimplePanel:=true;
8605    Statusbar.SimpleText:=Format(lisUESearching, [IncrementalSearchStr]);
8606
8607  end else begin
8608    Statusbar.SimplePanel:=false;
8609    PanelFilename:=TempEditor.Filename;
8610
8611    If TempEditor.Modified then
8612      PanelFileMode := ueModified
8613    else
8614      PanelFileMode := '';
8615
8616    If TempEditor.ReadOnly then begin
8617      if PanelFileMode <> '' then
8618        PanelFileMode := PanelFileMode + lisUEModeSeparator;
8619      PanelFileMode := PanelFileMode + uepReadonly;
8620    end;
8621
8622    if (EditorMacroForRecording.State = emRecording) and
8623       (EditorMacroForRecording.IsRecording(CurEditor))
8624    then begin
8625      if PanelFileMode <> '' then
8626        PanelFileMode := PanelFileMode + lisUEModeSeparator;
8627      PanelFileMode := PanelFileMode + ueMacroRecording;
8628    end;
8629    if (EditorMacroForRecording.State = emRecPaused) and
8630       (EditorMacroForRecording.IsRecording(CurEditor))
8631    then begin
8632      if PanelFileMode <> '' then
8633        PanelFileMode := PanelFileMode + lisUEModeSeparator;
8634      PanelFileMode := PanelFileMode + ueMacroRecordingPaused;
8635    end;
8636
8637    If TempEditor.IsLocked then begin
8638      if PanelFileMode <> '' then
8639        PanelFileMode := PanelFileMode + lisUEModeSeparator;
8640      PanelFileMode := PanelFileMode + ueLocked;
8641    end;
8642
8643    PanelXY := Format(' %6d:%4d',
8644                 [TempEditor.CurrentCursorYLine,TempEditor.CurrentCursorXLine]);
8645
8646    if GetActiveSE.InsertMode then
8647      PanelCharMode := uepIns
8648    else
8649      PanelCharMode := uepOvr;
8650
8651    Statusbar.Panels[0].Text := PanelXY;
8652    StatusBar.Panels[2].Text := PanelFileMode;
8653    Statusbar.Panels[3].Text := PanelCharMode;
8654    Statusbar.Panels[4].Text := PanelFilename;
8655    if(EditorMacroForRecording.IsRecording(CurEditor)) then
8656      Statusbar.Panels[1].Width := IDEImages.ScaledSize(20)
8657    else
8658      Statusbar.Panels[1].Width := 0;
8659
8660  end;
8661  Statusbar.EndUpdate;
8662
8663  CheckCurrentCodeBufferChanged;
8664End;
8665
8666function TSourceNotebook.FindPageWithEditor(ASourceEditor: TSourceEditor): integer;
8667var
8668  LTabSheet, LParent: TWinControl;
8669begin
8670  Result:=-1;
8671  LParent := ASourceEditor.EditorComponent.Parent;
8672  if LParent is TTabSheet then
8673  begin
8674    repeat
8675      LTabSheet := LParent;
8676      LParent := LParent.Parent;
8677    until (LParent = FNotebook) or (LParent = nil);
8678    if (LParent <> nil) and (LTabSheet is TTabSheet) then
8679      Result:=TTabSheet(LTabSheet).PageIndex;
8680  end;
8681end;
8682
8683function TSourceNotebook.FindSourceEditorWithEditorComponent(EditorComp: TComponent): TSourceEditor;
8684var
8685  i: integer;
8686begin
8687  for i:=0 to EditorCount-1 do begin
8688    Result:=Editors[i];
8689    if Result.EditorComponent=EditorComp then exit;
8690  end;
8691  Result:=nil;
8692end;
8693
8694procedure TSourceNotebook.NotebookMouseDown(Sender: TObject; Button: TMouseButton;
8695  Shift: TShiftState; X, Y: Integer);
8696var
8697  TabIndex: Integer;
8698begin
8699  if (Button = mbMiddle) then
8700  begin
8701    TabIndex:=FNotebook.IndexOfPageAt(X, Y);
8702    if TabIndex>=0 then begin
8703      if (GetKeyShiftState * [ssShift, ssCtrl, ssAlt] = EditorOpts.MiddleTabClickClosesOthersModifier) and
8704         (EditorOpts.MiddleTabClickClosesOthersModifier <> [])
8705      then
8706        CloseClicked(NoteBookPage[TabIndex], [ceoCloseOthers])
8707      else
8708      if (GetKeyShiftState * [ssShift, ssCtrl, ssAlt] = EditorOpts.MiddleTabClickClosesToRightModifier) and
8709         (EditorOpts.MiddleTabClickClosesToRightModifier <> [])
8710      then
8711        CloseClicked(NoteBookPage[TabIndex], [ceoCloseOthersOnRightSide])
8712      else
8713        CloseClicked(NoteBookPage[TabIndex], []);
8714    end;
8715  end else
8716  if (Button = mbRight) then
8717  begin
8718    //select on right click
8719    TabIndex:=FNotebook.IndexOfPageAt(X, Y);
8720    if TabIndex>=0 then
8721    begin
8722      FNotebook.ActivePageIndex := TabIndex;
8723      if Assigned(IDEDockMaster) then
8724        Manager.ActiveEditor:=GetActiveSE;
8725    end;
8726  end;
8727end;
8728
8729procedure TSourceNotebook.NotebookMouseUp(Sender: TObject;
8730  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
8731var
8732  TabIndex: Integer;
8733begin
8734  if (Button = mbRight) then
8735  begin
8736    TabIndex:=FNotebook.IndexOfPageAt(X, Y);
8737    if TabIndex>=0 then
8738    begin
8739      TabPopUpMenu.PopupComponent := FNotebook;
8740      TabPopUpMenu.PopUp;
8741      TabPopUpMenu.PopupComponent := nil;
8742    end;
8743  end;
8744end;
8745
8746procedure TSourceNotebook.NotebookDragDropEx(Sender, Source: TObject; OldIndex,
8747  NewIndex: Integer; CopyDrag: Boolean; var Done: Boolean);
8748  function SourceIndex: Integer;
8749  begin
8750    Result := Manager.SourceWindowCount - 1;
8751    while Result >= 0 do begin
8752      if Manager.SourceWindows[Result].FNotebook = Source then break;
8753      dec(Result);
8754    end;
8755  end;
8756begin
8757  {$IFnDEF SingleSrcWindow}
8758  If CopyDrag then begin
8759    Manager.SourceWindows[SourceIndex].CopyEditor
8760      (OldIndex, Manager.IndexOfSourceWindow(self), NewIndex);
8761  end
8762  else begin
8763  {$ENDIF}
8764    if (Source = FNotebook) then
8765      MoveEditor(OldIndex, NewIndex)
8766    else begin
8767      Manager.SourceWindows[SourceIndex].MoveEditor
8768        (OldIndex, Manager.IndexOfSourceWindow(self), NewIndex);
8769    end;
8770  {$IFnDEF SingleSrcWindow}
8771  end;
8772  {$ENDIF}
8773  Manager.ActiveSourceWindow := self;
8774  Manager.ShowActiveWindowOnTop(True);
8775  Done := True;
8776end;
8777
8778procedure TSourceNotebook.NotebookDragOverEx(Sender, Source: TObject;
8779  OldIndex, NewIndex: Integer; CopyDrag: Boolean; var Accept: Boolean);
8780
8781  function SourceIndex: Integer;
8782  begin
8783    Result := Manager.SourceWindowCount - 1;
8784    while Result >= 0 do begin
8785      if Manager.SourceWindows[Result].FNotebook = Source then break;
8786      dec(Result);
8787    end;
8788  end;
8789var
8790  Src: TSourceNotebook;
8791  NBHasSharedEditor: Boolean;
8792begin
8793  Src := Manager.SourceWindows[SourceIndex];
8794  NBHasSharedEditor := IndexOfEditorInShareWith
8795    (Src.FindSourceEditorWithPageIndex(OldIndex)) >= 0;
8796  {$IFnDEF SingleSrcWindow}
8797  if CopyDrag then
8798    Accept := (NewIndex >= 0) and (Source <> Sender) and (not NBHasSharedEditor)
8799  else
8800  {$ENDIF}
8801    Accept := (NewIndex >= 0) and
8802              ((Source <> Sender) or (OldIndex <> NewIndex)) and
8803              ((Source = Sender) or (not NBHasSharedEditor));
8804end;
8805
8806procedure TSourceNotebook.NotebookDragOver(Sender, Source: TObject; X, Y: Integer;
8807  State: TDragState; var Accept: Boolean);
8808begin
8809  if Accept=true then ; // set by NotebookDragOverEx
8810  FUpdateTabAndPageTimer.Enabled := False;
8811  if State = dsDragLeave then
8812    FUpdateTabAndPageTimer.Enabled := True
8813  else if Source is TExtendedNotebook then
8814    FNotebook.ShowTabs := (Manager=nil) or Manager.ShowTabs;
8815end;
8816
8817procedure TSourceNotebook.NotebookEndDrag(Sender, Target: TObject; X, Y: Integer);
8818begin
8819  FUpdateTabAndPageTimer.Enabled := True;
8820end;
8821
8822procedure TSourceNotebook.NotebookPageChanged(Sender: TObject);
8823var
8824  SrcEdit:TSourceEditor;
8825  CaretXY: TPoint;
8826  TopLine: Integer;
8827Begin
8828  if (Manager = nil) or (FUpdateLock > 0) Then begin
8829    Include(States, snNotebookPageChangedNeeded);
8830    exit;
8831  end;
8832  DebugLnEnter(SRCED_PAGES, ['>> TSourceNotebook.NotebookPageChanged PageIndex=', PageIndex, ' AutoFocusLock=', fAutoFocusLock, ' Sender=',DbgSName(Sender)]);
8833
8834  DebugBoss.LockCommandProcessing;
8835  try
8836    Exclude(States, snNotebookPageChangedNeeded);
8837    SrcEdit:=GetActiveSE;
8838    Manager.FHints.HideIfVisible;
8839    if (CodeContextFrm<>nil) then
8840      CodeContextFrm.Hide;
8841
8842    DebugLn(SRCED_PAGES, ['TSourceNotebook.NotebookPageChanged TempEdit=', DbgSName(SrcEdit), ' Vis=', dbgs(IsVisible), ' Hnd=', dbgs(HandleAllocated)]);
8843    if SrcEdit <> nil then
8844    begin
8845      if not SrcEdit.Visible then begin
8846        // As long as SynEdit had no Handle, it had kept all those Values untouched
8847        CaretXY := SrcEdit.EditorComponent.CaretXY;
8848        TopLine := SrcEdit.EditorComponent.TopLine;
8849        TSynEditMarkupManager(SrcEdit.EditorComponent.MarkupMgr).IncPaintLock;
8850        SrcEdit.BeginUpdate;
8851        SrcEdit.FEditor.HandleNeeded; // make sure we have a handle
8852        SrcEdit.Visible := True;
8853        SrcEdit.EndUpdate;
8854        // Restore the intial Positions, must be after lock
8855        SrcEdit.EditorComponent.LeftChar := 1;
8856        SrcEdit.EditorComponent.CaretXY := CaretXY;
8857        SrcEdit.EditorComponent.TopLine := TopLine;
8858        TSynEditMarkupManager(SrcEdit.EditorComponent.MarkupMgr).DecPaintLock;
8859        SrcEdit.UpdateIfDefNodeStates; // after editor is initialized
8860      end;
8861      if (fAutoFocusLock=0) and (Screen.ActiveCustomForm=GetParentForm(Self)) and
8862         not(Manager.HasAutoFocusLock)
8863      then
8864      begin
8865        DebugLnEnter(SRCED_PAGES, ['TSourceNotebook.NotebookPageChanged BEFORE SetFocus ', DbgSName(SrcEdit.EditorComponent),' Page=',   FindPageWithEditor(SrcEdit), ' ', SrcEdit.FileName]);
8866        SrcEdit.FocusEditor; // recursively calls NotebookPageChanged, via EditorEnter
8867        DebugLnExit(SRCED_PAGES, ['TSourceNotebook.NotebookPageChanged AFTER SetFocus ', DbgSName(SrcEdit.EditorComponent),' Page=',   FindPageWithEditor(SrcEdit)]);
8868      end;
8869      UpdateStatusBar;
8870      UpdateActiveEditColors(SrcEdit.EditorComponent);
8871      if (DebugBoss.State in [dsPause, dsRun]) and
8872         not SrcEdit.HasExecutionMarks and
8873         (SrcEdit.FileName <> '') then
8874        SrcEdit.FillExecutionMarks;
8875      DoActiveEditorChanged;
8876    end;
8877
8878    CheckCurrentCodeBufferChanged;
8879  finally
8880    DebugBoss.UnLockCommandProcessing;
8881  end;
8882  DebugLnExit(SRCED_PAGES, ['<< TSourceNotebook.NotebookPageChanged ']);
8883end;
8884
8885procedure TSourceNotebook.ProcessParentCommand(Sender: TObject;
8886  var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
8887  var Handled: boolean);
8888var
8889  IDECmd: TIDECommand;
8890  r: Boolean;
8891begin
8892  //DebugLn(['TSourceNotebook.ProcessParentCommand START ',dbgsName(Sender),' Command=',Command,' AChar=',AChar]);
8893
8894  FProcessingCommand:=true;
8895  if Assigned(Manager.OnProcessUserCommand) then begin
8896    Handled:=false;
8897    IDECmd:=IDECommandList.FindIDECommand(Command);
8898    r := (IDECmd <> nil) and (IDECmd.OnExecuteProc = @ExecuteIdeMenuClick);
8899    if r then IDECmd.OnExecuteProc := nil;
8900
8901    Manager.OnProcessUserCommand(Self,Command,Handled);
8902
8903    if r then IDECmd.OnExecuteProc := @ExecuteIdeMenuClick;
8904
8905    if Handled or (Command=ecNone) then begin
8906      FProcessingCommand:=false;
8907      Command:=ecNone;
8908      exit;
8909    end;
8910  end;
8911  //DebugLn(['TSourceNotebook.ProcessParentCommand after mainide: ',dbgsName(Sender),' Command=',Command,' AChar=',AChar]);
8912
8913  Handled:=true;
8914  case Command of
8915  ecNextEditor:           NextEditor;
8916  ecPrevEditor:           PrevEditor;
8917  ecPrevEditorInHistory:  FHistoryDlg.Show(True);
8918  ecNextEditorInHistory:  FHistoryDlg.Show(False);
8919  ecMoveEditorLeft:       MoveActivePageLeft;
8920  ecMoveEditorRight:      MoveActivePageRight;
8921  ecMoveEditorLeftmost:   MoveActivePageFirst;
8922  ecMoveEditorRightmost:  MoveActivePageLast;
8923  ecNextSharedEditor:     GotoNextSharedEditor(False);
8924  ecPrevSharedEditor:     GotoNextSharedEditor(True);
8925  ecNextWindow:           GotoNextWindow(False);
8926  ecPrevWindow:           GotoNextWindow(True);
8927  ecMoveEditorNextWindow: MoveEditorNextWindow(False, False);
8928  ecMoveEditorPrevWindow: MoveEditorNextWindow(True, False);
8929  ecMoveEditorNewWindow:
8930    if EditorCount > 1 then
8931      MoveEditor(FindPageWithEditor(GetActiveSE),
8932                 Manager.IndexOfSourceWindow(Manager.CreateNewWindow(True)), -1);
8933
8934  ecCopyEditorNextWindow: MoveEditorNextWindow(False, True);
8935  ecCopyEditorPrevWindow: MoveEditorNextWindow(True, True);
8936  ecCopyEditorNewWindow:
8937    CopyEditor(FindPageWithEditor(GetActiveSE),
8938               Manager.IndexOfSourceWindow(Manager.CreateNewWindow(True)), -1, True);
8939
8940  ecOpenFileAtCursor:     OpenAtCursorClicked(self);
8941  ecGotoEditor1..ecGotoEditor9,ecGotoEditor0:
8942    if PageCount>Command-ecGotoEditor1 then
8943      PageIndex := Command-ecGotoEditor1;
8944
8945  ecToggleFormUnit:       ToggleFormUnitClicked(Self);
8946  ecToggleObjectInsp:     ToggleObjectInspClicked(Self);
8947  ecSetFreeBookmark:
8948    if Assigned(Manager.OnSetBookmark) then
8949      Manager.OnSetBookmark(GetActiveSE, -1, False);
8950
8951  ecClearAllBookmark:
8952    if Assigned(Manager.OnClearBookmarkId) then
8953      Manager.OnClearBookmarkId(Self, -1);
8954
8955  ecJumpBack:             Manager.HistoryJump(Self,jhaBack);
8956  ecJumpForward:          Manager.HistoryJump(Self,jhaForward);
8957  ecAddJumpPoint:         Manager.AddJumpPointClicked(Self);
8958  ecViewJumpHistory:      Manager.ViewJumpHistoryClicked(Self);
8959
8960  else
8961    Handled:=ExecuteIDECommand(Self,Command);
8962    DebugLn('TSourceNotebook.ProcessParentCommand Command=',dbgs(Command),' Handled=',dbgs(Handled));
8963  end;  //case
8964  if Handled then Command:=ecNone;
8965  FProcessingCommand:=false;
8966end;
8967
8968procedure TSourceNotebook.ParentCommandProcessed(Sender: TObject;
8969  var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
8970  var Handled: boolean);
8971begin
8972  Assert(Assigned(Manager), 'TSourceNotebook.ParentCommandProcessed: Manager=Nil.');
8973  if Assigned(Manager.OnUserCommandProcessed) then begin
8974    Handled:=false;
8975    Manager.OnUserCommandProcessed(Self,Command,Handled);
8976    if Handled then exit;
8977  end;
8978
8979  Handled:=(Command=ecClose);
8980
8981  if Handled then Command:=ecNone;
8982end;
8983
8984procedure TSourceNotebook.ReloadEditorOptions;
8985var
8986  I: integer;
8987Begin
8988  for i := 0 to EditorCount-1 do
8989    Editors[i].RefreshEditorSettings;
8990
8991  if EditorOpts.ShowTabCloseButtons then
8992    FNoteBook.Options:=FNoteBook.Options+[nboShowCloseButtons]
8993  else
8994    FNoteBook.Options:=FNoteBook.Options-[nboShowCloseButtons];
8995  FNoteBook.MultiLine := EditorOpts.MultiLineTab;
8996  if FNotebook.ShowTabs then
8997    FNotebook.TabPosition := EditorOpts.TabPosition
8998  else
8999    FNotebook.TabPosition := tpTop;
9000
9001  Exclude(States,snWarnedFont);
9002  CheckFont;
9003  UpdatePageNames;
9004end;
9005
9006procedure TSourceNotebook.CheckFont;
9007var
9008  SrcEdit: TSourceEditor;
9009  DummyResult: TModalResult;
9010  CurFont: TFont;
9011begin
9012  if (snWarnedFont in States) then exit;
9013  Include(States,snWarnedFont);
9014  SrcEdit:=GetActiveSE;
9015  if SrcEdit = nil then
9016    Exit;
9017  CurFont:=SrcEdit.EditorComponent.Font;
9018  if SystemCharSetIsUTF8
9019  and ((EditorOpts.DoNotWarnForFont='')
9020       or (EditorOpts.DoNotWarnForFont<>CurFont.Name))
9021  then begin
9022    {$IFDEF HasMonoSpaceFonts}
9023    DummyResult:=IDEQuestionDialog(lisUEFontWith,
9024      Format(lisUETheCurre, [LineEnding, LineEnding]),
9025      mtWarning, [mrIgnore, mrYesToAll, lisUEDoNotSho]);
9026    {$ELSE}
9027    DummyResult:=mrYesToAll;
9028    {$ENDIF}
9029    if DummyResult=mrYesToAll then begin
9030      if EditorOpts.DoNotWarnForFont<>CurFont.Name then begin
9031        EditorOpts.DoNotWarnForFont:=CurFont.Name;
9032        EditorOpts.Save;
9033      end;
9034    end;
9035  end;
9036end;
9037
9038procedure TSourceNotebook.BeginAutoFocusLock;
9039begin
9040  inc(fAutoFocusLock);
9041end;
9042
9043procedure TSourceNotebook.EndAutoFocusLock;
9044begin
9045  dec(fAutoFocusLock);
9046end;
9047
9048procedure TSourceNotebook.EditorMouseMove(Sender: TObject; Shift: TShiftstate;
9049  X, Y: Integer);
9050begin
9051  Manager.FHints.HideAutoHintAfterMouseMoved;
9052  if Visible then
9053    Manager.FHints.UpdateHintTimer;
9054end;
9055
9056procedure TSourceNotebook.EditorMouseWheel(Sender: TObject; Shift: TShiftState;
9057  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
9058begin
9059  //handled:=true; //The scrolling is not done: it's not handled! See TWinControl.DoMouseWheel
9060end;
9061
9062procedure TSourceNotebook.EditorMouseDown(Sender: TObject;
9063  Button: TMouseButton; Shift: TShiftstate; X, Y: Integer);
9064begin
9065
9066end;
9067
9068function TSourceNotebook.EditorGetIndent(Sender: TObject; Editor: TObject;
9069  LogCaret, OldLogCaret: TPoint; FirstLinePos, LastLinePos: Integer;
9070  Reason: TSynEditorCommand; SetIndentProc: TSynBeautifierSetIndentProc
9071  ): Boolean;
9072var
9073  SrcEdit: TSourceEditor;
9074  p: LongInt;
9075  NestedComments: Boolean;
9076  NewIndent: TFABIndentationPolicy;
9077  Indent: LongInt;
9078  CodeBuf: TCodeBuffer;
9079begin
9080  Result:=false;
9081  // SynBeautifier is shared arrcoss SynEdits, and may call the wrong SrcNoteBook
9082  if assigned(Manager)
9083  then SrcEdit := Manager.FindSourceEditorWithEditorComponent(TComponent(Editor))
9084  else SrcEdit := FindSourceEditorWithEditorComponent(TComponent(Editor));
9085  if SrcEdit = nil then
9086    exit;
9087  if assigned(Manager) and Assigned(Manager.OnGetIndent) then begin
9088    Result := Manager.OnGetIndent(Sender, SrcEdit, LogCaret, OldLogCaret, FirstLinePos, LastLinePos,
9089                          Reason, SetIndentProc);
9090    if Result then exit;
9091  end;
9092  if (SrcEdit.SyncroLockCount > 0) then exit;
9093  if not (SrcEdit.SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
9094    exit;
9095  if Reason<>ecLineBreak then exit;
9096  if not CodeToolsOpts.IndentOnLineBreak then exit;
9097  {$IFDEF VerboseIndenter}
9098  debugln(['TSourceNotebook.EditorGetIndent LogCaret=',dbgs(LogCaret),' FirstLinePos=',FirstLinePos,' LastLinePos=',LastLinePos]);
9099  {$ENDIF}
9100  Result := True;
9101  SrcEdit.UpdateCodeBuffer;
9102  CodeBuf:=SrcEdit.CodeBuffer;
9103  CodeBuf.LineColToPosition(LogCaret.Y,LogCaret.X,p);
9104  if p<1 then exit;
9105  {$IFDEF VerboseIndenter}
9106  if FirstLinePos>0 then
9107    DebugLn(['TSourceNotebook.EditorGetIndent Firstline-1=',SrcEdit.Lines[FirstLinePos-2]]);
9108  DebugLn(['TSourceNotebook.EditorGetIndent Firstline+0=',SrcEdit.Lines[FirstLinePos-1]]);
9109  if FirstLinePos<SrcEdit.LineCount then
9110    DebugLn(['TSourceNotebook.EditorGetIndent Firstline+1=',SrcEdit.Lines[FirstLinePos+0]]);
9111  DebugLn(['TSourceNotebook.EditorGetIndent CodeBuffer: ',dbgstr(copy(CodeBuf.Source,p-10,10)),'|',dbgstr(copy(CodeBuf.Source,p,10))]);
9112  DebugLn(['TSourceNotebook.EditorGetIndent CodeBuffer: "',copy(CodeBuf.Source,p-10,10),'|',copy(CodeBuf.Source,p,10)]);
9113  {$ENDIF}
9114  NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuf.Filename);
9115  if not CodeToolBoss.Indenter.GetIndent(CodeBuf.Source,p,NestedComments,
9116    True,NewIndent,CodeToolsOpts.IndentContextSensitive)
9117  then exit;
9118  if not NewIndent.IndentValid then exit;
9119  Indent:=NewIndent.Indent;
9120  {$IFDEF VerboseIndenter}
9121  DebugLn(['TSourceNotebook.EditorGetIndent Indent=',Indent]);
9122  {$ENDIF}
9123  {$IFDEF VerboseIndenter}
9124  DebugLn(['TSourceNotebook.EditorGetIndent Apply to FirstLinePos+1']);
9125  {$ENDIF}
9126  SetIndentProc(LogCaret.Y, Indent, 0,' ');
9127  SrcEdit.CursorScreenXY:=Point(Indent+1,SrcEdit.CursorScreenXY.Y);
9128end;
9129
9130procedure TSourceNotebook.OnApplicationDeactivate(Sender: TObject);
9131begin
9132  if (CodeContextFrm<>nil) then
9133    CodeContextFrm.Hide;
9134  if (Manager<>nil) and (Manager.FHints<>nil) then
9135    Manager.FHints.HideIfVisible;
9136end;
9137
9138procedure TSourceNotebook.EditorKeyDown(Sender: TObject; var Key: Word;
9139  Shift: TShiftState);
9140begin
9141
9142end;
9143
9144procedure TSourceNotebook.EditorKeyUp(Sender: TObject; var Key: Word;
9145  Shift: TShiftState);
9146begin
9147
9148end;
9149
9150procedure TSourceNotebook.ShowSynEditHint(const MousePos: TPoint);
9151var
9152  EditPos: TPoint;
9153  ASrcEdit: TSourceEditor;
9154  ASynEdit: TSynEdit;
9155  EditCaret: TPoint;
9156  AMark: TSourceMark;
9157  i: integer;
9158  HintStr: String;
9159  CurHint: String;
9160  MLine: TSynEditMarkLine;
9161begin
9162  // hide other hints
9163  //debugln('TSourceNotebook.ShowSynEditHint A');
9164  Application.HideHint;
9165  //
9166  ASrcEdit:=GetActiveSE;
9167  if ASrcEdit=nil then exit;
9168  ASynEdit:=ASrcEdit.EditorComponent;
9169  EditPos:=ASynEdit.ScreenToClient(MousePos);
9170  if not PtInRect(ASynEdit.ClientRect,EditPos) then exit;
9171  EditCaret:=ASynEdit.PhysicalToLogicalPos(ASynEdit.PixelsToRowColumn(EditPos));
9172  if (EditCaret.Y<1) then exit;
9173  if EditPos.X<ASynEdit.Gutter.Width then begin
9174    // hint for a gutter item
9175    if EditorOpts.ShowGutterHints then begin
9176      HintStr:='';
9177      MLine := ASynEdit.Marks.Line[EditCaret.Y];
9178      if MLine <> nil then begin
9179        if ASynEdit.BookMarkOptions.DrawBookmarksFirst then
9180          MLine.Sort(smsoBookmarkFirst, smsoColumn)
9181        else
9182          MLine.Sort(smsoBookMarkLast, smsoColumn);
9183
9184        for i := 0 to MLine.Count - 1 do begin
9185          if not (MLine[i] is TSourceMark) then continue;
9186          AMark := TSourceMark(MLine[i]);
9187          if AMark = nil then continue;
9188          CurHint:=AMark.GetHint;
9189          if CurHint='' then continue;
9190          if HintStr<>'' then HintStr:=HintStr+LineEnding;
9191          HintStr:=HintStr+CurHint;
9192        end;
9193
9194        if (MessagesView<>nil) then
9195          MessagesView.SourceEditorHint(MLine,HintStr);
9196      end;
9197
9198      if HintStr<>'' then
9199        Manager.ActivateHint(MousePos,'',HintStr);
9200    end;
9201  end else begin
9202    // hint for source
9203    if Assigned(Manager) and Assigned(Manager.OnShowHintForSource) then
9204      Manager.OnShowHintForSource(ASrcEdit,EditCaret, True);
9205  end;
9206end;
9207
9208procedure TSourceNotebook.SetIncrementalSearchStr(const AValue: string);
9209begin
9210  if FIncrementalSearchStr=AValue then exit;
9211  FIncrementalSearchStr:=AValue;
9212  IncrementalSearch(False, False);
9213end;
9214
9215procedure TSourceNotebook.IncrementalSearch(ANext, ABackward: Boolean);
9216const
9217  SEARCH_OPTS: array[Boolean] of TSynSearchOptions = ([], [ssoBackwards]);
9218var
9219  CurEdit: TSynEdit;
9220  AStart : TPoint;
9221begin
9222  if not (snIncrementalFind in States)
9223  then begin
9224    UpdateStatusBar;
9225    Exit;
9226  end;
9227  if FIncrementalSearchEditor = nil then Exit;
9228
9229  // search string
9230  CurEdit := FIncrementalSearchEditor.EditorComponent;
9231  CurEdit.BeginUpdate;
9232  if FIncrementalSearchStr<>''
9233  then begin
9234    // search from search start position when not searching for the next
9235    AStart := CurEdit.LogicalCaretXY;
9236    if not ANext
9237    then AStart := FIncrementalSearchStartPos
9238    else if ABackward
9239    then AStart := CurEdit.BlockBegin;
9240    FIncrementalSearchBackwards:=ABackward;
9241    CurEdit.SearchReplaceEx(FIncrementalSearchStr,'', SEARCH_OPTS[ABackward], AStart);
9242
9243    // searching next resets incremental history
9244    if ANext
9245    then begin
9246      FIncrementalSearchStartPos := CurEdit.BlockBegin;
9247    end;
9248
9249    // cut the not found
9250    FIncrementalSearchStr := CurEdit.SelText;
9251
9252    CurEdit.SetHighlightSearch(FIncrementalSearchStr, []);
9253    if Length(FIncrementalSearchStr) > 0
9254    then FIncrementalFoundStr := FIncrementalSearchStr;
9255  end
9256  else begin
9257    // go to start
9258    CurEdit.LogicalCaretXY:= FIncrementalSearchStartPos;
9259    CurEdit.BlockBegin:=CurEdit.LogicalCaretXY;
9260    CurEdit.BlockEnd:=CurEdit.BlockBegin;
9261    CurEdit.SetHighlightSearch('', []);
9262  end;
9263  FIncrementalSearchPos:=CurEdit.LogicalCaretXY;
9264  CurEdit.EndUpdate;
9265
9266  UpdateStatusBar;
9267end;
9268
9269procedure TSourceNotebook.Activate;
9270begin
9271  inherited Activate;
9272  if assigned(Manager) then begin
9273    Manager.ActiveSourceWindow := self;
9274    Manager.DoWindowFocused(Self);
9275  end;
9276end;
9277
9278procedure TSourceNotebook.UpdateActiveEditColors(AEditor: TSynEdit);
9279begin
9280  if AEditor=nil then exit;
9281  EditorOpts.SetMarkupColors(AEditor);
9282  AEditor.UseIncrementalColor:= snIncrementalFind in States;
9283end;
9284
9285procedure TSourceNotebook.ClearExecutionLines;
9286var
9287  i: integer;
9288begin
9289  for i := 0 to EditorCount - 1 do
9290    Editors[i].ExecutionLine := -1;
9291end;
9292
9293procedure TSourceNotebook.ClearExecutionMarks;
9294var
9295  i: integer;
9296begin
9297  for i := 0 to EditorCount - 1 do
9298    Editors[i].ClearExecutionMarks;
9299end;
9300
9301//-----------------------------------------------------------------------------
9302
9303procedure InternalInit;
9304var
9305  h: TLazSyntaxHighlighter;
9306begin
9307  // fetch the resourcestrings before they are translated
9308  EnglishGPLNotice:=lisGPLNotice;
9309  EnglishLGPLNotice:=lisLGPLNotice;
9310  EnglishModifiedLGPLNotice:=lisModifiedLGPLNotice;
9311  EnglishMITNotice:=lisMITNotice;
9312
9313  for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
9314    Highlighters[h]:=nil;
9315  IDESearchInText:=@SearchInText;
9316  PasBeautifier := TSynBeautifierPascal.Create(nil);
9317
9318  SRCED_LOCK  := DebugLogger.RegisterLogGroup('SRCED_LOCK' {$IFDEF SRCED_LOCK} , True {$ENDIF} );
9319  SRCED_OPEN  := DebugLogger.RegisterLogGroup('SRCED_OPEN' {$IFDEF SRCED_OPEN} , True {$ENDIF} );
9320  SRCED_CLOSE := DebugLogger.RegisterLogGroup('SRCED_CLOSE' {$IFDEF SRCED_CLOSE} , True {$ENDIF} );
9321  SRCED_PAGES := DebugLogger.RegisterLogGroup('SRCED_PAGES' {$IFDEF SRCED_PAGES} , True {$ENDIF} );
9322
9323  IDEWindowsGlobalOptions.Add(NonModalIDEWindowNames[nmiwSourceNoteBook], False);
9324end;
9325
9326procedure InternalFinal;
9327var
9328  h: TLazSyntaxHighlighter;
9329begin
9330  for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
9331    FreeThenNil(Highlighters[h]);
9332  FreeThenNil(aWordCompletion);
9333  FreeAndNil(PasBeautifier);
9334end;
9335
9336{ TSourceEditorManagerBase }
9337
9338procedure TSourceEditorManagerBase.DoMacroRecorderState(Sender: TObject);
9339var
9340  i: Integer;
9341begin
9342  For i := 0 to SourceWindowCount - 1 do
9343    TSourceNotebook(SourceWindows[i]).UpdateStatusBar;
9344  DoEditorMacroStateChanged;
9345end;
9346
9347procedure TSourceEditorManagerBase.FreeSourceWindows;
9348var
9349  s: TSourceEditorWindowInterface;
9350begin
9351  PasBeautifier.OnGetDesiredIndent := nil;
9352  FSourceWindowByFocusList.Clear;
9353  while FSourceWindowList.Count > 0 do begin
9354    s := TSourceEditorWindowInterface(FSourceWindowList[0]);
9355    FSourceWindowList.Delete(0);
9356    s.Free;
9357  end;
9358  FSourceWindowList.Clear;
9359end;
9360
9361function TSourceEditorManagerBase.GetActiveSourceWindowIndex: integer;
9362begin
9363  Result := IndexOfSourceWindow(ActiveSourceWindow);
9364end;
9365
9366function TSourceEditorManagerBase.GetSourceWindowByLastFocused(Index: Integer): TSourceEditorWindowInterface;
9367begin
9368  Result := TSourceEditorWindowInterface(FSourceWindowByFocusList[Index]);
9369end;
9370
9371procedure TSourceEditorManagerBase.SetActiveSourceWindowIndex(const AValue: integer);
9372begin
9373  ActiveSourceWindow := SourceWindows[AValue];
9374end;
9375
9376procedure TSourceEditorManagerBase.SetShowTabs(const AShowTabs: Boolean);
9377begin
9378  FShowTabs := AShowTabs;
9379end;
9380
9381function TSourceEditorManagerBase.GetActiveSourceWindow: TSourceEditorWindowInterface;
9382begin
9383  Result := FActiveWindow;
9384end;
9385
9386procedure TSourceEditorManagerBase.SetActiveSourceWindow(
9387  const AValue: TSourceEditorWindowInterface);
9388var
9389  NewWindow: TSourceNotebook;
9390begin
9391  NewWindow:= AValue as TSourceNotebook;
9392  if NewWindow = FActiveWindow then exit;
9393
9394  //debugln(['TSourceEditorManagerBase.SetActiveSourceWindow ',dbgSourceNoteBook(FActiveWindow),' ',dbgSourceNoteBook(NewWindow)]);
9395  if (FActiveWindow <> nil) and (NewWindow <> nil) and (FActiveWindow.Focused) then
9396    NewWindow.SetFocus;
9397
9398  FActiveWindow := NewWindow;
9399  FSourceWindowByFocusList.Remove(NewWindow);
9400  FSourceWindowByFocusList.Insert(0, NewWindow);
9401
9402  if Assigned(OnCurrentCodeBufferChanged) then
9403    OnCurrentCodeBufferChanged(nil);
9404  FChangeNotifyLists[semWindowActivate].CallNotifyEvents(FActiveWindow);
9405  DoActiveEditorChanged;
9406end;
9407
9408function TSourceEditorManagerBase.GetSourceWindows(Index: integer
9409  ): TSourceEditorWindowInterface;
9410begin
9411  Result := TSourceEditorWindowInterface(FSourceWindowList[Index]);
9412end;
9413
9414procedure TSourceEditorManagerBase.DoWindowFocused(AWindow: TSourceNotebook);
9415begin
9416  FChangeNotifyLists[semWindowFocused].CallNotifyEvents(FActiveWindow);
9417end;
9418
9419function TSourceEditorManagerBase.GetActiveEditor: TSourceEditorInterface;
9420begin
9421  If FActiveWindow <> nil then
9422    Result := FActiveWindow.ActiveEditor
9423  else
9424    Result := nil;
9425end;
9426
9427procedure TSourceEditorManagerBase.SetActiveEditor(const AValue: TSourceEditorInterface);
9428var
9429  Window: TSourceEditorWindowInterface;
9430begin
9431  inc(FActiveEditorLock);
9432  try
9433    if (FActiveWindow <> nil) and (FActiveWindow.IndexOfEditor(AValue) >= 0) then
9434      Window := FActiveWindow
9435    else
9436      Window := SourceWindowWithEditor(AValue);
9437    if Window = nil then exit;
9438    ActiveSourceWindow := TSourceNotebook(Window);
9439    Window.ActiveEditor := AValue;
9440  finally
9441    dec(FActiveEditorLock);
9442    DoActiveEditorChanged;
9443  end;
9444end;
9445
9446procedure TSourceEditorManagerBase.DoActiveEditorChanged;
9447begin
9448  if FActiveEditorLock > 0 then exit;
9449  if FUpdateLock > 0 then begin
9450    include(FUpdateFlags, ufMgrActiveEditorChanged);
9451    exit;
9452  end;
9453  exclude(FUpdateFlags, ufMgrActiveEditorChanged);
9454  FChangeNotifyLists[semEditorActivate].CallNotifyEvents(ActiveEditor);
9455end;
9456
9457procedure TSourceEditorManagerBase.DoEditorStatusChanged(AEditor: TSourceEditor);
9458begin
9459  CodeToolsToSrcEditTimer.Enabled:=false;
9460  FChangeNotifyLists[semEditorStatus].CallNotifyEvents(AEditor);
9461end;
9462
9463function TSourceEditorManagerBase.GetSourceEditors(Index: integer): TSourceEditorInterface;
9464var
9465  i: Integer;
9466begin
9467  i := 0;
9468  while (i < SourceWindowCount) and (Index >= SourceWindows[i].Count) do begin
9469    Index := Index - SourceWindows[i].Count;
9470    inc(i);
9471  end;
9472  if (i < SourceWindowCount) then
9473    Result := SourceWindows[i].Items[Index]
9474  else
9475    Result := nil;
9476end;
9477
9478function TSourceEditorManagerBase.GetUniqueSourceEditors(Index: integer): TSourceEditorInterface;
9479var
9480  i: Integer;
9481begin
9482  for i := 0 to SourceEditorCount - 1 do begin
9483    Result := SourceEditors[i];
9484    if (TSourceEditor(Result).SharedEditorCount = 0) or
9485       (TSourceEditor(Result).SharedEditors[0] = Result)
9486    then
9487      dec(Index);
9488    if Index < 0 then exit;
9489  end;
9490  Result := nil;
9491end;
9492
9493function TSourceEditorManagerBase.SourceWindowWithEditor(
9494  const AEditor: TSourceEditorInterface): TSourceEditorWindowInterface;
9495var
9496  i: Integer;
9497begin
9498  Result := nil;
9499  for i := FSourceWindowList.Count-1 downto 0 do begin
9500    if TSourceNotebook(SourceWindows[i]).IndexOfEditor(AEditor) >= 0 then begin
9501      Result := SourceWindows[i];
9502      break;
9503    end;
9504  end;
9505end;
9506
9507function TSourceEditorManagerBase.SourceWindowCount: integer;
9508begin
9509  if assigned(FSourceWindowList) then
9510    Result := FSourceWindowList.Count
9511  else
9512    Result := 0;
9513end;
9514
9515function TSourceEditorManagerBase.IndexOfSourceWindow(
9516  AWindow: TSourceEditorWindowInterface): integer;
9517begin
9518  Result := SourceWindowCount - 1;
9519  while Result >= 0 do Begin
9520    if SourceWindows[Result] = AWindow then
9521      exit;
9522    dec(Result);
9523  end;
9524end;
9525
9526function TSourceEditorManagerBase.IndexOfSourceWindowByLastFocused(AWindow: TSourceEditorWindowInterface): integer;
9527begin
9528  Result := FSourceWindowByFocusList.IndexOf(AWindow);
9529end;
9530
9531function TSourceEditorManagerBase.SourceEditorIntfWithFilename(
9532  const Filename: string): TSourceEditorInterface;
9533var
9534  i: Integer;
9535begin
9536  for i:=0 to SourceWindowCount-1 do
9537  begin
9538    Result:=SourceWindows[i].SourceEditorIntfWithFilename(Filename);
9539    if Result<>nil then exit;
9540  end;
9541  Result:=nil;
9542end;
9543
9544function TSourceEditorManagerBase.SourceEditorCount: integer;
9545var
9546  i: Integer;
9547begin
9548  Result := 0;
9549  for i := 0 to SourceWindowCount - 1 do
9550    Result := Result + SourceWindows[i].Count;
9551end;
9552
9553function TSourceEditorManagerBase.UniqueSourceEditorCount: integer;
9554var
9555  SrcEdit: TSourceEditor;
9556  i: Integer;
9557begin
9558  Result := 0;
9559  for i := 0 to SourceEditorCount - 1 do begin
9560    SrcEdit := TSourceEditor(SourceEditors[i]);
9561    if (SrcEdit.SharedEditorCount = 0) or (SrcEdit.SharedEditors[0] = SrcEdit) then
9562      inc(Result);
9563  end;
9564end;
9565
9566function TSourceEditorManagerBase.GetEditorControlSettings(EditControl: TControl): boolean;
9567begin
9568  Result:=true;
9569  if EditControl is TSynEdit then begin
9570    EditorOpts.GetSynEditSettings(TSynEdit(EditControl));
9571    Result:=true;
9572  end else begin
9573    Result:=false;
9574  end;
9575end;
9576
9577function TSourceEditorManagerBase.GetHighlighterSettings(Highlighter: TObject): boolean;
9578begin
9579  Result:=true;
9580  if Highlighter is TSynCustomHighlighter then begin
9581    EditorOpts.GetHighlighterSettings(TSynCustomHighlighter(Highlighter));
9582    Result:=true;
9583  end else begin
9584    Result:=false;
9585  end;
9586end;
9587
9588function TSourceEditorManagerBase.GetDefaultCompletionForm: TSourceEditCompletion;
9589var
9590  i: Integer;
9591begin
9592  Result := FDefaultCompletionForm;
9593  if Result <> nil then exit;
9594  FDefaultCompletionForm := TSourceEditCompletion.Create(Self);
9595  FDefaultCompletionForm.LongLineHintTime := EditorOpts.CompletionLongLineHintInMSec;
9596  FDefaultCompletionForm.LongLineHintType := EditorOpts.CompletionLongLineHintType;
9597  Result := FDefaultCompletionForm;
9598  for i:=0 to SourceEditorCount - 1 do
9599    FDefaultCompletionForm.AddEditor(TSourceEditor(SourceEditors[i]).EditorComponent);
9600end;
9601
9602function TSourceEditorManagerBase.GetDefaultSynCompletionForm: TCustomForm;
9603begin
9604  if Assigned(GetDefaultCompletionForm) then
9605    Result := GetDefaultCompletionForm.TheForm
9606  else
9607    Result := nil;
9608end;
9609
9610function TSourceEditorManagerBase.GetSynCompletionLinesInWindow: integer;
9611var
9612  ComplForm: TCustomForm;
9613begin
9614  ComplForm := GetDefaultSynCompletionForm;
9615  if Assigned(ComplForm) then
9616    Result := TSynBaseCompletionForm(ComplForm).NbLinesInWindow
9617  else
9618    Result := -1;
9619end;
9620
9621procedure TSourceEditorManagerBase.SetSynCompletionLinesInWindow(LineCnt: integer);
9622var
9623  ComplForm: TCustomForm;
9624begin
9625  ComplForm := GetDefaultSynCompletionForm;
9626  if Assigned(ComplForm) then
9627    TSynBaseCompletionForm(ComplForm).NbLinesInWindow := LineCnt;
9628end;
9629
9630procedure TSourceEditorManagerBase.FreeCompletionPlugins;
9631var
9632  p: TSourceEditorCompletionPlugin;
9633begin
9634  while FCompletionPlugins.Count > 0 do begin
9635    p := TSourceEditorCompletionPlugin(FCompletionPlugins[0]);
9636    FCompletionPlugins.Delete(0);
9637    p.Free;
9638  end;
9639  FCompletionPlugins.Clear;
9640end;
9641
9642function TSourceEditorManagerBase.GetScreenRectForToken(AnEditor: TCustomSynEdit;
9643  PhysColumn, PhysRow, EndColumn: Integer): TRect;
9644begin
9645  Result.TopLeft := AnEditor.ClientToScreen(AnEditor.RowColumnToPixels(Point(PhysColumn, PhysRow)));
9646  Result.BottomRight := AnEditor.ClientToScreen(AnEditor.RowColumnToPixels(Point(EndColumn+1, PhysRow+1)));
9647end;
9648
9649function TSourceEditorManagerBase.GetShowTabs: Boolean;
9650begin
9651  Result := FShowTabs;
9652end;
9653
9654function TSourceEditorManagerBase.GetMarklingProducers(Index: integer
9655  ): TSourceMarklingProducer;
9656begin
9657  Result:=TSourceMarklingProducer(fProducers[Index]);
9658end;
9659
9660procedure TSourceEditorManagerBase.DoWindowShow(AWindow: TSourceNotebook);
9661begin
9662  FChangeNotifyLists[semWindowShow].CallNotifyEvents(AWindow);
9663end;
9664
9665procedure TSourceEditorManagerBase.DoWindowHide(AWindow: TSourceNotebook);
9666begin
9667  FChangeNotifyLists[semWindowHide].CallNotifyEvents(AWindow);
9668end;
9669
9670procedure TSourceEditorManagerBase.SyncMessageWnd(Sender: TObject);
9671begin
9672  MessagesView.MessagesFrame1.ApplyMultiSrcChanges(Sender as TETMultiSrcChanges);
9673end;
9674
9675procedure TSourceEditorManagerBase.BeginAutoFocusLock;
9676begin
9677  inc(FAutoFocusLock);
9678end;
9679
9680procedure TSourceEditorManagerBase.EndAutoFocusLock;
9681begin
9682  dec(FAutoFocusLock);
9683end;
9684
9685function TSourceEditorManagerBase.HasAutoFocusLock: Boolean;
9686begin
9687  Result := FAutoFocusLock > 0;
9688end;
9689
9690function TSourceEditorManagerBase.GetActiveCompletionPlugin: TSourceEditorCompletionPlugin;
9691begin
9692  Result := FActiveCompletionPlugin;
9693end;
9694
9695function TSourceEditorManagerBase.GetCompletionBoxPosition: integer;
9696begin
9697  Result:=-1;
9698  if (FDefaultCompletionForm<>nil) and FDefaultCompletionForm.IsActive then
9699    Result := FDefaultCompletionForm.Position;
9700end;
9701
9702function TSourceEditorManagerBase.GetCompletionPlugins(Index: integer
9703  ): TSourceEditorCompletionPlugin;
9704begin
9705  Result:=TSourceEditorCompletionPlugin(fCompletionPlugins[Index]);
9706end;
9707
9708function TSourceEditorManagerBase.FindIdentCompletionPlugin(
9709  SrcEdit: TSourceEditor; JumpToError: boolean; var s: string; var BoxX,
9710  BoxY: integer; var UseWordCompletion: boolean): boolean;
9711var
9712  i: Integer;
9713  Plugin: TSourceEditorCompletionPlugin;
9714  Handled: Boolean;
9715  Cancel: Boolean;
9716begin
9717  for i:=0 to CompletionPluginCount-1 do begin
9718    Plugin := CompletionPlugins[i];
9719    Handled:=false;
9720    Cancel:=false;
9721    Plugin.Init(SrcEdit,JumpToError,Handled,Cancel,s,BoxX,BoxY);
9722    if Cancel then begin
9723      DeactivateCompletionForm;
9724      exit(false);
9725    end;
9726    if Handled then begin
9727      FActiveCompletionPlugin:=Plugin;
9728      exit(true);
9729    end;
9730  end;
9731
9732  if not (SrcEdit.SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
9733    UseWordCompletion:=true;
9734  Result:=true;
9735end;
9736
9737function TSourceEditorManagerBase.CompletionPluginCount: integer;
9738begin
9739  Result:=fCompletionPlugins.Count;
9740end;
9741
9742procedure TSourceEditorManagerBase.DeactivateCompletionForm;
9743var
9744  PluginFocused: Boolean;
9745begin
9746  {$IFDEF VerboseIDECompletionBox}
9747  DebugLnEnter(['>> TSourceEditorManagerBase.DeactivateCompletionForm']);
9748  try
9749  {$ENDIF}
9750  if ActiveCompletionPlugin<>nil then begin
9751    ActiveCompletionPlugin.Cancel;
9752    FActiveCompletionPlugin:=nil;
9753  end;
9754
9755  if (FDefaultCompletionForm=nil) or
9756     (FDefaultCompletionForm.CurrentCompletionType = ctNone)
9757  then
9758    exit;
9759
9760  // Do not move focus, if it was moved by user
9761  PluginFocused := FDefaultCompletionForm.TheForm.Focused;
9762  {$IFDEF VerboseIDECompletionBox}
9763  DebugLn(['DeactivateCompletionForm  PluginFocused=', dbgs(PluginFocused), '  ActiveEditor=', DbgSName(ActiveEditor)]);
9764  {$ENDIF}
9765
9766  // clear the IdentifierList (otherwise it would try to update everytime
9767  // the codetools are used)
9768  CodeToolBoss.IdentifierList.Clear;
9769  FDefaultCompletionForm.CurrentCompletionType:=ctNone;
9770
9771  // SetFocus and Deactivate will all trigger this proc to be reentered.
9772  //   Setting "CurrentCompletionType:=ctNone" ensures an immediate exit
9773
9774  // Due to a bug under XFCE we must move focus before we close the form
9775  // This is relevant if the form is closed by enter/escape key
9776  if PluginFocused and (ActiveEditor<>nil) then
9777    TSourceEditor(ActiveEditor).FocusEditor;
9778
9779  // hide/close the form
9780  FDefaultCompletionForm.Deactivate;
9781
9782  // Ensure focus *after* the form was closed.
9783  // This is the normal implementation (all but XFCE)
9784  if PluginFocused and (ActiveEditor<>nil) then
9785    TSourceEditor(ActiveEditor).FocusEditor;
9786  {$IFDEF VerboseIDECompletionBox}
9787  finally
9788    DebugLnExit(['<< TSourceEditorManagerBase.DeactivateCompletionForm']);
9789  end;
9790  {$ENDIF}
9791end;
9792
9793procedure TSourceEditorManagerBase.RegisterCompletionPlugin(
9794  Plugin: TSourceEditorCompletionPlugin);
9795begin
9796  fCompletionPlugins.Add(Plugin);
9797  Plugin.FreeNotification(Self);
9798end;
9799
9800procedure TSourceEditorManagerBase.UnregisterCompletionPlugin(
9801  Plugin: TSourceEditorCompletionPlugin);
9802begin
9803  Plugin.RemoveFreeNotification(Self);
9804  fCompletionPlugins.Remove(Plugin);
9805end;
9806
9807procedure TSourceEditorManagerBase.Notification(AComponent: TComponent;
9808  Operation: TOperation);
9809begin
9810  inherited Notification(AComponent, Operation);
9811  if Operation=opRemove then
9812  begin
9813    if Assigned(fCompletionPlugins) then
9814      fCompletionPlugins.Remove(AComponent);
9815    if ActiveCompletionPlugin = AComponent then
9816      DeactivateCompletionForm;
9817    if AComponent is TSourceMarklingProducer then
9818      fProducers.Remove(AComponent);
9819  end;
9820end;
9821
9822constructor TSourceEditorManagerBase.Create(AOwner: TComponent);
9823var
9824  i: TsemChangeReason;
9825  h: TSrcEditMangerHandlerType;
9826begin
9827  FMacroRecorder := TIdeEditorMacro.Create(Self);
9828  FMacroRecorder.OnStateChange := @DoMacroRecorderState;
9829  OnEditorMacroStateChange := @DoMacroRecorderState;
9830  if EditorMacroForRecording = nil then
9831    EditorMacroForRecording := FMacroRecorder;
9832
9833  FShowTabs := True;
9834  FUpdateFlags := [];
9835  FAutoFocusLock := 0;
9836  for i := low(TsemChangeReason) to high(TsemChangeReason) do
9837    FChangeNotifyLists[i] := TMethodList.Create;
9838  for h:=low(FHandlers) to high(FHandlers) do
9839    FHandlers[h] := TMethodList.Create;
9840  SrcEditorIntf.SourceEditorManagerIntf := Self;
9841  FSourceWindowList := TFPList.Create;
9842  FSourceWindowByFocusList := TFPList.Create;
9843  FCompletionPlugins := TFPList.Create;
9844  FUpdateLock := 0;
9845  FActiveEditorLock := 0;
9846  fProducers := TFPList.Create;
9847  FChangesQueuedForMsgWnd:=TETMultiSrcChanges.Create(Self);
9848  FChangesQueuedForMsgWnd.AutoSync:=true;
9849  FChangesQueuedForMsgWnd.OnSync:=@SyncMessageWnd;
9850  inherited;
9851end;
9852
9853destructor TSourceEditorManagerBase.Destroy;
9854var
9855  i: integer;
9856  cr: TsemChangeReason;
9857  h: TSrcEditMangerHandlerType;
9858begin
9859  FreeAndNil(FChangesQueuedForMsgWnd);
9860  for i:=MarklingProducerCount-1 downto 0 do
9861    MarklingProducers[i].Free;
9862  FreeAndNil(fProducers);
9863  FActiveWindow := nil;
9864  FreeCompletionPlugins;
9865  FreeSourceWindows;
9866  SrcEditorIntf.SourceEditorManagerIntf := nil; // xx move down
9867  if EditorMacroForRecording = FMacroRecorder then
9868    EditorMacroForRecording := nil;
9869  FreeAndNil(FMacroRecorder);
9870  FreeAndNil(FCompletionPlugins);
9871  FreeAndNil(FSourceWindowList);
9872  FreeAndNil(FSourceWindowByFocusList);
9873  inherited Destroy;
9874  for cr := low(TsemChangeReason) to high(TsemChangeReason) do
9875    FreeAndNil(FChangeNotifyLists[cr]);
9876  for h:=low(FHandlers) to high(FHandlers) do
9877    FreeAndNil(FHandlers[h]);
9878end;
9879
9880procedure TSourceEditorManagerBase.RegisterChangeEvent(
9881  AReason: TsemChangeReason; AHandler: TNotifyEvent);
9882begin
9883  FChangeNotifyLists[AReason].Add(TMethod(AHandler));
9884end;
9885
9886procedure TSourceEditorManagerBase.UnRegisterChangeEvent(
9887  AReason: TsemChangeReason; AHandler: TNotifyEvent);
9888begin
9889  FChangeNotifyLists[AReason].Remove(TMethod(AHandler));
9890end;
9891
9892procedure TSourceEditorManagerBase.RegisterCopyPasteEvent(
9893  AHandler: TSemCopyPasteEvent);
9894begin
9895  FHandlers[semhtCopyPaste].Add(TMethod(AHandler));
9896end;
9897
9898procedure TSourceEditorManagerBase.UnRegisterCopyPasteEvent(
9899  AHandler: TSemCopyPasteEvent);
9900begin
9901  FHandlers[semhtCopyPaste].Remove(TMethod(AHandler));
9902end;
9903
9904function TSourceEditorManagerBase.MarklingProducerCount: integer;
9905begin
9906  Result:=fProducers.Count;
9907end;
9908
9909procedure TSourceEditorManagerBase.RegisterMarklingProducer(
9910  aProducer: TSourceMarklingProducer);
9911begin
9912  if fProducers.IndexOf(aProducer)>=0 then
9913    RaiseGDBException('TSourceEditorManagerBase.RegisterProducer already registered');
9914  fProducers.Add(aProducer);
9915  FreeNotification(aProducer);
9916end;
9917
9918procedure TSourceEditorManagerBase.UnregisterMarklingProducer(
9919  aProducer: TSourceMarklingProducer);
9920var
9921  i: LongInt;
9922begin
9923  i:=fProducers.IndexOf(aProducer);
9924  if i<0 then exit;
9925  fProducers.Delete(i);
9926  RemoveFreeNotification(aProducer);
9927end;
9928
9929procedure TSourceEditorManagerBase.InvalidateMarklingsOfAllFiles(
9930  aProducer: TSourceMarklingProducer);
9931var
9932  SrcWnd: TSourceEditorWindowInterface;
9933  i, j: Integer;
9934  SrcEdit: TSourceEditor;
9935begin
9936  if aProducer=nil then exit;
9937  for i := 0 to SourceWindowCount - 1 do
9938  begin
9939    SrcWnd:=SourceWindows[i];
9940    for j:=0 to SrcWnd.Count-1 do
9941    begin
9942      SrcEdit:=TSourceEditor(SrcWnd[j]);
9943      SrcEdit.FSharedValues.FMarklingsValid:=false;
9944    end;
9945  end;
9946end;
9947
9948procedure TSourceEditorManagerBase.InvalidateMarklings(
9949  aProducer: TSourceMarklingProducer; aFilename: string);
9950var
9951  SrcWnd: TSourceEditorWindowInterface;
9952  i: Integer;
9953  SrcEdit: TSourceEditor;
9954begin
9955  if aProducer=nil then exit;
9956  for i := 0 to SourceWindowCount - 1 do
9957  begin
9958    SrcWnd:=SourceWindows[i];
9959    SrcEdit:=TSourceEditor(SrcWnd.SourceEditorIntfWithFilename(aFilename));
9960    if SrcEdit<>nil then
9961      SrcEdit.FSharedValues.FMarklingsValid:=false;
9962  end;
9963end;
9964
9965procedure TSourceEditorManagerBase.IncUpdateLockInternal;
9966begin
9967  if FUpdateLock = 0 then begin
9968    FUpdateFlags := [];
9969    // Debugger cause ProcessMessages, which could lead to entering methods in unexpected order
9970    DebugBoss.LockCommandProcessing;
9971    Screen.BeginWaitCursor;
9972  end;
9973  inc(FUpdateLock);
9974end;
9975
9976procedure TSourceEditorManagerBase.DecUpdateLockInternal;
9977begin
9978  dec(FUpdateLock);
9979  if FUpdateLock = 0 then begin
9980    try
9981      Screen.EndWaitCursor;
9982      if (ufShowWindowOnTop in FUpdateFlags) then
9983        ShowActiveWindowOnTop(ufShowWindowOnTopFocus in FUpdateFlags);
9984      if (ufMgrActiveEditorChanged in FUpdateFlags) then
9985        DoActiveEditorChanged;
9986    finally
9987      DebugBoss.UnLockCommandProcessing;
9988    end;
9989  end;
9990end;
9991
9992procedure TSourceEditorManagerBase.IncUpdateLock;
9993var
9994  i: Integer;
9995begin
9996  IncUpdateLockInternal;
9997  for i := 0 to SourceWindowCount - 1 do
9998    TSourceNotebook(SourceWindows[i]).IncUpdateLockInternal;
9999end;
10000
10001procedure TSourceEditorManagerBase.DecUpdateLock;
10002var
10003  i: Integer;
10004begin
10005  try
10006    for i := 0 to SourceWindowCount - 1 do
10007      TSourceNotebook(SourceWindows[i]).DecUpdateLockInternal;
10008  finally
10009    DecUpdateLockInternal;
10010  end;
10011end;
10012
10013procedure TSourceEditorManagerBase.ShowActiveWindowOnTop(Focus: Boolean);
10014begin
10015  if ActiveSourceWindow = nil then exit;
10016  if FUpdateLock > 0 then begin
10017    include(FUpdateFlags, ufShowWindowOnTop);
10018    if Focus then
10019      include(FUpdateFlags, ufShowWindowOnTopFocus);
10020    exit;
10021  end;
10022  IDEWindowCreators.ShowForm(ActiveSourceWindow,true);
10023  if Focus and ActiveSourceWindow.IsVisible then
10024    TSourceNotebook(ActiveSourceWindow).FocusEditor;
10025end;
10026
10027{ TSourceEditorManager }
10028
10029function TSourceEditorManager.GetActiveSourceNotebook: TSourceNotebook;
10030begin
10031  Result := TSourceNotebook(inherited ActiveSourceWindow);
10032end;
10033
10034function TSourceEditorManager.GetActiveSrcEditor: TSourceEditor;
10035begin
10036  Result := TSourceEditor(inherited ActiveEditor);
10037end;
10038
10039function TSourceEditorManager.GetSourceEditorsByPage(WindowIndex,
10040  PageIndex: integer): TSourceEditor;
10041begin
10042  if SourceWindows[WindowIndex] <> nil then
10043    Result := SourceWindows[WindowIndex].FindSourceEditorWithPageIndex(PageIndex)
10044  else
10045    Result := nil;
10046end;
10047
10048function TSourceEditorManager.GetSourceNbByLastFocused(Index: Integer): TSourceNotebook;
10049begin
10050  Result := TSourceNotebook(inherited SourceWindowByLastFocused[Index]);
10051end;
10052
10053function TSourceEditorManager.GetSrcEditors(Index: integer): TSourceEditor;
10054begin
10055  Result := TSourceEditor(inherited SourceEditors[Index]);
10056end;
10057
10058procedure TSourceEditorManager.SetActiveSourceNotebook(const AValue: TSourceNotebook);
10059begin
10060  inherited ActiveSourceWindow := AValue;
10061end;
10062
10063function TSourceEditorManager.GetSourceNotebook(Index: integer): TSourceNotebook;
10064begin
10065  Result := TSourceNotebook(inherited SourceWindows[Index]);
10066end;
10067
10068procedure TSourceEditorManager.SetActiveSrcEditor(const AValue: TSourceEditor);
10069begin
10070  inherited ActiveEditor := AValue;
10071end;
10072
10073function TSourceEditorManager.SourceWindowWithEditor(
10074  const AEditor: TSourceEditorInterface): TSourceNotebook;
10075begin
10076  Result := TSourceNotebook(inherited SourceWindowWithEditor(AEditor));
10077end;
10078
10079function TSourceEditorManager.ActiveOrNewSourceWindow: TSourceNotebook;
10080var
10081  i: Integer;
10082begin
10083  Result := ActiveSourceWindow;
10084  if Result <> nil then exit;
10085  if SourceWindowCount>0 then begin
10086    for i:=0 to SourceWindowCount-1 do
10087    begin
10088      Result:=SourceWindows[i];
10089      if Result.FIsClosing then continue;
10090      ActiveSourceWindow := Result;
10091      exit;
10092    end;
10093  end;
10094
10095  Result := CreateNewWindow(True);
10096  ActiveSourceWindow := Result;
10097end;
10098
10099procedure TSourceEditorManager.AddCustomJumpPoint(ACaretXY: TPoint;
10100  ATopLine: integer; AEditor: TSourceEditor; DeleteForwardHistory: boolean);
10101begin
10102  if Assigned(OnAddJumpPoint) then
10103    OnAddJumpPoint(ACaretXY, ATopLine, AEditor, DeleteForwardHistory);
10104end;
10105
10106function TSourceEditorManager.NewSourceWindow: TSourceNotebook;
10107begin
10108  Result := CreateNewWindow(True);
10109  ActiveSourceWindow := Result;
10110end;
10111
10112procedure TSourceEditorManager.CreateSourceWindow(Sender: TObject;
10113  aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
10114var
10115  i: integer;
10116begin
10117  {$IFDEF VerboseIDEDocking}
10118  debugln(['TSourceEditorManager.CreateSourceWindow Sender=',DbgSName(Sender),' FormName="',aFormName,'"']);
10119  {$ENDIF}
10120  // Get ID from Name
10121  i := length(aFormName);
10122  while (i >= 1) and (aFormName[i] in ['0'..'9']) do
10123    dec(i);
10124  inc(i);
10125  i := StrToIntDef(copy(aFormName, i, MaxInt), 1)-1;
10126  AForm := CreateNewWindow(false,DoDisableAutoSizing, i);
10127  AForm.Name:=aFormName;
10128end;
10129
10130procedure TSourceEditorManager.GetDefaultLayout(Sender: TObject; aFormName: string;
10131  out aBounds: TRect; out DockSibling: string; out DockAlign: TAlign);
10132var
10133  i: LongInt;
10134  ScreenR: TRect;
10135begin
10136  DockSibling:='';
10137  DockAlign:=alNone;
10138  i:=StrToIntDef(
10139    copy(aFormName,length(NonModalIDEWindowNames[nmiwSourceNoteBook])+1,length(aFormName)),
10140    0);
10141  {$IFDEF VerboseIDEDocking}
10142  debugln(['TSourceEditorManager.GetDefaultLayout ',aFormName,' i=',i]);
10143  {$ENDIF}
10144  ScreenR:=IDEWindowCreators.GetScreenrectForDefaults;
10145  if ObjectInspector1<>nil then
10146  begin
10147    aBounds.Left := ObjectInspector1.Left + ObjectInspector1.Width + ObjectInspector1.Scale96ToForm(5);
10148    aBounds.Top := ObjectInspector1.Top;
10149  end
10150  else
10151  begin
10152    aBounds.Left := ScreenR.Left+MulDiv(200, Screen.PixelsPerInch, 96);
10153    aBounds.Top := ScreenR.Top+MulDiv(120, Screen.PixelsPerInch, 96);
10154  end;
10155  Inc(aBounds.Left,MulDiv(30, Screen.PixelsPerInch, 96)*i);
10156  Inc(aBounds.Top, MulDiv(30, Screen.PixelsPerInch, 96)*i);
10157  aBounds.Right:=ScreenR.Right-MulDiv(30, Screen.PixelsPerInch, 96);
10158  aBounds.Bottom:=ScreenR.Bottom-MulDiv(200, Screen.PixelsPerInch, 96);
10159  if (i=0) and (IDEDockMaster<>nil) then begin
10160    DockSibling:=NonModalIDEWindowNames[nmiwMainIDE];
10161    DockAlign:=alBottom;
10162  end;
10163end;
10164
10165function TSourceEditorManager.SourceWindowWithPage(const APage: TTabSheet): TSourceNotebook;
10166var
10167  i: Integer;
10168begin
10169  Result := nil;
10170  for i := FSourceWindowList.Count-1 downto 0 do begin
10171    if TSourceNotebook(SourceWindows[i]).FNoteBook.IndexOf(APage) >= 0 then begin
10172      Result := SourceWindows[i];
10173      break;
10174    end;
10175  end;
10176end;
10177
10178procedure TSourceEditorManager.SrcEditMenuProcedureJumpGetCaption(
10179  Sender: TObject; var ACaption, AHint: string);
10180var
10181  ShortFileName, CurFilename: String;
10182  MainCodeBuf: TCodeBuffer;
10183  CodeTool: TCodeTool;
10184  CaretXY: TCodeXYPosition;
10185  CleanPos: integer;
10186  CodeNode: TCodeTreeNode;
10187  ProcNode: TCodeTreeNode;
10188  ProcName: String;
10189  SrcEdit: TSourceEditor;
10190begin
10191  // ask Codetools
10192  SrcEdit:=GetActiveSE;
10193  if not Assigned(SrcEdit) then Exit;
10194  CurFilename:=SrcEdit.FileName;
10195  ShortFileName:=ExtractFileName(CurFilename);
10196  MainCodeBuf:=nil;
10197  if FilenameHasPascalExt(ShortFileName) or FilenameExtIs(ShortFileName,'inc') then
10198    MainCodeBuf:=CodeToolBoss.GetMainCode(SrcEdit.CodeBuffer)
10199  else if FilenameIsPascalSource(ShortFileName) then
10200    MainCodeBuf:=SrcEdit.CodeBuffer;
10201  CodeTool:=nil;
10202  CaretXY:=CleanCodeXYPosition;
10203  CaretXY.Code:=SrcEdit.CodeBuffer;
10204  CaretXY.X:=SrcEdit.CursorTextXY.X;
10205  CaretXY.Y:=SrcEdit.CursorTextXY.Y;
10206  CodeNode:=nil;
10207  if MainCodeBuf<>nil then begin
10208    CodeToolBoss.Explore(MainCodeBuf,CodeTool,true);
10209    if CodeTool<>nil then begin
10210      CodeTool.CaretToCleanPos(CaretXY,CleanPos);
10211      CodeNode:=CodeTool.FindDeepestNodeAtPos(CleanPos,false);
10212    end;
10213  end;
10214
10215  ProcName:='';
10216  if CodeNode<>nil then begin
10217    ProcNode:=CodeNode.GetNodeOfType(ctnProcedure);
10218    if ProcNode<>nil then
10219      ProcName:=CodeTool.ExtractProcName(ProcNode,[]);
10220  end;
10221  if ProcName<>'' then
10222    ACaption:=Format(lisJumpToProcedure, [ProcName])
10223  else
10224    ACaption:=uemProcedureJump;
10225end;
10226
10227function TSourceEditorManager.IndexOfSourceWindowWithID(const AnID: Integer): Integer;
10228begin
10229  Result := SourceWindowCount - 1;
10230  while Result >= 0 do begin
10231    if SourceWindows[Result].WindowID = AnID then break;
10232    dec(Result);
10233  end;
10234end;
10235
10236function TSourceEditorManager.SourceWindowWithID(const AnID: Integer): TSourceNotebook;
10237var
10238  i: Integer;
10239begin
10240  i := IndexOfSourceWindowWithID(AnID);
10241  if i >= 0 then
10242    Result := SourceWindows[i]
10243  else
10244    Result := CreateNewWindow(False, False, AnID);
10245end;
10246
10247function TSourceEditorManager.SourceEditorCount: integer;
10248var
10249  i: Integer;
10250begin
10251  Result := 0;
10252  for i := 0 to SourceWindowCount - 1 do
10253    Result := Result + SourceWindows[i].Count;
10254end;
10255
10256function TSourceEditorManager.GetActiveSE: TSourceEditor;
10257begin
10258  Result := TSourceEditor(ActiveEditor);
10259end;
10260
10261procedure TSourceEditorManager.SetWindowByIDAndPage(AWindowID, APageIndex: integer);
10262begin
10263  ActiveSourceWindowIndex := IndexOfSourceWindowWithID(AWindowID);
10264  ActiveSourceWindow.PageIndex:= APageIndex;
10265end;
10266
10267function TSourceEditorManager.SourceEditorIntfWithFilename(
10268  const Filename: string): TSourceEditor;
10269begin
10270  Result := TSourceEditor(inherited SourceEditorIntfWithFilename(Filename));
10271end;
10272
10273function TSourceEditorManager.FindSourceEditorWithEditorComponent(
10274  EditorComp: TComponent): TSourceEditor;
10275var
10276  i: Integer;
10277begin
10278  Result := nil;
10279  i := SourceWindowCount - 1;
10280  while i >= 0 do begin
10281    Result := SourceWindows[i].FindSourceEditorWithEditorComponent(EditorComp);
10282    if Result <> nil then break;
10283    dec(i);
10284  end;
10285end;
10286
10287procedure TSourceEditorManager.NewEditorCreated(AEditor: TSourceEditor);
10288begin
10289  if FDefaultCompletionForm <> nil then
10290    FDefaultCompletionForm.AddEditor(AEditor.EditorComponent);
10291end;
10292
10293procedure TSourceEditorManager.EditorRemoved(AEditor: TSourceEditor);
10294begin
10295  if FDefaultCompletionForm <> nil then begin
10296    if FDefaultCompletionForm.Editor = AEditor.EditorComponent then
10297      DeactivateCompletionForm;
10298    FDefaultCompletionForm.RemoveEditor(AEditor.EditorComponent);
10299  end;
10300end;
10301
10302procedure TSourceEditorManager.SendEditorCreated(AEditor: TSourceEditor);
10303begin
10304  FChangeNotifyLists[semEditorCreate].CallNotifyEvents(AEditor);
10305end;
10306
10307procedure TSourceEditorManager.SendEditorDestroyed(AEditor: TSourceEditor);
10308begin
10309  FChangeNotifyLists[semEditorDestroy].CallNotifyEvents(AEditor);
10310end;
10311
10312procedure TSourceEditorManager.Notification(AComponent: TComponent;
10313  Operation: TOperation);
10314begin
10315  inherited Notification(AComponent, Operation);
10316  if Operation=opRemove then
10317  begin
10318    if AComponent is TSourceNotebook then
10319      RemoveWindow(TSourceNotebook(AComponent));
10320  end;
10321end;
10322
10323procedure TSourceEditorManager.ClearErrorLines;
10324var
10325  i, j: Integer;
10326  SrcWin: TSourceNotebook;
10327begin
10328  for i := FSourceWindowList.Count - 1 downto 0 do
10329  begin
10330    SrcWin := SourceWindows[i];
10331    for j := 0 to SrcWin.EditorCount - 1 do
10332      SrcWin.Editors[j].ErrorLine := -1;
10333  end;
10334end;
10335
10336procedure TSourceEditorManager.ClearExecutionLines;
10337var
10338  i: Integer;
10339begin
10340  for i := FSourceWindowList.Count - 1 downto 0 do
10341    SourceWindows[i].ClearExecutionLines;
10342end;
10343
10344procedure TSourceEditorManager.ClearExecutionMarks;
10345var
10346  i: Integer;
10347begin
10348  for i := FSourceWindowList.Count - 1 downto 0 do
10349    SourceWindows[i].ClearExecutionMarks;
10350end;
10351
10352procedure TSourceEditorManager.FillExecutionMarks;
10353var
10354  i: Integer;
10355  SE: TSourceEditor;
10356begin
10357  for i := FSourceWindowList.Count - 1 downto 0 do begin
10358    SE := SourceWindows[i].GetActiveSE;
10359    if SE <> nil then
10360      SE.FillExecutionMarks;
10361  end;
10362end;
10363
10364procedure TSourceEditorManager.ReloadEditorOptions;
10365var
10366  i: Integer;
10367begin
10368  for i := FSourceWindowList.Count - 1 downto 0 do
10369    SourceWindows[i].ReloadEditorOptions;
10370
10371  AutoStartCompletionBoxTimer.Interval:=EditorOpts.AutoDelayInMSec;
10372  // reload code templates
10373  EditorOpts.LoadCodeTemplates(CodeTemplateModul);
10374  CodeTemplateModul.IndentToTokenStart:=EditorOpts.CodeTemplateIndentToTokenStart;
10375
10376  FHints.AutoHintTimer.Interval:=EditorOpts.AutoHintDelayInMSec;
10377
10378  if FDefaultCompletionForm <> nil then begin
10379    FDefaultCompletionForm.LongLineHintTime := EditorOpts.CompletionLongLineHintInMSec;
10380    FDefaultCompletionForm.LongLineHintType := EditorOpts.CompletionLongLineHintType;
10381  end;
10382end;
10383
10384function TSourceEditorManager.Beautify(const Src: string;
10385  const Flags: TSemBeautyFlags): string;
10386var
10387  NewIndent, NewTabWidth: Integer;
10388  Beauty: TBeautifyCodeOptions;
10389  OldDoNotSplitLineInFront, OldDoNotSplitLineAfter: TAtomTypes;
10390begin
10391  Beauty:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions;
10392  OldDoNotSplitLineInFront:=Beauty.DoNotSplitLineInFront;
10393  OldDoNotSplitLineAfter:=Beauty.DoNotSplitLineAfter;
10394  try
10395    if sembfNotBreakDots in Flags then
10396    begin
10397      Include(Beauty.DoNotSplitLineInFront,atPoint);
10398      Include(Beauty.DoNotSplitLineAfter,atPoint);
10399    end;
10400    Result:=CodeToolBoss.Beautifier.BeautifyStatement(Src,2,[bcfDoNotIndentFirstLine]);
10401
10402    if (eoTabsToSpaces in EditorOpts.SynEditOptions)
10403    or (EditorOpts.BlockTabIndent=0) then
10404      NewTabWidth:=0
10405    else
10406      NewTabWidth:=EditorOpts.TabWidth;
10407    NewIndent:=EditorOpts.BlockTabIndent*EditorOpts.TabWidth+EditorOpts.BlockIndent;
10408
10409    Result:=BasicCodeTools.ReIndent(Result,2,0,NewIndent,NewTabWidth);
10410  finally
10411    Beauty.DoNotSplitLineInFront:=OldDoNotSplitLineInFront;
10412    Beauty.DoNotSplitLineAfter:=OldDoNotSplitLineAfter;
10413  end;
10414end;
10415
10416procedure TSourceEditorManager.FindClicked(Sender: TObject);
10417begin
10418  if ActiveEditor <> nil then ActiveEditor.StartFindAndReplace(false);
10419end;
10420
10421procedure TSourceEditorManager.FindNextClicked(Sender: TObject);
10422begin
10423  if ActiveEditor <> nil then ActiveEditor.FindNextUTF8;
10424end;
10425
10426procedure TSourceEditorManager.FindPreviousClicked(Sender: TObject);
10427begin
10428  if ActiveEditor <> nil then ActiveEditor.FindPrevious;
10429end;
10430
10431procedure TSourceEditorManager.ReplaceClicked(Sender: TObject);
10432begin
10433  if ActiveEditor <> nil then ActiveEditor.StartFindAndReplace(true);
10434end;
10435
10436procedure TSourceEditorManager.IncrementalFindClicked(Sender: TObject);
10437begin
10438  if ActiveSourceWindow <> nil then ActiveSourceWindow.BeginIncrementalFind;
10439end;
10440
10441procedure TSourceEditorManager.GotoLineClicked(Sender: TObject);
10442begin
10443  if ActiveEditor <> nil then ActiveEditor.ShowGotoLineDialog;
10444end;
10445
10446procedure TSourceEditorManager.HideHint;
10447begin
10448  FHints.HideHint;
10449end;
10450
10451procedure TSourceEditorManager.JumpBackClicked(Sender: TObject);
10452begin
10453  if ActiveSourceWindow <> nil then HistoryJump(Sender,jhaBack);
10454end;
10455
10456procedure TSourceEditorManager.JumpForwardClicked(Sender: TObject);
10457begin
10458  if ActiveSourceWindow <> nil then HistoryJump(Sender,jhaForward);
10459end;
10460
10461procedure TSourceEditorManager.JumpToNextErrorClicked(Sender: TObject);
10462begin
10463  LazarusIDE.DoJumpToNextError(true);
10464end;
10465
10466procedure TSourceEditorManager.JumpToPrevErrorClicked(Sender: TObject);
10467begin
10468  LazarusIDE.DoJumpToNextError(false);
10469end;
10470
10471procedure TSourceEditorManager.JumpToImplementationClicked(Sender: TObject);
10472begin
10473  JumpToSection(jmpImplementation);
10474end;
10475
10476procedure TSourceEditorManager.JumpToImplementationUsesClicked(Sender: TObject);
10477begin
10478  JumpToSection(jmpImplementationUses);
10479end;
10480
10481procedure TSourceEditorManager.JumpToInitializationClicked(Sender: TObject);
10482begin
10483  JumpToSection(jmpInitialization);
10484end;
10485
10486procedure TSourceEditorManager.JumpToInterfaceClicked(Sender: TObject);
10487begin
10488  JumpToSection(jmpInterface);
10489end;
10490
10491procedure TSourceEditorManager.JumpToInterfaceUsesClicked(Sender: TObject);
10492begin
10493  JumpToSection(jmpInterfaceUses);
10494end;
10495
10496procedure TSourceEditorManager.JumpToPos(FileName: string;
10497  Pos: TCodeXYPosition; TopLine, BlockTopLine, BlockBottomLine: Integer);
10498begin
10499  if (LazarusIDE.DoOpenFileAndJumpToPos(Filename
10500       ,Point(Pos.X,Pos.Y), TopLine, BlockTopLine, BlockBottomLine, -1,-1
10501       ,[ofRegularFile,ofUseCache]) = mrOk)
10502  then
10503    ActiveEditor.EditorControl.SetFocus;
10504end;
10505
10506procedure TSourceEditorManager.JumpToPos(FileName: string;
10507  Pos: TCodeXYPosition; TopLine: Integer);
10508begin
10509  JumpToPos(FileName, Pos, TopLine, TopLine, TopLine);
10510end;
10511
10512procedure TSourceEditorManager.JumpToProcedure(const JumpType: TJumpToProcedureType);
10513const
10514  cJumpNames: array[TJumpToProcedureType] of string = (
10515    'procedure header', 'procedure begin');
10516var
10517  SrcEditor: TSourceEditorInterface;
10518  ProcNode: TCodeTreeNode;
10519  Tool: TCodeTool;
10520  CleanPos: integer;
10521  NewPos: TCodeXYPosition;
10522  NewTopLine, BlockTopLine, BlockBottomLine: integer;
10523  JumpFound: Boolean;
10524begin
10525  if not LazarusIDE.BeginCodeTools then Exit; //==>
10526
10527  SrcEditor := SourceEditorManagerIntf.ActiveEditor;
10528  if not Assigned(SrcEditor) then Exit; //==>
10529
10530  if CodeToolBoss.Explore(SrcEditor.CodeToolsBuffer as TCodeBuffer, Tool, false, false) then
10531  begin
10532    if Tool.CaretToCleanPos(
10533        CodeXYPosition(SrcEditor.CursorTextXY.X, SrcEditor.CursorTextXY.Y, SrcEditor.CodeToolsBuffer as TCodeBuffer),
10534        CleanPos) <> 0
10535    then
10536      Exit;
10537    ProcNode := Tool.FindDeepestNodeAtPos(CleanPos{%H-},true);
10538    while (ProcNode <> nil) and (ProcNode.Desc <> ctnProcedure) do
10539      ProcNode := ProcNode.Parent;
10540
10541    if (ProcNode <> nil) and (ProcNode.Desc = ctnProcedure) then
10542    begin
10543      if JumpType = jmpBegin then
10544        JumpFound := Tool.FindJumpPointInProcNode(ProcNode, NewPos, NewTopLine, BlockTopLine, BlockBottomLine)
10545      else
10546        JumpFound := Tool.JumpToCleanPos(ProcNode.StartPos, ProcNode.StartPos, ProcNode.EndPos, NewPos, NewTopLine, BlockTopLine, BlockBottomLine, True);
10547    end else
10548      JumpFound := False;
10549
10550    if JumpFound then
10551      JumpToPos(NewPos.Code.Filename, NewPos, NewTopLine, BlockTopLine, BlockBottomLine)
10552    else
10553    begin
10554      CodeToolBoss.SetError(20170421203224, nil, 0, 0,
10555        Format(lisCannotFind, [cJumpNames[JumpType]]));
10556      LazarusIDE.DoJumpToCodeToolBossError;
10557    end;
10558  end
10559  else
10560    LazarusIDE.DoJumpToCodeToolBossError;
10561end;
10562
10563procedure TSourceEditorManager.JumpToProcedureBeginClicked(Sender: TObject);
10564begin
10565  JumpToProcedure(jmpBegin);
10566end;
10567
10568procedure TSourceEditorManager.JumpToProcedureHeaderClicked(Sender: TObject);
10569begin
10570  JumpToProcedure(jmpHeader);
10571end;
10572
10573procedure TSourceEditorManager.JumpToSection(JumpType: TJumpToSectionType);
10574const
10575  cJumpNames: array[TJumpToSectionType] of string = (
10576    'Interface', 'Interface uses', 'Implementation', 'Implementation uses', 'Initialization');
10577var
10578  SrcEditor: TSourceEditorInterface;
10579  Node: TCodeTreeNode;
10580  Tool: TCodeTool;
10581  NewTopLine: Integer;
10582  NewCodePos: TCodeXYPosition;
10583begin
10584  if not LazarusIDE.BeginCodeTools then Exit; //==>
10585
10586  SrcEditor := SourceEditorManagerIntf.ActiveEditor;
10587  if not Assigned(SrcEditor) then Exit; //==>
10588
10589  if CodeToolBoss.Explore(SrcEditor.CodeToolsBuffer as TCodeBuffer, Tool, false, false) then
10590  begin
10591    case JumpType of
10592      jmpInterface: Node := Tool.FindInterfaceNode;
10593      jmpInterfaceUses:
10594      begin
10595        Node := Tool.FindMainUsesNode;
10596        if Node = nil then//if the uses section is missing, jump to interface
10597          Node := Tool.FindInterfaceNode;
10598      end;
10599      jmpImplementation: Node := Tool.FindImplementationNode;
10600      jmpImplementationUses:
10601      begin
10602        Node := Tool.FindImplementationUsesNode;
10603        if Node = nil then//if the uses section is missing, jump to implementation
10604          Node := Tool.FindImplementationNode;
10605      end;
10606      jmpInitialization:
10607      begin
10608        Node := Tool.FindInitializationNode;
10609        if Node = nil then//if initialization is missing, jump to last end
10610          Node := Tool.FindRootNode(ctnEndPoint);
10611      end;
10612    end;
10613
10614    if (Node <> nil) and Tool.CleanPosToCaretAndTopLine(Node.StartPos, NewCodePos, NewTopLine) then
10615      JumpToPos(NewCodePos.Code.Filename, NewCodePos, NewTopLine)
10616    else
10617    begin
10618      CodeToolBoss.SetError(20170421203236, nil, 0, 0,
10619        Format(lisCannotFind, [cJumpNames[JumpType]]));
10620      LazarusIDE.DoJumpToCodeToolBossError;
10621    end;
10622  end
10623  else
10624    LazarusIDE.DoJumpToCodeToolBossError;
10625end;
10626
10627procedure TSourceEditorManager.AddJumpPointClicked(Sender: TObject);
10628begin
10629  if Assigned(OnAddJumpPoint) and (ActiveEditor <> nil) then
10630    with ActiveEditor.EditorComponent do
10631      OnAddJumpPoint(LogicalCaretXY, TopLine, ActiveEditor, true);
10632end;
10633
10634procedure TSourceEditorManager.DeleteLastJumpPointClicked(Sender: TObject);
10635begin
10636  if Assigned(OnDeleteLastJumpPoint) then
10637    OnDeleteLastJumpPoint(Sender);
10638end;
10639
10640procedure TSourceEditorManager.ViewJumpHistoryClicked(Sender: TObject);
10641begin
10642  if Assigned(OnViewJumpHistory) then
10643    OnViewJumpHistory(Sender);
10644end;
10645
10646procedure TSourceEditorManager.BookMarkToggleClicked(Sender: TObject);
10647begin
10648  if Assigned(OnSetBookmark) then
10649    OnSetBookmark(ActiveEditor, (Sender as TIDEMenuItem).SectionIndex, True);
10650end;
10651
10652procedure TSourceEditorManager.BookMarkGotoClicked(Sender: TObject);
10653begin
10654  if Assigned(OnGotoBookmark) then
10655    OnGotoBookmark(ActiveEditor, (Sender as TIDEMenuItem).SectionIndex, False);
10656end;
10657
10658procedure TSourceEditorManager.BookMarkNextClicked(Sender: TObject);
10659begin
10660  if Assigned(OnGotoBookmark) then
10661    OnGotoBookmark(ActiveEditor, -1, False);
10662end;
10663
10664procedure TSourceEditorManager.BookMarkPrevClicked(Sender: TObject);
10665begin
10666  if Assigned(OnGotoBookmark) then
10667    OnGotoBookmark(ActiveEditor, -1, True);
10668end;
10669
10670function TSourceEditorManager.MacroFuncCol(const s: string; const Data: PtrInt;
10671  var Abort: boolean): string;
10672begin
10673  if (ActiveEditor <> nil) then
10674    Result:=IntToStr(ActiveEditor.EditorComponent.CaretX)
10675  else
10676    Result:='';
10677end;
10678
10679function TSourceEditorManager.MacroFuncRow(const s: string; const Data: PtrInt;
10680  var Abort: boolean): string;
10681begin
10682  if (ActiveEditor <> nil) then
10683    Result:=IntToStr(ActiveEditor.EditorComponent.CaretY)
10684  else
10685    Result:='';
10686end;
10687
10688function TSourceEditorManager.MacroFuncEdFile(const s: string;
10689  const Data: PtrInt; var Abort: boolean): string;
10690begin
10691  if (ActiveEditor <> nil) then
10692    Result := ActiveEditor.FileName
10693  else
10694    Result := '';
10695end;
10696
10697function TSourceEditorManager.MacroFuncCurToken(const s: string;
10698  const Data: PtrInt; var Abort: boolean): string;
10699begin
10700  if (ActiveEditor <> nil) then begin
10701    with ActiveEditor.EditorComponent do
10702      Result := GetWordAtRowCol(LogicalCaretXY)
10703  end else
10704    Result := '';
10705end;
10706
10707function TSourceEditorManager.MacroFuncConfirm(const s: string; const Data: PtrInt;
10708  var Abort: boolean): string;
10709begin
10710  Result:=s;
10711  Abort:=(ShowMacroConfirmDialog(Result)<>mrOk);
10712end;
10713
10714function TSourceEditorManager.MacroFuncPrompt(const s: string;
10715  const Data: PtrInt; var Abort: boolean): string;
10716begin
10717  Result:=s;
10718  Abort:=(ShowMacroPromptDialog(Result)<>mrOk);
10719end;
10720
10721function TSourceEditorManager.MacroFuncSave(const s: string;
10722  const Data: PtrInt; var Abort: boolean): string;
10723begin
10724  Result:='';
10725  if SourceEditorCount > 0 then
10726    Abort:=LazarusIDE.DoSaveEditorFile(ActiveEditor,[sfCheckAmbiguousFiles]) <> mrOk;
10727end;
10728
10729function TSourceEditorManager.MacroFuncSaveAll(const s: string;
10730  const Data: PtrInt; var Abort: boolean): string;
10731begin
10732  Result:='';
10733  Abort:=LazarusIDE.DoSaveAll([sfCheckAmbiguousFiles])<>mrOk;
10734end;
10735
10736procedure TSourceEditorManager.InitMacros(AMacroList: TTransferMacroList);
10737begin
10738  AMacroList.Add(TTransferMacro.Create('Col','',
10739                 lisCursorColumnInCurrentEditor,@MacroFuncCol,[]));
10740  AMacroList.Add(TTransferMacro.Create('Row','',
10741                 lisCursorRowInCUrrentEditor,@MacroFuncRow,[]));
10742  AMacroList.Add(TTransferMacro.Create('CurToken','',
10743                 lisWordAtCursorInCurrentEditor,@MacroFuncCurToken,[]));
10744  AMacroList.Add(TTransferMacro.Create('EdFile','',
10745                 lisExpandedFilenameOfCurrentEditor,@MacroFuncEdFile,[]));
10746  AMacroList.Add(TTransferMacro.Create('Confirm','',
10747                 lisConfirmation,@MacroFuncConfirm,[tmfInteractive]));
10748  AMacroList.Add(TTransferMacro.Create('Prompt','',
10749                 lisPromptForValue,@MacroFuncPrompt,[tmfInteractive]));
10750  AMacroList.Add(TTransferMacro.Create('Save','',
10751                 lisSaveCurrentEditorFile,@MacroFuncSave,[tmfInteractive]));
10752  AMacroList.Add(TTransferMacro.Create('SaveAll','',
10753                 lisSaveAllModified,@MacroFuncSaveAll,[tmfInteractive]));
10754end;
10755
10756procedure TSourceEditorManager.SetupShortCuts;
10757
10758  function GetCommand(ACommand: word; ToolButtonClass: TIDEToolButtonClass): TIDECommand;
10759  var
10760    ToolButton: TIDEButtonCommand;
10761  begin
10762    Result:=GetIdeCmdAndToolBtn(ACommand, ToolButton);
10763    if ToolButton<>nil then
10764      ToolButton.ToolButtonClass := ToolButtonClass;
10765  end;
10766
10767  // See also in ToolBarIntf:
10768  //  function GetCommand_DropDown
10769  //  function GetCommand_ButtonDrop
10770
10771var
10772  i: Integer;
10773begin
10774  {%region *** first static section *** }
10775    SrcEditMenuFindDeclaration.Command := GetIdeCmdRegToolBtn(ecFindDeclaration);
10776    {%region *** Submenu: Find Section *** }
10777      SrcEditMenuProcedureJump.Command          := GetIdeCmdRegToolBtn(ecFindProcedureDefinition);
10778      SrcEditMenuProcedureJump.OnRequestCaptionHint := @SrcEditMenuProcedureJumpGetCaption;
10779      SrcEditMenuFindNextWordOccurrence.Command := GetIdeCmdRegToolBtn(ecFindNextWordOccurrence);
10780      SrcEditMenuFindPrevWordOccurrence.Command := GetIdeCmdRegToolBtn(ecFindPrevWordOccurrence);
10781      SrcEditMenuFindInFiles.Command            := GetIdeCmdRegToolBtn(ecFindInFiles);
10782      SrcEditMenuFindIdentifierReferences.Command:=GetIdeCmdRegToolBtn(ecFindIdentifierRefs);
10783      SrcEditMenuFindUsedUnitReferences.Command:=GetIdeCmdRegToolBtn(ecFindUsedUnitRefs);
10784    {%endregion}
10785  {%endregion}
10786
10787  {%region *** Pages section ***}
10788    SrcEditMenuClosePage.Command       := GetIdeCmdRegToolBtn(ecClose);
10789    SrcEditMenuCloseOtherPages.OnClick := @SourceEditorManager.CloseOtherPagesClicked;
10790    SrcEditMenuCloseOtherPagesToRight.OnClick := @SourceEditorManager.CloseRightPagesClicked;
10791
10792    {$IFnDEF SingleSrcWindow}
10793    SrcEditMenuEditorLock.Command           := GetIdeCmdRegToolBtn(ecLockEditor);
10794    SrcEditMenuMoveToNewWindow.SyncProperties := False;
10795    SrcEditMenuMoveToNewWindow.Command      := GetIdeCmdRegToolBtn(ecMoveEditorNewWindow);
10796    SrcEditMenuMoveToOtherWindowNew.SyncProperties := False;
10797    SrcEditMenuMoveToOtherWindowNew.Command := GetIdeCmdRegToolBtn(ecMoveEditorNewWindow);
10798    SrcEditMenuCopyToNewWindow.SyncProperties := False;
10799    SrcEditMenuCopyToNewWindow.Command      := GetIdeCmdRegToolBtn(ecCopyEditorNewWindow);
10800    SrcEditMenuCopyToOtherWindowNew.SyncProperties := False;
10801    SrcEditMenuCopyToOtherWindowNew.Command := GetIdeCmdRegToolBtn(ecCopyEditorNewWindow);
10802    {$ENDIF}
10803  {%endregion}
10804
10805  {%region * Move Page (left/right) *}
10806    SrcEditMenuMoveEditorLeft.Command  := GetIdeCmdRegToolBtn(ecMoveEditorLeft);
10807    SrcEditMenuMoveEditorRight.Command := GetIdeCmdRegToolBtn(ecMoveEditorRight);
10808    SrcEditMenuMoveEditorFirst.Command := GetIdeCmdRegToolBtn(ecMoveEditorLeftmost);
10809    SrcEditMenuMoveEditorLast.Command  := GetIdeCmdRegToolBtn(ecMoveEditorRightmost);
10810  {%endregion}
10811
10812  SrcEditMenuOpenFileAtCursor.Command := GetIdeCmdRegToolBtn(ecOpenFileAtCursor);
10813
10814  {%region * sub menu Flags section *}
10815    SrcEditMenuReadOnly.OnClick          := @ReadOnlyClicked;
10816    SrcEditMenuShowLineNumbers.OnClick   := @ToggleLineNumbersClicked;
10817    SrcEditMenuDisableI18NForLFM.OnClick := @ToggleI18NForLFMClicked;
10818    SrcEditMenuShowUnitInfo.OnClick      := @ShowUnitInfo;
10819  {%endregion}
10820
10821  {%region *** Clipboard section ***}
10822    SrcEditMenuCut.Command:=GetIdeCmdRegToolBtn(ecCut);
10823    SrcEditMenuCopy.Command:=GetIdeCmdRegToolBtn(ecCopy);
10824    SrcEditMenuPaste.Command:=GetIdeCmdRegToolBtn(ecPaste);
10825    SrcEditMenuMultiPaste.Command:=GetIdeCmdRegToolBtn(ecMultiPaste);
10826    SrcEditMenuCopyFilename.OnClick:=@CopyFilenameClicked;
10827    SrcEditMenuSelectAll.Command:=GetIdeCmdRegToolBtn(ecSelectAll);
10828  {%endregion}
10829
10830  SrcEditMenuNextBookmark.Command:=GetIdeCmdRegToolBtn(ecNextBookmark);
10831  SrcEditMenuPrevBookmark.Command:=GetIdeCmdRegToolBtn(ecPrevBookmark);
10832  SrcEditMenuSetFreeBookmark.Command:=GetIdeCmdRegToolBtn(ecSetFreeBookmark);
10833  SrcEditMenuClearFileBookmark.Command:=GetIdeCmdRegToolBtn(ecClearBookmarkForFile);
10834  SrcEditMenuClearAllBookmark.Command:=GetIdeCmdRegToolBtn(ecClearAllBookmark);
10835
10836  for i in TBookmarkNumRange do
10837    SrcEditMenuGotoBookmark[i].Command := GetIdeCmdRegToolBtn(ecGotoMarker0 + i);
10838  GetCommand_ButtonDrop(ecGotoBookmarks ,SrcEditSubMenuGotoBookmarks);        // [ ▼]
10839
10840  for i in TBookmarkNumRange do
10841    SrcEditMenuToggleBookmark[i].Command := GetIdeCmdRegToolBtn(ecToggleMarker0 + i);
10842  GetCommand_ButtonDrop(ecToggleBookmarks ,SrcEditSubMenuToggleBookmarks);    // [ ▼]
10843
10844  {%region *** Source Section ***}
10845    SrcEditMenuEncloseSelection.Command:=GetIdeCmdRegToolBtn(ecSelectionEnclose);
10846    SrcEditMenuEncloseInIFDEF.Command:=GetIdeCmdRegToolBtn(ecSelectionEncloseIFDEF);
10847    SrcEditMenuCompleteCode.Command:=GetIdeCmdRegToolBtn(ecCompleteCode);
10848    SrcEditMenuUseUnit.Command:=GetIdeCmdRegToolBtn(ecUseUnit);
10849  {%endregion}
10850
10851  {%region *** Refactoring Section ***}
10852    SrcEditMenuRenameIdentifier.Command:=GetIdeCmdRegToolBtn(ecRenameIdentifier);
10853    SrcEditMenuExtractProc.Command:=GetIdeCmdRegToolBtn(ecExtractProc);
10854    SrcEditMenuInvertAssignment.Command:=GetIdeCmdRegToolBtn(ecInvertAssignment);
10855    SrcEditMenuShowAbstractMethods.Command:=GetIdeCmdRegToolBtn(ecShowAbstractMethods);
10856    SrcEditMenuShowEmptyMethods.Command:=GetIdeCmdRegToolBtn(ecRemoveEmptyMethods);
10857    SrcEditMenuShowUnusedUnits.Command:=GetIdeCmdRegToolBtn(ecRemoveUnusedUnits);
10858    SrcEditMenuFindOverloads.Command:=GetIdeCmdRegToolBtn(ecFindOverloads);
10859    SrcEditMenuMakeResourceString.Command:=GetIdeCmdRegToolBtn(ecMakeResourceString);
10860  {%endregion}
10861
10862  SrcEditMenuEditorProperties.OnClick:=@EditorPropertiesClicked;
10863
10864  DebugBoss.SetupSourceMenuShortCuts;
10865end;
10866
10867function TSourceEditorManager.FindUniquePageName(FileName: string;
10868  IgnoreEditor: TSourceEditor): string;
10869var
10870  I:integer;
10871  ShortName:string;
10872
10873  function PageNameExists(const AName:string):boolean;
10874  var a:integer;
10875  begin
10876    Result:=false;
10877    for a := 0 to SourceEditorCount - 1 do begin
10878      if (SourceEditors[a] <> IgnoreEditor) and
10879         (not SourceEditors[a].IsSharedWith(IgnoreEditor)) and
10880         (CompareText(AName, SourceEditors[a].PageName) = 0)
10881      then begin
10882        Result:=true;
10883        exit;
10884      end;
10885    end;
10886  end;
10887
10888begin
10889  if FileName='' then begin
10890    FileName:='unit1';
10891    if not PageNameExists(FileName) then begin
10892      Result:=Filename;
10893      exit;
10894    end;
10895  end;
10896  if FilenameHasPascalExt(FileName) then
10897    ShortName:=ExtractFileNameOnly(Filename)
10898  else
10899    ShortName:=ExtractFileName(FileName);
10900  Result:=ShortName;
10901  if PageNameExists(Result) then begin
10902    i:=1;
10903    repeat
10904      inc(i);
10905      Result:=ShortName+'('+IntToStr(i)+')';
10906    until PageNameExists(Result)=false;
10907  end;
10908end;
10909
10910function TSourceEditorManager.SomethingModified(Verbose: boolean): boolean;
10911var
10912  i: integer;
10913begin
10914  for i:=0 to SourceEditorCount - 1 do
10915  begin
10916    if SourceEditors[i].Modified then
10917    begin
10918      if Verbose then
10919        debugln(['TSourceEditorManager.SomethingModified ',SourceEditors[i].FileName]);
10920      exit(true);
10921    end;
10922  end;
10923  Result:=false;
10924end;
10925
10926procedure TSourceEditorManager.OnIdle(Sender: TObject; var Done: Boolean);
10927var
10928  SrcEdit: TSourceEditor;
10929  i, j: Integer;
10930  aFilename: String;
10931  FreeList, FreeMarklings: boolean;
10932  Marklings: TFPList;
10933  Markling: TSourceMarkling;
10934begin
10935  SrcEdit:=ActiveEditor;
10936  if (SrcEdit<>nil)
10937  and (not SrcEdit.FSharedValues.FMarklingsValid) then
10938  begin
10939    //debugln(['TSourceEditorManager.OnIdle ',MarklingProducerCount]);
10940    aFilename:=SrcEdit.FileName;
10941    SrcEdit.EditorComponent.BeginUpdate(False);
10942    for i:=0 to MarklingProducerCount-1 do
10943    begin
10944      Marklings:=MarklingProducers[i].GetMarklings(aFilename,FreeList,FreeMarklings);
10945      for j:=0 to Marklings.Count-1 do
10946      begin
10947        Markling:=TSourceMarkling(Marklings[j]);
10948        if Markling=nil then ;
10949        // ToDo: add mark to synedit
10950        //debugln(['TSourceEditorManager.OnIdle ',Markling.Id,' ',Markling.Line,',',Markling.Column]);
10951
10952      end;
10953      if FreeMarklings then
10954        for j:=0 to Marklings.Count-1 do
10955          TObject(Marklings[j]).Free;
10956      if FreeList then
10957        Marklings.Free;
10958    end;
10959    SrcEdit.EditorComponent.EndUpdate;
10960    SrcEdit.FSharedValues.FMarklingsValid:=true;
10961  end;
10962end;
10963
10964procedure TSourceEditorManager.OnUserInput(Sender: TObject; Msg: Cardinal);
10965begin
10966  CodeToolsToSrcEditTimer.Enabled:=true;
10967  // Hints
10968  if FHints.HintIsComplex then
10969  begin
10970    // TODO: introduce property, to indicate if hint is interactive
10971    if FHints.PtIsOnHint(Mouse.CursorPos) then begin // ignore any action over Hint
10972      if FHints.CurHintWindow.Active then
10973        exit;
10974      if (Msg = WM_MOUSEMOVE)
10975         or (Msg = LM_MOUSELEAVE)
10976         {$IFDEF WINDOWS}
10977         or (Msg = WM_NCMOUSEMOVE)
10978         or ((Msg >= WM_MOUSEFIRST) and (Msg <= WM_MOUSELAST))
10979         {$ENDIF}
10980      then
10981        exit;
10982    end;
10983    if (Msg = WM_MOUSEMOVE) {$IFDEF WINDOWS} or (Msg = WM_NCMOUSEMOVE){$ENDIF} then begin
10984      FHints.HideAutoHintAfterMouseMoved;
10985      exit;
10986    end;
10987  end;
10988
10989  //debugln('TSourceEditorManager.OnUserInput');
10990  // don't hide hint if Sender is a hint window or child control
10991  if not FHints.SenderIsHintControl(Sender) then
10992    FHints.HideAutoHint;
10993end;
10994
10995procedure TSourceEditorManager.LockAllEditorsInSourceChangeCache;
10996// lock all sourceeditors that are to be modified by the CodeToolBoss
10997var
10998  i: integer;
10999begin
11000  for i:=0 to SourceEditorCount - 1 do begin
11001    if CodeToolBoss.SourceChangeCache.BufferIsModified(SourceEditors[i].CodeBuffer)
11002    then
11003      SourceEditors[i].BeginGlobalUpdate;
11004  end;
11005end;
11006
11007procedure TSourceEditorManager.UnlockAllEditorsInSourceChangeCache;
11008// unlock all sourceeditors that were modified by the CodeToolBoss
11009var
11010  i: integer;
11011begin
11012  for i:=0 to SourceEditorCount - 1 do begin
11013    if CodeToolBoss.SourceChangeCache.BufferIsModified(SourceEditors[i].CodeBuffer)
11014    then
11015      SourceEditors[i].EndGlobalUpdate;
11016  end;
11017end;
11018
11019procedure TSourceEditorManager.BeginGlobalUpdate;
11020var
11021  i: integer;
11022begin
11023  for i:=0 to SourceEditorCount - 1 do
11024    SourceEditors[i].BeginGlobalUpdate;
11025end;
11026
11027procedure TSourceEditorManager.EndGlobalUpdate;
11028var
11029  i: integer;
11030begin
11031  for i:=0 to SourceEditorCount - 1 do
11032    SourceEditors[i].EndGlobalUpdate;
11033end;
11034
11035procedure TSourceEditorManager.CloseFile(AEditor: TSourceEditorInterface);
11036var
11037  i, j: Integer;
11038begin
11039  i := SourceWindowCount - 1;
11040  while i >= 0 do begin
11041    j := SourceWindows[i].FindPageWithEditor(TSourceEditor(AEditor));
11042    if j >= 0 then begin
11043      SourceWindows[i].CloseFile(j);
11044      break;
11045    end;
11046    dec(i);
11047  end;
11048end;
11049
11050procedure TSourceEditorManager.HistoryJump(Sender: TObject;
11051  JumpAction: TJumpHistoryAction);
11052var
11053  NewCaretXY: TPoint;
11054  NewTopLine: integer;
11055  NewEditor: TSourceEditor;
11056begin
11057  if Assigned(OnJumpToHistoryPoint) then begin
11058    NewCaretXY.X:=-1;
11059    NewEditor:=nil;
11060    OnJumpToHistoryPoint(NewCaretXY,NewTopLine,NewEditor,JumpAction);
11061    if NewEditor<>nil then begin
11062      ActiveEditor := NewEditor;
11063      ShowActiveWindowOnTop(True);
11064      with NewEditor.EditorComponent do begin
11065        if not NewEditor.IsLocked then
11066          TopLine:=NewTopLine;
11067        LogicalCaretXY:=NewCaretXY;
11068      end;
11069    end;
11070  end;
11071end;
11072
11073procedure TSourceEditorManager.ActivateHint(const ScreenPos: TPoint;
11074  const BaseURL, TheHint: string; AutoShown: Boolean; AMouseOffset: Boolean);
11075begin
11076  if csDestroying in ComponentState then exit;
11077
11078  FHints.ActivateHint(ScreenPos, BaseURL, TheHint, AutoShown, AMouseOffset);
11079end;
11080
11081procedure TSourceEditorManager.ActivateHint(const ScreenRect: TRect;
11082  const BaseURL, TheHint: string; AutoShown: Boolean; AMouseOffset: Boolean);
11083begin
11084  if csDestroying in ComponentState then exit;
11085
11086  FHints.ActivateHint(ScreenRect, BaseURL, TheHint, AutoShown, AMouseOffset);
11087end;
11088
11089procedure TSourceEditorManager.OnCodeTemplateTokenNotFound(Sender: TObject;
11090  AToken: string; AnEditor: TCustomSynEdit; var Index: integer);
11091begin
11092  if Index=0 then ;
11093  //debugln('TSourceNotebook.OnCodeTemplateTokenNotFound ',AToken,',',AnEditor.ReadOnly,',',DefaultCompletionForm.CurrentCompletionType=ctNone);
11094  if (AnEditor.ReadOnly=false) and
11095     (DefaultCompletionForm.CurrentCompletionType=ctNone)
11096  then begin
11097    DefaultCompletionForm.CurrentCompletionType:=ctTemplateCompletion;
11098    DefaultCompletionForm.Editor:=AnEditor;
11099    DefaultCompletionForm.Execute
11100      (AToken, GetScreenRectForToken(AnEditor, AnEditor.CaretX-length(AToken),
11101       AnEditor.CaretY, AnEditor.CaretX-1));
11102  end;
11103end;
11104
11105procedure TSourceEditorManager.OnCodeTemplateExecuteCompletion(
11106  ASynAutoComplete: TCustomSynAutoComplete; Index: integer);
11107var
11108  SrcEdit: TSourceEditorInterface;
11109  TemplateName: string;
11110  TemplateValue: string;
11111  TemplateComment: string;
11112  TemplateAttr: TStrings;
11113begin
11114  SrcEdit:=FindSourceEditorWithEditorComponent(ASynAutoComplete.Editor);
11115  if SrcEdit=nil then
11116    SrcEdit := ActiveEditor;
11117  //debugln('TSourceNotebook.OnCodeTemplateExecuteCompletion A ',dbgsName(SrcEdit),' ',dbgsName(ASynAutoComplete.Editor));
11118
11119  TemplateName:=ASynAutoComplete.Completions[Index];
11120  TemplateValue:=ASynAutoComplete.CompletionValues[Index];
11121  TemplateComment:=ASynAutoComplete.CompletionComments[Index];
11122  TemplateAttr:=ASynAutoComplete.CompletionAttributes[Index];
11123  ExecuteCodeTemplate(SrcEdit,TemplateName,TemplateValue,TemplateComment,
11124                      ASynAutoComplete.EndOfTokenChr,TemplateAttr,
11125                      ASynAutoComplete.IndentToTokenStart);
11126end;
11127
11128procedure TSourceEditorManager.CodeToolsToSrcEditTimerTimer(Sender: TObject);
11129var
11130  i: Integer;
11131  SrcEdit: TSourceEditor;
11132begin
11133  CodeToolsToSrcEditTimer.Enabled:=false;
11134
11135  for i:=0 to SourceEditorCount-1 do begin
11136    SrcEdit:=SourceEditors[i];
11137    if not SrcEdit.EditorComponent.IsVisible then continue;
11138    SrcEdit.UpdateIfDefNodeStates;
11139  end;
11140end;
11141
11142procedure TSourceEditorManager.OnSourceCompletionTimer(Sender: TObject);
11143
11144  function CheckCodeAttribute (XY: TPoint; out CodeAttri: String): Boolean;
11145  var
11146    SrcEdit: TSourceEditor;
11147  begin
11148    Result := False;
11149
11150    SrcEdit := ActiveEditor;
11151    if SrcEdit = nil then exit;
11152
11153    dec(XY.X);
11154    CodeAttri := SrcEdit.GetCodeAttributeName(XY);
11155    Result := CodeAttri <> '';
11156  end;
11157
11158  function CheckStartIdentCompletion: boolean;
11159  var
11160    Line: String;
11161    LogCaret: TPoint;
11162    SrcEdit: TSourceEditor;
11163    CodeAttribute: String;
11164  begin
11165    Result := false;
11166    SrcEdit := ActiveEditor;
11167    if SrcEdit = nil then exit;
11168    if not (SrcEdit.FEditor.Highlighter is TSynPasSyn) then
11169      exit; // only start completion automatically for pascal sources
11170
11171    Line := SrcEdit.FEditor.LineText;
11172    LogCaret := SrcEdit.FEditor.LogicalCaretXY;
11173    //DebugLn(['CheckStartIdentCompletion Line="',Line,'" LogCaret=',dbgs(LogCaret)]);
11174
11175    // check if last character is a point
11176    if (Line='') or (LogCaret.X<=1) or (LogCaret.X-1>length(Line))
11177    or ((SrcEdit.FCodeCompletionState.State = ccsDot) and (Line[LogCaret.X-1]<>'.'))
11178    then
11179      exit;
11180
11181    if not CheckCodeAttribute(LogCaret, CodeAttribute) then
11182      Exit;
11183
11184    if (CodeAttribute = SYNS_XML_AttrComment) or
11185       (CodeAttribute = SYNS_XML_AttrString)
11186    then
11187      Exit;
11188
11189    // check if range operator '..'
11190    if (LogCaret.X>2) and (Line[LogCaret.X-2]='.') then
11191      exit; // this is a double point ..
11192
11193    // invoke identifier completion
11194    SrcEdit.StartIdentCompletionBox(false,false);
11195    Result:=true;
11196  end;
11197
11198  function CheckTemplateCompletion: boolean;
11199  begin
11200    Result:=false;
11201    // execute context sensitive templates
11202    //FCodeTemplateModul.ExecuteCompletion(Value,GetActiveSE.EditorComponent);
11203  end;
11204
11205var
11206  TempEditor: TSourceEditor;
11207begin
11208  AutoStartCompletionBoxTimer.Enabled:=false;
11209  AutoStartCompletionBoxTimer.AutoEnabled:=false;
11210  TempEditor := ActiveEditor;
11211  if (TempEditor <> nil) and TempEditor.EditorComponent.Focused and
11212     (ComparePoints(TempEditor.EditorComponent.LogicalCaretXY, SourceCompletionCaretXY) = 0)
11213  then begin
11214    if CheckStartIdentCompletion then begin
11215    end
11216    else if CheckTemplateCompletion then begin
11217    end;
11218  end;
11219end;
11220
11221procedure TSourceEditorManager.OnSourceMarksAction(AMark: TSourceMark;
11222  AAction: TMarksAction);
11223var
11224  Editor: TSourceEditor;
11225begin
11226  Editor := TSourceEditor(AMark.SourceEditor);
11227  if Editor = nil then
11228    Exit;
11229
11230  if ( AMark.IsBreakPoint and (Editor.FSharedValues.ExecutionMark <> nil) and
11231       (AMark.Line = Editor.ExecutionLine)
11232     ) or (AMark = Editor.FSharedValues.ExecutionMark)
11233  then
11234    Editor.UpdateExecutionSourceMark;
11235end;
11236
11237procedure TSourceEditorManager.OnSourceMarksGetSynEdit(Sender: TObject;
11238  aFilename: string; var aSynEdit: TSynEdit);
11239var
11240  SrcEdit: TSourceEditor;
11241begin
11242  SrcEdit:=SourceEditorIntfWithFilename(aFilename);
11243  if SrcEdit=nil then exit;
11244  aSynEdit:=SrcEdit.EditorComponent;
11245end;
11246
11247function TSourceEditorManager.GotoDialog: TfrmGoto;
11248begin
11249  if FGotoDialog=nil then
11250    FGotoDialog := TfrmGoto.Create(self);
11251  Result := FGotoDialog;
11252end;
11253
11254procedure TSourceEditorManager.DoConfigureEditorToolbar(Sender: TObject);
11255begin
11256  LazarusIDE.DoOpenIDEOptions(TEditorToolbarOptionsFrame, '', [], []);
11257end;
11258
11259constructor TSourceEditorManager.Create(AOwner: TComponent);
11260begin
11261  inherited Create(AOwner);
11262
11263  FDefaultCompletionForm := nil;
11264
11265  // word completion
11266  if aWordCompletion=nil then begin
11267    AWordCompletion:=TSourceEditorWordCompletion.Create;
11268    AWordCompletion.WordBufferCapacity:=100;
11269  end;
11270
11271  // timer for auto start identifier completion
11272  AutoStartCompletionBoxTimer := TIdleTimer.Create(Self);
11273  with AutoStartCompletionBoxTimer do begin
11274    Name:='AutoStartCompletionBoxTimer';
11275    AutoEnabled := False;
11276    Enabled := false;
11277    Interval := EditorOpts.AutoDelayInMSec;
11278    OnTimer := @OnSourceCompletionTimer;
11279  end;
11280
11281  // timer for syncing codetools changes to synedit
11282  // started on idle
11283  // ended on user input
11284  // when triggered updates ifdef node states
11285  CodeToolsToSrcEditTimer:=TTimer.Create(Self);
11286  with CodeToolsToSrcEditTimer do begin
11287    Name:='CodeToolsToSrcEditTimer';
11288    Interval:=1000; // one second without user input
11289    Enabled:=false;
11290    OnTimer:=@CodeToolsToSrcEditTimerTimer;
11291  end;
11292
11293  // marks
11294  SourceEditorMarks:=TSourceMarks.Create(Self);
11295  SourceEditorMarks.OnAction:=@OnSourceMarksAction;
11296  SourceEditorMarks.ExtToolsMarks.OnGetSynEditOfFile:=@OnSourceMarksGetSynEdit;
11297
11298  // HintWindow
11299  FHints := TSourceEditorHintWindowManager.Create(Self);
11300  FHints.WindowName := Self.Name+'_HintWindow';
11301  FHints.HideInterval := 4000;
11302
11303  // code templates
11304  FCodeTemplateModul:=TSynEditAutoComplete.Create(Self);
11305
11306  EditorOpts.LoadCodeTemplates(FCodeTemplateModul);
11307  with FCodeTemplateModul do begin
11308    IndentToTokenStart := EditorOpts.CodeTemplateIndentToTokenStart;
11309    OnTokenNotFound := @OnCodeTemplateTokenNotFound;
11310    OnExecuteCompletion := @OnCodeTemplateExecuteCompletion;
11311    EndOfTokenChr:=' ()[]{},.;:"+-*^@$\<>=''';
11312  end;
11313
11314  // EditorToolBar
11315  CreateEditorToolBar(@DoConfigureEditorToolbar);
11316
11317  // layout
11318  IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwSourceNoteBook],
11319    nil,@CreateSourceWindow,'250','100','+70%','+70%',
11320    NonModalIDEWindowNames[nmiwMainIDE],alBottom,true,@GetDefaultLayout);
11321
11322  Application.AddOnIdleHandler(@OnIdle);
11323  Application.AddOnUserInputHandler(@OnUserInput);
11324end;
11325
11326destructor TSourceEditorManager.Destroy;
11327begin
11328  FreeAndNil(FHints);
11329  SourceEditorMarks.OnAction := nil;
11330  Application.RemoveAllHandlersOfObject(Self);
11331  // aWordCompletion is released in InternalFinal
11332  aWordCompletion.OnGetSource := nil;
11333
11334  inherited Destroy;
11335end;
11336
11337function SortSourceWindows(SrcWin1, SrcWin2: TSourceNotebook): Integer;
11338begin
11339  Result := AnsiStrComp(PChar(SrcWin1.Caption), PChar(SrcWin2.Caption));
11340end;
11341
11342function TSourceEditorManager.CreateNewWindow(Activate: Boolean; DoDisableAutoSizing: boolean;
11343  AnID: Integer): TSourceNotebook;
11344var
11345  i: Integer;
11346begin
11347  Result := TSourceNotebook(TSourceNotebook.NewInstance);
11348  {$IFDEF DebugDisableAutoSizing}
11349  if DoDisableAutoSizing then
11350    Result.DisableAutoSizing('TAnchorDockMaster Delayed')
11351  else
11352    Result.DisableAutoSizing('TSourceEditorManager.CreateNewWindow');
11353  {$ELSE}
11354  Result.DisableAutoSizing;
11355  {$ENDIF};
11356  if AnID > 0 then
11357    Result.Create(Self, AnID)
11358  else
11359    Result.Create(Self);
11360
11361  for i := 1 to FUpdateLock do
11362    Result.IncUpdateLockInternal;
11363  FSourceWindowList.Add(Result);
11364  FSourceWindowList.Sort(TListSortCompare(@SortSourceWindows));
11365  FSourceWindowByFocusList.Add(Result);
11366  PasBeautifier.OnGetDesiredIndent :=
11367    @TSourceNotebook(FSourceWindowList[0]).EditorGetIndent;
11368  if Activate then begin
11369    ActiveSourceWindow := Result;
11370    ShowActiveWindowOnTop(False);
11371  end;
11372  FChangeNotifyLists[semWindowCreate].CallNotifyEvents(Result);
11373  if not DoDisableAutoSizing then
11374    Result.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceEditorManager.CreateNewWindow'){$ENDIF};
11375end;
11376
11377function TSourceEditorManager.SenderToEditor(Sender: TObject): TSourceEditor;
11378begin
11379  if Sender is TSourceEditor then
11380    Result:=TSourceEditor(Sender)
11381  else if Sender is TSourceNotebook then
11382    Result:=TSourceNotebook(Sender).ActiveEditor as TSourceEditor
11383  else
11384    Result:=ActiveEditor;
11385end;
11386
11387procedure TSourceEditorManager.RemoveWindow(AWindow: TSourceNotebook);
11388var
11389  i: Integer;
11390begin
11391  if FSourceWindowList = nil then exit;
11392  i := FSourceWindowList.IndexOf(AWindow);
11393  FSourceWindowList.Remove(AWindow);
11394  FSourceWindowByFocusList.Remove(AWindow);
11395  if SourceWindowCount = 0 then
11396    ActiveSourceWindow := nil
11397  else if ActiveSourceWindow = AWindow then
11398    ActiveSourceWindow := SourceWindows[Max(0, Min(i, SourceWindowCount-1))];
11399  if FSourceWindowList.Count > 0 then
11400    PasBeautifier.OnGetDesiredIndent :=
11401      @TSourceNotebook(FSourceWindowList[0]).EditorGetIndent
11402  else
11403    PasBeautifier.OnGetDesiredIndent := nil;
11404  if i >= 0 then
11405    FChangeNotifyLists[semWindowDestroy].CallNotifyEvents(AWindow);
11406end;
11407
11408(* Context Menu handlers *)
11409
11410procedure TSourceEditorManager.CloseOtherPagesClicked(Sender: TObject);
11411begin
11412  if Assigned(OnCloseClicked) then
11413    OnCloseClicked(Sender, [ceoCloseOthers]);
11414end;
11415
11416procedure TSourceEditorManager.CloseOtherPagesClickedAsync(Sender: PtrInt);
11417begin
11418  CloseOtherPagesClicked(TObject(Sender));
11419end;
11420
11421procedure TSourceEditorManager.CloseRightPagesClicked(Sender: TObject);
11422begin
11423  if Assigned(OnCloseClicked) then
11424    OnCloseClicked(Sender, [ceoCloseOthersOnRightSide]);
11425end;
11426
11427procedure TSourceEditorManager.CloseRightPagesClickedAsync(Sender: PtrInt);
11428begin
11429  CloseRightPagesClicked(TObject(Sender));
11430end;
11431
11432procedure TSourceEditorManager.ReadOnlyClicked(Sender: TObject);
11433var ActEdit: TSourceEditor;
11434begin
11435  ActEdit:=ActiveEditor;
11436  if ActEdit = nil then exit;
11437
11438  if ActEdit.ReadOnly and (ActEdit.CodeBuffer<>nil)
11439  and (not ActEdit.CodeBuffer.IsVirtual)
11440  and (not FileIsWritable(ActEdit.CodeBuffer.Filename)) then begin
11441    IDEMessageDialog(ueFileROCap,
11442      ueFileROText1+ActEdit.CodeBuffer.Filename+ueFileROText2,
11443      mtError,[mbCancel]);
11444    exit;
11445  end;
11446  ActEdit.EditorComponent.ReadOnly := not(ActEdit.EditorComponent.ReadOnly);
11447  if Assigned(OnReadOnlyChanged) then
11448    OnReadOnlyChanged(Self);
11449  ActEdit.SourceNotebook.UpdateStatusBar;
11450end;
11451
11452procedure TSourceEditorManager.ToggleLineNumbersClicked(Sender: TObject);
11453var
11454  MenuITem: TIDESpecialCommand;
11455  ActEdit:TSourceEditor;
11456  i: integer;
11457  ShowLineNumbers: boolean;
11458begin
11459  MenuItem := Sender as TIDESpecialCommand;
11460  ActEdit:=ActiveEditor;
11461  if ActEdit = nil then exit;
11462
11463  MenuItem.Checked := not EditorOpts.ShowLineNumbers;
11464  ShowLineNumbers:=MenuItem.Checked;
11465
11466  for i:=0 to SourceEditorCount-1 do
11467    SourceEditors[i].EditorComponent.Gutter.LineNumberPart.Visible := ShowLineNumbers;
11468  EditorOpts.ShowLineNumbers := ShowLineNumbers;
11469  EditorOpts.Save;
11470end;
11471
11472procedure TSourceEditorManager.ToggleI18NForLFMClicked(Sender: TObject);
11473begin
11474  //
11475end;
11476
11477procedure TSourceEditorManager.ShowUnitInfo(Sender: TObject);
11478begin
11479  if Assigned(OnShowUnitInfo) then
11480    OnShowUnitInfo(Sender);
11481end;
11482
11483procedure TSourceEditorManager.CopyFilenameClicked(Sender: TObject);
11484var ActSE: TSourceEditor;
11485begin
11486  ActSE := GetActiveSE;
11487  if ActSE <> nil then
11488    Clipboard.AsText:=ActSE.FileName;
11489end;
11490
11491procedure TSourceEditorManager.EditorPropertiesClicked(Sender: TObject);
11492begin
11493  LazarusIDE.DoOpenIDEOptions(TEditorGeneralOptionsFrame);
11494end;
11495
11496initialization
11497  InternalInit;
11498
11499finalization
11500  InternalFinal;
11501
11502end.
11503
11504