mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-12 15:29:23 +02:00
9043 lines
288 KiB
ObjectPascal
9043 lines
288 KiB
ObjectPascal
{
|
|
/***************************************************************************
|
|
SourceEditor.pp
|
|
-------------------
|
|
|
|
***************************************************************************/
|
|
|
|
***************************************************************************
|
|
* *
|
|
* This source is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This code is distributed in the hope that it will be useful, but *
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* General Public License for more details. *
|
|
* *
|
|
* A copy of the GNU General Public License is available on the World *
|
|
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
|
|
* obtain it by writing to the Free Software Foundation, *
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
* *
|
|
***************************************************************************
|
|
}
|
|
{ This unit builds the TSourceNotebook that the editors are held on.
|
|
It also has a class that controls the editors (TSourceEditor)
|
|
}
|
|
unit SourceEditor;
|
|
|
|
{$mode objfpc}
|
|
{$H+}
|
|
|
|
interface
|
|
|
|
{$I ide.inc}
|
|
|
|
{ $DEFINE VerboseIDECompletionBox}
|
|
|
|
uses
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
MemCheck,
|
|
{$ENDIF}
|
|
Classes, SysUtils, Math, Controls, ExtendedNotebook, LCLProc, LCLType, LResources,
|
|
LCLIntf, FileUtil, Forms, ComCtrls, Dialogs, StdCtrls, Graphics, Translations,
|
|
ClipBrd, types, Extctrls, Menus, HelpIntfs, LConvEncoding,
|
|
// codetools
|
|
BasicCodeTools, CodeBeautifier, CodeToolManager, CodeCache, SourceLog,
|
|
// synedit
|
|
SynEditLines, SynEditStrConst, SynEditTypes, SynEdit, SynRegExpr,
|
|
SynEditHighlighter, SynEditAutoComplete, SynEditKeyCmds, SynCompletion,
|
|
SynEditMiscClasses, SynEditMarkupHighAll, SynEditMarks,
|
|
SynBeautifier, SynEditTextBase,
|
|
SynPluginSyncronizedEditBase, SourceSynEditor,
|
|
// Intf
|
|
SrcEditorIntf, MenuIntf, LazIDEIntf, PackageIntf, IDEHelpIntf, IDEImagesIntf,
|
|
IDEWindowIntf, ProjectIntf,
|
|
// IDE units
|
|
IDEDialogs, LazarusIDEStrConsts, IDECommands, EditorOptions,
|
|
WordCompletion, FindReplaceDialog, IDEProcs, IDEOptionDefs,
|
|
MacroPromptDlg, TransferMacros, CodeContextForm, SrcEditHintFrm,
|
|
EnvironmentOpts, MsgView, InputHistory, CodeMacroPrompt,
|
|
CodeTemplatesDlg, CodeToolsOptions,
|
|
SortSelectionDlg, EncloseSelectionDlg, ConDef, InvertAssignTool,
|
|
SourceEditProcs, SourceMarks, CharacterMapDlg, SearchFrm,
|
|
FPDocHints,
|
|
BaseDebugManager, Debugger, MainIntf, GotoFrm;
|
|
|
|
type
|
|
TSourceNotebook = class;
|
|
TSourceEditorManager = class;
|
|
|
|
TNotifyFileEvent = procedure(Sender: TObject; Filename : AnsiString) of object;
|
|
|
|
TOnProcessUserCommand = procedure(Sender: TObject;
|
|
Command: word; var Handled: boolean) of object;
|
|
TOnUserCommandProcessed = procedure(Sender: TObject;
|
|
Command: word; var Handled: boolean) of object;
|
|
|
|
TOnLinesInsertedDeleted = procedure(Sender : TObject;
|
|
FirstLine,Count : Integer) of Object;
|
|
TPlaceBookMarkEvent = procedure(Sender: TObject; var Mark: TSynEditMark) of object;
|
|
TBookMarkActionEvent = procedure(Sender: TObject; ID: Integer; Toggle: Boolean) of object;
|
|
|
|
TCharSet = set of Char;
|
|
|
|
{ TSynEditPlugin1 }
|
|
|
|
TSynEditPlugin1 = class(TSynEditPlugin)
|
|
private
|
|
FEnabled: Boolean;
|
|
FOnLinesInserted : TOnLinesInsertedDeleted;
|
|
FOnLinesDeleted : TOnLinesInsertedDeleted;
|
|
protected
|
|
Procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
|
|
function OwnedByEditor: Boolean; override;
|
|
public
|
|
property OnLinesInserted : TOnLinesInsertedDeleted
|
|
read FOnLinesinserted write FOnLinesInserted;
|
|
property OnLinesDeleted : TOnLinesInsertedDeleted
|
|
read FOnLinesDeleted write FOnLinesDeleted;
|
|
property Enabled: Boolean read FEnabled write FEnabled;
|
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TSourceEditCompletion }
|
|
|
|
TSourceEditCompletion=class(TSynCompletion)
|
|
private
|
|
FIdentCompletionJumpToError: boolean;
|
|
ccSelection: String;
|
|
// colors for the completion form (popup form, e.g. word completion)
|
|
FActiveEditDefaultFGColor: TColor;
|
|
FActiveEditDefaultBGColor: TColor;
|
|
FActiveEditSelectedFGColor: TColor;
|
|
FActiveEditSelectedBGColor: TColor;
|
|
|
|
procedure ccExecute(Sender: TObject);
|
|
procedure ccCancel(Sender: TObject);
|
|
procedure ccComplete(var Value: string; SourceValue: string;
|
|
var SourceStart, SourceEnd: TPoint;
|
|
KeyChar: TUTF8Char; Shift: TShiftState);
|
|
function OnSynCompletionPaintItem(const AKey: string; ACanvas: TCanvas;
|
|
X, Y: integer; ItemSelected: boolean; Index: integer): boolean;
|
|
function OnSynCompletionMeasureItem(const AKey: string; ACanvas: TCanvas;
|
|
ItemSelected: boolean; Index: integer): TPoint;
|
|
procedure OnSynCompletionSearchPosition(var APosition: integer);
|
|
procedure OnSynCompletionCompletePrefix(Sender: TObject);
|
|
procedure OnSynCompletionNextChar(Sender: TObject);
|
|
procedure OnSynCompletionPrevChar(Sender: TObject);
|
|
procedure OnSynCompletionKeyPress(Sender: TObject; var Key: Char);
|
|
procedure OnSynCompletionUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
|
|
procedure OnSynCompletionPositionChanged(Sender: TObject);
|
|
|
|
function InitIdentCompletionValues(S: TStrings): boolean;
|
|
procedure StartShowCodeHelp;
|
|
protected
|
|
CurrentCompletionType: TCompletionType;
|
|
function Manager: TSourceEditorManager;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
property IdentCompletionJumpToError: Boolean
|
|
read FIdentCompletionJumpToError write FIdentCompletionJumpToError;
|
|
end;
|
|
|
|
TSourceEditor = class;
|
|
|
|
{ TSourceEditorSharedValues }
|
|
|
|
TSourceEditorSharedValues = class
|
|
private
|
|
FSharedEditorList: TFPList; // list of TSourceEditor sharing one TSynEdit
|
|
function GetOtherSharedEditors(Caller: TSourceEditor; Index: Integer): TSourceEditor;
|
|
function GetSharedEditors(Index: Integer): TSourceEditor;
|
|
function SynEditor: TIDESynEditor;
|
|
public
|
|
procedure AddSharedEditor(AnEditor: TSourceEditor);
|
|
procedure RemoveSharedEditor(AnEditor: TSourceEditor);
|
|
procedure SetActiveSharedEditor(AnEditor: TSourceEditor);
|
|
function SharedEditorCount: Integer;
|
|
function OtherSharedEditorCount: Integer;
|
|
property SharedEditors[Index: Integer]: TSourceEditor read GetSharedEditors;
|
|
property OtherSharedEditors[Caller: TSourceEditor; Index: Integer]: TSourceEditor
|
|
read GetOtherSharedEditors;
|
|
private
|
|
FExecutionMark: TSourceMark;
|
|
FExecutionLine: integer;
|
|
FMarksRequested: Boolean;
|
|
FMarklingsValid: boolean;
|
|
public
|
|
UpdatingExecutionMark: Integer;
|
|
procedure CreateExecutionMark;
|
|
property ExecutionLine: Integer read FExecutionLine write FExecutionLine;
|
|
property ExecutionMark: TSourceMark read FExecutionMark write FExecutionMark;
|
|
procedure SetExecutionLine(NewLine: integer);
|
|
property MarksRequested: Boolean read FMarksRequested write FMarksRequested;
|
|
private
|
|
FInGlobalUpdate: Integer;
|
|
FModified: boolean;
|
|
FIgnoreCodeBufferLock: integer;
|
|
FEditorStampCommitedToCodetools: int64;
|
|
FCodeBuffer: TCodeBuffer;
|
|
function GetModified: Boolean;
|
|
procedure SetCodeBuffer(const AValue: TCodeBuffer);
|
|
procedure SetModified(const AValue: Boolean);
|
|
procedure OnCodeBufferChanged(Sender: TSourceLog; SrcLogEntry: TSourceLogEntry);
|
|
public
|
|
procedure BeginGlobalUpdate;
|
|
procedure EndGlobalUpdate;
|
|
property Modified: Boolean read GetModified write SetModified;
|
|
property IgnoreCodeBufferLock: Integer read FIgnoreCodeBufferLock;
|
|
procedure IncreaseIgnoreCodeBufferLock;
|
|
procedure DecreaseIgnoreCodeBufferLock;
|
|
function NeedsUpdateCodeBuffer: boolean;
|
|
procedure UpdateCodeBuffer;
|
|
property CodeBuffer: TCodeBuffer read FCodeBuffer write SetCodeBuffer;
|
|
protected
|
|
BookmarkEventLock: Integer;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TSourceEditor ---
|
|
TSourceEditor is the class that controls access for a single source editor,
|
|
which is part of TSourceNotebook. }
|
|
|
|
TSourceEditor = class(TSourceEditorInterface)
|
|
private
|
|
//FAOwner is normally a TSourceNotebook. This is set in the Create constructor.
|
|
FAOwner: TComponent;
|
|
FIsLocked: Boolean;
|
|
FIsNewSharedEditor: Boolean;
|
|
FSharedValues: TSourceEditorSharedValues;
|
|
FEditor: TIDESynEditor;
|
|
FTempCaret: TPoint;
|
|
FTempTopLine: Integer;
|
|
FEditPlugin: TSynEditPlugin1; // used to get the LinesInserted and
|
|
// LinesDeleted messages
|
|
FSyncroLockCount: Integer;
|
|
FPageName: string;
|
|
|
|
FPopUpMenu: TPopupMenu;
|
|
FSyntaxHighlighterType: TLazSyntaxHighlighter;
|
|
FErrorLine: integer;
|
|
FErrorColumn: integer;
|
|
FLineInfoNotification: TIDELineInfoNotification;
|
|
|
|
FOnEditorChange: TNotifyEvent;
|
|
FVisible: Boolean;
|
|
FOnMouseMove: TMouseMoveEvent;
|
|
FOnMouseDown: TMouseEvent;
|
|
FOnMouseWheel : TMouseWheelEvent;
|
|
FOnKeyDown: TKeyEvent;
|
|
|
|
FSourceNoteBook: TSourceNotebook;
|
|
|
|
procedure EditorMouseMoved(Sender: TObject; Shift: TShiftState; X,Y:Integer);
|
|
procedure EditorMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X,Y: Integer);
|
|
procedure EditorMouseWheel(Sender: TObject; Shift: TShiftState;
|
|
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure EditorStatusChanged(Sender: TObject; Changes: TSynStatusChanges);
|
|
procedure EditorPaste(Sender: TObject; var AText: String;
|
|
var AMode: TSynSelectionMode; ALogStartPos: TPoint;
|
|
var AnAction: TSynCopyPasteAction);
|
|
procedure EditorPlaceBookmark(Sender: TObject; var Mark: TSynEditMark);
|
|
procedure EditorClearBookmark(Sender: TObject; var Mark: TSynEditMark);
|
|
procedure EditorEnter(Sender: TObject);
|
|
procedure EditorActivateSyncro(Sender: TObject);
|
|
procedure EditorDeactivateSyncro(Sender: TObject);
|
|
function GetCodeBuffer: TCodeBuffer;
|
|
function GetExecutionLine: integer;
|
|
function GetHasExecutionMarks: Boolean;
|
|
function GetSharedEditors(Index: Integer): TSourceEditor;
|
|
procedure SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
|
|
function GetSource: TStrings;
|
|
procedure SetIsLocked(const AValue: Boolean);
|
|
procedure SetPageName(const AValue: string);
|
|
procedure UpdateExecutionSourceMark;
|
|
procedure UpdatePageName;
|
|
procedure SetSource(Value: TStrings);
|
|
function GetCurrentCursorXLine: Integer;
|
|
procedure SetCurrentCursorXLine(num : Integer);
|
|
function GetCurrentCursorYLine: Integer;
|
|
procedure SetCurrentCursorYLine(num: Integer);
|
|
Function GetInsertMode: Boolean;
|
|
procedure SetPopupMenu(NewPopupMenu: TPopupMenu);
|
|
|
|
function GotoLine(Value: Integer): Integer;
|
|
|
|
procedure CreateEditor(AOwner: TComponent; AParent: TWinControl);
|
|
procedure UpdateNoteBook(const ANewNoteBook: TSourceNotebook; ANewPage: TTabSheet);
|
|
procedure SetVisible(Value: boolean);
|
|
procedure UnbindEditor;
|
|
protected
|
|
ErrorMsgs: TStrings;
|
|
|
|
procedure ProcessCommand(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
|
|
procedure ProcessUserCommand(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
|
|
procedure UserCommandProcessed(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
|
|
procedure ccAddMessage(Texts: String);
|
|
function AutoCompleteChar(Char: TUTF8Char; var AddChar: boolean;
|
|
Category: TAutoCompleteOption): boolean;
|
|
function AutoBlockCompleteChar(Char: TUTF8Char; var AddChar: boolean;
|
|
Category: TAutoCompleteOption; aTextPos: TPoint; Line: string): boolean;
|
|
function AutoBlockCompleteChar(Char: TUTF8Char): boolean;
|
|
procedure AutoCompleteBlock;
|
|
|
|
procedure FocusEditor;// called by TSourceNotebook when the Notebook page
|
|
// changes so the editor is focused
|
|
procedure OnGutterClick(Sender: TObject; X, Y, Line: integer;
|
|
mark: TSynEditMark);
|
|
procedure OnEditorSpecialLineColor(Sender: TObject; Line: integer;
|
|
var Special: boolean; Markup: TSynSelectedColor);
|
|
function RefreshEditorSettings: Boolean;
|
|
function GetModified: Boolean; override;
|
|
procedure SetModified(const NewValue: Boolean); override;
|
|
procedure SetSyntaxHighlighterType(
|
|
ASyntaxHighlighterType: TLazSyntaxHighlighter);
|
|
procedure SetErrorLine(NewLine: integer);
|
|
procedure SetExecutionLine(NewLine: integer);
|
|
procedure StartIdentCompletionBox(JumpToError: boolean);
|
|
procedure StartWordCompletionBox(JumpToError: boolean);
|
|
|
|
procedure LinesInserted(sender: TObject; FirstLine, Count: Integer);
|
|
procedure LinesDeleted(sender: TObject; FirstLine, Count: Integer);
|
|
|
|
function GetFilename: string; override;
|
|
function GetEditorControl: TWinControl; override;
|
|
function GetCodeToolsBuffer: TObject; override;
|
|
Function GetReadOnly: Boolean; override;
|
|
procedure SetReadOnly(const NewValue: boolean); override;
|
|
|
|
function Manager: TSourceEditorManager;
|
|
property Visible: Boolean read FVisible write SetVisible default False;
|
|
function IsSharedWith(AnOtherEditor: TSourceEditor): Boolean;
|
|
procedure BeforeCodeBufferReplace;
|
|
procedure AfterCodeBufferReplace;
|
|
public
|
|
constructor Create(AOwner: TComponent; AParent: TWinControl; ASharedEditor: TSourceEditor = nil);
|
|
destructor Destroy; override;
|
|
function Close: Boolean;
|
|
|
|
// codebuffer
|
|
procedure BeginUndoBlock; override;
|
|
procedure EndUndoBlock; override;
|
|
procedure BeginUpdate; override;
|
|
procedure EndUpdate; override;
|
|
procedure BeginGlobalUpdate;
|
|
procedure EndGlobalUpdate;
|
|
procedure IncreaseIgnoreCodeBufferLock; override;
|
|
procedure DecreaseIgnoreCodeBufferLock; override;
|
|
procedure UpdateCodeBuffer; override;// copy the source from EditorComponent
|
|
function NeedsUpdateCodeBuffer: boolean; override;
|
|
|
|
// find
|
|
procedure StartFindAndReplace(Replace:boolean);
|
|
procedure AskReplace(Sender: TObject; const ASearch, AReplace:
|
|
string; Line, Column: integer; var Action: TSrcEditReplaceAction); override;
|
|
procedure OnReplace(Sender: TObject; const ASearch, AReplace:
|
|
string; Line, Column: integer; var Action: TSynReplaceAction);
|
|
function DoFindAndReplace: Integer;
|
|
procedure FindNextUTF8;
|
|
procedure FindPrevious;
|
|
procedure FindNextWordOccurrence(DirectionForward: boolean);
|
|
procedure ShowGotoLineDialog;
|
|
|
|
// dialogs
|
|
procedure GetDialogPosition(Width, Height: integer; out Left, Top: integer);
|
|
procedure ActivateHint(ClientPos: TPoint;
|
|
const BaseURL, TheHint: string);
|
|
|
|
// selections
|
|
function SelectionAvailable: boolean; override;
|
|
function GetText(OnlySelection: boolean): string; override;
|
|
procedure SelectText(const StartPos, EndPos: TPoint); override;
|
|
procedure ReplaceLines(StartLine, EndLine: integer; const NewText: string); override;
|
|
procedure EncloseSelection;
|
|
procedure UpperCaseSelection;
|
|
procedure LowerCaseSelection;
|
|
procedure TabsToSpacesInSelection;
|
|
procedure CommentSelection;
|
|
procedure UncommentSelection;
|
|
procedure ToggleCommentSelection;
|
|
procedure UpdateCommentSelection(CommentOn, Toggle: Boolean);
|
|
procedure ConditionalSelection;
|
|
procedure SortSelection;
|
|
procedure BreakLinesInSelection;
|
|
procedure InvertAssignment;
|
|
procedure SelectToBrace;
|
|
procedure SelectCodeBlock;
|
|
procedure SelectWord;
|
|
procedure SelectLine;
|
|
procedure SelectParagraph;
|
|
function CommentText(const Txt: string; CommentType: TCommentType): string;
|
|
procedure InsertCharacterFromMap;
|
|
procedure InsertLicenseNotice(const Notice: string; CommentType: TCommentType);
|
|
procedure InsertGPLNotice(CommentType: TCommentType);
|
|
procedure InsertLGPLNotice(CommentType: TCommentType);
|
|
procedure InsertModifiedLGPLNotice(CommentType: TCommentType);
|
|
procedure InsertUsername;
|
|
procedure InsertDateTime;
|
|
procedure InsertChangeLogEntry;
|
|
procedure InsertCVSKeyword(const AKeyWord: string);
|
|
function GetSelEnd: Integer; override;
|
|
function GetSelStart: Integer; override;
|
|
procedure SetSelEnd(const AValue: Integer); override;
|
|
procedure SetSelStart(const AValue: Integer); override;
|
|
function GetSelection: string; override;
|
|
procedure SetSelection(const AValue: string); override;
|
|
procedure CopyToClipboard; override;
|
|
procedure CutToClipboard; override;
|
|
|
|
// context help
|
|
procedure FindHelpForSourceAtCursor;
|
|
|
|
// editor commands
|
|
procedure DoEditorExecuteCommand(EditorCommand: word);
|
|
|
|
// used to get the word at the mouse cursor
|
|
function GetWordFromCaret(const ACaretPos: TPoint): String;
|
|
function GetWordAtCurrentCaret: String;
|
|
function GetOperandFromCaret(const ACaretPos: TPoint): String;
|
|
function GetOperandAtCurrentCaret: String;
|
|
function CaretInSelection(const ACaretPos: TPoint): Boolean;
|
|
|
|
// cursor
|
|
procedure CenterCursor(SoftCenter: Boolean = False);
|
|
function TextToScreenPosition(const Position: TPoint): TPoint; override;
|
|
function ScreenToTextPosition(const Position: TPoint): TPoint; override;
|
|
function ScreenToPixelPosition(const Position: TPoint): TPoint; override;
|
|
function GetCursorScreenXY: TPoint; override;
|
|
function GetCursorTextXY: TPoint; override;
|
|
procedure SetCursorScreenXY(const AValue: TPoint); override;
|
|
procedure SetCursorTextXY(const AValue: TPoint); override;
|
|
function GetBlockBegin: TPoint; override;
|
|
function GetBlockEnd: TPoint; override;
|
|
procedure SetBlockBegin(const AValue: TPoint); override;
|
|
procedure SetBlockEnd(const AValue: TPoint); override;
|
|
function GetTopLine: Integer; override;
|
|
procedure SetTopLine(const AValue: Integer); override;
|
|
function CursorInPixel: TPoint; override;
|
|
function IsCaretOnScreen(ACaret: TPoint; UseSoftCenter: Boolean = False): Boolean;
|
|
|
|
// text
|
|
function SearchReplace(const ASearch, AReplace: string;
|
|
SearchOptions: TSrcEditSearchOptions): integer; override;
|
|
function GetSourceText: string; override;
|
|
procedure SetSourceText(const AValue: string); override;
|
|
function LineCount: Integer; override;
|
|
function WidthInChars: Integer; override;
|
|
function HeightInLines: Integer; override;
|
|
function CharWidth: integer; override;
|
|
function GetLineText: string; override;
|
|
procedure SetLineText(const AValue: string); override;
|
|
function GetLines: TStrings; override;
|
|
procedure SetLines(const AValue: TStrings); override;
|
|
|
|
// context
|
|
function GetProjectFile: TLazProjectFile; override;
|
|
procedure UpdateProjectFile; override;
|
|
function GetDesigner(LoadForm: boolean): TIDesigner; override;
|
|
|
|
// notebook
|
|
procedure Activate;
|
|
function PageIndex: integer;
|
|
function IsActiveOnNoteBook: boolean;
|
|
|
|
// debugging
|
|
procedure FillExecutionMarks;
|
|
procedure ClearExecutionMarks;
|
|
procedure LineInfoNotificationChange(const ASender: TObject; const ASource: String);
|
|
function SourceToDebugLine(aLinePos: Integer): Integer;
|
|
function DebugToSourceLine(aLinePos: Integer): Integer;
|
|
public
|
|
// properties
|
|
property CodeBuffer: TCodeBuffer read GetCodeBuffer write SetCodeBuffer;
|
|
property CurrentCursorXLine: Integer
|
|
read GetCurrentCursorXLine write SetCurrentCursorXLine;
|
|
property CurrentCursorYLine: Integer
|
|
read GetCurrentCursorYLine write SetCurrentCursorYLine;
|
|
property EditorComponent: TIDESynEditor read FEditor;
|
|
property ErrorLine: integer read FErrorLine write SetErrorLine;
|
|
property ExecutionLine: integer read GetExecutionLine write SetExecutionLine;
|
|
property HasExecutionMarks: Boolean read GetHasExecutionMarks;
|
|
property InsertMode: Boolean read GetInsertmode;
|
|
property OnEditorChange: TNotifyEvent read FOnEditorChange
|
|
write FOnEditorChange;
|
|
property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
|
|
property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
|
|
property OnMouseWheel: TMouseWheelEvent read FOnMouseWheel write FOnMouseWheel;
|
|
property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
|
|
property Owner: TComponent read FAOwner;
|
|
property PageName: string read FPageName write SetPageName;
|
|
property PopupMenu: TPopupMenu read FPopUpMenu write SetPopUpMenu;
|
|
property ReadOnly: Boolean read GetReadOnly write SetReadOnly;
|
|
property Source: TStrings read GetSource write SetSource;
|
|
property SourceNotebook: TSourceNotebook read FSourceNoteBook;
|
|
property SyntaxHighlighterType: TLazSyntaxHighlighter
|
|
read fSyntaxHighlighterType write SetSyntaxHighlighterType;
|
|
property SyncroLockCount: Integer read FSyncroLockCount;
|
|
function SharedEditorCount: Integer;
|
|
property SharedEditors[Index: Integer]: TSourceEditor read GetSharedEditors;
|
|
property IsNewSharedEditor: Boolean read FIsNewSharedEditor write FIsNewSharedEditor;
|
|
property IsLocked: Boolean read FIsLocked write SetIsLocked;
|
|
end;
|
|
|
|
//============================================================================
|
|
|
|
{ TSourceNotebook }
|
|
|
|
TJumpHistoryAction = (jhaBack, jhaForward, jhaViewWindow);
|
|
|
|
TOnJumpToHistoryPoint = procedure(var NewCaretXY: TPoint;
|
|
var NewTopLine: integer;
|
|
var DestEditor: TSourceEditor;
|
|
Action: TJumpHistoryAction) of object;
|
|
TOnAddJumpPoint = procedure(ACaretXY: TPoint; ATopLine: integer;
|
|
AEditor: TSourceEditor; DeleteForwardHistory: boolean) of object;
|
|
TOnMovingPage = procedure(Sender: TObject;
|
|
OldPageIndex, NewPageIndex: integer) of object;
|
|
TOnCloseSrcEditor = procedure(Sender: TObject; InvertedClose: boolean) of object;
|
|
TOnShowHintForSource = procedure(SrcEdit: TSourceEditor; ClientPos: TPoint;
|
|
CaretPos: TPoint) of object;
|
|
TOnInitIdentCompletion = procedure(Sender: TObject; JumpToError: boolean;
|
|
out Handled, Abort: boolean) of object;
|
|
TSrcEditPopupMenuEvent = procedure(const AddMenuItemProc: TAddMenuItemProc
|
|
) of object;
|
|
TOnShowCodeContext = procedure(JumpToError: boolean;
|
|
out Abort: boolean) of object;
|
|
TOnGetIndentEvent = function(Sender: TObject; Editor: TSourceEditor;
|
|
LogCaret, OldLogCaret: TPoint; FirstLinePos, LinesCount: Integer;
|
|
Reason: TSynEditorCommand; SetIndentProc: TSynBeautifierSetIndentProc
|
|
): boolean of object;
|
|
|
|
TSourceNotebookState = (
|
|
snIncrementalFind,
|
|
snWarnedFont,
|
|
snUpdateStatusBarNeeded,
|
|
snNotbookPageChangedNeeded
|
|
);
|
|
TSourceNotebookStates = set of TSourceNotebookState;
|
|
|
|
{ TSourceNotebook }
|
|
|
|
TSourceNotebook = class(TSourceEditorWindowInterface)
|
|
StatusBar: TStatusBar;
|
|
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure StatusBarDblClick(Sender: TObject);
|
|
private
|
|
FNotebook: TExtendedNotebook;
|
|
FBaseCaption: String;
|
|
FIsClosing: Boolean;
|
|
SrcPopUpMenu: TPopupMenu;
|
|
protected
|
|
procedure CompleteCodeMenuItemClick(Sender: TObject);
|
|
procedure EncloseSelectionMenuItemClick(Sender: TObject);
|
|
procedure ExtractProcMenuItemClick(Sender: TObject);
|
|
procedure InvertAssignmentMenuItemClick(Sender: TObject);
|
|
procedure FindIdentifierReferencesMenuItemClick(Sender: TObject);
|
|
procedure RenameIdentifierMenuItemClick(Sender: TObject);
|
|
procedure ShowAbstractMethodsMenuItemClick(Sender: TObject);
|
|
procedure ShowEmptyMethodsMenuItemClick(Sender: TObject);
|
|
procedure ShowUnusedUnitsMenuItemClick(Sender: TObject);
|
|
procedure FindOverloadsMenuItemClick(Sender: TObject);
|
|
procedure RunToClicked(Sender: TObject);
|
|
procedure ViewCallStackClick(Sender: TObject);
|
|
procedure EditorPropertiesClicked(Sender: TObject);
|
|
procedure LineEndingClicked(Sender: TObject);
|
|
procedure EncodingClicked(Sender: TObject);
|
|
procedure HighlighterClicked(Sender: TObject);
|
|
procedure FindDeclarationClicked(Sender: TObject);
|
|
procedure ProcedureJumpClicked(Sender: TObject);
|
|
procedure FindNextWordOccurrenceClicked(Sender: TObject);
|
|
procedure FindPrevWordOccurrenceClicked(Sender: TObject);
|
|
procedure FindInFilesClicked(Sender: TObject);
|
|
procedure MoveEditorLeftClicked(Sender: TObject);
|
|
procedure MoveEditorRightClicked(Sender: TObject);
|
|
procedure MoveEditorFirstClicked(Sender: TObject);
|
|
procedure MoveEditorLastClicked(Sender: TObject);
|
|
procedure NotebookPageChanged(Sender: TObject);
|
|
procedure NotebookShowTabHint(Sender: TObject; HintInfo: PHintInfo);
|
|
procedure OpenAtCursorClicked(Sender: TObject);
|
|
procedure ReadOnlyClicked(Sender: TObject);
|
|
procedure OnPopupMenuOpenPasFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenPPFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenPFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenLFMFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenDFMFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenLRSFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenSFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenFile(Sender: TObject);
|
|
procedure ShowUnitInfo(Sender: TObject);
|
|
procedure SrcPopUpMenuPopup(Sender: TObject);
|
|
procedure ToggleLineNumbersClicked(Sender: TObject);
|
|
procedure ToggleI18NForLFMClicked(Sender: TObject);
|
|
procedure InsertCharacter(const C: TUTF8Char);
|
|
procedure SrcEditMenuCopyToNewWindowClicked(Sender: TObject);
|
|
procedure SrcEditMenuCopyToExistingWindowClicked(Sender: TObject);
|
|
procedure SrcEditMenuMoveToNewWindowClicked(Sender: TObject);
|
|
procedure SrcEditMenuMoveToExistingWindowClicked(Sender: TObject);
|
|
procedure EditorLockClicked(Sender: TObject);
|
|
public
|
|
procedure DeleteBreakpointClicked(Sender: TObject);
|
|
procedure ToggleBreakpointClicked(Sender: TObject);
|
|
private
|
|
FManager: TSourceEditorManager;
|
|
FUpdateLock, FFocusLock: Integer;
|
|
FPageIndex: Integer;
|
|
fAutoFocusLock: integer;
|
|
FIncrementalSearchPos: TPoint; // last set position
|
|
fIncrementalSearchStartPos: TPoint; // position where to start searching
|
|
FIncrementalSearchStr, FIncrementalFoundStr: string;
|
|
FIncrementalSearchBackwards : Boolean;
|
|
FIncrementalSearchEditor: TSourceEditor; // editor with active search (MWE:shouldnt all FIncrementalSearch vars go to that editor ?)
|
|
FKeyStrokes: TSynEditKeyStrokes;
|
|
FLastCodeBuffer: TCodeBuffer;
|
|
FProcessingCommand: boolean;
|
|
FSourceEditorList: TList; // list of TSourceEditor
|
|
FHistoryList: TList; // list of TSourceEditor page order for when a window closes
|
|
private
|
|
FUpdateTabAndPageTimer: TTimer;
|
|
// PopupMenu
|
|
procedure BuildPopupMenu;
|
|
procedure AssignPopupMenu;
|
|
//forwarders to FNoteBook
|
|
function GetNoteBookPage(Index: Integer): TTabSheet;
|
|
function GetNotebookPages: TStrings;
|
|
function GetPageCount: Integer;
|
|
function GetPageIndex: Integer;
|
|
procedure SetPageIndex(const AValue: Integer);
|
|
|
|
procedure UpdateHighlightMenuItems;
|
|
procedure UpdateLineEndingMenuItems;
|
|
procedure UpdateEncodingMenuItems;
|
|
procedure RemoveUserDefinedMenuItems;
|
|
function AddUserDefinedPopupMenuItem(const NewCaption: string;
|
|
const NewEnabled: boolean;
|
|
const NewOnClick: TNotifyEvent): TIDEMenuItem;
|
|
procedure RemoveContextMenuItems;
|
|
function AddContextPopupMenuItem(const NewCaption: string;
|
|
const NewEnabled: boolean;
|
|
const NewOnClick: TNotifyEvent): TIDEMenuItem;
|
|
|
|
// Incremental Search
|
|
procedure UpdateActiveEditColors(AEditor: TSynEdit);
|
|
procedure SetIncrementalSearchStr(const AValue: string);
|
|
procedure IncrementalSearch(ANext, ABackward: Boolean);
|
|
procedure UpdatePageNames;
|
|
procedure UpdateProjectFiles;
|
|
|
|
property NoteBookPage[Index: Integer]: TTabSheet read GetNoteBookPage;
|
|
procedure NoteBookInsertPage(Index: Integer; const S: string);
|
|
procedure NoteBookDeletePage(APageIndex: Integer);
|
|
procedure UpdateTabsAndPageTitle;
|
|
procedure UpdateTabsAndPageTimeReached(Sender: TObject);
|
|
protected
|
|
function NoteBookIndexOfPage(APage: TTabSheet): Integer;
|
|
procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState;
|
|
var Accept: Boolean); override;
|
|
procedure DragCanceled; override;
|
|
protected
|
|
States: TSourceNotebookStates;
|
|
// hintwindow stuff
|
|
FHintWindow: THintWindow;
|
|
FMouseHintTimer: TIdleTimer;
|
|
|
|
procedure Activate; override;
|
|
procedure CreateNotebook;
|
|
function NewSE(Pagenum: Integer; NewPagenum: Integer = -1; ASharedEditor: TSourceEditor = nil): TSourceEditor;
|
|
procedure AcceptEditor(AnEditor: TSourceEditor);
|
|
procedure ReleaseEditor(AnEditor: TSourceEditor);
|
|
procedure EditorChanged(Sender: TObject);
|
|
procedure DoClose(var CloseAction: TCloseAction); override;
|
|
procedure DoShow; override;
|
|
|
|
protected
|
|
function GetActiveCompletionPlugin: TSourceEditorCompletionPlugin; override;
|
|
function GetCompletionPlugins(Index: integer): TSourceEditorCompletionPlugin; override;
|
|
function GetCompletionBoxPosition: integer; override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
|
|
procedure EditorMouseMove(Sender: TObject; Shift: TShiftstate;
|
|
X,Y: Integer);
|
|
procedure EditorMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftstate; X,Y: Integer);
|
|
function EditorGetIndent(Sender: TObject; Editor: TObject;
|
|
LogCaret, OldLogCaret: TPoint; FirstLinePos, LastLinePos: Integer;
|
|
Reason: TSynEditorCommand;
|
|
SetIndentProc: TSynBeautifierSetIndentProc): Boolean;
|
|
procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure EditorMouseWheel(Sender: TObject; Shift: TShiftState;
|
|
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
|
|
procedure NotebookMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X,Y: Integer);
|
|
procedure NotebookDragTabMove(Sender, Source: TObject;
|
|
OldIndex, NewIndex: Integer; CopyDrag: Boolean;
|
|
var Done: Boolean);
|
|
procedure NotebookCanDragTabMove(Sender, Source: TObject;
|
|
OldIndex, NewIndex: Integer; CopyDrag: Boolean;
|
|
var Accept: Boolean);
|
|
procedure NotebookDragOver(Sender, Source: TObject;
|
|
X,Y: Integer; State: TDragState; var Accept: Boolean);
|
|
procedure NotebookEndDrag(Sender, Target: TObject; X,Y: Integer);
|
|
// hintwindow stuff
|
|
procedure HintTimer(Sender: TObject);
|
|
procedure OnApplicationUserInput(Sender: TObject; Msg: Cardinal);
|
|
procedure ShowSynEditHint(const MousePos: TPoint);
|
|
|
|
procedure NextEditor;
|
|
procedure PrevEditor;
|
|
procedure MoveEditor(OldPageIndex, NewPageIndex: integer);
|
|
procedure MoveEditorLeft(CurrentPageIndex: integer);
|
|
procedure MoveEditorRight(CurrentPageIndex: integer);
|
|
procedure MoveActivePageLeft;
|
|
procedure MoveActivePageRight;
|
|
procedure MoveEditorFirst(CurrentPageIndex: integer);
|
|
procedure MoveEditorLast(CurrentPageIndex: integer);
|
|
procedure MoveActivePageFirst;
|
|
procedure MoveActivePageLast;
|
|
procedure GotoNextWindow(Backward: Boolean = False);
|
|
procedure GotoNextSharedEditor(Backward: Boolean = False);
|
|
procedure MoveEditorNextWindow(Backward: Boolean = False; Copy: Boolean = False);
|
|
procedure MoveEditor(OldPageIndex, NewWindowIndex, NewPageIndex: integer);
|
|
procedure CopyEditor(OldPageIndex, NewWindowIndex, NewPageIndex: integer; Focus: Boolean = False);
|
|
procedure ProcessParentCommand(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
|
|
var Handled: boolean);
|
|
procedure ParentCommandProcessed(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
|
|
var Handled: boolean);
|
|
|
|
function GetActiveEditor: TSourceEditorInterface; override;
|
|
procedure SetActiveEditor(const AValue: TSourceEditorInterface); override;
|
|
function GetItems(Index: integer): TSourceEditorInterface; override;
|
|
function GetEditors(Index:integer): TSourceEditor;
|
|
|
|
property Manager: TSourceEditorManager read FManager;
|
|
|
|
procedure KeyDownBeforeInterface(var Key: Word; Shift: TShiftState); override;
|
|
|
|
procedure BeginAutoFocusLock;
|
|
procedure EndAutoFocusLock;
|
|
|
|
protected
|
|
procedure CloseTabClicked(Sender: TObject);
|
|
procedure CloseClicked(Sender: TObject);
|
|
procedure CloseOtherPagesClicked(Sender: TObject);
|
|
procedure ToggleFormUnitClicked(Sender: TObject);
|
|
procedure ToggleObjectInspClicked(Sender: TObject);
|
|
|
|
// editor page history
|
|
procedure HistorySetMostRecent(APage: TTabSheet);
|
|
procedure HistoryAdd(APage: TTabSheet);
|
|
procedure HistoryRemove(APage: TTabSheet);
|
|
function HistoryGetTopPageIndex: Integer;
|
|
|
|
// incremental find
|
|
procedure BeginIncrementalFind;
|
|
procedure EndIncrementalFind;
|
|
property IncrementalSearchStr: string
|
|
read FIncrementalSearchStr write SetIncrementalSearchStr;
|
|
|
|
// hints
|
|
procedure ActivateHint(const ScreenPos: TPoint;
|
|
const BaseURL, TheHint: string);
|
|
procedure HideHint;
|
|
procedure StartShowCodeContext(JumpToError: boolean);
|
|
|
|
// paste and copy
|
|
procedure CutClicked(Sender: TObject);
|
|
procedure CopyClicked(Sender: TObject);
|
|
procedure PasteClicked(Sender: TObject);
|
|
procedure CopyFilenameClicked(Sender: TObject);
|
|
|
|
procedure ReloadEditorOptions;
|
|
procedure CheckFont;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
property Editors[Index:integer]:TSourceEditor read GetEditors; // !!! not ordered for PageIndex
|
|
function EditorCount: integer;
|
|
function IndexOfEditor(aEditor: TSourceEditorInterface): integer;
|
|
function Count: integer; override;
|
|
|
|
function FindSourceEditorWithPageIndex(APageIndex:integer):TSourceEditor;
|
|
function FindPageWithEditor(ASourceEditor: TSourceEditor):integer;
|
|
function FindSourceEditorWithEditorComponent(
|
|
EditorComp: TComponent): TSourceEditor;
|
|
function GetActiveSE: TSourceEditor; { $note deprecate and use SetActiveEditor}
|
|
procedure CheckCurrentCodeBufferChanged;
|
|
function IndexOfEditorInShareWith(AnOtherEditor: TSourceEditor): Integer;
|
|
|
|
procedure UpdateStatusBar;
|
|
procedure ClearErrorLines; override;
|
|
procedure ClearExecutionLines;
|
|
procedure ClearExecutionMarks;
|
|
|
|
// new, close, focus
|
|
function NewFile(const NewShortName: String; ASource: TCodeBuffer;
|
|
FocusIt: boolean; AShareEditor: TSourceEditor = nil): TSourceEditor;
|
|
procedure CloseFile(APageIndex:integer);
|
|
procedure FocusEditor;
|
|
|
|
public
|
|
function GetEditorControlSettings(EditControl: TControl): boolean; override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function GetHighlighterSettings(Highlighter: TObject): boolean; override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
|
|
procedure DeactivateCompletionForm; override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
function CompletionPluginCount: integer; override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
procedure RegisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
procedure UnregisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
|
|
public
|
|
function GetCapabilities: TNoteBookCapabilities;
|
|
procedure IncUpdateLock;
|
|
procedure DecUpdateLock;
|
|
|
|
// forwarders to the FNotebook
|
|
property PageIndex: Integer read GetPageIndex write SetPageIndex;
|
|
property PageCount: Integer read GetPageCount;
|
|
property NotebookPages: TStrings read GetNotebookPages;
|
|
end;
|
|
|
|
{ TSourceEditorManagerBase }
|
|
(* Implement all Methods with the Interface types *)
|
|
|
|
TSourceEditorManagerBase = class(TSourceEditorManagerInterface)
|
|
private
|
|
FActiveWindow: TSourceNotebook;
|
|
FSourceWindowList: TFPList;
|
|
FSourceWindowByFocusList: TFPList;
|
|
FUpdateLock: Integer;
|
|
FActiveEditorLock: Integer;
|
|
FShowWindowOnTop: Boolean;
|
|
FShowWindowOnTopFocus: Boolean;
|
|
procedure FreeSourceWindows;
|
|
function GetActiveSourceWindowIndex: integer;
|
|
function GetSourceWindowByLastFocused(Index: Integer): TSourceEditorWindowInterface;
|
|
procedure SetActiveSourceWindowIndex(const AValue: integer);
|
|
protected
|
|
fProducers: TFPList; // list of TSourceMarklingProducer
|
|
FChangeNotifyLists: Array [TsemChangeReason] of TMethodList;
|
|
function GetActiveSourceWindow: TSourceEditorWindowInterface; override;
|
|
procedure SetActiveSourceWindow(const AValue: TSourceEditorWindowInterface); override;
|
|
function GetSourceWindows(Index: integer): TSourceEditorWindowInterface; override;
|
|
procedure DoWindowFocused(AWindow: TSourceNotebook); // Includes Focus to ChildControl (aka Activated)
|
|
function GetActiveEditor: TSourceEditorInterface; override;
|
|
procedure SetActiveEditor(const AValue: TSourceEditorInterface); override;
|
|
procedure DoActiveEditorChanged;
|
|
procedure DoEditorStatusChanged(AEditor: TSourceEditor);
|
|
function GetSourceEditors(Index: integer): TSourceEditorInterface; override;
|
|
function GetUniqueSourceEditors(Index: integer): TSourceEditorInterface; override;
|
|
function GetMarklingProducers(Index: integer): TSourceMarklingProducer; override;
|
|
public
|
|
// Windows
|
|
function SourceWindowWithEditor(const AEditor: TSourceEditorInterface): TSourceEditorWindowInterface;
|
|
override;
|
|
function SourceWindowCount: integer; override;
|
|
function IndexOfSourceWindow(AWindow: TSourceEditorWindowInterface): integer;
|
|
property ActiveSourceWindowIndex: integer
|
|
read GetActiveSourceWindowIndex write SetActiveSourceWindowIndex;
|
|
function IndexOfSourceWindowByLastFocused(AWindow: TSourceEditorWindowInterface): integer;
|
|
property SourceWindowByLastFocused[Index: Integer]: TSourceEditorWindowInterface
|
|
read GetSourceWindowByLastFocused;
|
|
// Editors
|
|
function SourceEditorIntfWithFilename(const Filename: string): TSourceEditorInterface;
|
|
override;
|
|
function SourceEditorCount: integer; override;
|
|
function UniqueSourceEditorCount: integer; override;
|
|
// Settings
|
|
function GetEditorControlSettings(EditControl: TControl): boolean; override;
|
|
function GetHighlighterSettings(Highlighter: TObject): boolean; override;
|
|
private
|
|
// Completion Plugins
|
|
FCompletionPlugins: TFPList;
|
|
FDefaultCompletionForm: TSourceEditCompletion;
|
|
FActiveCompletionPlugin: TSourceEditorCompletionPlugin;
|
|
function GetDefaultCompletionForm: TSourceEditCompletion;
|
|
procedure FreeCompletionPlugins;
|
|
protected
|
|
function GetActiveCompletionPlugin: TSourceEditorCompletionPlugin; override;
|
|
function GetCompletionBoxPosition: integer; override;
|
|
function GetCompletionPlugins(Index: integer): TSourceEditorCompletionPlugin; override;
|
|
function FindIdentCompletionPlugin(SrcEdit: TSourceEditor; JumpToError: boolean;
|
|
var s: string; var BoxX, BoxY: integer;
|
|
var UseWordCompletion: boolean): boolean;
|
|
property DefaultCompletionForm: TSourceEditCompletion
|
|
read GetDefaultCompletionForm;
|
|
public
|
|
// Completion Plugins
|
|
function CompletionPluginCount: integer; override;
|
|
procedure DeactivateCompletionForm; override;
|
|
procedure RegisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
|
|
procedure UnregisterCompletionPlugin(Plugin: TSourceEditorCompletionPlugin); override;
|
|
protected
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure RegisterChangeEvent(AReason: TsemChangeReason; AHandler: TNotifyEvent); override;
|
|
procedure UnRegisterChangeEvent(AReason: TsemChangeReason; AHandler: TNotifyEvent); override;
|
|
// producers
|
|
function MarklingProducerCount: integer; override;
|
|
procedure RegisterMarklingProducer(aProducer: TSourceMarklingProducer); override;
|
|
procedure UnregisterMarklingProducer(aProducer: TSourceMarklingProducer); override;
|
|
procedure InvalidateMarklingsOfAllFiles(aProducer: TSourceMarklingProducer); override;
|
|
procedure InvalidateMarklings(aProducer: TSourceMarklingProducer; aFilename: string); override;
|
|
public
|
|
procedure IncUpdateLock;
|
|
procedure DecUpdateLock;
|
|
procedure ShowActiveWindowOnTop(Focus: Boolean = False);
|
|
private
|
|
FOnCurrentCodeBufferChanged: TNotifyEvent;
|
|
public
|
|
property OnCurrentCodeBufferChanged: TNotifyEvent
|
|
read FOnCurrentCodeBufferChanged write FOnCurrentCodeBufferChanged;
|
|
end;
|
|
|
|
{ TSourceEditorManager }
|
|
(* Reintroduce all Methods with the final types *)
|
|
|
|
TSourceEditorManager = class(TSourceEditorManagerBase)
|
|
private
|
|
function GetActiveSourceNotebook: TSourceNotebook;
|
|
function GetActiveSrcEditor: TSourceEditor;
|
|
function GetSourceEditorsByPage(WindowIndex, PageIndex: integer
|
|
): TSourceEditor;
|
|
function GetSourceNbByLastFocused(Index: Integer): TSourceNotebook;
|
|
function GetSrcEditors(Index: integer): TSourceEditor;
|
|
procedure SetActiveSourceNotebook(const AValue: TSourceNotebook);
|
|
function GetSourceNotebook(Index: integer): TSourceNotebook;
|
|
procedure SetActiveSrcEditor(const AValue: TSourceEditor);
|
|
public
|
|
// Windows
|
|
function SourceWindowWithEditor(const AEditor: TSourceEditorInterface): TSourceNotebook;
|
|
reintroduce;
|
|
property SourceWindows[Index: integer]: TSourceNotebook read GetSourceNotebook; // reintroduce
|
|
property ActiveSourceWindow: TSourceNotebook
|
|
read GetActiveSourceNotebook write SetActiveSourceNotebook; // reintroduce
|
|
function ActiveOrNewSourceWindow: TSourceNotebook;
|
|
function NewSourceWindow: TSourceNotebook;
|
|
procedure CreateSourceWindow(Sender: TObject; aFormName: string;
|
|
var AForm: TCustomForm; DoDisableAutoSizing: boolean);
|
|
procedure GetDefaultLayout(Sender: TObject; aFormName: string;
|
|
out aBounds: TRect; out DockSibling: string; out DockAlign: TAlign);
|
|
function SourceWindowWithPage(const APage: TTabSheet): TSourceNotebook;
|
|
property SourceWindowByLastFocused[Index: Integer]: TSourceNotebook
|
|
read GetSourceNbByLastFocused;
|
|
// Editors
|
|
function SourceEditorCount: integer; override;
|
|
function GetActiveSE: TSourceEditor; { $note deprecate and use ActiveEditor}
|
|
property ActiveEditor: TSourceEditor read GetActiveSrcEditor write SetActiveSrcEditor; // reintroduced
|
|
property SourceEditors[Index: integer]: TSourceEditor read GetSrcEditors; // reintroduced
|
|
property SourceEditorsByPage[WindowIndex, PageIndex: integer]: TSourceEditor
|
|
read GetSourceEditorsByPage;
|
|
function SourceEditorIntfWithFilename(const Filename: string): TSourceEditor; reintroduce;
|
|
function FindSourceEditorWithEditorComponent(EditorComp: TComponent): TSourceEditor; // With SynEdit
|
|
protected
|
|
procedure NewEditorCreated(AEditor: TSourceEditor);
|
|
procedure EditorRemoved(AEditor: TSourceEditor);
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure RemoveWindow(AWindow: TSourceNotebook);
|
|
public
|
|
// Forward to all windows
|
|
procedure ClearErrorLines; override;
|
|
procedure ClearExecutionLines;
|
|
procedure ClearExecutionMarks;
|
|
procedure FillExecutionMarks;
|
|
procedure ReloadEditorOptions;
|
|
// find / replace text
|
|
procedure FindClicked(Sender: TObject);
|
|
procedure FindNextClicked(Sender: TObject);
|
|
procedure FindPreviousClicked(Sender: TObject);
|
|
procedure ReplaceClicked(Sender: TObject);
|
|
procedure IncrementalFindClicked(Sender: TObject);
|
|
procedure GotoLineClicked(Sender: TObject);
|
|
procedure JumpBackClicked(Sender: TObject);
|
|
procedure JumpForwardClicked(Sender: TObject);
|
|
procedure AddJumpPointClicked(Sender: TObject);
|
|
procedure DeleteLastJumpPointClicked(Sender: TObject);
|
|
procedure ViewJumpHistoryClicked(Sender: TObject);
|
|
protected
|
|
// Bookmarks
|
|
procedure BookMarkSetFreeClicked(Sender: TObject);
|
|
procedure BookMarkToggleClicked(Sender: TObject);
|
|
procedure BookMarkGotoClicked(Sender: TObject);
|
|
public
|
|
procedure BookMarkNextClicked(Sender: TObject);
|
|
procedure BookMarkPrevClicked(Sender: TObject);
|
|
protected
|
|
// macros
|
|
function MacroFuncCol(const s:string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
function MacroFuncRow(const s:string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
function MacroFuncEdFile(const s:string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
function MacroFuncCurToken(const s:string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
function MacroFuncPrompt(const s:string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
public
|
|
procedure InitMacros(AMacroList: TTransferMacroList);
|
|
procedure SetupShortCuts;
|
|
|
|
function FindUniquePageName(FileName:string; IgnoreEditor: TSourceEditor):string;
|
|
function SomethingModified: boolean;
|
|
procedure HideHint;
|
|
procedure OnIdle(Sender: TObject; var Done: Boolean);
|
|
procedure LockAllEditorsInSourceChangeCache;
|
|
procedure UnlockAllEditorsInSourceChangeCache;
|
|
procedure CloseFile(AEditor: TSourceEditorInterface);
|
|
// history jumping
|
|
procedure HistoryJump(Sender: TObject; CloseAction: TJumpHistoryAction);
|
|
private
|
|
FCodeTemplateModul: TSynEditAutoComplete;
|
|
FGotoDialog: TfrmGoto;
|
|
procedure OnFilesDroping(Sender: TObject; const FileNames: Array of String);
|
|
procedure OnCodeTemplateTokenNotFound(Sender: TObject; AToken: string;
|
|
AnEditor: TCustomSynEdit; var Index:integer);
|
|
procedure OnCodeTemplateExecuteCompletion(
|
|
ASynAutoComplete: TCustomSynAutoComplete;
|
|
Index: integer);
|
|
protected
|
|
procedure OnWordCompletionGetSource(var Source: TStrings; SourceIndex: integer);
|
|
procedure OnSourceCompletionTimer(Sender: TObject);
|
|
// marks
|
|
function OnSourceMarksGetSourceEditorID(ASrcEdit: TSourceEditorInterface): TObject;
|
|
function OnSourceMarksGetFilename(ASourceEditor: TObject): string;
|
|
procedure OnSourceMarksAction(AMark: TSourceMark; AAction: TMarksAction);
|
|
property CodeTemplateModul: TSynEditAutoComplete
|
|
read FCodeTemplateModul write FCodeTemplateModul;
|
|
// goto dialog
|
|
function GotoDialog: TfrmGoto;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function CreateNewWindow(Activate: Boolean= False;
|
|
DoDisableAutoSizing: boolean = False): TSourceNotebook;
|
|
private
|
|
FOnAddJumpPoint: TOnAddJumpPoint;
|
|
FOnClearBookmark: TPlaceBookMarkEvent;
|
|
FOnClickLink: TMouseEvent;
|
|
FOnCloseClicked: TOnCloseSrcEditor;
|
|
FOnDeleteLastJumpPoint: TNotifyEvent;
|
|
FOnEditorMoved: TNotifyEvent;
|
|
FOnEditorPropertiesClicked: TNotifyEvent;
|
|
FOnFindDeclarationClicked: TNotifyEvent;
|
|
FOnGetIndent: TOnGetIndentEvent;
|
|
FOnGotoBookmark: TBookMarkActionEvent;
|
|
FOnInitIdentCompletion: TOnInitIdentCompletion;
|
|
FOnJumpToHistoryPoint: TOnJumpToHistoryPoint;
|
|
FOnMouseLink: TSynMouseLinkEvent;
|
|
FOnNoteBookCloseQuery: TCloseEvent;
|
|
FOnOpenFileAtCursorClicked: TNotifyEvent;
|
|
FOnPlaceMark: TPlaceBookMarkEvent;
|
|
FOnPopupMenu: TSrcEditPopupMenuEvent;
|
|
FOnProcessUserCommand: TOnProcessUserCommand;
|
|
fOnReadOnlyChanged: TNotifyEvent;
|
|
FOnSetBookmark: TBookMarkActionEvent;
|
|
FOnShowCodeContext: TOnShowCodeContext;
|
|
FOnShowHintForSource: TOnShowHintForSource;
|
|
FOnShowUnitInfo: TNotifyEvent;
|
|
FOnToggleFormUnitClicked: TNotifyEvent;
|
|
FOnToggleObjectInspClicked: TNotifyEvent;
|
|
FOnUserCommandProcessed: TOnUserCommandProcessed;
|
|
FOnViewJumpHistory: TNotifyEvent;
|
|
public
|
|
property OnAddJumpPoint: TOnAddJumpPoint
|
|
read FOnAddJumpPoint write FOnAddJumpPoint;
|
|
property OnCloseClicked: TOnCloseSrcEditor
|
|
read FOnCloseClicked write FOnCloseClicked;
|
|
property OnClickLink: TMouseEvent read FOnClickLink write FOnClickLink;
|
|
property OnMouseLink: TSynMouseLinkEvent read FOnMouseLink write FOnMouseLink;
|
|
property OnGetIndent: TOnGetIndentEvent
|
|
read FOnGetIndent write FOnGetIndent;
|
|
property OnDeleteLastJumpPoint: TNotifyEvent
|
|
read FOnDeleteLastJumpPoint write FOnDeleteLastJumpPoint;
|
|
property OnEditorMoved: TNotifyEvent
|
|
read FOnEditorMoved write FOnEditorMoved;
|
|
property OnEditorPropertiesClicked: TNotifyEvent
|
|
read FOnEditorPropertiesClicked write FOnEditorPropertiesClicked;
|
|
property OnFindDeclarationClicked: TNotifyEvent
|
|
read FOnFindDeclarationClicked write FOnFindDeclarationClicked;
|
|
property OnInitIdentCompletion: TOnInitIdentCompletion
|
|
read FOnInitIdentCompletion write FOnInitIdentCompletion;
|
|
property OnShowCodeContext: TOnShowCodeContext
|
|
read FOnShowCodeContext write FOnShowCodeContext;
|
|
property OnJumpToHistoryPoint: TOnJumpToHistoryPoint
|
|
read FOnJumpToHistoryPoint write FOnJumpToHistoryPoint;
|
|
property OnPlaceBookmark: TPlaceBookMarkEvent // Bookmark was placed by SynEdit
|
|
read FOnPlaceMark write FOnPlaceMark;
|
|
property OnClearBookmark: TPlaceBookMarkEvent // Bookmark was cleared by SynEdit
|
|
read FOnClearBookmark write FOnClearBookmark;
|
|
property OnSetBookmark: TBookMarkActionEvent // request to set a Bookmark
|
|
read FOnSetBookmark write FOnSetBookmark;
|
|
property OnGotoBookmark: TBookMarkActionEvent // request to go to a Bookmark
|
|
read FOnGotoBookmark write FOnGotoBookmark;
|
|
property OnOpenFileAtCursorClicked: TNotifyEvent
|
|
read FOnOpenFileAtCursorClicked write FOnOpenFileAtCursorClicked;
|
|
property OnProcessUserCommand: TOnProcessUserCommand
|
|
read FOnProcessUserCommand write FOnProcessUserCommand;
|
|
property OnUserCommandProcessed: TOnUserCommandProcessed
|
|
read FOnUserCommandProcessed write FOnUserCommandProcessed;
|
|
property OnReadOnlyChanged: TNotifyEvent
|
|
read fOnReadOnlyChanged write fOnReadOnlyChanged;
|
|
property OnShowHintForSource: TOnShowHintForSource
|
|
read FOnShowHintForSource write FOnShowHintForSource;
|
|
property OnShowUnitInfo: TNotifyEvent
|
|
read FOnShowUnitInfo write FOnShowUnitInfo;
|
|
property OnToggleFormUnitClicked: TNotifyEvent
|
|
read FOnToggleFormUnitClicked write FOnToggleFormUnitClicked;
|
|
property OnToggleObjectInspClicked: TNotifyEvent
|
|
read FOnToggleObjectInspClicked write FOnToggleObjectInspClicked;
|
|
property OnViewJumpHistory: TNotifyEvent
|
|
read FOnViewJumpHistory write FOnViewJumpHistory;
|
|
property OnPopupMenu: TSrcEditPopupMenuEvent read FOnPopupMenu write FOnPopupMenu;
|
|
property OnNoteBookCloseQuery: TCloseEvent
|
|
read FOnNoteBookCloseQuery write FOnNoteBookCloseQuery;
|
|
end;
|
|
|
|
function SourceNotebook: TSourceNotebook;
|
|
deprecated {$IFDEF VER2_5}'use SourceEditorManager'{$ENDIF}; // deprecated in 0.9.29 March 2010
|
|
|
|
function SourceEditorManager: TSourceEditorManager;
|
|
|
|
|
|
//=============================================================================
|
|
|
|
const
|
|
SourceEditorMenuRootName = 'SourceEditor';
|
|
|
|
var
|
|
SrcEditMenuFindDeclaration: TIDEMenuCommand;
|
|
// finding / jumping
|
|
SrcEditMenuProcedureJump: TIDEMenuCommand;
|
|
SrcEditMenuFindNextWordOccurrence: TIDEMenuCommand;
|
|
SrcEditMenuFindPrevWordOccurrence: TIDEMenuCommand;
|
|
SrcEditMenuFindinFiles: TIDEMenuCommand;
|
|
// open file
|
|
SrcEditMenuOpenFileAtCursor: TIDEMenuCommand;
|
|
SrcEditMenuClosePage: TIDEMenuCommand;
|
|
SrcEditMenuCloseOtherPages: TIDEMenuCommand;
|
|
SrcEditMenuCut: TIDEMenuCommand;
|
|
SrcEditMenuCopy: TIDEMenuCommand;
|
|
SrcEditMenuPaste: TIDEMenuCommand;
|
|
SrcEditMenuCopyFilename: TIDEMenuCommand;
|
|
// bookmarks
|
|
SrcEditMenuNextBookmark: TIDEMenuCommand;
|
|
SrcEditMenuPrevBookmark: TIDEMenuCommand;
|
|
SrcEditMenuSetFreeBookmark: TIDEMenuCommand;
|
|
// debugging
|
|
SrcEditMenuToggleBreakpoint: TIDEMenuCommand;
|
|
SrcEditMenuRunToCursor: TIDEMenuCommand;
|
|
SrcEditMenuEvaluateModify: TIDEMenuCommand;
|
|
SrcEditMenuAddWatchAtCursor: TIDEMenuCommand;
|
|
SrcEditMenuInspect: TIDEMenuCommand;
|
|
SrcEditMenuViewCallStack: TIDEMenuCommand;
|
|
// refactoring
|
|
SrcEditMenuCompleteCode: TIDEMenuCommand;
|
|
SrcEditMenuEncloseSelection: TIDEMenuCommand;
|
|
SrcEditMenuRenameIdentifier: TIDEMenuCommand;
|
|
SrcEditMenuFindIdentifierReferences: TIDEMenuCommand;
|
|
SrcEditMenuExtractProc: TIDEMenuCommand;
|
|
SrcEditMenuInvertAssignment: TIDEMenuCommand;
|
|
SrcEditMenuShowAbstractMethods: TIDEMenuCommand;
|
|
SrcEditMenuShowEmptyMethods: TIDEMenuCommand;
|
|
SrcEditMenuShowUnusedUnits: TIDEMenuCommand;
|
|
SrcEditMenuFindOverloads: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorLeft: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorRight: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorFirst: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorLast: TIDEMenuCommand;
|
|
SrcEditMenuReadOnly: TIDEMenuCommand;
|
|
SrcEditMenuShowLineNumbers: TIDEMenuCommand;
|
|
SrcEditMenuDisableI18NForLFM: TIDEMenuCommand;
|
|
SrcEditMenuShowUnitInfo: TIDEMenuCommand;
|
|
SrcEditMenuEditorProperties: TIDEMenuCommand;
|
|
{$IFnDEF SingleSrcWindow}
|
|
// Multi Window
|
|
SrcEditMenuMoveToNewWindow: TIDEMenuCommand;
|
|
SrcEditMenuMoveToOtherWindow: TIDEMenuSection;
|
|
SrcEditMenuMoveToOtherWindowNew: TIDEMenuCommand;
|
|
SrcEditMenuMoveToOtherWindowList: TIDEMenuSection;
|
|
SrcEditMenuCopyToNewWindow: TIDEMenuCommand;
|
|
SrcEditMenuCopyToOtherWindow: TIDEMenuSection;
|
|
SrcEditMenuCopyToOtherWindowNew: TIDEMenuCommand;
|
|
SrcEditMenuCopyToOtherWindowList: TIDEMenuSection;
|
|
// EditorLocks
|
|
SrcEditMenuEditorLock: TIDEMenuCommand;
|
|
{$ENDIF}
|
|
|
|
|
|
procedure RegisterStandardSourceEditorMenuItems;
|
|
|
|
var
|
|
Highlighters: array[TLazSyntaxHighlighter] of TSynCustomHighlighter;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
const
|
|
(* SoftCenter are th visible Lines in the Editor where the caret can be locateted,
|
|
without CenterCursor adjusting the topline.
|
|
SoftCenter is defined by the amount of lines on the top/bottom of fthe editor,
|
|
which are *not* part of it.
|
|
*)
|
|
SoftCenterFactor = 5; // One fifth of the "LinesInWindow"on each side (top/bottom)
|
|
SoftCenterMinimum = 1;
|
|
SoftCenterMaximum = 8;
|
|
|
|
var
|
|
SourceCompletionTimer: TIdleTimer = nil;
|
|
SourceCompletionCaretXY: TPoint;
|
|
AWordCompletion: TWordCompletion = nil;
|
|
|
|
function SourceNotebook: TSourceNotebook;
|
|
begin
|
|
if SourceEditorManager = nil then
|
|
Result := nil
|
|
else
|
|
Result := SourceEditorManager.ActiveOrNewSourceWindow;
|
|
end;
|
|
|
|
function SourceEditorManager: TSourceEditorManager;
|
|
begin
|
|
Result := TSourceEditorManager(SourceEditorManagerIntf);
|
|
end;
|
|
|
|
procedure RegisterStandardSourceEditorMenuItems;
|
|
var
|
|
AParent: TIDEMenuSection;
|
|
I: Integer;
|
|
begin
|
|
SourceEditorMenuRoot:=RegisterIDEMenuRoot(SourceEditorMenuRootName);
|
|
AParent:=SourceEditorMenuRoot;
|
|
|
|
// register the first dynamic section for often used context sensitive stuff
|
|
SrcEditMenuSectionFirstDynamic:=RegisterIDEMenuSection(AParent,
|
|
'First dynamic section');
|
|
// register the first static section
|
|
SrcEditMenuSectionFirstStatic:=RegisterIDEMenuSection(AParent,
|
|
'First static section');
|
|
AParent:=SrcEditMenuSectionFirstStatic;
|
|
SrcEditMenuFindDeclaration:=RegisterIDEMenuCommand(AParent,
|
|
'Find Declaration',uemFindDeclaration);
|
|
// register the sub menu Find
|
|
SrcEditSubMenuFind:=RegisterIDESubMenu(AParent, 'Find section', lisMenuFind
|
|
);
|
|
AParent:=SrcEditSubMenuFind;
|
|
SrcEditMenuProcedureJump:=RegisterIDEMenuCommand(AParent,'Procedure Jump',
|
|
uemProcedureJump);
|
|
SrcEditMenuFindNextWordOccurrence:=RegisterIDEMenuCommand(AParent,
|
|
'Find next word occurrence', srkmecFindNextWordOccurrence, nil, nil, nil, 'menu_search_find_next');
|
|
SrcEditMenuFindPrevWordOccurrence:=RegisterIDEMenuCommand(AParent,
|
|
'Find previous word occurrence', srkmecFindPrevWordOccurrence, nil, nil, nil, 'menu_search_find_previous');
|
|
SrcEditMenuFindInFiles:=RegisterIDEMenuCommand(AParent,
|
|
'Find in files', srkmecFindInFiles, nil, nil, nil, 'menu_search_files');
|
|
SrcEditMenuSectionPages := RegisterIDEMenuSection(SourceEditorMenuRoot,
|
|
'Pages');
|
|
|
|
SrcEditMenuClosePage := RegisterIDEMenuCommand(SrcEditMenuSectionPages,
|
|
'Close Page',uemClosePage, nil, nil, nil, 'menu_close');
|
|
SrcEditMenuCloseOtherPages := RegisterIDEMenuCommand(SrcEditMenuSectionPages,
|
|
'Close All Other Pages',uemCloseOtherPages, nil, nil, nil);
|
|
|
|
{$IFnDEF SingleSrcWindow}
|
|
// Lock Editor
|
|
SrcEditMenuEditorLock := RegisterIDEMenuCommand(SrcEditMenuSectionPages,
|
|
'LockEditor', uemLockPage);
|
|
SrcEditMenuEditorLock.ShowAlwaysCheckable := True;
|
|
// Move to other Window
|
|
SrcEditMenuMoveToNewWindow := RegisterIDEMenuCommand(SrcEditMenuSectionPages,
|
|
'MoveToNewWindow', uemMoveToNewWindow);
|
|
SrcEditMenuMoveToOtherWindow := RegisterIDESubMenu(SrcEditMenuSectionPages,
|
|
'MoveToOtherWindow', uemMoveToOtherWindow);
|
|
SrcEditMenuMoveToOtherWindowNew := RegisterIDEMenuCommand(SrcEditMenuMoveToOtherWindow,
|
|
'MoveToOtherWindowNew', uemMoveToOtherWindowNew);
|
|
SrcEditMenuMoveToOtherWindowList := RegisterIDEMenuSection(SrcEditMenuMoveToOtherWindow,
|
|
'MoveToOtherWindowList Section');
|
|
|
|
SrcEditMenuCopyToNewWindow := RegisterIDEMenuCommand(SrcEditMenuSectionPages,
|
|
'CopyToNewWindow', uemCopyToNewWindow);
|
|
SrcEditMenuCopyToOtherWindow := RegisterIDESubMenu(SrcEditMenuSectionPages,
|
|
'CopyToOtherWindow', uemCopyToOtherWindow);
|
|
SrcEditMenuCopyToOtherWindowNew := RegisterIDEMenuCommand(SrcEditMenuCopyToOtherWindow,
|
|
'CopyToOtherWindowNew', uemCopyToOtherWindowNew);
|
|
SrcEditMenuCopyToOtherWindowList := RegisterIDEMenuSection(SrcEditMenuCopyToOtherWindow,
|
|
'CopyToOtherWindowList Section');
|
|
{$ENDIF}
|
|
// register the Move Page sub menu
|
|
SrcEditSubMenuMovePage:=RegisterIDESubMenu(SrcEditMenuSectionPages,
|
|
'Move Page ...', lisMovePage);
|
|
AParent:=SrcEditSubMenuMovePage;
|
|
SrcEditMenuMoveEditorLeft:=RegisterIDEMenuCommand(AParent,'MoveEditorLeft',
|
|
uemMovePageLeft);
|
|
SrcEditMenuMoveEditorRight:=RegisterIDEMenuCommand(AParent,'MoveEditorRight',
|
|
uemMovePageRight);
|
|
SrcEditMenuMoveEditorFirst:=RegisterIDEMenuCommand(AParent,'MoveEditorLeftmost',
|
|
uemMovePageLeftmost);
|
|
SrcEditMenuMoveEditorLast:=RegisterIDEMenuCommand(AParent,'MoveEditorRightmost',
|
|
uemMovePageRightmost);
|
|
|
|
// register the sub menu Open File
|
|
SrcEditSubMenuOpenFile:=RegisterIDESubMenu(SrcEditMenuSectionPages,
|
|
'Open File ...', lisOpenFile2);
|
|
AParent:=SrcEditSubMenuOpenFile;
|
|
SrcEditMenuOpenFileAtCursor:=RegisterIDEMenuCommand(AParent,
|
|
'Open File At Cursor',uemOpenFileAtCursor, nil, nil, nil, 'menu_search_openfile_atcursor');
|
|
// register the File Specific dynamic section
|
|
SrcEditMenuSectionFileDynamic:=RegisterIDEMenuSection(AParent,
|
|
'File dynamic section');
|
|
|
|
// register the Flags section
|
|
SrcEditSubMenuFlags:=RegisterIDESubMenu(SrcEditMenuSectionPages,
|
|
'Flags section', lisFileSettings);
|
|
AParent:=SrcEditSubMenuFlags;
|
|
SrcEditMenuReadOnly:=RegisterIDEMenuCommand(AParent,'ReadOnly',uemReadOnly);
|
|
SrcEditMenuReadOnly.ShowAlwaysCheckable:=true;
|
|
SrcEditMenuShowLineNumbers:=RegisterIDEMenuCommand(AParent,
|
|
'ShowLineNumbers',uemShowLineNumbers);
|
|
SrcEditMenuShowLineNumbers.ShowAlwaysCheckable:=true;
|
|
SrcEditMenuDisableI18NForLFM:=RegisterIDEMenuCommand(AParent,
|
|
'DisableI18NForLFM',lisDisableI18NForLFM);
|
|
SrcEditMenuShowUnitInfo:=RegisterIDEMenuCommand(AParent,'ShowUnitInfo',
|
|
uemShowUnitInfo);
|
|
SrcEditSubMenuHighlighter:=RegisterIDESubMenu(AParent,'Highlighter',
|
|
uemHighlighter);
|
|
SrcEditSubMenuEncoding:=RegisterIDESubMenu(AParent,'Encoding',
|
|
uemEncoding);
|
|
SrcEditSubMenuLineEnding:=RegisterIDESubMenu(AParent,'LineEnding',
|
|
uemLineEnding);
|
|
|
|
// register the Clipboard section
|
|
SrcEditMenuSectionClipboard:=RegisterIDEMenuSection(SourceEditorMenuRoot,
|
|
'Clipboard');
|
|
AParent:=SrcEditMenuSectionClipboard;
|
|
SrcEditMenuCut:=RegisterIDEMenuCommand(AParent,'Cut',uemCut, nil, nil, nil, 'laz_cut');
|
|
SrcEditMenuCopy:=RegisterIDEMenuCommand(AParent,'Copy',uemCopy, nil, nil, nil, 'laz_copy');
|
|
SrcEditMenuPaste:=RegisterIDEMenuCommand(AParent,'Paste',uemPaste, nil, nil, nil, 'laz_paste');
|
|
SrcEditMenuCopyFilename:=RegisterIDEMenuCommand(AParent,'Copy filename',
|
|
uemCopyFilename);
|
|
|
|
// register the Marks section
|
|
SrcEditMenuSectionMarks:=RegisterIDEMenuSection(SourceEditorMenuRoot,
|
|
'Marks section');
|
|
// register the Goto Bookmarks Submenu
|
|
SrcEditSubMenuGotoBookmarks:=RegisterIDESubMenu(SrcEditMenuSectionMarks,
|
|
'Goto bookmarks',uemGotoBookmark);
|
|
AParent:=SrcEditSubMenuGotoBookmarks;
|
|
for I := 0 to 9 do
|
|
RegisterIDEMenuCommand(AParent,'GotoBookmark'+IntToStr(I),
|
|
uemBookmarkN+IntToStr(i));
|
|
SrcEditMenuNextBookmark:=RegisterIDEMenuCommand(AParent,
|
|
'Goto next Bookmark',uemNextBookmark, nil, nil, nil, 'menu_search_next_bookmark');
|
|
SrcEditMenuPrevBookmark:=RegisterIDEMenuCommand(AParent,
|
|
'Goto previous Bookmark',uemPrevBookmark, nil, nil, nil, 'menu_search_previous_bookmark');
|
|
|
|
// register the Set Bookmarks Submenu
|
|
SrcEditSubMenuToggleBookmarks:=RegisterIDESubMenu(SrcEditMenuSectionMarks,
|
|
'Toggle bookmarks',uemToggleBookmark);
|
|
AParent:=SrcEditSubMenuToggleBookmarks;
|
|
for I := 0 to 9 do
|
|
RegisterIDEMenuCommand(AParent,'ToggleBookmark'+IntToStr(I),
|
|
uemBookmarkN+IntToStr(i));
|
|
SrcEditMenuSetFreeBookmark:=RegisterIDEMenuCommand(AParent,
|
|
'Set a free Bookmark',uemSetFreeBookmark);
|
|
|
|
// register the Debug section
|
|
SrcEditMenuSectionDebug:=RegisterIDEMenuSection(SourceEditorMenuRoot,
|
|
'Debug section');
|
|
// register the Debug submenu
|
|
SrcEditSubMenuDebug:=RegisterIDESubMenu(SrcEditMenuSectionDebug,
|
|
'Debug', uemDebugWord, nil, nil, 'debugger');
|
|
AParent:=SrcEditSubMenuDebug;
|
|
// register the Debug submenu items
|
|
SrcEditMenuToggleBreakpoint:=RegisterIDEMenuCommand(AParent,'Toggle Breakpoint',
|
|
uemToggleBreakpoint);
|
|
SrcEditMenuEvaluateModify:=RegisterIDEMenuCommand(AParent,'Evaluate/Modify...',
|
|
uemEvaluateModify, nil, nil, nil,'debugger_modify');
|
|
SrcEditMenuEvaluateModify.Enabled:=False;
|
|
SrcEditMenuAddWatchAtCursor:=RegisterIDEMenuCommand(AParent,
|
|
'Add Watch at Cursor',uemAddWatchAtCursor);
|
|
SrcEditMenuInspect:=RegisterIDEMenuCommand(AParent,
|
|
'Inspect...', uemInspect, nil, nil, nil, 'debugger_inspect');
|
|
SrcEditMenuInspect.Enabled:=False;
|
|
SrcEditMenuRunToCursor:=RegisterIDEMenuCommand(AParent,
|
|
'Run to cursor', uemRunToCursor, nil, nil, nil, 'menu_run_cursor');
|
|
SrcEditMenuViewCallStack:=RegisterIDEMenuCommand(AParent,
|
|
'View Call Stack', uemViewCallStack, nil, nil, nil, 'debugger_call_stack');
|
|
|
|
// register the Refactoring submenu
|
|
SrcEditSubMenuRefactor:=RegisterIDESubMenu(SourceEditorMenuRoot,
|
|
'Refactoring',uemRefactor);
|
|
AParent:=SrcEditSubMenuRefactor;
|
|
SrcEditMenuCompleteCode:=RegisterIDEMenuCommand(AParent,'CompleteCode',
|
|
uemCompleteCode);
|
|
SrcEditMenuEncloseSelection:=RegisterIDEMenuCommand(AParent,
|
|
'EncloseSelection',uemEncloseSelection);
|
|
SrcEditMenuRenameIdentifier:=RegisterIDEMenuCommand(AParent,
|
|
'RenameIdentifier',uemRenameIdentifier);
|
|
SrcEditMenuFindIdentifierReferences:=RegisterIDEMenuCommand(AParent,
|
|
'FindIdentifierReferences',uemFindIdentifierReferences);
|
|
SrcEditMenuExtractProc:=RegisterIDEMenuCommand(AParent,
|
|
'ExtractProc',uemExtractProc);
|
|
SrcEditMenuInvertAssignment:=RegisterIDEMenuCommand(AParent,
|
|
'InvertAssignment',uemInvertAssignment);
|
|
SrcEditMenuShowAbstractMethods:=RegisterIDEMenuCommand(AParent,
|
|
'ShowAbstractMethods',srkmecShowAbstractMethods);
|
|
SrcEditMenuShowEmptyMethods:=RegisterIDEMenuCommand(AParent,
|
|
'ShowEmptyMethods', lisCodeHelpShowEmptyMethods);
|
|
SrcEditMenuShowUnusedUnits:=RegisterIDEMenuCommand(AParent,
|
|
'ShowUnusedUnits', lisCodeHelpShowUnusedUnits);
|
|
SrcEditMenuFindOverloads:=RegisterIDEMenuCommand(AParent,
|
|
'FindOverloads', srkmecFindOverloads);
|
|
{$IFNDEF EnableFindOverloads}
|
|
SrcEditMenuFindOverloads.Visible:=false;
|
|
{$ENDIF}
|
|
|
|
SrcEditMenuEditorProperties:=RegisterIDEMenuCommand(SourceEditorMenuRoot,
|
|
'EditorProperties', dlgFROpts, nil, nil, nil, 'menu_environment_options');
|
|
end;
|
|
|
|
|
|
{ TSourceEditCompletion }
|
|
|
|
procedure TSourceEditCompletion.ccExecute(Sender: TObject);
|
|
// init completion form
|
|
// called by OnExecute just before showing
|
|
var
|
|
S: TStrings;
|
|
Prefix: String;
|
|
I: Integer;
|
|
NewStr: String;
|
|
Begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceEditCompletion.ccExecute START']);
|
|
{$ENDIF}
|
|
TheForm.Font := Editor.Font;
|
|
FActiveEditDefaultFGColor := Editor.Font.Color;
|
|
FActiveEditDefaultBGColor := Editor.Color;
|
|
FActiveEditSelectedFGColor := TSynEdit(Editor).SelectedColor.Foreground;
|
|
FActiveEditSelectedBGColor := TSynEdit(Editor).SelectedColor.Background;
|
|
|
|
if Editor.Highlighter<>nil
|
|
then begin
|
|
with Editor.Highlighter do begin
|
|
if IdentifierAttribute<>nil
|
|
then begin
|
|
if IdentifierAttribute.ForeGround<>clNone then
|
|
FActiveEditDefaultFGColor:=IdentifierAttribute.ForeGround;
|
|
if IdentifierAttribute.BackGround<>clNone then
|
|
FActiveEditDefaultBGColor:=IdentifierAttribute.BackGround;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
S := TStringList.Create;
|
|
try
|
|
Prefix := CurrentString;
|
|
case CurrentCompletionType of
|
|
ctIdentCompletion:
|
|
if not InitIdentCompletionValues(S) then begin
|
|
ItemList.Clear;
|
|
exit;
|
|
end;
|
|
|
|
ctWordCompletion:
|
|
begin
|
|
ccSelection := '';
|
|
end;
|
|
|
|
ctTemplateCompletion:
|
|
begin
|
|
ccSelection:='';
|
|
for I := 0 to Manager.CodeTemplateModul.Completions.Count-1 do begin
|
|
NewStr := Manager.CodeTemplateModul.Completions[I];
|
|
if NewStr<>'' then begin
|
|
NewStr:=#3'B'+NewStr+#3'b';
|
|
while length(NewStr)<10+4 do NewStr:=NewStr+' ';
|
|
NewStr:=NewStr+' '+Manager.CodeTemplateModul.CompletionComments[I];
|
|
S.Add(NewStr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
ItemList := S;
|
|
finally
|
|
S.Free;
|
|
end;
|
|
CurrentString:=Prefix;
|
|
// set colors
|
|
if (Editor<>nil) and (TheForm<>nil) then begin
|
|
with TheForm do begin
|
|
BackgroundColor := FActiveEditDefaultBGColor;
|
|
clSelect := FActiveEditSelectedBGColor;
|
|
TextColor := FActiveEditDefaultFGColor;
|
|
TextSelectedColor := FActiveEditSelectedFGColor;
|
|
//writeln('TSourceNotebook.ccExecute A Color=',DbgS(Color),
|
|
// ' clSelect=',DbgS(clSelect),
|
|
// ' TextColor=',DbgS(TextColor),
|
|
// ' TextSelectedColor=',DbgS(TextSelectedColor),
|
|
// '');
|
|
end;
|
|
if (CurrentCompletionType=ctIdentCompletion) and (SourceEditorManager.ActiveCompletionPlugin=nil)
|
|
then
|
|
StartShowCodeHelp
|
|
else if SrcEditHintWindow<>nil then
|
|
SrcEditHintWindow.HelpEnabled:=false;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.ccCancel(Sender: TObject);
|
|
// user cancels completion form
|
|
begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceNotebook.ccCancel START']);
|
|
//debugln(GetStackTrace(true));
|
|
{$ENDIF}
|
|
Manager.DeactivateCompletionForm;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.ccComplete(var Value: string;
|
|
SourceValue: string; var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char;
|
|
Shift: TShiftState);
|
|
// completion selected -> deactivate completion form
|
|
// Called when user has selected a completion item
|
|
|
|
function CharBehindIdent(const Line: string; StartPos: integer): char;
|
|
begin
|
|
while (StartPos<=length(Line))
|
|
and (Line[StartPos] in ['_','A'..'Z','a'..'z']) do
|
|
inc(StartPos);
|
|
while (StartPos<=length(Line)) and (Line[StartPos] in [' ',#9]) do
|
|
inc(StartPos);
|
|
if StartPos<=length(Line) then
|
|
Result:=Line[StartPos]
|
|
else
|
|
Result:=#0;
|
|
end;
|
|
|
|
function CharInFrontOfIdent(const Line: string; StartPos: integer): char;
|
|
begin
|
|
while (StartPos>=1)
|
|
and (Line[StartPos] in ['_','A'..'Z','a'..'z']) do
|
|
dec(StartPos);
|
|
while (StartPos>=1) and (Line[StartPos] in [' ',#9]) do
|
|
dec(StartPos);
|
|
if StartPos>=1 then
|
|
Result:=Line[StartPos]
|
|
else
|
|
Result:=#0;
|
|
end;
|
|
|
|
var
|
|
p1, p2: integer;
|
|
ValueType: TIdentComplValue;
|
|
NewCaretXY: TPoint;
|
|
CursorToLeft: integer;
|
|
NewValue: String;
|
|
OldCompletionType: TCompletionType;
|
|
Begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceNotebook.ccComplete START']);
|
|
{$ENDIF}
|
|
OldCompletionType:=CurrentCompletionType;
|
|
case CurrentCompletionType of
|
|
|
|
ctIdentCompletion:
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
begin
|
|
Manager.ActiveCompletionPlugin.Complete(Value,SourceValue,
|
|
SourceStart,SourceEnd,KeyChar,Shift);
|
|
Manager.FActiveCompletionPlugin:=nil;
|
|
end else begin
|
|
// add to history
|
|
CodeToolBoss.IdentifierHistory.Add(
|
|
CodeToolBoss.IdentifierList.FilteredItems[Position]);
|
|
// get value
|
|
NewValue:=GetIdentCompletionValue(self, KeyChar, ValueType, CursorToLeft);
|
|
if ValueType=icvIdentifier then ;
|
|
// insert value plus special chars like brackets, semicolons, ...
|
|
if ValueType <> icvNone then
|
|
Editor.TextBetweenPointsEx[SourceStart, SourceEnd, scamEnd] := NewValue;
|
|
if CursorToLeft>0 then
|
|
begin
|
|
NewCaretXY:=Editor.CaretXY;
|
|
dec(NewCaretXY.X,CursorToLeft);
|
|
Editor.CaretXY:=NewCaretXY;
|
|
end;
|
|
ccSelection := '';
|
|
Value:='';
|
|
SourceEnd := SourceStart;
|
|
end;
|
|
|
|
ctTemplateCompletion:
|
|
begin
|
|
// the completion is the bold text between #3'B' and #3'b'
|
|
p1:=Pos(#3,Value);
|
|
if p1>=0 then begin
|
|
p2:=p1+2;
|
|
while (p2<=length(Value)) and (Value[p2]<>#3) do inc(p2);
|
|
Value:=copy(Value,p1+2,p2-p1-2);
|
|
// keep parent identifier (in front of '.')
|
|
p1:=length(ccSelection);
|
|
while (p1>=1) and (ccSelection[p1]<>'.') do dec(p1);
|
|
if p1>=1 then
|
|
Value:=copy(ccSelection,1,p1)+Value;
|
|
end;
|
|
ccSelection := '';
|
|
if Value<>'' then
|
|
Manager.CodeTemplateModul.ExecuteCompletion(Value, Editor);
|
|
SourceEnd := SourceStart;
|
|
Value:='';
|
|
end;
|
|
|
|
ctWordCompletion:
|
|
// the completion is already in Value
|
|
begin
|
|
ccSelection := '';
|
|
if Value<>'' then AWordCompletion.AddWord(Value);
|
|
end;
|
|
|
|
else begin
|
|
Value:='';
|
|
end;
|
|
end;
|
|
|
|
Manager.DeactivateCompletionForm;
|
|
|
|
//DebugLn(['TSourceNotebook.ccComplete ',KeyChar,' ',OldCompletionType=ctIdentCompletion]);
|
|
if (KeyChar='.') and (OldCompletionType=ctIdentCompletion) then
|
|
begin
|
|
SourceCompletionCaretXY:=Editor.CaretXY;
|
|
SourceCompletionTimer.AutoEnabled:=true;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditCompletion.OnSynCompletionPaintItem(const AKey: string;
|
|
ACanvas: TCanvas; X, Y: integer; ItemSelected: boolean; Index: integer
|
|
): boolean;
|
|
var
|
|
MaxX: Integer;
|
|
t: TCompletionType;
|
|
begin
|
|
with ACanvas do begin
|
|
if (Editor<>nil) then
|
|
Font := Editor.Font
|
|
else begin
|
|
Font.Height:=EditorOpts.EditorFontHeight; // set Height before name for XLFD !
|
|
Font.Name:=EditorOpts.EditorFont;
|
|
end;
|
|
Font.Style:=[];
|
|
if not ItemSelected then
|
|
Font.Color := FActiveEditDefaultFGColor
|
|
else
|
|
Font.Color := FActiveEditSelectedFGColor;
|
|
end;
|
|
MaxX:=TheForm.ClientWidth;
|
|
t:=CurrentCompletionType;
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
begin
|
|
if Manager.ActiveCompletionPlugin.HasCustomPaint then
|
|
begin
|
|
Manager.ActiveCompletionPlugin.PaintItem(AKey,ACanvas,X,Y,ItemSelected,Index);
|
|
end else begin
|
|
t:=ctWordCompletion;
|
|
end;
|
|
end;
|
|
PaintCompletionItem(AKey,ACanvas,X,Y,MaxX,ItemSelected,Index,self,
|
|
t,Editor.Highlighter);
|
|
Result:=true;
|
|
end;
|
|
|
|
function TSourceEditCompletion.OnSynCompletionMeasureItem(const AKey: string;
|
|
ACanvas: TCanvas; ItemSelected: boolean; Index: integer): TPoint;
|
|
var
|
|
MaxX: Integer;
|
|
t: TCompletionType;
|
|
begin
|
|
with ACanvas do begin
|
|
if (Editor<>nil) then
|
|
Font:=Editor.Font
|
|
else begin
|
|
Font.Height:=EditorOpts.EditorFontHeight; // set Height before name of XLFD !
|
|
Font.Name:=EditorOpts.EditorFont;
|
|
end;
|
|
Font.Style:=[];
|
|
if not ItemSelected then
|
|
Font.Color := FActiveEditDefaultFGColor
|
|
else
|
|
Font.Color := FActiveEditSelectedFGColor;
|
|
end;
|
|
MaxX := Screen.Width-20;
|
|
t:=CurrentCompletionType;
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
begin
|
|
if Manager.ActiveCompletionPlugin.HasCustomPaint then
|
|
begin
|
|
Manager.ActiveCompletionPlugin.MeasureItem(AKey,ACanvas,ItemSelected,Index);
|
|
end else begin
|
|
t:=ctWordCompletion;
|
|
end;
|
|
end;
|
|
Result := PaintCompletionItem(AKey,ACanvas,0,0,MaxX,ItemSelected,Index,
|
|
self,t,nil,True);
|
|
Result.Y:=FontHeight;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionSearchPosition(
|
|
var APosition: integer);
|
|
// prefix changed -> filter list
|
|
var
|
|
i,x:integer;
|
|
CurStr,s:Ansistring;
|
|
SL: TStrings;
|
|
ItemCnt: Integer;
|
|
begin
|
|
case CurrentCompletionType of
|
|
|
|
ctIdentCompletion:
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
begin
|
|
// let plugin rebuild completion list
|
|
SL:=TStringList.Create;
|
|
try
|
|
Manager.ActiveCompletionPlugin.PrefixChanged(CurrentString,
|
|
APosition,sl);
|
|
ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end else begin
|
|
// rebuild completion list
|
|
APosition:=0;
|
|
CurStr:=CurrentString;
|
|
CodeToolBoss.IdentifierList.Prefix:=CurStr;
|
|
ItemCnt:=CodeToolBoss.IdentifierList.GetFilteredCount;
|
|
SL:=TStringList.Create;
|
|
try
|
|
sl.Capacity:=ItemCnt;
|
|
for i:=0 to ItemCnt-1 do
|
|
SL.Add('Dummy'); // these entries are not shown
|
|
ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
ctTemplateCompletion:
|
|
begin
|
|
// search CurrentString in bold words (words after #3'B')
|
|
CurStr:=CurrentString;
|
|
i:=0;
|
|
while i<ItemList.Count do begin
|
|
s:=ItemList[i];
|
|
x:=1;
|
|
while (x<=length(s)) and (s[x]<>#3) do inc(x);
|
|
if x<length(s) then begin
|
|
inc(x,2);
|
|
if AnsiCompareText(CurStr,copy(s,x,length(CurStr)))=0 then begin
|
|
APosition:=i;
|
|
break;
|
|
end;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
ctWordCompletion:
|
|
begin
|
|
// rebuild completion list
|
|
APosition:=0;
|
|
CurStr:=CurrentString;
|
|
SL:=TStringList.Create;
|
|
try
|
|
aWordCompletion.GetWordList(SL, CurStr, false, 100);
|
|
ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionCompletePrefix(Sender: TObject);
|
|
var
|
|
OldPrefix: String;
|
|
NewPrefix: String;
|
|
SL: TStringList;
|
|
AddPrefix: String;
|
|
begin
|
|
OldPrefix:=CurrentString;
|
|
NewPrefix:=OldPrefix;
|
|
|
|
case CurrentCompletionType of
|
|
|
|
ctIdentCompletion:
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
begin
|
|
Manager.ActiveCompletionPlugin.CompletePrefix(NewPrefix);
|
|
end else begin
|
|
NewPrefix:=CodeToolBoss.IdentifierList.CompletePrefix(OldPrefix);
|
|
end;
|
|
|
|
ctWordCompletion:
|
|
begin
|
|
aWordCompletion.CompletePrefix(OldPrefix,NewPrefix,false);
|
|
end;
|
|
|
|
end;
|
|
|
|
if NewPrefix<>OldPrefix then begin
|
|
AddPrefix:=copy(NewPrefix,length(OldPrefix)+1,length(NewPrefix));
|
|
Editor.InsertTextAtCaret(AddPrefix);
|
|
if CurrentCompletionType=ctWordCompletion then begin
|
|
SL:=TStringList.Create;
|
|
try
|
|
aWordCompletion.GetWordList(SL, NewPrefix, false, 100);
|
|
ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
CurrentString:=NewPrefix;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionNextChar(Sender: TObject);
|
|
var
|
|
NewPrefix: String;
|
|
Line: String;
|
|
LogCaret: TPoint;
|
|
CharLen: LongInt;
|
|
AddPrefix: String;
|
|
begin
|
|
if Editor=nil then exit;
|
|
LogCaret:=Editor.LogicalCaretXY;
|
|
if LogCaret.Y>=Editor.Lines.Count then exit;
|
|
Line:=Editor.Lines[LogCaret.Y-1];
|
|
if LogCaret.X>length(Line) then exit;
|
|
CharLen:=UTF8CharacterLength(@Line[LogCaret.X]);
|
|
AddPrefix:=copy(Line,LogCaret.X,CharLen);
|
|
NewPrefix:=CurrentString+AddPrefix;
|
|
//debugln('TSourceNotebook.OnSynCompletionNextChar NewPrefix="',NewPrefix,'" LogCaret.X=',dbgs(LogCaret.X));
|
|
inc(LogCaret.X);
|
|
Editor.LogicalCaretXY:=LogCaret;
|
|
CurrentString:=NewPrefix;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionPrevChar(Sender: TObject);
|
|
var
|
|
NewPrefix: String;
|
|
NewLen: LongInt;
|
|
begin
|
|
NewPrefix:=CurrentString;
|
|
if NewPrefix='' then exit;
|
|
if Editor=nil then exit;
|
|
Editor.CaretX:=Editor.CaretX-1;
|
|
NewLen:=UTF8FindNearestCharStart(PChar(NewPrefix),length(NewPrefix),
|
|
length(NewPrefix))-1;
|
|
NewPrefix:=copy(NewPrefix,1,NewLen);
|
|
CurrentString:=NewPrefix;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionKeyPress(Sender: TObject;
|
|
var Key: Char);
|
|
begin
|
|
if (System.Pos(Key,EndOfTokenChr)>0) then begin
|
|
// identifier completed
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress A');
|
|
TheForm.OnValidate(Sender,Key,[]);
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress B');
|
|
Key:=#0;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionUTF8KeyPress(Sender: TObject;
|
|
var UTF8Key: TUTF8Char);
|
|
begin
|
|
if (length(UTF8Key)=1)
|
|
and (System.Pos(UTF8Key[1],EndOfTokenChr)>0) then begin
|
|
// identifier completed
|
|
//debugln('TSourceNotebook.OnSynCompletionUTF8KeyPress A');
|
|
TheForm.OnValidate(Sender,UTF8Key,[]);
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress B');
|
|
UTF8Key:='';
|
|
end else begin
|
|
Editor.CommandProcessor(ecChar,UTF8Key,nil);
|
|
UTF8Key:='';
|
|
end;
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress B UTF8Key=',dbgstr(UTF8Key));
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.OnSynCompletionPositionChanged(Sender: TObject
|
|
);
|
|
begin
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
Manager.ActiveCompletionPlugin.IndexChanged(Position);
|
|
if SrcEditHintWindow<>nil then
|
|
SrcEditHintWindow.UpdateHints;
|
|
end;
|
|
|
|
function TSourceEditCompletion.InitIdentCompletionValues(S: TStrings): boolean;
|
|
var
|
|
i: integer;
|
|
Handled: boolean;
|
|
Abort: boolean;
|
|
Prefix: string;
|
|
ItemCnt: Integer;
|
|
begin
|
|
Result:=false;
|
|
Prefix := CurrentString;
|
|
if Manager.ActiveCompletionPlugin<>nil then
|
|
begin
|
|
Result := Manager.ActiveCompletionPlugin.Collect(S);
|
|
end else if Assigned(Manager.OnInitIdentCompletion) then
|
|
begin
|
|
Manager.OnInitIdentCompletion(Self, FIdentCompletionJumpToError, Handled, Abort);
|
|
if Handled then begin
|
|
if Abort then exit;
|
|
// add one entry per item
|
|
CodeToolBoss.IdentifierList.Prefix:=Prefix;
|
|
ItemCnt:=CodeToolBoss.IdentifierList.GetFilteredCount;
|
|
//DebugLn('InitIdentCompletion B Prefix=',Prefix,' ItemCnt=',IntToStr(ItemCnt));
|
|
Position:=0;
|
|
for i:=0 to ItemCnt-1 do
|
|
s.Add('Dummy');
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditCompletion.StartShowCodeHelp;
|
|
begin
|
|
if SrcEditHintWindow = nil then begin
|
|
SrcEditHintWindow := TSrcEditHintWindow.Create(Manager);
|
|
SrcEditHintWindow.Name:='TSourceNotebook_SrcEditHintWindow';
|
|
SrcEditHintWindow.Provider:=TFPDocHintProvider.Create(SrcEditHintWindow);
|
|
end;
|
|
SrcEditHintWindow.AnchorForm := TheForm;
|
|
{$IFDEF EnableCodeHelp}
|
|
SrcEditHintWindow.HelpEnabled:=true;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TSourceEditCompletion.Manager: TSourceEditorManager;
|
|
begin
|
|
Result := SourceEditorManager;
|
|
end;
|
|
|
|
constructor TSourceEditCompletion.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
EndOfTokenChr:='()[].,;:-+=^*<>/';
|
|
Width:=400;
|
|
OnExecute := @ccExecute;
|
|
OnCancel := @ccCancel;
|
|
OnCodeCompletion := @ccComplete;
|
|
OnPaintItem:=@OnSynCompletionPaintItem;
|
|
OnMeasureItem := @OnSynCompletionMeasureItem;
|
|
OnSearchPosition:=@OnSynCompletionSearchPosition;
|
|
OnKeyCompletePrefix:=@OnSynCompletionCompletePrefix;
|
|
OnKeyNextChar:=@OnSynCompletionNextChar;
|
|
OnKeyPrevChar:=@OnSynCompletionPrevChar;
|
|
OnKeyPress:=@OnSynCompletionKeyPress;
|
|
OnUTF8KeyPress:=@OnSynCompletionUTF8KeyPress;
|
|
OnPositionChanged:=@OnSynCompletionPositionChanged;
|
|
ShortCut:=Menus.ShortCut(VK_UNKNOWN,[]);
|
|
end;
|
|
|
|
{ TSourceEditorSharedValues }
|
|
|
|
function TSourceEditorSharedValues.GetSharedEditors(Index: Integer
|
|
): TSourceEditor;
|
|
begin
|
|
Result := TSourceEditor(FSharedEditorList[Index]);
|
|
end;
|
|
|
|
function TSourceEditorSharedValues.GetOtherSharedEditors(Caller: TSourceEditor;
|
|
Index: Integer): TSourceEditor;
|
|
begin
|
|
if Index >= FSharedEditorList.IndexOf(Caller) then
|
|
inc(Index);
|
|
Result := TSourceEditor(FSharedEditorList[Index]);
|
|
end;
|
|
|
|
function TSourceEditorSharedValues.SynEditor: TIDESynEditor;
|
|
begin
|
|
Result := SharedEditors[0].FEditor;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.SetCodeBuffer(const AValue: TCodeBuffer);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FCodeBuffer = AValue then exit;
|
|
if FCodeBuffer<>nil then
|
|
FCodeBuffer.RemoveChangeHook(@OnCodeBufferChanged);
|
|
FCodeBuffer := AValue;
|
|
if FCodeBuffer <> nil then
|
|
begin
|
|
FCodeBuffer.AddChangeHook(@OnCodeBufferChanged);
|
|
if (FIgnoreCodeBufferLock <= 0) and (not FCodeBuffer.IsEqual(SynEditor.Lines))
|
|
then begin
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln(' *** WARNING *** : TSourceEditor.SetCodeBuffer - loosing marks: ',Filename);
|
|
{$ENDIF}
|
|
for i := 0 to FSharedEditorList.Count - 1 do
|
|
if assigned(SharedEditors[i].FEditPlugin) then
|
|
SharedEditors[i].FEditPlugin.Enabled := False;
|
|
SynEditor.BeginUpdate;
|
|
FCodeBuffer.AssignTo(SynEditor.Lines, false);
|
|
FEditorStampCommitedToCodetools:=(SynEditor.Lines as TSynEditLines).TextChangeStamp;
|
|
SynEditor.EndUpdate;
|
|
for i := 0 to FSharedEditorList.Count - 1 do
|
|
if assigned(SharedEditors[i].FEditPlugin) then
|
|
SharedEditors[i].FEditPlugin.Enabled := True;
|
|
end;
|
|
for i := 0 to FSharedEditorList.Count - 1 do begin
|
|
if SharedEditors[i].IsActiveOnNoteBook then SharedEditors[i].SourceNotebook.UpdateStatusBar;
|
|
// HasExecutionMarks is shared through synedit => this is only needed once
|
|
// but HasExecutionMarks must be called on each synedit, so each synedit is notified
|
|
if (DebugBoss.State in [dsPause, dsRun]) and
|
|
not SharedEditors[i].HasExecutionMarks and (FCodeBuffer.FileName <> '')
|
|
then
|
|
SharedEditors[i].FillExecutionMarks;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorSharedValues.GetModified: Boolean;
|
|
begin
|
|
Result := FModified or SynEditor.Modified;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.SetModified(const AValue: Boolean);
|
|
var
|
|
OldModified: Boolean;
|
|
i: Integer;
|
|
begin
|
|
OldModified := Modified; // Include SynEdit
|
|
FModified := AValue;
|
|
if not FModified then
|
|
begin
|
|
SynEditor.Modified := False; // All shared SynEdits share this value
|
|
FEditorStampCommitedToCodetools := TSynEditLines(SynEditor.Lines).TextChangeStamp;
|
|
for i := 0 to FSharedEditorList.Count - 1 do
|
|
SharedEditors[i].FEditor.MarkTextAsSaved; // Todo: centralize in SynEdit
|
|
end;
|
|
if OldModified <> Modified then
|
|
for i := 0 to FSharedEditorList.Count - 1 do begin
|
|
SharedEditors[i].UpdatePageName;
|
|
SharedEditors[i].SourceNotebook.UpdateStatusBar;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.OnCodeBufferChanged(Sender: TSourceLog;
|
|
SrcLogEntry: TSourceLogEntry);
|
|
|
|
procedure MoveTxt(const StartPos, EndPos, MoveToPos: TPoint;
|
|
DirectionForward: boolean);
|
|
var Txt: string;
|
|
begin
|
|
if DirectionForward then begin
|
|
SynEditor.TextBetweenPointsEx[MoveToPos, MoveToPos, scamAdjust] :=
|
|
SynEditor.TextBetweenPoints[StartPos, EndPos];
|
|
SynEditor.TextBetweenPointsEx[StartPos, EndPos, scamAdjust] := '';
|
|
end else begin
|
|
Txt := SynEditor.TextBetweenPoints[StartPos, EndPos];
|
|
SynEditor.TextBetweenPointsEx[StartPos, EndPos, scamAdjust] := '';
|
|
SynEditor.TextBetweenPointsEx[MoveToPos, MoveToPos, scamAdjust] := Txt;;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
StartPos, EndPos, MoveToPos: TPoint;
|
|
CodeToolsInSync: Boolean;
|
|
i: Integer;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln(['[TSourceEditor.OnCodeBufferChanged] A ',FIgnoreCodeBufferLock,' ',SrcLogEntry<>nil]);
|
|
{$ENDIF}
|
|
if FIgnoreCodeBufferLock>0 then exit;
|
|
CodeToolsInSync:=not NeedsUpdateCodeBuffer;
|
|
if SrcLogEntry<>nil then begin
|
|
SynEditor.BeginUpdate;
|
|
SynEditor.BeginUndoBlock;
|
|
SynEditor.TemplateEdit.IncExternalEditLock;
|
|
SynEditor.SyncroEdit.IncExternalEditLock;
|
|
try
|
|
case SrcLogEntry.Operation of
|
|
sleoInsert:
|
|
begin
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
|
|
if StartPos.Y>=1 then
|
|
SynEditor.TextBetweenPointsEx[StartPos, StartPos, scamAdjust] := SrcLogEntry.Txt;
|
|
end;
|
|
sleoDelete:
|
|
begin
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.Position+SrcLogEntry.Len,
|
|
EndPos.Y,EndPos.X);
|
|
if (StartPos.Y>=1) and (EndPos.Y>=1) then
|
|
SynEditor.TextBetweenPointsEx[StartPos, EndPos, scamAdjust] := '';
|
|
end;
|
|
sleoMove:
|
|
begin
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.Position+SrcLogEntry.Len,
|
|
EndPos.Y,EndPos.X);
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.MoveTo,MoveToPos.Y,MoveToPos.X);
|
|
if (StartPos.Y>=1) and (EndPos.Y>=1) and (MoveToPos.Y>=1) then
|
|
MoveTxt(StartPos, EndPos, MoveToPos,
|
|
SrcLogEntry.Position<SrcLogEntry.MoveTo);
|
|
end;
|
|
end;
|
|
finally
|
|
SynEditor.SyncroEdit.DecExternalEditLock;
|
|
SynEditor.TemplateEdit.DecExternalEditLock;
|
|
SynEditor.EndUndoBlock;
|
|
SynEditor.EndUpdate;
|
|
end;
|
|
end else begin
|
|
{$IFDEF VerboseSrcEditBufClean}
|
|
debugln(['TSourceEditor.OnCodeBufferChanged clean up ',TCodeBuffer(Sender).FileName,' ',Sender=CodeBuffer,' ',Filename]);
|
|
DumpStack;
|
|
{$ENDIF}
|
|
SynEditor.BeginUpdate;
|
|
for i := 0 to SharedEditorCount-1 do
|
|
SharedEditors[i].BeforeCodeBufferReplace;
|
|
Sender.AssignTo(SynEditor.Lines,false);
|
|
for i := 0 to SharedEditorCount-1 do
|
|
SharedEditors[i].AfterCodeBufferReplace;
|
|
SynEditor.EndUpdate;
|
|
end;
|
|
if CodeToolsInSync then begin
|
|
// synedit and codetools were in sync -> mark as still in sync
|
|
FEditorStampCommitedToCodetools:=TSynEditLines(SynEditor.Lines).TextChangeStamp;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.BeginGlobalUpdate;
|
|
begin
|
|
inc(FInGlobalUpdate);
|
|
if FInGlobalUpdate > 1 then exit;
|
|
SynEditor.BeginUpdate; // locks all shared SynEdits too
|
|
SynEditor.BeginUndoBlock;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.EndGlobalUpdate;
|
|
begin
|
|
dec(FInGlobalUpdate);
|
|
if FInGlobalUpdate > 0 then exit;
|
|
SynEditor.EndUndoBlock;
|
|
SynEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.AddSharedEditor(AnEditor: TSourceEditor);
|
|
begin
|
|
if FSharedEditorList.IndexOf(AnEditor) < 0 then
|
|
FSharedEditorList.Add(AnEditor);
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.RemoveSharedEditor(AnEditor: TSourceEditor
|
|
);
|
|
begin
|
|
FSharedEditorList.Remove(AnEditor);
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.SetActiveSharedEditor(AnEditor: TSourceEditor);
|
|
begin
|
|
if FInGlobalUpdate > 0 then exit;
|
|
// Move to the front, for UpdateCodetools (get undo-caret from correct synedit)
|
|
FSharedEditorList.Remove(AnEditor);
|
|
FSharedEditorList.Insert(0, AnEditor);
|
|
end;
|
|
|
|
function TSourceEditorSharedValues.SharedEditorCount: Integer;
|
|
begin
|
|
Result := FSharedEditorList.Count;
|
|
end;
|
|
|
|
function TSourceEditorSharedValues.OtherSharedEditorCount: Integer;
|
|
begin
|
|
Result := FSharedEditorList.Count - 1;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.CreateExecutionMark;
|
|
begin
|
|
FExecutionMark := TSourceMark.Create(SharedEditors[0], nil);
|
|
SourceEditorMarks.Add(FExecutionMark);
|
|
FExecutionMark.LineColorAttrib := ahaExecutionPoint;
|
|
FExecutionMark.Priority := 1;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.SetExecutionLine(NewLine: integer);
|
|
var
|
|
BrkMark: TSourceMark;
|
|
begin
|
|
if FExecutionLine = NewLine then
|
|
exit;
|
|
|
|
inc(UpdatingExecutionMark);
|
|
try
|
|
if FExecutionLine >= 0 then begin
|
|
BrkMark := SourceEditorMarks.FindBreakPointMark(SharedEditors[0], FExecutionLine);
|
|
if BrkMark <> nil then
|
|
BrkMark.Visible := True;
|
|
end;
|
|
|
|
if (FExecutionMark = nil) then begin
|
|
if NewLine = -1 then
|
|
exit;
|
|
CreateExecutionMark;
|
|
end;
|
|
|
|
FExecutionLine := NewLine;
|
|
FExecutionMark.Visible := NewLine <> -1;
|
|
|
|
if FExecutionLine >= 0 then begin
|
|
BrkMark := SourceEditorMarks.FindBreakPointMark(SharedEditors[0], FExecutionLine);
|
|
if BrkMark <> nil then
|
|
BrkMark.Visible := False;
|
|
end;
|
|
|
|
FExecutionMark.Line := NewLine;
|
|
finally
|
|
dec(UpdatingExecutionMark);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.IncreaseIgnoreCodeBufferLock;
|
|
begin
|
|
inc(FIgnoreCodeBufferLock);
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.DecreaseIgnoreCodeBufferLock;
|
|
begin
|
|
if FIgnoreCodeBufferLock<=0 then raise Exception.Create('unbalanced calls');
|
|
dec(FIgnoreCodeBufferLock);
|
|
end;
|
|
|
|
function TSourceEditorSharedValues.NeedsUpdateCodeBuffer: boolean;
|
|
begin
|
|
Result := TSynEditLines(SharedEditors[0].FEditor.Lines).TextChangeStamp
|
|
<> FEditorStampCommitedToCodetools;
|
|
end;
|
|
|
|
procedure TSourceEditorSharedValues.UpdateCodeBuffer;
|
|
begin
|
|
if not NeedsUpdateCodeBuffer then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
if FCodeBuffer=nil then begin
|
|
debugln('*********** Oh, no: UpdateCodeBuffer ************ ');
|
|
end;
|
|
{$ENDIF}
|
|
if FCodeBuffer=nil then exit;
|
|
//DebugLn(['TSourceEditor.UpdateCodeBuffer ',FCodeBuffer.FileName]);
|
|
IncreaseIgnoreCodeBufferLock;
|
|
SynEditor.BeginUpdate;
|
|
try
|
|
FCodeBuffer.Assign(SynEditor.Lines);
|
|
FEditorStampCommitedToCodetools:=(SynEditor.Lines as TSynEditLines).TextChangeStamp;
|
|
finally
|
|
SynEditor.EndUpdate;
|
|
DecreaseIgnoreCodeBufferLock;
|
|
end;
|
|
end;
|
|
|
|
constructor TSourceEditorSharedValues.Create;
|
|
begin
|
|
FSharedEditorList := TFPList.Create;
|
|
BookmarkEventLock := 0;
|
|
FExecutionLine:=-1;
|
|
FExecutionMark := nil;
|
|
FMarksRequested := False;
|
|
FInGlobalUpdate := 0;
|
|
end;
|
|
|
|
destructor TSourceEditorSharedValues.Destroy;
|
|
begin
|
|
CodeBuffer := nil;
|
|
FreeAndNil(FSharedEditorList);
|
|
// no need to care about ExecutionMark, it was removed in EditorClose
|
|
// via: SourceEditorMarks.DeleteAllForEditor(Self);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ TSourceEditor }
|
|
|
|
{ The constructor for @link(TSourceEditor).
|
|
AOwner is the @link(TSourceNotebook)
|
|
and the AParent is usually a page of a @link(TPageControl) }
|
|
constructor TSourceEditor.Create(AOwner: TComponent; AParent: TWinControl;
|
|
ASharedEditor: TSourceEditor = nil);
|
|
var
|
|
i: Integer;
|
|
Begin
|
|
if ASharedEditor = nil then
|
|
FSharedValues := TSourceEditorSharedValues.Create
|
|
else
|
|
FSharedValues := ASharedEditor.FSharedValues;
|
|
FSharedValues.AddSharedEditor(Self);
|
|
|
|
inherited Create;
|
|
FAOwner := AOwner;
|
|
if (FAOwner<>nil) and (FAOwner is TSourceNotebook) then
|
|
FSourceNoteBook:=TSourceNotebook(FAOwner)
|
|
else
|
|
FSourceNoteBook:=nil;
|
|
|
|
FSyntaxHighlighterType:=lshNone;
|
|
FErrorLine:=-1;
|
|
FErrorColumn:=-1;
|
|
FSyncroLockCount := 0;
|
|
FLineInfoNotification := TIDELineInfoNotification.Create;
|
|
FLineInfoNotification.AddReference;
|
|
FLineInfoNotification.OnChange := @LineInfoNotificationChange;
|
|
|
|
CreateEditor(AOwner,AParent);
|
|
FIsNewSharedEditor := False;
|
|
if ASharedEditor <> nil then begin
|
|
PageName := ASharedEditor.PageName;
|
|
FEditor.ShareTextBufferFrom(ASharedEditor.EditorComponent);
|
|
FEditor.Highlighter := ASharedEditor.EditorComponent.Highlighter;
|
|
|
|
// bookmakrs
|
|
inc(FSharedValues.BookmarkEventLock);
|
|
try
|
|
for i := 0 to ASharedEditor.FEditor.Marks.Count - 1 do
|
|
if ASharedEditor.FEditor.Marks[i].IsBookmark then
|
|
FEditor.SetBookMark(ASharedEditor.FEditor.Marks[i].BookmarkNumber,
|
|
ASharedEditor.FEditor.Marks[i].Column,
|
|
ASharedEditor.FEditor.Marks[i].Line);
|
|
finally
|
|
dec(FSharedValues.BookmarkEventLock);
|
|
end;
|
|
|
|
SourceEditorMarks.AddSourceEditor(Self, ASharedEditor);
|
|
end;
|
|
|
|
FEditPlugin := TSynEditPlugin1.Create(FEditor);
|
|
// IMPORTANT: when you change below, don't forget updating UnbindEditor
|
|
FEditPlugin.OnLinesInserted := @LinesInserted;
|
|
FEditPlugin.OnLinesDeleted := @LinesDeleted;
|
|
end;
|
|
|
|
destructor TSourceEditor.Destroy;
|
|
begin
|
|
if (FAOwner<>nil) and (FEditor<>nil) then begin
|
|
UnbindEditor;
|
|
FEditor.Visible:=false;
|
|
FEditor.Parent:=nil;
|
|
if SourceEditorMarks<>nil then
|
|
SourceEditorMarks.DeleteAllForEditor(Self);
|
|
TSourceNotebook(FAOwner).ReleaseEditor(self);
|
|
// free the synedit control after processing the events
|
|
Application.ReleaseComponent(FEditor);
|
|
end;
|
|
FEditor:=nil;
|
|
if (DebugBoss <> nil) and (DebugBoss.LineInfo <> nil) then
|
|
DebugBoss.LineInfo.RemoveNotification(FLineInfoNotification);
|
|
FLineInfoNotification.ReleaseReference;
|
|
inherited Destroy;
|
|
FSharedValues.RemoveSharedEditor(Self);
|
|
if FSharedValues.SharedEditorCount = 0 then
|
|
FreeAndNil(FSharedValues);
|
|
end;
|
|
|
|
{------------------------------G O T O L I N E -----------------------------}
|
|
Function TSourceEditor.GotoLine(Value: Integer): Integer;
|
|
Var
|
|
P: TPoint;
|
|
NewTopLine: integer;
|
|
Begin
|
|
Manager.AddJumpPointClicked(Self);
|
|
P.X := 1;
|
|
P.Y := Value;
|
|
NewTopLine := P.Y - (FEditor.LinesInWindow div 2);
|
|
if NewTopLine < 1 then NewTopLine:=1;
|
|
FEditor.CaretXY := P;
|
|
FEditor.TopLine := NewTopLine;
|
|
Result:=FEditor.CaretY;
|
|
end;
|
|
|
|
procedure TSourceEditor.ShowGotoLineDialog;
|
|
var
|
|
NewLeft: integer;
|
|
NewTop: integer;
|
|
dlg: TfrmGoto;
|
|
begin
|
|
dlg := Manager.GotoDialog;
|
|
dlg.Edit1.Text:='';
|
|
GetDialogPosition(dlg.Width, dlg.Height, NewLeft, NewTop);
|
|
dlg.SetBounds(NewLeft, NewTop, dlg.Width, dlg.Height);
|
|
if (dlg.ShowModal = mrOK) then
|
|
GotoLine(StrToIntDef(dlg.Edit1.Text,1));
|
|
Self.FocusEditor;
|
|
end;
|
|
|
|
procedure TSourceEditor.GetDialogPosition(Width, Height: integer;
|
|
out Left, Top: integer);
|
|
var
|
|
P: TPoint;
|
|
ABounds: TRect;
|
|
begin
|
|
with EditorComponent do
|
|
P := ClientToScreen(Point(CaretXPix, CaretYPix));
|
|
ABounds := Screen.MonitorFromPoint(P).BoundsRect;
|
|
Left := EditorComponent.ClientOrigin.X + (EditorComponent.Width - Width) div 2;
|
|
Top := P.Y - Height - 3 * EditorComponent.LineHeight;
|
|
if Top < ABounds.Top + 10 then
|
|
Top := P.Y + 2 * EditorComponent.LineHeight;
|
|
if Top + Height > ABounds.Bottom then
|
|
Top := (ABounds.Bottom + ABounds.Top - Height) div 2;
|
|
if Top < ABounds.Top then Top := ABounds.Top;
|
|
end;
|
|
|
|
procedure TSourceEditor.ActivateHint(ClientPos: TPoint;
|
|
const BaseURL, TheHint: string);
|
|
var
|
|
ScreenPos: TPoint;
|
|
begin
|
|
if SourceNotebook=nil then exit;
|
|
ScreenPos:=EditorComponent.ClientToScreen(ClientPos);
|
|
SourceNotebook.ActivateHint(ScreenPos,BaseURL,TheHint);
|
|
end;
|
|
|
|
{------------------------------S T A R T F I N D-----------------------------}
|
|
procedure TSourceEditor.StartFindAndReplace(Replace:boolean);
|
|
const
|
|
SaveOptions = [ssoWholeWord,ssoBackwards,ssoEntireScope,ssoRegExpr,ssoRegExprMultiLine];
|
|
var
|
|
NewOptions: TSynSearchOptions;
|
|
ALeft,ATop:integer;
|
|
bSelectedTextOption: Boolean;
|
|
DlgResult: TModalResult;
|
|
begin
|
|
LazFindReplaceDialog.ResetUserHistory;
|
|
//debugln('TSourceEditor.StartFindAndReplace A LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'"');
|
|
if ReadOnly then Replace := False;
|
|
NewOptions:=LazFindReplaceDialog.Options;
|
|
if Replace then
|
|
NewOptions := NewOptions + [ssoReplace, ssoReplaceAll]
|
|
else
|
|
NewOptions := NewOptions - [ssoReplace, ssoReplaceAll];
|
|
NewOptions:=NewOptions-SaveOptions+InputHistories.FindOptions*SaveOptions;
|
|
LazFindReplaceDialog.Options := NewOptions;
|
|
|
|
// Fill in history items
|
|
LazFindReplaceDialog.TextToFindComboBox.Items.Assign(InputHistories.FindHistory);
|
|
LazFindReplaceDialog.ReplaceTextComboBox.Items.Assign(
|
|
InputHistories.ReplaceHistory);
|
|
|
|
with EditorComponent do begin
|
|
if EditorOpts.FindTextAtCursor then begin
|
|
if SelAvail and (BlockBegin.Y = BlockEnd.Y) then begin
|
|
//debugln('TSourceEditor.StartFindAndReplace B FindTextAtCursor SelAvail');
|
|
LazFindReplaceDialog.FindText := SelText
|
|
end else begin
|
|
//debugln('TSourceEditor.StartFindAndReplace B FindTextAtCursor not SelAvail');
|
|
LazFindReplaceDialog.FindText := GetWordAtRowCol(LogicalCaretXY);
|
|
end;
|
|
end else begin
|
|
//debugln('TSourceEditor.StartFindAndReplace B not FindTextAtCursor');
|
|
LazFindReplaceDialog.FindText:='';
|
|
end;
|
|
end;
|
|
LazFindReplaceDialog.EnableAutoComplete:=InputHistories.FindAutoComplete;
|
|
// if there is no FindText, use the most recently used FindText
|
|
if (LazFindReplaceDialog.FindText='') and (InputHistories.FindHistory.Count > 0) then
|
|
LazFindReplaceDialog.FindText:=InputHistories.FindHistory[0];
|
|
|
|
GetDialogPosition(LazFindReplaceDialog.Width,LazFindReplaceDialog.Height,ALeft,ATop);
|
|
LazFindReplaceDialog.Left:=ALeft;
|
|
LazFindReplaceDialog.Top:=ATop;
|
|
|
|
try
|
|
bSelectedTextOption := (ssoSelectedOnly in LazFindReplaceDialog.Options);
|
|
//if there are selected text and more than 1 word, automatically enable selected text option
|
|
if EditorComponent.SelAvail
|
|
and (EditorComponent.BlockBegin.Y<>EditorComponent.BlockEnd.Y) then
|
|
LazFindReplaceDialog.Options := LazFindReplaceDialog.Options + [ssoSelectedOnly];
|
|
|
|
DlgResult:=LazFindReplaceDialog.ShowModal;
|
|
InputHistories.FindOptions:=LazFindReplaceDialog.Options*SaveOptions;
|
|
InputHistories.FindAutoComplete:=LazFindReplaceDialog.EnableAutoComplete;
|
|
if DlgResult = mrCancel then
|
|
exit;
|
|
//debugln('TSourceEditor.StartFindAndReplace B LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'"');
|
|
|
|
Replace:=ssoReplace in LazFindReplaceDialog.Options;
|
|
if Replace then
|
|
InputHistories.AddToReplaceHistory(LazFindReplaceDialog.ReplaceText);
|
|
InputHistories.AddToFindHistory(LazFindReplaceDialog.FindText);
|
|
InputHistories.Save;
|
|
DoFindAndReplace;
|
|
finally
|
|
//Restore original find options
|
|
if bSelectedTextOption then
|
|
LazFindReplaceDialog.Options := LazFindReplaceDialog.Options + [ssoSelectedOnly]
|
|
else
|
|
LazFindReplaceDialog.Options := LazFindReplaceDialog.Options - [ssoSelectedOnly];
|
|
end;//End try-finally
|
|
end;
|
|
|
|
procedure TSourceEditor.AskReplace(Sender: TObject; const ASearch,
|
|
AReplace: string; Line, Column: integer; var Action: TSrcEditReplaceAction);
|
|
var
|
|
SynAction: TSynReplaceAction;
|
|
begin
|
|
SynAction:=raCancel;
|
|
SourceNotebook.BringToFront;
|
|
OnReplace(Sender, ASearch, AReplace, Line, Column, SynAction);
|
|
case SynAction of
|
|
raSkip: Action:=seraSkip;
|
|
raReplaceAll: Action:=seraReplaceAll;
|
|
raReplace: Action:=seraReplace;
|
|
raCancel: Action:=seraCancel;
|
|
else
|
|
RaiseGDBException('TSourceEditor.AskReplace: inconsistency');
|
|
end;
|
|
end;
|
|
|
|
{------------------------------F I N D A G A I N ----------------------------}
|
|
procedure TSourceEditor.FindNextUTF8;
|
|
var
|
|
OldOptions: TSynSearchOptions;
|
|
begin
|
|
if snIncrementalFind in FSourceNoteBook.States
|
|
then begin
|
|
FSourceNoteBook.IncrementalSearch(True, False);
|
|
end
|
|
else if LazFindReplaceDialog.FindText = ''
|
|
then begin
|
|
StartFindAndReplace(False)
|
|
end
|
|
else begin
|
|
OldOptions:=LazFindReplaceDialog.Options;
|
|
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options
|
|
-[ssoEntireScope,ssoReplaceAll];
|
|
DoFindAndReplace;
|
|
LazFindReplaceDialog.Options:=OldOptions;
|
|
end;
|
|
End;
|
|
|
|
{---------------------------F I N D P R E V I O U S ------------------------}
|
|
procedure TSourceEditor.FindPrevious;
|
|
var
|
|
OldOptions: TSynSearchOptions;
|
|
begin
|
|
if snIncrementalFind in FSourceNoteBook.States
|
|
then begin
|
|
FSourceNoteBook.IncrementalSearch(True, True);
|
|
end
|
|
else begin
|
|
OldOptions:=LazFindReplaceDialog.Options;
|
|
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options-[ssoEntireScope];
|
|
if ssoBackwards in LazFindReplaceDialog.Options then
|
|
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options-[ssoBackwards]
|
|
else
|
|
LazFindReplaceDialog.Options:=LazFindReplaceDialog.Options+[ssoBackwards];
|
|
if LazFindReplaceDialog.FindText = '' then
|
|
StartFindAndReplace(False)
|
|
else
|
|
DoFindAndReplace;
|
|
LazFindReplaceDialog.Options:=OldOptions;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.FindNextWordOccurrence(DirectionForward: boolean);
|
|
var
|
|
StartX, EndX: Integer;
|
|
Flags: TSynSearchOptions;
|
|
LogCaret: TPoint;
|
|
begin
|
|
LogCaret:=EditorComponent.LogicalCaretXY;
|
|
EditorComponent.GetWordBoundsAtRowCol(LogCaret,StartX,EndX);
|
|
if EndX<=StartX then exit;
|
|
Flags:=[ssoWholeWord];
|
|
if DirectionForward then begin
|
|
LogCaret.X:=EndX;
|
|
end else begin
|
|
LogCaret.X:=StartX;
|
|
Include(Flags,ssoBackwards);
|
|
end;
|
|
EditorComponent.LogicalCaretXY:=LogCaret;
|
|
EditorComponent.SearchReplace(EditorComponent.GetWordAtRowCol(LogCaret),
|
|
'',Flags);
|
|
end;
|
|
|
|
function TSourceEditor.DoFindAndReplace: integer;
|
|
var
|
|
OldCaretXY: TPoint;
|
|
AText, ACaption: String;
|
|
NewTopLine: integer;
|
|
begin
|
|
Result:=0;
|
|
if SourceNotebook<>nil then
|
|
Manager.AddJumpPointClicked(Self);
|
|
if (ssoReplace in LazFindReplaceDialog.Options)
|
|
and ReadOnly then begin
|
|
DebugLn(['TSourceEditor.DoFindAndReplace Read only']);
|
|
exit;
|
|
end;
|
|
|
|
OldCaretXY:=EditorComponent.CaretXY;
|
|
if EditorComponent.SelAvail and
|
|
not(ssoSelectedOnly in LazFindReplaceDialog.Options)
|
|
then begin
|
|
// Adjust the cursor. to exclude the selection from being searched
|
|
// needed for find next / find previous
|
|
if ssoBackwards in LazFindReplaceDialog.Options then
|
|
EditorComponent.LogicalCaretXY:=EditorComponent.BlockBegin
|
|
else
|
|
EditorComponent.LogicalCaretXY:=EditorComponent.BlockEnd
|
|
end;
|
|
//debugln('TSourceEditor.DoFindAndReplace A LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'" ssoEntireScope=',dbgs(ssoEntireScope in LazFindReplaceDialog.Options),' ssoBackwards=',dbgs(ssoBackwards in LazFindReplaceDialog.Options));
|
|
try
|
|
Result:=EditorComponent.SearchReplace(
|
|
LazFindReplaceDialog.FindText,LazFindReplaceDialog.ReplaceText,
|
|
LazFindReplaceDialog.Options);
|
|
except
|
|
on E: ERegExpr do begin
|
|
MessageDlg(lisUEErrorInRegularExpression,
|
|
E.Message,mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if (OldCaretXY.X = EditorComponent.CaretX) and
|
|
(OldCaretXY.Y = EditorComponent.CaretY) and
|
|
not (ssoReplaceAll in LazFindReplaceDialog.Options) then
|
|
begin
|
|
ACaption := lisUENotFound;
|
|
AText := Format(lisUESearchStringNotFound, [ValidUTF8String(LazFindReplaceDialog.FindText)]);
|
|
MessageDlg(ACaption, AText, mtInformation, [mbOk], 0);
|
|
Manager.DeleteLastJumpPointClicked(Self);
|
|
end else
|
|
if (EditorComponent.CaretY <= EditorComponent.TopLine + 1) or
|
|
(EditorComponent.CaretY >= EditorComponent.TopLine + EditorComponent.LinesInWindow - 1) then
|
|
begin
|
|
NewTopLine := EditorComponent.CaretY - (EditorComponent.LinesInWindow div 2);
|
|
if NewTopLine < 1 then
|
|
NewTopLine := 1;
|
|
EditorComponent.TopLine := NewTopLine;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.OnReplace(Sender: TObject; const ASearch, AReplace:
|
|
string; Line, Column: integer; var Action: TSynReplaceAction);
|
|
var a,x,y:integer;
|
|
AText:AnsiString;
|
|
begin
|
|
if FAOwner<>nil then
|
|
TSourceNotebook(FAOwner).UpdateStatusBar;
|
|
AText:=Format(lisUEReplaceThisOccurrenceOfWith, ['"', ASearch, '"', #13, '"',
|
|
AReplace, '"']);
|
|
|
|
GetDialogPosition(300,150,X,Y);
|
|
a:=MessageDlgPos(AText,mtconfirmation,
|
|
[mbYes,mbYesToAll,mbNo,mbCancel],0,X,Y);
|
|
|
|
case a of
|
|
mrYes:Action:=raReplace;
|
|
mrNo :Action:=raSkip;
|
|
mrAll,mrYesToAll:Action:=raReplaceAll;
|
|
else
|
|
Action:=raCancel;
|
|
end;
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Procedure TSourceEditor.FocusEditor;
|
|
Begin
|
|
{$IFDEF VerboseFocus}
|
|
debugln('TSourceEditor.FocusEditor A ',PageName,' ',FEditor.Name);
|
|
{$ENDIF}
|
|
IDEWindowCreators.ShowForm(SourceNotebook,true);
|
|
if FEditor.IsVisible then begin
|
|
FEditor.SetFocus;
|
|
FSharedValues.SetActiveSharedEditor(Self);
|
|
end else begin
|
|
{$IFDEF VerboseFocus}
|
|
debugln('TSourceEditor.FocusEditor not IsVisible: ',PageName,' ',FEditor.Name);
|
|
{$ENDIF}
|
|
end;
|
|
//DebugLn('TSourceEditor.FocusEditor ',dbgsName(FindOwnerControl(GetFocus)),' ',dbgs(GetFocus));
|
|
{$IFDEF VerboseFocus}
|
|
debugln('TSourceEditor.FocusEditor END ',PageName,' ',FEditor.Name);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
Function TSourceEditor.GetReadOnly: Boolean;
|
|
Begin
|
|
Result:=FEditor.ReadOnly;
|
|
End;
|
|
|
|
procedure TSourceEditor.SetReadOnly(const NewValue: boolean);
|
|
begin
|
|
FEditor.ReadOnly:=NewValue;
|
|
end;
|
|
|
|
function TSourceEditor.Manager: TSourceEditorManager;
|
|
begin
|
|
if FSourceNoteBook <> nil then
|
|
Result := FSourceNoteBook.Manager
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceEditor.IsSharedWith(AnOtherEditor: TSourceEditor): Boolean;
|
|
begin
|
|
Result := (AnOtherEditor <> nil) and
|
|
(AnOtherEditor.FSharedValues = FSharedValues);
|
|
end;
|
|
|
|
procedure TSourceEditor.BeforeCodeBufferReplace;
|
|
begin
|
|
FTempTopLine := FEditor.TopLine;
|
|
FTempCaret := FEditor.CaretXY;
|
|
end;
|
|
|
|
procedure TSourceEditor.AfterCodeBufferReplace;
|
|
begin
|
|
if (FTempTopLine > FEditor.Lines.Count) or(FTempCaret.Y > FEditor.Lines.Count)
|
|
then
|
|
exit;
|
|
FEditor.TopLine := FTempTopLine;
|
|
FEditor.CaretXY := FTempCaret;
|
|
end;
|
|
|
|
Procedure TSourceEditor.ProcessCommand(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
|
|
// these are normal commands for synedit (lower than ecUserFirst),
|
|
// define extra actions here
|
|
// for non synedit keys (bigger than ecUserFirst) use ProcessUserCommand
|
|
var
|
|
AddChar: Boolean;
|
|
s: String;
|
|
begin
|
|
//DebugLn('TSourceEditor.ProcessCommand Command=',dbgs(Command));
|
|
FSharedValues.SetActiveSharedEditor(Self);
|
|
SourceCompletionTimer.AutoEnabled:=false;
|
|
|
|
if (Command=ecChar) and (AChar=#27) then begin
|
|
// close hint windows
|
|
if (CodeContextFrm<>nil) then
|
|
CodeContextFrm.Hide;
|
|
if (SrcEditHintWindow<>nil) then
|
|
SrcEditHintWindow.Hide;
|
|
end;
|
|
|
|
if (FSourceNoteBook<>nil)
|
|
and (snIncrementalFind in FSourceNoteBook.States) then begin
|
|
case Command of
|
|
ecChar:
|
|
begin
|
|
if AChar=#27 then begin
|
|
if (CodeContextFrm<>nil) then
|
|
CodeContextFrm.Hide;
|
|
|
|
FSourceNoteBook.IncrementalSearchStr:='';
|
|
end else
|
|
FSourceNoteBook.IncrementalSearchStr:=
|
|
FSourceNoteBook.IncrementalSearchStr+AChar;
|
|
Command:=ecNone;
|
|
end;
|
|
|
|
ecDeleteLastChar:
|
|
begin
|
|
FSourceNoteBook.IncrementalSearchStr:=
|
|
LeftStr(FSourceNoteBook.IncrementalSearchStr,
|
|
length(FSourceNoteBook.IncrementalSearchStr)-1);
|
|
Command:=ecNone;
|
|
end;
|
|
|
|
ecLineBreak:
|
|
begin
|
|
FSourceNoteBook.EndIncrementalFind;
|
|
Command:=ecNone;
|
|
end;
|
|
|
|
ecPaste:
|
|
begin
|
|
s:=Clipboard.AsText;
|
|
s:=copy(s,1,EditorOpts.RightMargin);
|
|
FSourceNoteBook.IncrementalSearchStr:=
|
|
FSourceNoteBook.IncrementalSearchStr+s;
|
|
Command:=ecNone;
|
|
end;
|
|
|
|
else
|
|
FSourceNoteBook.EndIncrementalFind;
|
|
end;
|
|
end;
|
|
|
|
case Command of
|
|
|
|
ecSelEditorTop, ecSelEditorBottom, ecEditorTop, ecEditorBottom:
|
|
begin
|
|
if FaOwner<>nil then
|
|
Manager.AddJumpPointClicked(Self);
|
|
end;
|
|
|
|
ecCopy,ecCut:
|
|
begin
|
|
if (not FEditor.SelAvail) then begin
|
|
// nothing selected
|
|
if EditorOpts.CopyWordAtCursorOnCopyNone then begin
|
|
FEditor.SelectWord;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
ecChar:
|
|
begin
|
|
AddChar:=true;
|
|
//debugln(['TSourceEditor.ProcessCommand AChar="',AChar,'" AutoIdentifierCompletion=',dbgs(EditorOpts.AutoIdentifierCompletion),' Interval=',SourceCompletionTimer.Interval,' ',Dbgs(FEditor.CaretXY),' ',FEditor.IsIdentChar(aChar)]);
|
|
if (aChar=' ') and AutoCompleteChar(aChar,AddChar,acoSpace) then begin
|
|
// completed
|
|
end else if (not FEditor.IsIdentChar(aChar))
|
|
and AutoCompleteChar(aChar,AddChar,acoWordEnd) then begin
|
|
// completed
|
|
end else if CodeToolsOpts.IdentComplAutoStartAfterPoint then begin
|
|
// store caret position to detect caret changes
|
|
SourceCompletionCaretXY:=FEditor.CaretXY;
|
|
// add the char
|
|
inc(SourceCompletionCaretXY.x,length(AChar));
|
|
SourceCompletionTimer.AutoEnabled:=true;
|
|
end;
|
|
//DebugLn(['TSourceEditor.ProcessCommand ecChar AddChar=',AddChar]);
|
|
if not AddChar then Command:=ecNone;
|
|
end;
|
|
|
|
ecLineBreak:
|
|
begin
|
|
AddChar:=true;
|
|
if AutoCompleteChar(aChar,AddChar,acoLineBreak) then ;
|
|
//DebugLn(['TSourceEditor.ProcessCommand ecLineBreak AddChar=',AddChar]);
|
|
if not AddChar then Command:=ecNone;
|
|
if EditorOpts.AutoBlockCompletion then
|
|
AutoCompleteBlock;
|
|
end;
|
|
|
|
ecPrevBookmark: // Note: book mark commands lower than ecUserFirst must be handled here
|
|
if Assigned(Manager.OnGotoBookmark) then
|
|
Manager.OnGotoBookmark(Self, -1, True);
|
|
|
|
ecNextBookmark:
|
|
if Assigned(Manager.OnGotoBookmark) then
|
|
Manager.OnGotoBookmark(Self, -1, False);
|
|
|
|
ecGotoMarker0..ecGotoMarker9:
|
|
if Assigned(Manager.OnGotoBookmark) then
|
|
Manager.OnGotoBookmark(Self, Command - ecGotoMarker0, False);
|
|
|
|
ecSetMarker0..ecSetMarker9:
|
|
if Assigned(Manager.OnSetBookmark) then
|
|
Manager.OnSetBookmark(Self, Command - ecSetMarker0, False);
|
|
|
|
ecToggleMarker0..ecToggleMarker9:
|
|
if Assigned(Manager.OnSetBookmark) then
|
|
Manager.OnSetBookmark(Self, Command - ecToggleMarker0, True);
|
|
|
|
ecSelectAll:
|
|
Manager.AddJumpPointClicked(Self);
|
|
|
|
end;
|
|
//debugln('TSourceEditor.ProcessCommand B IdentCompletionTimer.AutoEnabled=',dbgs(SourceCompletionTimer.AutoEnabled));
|
|
end;
|
|
|
|
Procedure TSourceEditor.ProcessUserCommand(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
|
|
// these are the keys above ecUserFirst
|
|
// define all extra keys here, that should not be handled by synedit
|
|
var
|
|
Handled: boolean;
|
|
Begin
|
|
//debugln('TSourceEditor.ProcessUserCommand A ',dbgs(Command));
|
|
FSharedValues.SetActiveSharedEditor(Self);
|
|
Handled:=true;
|
|
|
|
if Manager.ActiveSourceWindow <> SourceNotebook then begin
|
|
debugln('Warning: ActiveSourceWindow is set incorrectly');
|
|
Manager.ActiveSourceWindow := SourceNotebook;
|
|
end;
|
|
|
|
case Command of
|
|
|
|
ecContextHelp:
|
|
FindHelpForSourceAtCursor;
|
|
|
|
ecIdentCompletion :
|
|
StartIdentCompletionBox(true);
|
|
|
|
ecShowCodeContext :
|
|
SourceNotebook.StartShowCodeContext(true);
|
|
|
|
ecWordCompletion :
|
|
StartWordCompletionBox(true);
|
|
|
|
ecFind:
|
|
StartFindAndReplace(false);
|
|
|
|
ecFindNext:
|
|
FindNextUTF8;
|
|
|
|
ecFindPrevious:
|
|
FindPrevious;
|
|
|
|
ecIncrementalFind:
|
|
if FSourceNoteBook<>nil then FSourceNoteBook.BeginIncrementalFind;
|
|
|
|
ecReplace:
|
|
StartFindAndReplace(true);
|
|
|
|
ecGotoLineNumber :
|
|
ShowGotoLineDialog;
|
|
|
|
ecFindNextWordOccurrence:
|
|
FindNextWordOccurrence(true);
|
|
|
|
ecFindPrevWordOccurrence:
|
|
FindNextWordOccurrence(false);
|
|
|
|
ecSelectionEnclose:
|
|
EncloseSelection;
|
|
|
|
ecSelectionUpperCase:
|
|
UpperCaseSelection;
|
|
|
|
ecSelectionLowerCase:
|
|
LowerCaseSelection;
|
|
|
|
ecSelectionTabs2Spaces:
|
|
TabsToSpacesInSelection;
|
|
|
|
ecSelectionComment:
|
|
CommentSelection;
|
|
|
|
ecSelectionUnComment:
|
|
UncommentSelection;
|
|
|
|
ecToggleComment:
|
|
ToggleCommentSelection;
|
|
|
|
ecSelectionConditional:
|
|
ConditionalSelection;
|
|
|
|
ecSelectionSort:
|
|
SortSelection;
|
|
|
|
ecSelectionBreakLines:
|
|
BreakLinesInSelection;
|
|
|
|
ecInvertAssignment:
|
|
InvertAssignment;
|
|
|
|
ecSelectToBrace:
|
|
SelectToBrace;
|
|
|
|
ecSelectCodeBlock:
|
|
SelectCodeBlock;
|
|
|
|
ecSelectLine:
|
|
SelectLine;
|
|
|
|
ecSelectWord:
|
|
SelectWord;
|
|
|
|
ecSelectParagraph:
|
|
SelectParagraph;
|
|
|
|
ecInsertCharacter:
|
|
InsertCharacterFromMap;
|
|
|
|
ecInsertGPLNotice:
|
|
InsertGPLNotice(comtDefault);
|
|
|
|
ecInsertLGPLNotice:
|
|
InsertLGPLNotice(comtDefault);
|
|
|
|
ecInsertModifiedLGPLNotice:
|
|
InsertModifiedLGPLNotice(comtDefault);
|
|
|
|
ecInsertUserName:
|
|
InsertUsername;
|
|
|
|
ecInsertDateTime:
|
|
InsertDateTime;
|
|
|
|
ecInsertChangeLogEntry:
|
|
InsertChangeLogEntry;
|
|
|
|
ecInsertCVSAuthor:
|
|
InsertCVSKeyword('Author');
|
|
|
|
ecInsertCVSDate:
|
|
InsertCVSKeyword('Date');
|
|
|
|
ecInsertCVSHeader:
|
|
InsertCVSKeyword('Header');
|
|
|
|
ecInsertCVSID:
|
|
InsertCVSKeyword('ID');
|
|
|
|
ecInsertCVSLog:
|
|
InsertCVSKeyword('Log');
|
|
|
|
ecInsertCVSName:
|
|
InsertCVSKeyword('Name');
|
|
|
|
ecInsertCVSRevision:
|
|
InsertCVSKeyword('Revision');
|
|
|
|
ecInsertCVSSource:
|
|
InsertCVSKeyword('Source');
|
|
|
|
ecLockEditor:
|
|
IsLocked := not IsLocked;
|
|
|
|
else
|
|
begin
|
|
Handled:=false;
|
|
if FaOwner<>nil then
|
|
TSourceNotebook(FaOwner).ProcessParentCommand(self,Command,aChar,Data,
|
|
Handled);
|
|
end;
|
|
end; //case
|
|
if Handled then Command:=ecNone;
|
|
end;
|
|
|
|
Procedure TSourceEditor.UserCommandProcessed(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer);
|
|
// called after the source editor processed a key
|
|
var Handled: boolean;
|
|
begin
|
|
Handled:=true;
|
|
case Command of
|
|
|
|
ecNone: ;
|
|
|
|
ecChar:
|
|
begin
|
|
if AutoBlockCompleteChar(AChar) then
|
|
Handled:=true;
|
|
end;
|
|
|
|
else
|
|
begin
|
|
Handled:=false;
|
|
if FaOwner<>nil then
|
|
TSourceNotebook(FaOwner).ParentCommandProcessed(Self,Command,aChar,Data,
|
|
Handled);
|
|
end;
|
|
end;
|
|
if Handled then Command:=ecNone;
|
|
end;
|
|
|
|
Procedure TSourceEditor.EditorStatusChanged(Sender: TObject;
|
|
Changes: TSynStatusChanges);
|
|
Begin
|
|
If Assigned(OnEditorChange) then
|
|
OnEditorChange(Sender);
|
|
UpdatePageName;
|
|
end;
|
|
|
|
function TSourceEditor.SelectionAvailable: boolean;
|
|
begin
|
|
Result := EditorComponent.SelAvail;
|
|
end;
|
|
|
|
function TSourceEditor.GetText(OnlySelection: boolean): string;
|
|
begin
|
|
if OnlySelection then
|
|
Result:=EditorComponent.SelText
|
|
else
|
|
Result:=EditorComponent.Lines.Text;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.UpperCaseSelection
|
|
|
|
Turns current text selection uppercase.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.UpperCaseSelection;
|
|
var
|
|
OldBlockBegin, OldBlockEnd: TPoint;
|
|
OldMode: TSynSelectionMode;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
OldMode:=FEditor.SelectionMode;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
FEditor.SelText:=UpperCase(EditorComponent.SelText);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.SelectionMode := OldMode;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.LowerCaseSelection
|
|
|
|
Turns current text selection lowercase.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.LowerCaseSelection;
|
|
var
|
|
OldBlockBegin, OldBlockEnd: TPoint;
|
|
OldMode: TSynSelectionMode;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
OldMode:=FEditor.SelectionMode;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
FEditor.SelText:=LowerCase(EditorComponent.SelText);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.SelectionMode := OldMode;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.TabsToSpacesInSelection
|
|
|
|
Convert all tabs into spaces in current text selection.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.TabsToSpacesInSelection;
|
|
var
|
|
OldBlockBegin, OldBlockEnd: TPoint;
|
|
OldMode: TSynSelectionMode;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
OldMode:=FEditor.SelectionMode;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
// ToDo: replace step by step to keep bookmarks and breakpoints
|
|
FEditor.SelText:=TabsToSpaces(EditorComponent.SelText,
|
|
EditorComponent.TabWidth,FEditor.UseUTF8);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.SelectionMode := OldMode;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.CommentSelection;
|
|
begin
|
|
UpdateCommentSelection(True, False);
|
|
end;
|
|
|
|
procedure TSourceEditor.UncommentSelection;
|
|
begin
|
|
UpdateCommentSelection(False, False);
|
|
end;
|
|
|
|
procedure TSourceEditor.ToggleCommentSelection;
|
|
begin
|
|
UpdateCommentSelection(False, True);
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdateCommentSelection(CommentOn, Toggle: Boolean);
|
|
var
|
|
OldCaretPos, OldBlockStart, OldBlockEnd: TPoint;
|
|
WasSelAvail: Boolean;
|
|
WasSelMode: TSynSelectionMode;
|
|
BlockBeginLine: Integer;
|
|
BlockEndLine: Integer;
|
|
CommonIndent: Integer;
|
|
|
|
function FirstNonBlankPos(const Text: String; Start: Integer = 1): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := Start to Length(Text) do
|
|
if (Text[i] <> #32) and (Text[i] <> #9) then
|
|
exit(i);
|
|
Result := -1;
|
|
end;
|
|
|
|
function MinCommonIndent: Integer;
|
|
var
|
|
i, j: Integer;
|
|
begin
|
|
If CommonIndent = 0 then begin
|
|
CommonIndent := Max(FirstNonBlankPos(FEditor.Lines[BlockBeginLine - 1]), 1);
|
|
for i := BlockBeginLine + 1 to BlockEndLine do begin
|
|
j := FirstNonBlankPos(FEditor.Lines[i - 1]);
|
|
if (j < CommonIndent) and (j > 0) then
|
|
CommonIndent := j;
|
|
end;
|
|
end;
|
|
Result := CommonIndent;
|
|
end;
|
|
|
|
function InsertPos(ALine: Integer): Integer;
|
|
begin
|
|
if not WasSelAvail then
|
|
Result := MinCommonIndent
|
|
else case WasSelMode of
|
|
smColumn: // CommonIndent is not used otherwise
|
|
begin
|
|
if CommonIndent = 0 then
|
|
CommonIndent := Min(FEditor.LogicalToPhysicalPos(OldBlockStart).X,
|
|
FEditor.LogicalToPhysicalPos(OldBlockEnd).X);
|
|
Result := FEditor.PhysicalToLogicalPos(Point(CommonIndent, ALine)).X;
|
|
end;
|
|
smNormal:
|
|
begin
|
|
if OldBlockStart.Y = OldBlockEnd.Y then
|
|
Result := OldBlockStart.X
|
|
else
|
|
Result := MinCommonIndent;
|
|
end;
|
|
else
|
|
Result := 1;
|
|
end;
|
|
end;
|
|
|
|
function DeletePos(ALine: Integer): Integer;
|
|
var
|
|
line: String;
|
|
begin
|
|
line := FEditor.Lines[ALine - 1];
|
|
Result := FirstNonBlankPos(line, InsertPos(ALine));
|
|
if (WasSelMode = smColumn) and((Result < 1) or (Result > length(line) - 1))
|
|
then
|
|
Result := length(line) - 1;
|
|
Result := Max(1, Result);
|
|
if (Length(line) < Result +1) or
|
|
(line[Result] <> '/') or (line[Result+1] <> '/') then
|
|
Result := -1;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
NonBlankStart: Integer;
|
|
begin
|
|
if ReadOnly then exit;
|
|
OldCaretPos := FEditor.CaretXY;
|
|
OldBlockStart := FEditor.BlockBegin;
|
|
OldBlockEnd := FEditor.BlockEnd;
|
|
WasSelAvail := FEditor.SelAvail;
|
|
WasSelMode := FEditor.SelectionMode;
|
|
CommonIndent := 0;
|
|
|
|
BlockBeginLine := OldBlockStart.Y;
|
|
BlockEndLine := OldBlockEnd.Y;
|
|
if (OldBlockEnd.X = 1) and (BlockEndLine > BlockBeginLine) and (FEditor.SelectionMode <> smLine) then
|
|
Dec(BlockEndLine);
|
|
|
|
if Toggle then begin
|
|
CommentOn := False;
|
|
for i := BlockBeginLine to BlockEndLine do
|
|
if DeletePos(i) < 0 then begin
|
|
CommentOn := True;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
BeginUpdate;
|
|
BeginUndoBlock;
|
|
FEditor.SelectionMode := smNormal;
|
|
|
|
if CommentOn then begin
|
|
for i := BlockEndLine downto BlockBeginLine do
|
|
FEditor.TextBetweenPoints[Point(InsertPos(i), i), Point(InsertPos(i), i)] := '//';
|
|
if OldCaretPos.X > InsertPos(OldCaretPos.Y) then
|
|
OldCaretPos.x := OldCaretPos.X + 2;
|
|
if OldBlockStart.X > InsertPos(OldBlockStart.Y) then
|
|
OldBlockStart.X := OldBlockStart.X + 2;
|
|
if OldBlockEnd.X > InsertPos(OldBlockEnd.Y) then
|
|
OldBlockEnd.X := OldBlockEnd.X + 2;
|
|
end
|
|
else begin
|
|
for i := BlockEndLine downto BlockBeginLine do
|
|
begin
|
|
NonBlankStart := DeletePos(i);
|
|
if NonBlankStart < 1 then continue;
|
|
FEditor.TextBetweenPoints[Point(NonBlankStart, i), Point(NonBlankStart + 2, i)] := '';
|
|
if (OldCaretPos.Y = i) and (OldCaretPos.X > NonBlankStart) then
|
|
OldCaretPos.x := Max(OldCaretPos.X - 2, NonBlankStart);
|
|
if (OldBlockStart.Y = i) and (OldBlockStart.X > NonBlankStart) then
|
|
OldBlockStart.X := Max(OldBlockStart.X - 2, NonBlankStart);
|
|
if (OldBlockEnd.Y = i) and (OldBlockEnd.X > NonBlankStart) then
|
|
OldBlockEnd.X := Max(OldBlockEnd.X - 2, NonBlankStart);
|
|
end;
|
|
end;
|
|
|
|
EndUndoBlock;
|
|
EndUpdate;
|
|
|
|
FEditor.CaretXY := OldCaretPos;
|
|
FEditor.BlockBegin := OldBlockStart;
|
|
FEditor.BlockEnd := OldBlockEnd;
|
|
FEditor.SelectionMode := WasSelMode;
|
|
end;
|
|
|
|
procedure TSourceEditor.ConditionalSelection;
|
|
var
|
|
IsPascal: Boolean;
|
|
i: Integer;
|
|
P: TPoint;
|
|
begin
|
|
if ReadOnly then exit;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
if not EditorComponent.SelAvail then begin
|
|
P.Y := FEditor.CaretY;
|
|
P.X := 1;
|
|
FEditor.BlockBegin := P;
|
|
Inc(P.Y);
|
|
FEditor.BlockEnd := P;
|
|
end;
|
|
// ToDo: replace step by step to keep bookmarks and breakpoints
|
|
IsPascal := True;
|
|
i:=EditorOpts.HighlighterList.FindByHighlighter(FEditor.Highlighter);
|
|
if i>=0 then
|
|
IsPascal := EditorOpts.HighlighterList[i].DefaultCommentType <> comtCPP;
|
|
FEditor.SelText:=AddConditional(EditorComponent.SelText,IsPascal);
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.SortSelection;
|
|
var
|
|
OldSelText, NewSortedText: string;
|
|
begin
|
|
if ReadOnly then exit;
|
|
OldSelText:=EditorComponent.SelText;
|
|
if OldSelText='' then exit;
|
|
if ShowSortSelectionDialog(OldSelText,EditorComponent.Highlighter,
|
|
NewSortedText)=mrOk
|
|
then
|
|
EditorComponent.SelText:=NewSortedText;
|
|
end;
|
|
|
|
procedure TSourceEditor.BreakLinesInSelection;
|
|
var
|
|
OldSelection: String;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
// ToDo: replace step by step to keep bookmarks and breakpoints
|
|
OldSelection:=EditorComponent.SelText;
|
|
FEditor.SelText:=BreakLinesInText(OldSelection,FEditor.RightEdge);
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.InvertAssignment;
|
|
var
|
|
codelines: TStringList;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
// ToDo: replace step by step to keep bookmarks and breakpoints
|
|
codelines := TStringList.Create;
|
|
try
|
|
codelines.Text := FEditor.SelText;
|
|
FEditor.SelText := InvertAssignTool.InvertAssignment( codelines ).Text;
|
|
finally
|
|
codelines.Free;
|
|
end;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.SelectToBrace;
|
|
begin
|
|
EditorComponent.SelectToBrace;
|
|
end;
|
|
|
|
procedure TSourceEditor.SelectCodeBlock;
|
|
begin
|
|
// ToDo:
|
|
DebugLn('TSourceEditor.SelectCodeBlock: not implemented yet');
|
|
end;
|
|
|
|
procedure TSourceEditor.SelectWord;
|
|
begin
|
|
EditorComponent.SelectWord;
|
|
end;
|
|
|
|
procedure TSourceEditor.SelectLine;
|
|
begin
|
|
EditorComponent.SelectLine;
|
|
end;
|
|
|
|
procedure TSourceEditor.SelectParagraph;
|
|
begin
|
|
EditorComponent.SelectParagraph;
|
|
end;
|
|
|
|
function TSourceEditor.CommentText(const Txt: string; CommentType: TCommentType
|
|
): string;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result:=Txt;
|
|
case CommentType of
|
|
comtNone: exit;
|
|
comtDefault:
|
|
begin
|
|
i:=EditorOpts.HighlighterList.FindByHighlighter(FEditor.Highlighter);
|
|
if i>=0 then
|
|
CommentType:=EditorOpts.HighlighterList[i].DefaultCommentType;
|
|
end;
|
|
end;
|
|
Result:=IDEProcs.CommentText(Txt,CommentType);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertCharacterFromMap;
|
|
begin
|
|
ShowCharacterMap(@SourceNotebook.InsertCharacter);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertLicenseNotice(const Notice: string;
|
|
CommentType: TCommentType);
|
|
var
|
|
Txt: string;
|
|
begin
|
|
if ReadOnly then Exit;
|
|
Txt:=CommentText(LCLProc.BreakString(
|
|
Format(Notice,[#13#13,#13#13,#13#13,#13#13,#13#13]),
|
|
FEditor.RightEdge-2,0),CommentType);
|
|
FEditor.InsertTextAtCaret(Txt);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertGPLNotice(CommentType: TCommentType);
|
|
begin
|
|
InsertLicenseNotice(lisGPLNotice, CommentType);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertLGPLNotice(CommentType: TCommentType);
|
|
begin
|
|
InsertLicenseNotice(lisLGPLNotice, CommentType);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertModifiedLGPLNotice(CommentType: TCommentType);
|
|
begin
|
|
InsertLicenseNotice(lisModifiedLGPLNotice, CommentType);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertUsername;
|
|
begin
|
|
if ReadOnly then Exit;
|
|
FEditor.InsertTextAtCaret(GetCurrentUserName);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertDateTime;
|
|
begin
|
|
if ReadOnly then Exit;
|
|
FEditor.InsertTextAtCaret(DateTimeToStr(now));
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertChangeLogEntry;
|
|
var s: string;
|
|
begin
|
|
if ReadOnly then Exit;
|
|
s:=DateToStr(now)+' '+GetCurrentUserName+' '+GetCurrentMailAddress;
|
|
FEditor.InsertTextAtCaret(s);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertCVSKeyword(const AKeyWord: string);
|
|
begin
|
|
if ReadOnly then Exit;
|
|
FEditor.InsertTextAtCaret('$'+AKeyWord+'$'+LineEnding);
|
|
end;
|
|
|
|
function TSourceEditor.GetSelEnd: Integer;
|
|
begin
|
|
Result:=FEditor.SelEnd;
|
|
end;
|
|
|
|
function TSourceEditor.GetSelStart: Integer;
|
|
begin
|
|
Result:=FEditor.SelStart;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetSelEnd(const AValue: Integer);
|
|
begin
|
|
FEditor.SelEnd:=AValue;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetSelStart(const AValue: Integer);
|
|
begin
|
|
FEditor.SelStart:=AValue;
|
|
end;
|
|
|
|
function TSourceEditor.GetSelection: string;
|
|
begin
|
|
Result:=FEditor.SelText;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetSelection(const AValue: string);
|
|
begin
|
|
FEditor.SelText:=AValue;
|
|
end;
|
|
|
|
procedure TSourceEditor.CopyToClipboard;
|
|
begin
|
|
FEditor.CopyToClipboard;
|
|
end;
|
|
|
|
procedure TSourceEditor.CutToClipboard;
|
|
begin
|
|
FEditor.CutToClipboard;
|
|
end;
|
|
|
|
procedure TSourceEditor.FindHelpForSourceAtCursor;
|
|
begin
|
|
//DebugLn('TSourceEditor.FindHelpForSourceAtCursor A');
|
|
ShowHelpOrErrorForSourcePosition(Filename,FEditor.LogicalCaretXY);
|
|
end;
|
|
|
|
procedure TSourceEditor.OnGutterClick(Sender: TObject; X, Y, Line: integer;
|
|
mark: TSynEditMark);
|
|
var
|
|
Marks: PSourceMark;
|
|
i, MarkCount: Integer;
|
|
BreakFound: Boolean;
|
|
begin
|
|
// create or delete breakpoint
|
|
// find breakpoint mark at line
|
|
Marks := nil;
|
|
try
|
|
SourceEditorMarks.GetMarksForLine(Self, Line, Marks, MarkCount);
|
|
BreakFound := False;
|
|
for i := 0 to MarkCount - 1 do
|
|
begin
|
|
if Marks[i].IsBreakPoint then
|
|
begin
|
|
BreakFound := True;
|
|
DebugBoss.DoDeleteBreakPointAtMark(Marks[i])
|
|
end;
|
|
end;
|
|
finally
|
|
FreeMem(Marks);
|
|
end;
|
|
|
|
if not BreakFound then
|
|
DebugBoss.DoCreateBreakPoint(Filename, Line, True);
|
|
end;
|
|
|
|
procedure TSourceEditor.OnEditorSpecialLineColor(Sender: TObject; Line: integer;
|
|
var Special: boolean; Markup: TSynSelectedColor);
|
|
var
|
|
i:integer;
|
|
aha: TAdditionalHilightAttribute;
|
|
CurMarks: PSourceMark;
|
|
CurMarkCount: integer;
|
|
CurFG: TColor;
|
|
CurBG: TColor;
|
|
begin
|
|
aha := ahaNone;
|
|
Special := False;
|
|
|
|
if ErrorLine = Line
|
|
then begin
|
|
aha := ahaErrorLine
|
|
end
|
|
else begin
|
|
SourceEditorMarks.GetMarksForLine(Self, Line, CurMarks, CurMarkCount);
|
|
if CurMarkCount > 0 then
|
|
begin
|
|
for i := 0 to CurMarkCount - 1 do
|
|
begin
|
|
if not CurMarks[i].Visible then
|
|
Continue;
|
|
// check highlight attribute
|
|
aha := CurMarks[i].LineColorAttrib;
|
|
if aha <> ahaNone then Break;
|
|
|
|
// check custom colors
|
|
CurFG := CurMarks[i].LineColorForeGround;
|
|
CurBG := CurMarks[i].LineColorBackGround;
|
|
if (CurFG <> clNone) or (CurBG <> clNone) then
|
|
begin
|
|
Markup.Foreground := CurFG;
|
|
Markup.Background := CurBG;
|
|
Special := True;
|
|
break;
|
|
end;
|
|
end;
|
|
// clean up
|
|
FreeMem(CurMarks);
|
|
end;
|
|
end;
|
|
|
|
if aha <> ahaNone
|
|
then begin
|
|
Special := True;
|
|
EditorOpts.SetMarkupColor(TCustomSynEdit(Sender).Highlighter, aha, Markup);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetSyntaxHighlighterType(
|
|
ASyntaxHighlighterType: TLazSyntaxHighlighter);
|
|
begin
|
|
if (ASyntaxHighlighterType=fSyntaxHighlighterType)
|
|
and ((FEditor.Highlighter<>nil) = EditorOpts.UseSyntaxHighlight) then exit;
|
|
|
|
if EditorOpts.UseSyntaxHighlight
|
|
then begin
|
|
if Highlighters[ASyntaxHighlighterType]=nil then begin
|
|
Highlighters[ASyntaxHighlighterType]:=
|
|
EditorOpts.CreateSyn(ASyntaxHighlighterType);
|
|
end;
|
|
FEditor.Highlighter:=Highlighters[ASyntaxHighlighterType];
|
|
end
|
|
else
|
|
FEditor.Highlighter:=nil;
|
|
|
|
FSyntaxHighlighterType:=ASyntaxHighlighterType;
|
|
SourceNotebook.UpdateActiveEditColors(FEditor);
|
|
end;
|
|
|
|
procedure TSourceEditor.SetErrorLine(NewLine: integer);
|
|
begin
|
|
if fErrorLine=NewLine then exit;
|
|
fErrorLine:=NewLine;
|
|
fErrorColumn:=EditorComponent.CaretX;
|
|
EditorComponent.Invalidate;
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdateExecutionSourceMark;
|
|
var
|
|
BreakPoint: TIDEBreakPoint;
|
|
ExecutionMark: TSourceMark;
|
|
BrkMark: TSourceMark;
|
|
begin
|
|
if FSharedValues.UpdatingExecutionMark > 0 then exit;
|
|
ExecutionMark := FSharedValues.ExecutionMark;
|
|
if ExecutionMark = nil then exit;
|
|
|
|
inc(FSharedValues.UpdatingExecutionMark);
|
|
try
|
|
if ExecutionMark.Visible then
|
|
begin
|
|
BrkMark := SourceEditorMarks.FindBreakPointMark(Self, ExecutionLine);
|
|
if BrkMark <> nil then begin
|
|
BrkMark.Visible := False;
|
|
BreakPoint := DebugBoss.BreakPoints.Find(Self.FileName, ExecutionLine);
|
|
if (BreakPoint <> nil) and (not BreakPoint.Enabled) then
|
|
ExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineDisabledBreakPointImg
|
|
else
|
|
ExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineBreakPointImg;
|
|
end
|
|
else
|
|
ExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineImg;
|
|
end;
|
|
finally
|
|
dec(FSharedValues.UpdatingExecutionMark);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetExecutionLine(NewLine: integer);
|
|
begin
|
|
if ExecutionLine=NewLine then exit;
|
|
FSharedValues.SetExecutionLine(NewLine);
|
|
UpdateExecutionSourceMark;
|
|
end;
|
|
|
|
Function TSourceEditor.RefreshEditorSettings: Boolean;
|
|
var
|
|
SimilarEditor: TSynEdit;
|
|
Begin
|
|
Result:=true;
|
|
SetSyntaxHighlighterType(fSyntaxHighlighterType);
|
|
|
|
// try to copy settings from an editor to the left
|
|
SimilarEditor:=nil;
|
|
if (SourceNotebook.EditorCount>0) and (SourceNotebook.Editors[0]<>Self) then
|
|
SimilarEditor:=SourceNotebook.Editors[0].EditorComponent;
|
|
EditorOpts.GetSynEditSettings(FEditor,SimilarEditor);
|
|
|
|
SourceNotebook.UpdateActiveEditColors(FEditor);
|
|
end;
|
|
|
|
Procedure TSourceEditor.ccAddMessage(Texts: String);
|
|
Begin
|
|
ErrorMsgs.Add(Texts);
|
|
End;
|
|
|
|
function TSourceEditor.AutoCompleteChar(Char: TUTF8Char; var AddChar: boolean;
|
|
Category: TAutoCompleteOption): boolean;
|
|
// returns true if handled
|
|
var
|
|
AToken: String;
|
|
i, x1, x2: Integer;
|
|
p: TPoint;
|
|
Line: String;
|
|
CatName: String;
|
|
SrcToken: String;
|
|
IdChars: TSynIdentChars;
|
|
WordToken: String;
|
|
begin
|
|
Result:=false;
|
|
Line:=GetLineText;
|
|
p:=GetCursorTextXY;
|
|
if (p.x>length(Line)+1) or (Line='') then exit;
|
|
CatName:=AutoCompleteOptionNames[Category];
|
|
|
|
FEditor.GetWordBoundsAtRowCol(p, x1, x2);
|
|
// use the token left of the caret
|
|
x2 := Min(x2, p.x);
|
|
WordToken := copy(Line, x1, x2-x1);
|
|
IdChars := FEditor.IdentChars;
|
|
for i:=0 to Manager.CodeTemplateModul.Completions.Count-1 do begin
|
|
AToken:=Manager.CodeTemplateModul.Completions[i];
|
|
if AToken='' then continue;
|
|
if AToken[1] in IdChars then
|
|
SrcToken:=WordToken
|
|
else
|
|
SrcToken:=copy(Line,length(Line)-length(AToken)+1,length(AToken));
|
|
//DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
|
|
if (AnsiCompareText(AToken,SrcToken)=0)
|
|
and (Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)>=0)
|
|
then begin
|
|
Result:=true;
|
|
//DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(CatName)]);
|
|
Manager.CodeTemplateModul.ExecuteCompletion(AToken,FEditor);
|
|
AddChar:=not Manager.CodeTemplateModul.CompletionAttributes[i].IndexOfName(
|
|
AutoCompleteOptionNames[acoRemoveChar])>=0;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if EditorOpts.AutoBlockCompletion
|
|
and (SyntaxHighlighterType in [lshFreePascal,lshDelphi]) then
|
|
Result:=AutoBlockCompleteChar(Char,AddChar,Category,p,Line);
|
|
end;
|
|
|
|
function TSourceEditor.AutoBlockCompleteChar(Char: TUTF8Char;
|
|
var AddChar: boolean; Category: TAutoCompleteOption; aTextPos: TPoint;
|
|
Line: string): boolean;
|
|
// returns true if handled
|
|
var
|
|
x1: integer;
|
|
x2: integer;
|
|
WordToken: String;
|
|
p: LongInt;
|
|
StartPos: integer;
|
|
s: String;
|
|
begin
|
|
Result:=false;
|
|
FEditor.GetWordBoundsAtRowCol(aTextPos, x1, x2);
|
|
// use the token left of the caret
|
|
x2 := Min(x2, aTextPos.x);
|
|
WordToken := copy(Line, x1, x2-x1);
|
|
if (Category in [acoSpace])
|
|
and ((SysUtils.CompareText(WordToken,'if')=0)
|
|
or (SysUtils.CompareText(WordToken,'while')=0)
|
|
or (SysUtils.CompareText(WordToken,'for')=0)
|
|
)
|
|
then begin
|
|
p:=x2;
|
|
ReadRawNextPascalAtom(Line,p,StartPos);
|
|
if SysUtils.CompareText(copy(Line,StartPos,p-StartPos),'begin')=0 then begin
|
|
// 'if begin' => insert 'then'
|
|
// 'while begin' => insert 'do'
|
|
// 'for begin' => insert 'do'
|
|
Result:=true;
|
|
if (SysUtils.CompareText(WordToken,'if')=0) then
|
|
s:='then'
|
|
else
|
|
s:='do';
|
|
s:=' '+CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.BeautifyKeyWord(s);
|
|
if not (Line[x2] in [' ',#9]) then
|
|
s:=s+' ';
|
|
FEditor.BeginUndoBlock;
|
|
FEditor.InsertTextAtCaret(s);
|
|
FEditor.LogicalCaretXY:=aTextPos;
|
|
FEditor.EndUndoBlock;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditor.AutoBlockCompleteChar(Char: TUTF8Char): boolean;
|
|
var
|
|
p: TPoint;
|
|
x1: integer;
|
|
x2: integer;
|
|
Line: String;
|
|
WordToken: String;
|
|
begin
|
|
Result:=false;
|
|
if (not EditorOpts.AutoBlockCompletion)
|
|
or (not (SyntaxHighlighterType in [lshFreePascal,lshDelphi])) then
|
|
exit;
|
|
p:=GetCursorTextXY;
|
|
FEditor.GetWordBoundsAtRowCol(p, x1, x2);
|
|
Line:=GetLineText;
|
|
WordToken := copy(Line, x1, x2-x1);
|
|
if (SysUtils.CompareText(WordToken,'begin')=0)
|
|
then begin
|
|
debugln(['TSourceEditor.AutoBlockCompleteChar ']);
|
|
// user typed 'begin'
|
|
if not LazarusIDE.SaveSourceEditorChangesToCodeCache(self) then exit;
|
|
FEditor.BeginUndoBlock;
|
|
try
|
|
if not CodeToolBoss.CompleteBlock(CodeBuffer,p.X,p.Y,true) then exit;
|
|
finally
|
|
FEditor.EndUndoBlock;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.AutoCompleteBlock;
|
|
var
|
|
XY: TPoint;
|
|
NewCode: TCodeBuffer;
|
|
NewX, NewY, NewTopLine: integer;
|
|
begin
|
|
if not LazarusIDE.SaveSourceEditorChangesToCodeCache(self) then exit;
|
|
XY:=FEditor.LogicalCaretXY;
|
|
FEditor.BeginUndoBlock;
|
|
try
|
|
if not CodeToolBoss.CompleteBlock(CodeBuffer,XY.X,XY.Y,false,
|
|
NewCode,NewX,NewY,NewTopLine) then exit;
|
|
XY:=FEditor.LogicalCaretXY;
|
|
//DebugLn(['TSourceEditor.AutoCompleteBlock XY=',dbgs(XY),' NewX=',NewX,' NewY=',NewY]);
|
|
if (NewCode<>CodeBuffer) or (NewX<>XY.X) or (NewY<>XY.Y) or (NewTopLine>0)
|
|
then begin
|
|
XY.X:=NewX;
|
|
XY.Y:=NewY;
|
|
FEditor.LogicalCaretXY:=XY;
|
|
end;
|
|
finally
|
|
FEditor.EndUndoBlock;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdateNoteBook(const ANewNoteBook: TSourceNotebook; ANewPage: TTabSheet);
|
|
begin
|
|
if FSourceNoteBook = ANewNoteBook then exit;
|
|
|
|
FSourceNoteBook := ANewNoteBook;
|
|
FAOwner := ANewNoteBook;
|
|
FPageName := ANewNoteBook.NoteBookPages[ANewNoteBook.NoteBookIndexOfPage(ANewPage)];
|
|
|
|
// Change the Owner of the SynEdit
|
|
EditorComponent.Owner.RemoveComponent(EditorComponent);
|
|
FSourceNoteBook.InsertComponent(EditorComponent);
|
|
// And the Parent
|
|
EditorComponent.Parent := ANewPage;
|
|
end;
|
|
|
|
{ AOwner is the TSourceNotebook
|
|
AParent is a page of the TPageControl }
|
|
Procedure TSourceEditor.CreateEditor(AOwner: TComponent; AParent: TWinControl);
|
|
var
|
|
NewName: string;
|
|
i: integer;
|
|
bmp: TCustomBitmap;
|
|
Begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceEditor.CreateEditor A ');
|
|
{$ENDIF}
|
|
if not assigned(FEditor) then Begin
|
|
FVisible := False;
|
|
i:=0;
|
|
repeat
|
|
inc(i);
|
|
NewName:='SynEdit'+IntToStr(i);
|
|
until (AOwner.FindComponent(NewName)=nil);
|
|
FEditor := TIDESynEditor.Create(AOwner);
|
|
FEditor.BeginUpdate;
|
|
with FEditor do begin
|
|
Name:=NewName;
|
|
Text:='';
|
|
Align := alClient;
|
|
Visible := False;
|
|
BookMarkOptions.EnableKeys := false;
|
|
BookMarkOptions.LeftMargin:=1;
|
|
BookMarkOptions.BookmarkImages := SourceEditorMarks.ImgList;
|
|
Gutter.MarksPart.DebugMarksImageIndex := SourceEditorMarks.SourceLineImg;
|
|
WantTabs := true;
|
|
ScrollBars := ssAutoBoth;
|
|
|
|
// IMPORTANT: when you change below, don't forget updating UnbindEditor
|
|
OnStatusChange := @EditorStatusChanged;
|
|
OnProcessCommand := @ProcessCommand;
|
|
OnProcessUserCommand := @ProcessUserCommand;
|
|
OnCommandProcessed := @UserCommandProcessed;
|
|
OnReplaceText := @OnReplace;
|
|
OnGutterClick := @Self.OnGutterClick;
|
|
OnSpecialLineMarkup := @OnEditorSpecialLineColor;
|
|
OnMouseMove := @EditorMouseMoved;
|
|
OnMouseWheel := @EditorMouseWheel;
|
|
OnMouseDown := @EditorMouseDown;
|
|
OnClickLink := Manager.OnClickLink;
|
|
OnMouseLink := Manager.OnMouseLink;
|
|
OnKeyDown := @EditorKeyDown;
|
|
OnPaste:=@EditorPaste;
|
|
OnEnter:=@EditorEnter;
|
|
OnPlaceBookmark := @EditorPlaceBookmark;
|
|
OnClearBookmark := @EditorClearBookmark;
|
|
// IMPORTANT: when you change above, don't forget updating UnbindEditor
|
|
Parent := AParent;
|
|
end;
|
|
Manager.CodeTemplateModul.AddEditor(FEditor);
|
|
Manager.NewEditorCreated(self);
|
|
FEditor.TemplateEdit.OnActivate := @EditorActivateSyncro;
|
|
FEditor.TemplateEdit.OnDeactivate := @EditorDeactivateSyncro;
|
|
bmp := CreateBitmapFromLazarusResource('tsynsyncroedit');
|
|
FEditor.SyncroEdit.GutterGlyph.Assign(bmp);
|
|
bmp.Free;
|
|
FEditor.SyncroEdit.OnActivate := @EditorActivateSyncro;
|
|
FEditor.SyncroEdit.OnDeactivate := @EditorDeactivateSyncro;
|
|
|
|
RefreshEditorSettings;
|
|
FEditor.EndUpdate;
|
|
end else begin
|
|
FEditor.Parent:=AParent;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
|
|
begin
|
|
FSharedValues.CodeBuffer := NewCodeBuffer;
|
|
end;
|
|
|
|
procedure TSourceEditor.StartIdentCompletionBox(JumpToError: boolean);
|
|
var
|
|
I: Integer;
|
|
P: TPoint;
|
|
TextS, TextS2: String;
|
|
LogCaret: TPoint;
|
|
UseWordCompletion: Boolean;
|
|
Completion: TSourceEditCompletion;
|
|
begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceEditor.StartIdentCompletionBox JumpToError: ',JumpToError]);
|
|
{$ENDIF}
|
|
if (FEditor.ReadOnly) then exit;
|
|
Completion := Manager.DefaultCompletionForm;
|
|
if (Completion.CurrentCompletionType<>ctNone) then exit;
|
|
Completion.IdentCompletionJumpToError := JumpToError;
|
|
Completion.CurrentCompletionType:=ctIdentCompletion;
|
|
TextS := FEditor.LineText;
|
|
LogCaret:=FEditor.LogicalCaretXY;
|
|
Completion.Editor:=FEditor;
|
|
i := LogCaret.X - 1;
|
|
if i > length(TextS) then
|
|
TextS2 := ''
|
|
else begin
|
|
while (i > 0) and (TextS[i] in ['a'..'z','A'..'Z','0'..'9','_']) do
|
|
dec(i);
|
|
TextS2 := Trim(copy(TextS, i + 1, LogCaret.X - i - 1));
|
|
end;
|
|
with FEditor do begin
|
|
P := Point(CaretXPix - length(TextS2)*CharWidth,CaretYPix + LineHeight + 1);
|
|
P.X:=Max(0,Min(P.X,ClientWidth-Completion.Width));
|
|
P := ClientToScreen(p);
|
|
end;
|
|
UseWordCompletion:=false;
|
|
if not Manager.FindIdentCompletionPlugin
|
|
(Self, JumpToError, TextS2, P.X, P.Y, UseWordCompletion)
|
|
then
|
|
exit;
|
|
if UseWordCompletion then
|
|
Completion.CurrentCompletionType:=ctWordCompletion;
|
|
|
|
Completion.Execute(TextS2,P.X,P.Y);
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceEditor.StartIdentCompletionBox END Completion.TheForm.Visible=',Completion.TheForm.Visible]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceEditor.StartWordCompletionBox(JumpToError: boolean);
|
|
var
|
|
TextS: String;
|
|
LogCaret: TPoint;
|
|
i: Integer;
|
|
TextS2: String;
|
|
P: TPoint;
|
|
Completion: TSourceEditCompletion;
|
|
begin
|
|
if (FEditor.ReadOnly) then exit;
|
|
Completion := Manager.DefaultCompletionForm;
|
|
if (Completion.CurrentCompletionType<>ctNone) then exit;
|
|
Completion.CurrentCompletionType:=ctWordCompletion;
|
|
TextS := FEditor.LineText;
|
|
LogCaret:=FEditor.LogicalCaretXY;
|
|
Completion.Editor:=FEditor;
|
|
i := LogCaret.X - 1;
|
|
if i > length(TextS) then
|
|
TextS2 := ''
|
|
else begin
|
|
while (i > 0) and (TextS[i] in ['a'..'z','A'..'Z','0'..'9','_']) do
|
|
dec(i);
|
|
TextS2 := Trim(copy(TextS, i + 1, LogCaret.X - i - 1));
|
|
end;
|
|
with FEditor do begin
|
|
P := Point(CaretXPix - length(TextS2)*CharWidth,CaretYPix + LineHeight + 1);
|
|
P.X:=Max(0,Min(P.X,ClientWidth - Completion.Width));
|
|
P := ClientToScreen(p);
|
|
end;
|
|
Completion.Execute(TextS2,P.X,P.Y);
|
|
end;
|
|
|
|
procedure TSourceEditor.IncreaseIgnoreCodeBufferLock;
|
|
begin
|
|
FSharedValues.IncreaseIgnoreCodeBufferLock;
|
|
end;
|
|
|
|
procedure TSourceEditor.DecreaseIgnoreCodeBufferLock;
|
|
begin
|
|
FSharedValues.DecreaseIgnoreCodeBufferLock;
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdateCodeBuffer;
|
|
// copy the source from EditorComponent to codetools
|
|
begin
|
|
FSharedValues.UpdateCodeBuffer;
|
|
end;
|
|
|
|
function TSourceEditor.NeedsUpdateCodeBuffer: boolean;
|
|
begin
|
|
Result := FSharedValues.NeedsUpdateCodeBuffer;
|
|
end;
|
|
|
|
Function TSourceEditor.GetSource: TStrings;
|
|
Begin
|
|
//return synedit's source.
|
|
Result := FEditor.Lines;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetIsLocked(const AValue: Boolean);
|
|
begin
|
|
if FIsLocked = AValue then exit;
|
|
FIsLocked := AValue;
|
|
UpdatePageName;
|
|
SourceNotebook.UpdateStatusBar;
|
|
UpdateProjectFile;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetPageName(const AValue: string);
|
|
begin
|
|
if FPageName=AValue then exit;
|
|
FPageName:=AValue;
|
|
UpdatePageName;
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdatePageName;
|
|
var
|
|
p: Integer;
|
|
NewPageName: String;
|
|
begin
|
|
p:=SourceNotebook.FindPageWithEditor(Self);
|
|
if EditorOpts.ShowTabNumbers and (p < 10) then
|
|
// Number pages 1, ..., 9, 0 -- according to Alt+N hotkeys.
|
|
NewPageName:=Format('%s:%d', [FPageName, (p+1) mod 10])
|
|
else
|
|
NewPageName:=FPageName;
|
|
if IsLocked then NewPageName:='#'+NewPageName;
|
|
if Modified then NewPageName:='*'+NewPageName;
|
|
if SourceNotebook.NoteBookPages[p] <> NewPageName then begin
|
|
SourceNotebook.NoteBookPages[p] := NewPageName;
|
|
SourceNotebook.UpdateTabsAndPageTitle;
|
|
end;
|
|
end;
|
|
|
|
Procedure TSourceEditor.SetSource(value: TStrings);
|
|
Begin
|
|
FEditor.Lines.Assign(Value);
|
|
end;
|
|
|
|
Function TSourceEditor.GetCurrentCursorXLine: Integer;
|
|
Begin
|
|
Result := FEditor.CaretX
|
|
end;
|
|
|
|
Procedure TSourceEditor.SetCurrentCursorXLine(num: Integer);
|
|
Begin
|
|
FEditor.CaretX := Num;
|
|
end;
|
|
|
|
Function TSourceEditor.GetCurrentCursorYLine: Integer;
|
|
Begin
|
|
Result := FEditor.CaretY;
|
|
end;
|
|
|
|
Procedure TSourceEditor.SetCurrentCursorYLine(num: Integer);
|
|
Begin
|
|
FEditor.CaretY := Num;
|
|
end;
|
|
|
|
Procedure TSourceEditor.SelectText(const StartPos, EndPos: TPoint);
|
|
Begin
|
|
FEditor.BlockBegin := StartPos;
|
|
FEditor.BlockEnd := EndPos;
|
|
end;
|
|
|
|
procedure TSourceEditor.ReplaceLines(StartLine, EndLine: integer;
|
|
const NewText: string);
|
|
begin
|
|
if ReadOnly then Exit;
|
|
FEditor.TextBetweenPointsEx[Point(1,StartLine),
|
|
Point(length(FEditor.Lines[Endline-1])+1,EndLine),
|
|
scamEnd] := NewText;
|
|
end;
|
|
|
|
procedure TSourceEditor.EncloseSelection;
|
|
var
|
|
EncloseType: TEncloseSelectionType;
|
|
EncloseTemplate: string;
|
|
NewSelection: string;
|
|
NewCaretXY: TPoint;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not FEditor.SelAvail then
|
|
exit;
|
|
if ShowEncloseSelectionDialog(EncloseType)<>mrOk then exit;
|
|
GetEncloseSelectionParams(EncloseType,EncloseTemplate);
|
|
EncloseTextSelection(EncloseTemplate,FEditor.Lines,
|
|
FEditor.BlockBegin,FEditor.BlockEnd,
|
|
FEditor.BlockIndent,
|
|
NewSelection,NewCaretXY);
|
|
//writeln('TSourceEditor.EncloseSelection A NewCaretXY=',NewCaretXY.X,',',NewCaretXY.Y,
|
|
// ' "',NewSelection,'"');
|
|
FEditor.SelText:=NewSelection;
|
|
FEditor.LogicalCaretXY:=NewCaretXY;
|
|
end;
|
|
|
|
Function TSourceEditor.GetModified: Boolean;
|
|
Begin
|
|
Result := FSharedValues.Modified;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetModified(const NewValue: Boolean);
|
|
begin
|
|
FSharedValues.SetModified(NewValue);
|
|
end;
|
|
|
|
Function TSourceEditor.GetInsertMode: Boolean;
|
|
Begin
|
|
Result := FEditor.Insertmode;
|
|
end;
|
|
|
|
Function TSourceEditor.Close: Boolean;
|
|
Begin
|
|
Result := True;
|
|
Visible := False;
|
|
Manager.EditorRemoved(Self);
|
|
SourceEditorMarks.DeleteAllForEditor(Self);
|
|
UnbindEditor;
|
|
FEditor.Parent:=nil;
|
|
if FSharedValues.SharedEditorCount = 1 then
|
|
CodeBuffer := nil;
|
|
end;
|
|
|
|
procedure TSourceEditor.BeginUndoBlock;
|
|
begin
|
|
FEditor.BeginUndoBlock;
|
|
end;
|
|
|
|
procedure TSourceEditor.EndUndoBlock;
|
|
begin
|
|
FEditor.EndUndoBlock;
|
|
end;
|
|
|
|
procedure TSourceEditor.BeginUpdate;
|
|
begin
|
|
FEditor.BeginUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.EndUpdate;
|
|
begin
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.BeginGlobalUpdate;
|
|
begin
|
|
FSharedValues.BeginGlobalUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.EndGlobalUpdate;
|
|
begin
|
|
FSharedValues.EndGlobalUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetPopupMenu(NewPopupMenu: TPopupMenu);
|
|
begin
|
|
if NewPopupMenu<>FPopupMenu then begin
|
|
FPopupMenu:=NewPopupMenu;
|
|
if FEditor<>nil then begin
|
|
if FEditor.PopupMenu <> nil then // Todo: why?
|
|
FEditor.PopupMenu.RemoveFreeNotification(FEditor);
|
|
FEditor.PopupMenu:=NewPopupMenu;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditor.GetFilename: string;
|
|
begin
|
|
if CodeBuffer <> nil then
|
|
Result := CodeBuffer.Filename
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TSourceEditor.GetEditorControl: TWinControl;
|
|
begin
|
|
Result:=FEditor;
|
|
end;
|
|
|
|
function TSourceEditor.GetCodeToolsBuffer: TObject;
|
|
begin
|
|
Result:=CodeBuffer;
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorPaste(Sender: TObject; var AText: String;
|
|
var AMode: TSynSelectionMode; ALogStartPos: TPoint;
|
|
var AnAction: TSynCopyPasteAction);
|
|
var
|
|
p: integer;
|
|
NestedComments: Boolean;
|
|
NewIndent: TFABIndentationPolicy;
|
|
Indent: LongInt;
|
|
NewSrc: string;
|
|
begin
|
|
if AMode<>smNormal then exit;
|
|
if SyncroLockCount > 0 then exit;
|
|
if not CodeToolsOpts.IndentOnPaste then exit;
|
|
if not (SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
|
|
exit;
|
|
{$IFDEF VerboseIndenter}
|
|
debugln(['TSourceEditor.EditorPaste LogCaret=',dbgs(ALogStartPos)]);
|
|
{$ENDIF}
|
|
if ALogStartPos.X>1 then exit;
|
|
UpdateCodeBuffer;
|
|
CodeBuffer.LineColToPosition(ALogStartPos.Y,ALogStartPos.X,p);
|
|
if p<1 then exit;
|
|
{$IFDEF VerboseIndenter}
|
|
if ALogStartPos.Y>1 then
|
|
DebugLn(['TSourceEditor.EditorPaste Y-1=',Lines[ALogStartPos.Y-2]]);
|
|
DebugLn(['TSourceEditor.EditorPaste Y+0=',Lines[ALogStartPos.Y-1]]);
|
|
if ALogStartPos.Y<LineCount then
|
|
DebugLn(['TSourceEditor.EditorPaste Y+1=',Lines[ALogStartPos.Y+0]]);
|
|
{$ENDIF}
|
|
NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuffer.Filename);
|
|
if not CodeToolBoss.Indenter.GetIndent(CodeBuffer.Source,p,NestedComments,
|
|
true,NewIndent,CodeToolsOpts.IndentContextSensitive,AText)
|
|
then exit;
|
|
if not NewIndent.IndentValid then exit;
|
|
Indent:=NewIndent.Indent-GetLineIndentWithTabs(AText,1,EditorComponent.TabWidth);
|
|
{$IFDEF VerboseIndenter}
|
|
debugln(AText);
|
|
DebugLn(['TSourceEditor.EditorPaste Indent=',Indent]);
|
|
{$ENDIF}
|
|
IndentText(AText,Indent,EditorComponent.TabWidth,NewSrc);
|
|
AText:=NewSrc;
|
|
{$IFDEF VerboseIndenter}
|
|
debugln(AText);
|
|
DebugLn(['TSourceEditor.EditorPaste END']);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorPlaceBookmark(Sender: TObject;
|
|
var Mark: TSynEditMark);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FSharedValues.BookmarkEventLock > 0 then exit;
|
|
inc(FSharedValues.BookmarkEventLock);
|
|
try
|
|
for i := 0 to FSharedValues.OtherSharedEditorCount -1 do
|
|
FSharedValues.OtherSharedEditors[Self, i].EditorComponent.SetBookMark
|
|
(Mark.BookmarkNumber, Mark.Column, Mark.Line);
|
|
finally
|
|
dec(FSharedValues.BookmarkEventLock);
|
|
end;
|
|
if Assigned(Manager) and Assigned(Manager.OnPlaceBookmark) then
|
|
Manager.OnPlaceBookmark(Self, Mark);
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorClearBookmark(Sender: TObject;
|
|
var Mark: TSynEditMark);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FSharedValues.BookmarkEventLock > 0 then exit;
|
|
inc(FSharedValues.BookmarkEventLock);
|
|
try
|
|
for i := 0 to FSharedValues.OtherSharedEditorCount -1 do
|
|
FSharedValues.OtherSharedEditors[Self, i].EditorComponent.ClearBookMark(Mark.BookmarkNumber);
|
|
finally
|
|
dec(FSharedValues.BookmarkEventLock);
|
|
end;
|
|
if Assigned(Manager) and Assigned(Manager.OnClearBookmark) then
|
|
Manager.OnClearBookmark(Self, Mark);
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorEnter(Sender: TObject);
|
|
begin
|
|
if (FSourceNoteBook.FUpdateLock <> 0) or
|
|
(FSourceNoteBook.FFocusLock <> 0)
|
|
then exit;
|
|
if (FSourceNoteBook.PageIndex = PageIndex) then
|
|
Activate
|
|
else
|
|
SourceNotebook.GetActiveSE.FocusEditor;
|
|
// Navigating with mousebuttons between editors (eg jump history on btn 4/5)
|
|
// can trigger the old editor to be refocused (while not visible)
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorActivateSyncro(Sender: TObject);
|
|
begin
|
|
inc(FSyncroLockCount);
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorDeactivateSyncro(Sender: TObject);
|
|
begin
|
|
dec(FSyncroLockCount);
|
|
end;
|
|
|
|
function TSourceEditor.GetCodeBuffer: TCodeBuffer;
|
|
begin
|
|
Result := FSharedValues.CodeBuffer;
|
|
end;
|
|
|
|
function TSourceEditor.GetExecutionLine: integer;
|
|
begin
|
|
Result := FSharedValues.ExecutionLine;
|
|
end;
|
|
|
|
function TSourceEditor.GetHasExecutionMarks: Boolean;
|
|
begin
|
|
Result := EditorComponent.IDEGutterMarks.HasDebugMarks;
|
|
end;
|
|
|
|
function TSourceEditor.GetSharedEditors(Index: Integer): TSourceEditor;
|
|
begin
|
|
Result := FSharedValues.SharedEditors[Index];
|
|
end;
|
|
|
|
Procedure TSourceEditor.EditorMouseMoved(Sender: TObject;
|
|
Shift: TShiftState; X,Y: Integer);
|
|
begin
|
|
// Writeln('MouseMove in Editor',X,',',Y);
|
|
if Assigned(OnMouseMove) then
|
|
OnMouseMove(Self,Shift,X,Y);
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorMouseWheel(Sender: TObject; Shift: TShiftState;
|
|
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
begin
|
|
// Writeln('MouseWheel in Editor');
|
|
if Assigned(OnMouseWheel) then
|
|
OnMouseWheel(Self, Shift, WheelDelta, MousePos, Handled)
|
|
end;
|
|
|
|
Procedure TSourceEditor.EditorMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
if Assigned(OnMouseDown) then
|
|
OnMouseDown(Sender, Button, Shift, X,Y);
|
|
end;
|
|
|
|
Procedure TSourceEditor.EditorKeyDown(Sender: TObject; var Key: Word; Shift :
|
|
TShiftState);
|
|
begin
|
|
//DebugLn('TSourceEditor.EditorKeyDown A ',dbgsName(Sender),' ',IntToStr(Key));
|
|
if Assigned(OnKeyDown) then
|
|
OnKeyDown(Sender, Key, Shift);
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.CenterCursor
|
|
Params: none
|
|
Result: none
|
|
|
|
Center the current cursor line in editor.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.CenterCursor(SoftCenter: Boolean = False);
|
|
var
|
|
Y, CurTopLine, LinesInWin, MinLines, NewTopLine: Integer;
|
|
begin
|
|
LinesInWin := EditorComponent.LinesInWindow;
|
|
CurTopLine := EditorComponent.TopView;
|
|
Y := EditorComponent.TextIndexToViewPos(EditorComponent.CaretY);
|
|
|
|
if SoftCenter then begin
|
|
MinLines := Min(
|
|
Min( Max(LinesInWin div SoftCenterFactor, SoftCenterMinimum),
|
|
SoftCenterMaximum),
|
|
Max(LinesInWin div 2 - 1, 0) // make sure there is at least one line in the soft center
|
|
);
|
|
|
|
if (Y <= CurTopLine) or (Y >= CurTopLine + LinesInWin) then
|
|
// Caret not yet visible => hard-center
|
|
NewTopLine := Max(1, Y - (LinesInWin div 2))
|
|
else
|
|
if Y < CurTopLine + MinLines then
|
|
NewTopLine := Max(1, Y - MinLines)
|
|
else
|
|
if Y > CurTopLine + LinesInWin - MinLines then
|
|
NewTopLine := Max(1, Y - LinesInWin + MinLines)
|
|
else
|
|
NewTopLine := CurTopLine;
|
|
end
|
|
else
|
|
// not using SoftCenter
|
|
NewTopLine := Max(1, Y - (LinesInWin div 2));
|
|
|
|
if NewTopLine < 1 then NewTopLine := 1;
|
|
EditorComponent.TopView := NewTopLine;
|
|
end;
|
|
|
|
function TSourceEditor.TextToScreenPosition(const Position: TPoint): TPoint;
|
|
begin
|
|
Result:=FEditor.LogicalToPhysicalPos(Position);
|
|
end;
|
|
|
|
function TSourceEditor.ScreenToTextPosition(const Position: TPoint): TPoint;
|
|
begin
|
|
Result:=FEditor.PhysicalToLogicalPos(Position);
|
|
end;
|
|
|
|
function TSourceEditor.ScreenToPixelPosition(const Position: TPoint): TPoint;
|
|
begin
|
|
Result:=FEditor.RowColumnToPixels(Position);
|
|
end;
|
|
|
|
function TSourceEditor.LineCount: Integer;
|
|
begin
|
|
Result:=FEditor.Lines.Count;
|
|
end;
|
|
|
|
function TSourceEditor.WidthInChars: Integer;
|
|
begin
|
|
Result:=FEditor.CharsInWindow;
|
|
end;
|
|
|
|
function TSourceEditor.HeightInLines: Integer;
|
|
begin
|
|
Result:=FEditor.LinesInWindow;
|
|
end;
|
|
|
|
function TSourceEditor.CharWidth: integer;
|
|
begin
|
|
Result:=FEditor.CharWidth;
|
|
end;
|
|
|
|
function TSourceEditor.GetLineText: string;
|
|
begin
|
|
Result:=FEditor.LineText;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetLineText(const AValue: string);
|
|
begin
|
|
FEditor.LineText:=AValue;
|
|
end;
|
|
|
|
function TSourceEditor.GetLines: TStrings;
|
|
begin
|
|
Result:=FEditor.Lines;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetLines(const AValue: TStrings);
|
|
begin
|
|
FEditor.Lines:=AValue;
|
|
end;
|
|
|
|
function TSourceEditor.GetProjectFile: TLazProjectFile;
|
|
begin
|
|
Result:=LazarusIDE.GetProjectFileForProjectEditor(Self);
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdateProjectFile;
|
|
begin
|
|
if Assigned(Manager) and Assigned(Manager.OnEditorMoved)
|
|
then Manager.OnEditorMoved(self);
|
|
end;
|
|
|
|
function TSourceEditor.GetDesigner(LoadForm: boolean): TIDesigner;
|
|
begin
|
|
Result:=LazarusIDE.GetDesignerForProjectEditor(Self, LoadForm)
|
|
end;
|
|
|
|
function TSourceEditor.GetCursorScreenXY: TPoint;
|
|
begin
|
|
Result:=FEditor.CaretXY;
|
|
end;
|
|
|
|
function TSourceEditor.GetCursorTextXY: TPoint;
|
|
begin
|
|
Result:=FEditor.LogicalCaretXY;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetCursorScreenXY(const AValue: TPoint);
|
|
begin
|
|
FEditor.CaretXY:=AValue;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetCursorTextXY(const AValue: TPoint);
|
|
begin
|
|
FEditor.LogicalCaretXY:=AValue;
|
|
end;
|
|
|
|
function TSourceEditor.GetBlockBegin: TPoint;
|
|
begin
|
|
Result:=FEditor.BlockBegin;
|
|
end;
|
|
|
|
function TSourceEditor.GetBlockEnd: TPoint;
|
|
begin
|
|
Result:=FEditor.BlockEnd;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetBlockBegin(const AValue: TPoint);
|
|
begin
|
|
FEditor.BlockBegin:=AValue;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetBlockEnd(const AValue: TPoint);
|
|
begin
|
|
FEditor.BlockEnd:=AValue;
|
|
end;
|
|
|
|
function TSourceEditor.GetTopLine: Integer;
|
|
begin
|
|
Result:=FEditor.TopLine;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetTopLine(const AValue: Integer);
|
|
begin
|
|
FEditor.TopLine:=AValue;
|
|
end;
|
|
|
|
function TSourceEditor.CursorInPixel: TPoint;
|
|
begin
|
|
Result:=Point(FEditor.CaretXPix,FEditor.CaretYPix);
|
|
end;
|
|
|
|
function TSourceEditor.IsCaretOnScreen(ACaret: TPoint; UseSoftCenter: Boolean = False): Boolean;
|
|
var
|
|
LinesInWin, MinLines, CurTopLine, Y: Integer;
|
|
begin
|
|
LinesInWin := EditorComponent.LinesInWindow;
|
|
CurTopLine := EditorComponent.TopView;
|
|
Y := EditorComponent.TextIndexToViewPos(ACaret.Y);
|
|
if UsesoftCenter then begin
|
|
MinLines := Min(
|
|
Min( Max(LinesInWin div SoftCenterFactor, SoftCenterMinimum),
|
|
SoftCenterMaximum),
|
|
Max(LinesInWin div 2 - 1, 0) // make sure there is at least one line in the soft center
|
|
);
|
|
end
|
|
else
|
|
MinLines := 0;
|
|
|
|
Result := (Y >= CurTopLine + MinLines) and
|
|
(Y <= CurTopLine + LinesInWin - MinLines) and
|
|
(ACaret.X >= FEditor.LeftChar) and
|
|
(ACaret.X <= FEditor.LeftChar + FEditor.CharsInWindow);
|
|
end;
|
|
|
|
function TSourceEditor.SearchReplace(const ASearch, AReplace: string;
|
|
SearchOptions: TSrcEditSearchOptions): integer;
|
|
const
|
|
SrcEdit2SynEditSearchOption: array[TSrcEditSearchOption] of TSynSearchOption =(
|
|
ssoMatchCase,
|
|
ssoWholeWord,
|
|
ssoBackwards,
|
|
ssoEntireScope,
|
|
ssoSelectedOnly,
|
|
ssoReplace,
|
|
ssoReplaceAll,
|
|
ssoPrompt,
|
|
ssoRegExpr,
|
|
ssoRegExprMultiLine
|
|
);
|
|
var
|
|
OldOptions, NewOptions: TSynSearchOptions;
|
|
o: TSrcEditSearchOption;
|
|
begin
|
|
OldOptions:=LazFindReplaceDialog.Options;
|
|
NewOptions:=[];
|
|
for o:=Low(TSrcEditSearchOption) to High(TSrcEditSearchOption) do
|
|
if o in SearchOptions then
|
|
Include(NewOptions,SrcEdit2SynEditSearchOption[o]);
|
|
LazFindReplaceDialog.Options:=NewOptions;
|
|
Result:=DoFindAndReplace;
|
|
LazFindReplaceDialog.Options:=OldOptions;
|
|
end;
|
|
|
|
function TSourceEditor.GetSourceText: string;
|
|
begin
|
|
Result:=FEditor.Text;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetSourceText(const AValue: string);
|
|
begin
|
|
FEditor.Text:=AValue;
|
|
end;
|
|
|
|
procedure TSourceEditor.Activate;
|
|
begin
|
|
{ $note: avoid this if FSourceNoteBook.FUpdateLock > 0 / e.g. debugger calls ProcessMessages, and the internall Index is lost/undone}
|
|
if (FSourceNoteBook=nil) then exit;
|
|
if (FSourceNoteBook.FUpdateLock = 0) then
|
|
FSourceNoteBook.ActiveEditor := Self;
|
|
end;
|
|
|
|
function TSourceEditor.PageIndex: integer;
|
|
begin
|
|
if FSourceNoteBook<>nil then
|
|
Result:=FSourceNoteBook.FindPageWithEditor(Self)
|
|
else
|
|
Result:=-1;
|
|
end;
|
|
|
|
function TSourceEditor.CaretInSelection(const ACaretPos: TPoint): Boolean;
|
|
begin
|
|
Result := (CompareCaret(EditorComponent.BlockBegin, ACaretpos) >= 0)
|
|
and (CompareCaret(ACaretPos, EditorComponent.BlockEnd) >= 0);
|
|
end;
|
|
|
|
function TSourceEditor.IsActiveOnNoteBook: boolean;
|
|
begin
|
|
if FSourceNoteBook<>nil then
|
|
Result:=(FSourceNoteBook.GetActiveSE=Self)
|
|
else
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TSourceEditor.FillExecutionMarks;
|
|
var
|
|
ASource: String;
|
|
i, idx: integer;
|
|
Addr: TDBGPtr;
|
|
begin
|
|
if EditorComponent.IDEGutterMarks.HasDebugMarks then Exit;
|
|
|
|
ASource := FileName;
|
|
idx := DebugBoss.LineInfo.IndexOf(ASource);
|
|
if (idx = -1) then
|
|
begin
|
|
if not FSharedValues.MarksRequested then
|
|
begin
|
|
FSharedValues.MarksRequested := True;
|
|
DebugBoss.LineInfo.AddNotification(FLineInfoNotification);
|
|
DebugBoss.LineInfo.Request(ASource);
|
|
end;
|
|
Exit;
|
|
end;
|
|
|
|
for i := 0 to EditorComponent.Lines.Count - 1 do
|
|
begin
|
|
Addr := DebugBoss.LineInfo.GetAddress(idx, i);
|
|
if (Addr <> 0) then
|
|
EditorComponent.IDEGutterMarks.SetDebugMarks(i, i);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.ClearExecutionMarks;
|
|
begin
|
|
EditorComponent.IDEGutterMarks.ClearDebugMarks;
|
|
FSharedValues.MarksRequested := False;
|
|
if (FLineInfoNotification <> nil) and (DebugBoss <> nil) and (DebugBoss.LineInfo <> nil) then
|
|
DebugBoss.LineInfo.RemoveNotification(FLineInfoNotification);
|
|
end;
|
|
|
|
procedure TSourceEditor.LineInfoNotificationChange(const ASender: TObject; const ASource: String);
|
|
begin
|
|
if ASource = FileName then
|
|
FillExecutionMarks;
|
|
end;
|
|
|
|
function TSourceEditor.SourceToDebugLine(aLinePos: Integer): Integer;
|
|
begin
|
|
Result := FEditor.IDEGutterMarks.SourceLineToDebugLine(aLinePos, True);
|
|
end;
|
|
|
|
function TSourceEditor.DebugToSourceLine(aLinePos: Integer): Integer;
|
|
begin
|
|
Result := FEditor.IDEGutterMarks.DebugLineToSourceLine(aLinePos);
|
|
end;
|
|
|
|
function TSourceEditor.SharedEditorCount: Integer;
|
|
begin
|
|
Result := FSharedValues.SharedEditorCount;
|
|
if Result = 1 then
|
|
Result := 0; // not a sharing editor
|
|
end;
|
|
|
|
function TSourceEditor.GetWordAtCurrentCaret: String;
|
|
var
|
|
CaretPos: TPoint;
|
|
begin
|
|
CaretPos.Y := CurrentCursorYLine;
|
|
CaretPos.X := CurrentCursorXLine;
|
|
Result := GetWordFromCaret(ScreenToTextPosition(CaretPos));
|
|
end;
|
|
|
|
function TSourceEditor.GetOperandFromCaret(const ACaretPos: TPoint): String;
|
|
begin
|
|
if not CodeToolBoss.ExtractOperand(CodeBuffer, ACaretPos.X, ACaretPos.Y,
|
|
Result, False, False, true)
|
|
then
|
|
Result := GetWordFromCaret(ACaretPos);
|
|
end;
|
|
|
|
function TSourceEditor.GetOperandAtCurrentCaret: String;
|
|
var
|
|
CaretPos: TPoint;
|
|
begin
|
|
CaretPos.Y := CurrentCursorYLine;
|
|
CaretPos.X := CurrentCursorXLine;
|
|
Result := GetOperandFromCaret(ScreenToTextPosition(CaretPos));
|
|
end;
|
|
|
|
function TSourceEditor.GetWordFromCaret(const ACaretPos: TPoint): String;
|
|
begin
|
|
Result := FEditor.GetWordAtRowCol(ACaretPos);
|
|
end;
|
|
|
|
procedure TSourceEditor.LinesDeleted(Sender: TObject; FirstLine,
|
|
Count: Integer);
|
|
begin
|
|
// notify the notebook that lines were deleted.
|
|
// marks will use this to update themselves
|
|
if (Self = FSharedValues.SharedEditors[0]) then
|
|
MessagesView.SrcEditLinesInsertedDeleted(Filename,FirstLine,-Count);
|
|
end;
|
|
|
|
procedure TSourceEditor.LinesInserted(Sender: TObject; FirstLine,
|
|
Count: Integer);
|
|
begin
|
|
// notify the notebook that lines were Inserted.
|
|
// marks will use this to update themselves
|
|
if (Self = FSharedValues.SharedEditors[0]) then
|
|
MessagesView.SrcEditLinesInsertedDeleted(Filename,FirstLine,Count);
|
|
end;
|
|
|
|
procedure TSourceEditor.SetVisible(Value: boolean);
|
|
begin
|
|
if FVisible=Value then exit;
|
|
if FEditor<>nil then FEditor.Visible:=Value;
|
|
FVisible:=Value;
|
|
end;
|
|
|
|
procedure TSourceEditor.UnbindEditor;
|
|
// disconnect all events
|
|
var
|
|
i: Integer;
|
|
begin
|
|
with EditorComponent do begin
|
|
OnStatusChange := nil;
|
|
OnProcessCommand := nil;
|
|
OnProcessUserCommand := nil;
|
|
OnCommandProcessed := nil;
|
|
OnReplaceText := nil;
|
|
OnGutterClick := nil;
|
|
OnSpecialLineMarkup := nil;
|
|
OnMouseMove := nil;
|
|
OnMouseWheel := nil;
|
|
OnMouseDown := nil;
|
|
OnClickLink := nil;
|
|
OnMouseLink := nil;
|
|
OnKeyDown := nil;
|
|
OnEnter := nil;
|
|
OnPlaceBookmark := nil;
|
|
OnClearBookmark := nil;
|
|
end;
|
|
for i := 0 to EditorComponent.PluginCount - 1 do
|
|
if EditorComponent.Plugin[i] is TSynPluginSyncronizedEditBase then begin
|
|
TSynPluginSyncronizedEditBase(EditorComponent.Plugin[i]).OnActivate := nil;
|
|
TSynPluginSyncronizedEditBase(EditorComponent.Plugin[i]).OnDeactivate := nil;
|
|
end;
|
|
if FEditPlugin<>nil then begin
|
|
FEditPlugin.OnLinesInserted := nil;
|
|
FEditPlugin.OnLinesDeleted := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.DoEditorExecuteCommand(EditorCommand: word);
|
|
begin
|
|
EditorComponent.CommandProcessor(TSynEditorCommand(EditorCommand),' ',nil);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------}
|
|
{ TSourceNotebook }
|
|
|
|
constructor TSourceNotebook.Create(AOwner: TComponent);
|
|
var
|
|
i: Integer;
|
|
n: TComponent;
|
|
begin
|
|
inherited Create(AOwner);
|
|
FManager := TSourceEditorManager(AOwner);
|
|
FUpdateLock := 0;
|
|
FFocusLock := 0;
|
|
Visible:=false;
|
|
FIsClosing := False;
|
|
i := 2;
|
|
n := Owner.FindComponent(NonModalIDEWindowNames[nmiwSourceNoteBookName]);
|
|
if (n <> nil) and (n <> self) then begin
|
|
while Owner.FindComponent(NonModalIDEWindowNames[nmiwSourceNoteBookName]+IntToStr(i)) <> nil do
|
|
inc(i);
|
|
Name := NonModalIDEWindowNames[nmiwSourceNoteBookName] + IntToStr(i);
|
|
end
|
|
else
|
|
Name := NonModalIDEWindowNames[nmiwSourceNoteBookName];
|
|
|
|
if Manager.SourceWindowCount > 0 then
|
|
FBaseCaption := locWndSrcEditor + ' (' + IntToStr(Manager.SourceWindowCount+1) + ')'
|
|
else
|
|
FBaseCaption := locWndSrcEditor;
|
|
Caption := FBaseCaption;
|
|
KeyPreview:=true;
|
|
FProcessingCommand := false;
|
|
|
|
FSourceEditorList := TList.Create;
|
|
FHistoryList := TList.create;
|
|
|
|
// key mapping
|
|
FKeyStrokes:=TSynEditKeyStrokes.Create(Self);
|
|
EditorOpts.KeyMap.AssignTo(FKeyStrokes,TSourceEditorWindowInterface);
|
|
|
|
// popup menu
|
|
BuildPopupMenu;
|
|
|
|
// HintTimer
|
|
FMouseHintTimer := TIdleTimer.Create(Self);
|
|
with FMouseHintTimer do begin
|
|
Name:=Self.Name+'_MouseHintTimer';
|
|
Interval := EditorOpts.AutoDelayInMSec;
|
|
Enabled := False;
|
|
AutoEnabled := False;
|
|
OnTimer := @HintTimer;
|
|
end;
|
|
|
|
// HintWindow
|
|
FHintWindow := THintWindow.Create(Self);
|
|
with FHintWindow do begin
|
|
Name:=Self.Name+'_HintWindow';
|
|
Visible := False;
|
|
Caption := '';
|
|
HideInterval := 4000;
|
|
AutoHide := False;
|
|
end;
|
|
|
|
FUpdateTabAndPageTimer := TTimer.Create(Self);
|
|
FUpdateTabAndPageTimer.Interval := 500;
|
|
FUpdateTabAndPageTimer.OnTimer := @UpdateTabsAndPageTimeReached;
|
|
|
|
CreateNotebook;
|
|
|
|
Application.AddOnUserInputHandler(@OnApplicationUserInput,true);
|
|
end;
|
|
|
|
destructor TSourceNotebook.Destroy;
|
|
var
|
|
i: integer;
|
|
begin
|
|
if assigned(Manager) then
|
|
Manager.RemoveWindow(Self);
|
|
DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.Destroy'){$ENDIF};
|
|
FProcessingCommand:=false;
|
|
for i:=FSourceEditorList.Count-1 downto 0 do
|
|
Editors[i].Free;
|
|
FKeyStrokes.Free;
|
|
FSourceEditorList.Free;
|
|
FHistoryList.Free;
|
|
|
|
Application.RemoveOnUserInputHandler(@OnApplicationUserInput);
|
|
FreeThenNil(FMouseHintTimer);
|
|
FreeThenNil(FHintWindow);
|
|
FreeAndNil(FNotebook);
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSourceNotebook.DeactivateCompletionForm;
|
|
begin
|
|
Manager.DeactivateCompletionForm;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.CreateNotebook;
|
|
var
|
|
APage: TTabSheet;
|
|
Begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] START');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] A ');
|
|
{$ENDIF}
|
|
FNotebook := TExtendedNotebook.Create(self);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] B');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] B ');
|
|
{$ENDIF}
|
|
with FNotebook do Begin
|
|
Name:='SrcEditNotebook';
|
|
Parent := Self;
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('[TSourceNotebook.CreateNotebook] C');
|
|
{$ENDIF}
|
|
Align := alClient;
|
|
APage:=TTabSheet.Create(FNotebook);
|
|
APage.Caption:='unit1';
|
|
APage.Parent:=FNotebook;
|
|
PageIndex := 0; // Set it to the first page
|
|
if not (nbcPageListPopup in GetCapabilities) then
|
|
PopupMenu := SrcPopupMenu;
|
|
if EditorOpts.ShowTabCloseButtons then
|
|
Options:=Options+[nboShowCloseButtons]
|
|
else
|
|
Options:=Options-[nboShowCloseButtons];
|
|
TabPosition := EditorOpts.TabPosition;
|
|
OnPageChanged := @NotebookPageChanged;
|
|
OnCloseTabClicked:=@CloseTabClicked;
|
|
OnMouseDown:=@NotebookMouseDown;
|
|
TabDragMode := dmAutomatic;
|
|
OnTabDragOverEx := @NotebookCanDragTabMove;
|
|
OnTabDragDropEx := @NotebookDragTabMove;
|
|
OnTabDragOver := @NotebookDragOver;
|
|
OnTabEndDrag := @NotebookEndDrag;
|
|
ShowHint:=true;
|
|
OnShowHint:=@NotebookShowTabHint;
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('[TSourceNotebook.CreateNotebook] D');
|
|
{$ENDIF}
|
|
Visible := False;
|
|
end; //with
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('[TSourceNotebook.CreateNotebook] END');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] END ');
|
|
{$ENDIF}
|
|
End;
|
|
|
|
procedure TSourceNotebook.EditorPropertiesClicked(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnEditorPropertiesClicked) then
|
|
Manager.OnEditorPropertiesClicked(Sender);
|
|
end;
|
|
|
|
type
|
|
TLineEnding = (leLF, leCR, leCRLF);
|
|
const
|
|
LE_Strs : array [TLineEnding] of String = (#10, #13, #13#10);
|
|
|
|
procedure TSourceNotebook.LineEndingClicked(Sender: TObject);
|
|
var
|
|
IDEMenuItem: TIDEMenuItem;
|
|
SrcEdit: TSourceEditor;
|
|
NewLineEnding: String;
|
|
OldLineEnding: String;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
if not (Sender is TIDEMenuItem) then exit;
|
|
if SrcEdit.CodeBuffer=nil then exit;
|
|
|
|
IDEMenuItem:=TIDEMenuItem(Sender);
|
|
NewLineEnding:=LE_Strs[TLineEnding(IDEMenuItem.Tag)];
|
|
DebugLn(['TSourceNotebook.LineEndingClicked NewLineEnding=',NewLineEnding]);
|
|
OldLineEnding:=SrcEdit.CodeBuffer.DiskLineEnding;
|
|
if OldLineEnding='' then
|
|
OldLineEnding:=LineEnding;
|
|
if NewLineEnding<>SrcEdit.CodeBuffer.DiskLineEnding then begin
|
|
DebugLn(['TSourceNotebook.LineEndingClicked Old=',dbgstr(OldLineEnding),' New=',dbgstr(NewLineEnding)]);
|
|
// change file
|
|
SrcEdit.CodeBuffer.DiskLineEnding:=NewLineEnding;
|
|
SrcEdit.CodeBuffer.Source:=
|
|
ChangeLineEndings(SrcEdit.CodeBuffer.Source,NewLineEnding);
|
|
SrcEdit.CodeBuffer.Modified:=true;
|
|
SrcEdit.Modified:=true;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.EncodingClicked(Sender: TObject);
|
|
var
|
|
IDEMenuItem: TIDEMenuItem;
|
|
SrcEdit: TSourceEditor;
|
|
NewEncoding: String;
|
|
OldEncoding: String;
|
|
CurResult: TModalResult;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
if Sender is TIDEMenuItem then begin
|
|
IDEMenuItem:=TIDEMenuItem(Sender);
|
|
NewEncoding:=IDEMenuItem.Caption;
|
|
if SysUtils.CompareText(copy(NewEncoding,1,length(EncodingAnsi)+2),EncodingAnsi+' (')=0
|
|
then begin
|
|
// the ansi encoding is shown as 'ansi (system encoding)' -> cut
|
|
NewEncoding:=EncodingAnsi;
|
|
end else if NewEncoding=lisUtf8WithBOM then begin
|
|
NewEncoding:=EncodingUTF8BOM;
|
|
end;
|
|
DebugLn(['TSourceNotebook.EncodingClicked NewEncoding=',NewEncoding]);
|
|
if SrcEdit.CodeBuffer<>nil then begin
|
|
OldEncoding:=NormalizeEncoding(SrcEdit.CodeBuffer.DiskEncoding);
|
|
if OldEncoding='' then
|
|
OldEncoding:=GetDefaultTextEncoding;
|
|
if NewEncoding<>SrcEdit.CodeBuffer.DiskEncoding then begin
|
|
DebugLn(['TSourceNotebook.EncodingClicked Old=',OldEncoding,' New=',NewEncoding]);
|
|
if SrcEdit.ReadOnly then begin
|
|
if SrcEdit.CodeBuffer.IsVirtual then
|
|
CurResult:=mrCancel
|
|
else
|
|
CurResult:=IDEQuestionDialog(lisChangeEncoding,
|
|
Format(lisEncodingOfFileOnDiskIsNewEncodingIs, ['"',
|
|
SrcEdit.CodeBuffer.Filename, '"', #13, OldEncoding, NewEncoding]),
|
|
mtConfirmation, [mrOk, lisReopenWithAnotherEncoding, mrCancel], '');
|
|
end else begin
|
|
if SrcEdit.CodeBuffer.IsVirtual then
|
|
CurResult:=IDEQuestionDialog(lisChangeEncoding,
|
|
Format(lisEncodingOfFileOnDiskIsNewEncodingIs, ['"',
|
|
SrcEdit.CodeBuffer.Filename, '"', #13, OldEncoding, NewEncoding]),
|
|
mtConfirmation, [mrYes, lisChangeFile, mrCancel], '')
|
|
else
|
|
CurResult:=IDEQuestionDialog(lisChangeEncoding,
|
|
Format(lisEncodingOfFileOnDiskIsNewEncodingIs2, ['"',
|
|
SrcEdit.CodeBuffer.Filename, '"', #13, OldEncoding, NewEncoding]),
|
|
mtConfirmation, [mrYes, lisChangeFile, mrOk,
|
|
lisReopenWithAnotherEncoding, mrCancel], '');
|
|
end;
|
|
if CurResult=mrYes then begin
|
|
// change file
|
|
SrcEdit.CodeBuffer.DiskEncoding:=NewEncoding;
|
|
SrcEdit.CodeBuffer.Modified:=true;
|
|
// set override
|
|
InputHistories.FileEncodings[SrcEdit.CodeBuffer.Filename]:=NewEncoding;
|
|
DebugLn(['TSourceNotebook.EncodingClicked Change file to ',SrcEdit.CodeBuffer.DiskEncoding]);
|
|
if (not SrcEdit.CodeBuffer.IsVirtual)
|
|
and (LazarusIDE.DoSaveEditorFile(SrcEdit, []) <> mrOk)
|
|
then begin
|
|
DebugLn(['TSourceNotebook.EncodingClicked LazarusIDE.DoSaveEditorFile failed']);
|
|
end;
|
|
end else if CurResult=mrOK then begin
|
|
// reopen with another encoding
|
|
if SrcEdit.Modified then begin
|
|
if IDEQuestionDialog(lisAbandonChanges,
|
|
Format(lisAllYourModificationsToWillBeLostAndTheFileReopened, [
|
|
'"', SrcEdit.CodeBuffer.Filename, '"', #13]),
|
|
mtConfirmation,[mbOk,mbAbort],'')<>mrOk
|
|
then begin
|
|
exit;
|
|
end;
|
|
end;
|
|
// set override
|
|
InputHistories.FileEncodings[SrcEdit.CodeBuffer.Filename]:=NewEncoding;
|
|
if not SrcEdit.CodeBuffer.Revert then begin
|
|
IDEMessageDialog(lisCodeToolsDefsReadError,
|
|
Format(lisUnableToRead, [SrcEdit.CodeBuffer.Filename]),
|
|
mtError,[mbCancel],'');
|
|
exit;
|
|
end;
|
|
SrcEdit.EditorComponent.BeginUpdate;
|
|
SrcEdit.CodeBuffer.AssignTo(SrcEdit.EditorComponent.Lines,False);
|
|
SrcEdit.EditorComponent.EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.HighlighterClicked(Sender: TObject);
|
|
var
|
|
IDEMenuItem: TIDEMenuItem;
|
|
i: LongInt;
|
|
SrcEdit: TSourceEditor;
|
|
h: TLazSyntaxHighlighter;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
if Sender is TIDEMenuItem then begin
|
|
IDEMenuItem:=TIDEMenuItem(Sender);
|
|
i:=IDEMenuItem.SectionIndex;
|
|
if (i>=ord(Low(TLazSyntaxHighlighter)))
|
|
and (i<=ord(High(TLazSyntaxHighlighter))) then begin
|
|
h:=TLazSyntaxHighlighter(i);
|
|
SrcEdit.SyntaxHighlighterType:=h;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SrcPopUpMenuPopup(Sender: TObject);
|
|
var
|
|
CurFilename, FileName: String;
|
|
|
|
procedure MaybeAddPopup(const ASuffix: String; const ANewOnClick: TNotifyEvent);
|
|
begin
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,ASuffix)) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(FileName,ASuffix)]),true,ANewOnClick);
|
|
end;
|
|
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
BookMarkID, BookMarkX, BookMarkY: integer;
|
|
MarkSrcEdit: TSourceEditor;
|
|
MarkDesc: String;
|
|
MarkMenuItem: TIDEMenuItem;
|
|
EditorComp: TSynEdit;
|
|
Marks: PSourceMark;
|
|
MarkCount: integer;
|
|
i: Integer;
|
|
NBAvail: Boolean;
|
|
CurMark: TSourceMark;
|
|
EditorPopupPoint, EditorCaret: TPoint;
|
|
SelAvail: Boolean;
|
|
SelAvailAndWritable: Boolean;
|
|
CurWordAtCursor: String;
|
|
AtIdentifier: Boolean;
|
|
begin
|
|
//DebugLn(['TSourceNotebook.SrcPopUpMenuPopup ',dbgsName(Sender)]);
|
|
//SourceEditorMenuRoot.WriteDebugReport('TSourceNotebook.SrcPopUpMenuPopup START ',true);
|
|
//SourceEditorMenuRoot.ConsistencyCheck;
|
|
|
|
SourceEditorMenuRoot.MenuItem:=SrcPopupMenu.Items;
|
|
SourceEditorMenuRoot.BeginUpdate;
|
|
AssignPopupMenu; // Point all on click events to this SourceNoteBook
|
|
try
|
|
RemoveUserDefinedMenuItems;
|
|
RemoveContextMenuItems;
|
|
|
|
ASrcEdit:=
|
|
FindSourceEditorWithEditorComponent(TPopupMenu(Sender).PopupComponent);
|
|
if ASrcEdit=nil then begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then begin
|
|
DebugLn(['TSourceNotebook.SrcPopUpMenuPopup ASrcEdit=nil ',dbgsName(TPopupMenu(Sender).PopupComponent)]);
|
|
exit;
|
|
end;
|
|
end;
|
|
EditorComp:=ASrcEdit.EditorComponent;
|
|
|
|
// Clipboard
|
|
SrcEditMenuCut.Enabled := ASrcEdit.SelectionAvailable and not ASrcEdit.ReadOnly;
|
|
SrcEditMenuCopy.Enabled := ASrcEdit.SelectionAvailable;
|
|
SrcEditMenuPaste.Enabled := not ASrcEdit.ReadOnly;
|
|
|
|
// Readonly, ShowLineNumbers
|
|
SrcEditMenuReadOnly.Checked:=ASrcEdit.ReadOnly;
|
|
SrcEditMenuShowLineNumbers.Checked :=
|
|
EditorComp.Gutter.LineNumberPart.Visible;
|
|
SrcEditMenuDisableI18NForLFM.Visible:=false;
|
|
|
|
UpdateHighlightMenuItems;
|
|
UpdateLineEndingMenuItems;
|
|
UpdateEncodingMenuItems;
|
|
|
|
// bookmarks
|
|
for BookMarkID:=0 to 9 do begin
|
|
MarkDesc:=' '+IntToStr(BookMarkID);
|
|
MarkSrcEdit := nil;
|
|
i := 0;
|
|
while i < Manager.SourceEditorCount do begin
|
|
if Manager.SourceEditors[i].EditorComponent.GetBookMark
|
|
(BookMarkID,BookMarkX,BookMarkY)
|
|
then begin
|
|
MarkDesc := MarkDesc+': ' + Manager.SourceEditors[i].PageName
|
|
+' ('+IntToStr(BookMarkY)+','+IntToStr(BookMarkX)+')';
|
|
break;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
// goto book mark item
|
|
MarkMenuItem:=SrcEditSubMenuGotoBookmarks[BookMarkID];
|
|
if MarkMenuItem is TIDEMenuCommand then
|
|
TIDEMenuCommand(MarkMenuItem).Checked:=(MarkSrcEdit<>nil);
|
|
MarkMenuItem.Caption:=uemBookmarkN+MarkDesc;
|
|
// set book mark item
|
|
MarkMenuItem:=SrcEditSubMenuToggleBookmarks[BookMarkID];
|
|
if MarkMenuItem is TIDEMenuCommand then
|
|
TIDEMenuCommand(MarkMenuItem).Checked:=(MarkSrcEdit<>nil);
|
|
MarkMenuItem.Caption:=uemToggleBookmark+MarkDesc;
|
|
end;
|
|
|
|
// editor layout
|
|
SrcEditMenuMoveEditorLeft.MenuItem.Enabled:= (PageCount>1);
|
|
SrcEditMenuMoveEditorRight.MenuItem.Enabled:= (PageCount>1);
|
|
SrcEditMenuMoveEditorFirst.MenuItem.Enabled:= (PageCount>1) and (PageIndex>0);
|
|
SrcEditMenuMoveEditorLast.MenuItem.Enabled:= (PageCount>1) and (PageIndex<(PageCount-1));
|
|
|
|
EditorPopupPoint:=EditorComp.ScreenToClient(SrcPopUpMenu.PopupPoint);
|
|
if EditorPopupPoint.X>EditorComp.Gutter.Width then begin
|
|
// user clicked on text
|
|
// collect some flags
|
|
SelAvail:=ASrcEdit.EditorComponent.SelAvail;
|
|
SelAvailAndWritable:=SelAvail and (not ASrcEdit.ReadOnly);
|
|
// enable menu items
|
|
SrcEditMenuEncloseSelection.Enabled := SelAvailAndWritable;
|
|
SrcEditMenuExtractProc.Enabled := SelAvailAndWritable;
|
|
SrcEditMenuInvertAssignment.Enabled := SelAvailAndWritable;
|
|
CurWordAtCursor:=ASrcEdit.GetWordAtCurrentCaret;
|
|
AtIdentifier:=IsValidIdent(CurWordAtCursor);
|
|
SrcEditMenuFindIdentifierReferences.Enabled:=AtIdentifier;
|
|
SrcEditMenuRenameIdentifier.Enabled:=AtIdentifier
|
|
and (not ASrcEdit.ReadOnly);
|
|
SrcEditMenuShowAbstractMethods.Enabled:=not ASrcEdit.ReadOnly;
|
|
SrcEditMenuShowEmptyMethods.Enabled:=not ASrcEdit.ReadOnly;
|
|
SrcEditMenuFindOverloads.Enabled:=AtIdentifier;
|
|
end else
|
|
begin
|
|
EditorCaret := EditorComp.PhysicalToLogicalPos(EditorComp.PixelsToRowColumn(EditorPopupPoint));
|
|
// user clicked on gutter
|
|
SourceEditorMarks.GetMarksForLine(ASrcEdit, EditorCaret.y,
|
|
Marks, MarkCount);
|
|
if Marks <> nil then
|
|
begin
|
|
for i := 0 to MarkCount - 1 do
|
|
begin
|
|
CurMark := Marks[i];
|
|
CurMark.CreatePopupMenuItems(@AddUserDefinedPopupMenuItem);
|
|
end;
|
|
FreeMem(Marks);
|
|
end;
|
|
end;
|
|
|
|
// add context specific menu items
|
|
CurFilename:=ASrcEdit.FileName;
|
|
FileName:=ExtractFileName(CurFilename);
|
|
if (FilenameIsAbsolute(CurFilename)) then begin
|
|
if FilenameIsPascalUnit(CurFilename) then begin
|
|
MaybeAddPopup('.lfm', @OnPopupMenuOpenLFMFile);
|
|
MaybeAddPopup('.dfm', @OnPopupMenuOpenDFMFile);
|
|
MaybeAddPopup('.lrs', @OnPopupMenuOpenLRSFile);
|
|
MaybeAddPopup('.s', @OnPopupMenuOpenSFile);
|
|
end;
|
|
if (CompareFileExt(CurFilename,'.lfm',true)=0)
|
|
or (CompareFileExt(CurFilename,'.dfm',true)=0) then begin
|
|
MaybeAddPopup('.pas', @OnPopupMenuOpenPasFile);
|
|
MaybeAddPopup('.pp', @OnPopupMenuOpenPPFile);
|
|
MaybeAddPopup('.p', @OnPopupMenuOpenPFile);
|
|
end;
|
|
if (CompareFileExt(CurFilename,'.lpi',true)=0)
|
|
or (CompareFileExt(CurFilename,'.lpk',true)=0) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,[FileName]),true,@OnPopupMenuOpenFile);
|
|
end;
|
|
|
|
{$IFnDEF SingleSrcWindow}
|
|
// Editor locks
|
|
SrcEditMenuEditorLock.Checked := ASrcEdit.IsLocked;
|
|
// Multi win
|
|
SrcEditMenuMoveToOtherWindowList.Clear;
|
|
NBAvail := False;
|
|
for i := 0 to Manager.SourceWindowCount - 1 do
|
|
if (i <> Manager.IndexOfSourceWindow(self)) and
|
|
(Manager.SourceWindows[i].IndexOfEditorInShareWith(ASrcEdit) < 0)
|
|
then begin
|
|
NBAvail := True;
|
|
with RegisterIDEMenuCommand(SrcEditMenuMoveToOtherWindowList,
|
|
'MoveToWindow'+IntToStr(i),
|
|
Manager.SourceWindows[i].Caption,
|
|
@SrcEditMenuMoveToExistingWindowClicked)
|
|
do
|
|
Tag := i;
|
|
end;
|
|
SrcEditMenuMoveToNewWindow.Visible := not NBAvail;
|
|
SrcEditMenuMoveToNewWindow.Enabled := PageCount > 1;
|
|
SrcEditMenuMoveToOtherWindow.Visible := NBAvail;
|
|
SrcEditMenuMoveToOtherWindowNew.Enabled := (PageCount > 1);
|
|
|
|
NBAvail := False;
|
|
SrcEditMenuCopyToOtherWindowList.Clear;
|
|
for i := 0 to Manager.SourceWindowCount - 1 do
|
|
if (Manager.SourceWindows[i].IndexOfEditorInShareWith(ASrcEdit) < 0) and
|
|
(i <> Manager.IndexOfSourceWindow(self))
|
|
then begin
|
|
NBAvail := True;
|
|
with RegisterIDEMenuCommand(SrcEditMenuCopyToOtherWindowList,
|
|
'CopyToWindow'+IntToStr(i),
|
|
Manager.SourceWindows[i].Caption,
|
|
@SrcEditMenuCopyToExistingWindowClicked)
|
|
do
|
|
Tag := i;
|
|
end;
|
|
SrcEditMenuCopyToNewWindow.Visible := not NBAvail;
|
|
SrcEditMenuCopyToOtherWindow.Visible := NBAvail;
|
|
{$ENDIF}
|
|
|
|
if Assigned(Manager.OnPopupMenu) then Manager.OnPopupMenu(@AddContextPopupMenuItem);
|
|
|
|
SourceEditorMenuRoot.NotifySubSectionOnShow(Self);
|
|
finally
|
|
SourceEditorMenuRoot.EndUpdate;
|
|
end;
|
|
//SourceEditorMenuRoot.WriteDebugReport('TSourceNotebook.SrcPopUpMenuPopup END ',true);
|
|
//SourceEditorMenuRoot.ConsistencyCheck;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NotebookShowTabHint(Sender: TObject;
|
|
HintInfo: PHintInfo);
|
|
var
|
|
Tabindex: integer;
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
if (PageCount=0) or (HintInfo=nil) then exit;
|
|
TabIndex:=FNoteBook.TabIndexAtClientPos(FNotebook.ScreenToClient(Mouse.CursorPos));
|
|
if TabIndex<0 then exit;
|
|
ASrcEdit:=FindSourceEditorWithPageIndex(TabIndex);
|
|
if ASrcEdit=nil then exit;
|
|
if ASrcEdit.CodeBuffer<>nil then begin
|
|
HintInfo^.HintStr:=ASrcEdit.CodeBuffer.Filename;
|
|
end;
|
|
end;
|
|
|
|
function TSourceNotebook.GetItems(Index: integer): TSourceEditorInterface;
|
|
begin
|
|
Result:=TSourceEditorInterface(FSourceEditorList[Index]);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.BuildPopupMenu;
|
|
begin
|
|
//debugln('TSourceNotebook.BuildPopupMenu');
|
|
|
|
SrcPopupMenu := TPopupMenu.Create(Self);
|
|
with SrcPopupMenu do
|
|
begin
|
|
AutoPopup := True;
|
|
OnPopup :=@SrcPopupMenuPopup;
|
|
Images := IDEImages.Images_16;
|
|
end;
|
|
|
|
// assign the root TMenuItem to the registered menu root.
|
|
// This will automatically create all registered items
|
|
{$IFDEF VerboseMenuIntf}
|
|
SrcPopupMenu.Items.WriteDebugReport('TSourceNotebook.BuildPopupMenu ');
|
|
SourceEditorMenuRoot.ConsistencyCheck;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceNotebook.AssignPopupMenu;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
SrcEditMenuFindDeclaration.OnClick:=@FindDeclarationClicked;
|
|
SrcEditMenuProcedureJump.OnClick:=@ProcedureJumpClicked;
|
|
SrcEditMenuFindNextWordOccurrence.OnClick:=@FindNextWordOccurrenceClicked;
|
|
SrcEditMenuFindPrevWordOccurrence.OnClick:=@FindPrevWordOccurrenceClicked;
|
|
SrcEditMenuFindinFiles.OnClick:=@FindInFilesClicked;
|
|
SrcEditMenuOpenFileAtCursor.OnClick:=@OpenAtCursorClicked;
|
|
|
|
SrcEditMenuClosePage.OnClick:=@CloseClicked;
|
|
SrcEditMenuCloseOtherPages.OnClick:=@CloseOtherPagesClicked;
|
|
SrcEditMenuCut.OnClick:=@CutClicked;
|
|
SrcEditMenuCopy.OnClick:=@CopyClicked;
|
|
SrcEditMenuPaste.OnClick:=@PasteClicked;
|
|
SrcEditMenuCopyFilename.OnClick:=@CopyFilenameClicked;
|
|
for i:=0 to 9 do begin
|
|
SrcEditSubMenuGotoBookmarks.FindByName('GotoBookmark'+IntToStr(i))
|
|
.OnClick:=@Manager.BookmarkGotoClicked;
|
|
SrcEditSubMenuToggleBookmarks.FindByName('ToggleBookmark'+IntToStr(i))
|
|
.OnClick:=@Manager.BookMarkToggleClicked;
|
|
end;
|
|
SrcEditMenuSetFreeBookmark.OnClick:=@Manager.BookMarkSetFreeClicked;
|
|
SrcEditMenuNextBookmark.OnClick:=@Manager.BookMarkNextClicked;
|
|
SrcEditMenuPrevBookmark.OnClick:=@Manager.BookMarkPrevClicked;
|
|
|
|
SrcEditMenuToggleBreakpoint.OnClick:=@ToggleBreakpointClicked;
|
|
SrcEditMenuRunToCursor.OnClick:=@RunToClicked;
|
|
SrcEditMenuViewCallStack.OnClick:=@ViewCallStackClick;
|
|
|
|
SrcEditMenuMoveEditorLeft.OnClick:=@MoveEditorLeftClicked;
|
|
SrcEditMenuMoveEditorRight.OnClick:=@MoveEditorRightClicked;
|
|
SrcEditMenuMoveEditorFirst.OnClick:=@MoveEditorFirstClicked;
|
|
SrcEditMenuMoveEditorLast.OnClick:=@MoveEditorLastClicked;
|
|
SrcEditMenuMoveEditorLast.OnClick:=@MoveEditorLastClicked;
|
|
|
|
SrcEditMenuCompleteCode.OnClick:=@CompleteCodeMenuItemClick;
|
|
SrcEditMenuEncloseSelection.OnClick:=@EncloseSelectionMenuItemClick;
|
|
SrcEditMenuExtractProc.OnClick:=@ExtractProcMenuItemClick;
|
|
SrcEditMenuInvertAssignment.OnClick:=@InvertAssignmentMenuItemClick;
|
|
SrcEditMenuFindIdentifierReferences.OnClick:=
|
|
@FindIdentifierReferencesMenuItemClick;
|
|
SrcEditMenuRenameIdentifier.OnClick:=@RenameIdentifierMenuItemClick;
|
|
SrcEditMenuShowAbstractMethods.OnClick:=@ShowAbstractMethodsMenuItemClick;
|
|
SrcEditMenuShowEmptyMethods.OnClick:=@ShowEmptyMethodsMenuItemClick;
|
|
SrcEditMenuShowUnusedUnits.OnClick:=@ShowUnusedUnitsMenuItemClick;
|
|
SrcEditMenuFindOverloads.OnClick:=@FindOverloadsMenuItemClick;
|
|
|
|
SrcEditMenuReadOnly.OnClick:=@ReadOnlyClicked;
|
|
SrcEditMenuShowLineNumbers.OnClick:=@ToggleLineNumbersClicked;
|
|
SrcEditMenuDisableI18NForLFM.OnClick:=@ToggleI18NForLFMClicked;
|
|
SrcEditMenuShowUnitInfo.OnClick:=@ShowUnitInfo;
|
|
SrcEditMenuEditorProperties.OnClick:=@EditorPropertiesClicked;
|
|
|
|
{$IFnDEF SingleSrcWindow}
|
|
// EditorLocks
|
|
SrcEditMenuEditorLock.OnClick := @EditorLockClicked;
|
|
// MultiWin
|
|
SrcEditMenuMoveToNewWindow.OnClick := @SrcEditMenuMoveToNewWindowClicked;
|
|
SrcEditMenuMoveToOtherWindowNew.OnClick := @SrcEditMenuMoveToNewWindowClicked;
|
|
|
|
SrcEditMenuCopyToNewWindow.OnClick := @SrcEditMenuCopyToNewWindowClicked;
|
|
SrcEditMenuCopyToOtherWindowNew.OnClick := @SrcEditMenuCopyToNewWindowClicked;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TSourceNotebook.GetNoteBookPage(Index: Integer): TTabSheet;
|
|
begin
|
|
if FNotebook.Visible then
|
|
Result := FNotebook.Pages[Index]
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceNotebook.GetNotebookPages: TStrings;
|
|
begin
|
|
if FNotebook.Visible then
|
|
Result := TCustomNotebook(FNotebook).Pages
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceNotebook.GetPageCount: Integer;
|
|
begin
|
|
If FNotebook.Visible then
|
|
Result := FNotebook.PageCount
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TSourceNotebook.GetPageIndex: Integer;
|
|
begin
|
|
if FUpdateLock > 0 then
|
|
Result := FPageIndex
|
|
else
|
|
if FNotebook.Visible then
|
|
Result := FNotebook.PageIndex
|
|
else
|
|
Result := -1
|
|
end;
|
|
|
|
procedure TSourceNotebook.SetPageIndex(const AValue: Integer);
|
|
begin
|
|
FPageIndex := AValue;
|
|
if FUpdateLock = 0 then begin
|
|
FPageIndex := Max(0, Min(FPageIndex, FNotebook.PageCount-1));
|
|
if Assigned(Manager) and (FNotebook.PageIndex = FPageIndex) then
|
|
Manager.DoActiveEditorChanged;
|
|
// make sure the statusbar is updated
|
|
Include(States, snNotbookPageChangedNeeded);
|
|
FNotebook.PageIndex := FPageIndex;
|
|
if snNotbookPageChangedNeeded in States then
|
|
NotebookPageChanged(nil);
|
|
HistorySetMostRecent(FNotebook.Pages[FPageIndex]);
|
|
end;
|
|
end;
|
|
|
|
function TSourceNotebook.GetCompletionBoxPosition: integer;
|
|
begin
|
|
Result := Manager.CompletionBoxPosition;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateHighlightMenuItems;
|
|
var
|
|
h: TLazSyntaxHighlighter;
|
|
i: Integer;
|
|
CurName: String;
|
|
CurCaption: String;
|
|
IDEMenuItem: TIDEMenuItem;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEditSubMenuHighlighter.ChildsAsSubMenu:=true;
|
|
SrcEdit:=GetActiveSE;
|
|
i:=0;
|
|
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do begin
|
|
CurName:='Highlighter'+IntToStr(i);
|
|
CurCaption:=LazSyntaxHighlighterNames[h];
|
|
if SrcEditSubMenuHighlighter.Count=i then begin
|
|
// add new item
|
|
IDEMenuItem:=RegisterIDEMenuCommand(SrcEditSubMenuHighlighter,
|
|
CurName,CurCaption,@HighlighterClicked);
|
|
end else begin
|
|
IDEMenuItem:=SrcEditSubMenuHighlighter[i];
|
|
IDEMenuItem.Caption:=CurCaption;
|
|
IDEMenuItem.OnClick:=@HighlighterClicked;
|
|
end;
|
|
if IDEMenuItem is TIDEMenuCommand then
|
|
TIDEMenuCommand(IDEMenuItem).Checked:=(SrcEdit<>nil)
|
|
and (SrcEdit.SyntaxHighlighterType=h);
|
|
inc(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateLineEndingMenuItems;
|
|
var
|
|
le: TLineEnding;
|
|
SrcEdit: TSourceEditor;
|
|
FileEndings: String;
|
|
IDEMenuItem: TIDEMenuCommand;
|
|
const
|
|
LE_Names : array [TLineEnding] of String =(
|
|
'LF (Unix, Linux)',
|
|
'CR (Mac)',
|
|
'CRLF (Win, DOS)'
|
|
);
|
|
begin
|
|
SrcEditSubMenuLineEnding.ChildsAsSubMenu:=true;
|
|
SrcEdit:=GetActiveSE;
|
|
if (SrcEdit<>nil) and (SrcEdit.CodeBuffer<>nil) then
|
|
FileEndings:=SrcEdit.CodeBuffer.DiskLineEnding
|
|
else
|
|
FileEndings:=LineEnding;
|
|
//DebugLn(['TSourceNotebook.UpdateEncodingMenuItems ',Encoding]);
|
|
for le:=low(TLineEnding) to High(TLineEnding) do begin
|
|
if SrcEditSubMenuLineEnding.Count=Ord(le) then begin
|
|
// add new item
|
|
IDEMenuItem:=RegisterIDEMenuCommand(SrcEditSubMenuLineEnding,
|
|
'LineEnding'+IntToStr(Ord(le)),LE_Names[le],@LineEndingClicked);
|
|
end else begin
|
|
IDEMenuItem:=SrcEditSubMenuLineEnding[Ord(le)] as TIDEMenuCommand;
|
|
IDEMenuItem.Caption:=LE_Names[le];
|
|
IDEMenuItem.OnClick:=@LineEndingClicked;
|
|
end;
|
|
IDEMenuItem.Tag:=Ord(le);
|
|
IDEMenuItem.Checked:=(FileEndings=LE_Strs[le]);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdatePageNames;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to PageCount-1 do
|
|
FindSourceEditorWithPageIndex(i).UpdatePageName;
|
|
UpdateTabsAndPageTitle;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateProjectFiles;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to EditorCount - 1 do
|
|
Editors[i].UpdateProjectFile;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateEncodingMenuItems;
|
|
var
|
|
List: TStringList;
|
|
i: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
Encoding: String;
|
|
CurEncoding: string;
|
|
CurName: String;
|
|
CurCaption: String;
|
|
IDEMenuItem: TIDEMenuItem;
|
|
SysEncoding: String;
|
|
begin
|
|
SrcEditSubMenuEncoding.ChildsAsSubMenu:=true;
|
|
SrcEdit:=GetActiveSE;
|
|
Encoding:='';
|
|
if SrcEdit<>nil then begin
|
|
if SrcEdit.CodeBuffer<>nil then
|
|
Encoding:=NormalizeEncoding(SrcEdit.CodeBuffer.DiskEncoding);
|
|
end;
|
|
if Encoding='' then
|
|
Encoding:=GetDefaultTextEncoding;
|
|
//DebugLn(['TSourceNotebook.UpdateEncodingMenuItems ',Encoding]);
|
|
List:=TStringList.Create;
|
|
GetSupportedEncodings(List);
|
|
for i:=0 to List.Count-1 do begin
|
|
CurName:='Encoding'+IntToStr(i);
|
|
CurEncoding:=List[i];
|
|
CurCaption:=CurEncoding;
|
|
if SysUtils.CompareText(CurEncoding,EncodingAnsi)=0 then begin
|
|
SysEncoding:=GetDefaultTextEncoding;
|
|
if (SysEncoding<>'') and (SysUtils.CompareText(SysEncoding,EncodingAnsi)<>0)
|
|
then
|
|
CurCaption:=CurCaption+' ('+GetDefaultTextEncoding+')';
|
|
end;
|
|
if CurEncoding='UTF-8BOM' then begin
|
|
CurCaption:=lisUtf8WithBOM;
|
|
end;
|
|
if SrcEditSubMenuEncoding.Count=i then begin
|
|
// add new item
|
|
IDEMenuItem:=RegisterIDEMenuCommand(SrcEditSubMenuEncoding,
|
|
CurName,CurCaption,@EncodingClicked);
|
|
end else begin
|
|
IDEMenuItem:=SrcEditSubMenuEncoding[i];
|
|
IDEMenuItem.Caption:=CurCaption;
|
|
IDEMenuItem.OnClick:=@EncodingClicked;
|
|
end;
|
|
if IDEMenuItem is TIDEMenuCommand then
|
|
TIDEMenuCommand(IDEMenuItem).Checked:=
|
|
Encoding=NormalizeEncoding(CurEncoding);
|
|
end;
|
|
List.Free;
|
|
end;
|
|
|
|
procedure TSourceNotebook.RemoveUserDefinedMenuItems;
|
|
begin
|
|
SrcEditMenuSectionFirstDynamic.Clear;
|
|
end;
|
|
|
|
function TSourceNotebook.AddUserDefinedPopupMenuItem(const NewCaption: string;
|
|
const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TIDEMenuItem;
|
|
begin
|
|
Result:=RegisterIDEMenuCommand(SrcEditMenuSectionFirstDynamic.GetPath,
|
|
'Dynamic',NewCaption,NewOnClick);
|
|
Result.Enabled:=NewEnabled;
|
|
end;
|
|
|
|
procedure TSourceNotebook.RemoveContextMenuItems;
|
|
begin
|
|
SrcEditMenuSectionFileDynamic.Clear;
|
|
{$IFDEF VerboseMenuIntf}
|
|
SrcEditMenuSectionFileDynamic.WriteDebugReport('TSourceNotebook.RemoveContextMenuItems ');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TSourceNotebook.AddContextPopupMenuItem(const NewCaption: string;
|
|
const NewEnabled: boolean; const NewOnClick: TNotifyEvent): TIDEMenuItem;
|
|
begin
|
|
Result:=RegisterIDEMenuCommand(SrcEditMenuSectionFileDynamic.GetPath,
|
|
'FileDynamic',NewCaption,NewOnClick);
|
|
Result.Enabled:=NewEnabled;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
Procedure TSourceNotebook.EditorChanged
|
|
Params: Sender: TObject
|
|
Result: none
|
|
|
|
Called whenever an editor status changes. Sender is normally a TSynEdit.
|
|
-------------------------------------------------------------------------------}
|
|
Procedure TSourceNotebook.EditorChanged(Sender: TObject);
|
|
var SenderDeleted: boolean;
|
|
Begin
|
|
SenderDeleted:=(Sender as TControl).Parent=nil;
|
|
if SenderDeleted then exit;
|
|
UpdateStatusBar;
|
|
if assigned(Manager) then
|
|
Manager.DoEditorStatusChanged(FindSourceEditorWithEditorComponent(TSynEdit(Sender)));
|
|
End;
|
|
|
|
procedure TSourceNotebook.DoClose(var CloseAction: TCloseAction);
|
|
var
|
|
Layout: TSimpleWindowLayout;
|
|
begin
|
|
//debugln(['TSourceNotebook.DoClose ',DbgSName(Self)]);
|
|
inherited DoClose(CloseAction);
|
|
CloseAction := caHide;
|
|
{$IFnDEF SingleSrcWindow}
|
|
if (PageCount = 0) and (Parent=nil) then begin { $NOTE maybe keep the last one}
|
|
// Make the name unique, because it may not immediately be released
|
|
// => disconnect first
|
|
Layout:=IDEWindowCreators.SimpleLayoutStorage.ItemByForm(Self);
|
|
if Layout<>nil then
|
|
Layout.Form:=nil;
|
|
Name := Name + '___' + IntToStr(PtrUInt(Pointer(Self)));
|
|
CloseAction := caFree;
|
|
end
|
|
else begin
|
|
FIsClosing := True;
|
|
try
|
|
if Assigned(Manager) and Assigned(Manager.OnNoteBookCloseQuery) then
|
|
Manager.OnNoteBookCloseQuery(Self, CloseAction);
|
|
finally
|
|
FIsClosing := False;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceNotebook.DoShow;
|
|
begin
|
|
inherited DoShow;
|
|
// statusbar was not updated when visible=false, update now
|
|
if snUpdateStatusBarNeeded in States then
|
|
UpdateStatusBar;
|
|
end;
|
|
|
|
function TSourceNotebook.IndexOfEditorInShareWith(AnOtherEditor: TSourceEditor
|
|
): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to EditorCount - 1 do
|
|
if Editors[i].IsSharedWith(AnOtherEditor) then
|
|
exit(i);
|
|
Result := -1;
|
|
end;
|
|
|
|
function TSourceNotebook.GetActiveCompletionPlugin: TSourceEditorCompletionPlugin;
|
|
begin
|
|
Result := Manager.ActiveCompletionPlugin;
|
|
end;
|
|
|
|
function TSourceNotebook.CompletionPluginCount: integer;
|
|
begin
|
|
Result := SourceEditorManager.CompletionPluginCount;
|
|
end;
|
|
|
|
procedure TSourceNotebook.RegisterCompletionPlugin(
|
|
Plugin: TSourceEditorCompletionPlugin);
|
|
begin
|
|
// Deprecated; forward to manager
|
|
SourceEditorManager.RegisterCompletionPlugin(Plugin);
|
|
end;
|
|
|
|
procedure TSourceNotebook.UnregisterCompletionPlugin(
|
|
Plugin: TSourceEditorCompletionPlugin);
|
|
begin
|
|
// Deprecated; forward to manager
|
|
SourceEditorManager.UnregisterCompletionPlugin(Plugin);
|
|
end;
|
|
|
|
function TSourceNotebook.GetCompletionPlugins(Index: integer
|
|
): TSourceEditorCompletionPlugin;
|
|
begin
|
|
Result := SourceEditorManager.CompletionPlugins[Index];
|
|
end;
|
|
|
|
function TSourceNotebook.NewSE(PageNum: Integer; NewPageNum: Integer = -1; ASharedEditor: TSourceEditor = nil): TSourceEditor;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE A ');
|
|
{$ENDIF}
|
|
if Pagenum < 0 then begin
|
|
// add a new page right to the current
|
|
if NewPageNum >= 0 then
|
|
PageNum := NewPageNum
|
|
else
|
|
Pagenum := PageIndex+1;
|
|
Pagenum := Max(0,Min(PageNum, PageCount));
|
|
NoteBookInsertPage(PageNum, Manager.FindUniquePageName('', nil));
|
|
NotebookPage[PageNum].ReAlign;
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE B ', PageIndex,',',PagesCount);
|
|
{$ENDIF}
|
|
Result := TSourceEditor.Create(Self, NotebookPage[PageNum], ASharedEditor);
|
|
Result.FPageName := NoteBookPages[Pagenum];
|
|
AcceptEditor(Result);
|
|
PageIndex := Pagenum;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE end ');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceNotebook.AcceptEditor(AnEditor: TSourceEditor);
|
|
begin
|
|
FSourceEditorList.Add(AnEditor);
|
|
|
|
AnEditor.EditorComponent.BeginUpdate;
|
|
AnEditor.PopupMenu := SrcPopupMenu;
|
|
AnEditor.OnEditorChange := @EditorChanged;
|
|
AnEditor.OnMouseMove := @EditorMouseMove;
|
|
AnEditor.OnMouseDown := @EditorMouseDown;
|
|
AnEditor.OnMouseWheel := @EditorMouseWheel;
|
|
AnEditor.OnKeyDown := @EditorKeyDown;
|
|
AnEditor.EditorComponent.Beautifier.OnGetDesiredIndent := @EditorGetIndent;
|
|
AnEditor.EditorComponent.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ReleaseEditor(AnEditor: TSourceEditor);
|
|
begin
|
|
FSourceEditorList.Remove(AnEditor);
|
|
end;
|
|
|
|
function TSourceNotebook.FindSourceEditorWithPageIndex(
|
|
APageIndex: integer): TSourceEditor;
|
|
var I: integer;
|
|
TempEditor: TControl;
|
|
begin
|
|
Result := nil;
|
|
if (FSourceEditorList=nil)
|
|
or (APageIndex < 0) or (APageIndex >= PageCount) then exit;
|
|
TempEditor:=nil;
|
|
with NotebookPage[APageIndex] do
|
|
for I := 0 to ControlCount-1 do
|
|
if Controls[I] is TSynEdit then
|
|
Begin
|
|
TempEditor := Controls[I];
|
|
Break;
|
|
end;
|
|
if TempEditor=nil then exit;
|
|
I := FSourceEditorList.Count-1;
|
|
while (I>=0)
|
|
and (TSourceEditor(FSourceEditorList[I]).EditorComponent <> TempEditor) do
|
|
dec(i);
|
|
if i<0 then exit;
|
|
Result := TSourceEditor(FSourceEditorList[i]);
|
|
end;
|
|
|
|
Function TSourceNotebook.GetActiveSE: TSourceEditor;
|
|
Begin
|
|
Result := nil;
|
|
if (FSourceEditorList=nil) or (FSourceEditorList.Count=0) or (PageIndex<0) then
|
|
exit;
|
|
Result:=FindSourceEditorWithPageIndex(PageIndex);
|
|
end;
|
|
|
|
function TSourceNotebook.GetActiveEditor: TSourceEditorInterface;
|
|
begin
|
|
Result:=GetActiveSE;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SetActiveEditor(const AValue: TSourceEditorInterface
|
|
);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := FindPageWithEditor(AValue as TSourceEditor);
|
|
inc(FFocusLock);
|
|
if i>= 0 then
|
|
PageIndex := i;
|
|
dec(FFocusLock);
|
|
SourceEditorManager.ActiveSourceWindow := self;
|
|
end;
|
|
|
|
procedure TSourceNotebook.CheckCurrentCodeBufferChanged;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
// Todo: Move to manager, include window changes
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit = nil then Exit;
|
|
if FLastCodeBuffer=SrcEdit.CodeBuffer then exit;
|
|
FLastCodeBuffer:=SrcEdit.CodeBuffer;
|
|
if assigned(Manager) and Assigned(Manager.OnCurrentCodeBufferChanged) then
|
|
Manager.OnCurrentCodeBufferChanged(Self);
|
|
end;
|
|
|
|
function TSourceNotebook.GetCapabilities: TNoteBookCapabilities;
|
|
begin
|
|
Result := FNotebook.GetCapabilities
|
|
end;
|
|
|
|
procedure TSourceNotebook.IncUpdateLock;
|
|
begin
|
|
inc(FUpdateLock);
|
|
end;
|
|
|
|
procedure TSourceNotebook.DecUpdateLock;
|
|
begin
|
|
dec(FUpdateLock);
|
|
if FUpdateLock = 0 then
|
|
PageIndex := FPageIndex;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NoteBookInsertPage(Index: Integer; const S: string);
|
|
begin
|
|
if FNotebook.Visible then
|
|
NotebookPages.Insert(Index, S)
|
|
else begin
|
|
IDEWindowCreators.ShowForm(Self,false);
|
|
FNotebook.Visible := True;
|
|
NotebookPages[Index] := S;
|
|
end;
|
|
HistoryAdd(FNotebook.Pages[Index]);
|
|
UpdateTabsAndPageTitle;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NoteBookDeletePage(APageIndex: Integer);
|
|
begin
|
|
if PageCount > 1 then begin
|
|
// make sure to select another page in the NoteBook, otherwise the
|
|
// widgetset will choose one and will send a message
|
|
// if this is the current page, switch to right APageIndex (if possible)
|
|
//todo: determine whether we can use SetPageIndex instead
|
|
HistoryRemove(FNotebook.Pages[APageIndex]);
|
|
if PageIndex = APageIndex then begin
|
|
if EditorOpts.UseTabHistory then
|
|
FPageIndex := HistoryGetTopPageIndex
|
|
else
|
|
FPageIndex := -1;
|
|
// default if not in history or not using history
|
|
if FPageIndex = -1 then
|
|
if APageIndex < PageCount - 1 then
|
|
FPageIndex := APageIndex + 1
|
|
else
|
|
FPageIndex := APageIndex - 1;
|
|
FNoteBook.PageIndex := FPageIndex;
|
|
end;
|
|
NotebookPages.Delete(APageIndex);
|
|
end else
|
|
FNotebook.Visible := False;
|
|
UpdateTabsAndPageTitle;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateTabsAndPageTitle;
|
|
begin
|
|
if (PageCount = 1) and (EditorOpts.HideSingleTabInWindow) then begin
|
|
Caption := FBaseCaption + ': ' + NotebookPages[0];
|
|
FNotebook.ShowTabs := False;
|
|
end else begin
|
|
Caption := FBaseCaption;
|
|
FNotebook.ShowTabs := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateTabsAndPageTimeReached(Sender: TObject);
|
|
begin
|
|
FUpdateTabAndPageTimer.Enabled := False;
|
|
UpdateTabsAndPageTitle;
|
|
end;
|
|
|
|
function TSourceNotebook.NoteBookIndexOfPage(APage: TTabSheet): Integer;
|
|
begin
|
|
Result := FNoteBook.IndexOf(APage);
|
|
end;
|
|
|
|
procedure TSourceNotebook.DragOver(Source: TObject; X, Y: Integer; State: TDragState;
|
|
var Accept: Boolean);
|
|
begin
|
|
FUpdateTabAndPageTimer.Enabled := False;
|
|
inherited DragOver(Source, X, Y, State, Accept);
|
|
if State = dsDragLeave then
|
|
FUpdateTabAndPageTimer.Enabled := True
|
|
else if Source is TExtendedNotebook then
|
|
FNotebook.ShowTabs := True;
|
|
end;
|
|
|
|
procedure TSourceNotebook.DragCanceled;
|
|
begin
|
|
inherited DragCanceled;
|
|
FUpdateTabAndPageTimer.Enabled := True;
|
|
end;
|
|
|
|
procedure TSourceNotebook.BeginIncrementalFind;
|
|
var
|
|
TempEditor: TSourceEditor;
|
|
begin
|
|
if (snIncrementalFind in States)AND not(FIncrementalSearchEditor = nil)
|
|
then begin
|
|
if (IncrementalSearchStr= '') then begin
|
|
FIncrementalSearchStr := FIncrementalFoundStr;
|
|
IncrementalSearch(False, FIncrementalSearchBackwards);
|
|
end
|
|
else IncrementalSearch(True, FIncrementalSearchBackwards);
|
|
exit;
|
|
end;
|
|
|
|
TempEditor:=GetActiveSE;
|
|
if TempEditor = nil then exit;
|
|
Include(States, snIncrementalFind);
|
|
fIncrementalSearchStartPos:=TempEditor.EditorComponent.LogicalCaretXY;
|
|
FIncrementalSearchPos:=fIncrementalSearchStartPos;
|
|
FIncrementalSearchEditor := TempEditor;
|
|
if assigned(FIncrementalSearchEditor.EditorComponent) then
|
|
with FIncrementalSearchEditor.EditorComponent do begin
|
|
UseIncrementalColor:= true;
|
|
if assigned(MarkupByClass[TSynEditMarkupHighlightAllCaret]) then
|
|
MarkupByClass[TSynEditMarkupHighlightAllCaret].TempDisable;
|
|
end;
|
|
|
|
IncrementalSearchStr:='';
|
|
|
|
UpdateStatusBar;
|
|
end;
|
|
|
|
procedure TSourceNotebook.EndIncrementalFind;
|
|
begin
|
|
if not (snIncrementalFind in States) then exit;
|
|
|
|
Exclude(States,snIncrementalFind);
|
|
|
|
if FIncrementalSearchEditor <> nil
|
|
then begin
|
|
if assigned(FIncrementalSearchEditor.EditorComponent) then
|
|
with FIncrementalSearchEditor.EditorComponent do begin
|
|
UseIncrementalColor:= False;
|
|
if assigned(MarkupByClass[TSynEditMarkupHighlightAllCaret]) then
|
|
MarkupByClass[TSynEditMarkupHighlightAllCaret].TempEnable;
|
|
end;
|
|
FIncrementalSearchEditor.EditorComponent.SetHighlightSearch('', []);
|
|
FIncrementalSearchEditor := nil;
|
|
end;
|
|
|
|
LazFindReplaceDialog.FindText:=fIncrementalSearchStr;
|
|
LazFindReplaceDialog.Options:=[];
|
|
UpdateStatusBar;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.NextEditor;
|
|
Begin
|
|
if PageIndex < PageCount-1 then
|
|
PageIndex := PageIndex+1
|
|
else
|
|
PageIndex := 0;
|
|
End;
|
|
|
|
Procedure TSourceNotebook.PrevEditor;
|
|
Begin
|
|
if PageIndex > 0 then
|
|
PageIndex := PageIndex-1
|
|
else
|
|
PageIndex := PageCount-1;
|
|
End;
|
|
|
|
procedure TSourceNotebook.MoveEditor(OldPageIndex, NewPageIndex: integer);
|
|
begin
|
|
if (PageCount<=1)
|
|
or (OldPageIndex=NewPageIndex)
|
|
or (OldPageIndex<0) or (OldPageIndex>=PageCount)
|
|
or (NewPageIndex<0) or (NewPageIndex>=PageCount)
|
|
then
|
|
exit;
|
|
NoteBookPages.Move(OldPageIndex,NewPageIndex);
|
|
UpdatePageNames;
|
|
UpdateProjectFiles;
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorLeft(CurrentPageIndex: integer);
|
|
begin
|
|
if (PageCount<=1) then exit;
|
|
if CurrentPageIndex>0 then
|
|
MoveEditor(CurrentPageIndex, CurrentPageIndex-1)
|
|
else
|
|
MoveEditor(CurrentPageIndex, PageCount-1);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorRight(CurrentPageIndex: integer);
|
|
begin
|
|
if (PageCount<=1) then exit;
|
|
if CurrentPageIndex < PageCount-1 then
|
|
MoveEditor(CurrentPageIndex, CurrentPageIndex+1)
|
|
else
|
|
MoveEditor(CurrentPageIndex, 0);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorFirst(CurrentPageIndex: integer);
|
|
begin
|
|
if (PageCount<=1) then exit;
|
|
MoveEditor(CurrentPageIndex, 0)
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorLast(CurrentPageIndex: integer);
|
|
begin
|
|
if (PageCount<=1) then exit;
|
|
MoveEditor(CurrentPageIndex, PageCount-1);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageLeft;
|
|
begin
|
|
MoveEditorLeft(PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageRight;
|
|
begin
|
|
MoveEditorRight(PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageFirst;
|
|
begin
|
|
MoveEditorFirst(PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageLast;
|
|
begin
|
|
MoveEditorLast(PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.GotoNextWindow(Backward: Boolean);
|
|
begin
|
|
if Backward then begin
|
|
if Manager.IndexOfSourceWindow(Self) > 0 then
|
|
Manager.ActiveSourceWindow := Manager.SourceWindows[Manager.IndexOfSourceWindow(Self)-1]
|
|
else
|
|
Manager.ActiveSourceWindow := Manager.SourceWindows[Manager.SourceWindowCount-1];
|
|
end else begin
|
|
if Manager.IndexOfSourceWindow(Self) < Manager.SourceWindowCount - 1 then
|
|
Manager.ActiveSourceWindow := Manager.SourceWindows[Manager.IndexOfSourceWindow(Self)+1]
|
|
else
|
|
Manager.ActiveSourceWindow := Manager.SourceWindows[0];
|
|
end;
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
|
|
procedure TSourceNotebook.GotoNextSharedEditor(Backward: Boolean = False);
|
|
var
|
|
SrcEd: TSourceEditor;
|
|
i, j: Integer;
|
|
begin
|
|
i := Manager.IndexOfSourceWindow(Self);
|
|
SrcEd := GetActiveSE;
|
|
repeat
|
|
if Backward then dec(i)
|
|
else inc(i);
|
|
if i < 0 then
|
|
i := Manager.SourceWindowCount - 1;
|
|
if i = Manager.SourceWindowCount then
|
|
i := 0;
|
|
j := Manager.SourceWindows[i].IndexOfEditorInShareWith(SrcEd);
|
|
if j >= 0 then begin
|
|
Manager.ActiveEditor := Manager.SourceWindows[i].Editors[j];
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
exit;
|
|
end;
|
|
until Manager.SourceWindows[i] = Self;
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorNextWindow(Backward: Boolean; Copy: Boolean);
|
|
var
|
|
SrcEd: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
i := Manager.IndexOfSourceWindow(Self);
|
|
SrcEd := GetActiveSE;
|
|
repeat
|
|
if Backward then dec(i)
|
|
else inc(i);
|
|
if i < 0 then
|
|
i := Manager.SourceWindowCount - 1;
|
|
if i = Manager.SourceWindowCount then
|
|
i := 0;
|
|
if Manager.SourceWindows[i].IndexOfEditorInShareWith(SrcEd) < 0 then
|
|
break;
|
|
until Manager.SourceWindows[i] = Self;
|
|
if Manager.SourceWindows[i] = Self then exit;
|
|
|
|
if Copy then
|
|
CopyEditor(FindPageWithEditor(GetActiveSE), i, -1)
|
|
else
|
|
MoveEditor(FindPageWithEditor(GetActiveSE), i, -1);
|
|
|
|
Manager.ActiveSourceWindowIndex := i;
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditor(OldPageIndex, NewWindowIndex,
|
|
NewPageIndex: integer);
|
|
var
|
|
DestWin: TSourceNotebook;
|
|
Edit: TSourceEditor;
|
|
begin
|
|
if (NewWindowIndex < 0) or (NewWindowIndex >= Manager.SourceWindowCount) then
|
|
exit;
|
|
DestWin := Manager.SourceWindows[NewWindowIndex];
|
|
if DestWin = self then begin
|
|
MoveEditor(OldPageIndex, NewPageIndex);
|
|
exit
|
|
end;
|
|
|
|
if NewPageIndex < 0 then
|
|
NewPageIndex := DestWin.PageCount;
|
|
if (OldPageIndex<0) or (OldPageIndex>=PageCount) or
|
|
(NewPageIndex<0) or (NewPageIndex>DestWin.PageCount)
|
|
then
|
|
exit;
|
|
|
|
Edit := FindSourceEditorWithPageIndex(OldPageIndex);
|
|
DestWin.NoteBookInsertPage(NewPageIndex, Edit.PageName);
|
|
DestWin.PageIndex := NewPageIndex;
|
|
|
|
ReleaseEditor(Edit);
|
|
Edit.UpdateNoteBook(DestWin, DestWin.NoteBookPage[NewPageIndex]);
|
|
DestWin.AcceptEditor(Edit);
|
|
DestWin.NotebookPage[NewPageIndex].ReAlign;
|
|
|
|
NoteBookDeletePage(OldPageIndex);
|
|
UpdatePageNames;
|
|
UpdateProjectFiles;
|
|
DestWin.UpdatePageNames;
|
|
DestWin.UpdateProjectFiles;
|
|
DestWin.UpdateActiveEditColors(Edit.EditorComponent);
|
|
DestWin.UpdateStatusBar;
|
|
|
|
if (PageCount = 0) and (Parent=nil) and not FIsClosing then
|
|
Close;
|
|
end;
|
|
|
|
procedure TSourceNotebook.CopyEditor(OldPageIndex, NewWindowIndex,
|
|
NewPageIndex: integer; Focus: Boolean = False);
|
|
var
|
|
DestWin: TSourceNotebook;
|
|
SrcEdit, NewEdit: TSourceEditor;
|
|
begin
|
|
if (NewWindowIndex < 0) or (NewWindowIndex >= Manager.SourceWindowCount) then
|
|
exit;
|
|
DestWin := Manager.SourceWindows[NewWindowIndex];
|
|
if DestWin = self then exit;
|
|
|
|
if (OldPageIndex<0) or (OldPageIndex>=PageCount) or
|
|
(NewPageIndex>DestWin.PageCount)
|
|
then
|
|
exit;
|
|
|
|
SrcEdit := FindSourceEditorWithPageIndex(OldPageIndex);
|
|
NewEdit := DestWin.NewSE(-1, NewPageIndex, SrcEdit);
|
|
NewEdit.IsNewSharedEditor := True;
|
|
|
|
NewEdit.PageName := SrcEdit.PageName;
|
|
NewEdit.SyntaxHighlighterType := SrcEdit.SyntaxHighlighterType;
|
|
NewEdit.EditorComponent.TopLine := SrcEdit.EditorComponent.TopLine;
|
|
NewEdit.EditorComponent.CaretXY := SrcEdit.EditorComponent.CaretXY;
|
|
|
|
UpdatePageNames;
|
|
UpdateProjectFiles;
|
|
DestWin.UpdateProjectFiles;
|
|
// Update IsVisibleTab; needs UnitEditorInfo created in DestWin.UpdateProjectFiles
|
|
if Focus then begin
|
|
Manager.ActiveEditor := NewEdit;
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
end;
|
|
Manager.DoActiveEditorChanged;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ActivateHint(const ScreenPos: TPoint;
|
|
const BaseURL, TheHint: string);
|
|
var
|
|
HintWinRect: TRect;
|
|
AHint: String;
|
|
begin
|
|
if csDestroying in ComponentState then exit;
|
|
if FHintWindow<>nil then
|
|
FHintWindow.Visible:=false;
|
|
if FHintWindow=nil then
|
|
FHintWindow:=THintWindow.Create(Self);
|
|
AHint:=TheHint;
|
|
if LazarusHelp.CreateHint(FHintWindow,ScreenPos,BaseURL,AHint,HintWinRect) then
|
|
FHintWindow.ActivateHint(HintWinRect,aHint);
|
|
end;
|
|
|
|
procedure TSourceNotebook.HideHint;
|
|
begin
|
|
//DebugLn(['TSourceNotebook.HideHint ']);
|
|
if FMouseHintTimer<>nil then
|
|
begin
|
|
FMouseHintTimer.AutoEnabled := false;
|
|
FMouseHintTimer.Enabled:=false;
|
|
end;
|
|
if SourceCompletionTimer<>nil then
|
|
SourceCompletionTimer.Enabled:=false;
|
|
if FHintWindow<>nil then
|
|
FHintWindow.Visible:=false;
|
|
end;
|
|
|
|
procedure TSourceNotebook.StartShowCodeContext(JumpToError: boolean);
|
|
var
|
|
Abort: boolean;
|
|
begin
|
|
if assigned(Manager) and (Manager.OnShowCodeContext<>nil) then begin
|
|
Manager.OnShowCodeContext(JumpToError,Abort);
|
|
if Abort then ;
|
|
end;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ReadOnlyClicked(Sender: TObject);
|
|
var ActEdit: TSourceEditor;
|
|
begin
|
|
ActEdit:=GetActiveSE;
|
|
if ActEdit.ReadOnly and (ActEdit.CodeBuffer<>nil)
|
|
and (not ActEdit.CodeBuffer.IsVirtual)
|
|
and (not FileIsWritable(ActEdit.CodeBuffer.Filename)) then begin
|
|
MessageDlg(ueFileROCap,
|
|
ueFileROText1+ActEdit.CodeBuffer.Filename+ueFileROText2,
|
|
mtError,[mbCancel],0);
|
|
exit;
|
|
end;
|
|
ActEdit.EditorComponent.ReadOnly := not(ActEdit.EditorComponent.ReadOnly);
|
|
if assigned(Manager) and Assigned(Manager.OnReadOnlyChanged) then
|
|
Manager.OnReadOnlyChanged(Self);
|
|
UpdateStatusBar;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenPasFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.pas'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenPPFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.pp'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenPFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.p'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenLFMFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.lfm'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenDFMFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.dfm'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenLRSFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.lrs'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenSFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.s'),
|
|
PageIndex+1, Manager.IndexOfSourceWindow(self),
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenFile(Sender: TObject);
|
|
var
|
|
AFilename: String;
|
|
begin
|
|
AFilename:=GetActiveSE.Filename;
|
|
if CompareFileExt(AFilename,'.lpi')=0 then
|
|
MainIDEInterface.DoOpenProjectFile(AFilename,
|
|
[ofOnlyIfExists,ofAddToRecent,ofUseCache])
|
|
else if CompareFileExt(AFilename,'.lpk')=0 then
|
|
PackageEditingInterface.DoOpenPackageFile(AFilename,[pofAddToRecent],false);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ShowUnitInfo(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnShowUnitInfo) then
|
|
Manager.OnShowUnitInfo(Sender);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ToggleLineNumbersClicked(Sender: TObject);
|
|
var
|
|
MenuITem: TIDEMenuCommand;
|
|
ActEdit:TSourceEditor;
|
|
i: integer;
|
|
ShowLineNumbers: boolean;
|
|
begin
|
|
MenuItem := Sender as TIDEMenuCommand;
|
|
ActEdit:=GetActiveSE;
|
|
MenuItem.Checked :=
|
|
not ActEdit.EditorComponent.Gutter.LineNumberPart.Visible;
|
|
ShowLineNumbers:=MenuItem.Checked;
|
|
for i:=0 to EditorCount-1 do
|
|
Editors[i].EditorComponent.Gutter.LineNumberPart.Visible
|
|
:= ShowLineNumbers;
|
|
EditorOpts.ShowLineNumbers := ShowLineNumbers;
|
|
EditorOpts.Save;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ToggleI18NForLFMClicked(Sender: TObject);
|
|
begin
|
|
|
|
end;
|
|
|
|
Procedure TSourceNotebook.OpenAtCursorClicked(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnOpenFileAtCursorClicked) then
|
|
Manager.OnOpenFileAtCursorClicked(Sender);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.FindDeclarationClicked(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnFindDeclarationClicked) then
|
|
Manager.OnFindDeclarationClicked(Sender);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ProcedureJumpClicked(Sender: TObject);
|
|
var ActSE: TSourceEditor;
|
|
begin
|
|
ActSE := GetActiveSE;
|
|
if ActSE <> nil then
|
|
ActSE.DoEditorExecuteCommand(ecFindProcedureDefinition);
|
|
end;
|
|
|
|
procedure TSourceNotebook.FindNextWordOccurrenceClicked(Sender: TObject);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit := GetActiveSE;
|
|
if SrcEdit<>nil then
|
|
SrcEdit.FindNextWordOccurrence(true);
|
|
end;
|
|
|
|
procedure TSourceNotebook.FindPrevWordOccurrenceClicked(Sender: TObject);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit := GetActiveSE;
|
|
if SrcEdit<>nil then
|
|
SrcEdit.FindNextWordOccurrence(false);
|
|
end;
|
|
|
|
procedure TSourceNotebook.FindInFilesClicked(Sender: TObject);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit := GetActiveSE;
|
|
if SrcEdit<>nil then
|
|
SrcEdit.DoEditorExecuteCommand(ecFindInFiles);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.CutClicked(Sender: TObject);
|
|
var ActSE: TSourceEditor;
|
|
begin
|
|
ActSE := GetActiveSE;
|
|
if ActSE <> nil then
|
|
ActSE.DoEditorExecuteCommand(ecCut);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.CopyClicked(Sender: TObject);
|
|
var ActSE: TSourceEditor;
|
|
begin
|
|
ActSE := GetActiveSE;
|
|
if ActSE <> nil then
|
|
ActSE.DoEditorExecuteCommand(ecCopy);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.PasteClicked(Sender: TObject);
|
|
var ActSE: TSourceEditor;
|
|
begin
|
|
ActSE := GetActiveSE;
|
|
if ActSE <> nil then
|
|
ActSE.DoEditorExecuteCommand(ecPaste);
|
|
end;
|
|
|
|
procedure TSourceNotebook.CopyFilenameClicked(Sender: TObject);
|
|
var ActSE: TSourceEditor;
|
|
begin
|
|
ActSE := GetActiveSE;
|
|
if ActSE <> nil then
|
|
Clipboard.AsText:=ActSE.FileName;
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorLeftClicked(Sender: TObject);
|
|
begin
|
|
MoveActivePageLeft;
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorRightClicked(Sender: TObject);
|
|
begin
|
|
MoveActivePageRight;
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorFirstClicked(Sender: TObject);
|
|
begin
|
|
MoveActivePageFirst;
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorLastClicked(Sender: TObject);
|
|
begin
|
|
MoveActivePageLast;
|
|
end;
|
|
|
|
procedure TSourceNotebook.StatusBarDblClick(Sender: TObject);
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
P := StatusBar.ScreenToClient(Mouse.CursorPos);
|
|
// if we clicked on first panel which shows position in code
|
|
if assigned(Manager) and (StatusBar.GetPanelIndexAt(P.X, P.Y) = 0) then
|
|
begin
|
|
// then show goto line dialog
|
|
Manager.GotoLineClicked(nil);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ToggleBreakpointClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
Line: LongInt;
|
|
BreakPtMark: TSourceMark;
|
|
begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
// create or delete breakpoint
|
|
// find breakpoint mark at line
|
|
Line:=ASrcEdit.EditorComponent.CaretY;
|
|
BreakPtMark := SourceEditorMarks.FindBreakPointMark(ASrcEdit, Line);
|
|
if BreakPtMark = nil then
|
|
DebugBoss.DoCreateBreakPoint(ASrcEdit.Filename,Line,true)
|
|
else
|
|
DebugBoss.DoDeleteBreakPointAtMark(BreakPtMark);
|
|
end;
|
|
|
|
procedure TSourceNotebook.CompleteCodeMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecCompleteCode);
|
|
end;
|
|
|
|
procedure TSourceNotebook.DeleteBreakpointClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
DebugBoss.DoDeleteBreakPoint(ASrcEdit.Filename,
|
|
ASrcEdit.EditorComponent.CaretY);
|
|
end;
|
|
|
|
procedure TSourceNotebook.EncloseSelectionMenuItemClick(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
ASrcEdit.EncloseSelection;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ExtractProcMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecExtractProc);
|
|
end;
|
|
|
|
procedure TSourceNotebook.InvertAssignmentMenuItemClick(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
ASrcEdit.InvertAssignment;
|
|
end;
|
|
|
|
procedure TSourceNotebook.FindIdentifierReferencesMenuItemClick(Sender: TObject
|
|
);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecFindIdentifierRefs);
|
|
end;
|
|
|
|
procedure TSourceNotebook.RenameIdentifierMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecRenameIdentifier);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ShowAbstractMethodsMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecShowAbstractMethods);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ShowEmptyMethodsMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecRemoveEmptyMethods);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ShowUnusedUnitsMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecRemoveUnusedUnits);
|
|
end;
|
|
|
|
procedure TSourceNotebook.FindOverloadsMenuItemClick(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoCommand(ecFindOverloads);
|
|
end;
|
|
|
|
procedure TSourceNotebook.RunToClicked(Sender: TObject);
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
DebugBoss.DoRunToCursor;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ViewCallStackClick(Sender: TObject);
|
|
var
|
|
Command: TSynEditorCommand;
|
|
AChar: TUTF8Char;
|
|
Handled: boolean;
|
|
begin
|
|
Command:=ecToggleCallStack;
|
|
AChar:=#0;
|
|
Handled:=false;
|
|
ProcessParentCommand(Self,Command,AChar,nil,Handled);
|
|
end;
|
|
|
|
function TSourceNotebook.NewFile(const NewShortName: String;
|
|
ASource: TCodeBuffer; FocusIt: boolean; AShareEditor: TSourceEditor = nil): TSourceEditor;
|
|
Begin
|
|
//create a new page
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] A ');
|
|
{$ENDIF}
|
|
DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.NewFile'){$ENDIF};
|
|
try
|
|
IDEWindowCreators.ShowForm(Self,false);
|
|
Result := NewSE(-1, -1, AShareEditor);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] B ');
|
|
{$ENDIF}
|
|
Result.CodeBuffer:=ASource;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] D ');
|
|
{$ENDIF}
|
|
//debugln(['TSourceNotebook.NewFile ',NewShortName,' ',ASource.Filename]);
|
|
Result.PageName:= Manager.FindUniquePageName(NewShortName, Result);
|
|
UpdatePageNames;
|
|
UpdateProjectFiles;
|
|
UpdateStatusBar;
|
|
finally
|
|
EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.NewFile'){$ENDIF};
|
|
end;
|
|
if FocusIt then FocusEditor;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] end');
|
|
{$ENDIF}
|
|
CheckFont;
|
|
end;
|
|
|
|
procedure TSourceNotebook.CloseFile(APageIndex:integer);
|
|
var
|
|
TempEditor: TSourceEditor;
|
|
WasSelected: Boolean;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.CloseFile A APageIndex=',APageIndex);
|
|
{$ENDIF}
|
|
TempEditor:=FindSourceEditorWithPageIndex(APageIndex);
|
|
if TempEditor=nil then exit;
|
|
WasSelected:=PageIndex=APageIndex;
|
|
//debugln(['TSourceNotebook.CloseFile ',TempEditor.FileName,' ',TempEditor.APageIndex]);
|
|
DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.CloseFile'){$ENDIF};
|
|
try
|
|
EndIncrementalFind;
|
|
TempEditor.Close;
|
|
TempEditor.Free;
|
|
TempEditor:=nil;
|
|
// delete the page
|
|
//writeln('TSourceNotebook.CloseFile B APageIndex=',APageIndex,' PageCount=',PageCount,' NoteBook.APageIndex=',Notebook.APageIndex);
|
|
NoteBookDeletePage(APageIndex);
|
|
//writeln('TSourceNotebook.CloseFile C APageIndex=',APageIndex,' PageCount=',PageCount,' NoteBook.APageIndex=',Notebook.APageIndex);
|
|
UpdateProjectFiles;
|
|
UpdatePageNames;
|
|
if WasSelected then
|
|
UpdateStatusBar;
|
|
// set focus to new editor
|
|
if (PageCount = 0) and (Parent=nil) then begin
|
|
{$IFnDEF SingleSrcWindow}
|
|
Manager.RemoveWindow(self);
|
|
FManager := nil;
|
|
{$ENDIF}
|
|
if not FIsClosing then
|
|
Close;
|
|
end;
|
|
finally
|
|
EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TSourceNotebook.CloseFile'){$ENDIF};
|
|
end;
|
|
// Move focus from Notebook-tabs to editor
|
|
TempEditor:=FindSourceEditorWithPageIndex(PageIndex);
|
|
if IsVisible and (TempEditor <> nil) and (FUpdateLock = 0) then
|
|
TempEditor.EditorComponent.SetFocus;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.CloseFile END');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceNotebook.FocusEditor;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if (fAutoFocusLock>0) then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
SrcEdit.FocusEditor;
|
|
end;
|
|
|
|
procedure TSourceNotebook.FormMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
Cursor:=crDefault;
|
|
end;
|
|
|
|
function TSourceNotebook.GetEditors(Index:integer):TSourceEditor;
|
|
begin
|
|
Result:=TSourceEditor(FSourceEditorList[Index]);
|
|
end;
|
|
|
|
function TSourceNotebook.EditorCount:integer;
|
|
begin
|
|
Result:=FSourceEditorList.Count;
|
|
end;
|
|
|
|
function TSourceNotebook.IndexOfEditor(aEditor: TSourceEditorInterface
|
|
): integer;
|
|
begin
|
|
Result := FSourceEditorList.IndexOf(aEditor);
|
|
end;
|
|
|
|
function TSourceNotebook.Count: integer;
|
|
begin
|
|
Result:=FSourceEditorList.Count;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.CloseClicked(Sender: TObject);
|
|
Begin
|
|
if assigned(Manager) and Assigned(Manager.OnCloseClicked) then
|
|
Manager.OnCloseClicked(Sender, False);
|
|
end;
|
|
|
|
procedure TSourceNotebook.CloseOtherPagesClicked(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnCloseClicked) then
|
|
Manager.OnCloseClicked(Sender, True);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ToggleFormUnitClicked(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnToggleFormUnitClicked) then
|
|
Manager.OnToggleFormUnitClicked(Sender);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ToggleObjectInspClicked(Sender: TObject);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnToggleObjectInspClicked) then
|
|
Manager.OnToggleObjectInspClicked(Sender);
|
|
end;
|
|
|
|
procedure TSourceNotebook.HistorySetMostRecent(APage: TTabSheet);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
if APage = nil then
|
|
Exit;
|
|
Index := FHistoryList.IndexOf(APage);
|
|
if Index <> -1 then
|
|
FHistoryList.Delete(Index);
|
|
FHistoryList.Insert(0, APage);
|
|
end;
|
|
|
|
procedure TSourceNotebook.HistoryAdd(APage: TTabSheet);
|
|
begin
|
|
FHistoryList.Add(APage);
|
|
end;
|
|
|
|
procedure TSourceNotebook.HistoryRemove(APage: TTabSheet);
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
Index := FHistoryList.IndexOf(APage);
|
|
if Index <> -1 then
|
|
FHistoryList.Delete(Index);
|
|
end;
|
|
|
|
function TSourceNotebook.HistoryGetTopPageIndex: Integer;
|
|
begin
|
|
Result := -1;
|
|
if FHistoryList.Count = 0 then
|
|
Exit;
|
|
Result := FNotebook.IndexOf(TCustomPage(FHistoryList.Items[0]));
|
|
end;
|
|
|
|
procedure TSourceNotebook.InsertCharacter(const C: TUTF8Char);
|
|
var
|
|
FActiveEdit: TSourceEditor;
|
|
begin
|
|
FActiveEdit := GetActiveSE;
|
|
if FActiveEdit <> nil then
|
|
begin
|
|
if FActiveEdit.ReadOnly then Exit;
|
|
FActiveEdit.EditorComponent.InsertTextAtCaret(C);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SrcEditMenuCopyToNewWindowClicked(Sender: TObject);
|
|
begin
|
|
inc(FFocusLock);
|
|
try
|
|
CopyEditor(PageIndex, Manager.IndexOfSourceWindow(Manager.CreateNewWindow(True)), -1);
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
finally
|
|
dec(FFocusLock);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SrcEditMenuCopyToExistingWindowClicked(Sender: TObject);
|
|
begin
|
|
inc(FFocusLock);
|
|
try
|
|
CopyEditor(PageIndex, (Sender as TIDEMenuItem).Tag, -1);
|
|
finally
|
|
dec(FFocusLock);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SrcEditMenuMoveToNewWindowClicked(Sender: TObject);
|
|
begin
|
|
inc(FFocusLock);
|
|
try
|
|
MoveEditor(PageIndex, Manager.IndexOfSourceWindow(Manager.CreateNewWindow(True)), -1);
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
finally
|
|
dec(FFocusLock);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SrcEditMenuMoveToExistingWindowClicked(Sender: TObject);
|
|
begin
|
|
MoveEditor(PageIndex, (Sender as TIDEMenuItem).Tag, -1)
|
|
end;
|
|
|
|
procedure TSourceNotebook.EditorLockClicked(Sender: TObject);
|
|
begin
|
|
GetActiveSE.IsLocked := not GetActiveSE.IsLocked;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.UpdateStatusBar;
|
|
var
|
|
tempEditor: TSourceEditor;
|
|
PanelFilename: String;
|
|
PanelCharMode: string;
|
|
PanelXY: string;
|
|
PanelFileMode: string;
|
|
CurEditor: TSynEdit;
|
|
begin
|
|
if (not IsVisible) or (FUpdateLock > 0) then
|
|
begin
|
|
Include(States,snUpdateStatusBarNeeded);
|
|
exit;
|
|
end;
|
|
Exclude(States,snUpdateStatusBarNeeded);
|
|
TempEditor := GetActiveSE;
|
|
if TempEditor = nil then Exit;
|
|
CurEditor:=TempEditor.EditorComponent;
|
|
//debugln(['TSourceNotebook.UpdateStatusBar ',tempEditor.FileName,' ',PageIndex]);
|
|
|
|
if (snIncrementalFind in States)
|
|
and (CompareCaret(CurEditor.LogicalCaretXY,FIncrementalSearchPos)<>0) then
|
|
begin
|
|
// some action has changed the cursor during incremental search
|
|
// -> end incremental search
|
|
EndIncrementalFind;
|
|
// this called UpdateStatusBar -> exit
|
|
exit;
|
|
end;
|
|
|
|
if (CurEditor.CaretY<>TempEditor.ErrorLine)
|
|
or (CurEditor.CaretX<>TempEditor.fErrorColumn) then
|
|
TempEditor.ErrorLine:=-1;
|
|
Statusbar.BeginUpdate;
|
|
|
|
if snIncrementalFind in States then begin
|
|
Statusbar.SimplePanel:=true;
|
|
Statusbar.SimpleText:=Format(lisUESearching, [IncrementalSearchStr]);
|
|
|
|
end else begin
|
|
Statusbar.SimplePanel:=false;
|
|
PanelFilename:=TempEditor.Filename;
|
|
|
|
If TempEditor.Modified then
|
|
PanelFileMode := ueModified
|
|
else
|
|
PanelFileMode := '';
|
|
|
|
If TempEditor.ReadOnly then begin
|
|
if PanelFileMode <> '' then
|
|
PanelFileMode := PanelFileMode + lisUEModeSeparator;
|
|
PanelFileMode := PanelFileMode + uepReadonly;
|
|
end;
|
|
|
|
If TempEditor.IsLocked then begin
|
|
if PanelFileMode <> '' then
|
|
PanelFileMode := PanelFileMode + lisUEModeSeparator;
|
|
PanelFileMode := PanelFileMode + ueLocked;
|
|
end;
|
|
|
|
PanelXY := Format(' %6d:%4d',
|
|
[TempEditor.CurrentCursorYLine,TempEditor.CurrentCursorXLine]);
|
|
|
|
if GetActiveSE.InsertMode then
|
|
PanelCharMode := uepIns
|
|
else
|
|
PanelCharMode := uepOvr;
|
|
|
|
Statusbar.Panels[0].Text := PanelXY;
|
|
StatusBar.Panels[1].Text := PanelFileMode;
|
|
Statusbar.Panels[2].Text := PanelCharMode;
|
|
Statusbar.Panels[3].Text := PanelFilename;
|
|
end;
|
|
Statusbar.EndUpdate;
|
|
|
|
CheckCurrentCodeBufferChanged;
|
|
End;
|
|
|
|
function TSourceNotebook.FindPageWithEditor(
|
|
ASourceEditor: TSourceEditor):integer;
|
|
begin
|
|
if (ASourceEditor.EditorComponent.Parent is TTabSheet) and
|
|
(TTabSheet(ASourceEditor.EditorComponent.Parent).Parent = FNotebook)
|
|
then
|
|
Result:=TTabSheet(ASourceEditor.EditorComponent.Parent).PageIndex
|
|
else
|
|
Result:=-1;
|
|
end;
|
|
|
|
function TSourceNotebook.FindSourceEditorWithEditorComponent(
|
|
EditorComp: TComponent): TSourceEditor;
|
|
var i: integer;
|
|
begin
|
|
for i:=0 to EditorCount-1 do begin
|
|
Result:=Editors[i];
|
|
if Result.EditorComponent=EditorComp then exit;
|
|
end;
|
|
Result:=nil;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NotebookMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
TabIndex: Integer;
|
|
begin
|
|
if (Button = mbMiddle) then begin
|
|
TabIndex:=FNotebook.TabIndexAtClientPos(Point(X,Y));
|
|
if TabIndex>=0 then
|
|
CloseClicked(NoteBookPage[TabIndex])
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NotebookDragTabMove(Sender, Source: TObject; OldIndex,
|
|
NewIndex: Integer; CopyDrag: Boolean; var Done: Boolean);
|
|
function SourceIndex: Integer;
|
|
begin
|
|
Result := Manager.SourceWindowCount - 1;
|
|
while Result >= 0 do begin
|
|
if Manager.SourceWindows[Result].FNotebook = Source then break;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
begin
|
|
{$IFnDEF SingleSrcWindow}
|
|
If CopyDrag then begin
|
|
Manager.SourceWindows[SourceIndex].CopyEditor
|
|
(OldIndex, Manager.IndexOfSourceWindow(self), NewIndex);
|
|
end
|
|
else begin
|
|
{$ENDIF}
|
|
if (Source = FNotebook) then
|
|
MoveEditor(OldIndex, NewIndex)
|
|
else begin
|
|
Manager.SourceWindows[SourceIndex].MoveEditor
|
|
(OldIndex, Manager.IndexOfSourceWindow(self), NewIndex);
|
|
end;
|
|
{$IFnDEF SingleSrcWindow}
|
|
end;
|
|
{$ENDIF}
|
|
Manager.ActiveSourceWindow := self;
|
|
Manager.ShowActiveWindowOnTop(True);
|
|
Done := True;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NotebookCanDragTabMove(Sender, Source: TObject;
|
|
OldIndex, NewIndex: Integer; CopyDrag: Boolean; var Accept: Boolean);
|
|
|
|
function SourceIndex: Integer;
|
|
begin
|
|
Result := Manager.SourceWindowCount - 1;
|
|
while Result >= 0 do begin
|
|
if Manager.SourceWindows[Result].FNotebook = Source then break;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
var
|
|
Src: TSourceNotebook;
|
|
NBHasSharedEditor: Boolean;
|
|
begin
|
|
Src := Manager.SourceWindows[SourceIndex];
|
|
NBHasSharedEditor := IndexOfEditorInShareWith
|
|
(Src.FindSourceEditorWithPageIndex(OldIndex)) >= 0;
|
|
{$IFnDEF SingleSrcWindow}
|
|
if CopyDrag then
|
|
Accept := (NewIndex >= 0) and (Source <> Sender) and (not NBHasSharedEditor)
|
|
else
|
|
{$ENDIF}
|
|
Accept := (NewIndex >= 0) and
|
|
((Source <> Sender) or (OldIndex <> NewIndex)) and
|
|
((Source = Sender) or (not NBHasSharedEditor));
|
|
end;
|
|
|
|
procedure TSourceNotebook.NotebookDragOver(Sender, Source: TObject; X, Y: Integer;
|
|
State: TDragState; var Accept: Boolean);
|
|
begin
|
|
FUpdateTabAndPageTimer.Enabled := False;
|
|
if State = dsDragLeave then
|
|
FUpdateTabAndPageTimer.Enabled := True
|
|
else if Source is TExtendedNotebook then
|
|
FNotebook.ShowTabs := True;
|
|
end;
|
|
|
|
procedure TSourceNotebook.NotebookEndDrag(Sender, Target: TObject; X, Y: Integer);
|
|
begin
|
|
FUpdateTabAndPageTimer.Enabled := True;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.NotebookPageChanged(Sender: TObject);
|
|
var
|
|
TempEditor:TSourceEditor;
|
|
CaretXY: TPoint;
|
|
TopLine: Integer;
|
|
Begin
|
|
if (not assigned(Manager)) or (FUpdateLock > 0) Then begin
|
|
Include(States, snNotbookPageChangedNeeded);
|
|
exit;
|
|
end;
|
|
Exclude(States, snNotbookPageChangedNeeded);
|
|
TempEditor:=GetActiveSE;
|
|
|
|
//writeln('TSourceNotebook.NotebookPageChanged ',Pageindex,' ',TempEditor <> nil,' fAutoFocusLock=',fAutoFocusLock);
|
|
if TempEditor <> nil then
|
|
begin
|
|
if not TempEditor.Visible then begin
|
|
// As long as SynEdit had no Handle, it had kept all those Values untouched
|
|
CaretXY := TempEditor.EditorComponent.CaretXY;
|
|
TopLine := TempEditor.EditorComponent.TopLine;
|
|
TempEditor.BeginUpdate;
|
|
TempEditor.Visible := True;
|
|
TempEditor.EndUpdate;
|
|
// Restore the intial Positions, must be after lock
|
|
TempEditor.EditorComponent.LeftChar := 1;
|
|
TempEditor.EditorComponent.CaretXY := CaretXY;
|
|
TempEditor.EditorComponent.TopLine := TopLine;
|
|
end;
|
|
if (fAutoFocusLock=0) and (Screen.ActiveCustomForm=GetParentForm(Self)) then
|
|
begin
|
|
{$IFDEF VerboseFocus}
|
|
writeln('TSourceNotebook.NotebookPageChanged BEFORE SetFocus ',
|
|
TempEditor.EditorComponent.Name,' ',
|
|
NoteBookPages[FindPageWithEditor(TempEditor)]);
|
|
{$ENDIF}
|
|
TempEditor.FocusEditor;
|
|
{$IFDEF VerboseFocus}
|
|
writeln('TSourceNotebook.NotebookPageChanged AFTER SetFocus ',
|
|
TempEditor.EditorComponent.Name,' ',
|
|
NotebookPages[FindPageWithEditor(TempEditor)]);
|
|
{$ENDIF}
|
|
end;
|
|
UpdateStatusBar;
|
|
UpdateActiveEditColors(TempEditor.EditorComponent);
|
|
if (DebugBoss.State in [dsPause, dsRun]) and
|
|
not TempEditor.HasExecutionMarks and
|
|
(TempEditor.FileName <> '') then
|
|
TempEditor.FillExecutionMarks;
|
|
Manager.DoActiveEditorChanged;
|
|
end;
|
|
|
|
CheckCurrentCodeBufferChanged;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ProcessParentCommand(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
|
|
var Handled: boolean);
|
|
begin
|
|
//DebugLn(['TSourceNotebook.ProcessParentCommand START ',dbgsName(Sender),' Command=',Command,' AChar=',AChar]);
|
|
|
|
FProcessingCommand:=true;
|
|
if Assigned(Manager.OnProcessUserCommand) then begin
|
|
Handled:=false;
|
|
Manager.OnProcessUserCommand(Self,Command,Handled);
|
|
if Handled or (Command=ecNone) then begin
|
|
FProcessingCommand:=false;
|
|
Command:=ecNone;
|
|
exit;
|
|
end;
|
|
end;
|
|
//DebugLn(['TSourceNotebook.ProcessParentCommand after mainide: ',dbgsName(Sender),' Command=',Command,' AChar=',AChar]);
|
|
|
|
Handled:=true;
|
|
case Command of
|
|
|
|
ecNextEditor:
|
|
NextEditor;
|
|
|
|
ecPrevEditor :
|
|
PrevEditor;
|
|
|
|
ecMoveEditorLeft:
|
|
MoveActivePageLeft;
|
|
|
|
ecMoveEditorRight:
|
|
MoveActivePageRight;
|
|
|
|
ecMoveEditorLeftmost:
|
|
MoveActivePageFirst;
|
|
|
|
ecMoveEditorRightmost:
|
|
MoveActivePageLast;
|
|
|
|
ecNextSharedEditor:
|
|
GotoNextSharedEditor(False);
|
|
ecPrevSharedEditor:
|
|
GotoNextSharedEditor(True);
|
|
ecNextWindow:
|
|
GotoNextWindow(False);
|
|
ecPrevWindow:
|
|
GotoNextWindow(True);
|
|
ecMoveEditorNextWindow:
|
|
MoveEditorNextWindow(False, False);
|
|
ecMoveEditorPrevWindow:
|
|
MoveEditorNextWindow(True, False);
|
|
ecMoveEditorNewWindow:
|
|
if EditorCount > 1 then
|
|
MoveEditor(FindPageWithEditor(GetActiveSE), Manager.IndexOfSourceWindow(Manager.CreateNewWindow(True)), -1);
|
|
ecCopyEditorNextWindow:
|
|
MoveEditorNextWindow(False, True);
|
|
ecCopyEditorPrevWindow:
|
|
MoveEditorNextWindow(True, True);
|
|
ecCopyEditorNewWindow:
|
|
CopyEditor(FindPageWithEditor(GetActiveSE), Manager.IndexOfSourceWindow(Manager.CreateNewWindow(True)), -1, True);
|
|
|
|
|
|
ecOpenFileAtCursor:
|
|
OpenAtCursorClicked(self);
|
|
|
|
ecGotoEditor1..ecGotoEditor9,ecGotoEditor0:
|
|
if PageCount>Command-ecGotoEditor1 then
|
|
PageIndex:=Command-ecGotoEditor1;
|
|
|
|
ecToggleFormUnit:
|
|
ToggleFormUnitClicked(Self);
|
|
|
|
ecToggleObjectInsp:
|
|
ToggleObjectInspClicked(Self);
|
|
|
|
ecSetFreeBookmark:
|
|
if Assigned(Manager.OnSetBookmark) then
|
|
Manager.OnSetBookmark(GetActiveSE, -1, False);
|
|
|
|
ecJumpBack:
|
|
Manager.HistoryJump(Self,jhaBack);
|
|
|
|
ecJumpForward:
|
|
Manager.HistoryJump(Self,jhaForward);
|
|
|
|
ecAddJumpPoint:
|
|
Manager.AddJumpPointClicked(Self);
|
|
|
|
ecViewJumpHistory:
|
|
Manager.ViewJumpHistoryClicked(Self);
|
|
|
|
else
|
|
Handled:=ExecuteIDECommand(Self,Command);
|
|
DebugLn('TSourceNotebook.ProcessParentCommand Command=',dbgs(Command),' Handled=',dbgs(Handled));
|
|
end; //case
|
|
if Handled then Command:=ecNone;
|
|
FProcessingCommand:=false;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ParentCommandProcessed(Sender: TObject;
|
|
var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
|
|
var Handled: boolean);
|
|
begin
|
|
if assigned(Manager) and Assigned(Manager.OnUserCommandProcessed) then begin
|
|
Handled:=false;
|
|
Manager.OnUserCommandProcessed(Self,Command,Handled);
|
|
if Handled then exit;
|
|
end;
|
|
|
|
Handled:=(Command=ecClose);
|
|
|
|
if Handled then Command:=ecNone;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ReloadEditorOptions;
|
|
var
|
|
I: integer;
|
|
Begin
|
|
for i := 0 to EditorCount-1 do
|
|
Editors[i].RefreshEditorSettings;
|
|
|
|
EditorOpts.KeyMap.AssignTo(FKeyStrokes,TSourceEditorWindowInterface);
|
|
if EditorOpts.ShowTabCloseButtons then
|
|
FNoteBook.Options:=FNoteBook.Options+[nboShowCloseButtons]
|
|
else
|
|
FNoteBook.Options:=FNoteBook.Options-[nboShowCloseButtons];
|
|
FNotebook.TabPosition := EditorOpts.TabPosition;
|
|
|
|
FMouseHintTimer.Interval:=EditorOpts.AutoDelayInMSec;
|
|
|
|
Exclude(States,snWarnedFont);
|
|
CheckFont;
|
|
UpdatePageNames;
|
|
end;
|
|
|
|
procedure TSourceNotebook.CheckFont;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
DummyResult: TModalResult;
|
|
CurFont: TFont;
|
|
begin
|
|
if (snWarnedFont in States) then exit;
|
|
Include(States,snWarnedFont);
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit = nil then
|
|
Exit;
|
|
CurFont:=SrcEdit.EditorComponent.Font;
|
|
if (not CurFont.CanUTF8) and SystemCharSetIsUTF8
|
|
and ((EditorOpts.DoNotWarnForFont='')
|
|
or (EditorOpts.DoNotWarnForFont<>CurFont.Name))
|
|
then begin
|
|
{$IFDEF HasMonoSpaceFonts}
|
|
DummyResult:=QuestionDlg(lisUEFontWith,
|
|
Format(lisUETheCurre, [#13, #13]),
|
|
mtWarning, [mrIgnore, mrYesToAll, lisUEDoNotSho], 0);
|
|
{$ELSE}
|
|
DummyResult:=mrYesToAll;
|
|
{$ENDIF}
|
|
if DummyResult=mrYesToAll then begin
|
|
if EditorOpts.DoNotWarnForFont<>CurFont.Name then begin
|
|
EditorOpts.DoNotWarnForFont:=CurFont.Name;
|
|
EditorOpts.Save;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.KeyDownBeforeInterface(var Key: Word;
|
|
Shift: TShiftState);
|
|
var i, Command: integer;
|
|
Begin
|
|
inherited KeyDown(Key,Shift);
|
|
if not assigned(Manager) then exit;
|
|
i := FKeyStrokes.FindKeycode(Key, Shift);
|
|
if i>=0 then begin
|
|
Command:=FKeyStrokes[i].Command;
|
|
case Command of
|
|
|
|
ecGotoMarker0..ecGotoMarker9:
|
|
begin
|
|
if Assigned(Manager.OnGotoBookmark) then
|
|
Manager.OnGotoBookmark(ActiveEditor, Command - ecGotoMarker0, False);
|
|
Key:=0;
|
|
end;
|
|
|
|
ecSetMarker0..ecSetMarker9:
|
|
begin
|
|
if Assigned(Manager.OnSetBookmark) then
|
|
Manager.OnSetBookmark(GetActiveSE, Command - ecSetMarker0, False);
|
|
Key:=0;
|
|
end;
|
|
|
|
ecToggleMarker0..ecToggleMarker9:
|
|
begin
|
|
if Assigned(Manager.OnSetBookmark) then
|
|
Manager.OnSetBookmark(GetActiveSE, Command - ecToggleMarker0, True);
|
|
Key:=0;
|
|
end;
|
|
|
|
ecClose:
|
|
begin
|
|
CloseClicked(Self);
|
|
Key:=0;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.BeginAutoFocusLock;
|
|
begin
|
|
inc(fAutoFocusLock);
|
|
end;
|
|
|
|
procedure TSourceNotebook.EndAutoFocusLock;
|
|
begin
|
|
dec(fAutoFocusLock);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.EditorMouseMove(Sender: TObject; Shift: TShiftstate;
|
|
X,Y: Integer);
|
|
begin
|
|
HideHint;
|
|
if not Visible then exit;
|
|
if (MainIDEInterface.ToolStatus=itDebugger) then
|
|
FMouseHintTimer.AutoEnabled := EditorOpts.AutoToolTipExprEval or EditorOpts.AutoToolTipSymbTools
|
|
else
|
|
FMouseHintTimer.AutoEnabled := EditorOpts.AutoToolTipSymbTools;
|
|
end;
|
|
|
|
procedure TSourceNotebook.EditorMouseWheel(Sender: TObject; Shift: TShiftState;
|
|
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
begin
|
|
HideHint;
|
|
//handled:=true; //The scrolling is not done: it's not handled! See TWinControl.DoMouseWheel
|
|
end;
|
|
|
|
procedure TSourceNotebook.EditorMouseDown(Sender: TObject;
|
|
Button: TMouseButton; Shift: TShiftstate; X, Y: Integer);
|
|
begin
|
|
|
|
end;
|
|
|
|
function TSourceNotebook.EditorGetIndent(Sender: TObject; Editor: TObject;
|
|
LogCaret, OldLogCaret: TPoint; FirstLinePos, LastLinePos: Integer;
|
|
Reason: TSynEditorCommand; SetIndentProc: TSynBeautifierSetIndentProc
|
|
): Boolean;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
p: LongInt;
|
|
NestedComments: Boolean;
|
|
NewIndent: TFABIndentationPolicy;
|
|
Indent: LongInt;
|
|
CodeBuf: TCodeBuffer;
|
|
begin
|
|
Result:=false;
|
|
//SrcEdit:=GetActiveSE;
|
|
SrcEdit := Manager.ActiveEditor; // Todo: Each SynEdit needs its own Beautifier, otherwise they call the wrong notebook
|
|
if assigned(Manager) and Assigned(Manager.OnGetIndent) then begin
|
|
Result := Manager.OnGetIndent(Sender, SrcEdit, LogCaret, OldLogCaret, FirstLinePos, LastLinePos,
|
|
Reason, SetIndentProc);
|
|
if Result then exit;
|
|
end;
|
|
if (SrcEdit.SyncroLockCount > 0) then exit;
|
|
if not (SrcEdit.SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
|
|
exit;
|
|
if Reason<>ecLineBreak then exit;
|
|
if not CodeToolsOpts.IndentOnLineBreak then exit;
|
|
{$IFDEF VerboseIndenter}
|
|
debugln(['TSourceNotebook.EditorGetIndent LogCaret=',dbgs(LogCaret),' FirstLinePos=',FirstLinePos,' LastLinePos=',LastLinePos]);
|
|
{$ENDIF}
|
|
Result := True;
|
|
SrcEdit.UpdateCodeBuffer;
|
|
CodeBuf:=SrcEdit.CodeBuffer;
|
|
CodeBuf.LineColToPosition(LogCaret.Y,LogCaret.X,p);
|
|
if p<1 then exit;
|
|
{$IFDEF VerboseIndenter}
|
|
if FirstLinePos>0 then
|
|
DebugLn(['TSourceNotebook.EditorGetIndent Firstline-1=',SrcEdit.Lines[FirstLinePos-2]]);
|
|
DebugLn(['TSourceNotebook.EditorGetIndent Firstline+0=',SrcEdit.Lines[FirstLinePos-1]]);
|
|
if FirstLinePos<SrcEdit.LineCount then
|
|
DebugLn(['TSourceNotebook.EditorGetIndent Firstline+1=',SrcEdit.Lines[FirstLinePos+0]]);
|
|
DebugLn(['TSourceNotebook.EditorGetIndent CodeBuffer: ',dbgstr(copy(CodeBuf.Source,p-10,10)),'|',dbgstr(copy(CodeBuf.Source,p,10))]);
|
|
DebugLn(['TSourceNotebook.EditorGetIndent CodeBuffer: "',copy(CodeBuf.Source,p-10,10),'|',copy(CodeBuf.Source,p,10)]);
|
|
{$ENDIF}
|
|
NestedComments:=CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuf.Filename);
|
|
if not CodeToolBoss.Indenter.GetIndent(CodeBuf.Source,p,NestedComments,
|
|
True,NewIndent,CodeToolsOpts.IndentContextSensitive)
|
|
then exit;
|
|
if not NewIndent.IndentValid then exit;
|
|
Indent:=NewIndent.Indent;
|
|
{$IFDEF VerboseIndenter}
|
|
DebugLn(['TSourceNotebook.EditorGetIndent Indent=',Indent]);
|
|
{$ENDIF}
|
|
{$IFDEF VerboseIndenter}
|
|
DebugLn(['TSourceNotebook.EditorGetIndent Apply to FirstLinePos+1']);
|
|
{$ENDIF}
|
|
SetIndentProc(LogCaret.Y, Indent, 0,' ');
|
|
SrcEdit.CursorScreenXY:=Point(Indent+1,SrcEdit.CursorScreenXY.Y);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.HintTimer(sender: TObject);
|
|
var
|
|
MousePos: TPoint;
|
|
AControl: TControl;
|
|
begin
|
|
FMouseHintTimer.Enabled := False;
|
|
FMouseHintTimer.AutoEnabled := False;
|
|
if not IsVisible then exit;
|
|
MousePos := Mouse.CursorPos;
|
|
AControl:=FindLCLControl(MousePos);
|
|
if (AControl=nil) or (not ContainsControl(AControl)) then exit;
|
|
if AControl is TSynEdit then
|
|
ShowSynEditHint(MousePos);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
procedure TSourceNotebook.OnApplicationUserInput(Sender: TObject;
|
|
Msg: Cardinal);
|
|
------------------------------------------------------------------------------}
|
|
procedure TSourceNotebook.OnApplicationUserInput(Sender: TObject; Msg: Cardinal
|
|
);
|
|
begin
|
|
//debugln('TSourceNotebook.OnApplicationUserInput');
|
|
HideHint;
|
|
end;
|
|
|
|
procedure TSourceNotebook.EditorKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TSourceNotebook.ShowSynEditHint(const MousePos: TPoint);
|
|
var
|
|
EditPos: TPoint;
|
|
ASrcEdit: TSourceEditor;
|
|
ASynEdit: TSynEdit;
|
|
EditCaret: TPoint;
|
|
LineMarks: TSynEditMarks;
|
|
AMark: TSourceMark;
|
|
i: integer;
|
|
HintStr: String;
|
|
CurHint: String;
|
|
begin
|
|
// hide other hints
|
|
//debugln('TSourceNotebook.ShowSynEditHint A');
|
|
Application.HideHint;
|
|
//
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
ASynEdit:=ASrcEdit.EditorComponent;
|
|
EditPos:=ASynEdit.ScreenToClient(MousePos);
|
|
if not PtInRect(ASynEdit.ClientRect,EditPos) then exit;
|
|
EditCaret:=ASynEdit.PhysicalToLogicalPos(ASynEdit.PixelsToRowColumn(EditPos));
|
|
if (EditCaret.Y<1) then exit;
|
|
if EditPos.X<ASynEdit.Gutter.Width then begin
|
|
// hint for a gutter item
|
|
if EditorOpts.ShowGutterHints then begin
|
|
ASynEdit.Marks.GetMarksForLine(EditCaret.Y,LineMarks);
|
|
HintStr:='';
|
|
for i:=Low(TSynEditMarks) to High(TSynEditMarks) do begin
|
|
if not (LineMarks[i] is TSourceSynMark) then continue;
|
|
AMark := TSourceSynMark(LineMarks[i]).SourceMark;
|
|
if AMark = nil then continue;
|
|
CurHint:=AMark.GetHint;
|
|
if CurHint='' then continue;
|
|
if HintStr<>'' then HintStr:=HintStr+LineEnding;
|
|
HintStr:=HintStr+CurHint;
|
|
end;
|
|
if HintStr<>'' then
|
|
ActivateHint(MousePos,'',HintStr);
|
|
end;
|
|
end else begin
|
|
// hint for source
|
|
if assigned(manager) and Assigned(Manager.OnShowHintForSource) then
|
|
Manager.OnShowHintForSource(ASrcEdit,EditPos,EditCaret);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SetIncrementalSearchStr(const AValue: string);
|
|
begin
|
|
if FIncrementalSearchStr=AValue then exit;
|
|
FIncrementalSearchStr:=AValue;
|
|
IncrementalSearch(False, False);
|
|
end;
|
|
|
|
procedure TSourceNotebook.IncrementalSearch(ANext, ABackward: Boolean);
|
|
const
|
|
SEARCH_OPTS: array[Boolean] of TSynSearchOptions = ([], [ssoBackwards]);
|
|
var
|
|
CurEdit: TSynEdit;
|
|
AStart : TPoint;
|
|
begin
|
|
if not (snIncrementalFind in States)
|
|
then begin
|
|
UpdateStatusBar;
|
|
Exit;
|
|
end;
|
|
if FIncrementalSearchEditor = nil then Exit;
|
|
|
|
// search string
|
|
CurEdit := FIncrementalSearchEditor.EditorComponent;
|
|
CurEdit.BeginUpdate;
|
|
if FIncrementalSearchStr<>''
|
|
then begin
|
|
// search from search start position when not searching for the next
|
|
AStart := CurEdit.LogicalCaretXY;
|
|
if not ANext
|
|
then AStart := FIncrementalSearchStartPos
|
|
else if ABackward
|
|
then AStart := CurEdit.BlockBegin;
|
|
FIncrementalSearchBackwards:=ABackward;
|
|
CurEdit.SearchReplaceEx(FIncrementalSearchStr,'', SEARCH_OPTS[ABackward], AStart);
|
|
|
|
// searching next resets incremental history
|
|
if ANext
|
|
then begin
|
|
FIncrementalSearchStartPos := CurEdit.BlockBegin;
|
|
end;
|
|
|
|
// cut the not found
|
|
FIncrementalSearchStr := CurEdit.SelText;
|
|
|
|
CurEdit.SetHighlightSearch(FIncrementalSearchStr, []);
|
|
if Length(FIncrementalSearchStr) > 0
|
|
then FIncrementalFoundStr := FIncrementalSearchStr;
|
|
end
|
|
else begin
|
|
// go to start
|
|
CurEdit.LogicalCaretXY:= FIncrementalSearchStartPos;
|
|
CurEdit.BlockBegin:=CurEdit.LogicalCaretXY;
|
|
CurEdit.BlockEnd:=CurEdit.BlockBegin;
|
|
CurEdit.SetHighlightSearch('', []);
|
|
end;
|
|
FIncrementalSearchPos:=CurEdit.LogicalCaretXY;
|
|
CurEdit.EndUpdate;
|
|
|
|
UpdateStatusBar;
|
|
end;
|
|
|
|
procedure TSourceNotebook.Activate;
|
|
begin
|
|
inherited Activate;
|
|
if assigned(Manager) then
|
|
Manager.ActiveSourceWindow := self;
|
|
if assigned(Manager) then
|
|
Manager.DoWindowFocused(Self);
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateActiveEditColors(AEditor: TSynEdit);
|
|
begin
|
|
if AEditor=nil then exit;
|
|
EditorOpts.SetMarkupColors(AEditor);
|
|
AEditor.UseIncrementalColor:= snIncrementalFind in States;
|
|
end;
|
|
|
|
function TSourceNotebook.GetEditorControlSettings(EditControl: TControl
|
|
): boolean;
|
|
begin
|
|
// Deprecated; forward to manager
|
|
Result := SourceEditorManager.GetEditorControlSettings(EditControl);
|
|
end;
|
|
|
|
function TSourceNotebook.GetHighlighterSettings(Highlighter: TObject): boolean;
|
|
begin
|
|
// Deprecated; forward to manager
|
|
Result := SourceEditorManager.GetHighlighterSettings(Highlighter);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ClearErrorLines;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to EditorCount - 1 do
|
|
Editors[i].ErrorLine := -1;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ClearExecutionLines;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to EditorCount - 1 do
|
|
Editors[i].ExecutionLine := -1;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ClearExecutionMarks;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to EditorCount - 1 do
|
|
Editors[i].ClearExecutionMarks;
|
|
end;
|
|
|
|
procedure TSourceNotebook.CloseTabClicked(Sender: TObject);
|
|
begin
|
|
FPageIndex := PageIndex;
|
|
if assigned(manager) and Assigned(Manager.OnCloseClicked) then
|
|
Manager.OnCloseClicked(Sender, GetKeyState(VK_CONTROL) < 0);
|
|
end;
|
|
|
|
{ TSynEditPlugin1 }
|
|
|
|
constructor TSynEditPlugin1.Create(AOwner: TComponent);
|
|
Begin
|
|
inherited Create(AOwner);
|
|
FEnabled := True;
|
|
ViewedTextBuffer.AddChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
|
|
end;
|
|
|
|
destructor TSynEditPlugin1.Destroy;
|
|
begin
|
|
ViewedTextBuffer.RemoveChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSynEditPlugin1.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount: Integer);
|
|
begin
|
|
if not FEnabled then exit;
|
|
if ACount < 0 then begin
|
|
if Assigned(OnLinesDeleted) then
|
|
OnLinesDeleted(self, AIndex+1, -ACount);
|
|
end else begin
|
|
if Assigned(OnLinesInserted) then
|
|
OnLinesInserted(self, AIndex+1, ACount);
|
|
end;
|
|
end;
|
|
|
|
function TSynEditPlugin1.OwnedByEditor: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
procedure InternalInit;
|
|
var h: TLazSyntaxHighlighter;
|
|
begin
|
|
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
|
|
Highlighters[h]:=nil;
|
|
IDESearchInText:=@SearchInText;
|
|
end;
|
|
|
|
procedure InternalFinal;
|
|
var h: TLazSyntaxHighlighter;
|
|
begin
|
|
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
|
|
FreeThenNil(Highlighters[h]);
|
|
FreeThenNil(aWordCompletion);
|
|
end;
|
|
|
|
{ TSourceEditorManagerBase }
|
|
|
|
procedure TSourceEditorManagerBase.FreeSourceWindows;
|
|
var
|
|
s: TSourceEditorWindowInterface;
|
|
begin
|
|
FSourceWindowByFocusList.Clear;
|
|
while FSourceWindowList.Count > 0 do begin
|
|
s := TSourceEditorWindowInterface(FSourceWindowList[0]);
|
|
FSourceWindowList.Delete(0);
|
|
s.Free;
|
|
end;
|
|
FSourceWindowList.Clear;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetActiveSourceWindowIndex: integer;
|
|
begin
|
|
Result := IndexOfSourceWindow(ActiveSourceWindow);
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetSourceWindowByLastFocused(Index: Integer): TSourceEditorWindowInterface;
|
|
begin
|
|
Result := TSourceEditorWindowInterface(FSourceWindowByFocusList[Index]);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.SetActiveSourceWindowIndex(
|
|
const AValue: integer);
|
|
begin
|
|
ActiveSourceWindow := SourceWindows[AValue];
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetActiveSourceWindow: TSourceEditorWindowInterface;
|
|
begin
|
|
Result := FActiveWindow;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.SetActiveSourceWindow(
|
|
const AValue: TSourceEditorWindowInterface);
|
|
begin
|
|
if AValue = FActiveWindow then exit;
|
|
if (FActiveWindow <> nil) and (AValue <> nil) and (FActiveWindow.Focused) then
|
|
AValue.SetFocus;
|
|
|
|
FActiveWindow := AValue as TSourceNotebook;
|
|
FSourceWindowByFocusList.Remove(AValue);
|
|
FSourceWindowByFocusList.Insert(0, AValue);
|
|
|
|
// Todo: Each synEdit needs it's own beautifier
|
|
if SourceEditorCount > 0 then
|
|
TSourceEditor(SourceEditors[0]).EditorComponent.Beautifier.OnGetDesiredIndent
|
|
:= @TSourceNotebook(ActiveSourceWindow).EditorGetIndent;
|
|
|
|
if Assigned(OnCurrentCodeBufferChanged) then
|
|
OnCurrentCodeBufferChanged(nil);
|
|
FChangeNotifyLists[semWindowActivate].CallNotifyEvents(FActiveWindow);
|
|
DoActiveEditorChanged;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetSourceWindows(Index: integer
|
|
): TSourceEditorWindowInterface;
|
|
begin
|
|
Result := TSourceEditorWindowInterface(FSourceWindowList[Index]);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.DoWindowFocused(AWindow: TSourceNotebook);
|
|
begin
|
|
FChangeNotifyLists[semWindowFocused].CallNotifyEvents(FActiveWindow);
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetActiveEditor: TSourceEditorInterface;
|
|
begin
|
|
If FActiveWindow <> nil then
|
|
Result := FActiveWindow.ActiveEditor
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.SetActiveEditor(
|
|
const AValue: TSourceEditorInterface);
|
|
var
|
|
Window: TSourceEditorWindowInterface;
|
|
begin
|
|
inc(FActiveEditorLock);
|
|
try
|
|
if (FActiveWindow <> nil) and (FActiveWindow.IndexOfEditor(AValue) >= 0) then
|
|
Window := FActiveWindow
|
|
else
|
|
Window := SourceWindowWithEditor(AValue);
|
|
if Window = nil then exit;
|
|
ActiveSourceWindow := TSourceNotebook(Window);
|
|
Window.ActiveEditor := AValue;
|
|
finally
|
|
dec(FActiveEditorLock);
|
|
DoActiveEditorChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.DoActiveEditorChanged;
|
|
begin
|
|
if FActiveEditorLock > 0 then exit;
|
|
FChangeNotifyLists[semEditorActivate].CallNotifyEvents(ActiveEditor);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.DoEditorStatusChanged(AEditor: TSourceEditor);
|
|
begin
|
|
FChangeNotifyLists[semEditorStatus].CallNotifyEvents(AEditor);
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetSourceEditors(Index: integer
|
|
): TSourceEditorInterface;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
i := 0;
|
|
while (i < SourceWindowCount) and (Index >= SourceWindows[i].Count) do begin
|
|
Index := Index - SourceWindows[i].Count;
|
|
inc(i);
|
|
end;
|
|
if (i < SourceWindowCount) then
|
|
Result := SourceWindows[i].Items[Index]
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetUniqueSourceEditors(Index: integer
|
|
): TSourceEditorInterface;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to SourceEditorCount - 1 do begin
|
|
Result := SourceEditors[i];
|
|
if (TSourceEditor(Result).SharedEditorCount = 0) or
|
|
(TSourceEditor(Result).SharedEditors[0] = Result)
|
|
then
|
|
dec(Index);
|
|
if Index < 0 then exit;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.SourceWindowWithEditor(
|
|
const AEditor: TSourceEditorInterface): TSourceEditorWindowInterface;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
for i := FSourceWindowList.Count-1 downto 0 do begin
|
|
if TSourceNotebook(SourceWindows[i]).IndexOfEditor(AEditor) >= 0 then begin
|
|
Result := SourceWindows[i];
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.SourceWindowCount: integer;
|
|
begin
|
|
if assigned(FSourceWindowList) then
|
|
Result := FSourceWindowList.Count
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.IndexOfSourceWindow(
|
|
AWindow: TSourceEditorWindowInterface): integer;
|
|
begin
|
|
Result := SourceWindowCount - 1;
|
|
while Result >= 0 do Begin
|
|
if SourceWindows[Result] = AWindow then
|
|
exit;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.IndexOfSourceWindowByLastFocused(AWindow: TSourceEditorWindowInterface): integer;
|
|
begin
|
|
Result := FSourceWindowByFocusList.IndexOf(AWindow);
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.SourceEditorIntfWithFilename(
|
|
const Filename: string): TSourceEditorInterface;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := SourceEditorCount - 1 downto 0 do begin
|
|
Result := SourceEditors[i];
|
|
if CompareFilenames(Result.Filename, Filename) = 0 then exit;
|
|
end;
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.SourceEditorCount: integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
Result := Result + SourceWindows[i].Count;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.UniqueSourceEditorCount: integer;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 0 to SourceEditorCount - 1 do begin
|
|
SrcEdit := TSourceEditor(SourceEditors[i]);
|
|
if (SrcEdit.SharedEditorCount = 0) or (SrcEdit.SharedEditors[0] = SrcEdit) then
|
|
inc(Result);
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetEditorControlSettings(EditControl: TControl
|
|
): boolean;
|
|
begin
|
|
Result:=true;
|
|
if EditControl is TSynEdit then begin
|
|
EditorOpts.GetSynEditSettings(TSynEdit(EditControl));
|
|
Result:=true;
|
|
end else begin
|
|
Result:=false;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetHighlighterSettings(Highlighter: TObject
|
|
): boolean;
|
|
begin
|
|
Result:=true;
|
|
if Highlighter is TSynCustomHighlighter then begin
|
|
EditorOpts.GetHighlighterSettings(TSynCustomHighlighter(Highlighter));
|
|
Result:=true;
|
|
end else begin
|
|
Result:=false;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetDefaultCompletionForm: TSourceEditCompletion;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := FDefaultCompletionForm;
|
|
if Result <> nil then exit;
|
|
FDefaultCompletionForm := TSourceEditCompletion.Create(Self);
|
|
FDefaultCompletionForm.LongLineHintTime := EditorOpts.CompletionLongLineHintInMSec;
|
|
FDefaultCompletionForm.LongLineHintType := EditorOpts.CompletionLongLineHintType;
|
|
Result := FDefaultCompletionForm;
|
|
for i:=0 to SourceEditorCount - 1 do
|
|
FDefaultCompletionForm.AddEditor(TSourceEditor(SourceEditors[i]).EditorComponent);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.FreeCompletionPlugins;
|
|
var
|
|
p: TSourceEditorCompletionPlugin;
|
|
begin
|
|
while FCompletionPlugins.Count > 0 do begin
|
|
p := TSourceEditorCompletionPlugin(FCompletionPlugins[0]);
|
|
FCompletionPlugins.Delete(0);
|
|
p.Free;
|
|
end;
|
|
FCompletionPlugins.Clear;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetMarklingProducers(Index: integer
|
|
): TSourceMarklingProducer;
|
|
begin
|
|
Result:=TSourceMarklingProducer(fProducers[Index]);
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetActiveCompletionPlugin: TSourceEditorCompletionPlugin;
|
|
begin
|
|
Result := FActiveCompletionPlugin;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetCompletionBoxPosition: integer;
|
|
begin
|
|
Result:=-1;
|
|
if (FDefaultCompletionForm<>nil) and FDefaultCompletionForm.IsActive then
|
|
Result := FDefaultCompletionForm.Position;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.GetCompletionPlugins(Index: integer
|
|
): TSourceEditorCompletionPlugin;
|
|
begin
|
|
Result:=TSourceEditorCompletionPlugin(fCompletionPlugins[Index]);
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.FindIdentCompletionPlugin(
|
|
SrcEdit: TSourceEditor; JumpToError: boolean; var s: string; var BoxX,
|
|
BoxY: integer; var UseWordCompletion: boolean): boolean;
|
|
var
|
|
i: Integer;
|
|
Plugin: TSourceEditorCompletionPlugin;
|
|
Handled: Boolean;
|
|
Cancel: Boolean;
|
|
begin
|
|
for i:=0 to CompletionPluginCount-1 do begin
|
|
Plugin := CompletionPlugins[i];
|
|
Handled:=false;
|
|
Cancel:=false;
|
|
Plugin.Init(SrcEdit,JumpToError,Handled,Cancel,s,BoxX,BoxY);
|
|
if Cancel then begin
|
|
DeactivateCompletionForm;
|
|
exit(false);
|
|
end;
|
|
if Handled then begin
|
|
FActiveCompletionPlugin:=Plugin;
|
|
exit(true);
|
|
end;
|
|
end;
|
|
|
|
if not (SrcEdit.SyntaxHighlighterType in [lshFreePascal, lshDelphi]) then
|
|
UseWordCompletion:=true;
|
|
Result:=true;
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.CompletionPluginCount: integer;
|
|
begin
|
|
Result:=fCompletionPlugins.Count;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.DeactivateCompletionForm;
|
|
var
|
|
PluginFocused: Boolean;
|
|
begin
|
|
if ActiveCompletionPlugin<>nil then begin
|
|
ActiveCompletionPlugin.Cancel;
|
|
FActiveCompletionPlugin:=nil;
|
|
end;
|
|
|
|
if (FDefaultCompletionForm=nil) or
|
|
(FDefaultCompletionForm.CurrentCompletionType = ctNone)
|
|
then
|
|
exit;
|
|
|
|
// Do not move focus, if it was moved by user
|
|
PluginFocused := FDefaultCompletionForm.TheForm.Focused;
|
|
|
|
// clear the IdentifierList (otherwise it would try to update everytime
|
|
// the codetools are used)
|
|
CodeToolBoss.IdentifierList.Clear;
|
|
FDefaultCompletionForm.CurrentCompletionType:=ctNone;
|
|
|
|
(* SetFocus and Deactivate will all trigger this proc to be reentered.
|
|
Setting "CurrentCompletionType:=ctNone" ensures an immediate exit
|
|
*)
|
|
|
|
(* Due to a bug under XFCE we must move focus before we close the form
|
|
This is relevant if the form is closed by enter/escape key
|
|
*)
|
|
if PluginFocused and (ActiveEditor<>nil) then
|
|
TSourceEditor(ActiveEditor).FocusEditor;
|
|
|
|
(* hide/close the form *)
|
|
FDefaultCompletionForm.Deactivate;
|
|
|
|
(* Ensure focus *after* the form was closed.
|
|
This is the normal implementation (all but XFCE)
|
|
*)
|
|
if PluginFocused and (ActiveEditor<>nil) then
|
|
TSourceEditor(ActiveEditor).FocusEditor;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.RegisterCompletionPlugin(
|
|
Plugin: TSourceEditorCompletionPlugin);
|
|
begin
|
|
fCompletionPlugins.Add(Plugin);
|
|
Plugin.FreeNotification(Self);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.UnregisterCompletionPlugin(
|
|
Plugin: TSourceEditorCompletionPlugin);
|
|
begin
|
|
Plugin.RemoveFreeNotification(Self);
|
|
fCompletionPlugins.Remove(Plugin);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if Operation=opRemove then
|
|
begin
|
|
if Assigned(fCompletionPlugins) then
|
|
fCompletionPlugins.Remove(AComponent);
|
|
if ActiveCompletionPlugin = AComponent then
|
|
DeactivateCompletionForm;
|
|
if AComponent is TSourceMarklingProducer then
|
|
fProducers.Remove(AComponent);
|
|
end;
|
|
end;
|
|
|
|
constructor TSourceEditorManagerBase.Create(AOwner: TComponent);
|
|
var
|
|
i: TsemChangeReason;
|
|
begin
|
|
for i := low(TsemChangeReason) to high(TsemChangeReason) do
|
|
FChangeNotifyLists[i] := TMethodList.Create;
|
|
SrcEditorIntf.SourceEditorManagerIntf := Self;
|
|
FSourceWindowList := TFPList.Create;
|
|
FSourceWindowByFocusList := TFPList.Create;
|
|
FCompletionPlugins := TFPList.Create;
|
|
FUpdateLock := 0;
|
|
FActiveEditorLock := 0;
|
|
fProducers := TFPList.Create;
|
|
inherited;
|
|
end;
|
|
|
|
destructor TSourceEditorManagerBase.Destroy;
|
|
var
|
|
i: integer;
|
|
cr: TsemChangeReason;
|
|
begin
|
|
for i:=MarklingProducerCount-1 downto 0 do
|
|
MarklingProducers[i].Free;
|
|
FreeAndNil(fProducers);
|
|
FActiveWindow := nil;
|
|
FreeCompletionPlugins;
|
|
FreeSourceWindows;
|
|
SrcEditorIntf.SourceEditorManagerIntf := nil; // xx move down
|
|
FreeAndNil(FCompletionPlugins);
|
|
FreeAndNil(FSourceWindowList);
|
|
FreeAndNil(FSourceWindowByFocusList);
|
|
for cr := low(TsemChangeReason) to high(TsemChangeReason) do
|
|
FChangeNotifyLists[cr].Free;;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.RegisterChangeEvent(
|
|
AReason: TsemChangeReason; AHandler: TNotifyEvent);
|
|
begin
|
|
FChangeNotifyLists[AReason].Add(TMethod(AHandler));
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.UnRegisterChangeEvent(
|
|
AReason: TsemChangeReason; AHandler: TNotifyEvent);
|
|
begin
|
|
FChangeNotifyLists[AReason].Remove(TMethod(AHandler));
|
|
end;
|
|
|
|
function TSourceEditorManagerBase.MarklingProducerCount: integer;
|
|
begin
|
|
Result:=fProducers.Count;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.RegisterMarklingProducer(
|
|
aProducer: TSourceMarklingProducer);
|
|
begin
|
|
if fProducers.IndexOf(aProducer)>=0 then
|
|
RaiseException('TSourceEditorManagerBase.RegisterProducer already registered');
|
|
fProducers.Add(aProducer);
|
|
FreeNotification(aProducer);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.UnregisterMarklingProducer(
|
|
aProducer: TSourceMarklingProducer);
|
|
var
|
|
i: LongInt;
|
|
begin
|
|
i:=fProducers.IndexOf(aProducer);
|
|
if i<0 then exit;
|
|
fProducers.Delete(i);
|
|
RemoveFreeNotification(aProducer);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.InvalidateMarklingsOfAllFiles(
|
|
aProducer: TSourceMarklingProducer);
|
|
var
|
|
SrcWnd: TSourceEditorWindowInterface;
|
|
i: Integer;
|
|
j: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if aProducer=nil then exit;
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
begin
|
|
SrcWnd:=SourceWindows[i];
|
|
for j:=0 to SrcWnd.Count-1 do
|
|
begin
|
|
SrcEdit:=TSourceEditor(SrcWnd[j]);
|
|
SrcEdit.FSharedValues.FMarklingsValid:=false;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.InvalidateMarklings(
|
|
aProducer: TSourceMarklingProducer; aFilename: string);
|
|
var
|
|
SrcWnd: TSourceEditorWindowInterface;
|
|
i: Integer;
|
|
j: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if aProducer=nil then exit;
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
begin
|
|
SrcWnd:=SourceWindows[i];
|
|
for j:=0 to SrcWnd.Count-1 do
|
|
begin
|
|
SrcEdit:=TSourceEditor(SrcWnd[j]);
|
|
if CompareFilenames(SrcEdit.FileName,aFilename)=0 then
|
|
SrcEdit.FSharedValues.FMarklingsValid:=false;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.IncUpdateLock;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FUpdateLock = 0 then begin
|
|
FShowWindowOnTop := False;
|
|
FShowWindowOnTopFocus := False;
|
|
end;
|
|
inc(FUpdateLock);
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
TSourceNotebook(SourceWindows[i]).IncUpdateLock;
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.DecUpdateLock;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
TSourceNotebook(SourceWindows[i]).DecUpdateLock;
|
|
dec(FUpdateLock);
|
|
if (FUpdateLock = 0) and FShowWindowOnTop then
|
|
ShowActiveWindowOnTop(FShowWindowOnTopFocus);
|
|
end;
|
|
|
|
procedure TSourceEditorManagerBase.ShowActiveWindowOnTop(Focus: Boolean);
|
|
begin
|
|
if ActiveSourceWindow = nil then exit;
|
|
if FUpdateLock > 0 then begin
|
|
FShowWindowOnTop := True;
|
|
if Focus then
|
|
FShowWindowOnTopFocus := True;
|
|
exit;
|
|
end;
|
|
IDEWindowCreators.ShowForm(ActiveSourceWindow,true);
|
|
if Focus and ActiveSourceWindow.IsVisible then
|
|
TSourceNotebook(ActiveSourceWindow).FocusEditor;
|
|
end;
|
|
|
|
{ TSourceEditorManager }
|
|
|
|
function TSourceEditorManager.GetActiveSourceNotebook: TSourceNotebook;
|
|
begin
|
|
Result := TSourceNotebook(inherited ActiveSourceWindow);
|
|
end;
|
|
|
|
function TSourceEditorManager.GetActiveSrcEditor: TSourceEditor;
|
|
begin
|
|
Result := TSourceEditor(inherited ActiveEditor);
|
|
end;
|
|
|
|
function TSourceEditorManager.GetSourceEditorsByPage(WindowIndex,
|
|
PageIndex: integer): TSourceEditor;
|
|
begin
|
|
if SourceWindows[WindowIndex] <> nil then
|
|
Result := SourceWindows[WindowIndex].FindSourceEditorWithPageIndex(PageIndex)
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TSourceEditorManager.GetSourceNbByLastFocused(Index: Integer): TSourceNotebook;
|
|
begin
|
|
Result := TSourceNotebook(inherited SourceWindowByLastFocused[Index]);
|
|
end;
|
|
|
|
function TSourceEditorManager.GetSrcEditors(Index: integer): TSourceEditor;
|
|
begin
|
|
Result := TSourceEditor(inherited SourceEditors[Index]);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.SetActiveSourceNotebook(
|
|
const AValue: TSourceNotebook);
|
|
begin
|
|
inherited ActiveSourceWindow := AValue;
|
|
end;
|
|
|
|
function TSourceEditorManager.GetSourceNotebook(Index: integer
|
|
): TSourceNotebook;
|
|
begin
|
|
Result := TSourceNotebook(inherited SourceWindows[Index]);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.SetActiveSrcEditor(const AValue: TSourceEditor);
|
|
begin
|
|
inherited ActiveEditor := AValue;
|
|
end;
|
|
|
|
function TSourceEditorManager.SourceWindowWithEditor(
|
|
const AEditor: TSourceEditorInterface): TSourceNotebook;
|
|
begin
|
|
Result := TSourceNotebook(inherited SourceWindowWithEditor(AEditor));
|
|
end;
|
|
|
|
function TSourceEditorManager.ActiveOrNewSourceWindow: TSourceNotebook;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := ActiveSourceWindow;
|
|
if Result <> nil then exit;
|
|
if SourceWindowCount>0 then begin
|
|
for i:=0 to SourceWindowCount-1 do
|
|
begin
|
|
Result:=SourceWindows[i];
|
|
if Result.FIsClosing then continue;
|
|
ActiveSourceWindow := Result;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
Result := CreateNewWindow(True);
|
|
ActiveSourceWindow := Result;
|
|
end;
|
|
|
|
function TSourceEditorManager.NewSourceWindow: TSourceNotebook;
|
|
begin
|
|
Result := CreateNewWindow(True);
|
|
ActiveSourceWindow := Result;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.CreateSourceWindow(Sender: TObject;
|
|
aFormName: string; var AForm: TCustomForm; DoDisableAutoSizing: boolean);
|
|
begin
|
|
{$IFDEF VerboseIDEDocking}
|
|
debugln(['TSourceEditorManager.CreateSourceWindow Sender=',DbgSName(Sender),' FormName="',aFormName,'"']);
|
|
{$ENDIF}
|
|
AForm := CreateNewWindow(false,DoDisableAutoSizing);
|
|
AForm.Name:=aFormName;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.GetDefaultLayout(Sender: TObject;
|
|
aFormName: string; out aBounds: TRect; out DockSibling: string; out
|
|
DockAlign: TAlign);
|
|
var
|
|
i: LongInt;
|
|
p: Integer;
|
|
begin
|
|
DockSibling:='';
|
|
DockAlign:=alNone;
|
|
i:=StrToIntDef(
|
|
copy(aFormName,length(NonModalIDEWindowNames[nmiwSourceNoteBookName])+1,
|
|
length(aFormName)),0);
|
|
{$IFDEF VerboseIDEDocking}
|
|
debugln(['TSourceEditorManager.GetDefaultLayout ',aFormName,' i=',i]);
|
|
{$ENDIF}
|
|
if Application.MainForm<>nil then
|
|
p:=Min(200,Application.MainForm.Top+Application.MainForm.Height+25)
|
|
else
|
|
p:=120;
|
|
inc(p,30*i);
|
|
aBounds:=Rect(250+30*i,p,Min(1000,Screen.Width-300),Screen.Height-200);
|
|
if (i=0) and (IDEDockMaster<>nil) then begin
|
|
DockSibling:=NonModalIDEWindowNames[nmiwMainIDEName];
|
|
DockAlign:=alBottom;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManager.SourceWindowWithPage(const APage: TTabSheet
|
|
): TSourceNotebook;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
for i := FSourceWindowList.Count-1 downto 0 do begin
|
|
if TSourceNotebook(SourceWindows[i]).FNoteBook.PageList.IndexOf(APage) >= 0 then begin
|
|
Result := SourceWindows[i];
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManager.SourceEditorCount: integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := 0;
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
Result := Result + SourceWindows[i].Count;
|
|
end;
|
|
|
|
|
|
function TSourceEditorManager.GetActiveSE: TSourceEditor;
|
|
begin
|
|
Result := TSourceEditor(ActiveEditor);
|
|
end;
|
|
|
|
function TSourceEditorManager.SourceEditorIntfWithFilename(
|
|
const Filename: string): TSourceEditor;
|
|
begin
|
|
Result := TSourceEditor(inherited SourceEditorIntfWithFilename(Filename));
|
|
end;
|
|
|
|
function TSourceEditorManager.FindSourceEditorWithEditorComponent(
|
|
EditorComp: TComponent): TSourceEditor;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
i := SourceWindowCount - 1;
|
|
while i >= 0 do begin
|
|
Result := SourceWindows[i].FindSourceEditorWithEditorComponent(EditorComp);
|
|
if Result <> nil then break;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.NewEditorCreated(AEditor: TSourceEditor);
|
|
begin
|
|
if FDefaultCompletionForm <> nil then
|
|
FDefaultCompletionForm.AddEditor(AEditor.EditorComponent);
|
|
FChangeNotifyLists[semEditorCreate].CallNotifyEvents(AEditor);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.EditorRemoved(AEditor: TSourceEditor);
|
|
begin
|
|
if FDefaultCompletionForm <> nil then
|
|
FDefaultCompletionForm.RemoveEditor(AEditor.EditorComponent);
|
|
FChangeNotifyLists[semEditorDestroy].CallNotifyEvents(AEditor);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if Operation=opRemove then
|
|
begin
|
|
if AComponent is TSourceNotebook then
|
|
RemoveWindow(TSourceNotebook(AComponent));
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.ClearErrorLines;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := FSourceWindowList.Count - 1 downto 0 do
|
|
SourceWindows[i].ClearErrorLines;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.ClearExecutionLines;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := FSourceWindowList.Count - 1 downto 0 do
|
|
SourceWindows[i].ClearExecutionLines;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.ClearExecutionMarks;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := FSourceWindowList.Count - 1 downto 0 do
|
|
SourceWindows[i].ClearExecutionMarks;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.FillExecutionMarks;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := FSourceWindowList.Count - 1 downto 0 do
|
|
SourceWindows[i].GetActiveSE.FillExecutionMarks;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.ReloadEditorOptions;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := FSourceWindowList.Count - 1 downto 0 do
|
|
SourceWindows[i].ReloadEditorOptions;
|
|
|
|
SourceCompletionTimer.Interval:=EditorOpts.AutoDelayInMSec;
|
|
// reload code templates
|
|
with CodeTemplateModul do begin
|
|
if FileExistsUTF8(EditorOpts.CodeTemplateFilename) then
|
|
AutoCompleteList.LoadFromFile(UTF8ToSys(EditorOpts.CodeTemplateFilename))
|
|
else
|
|
if FileExistsUTF8('lazarus.dci') then
|
|
AutoCompleteList.LoadFromFile(UTF8ToSys('lazarus.dci'));
|
|
IndentToTokenStart:=EditorOpts.CodeTemplateIndentToTokenStart;
|
|
end;
|
|
|
|
if FDefaultCompletionForm <> nil then begin
|
|
FDefaultCompletionForm.LongLineHintTime := EditorOpts.CompletionLongLineHintInMSec;
|
|
FDefaultCompletionForm.LongLineHintType := EditorOpts.CompletionLongLineHintType;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.FindClicked(Sender: TObject);
|
|
begin
|
|
if ActiveEditor <> nil then ActiveEditor.StartFindAndReplace(false);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.FindNextClicked(Sender: TObject);
|
|
begin
|
|
if ActiveEditor <> nil then ActiveEditor.FindNextUTF8;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.FindPreviousClicked(Sender: TObject);
|
|
begin
|
|
if ActiveEditor <> nil then ActiveEditor.FindPrevious;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.ReplaceClicked(Sender: TObject);
|
|
begin
|
|
if ActiveEditor <> nil then ActiveEditor.StartFindAndReplace(true);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.IncrementalFindClicked(Sender: TObject);
|
|
begin
|
|
if ActiveSourceWindow <> nil then ActiveSourceWindow.BeginIncrementalFind;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.GotoLineClicked(Sender: TObject);
|
|
begin
|
|
if ActiveEditor <> nil then ActiveEditor.ShowGotoLineDialog;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.JumpBackClicked(Sender: TObject);
|
|
begin
|
|
if ActiveSourceWindow <> nil then HistoryJump(Sender,jhaBack);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.JumpForwardClicked(Sender: TObject);
|
|
begin
|
|
if ActiveSourceWindow <> nil then HistoryJump(Sender,jhaForward);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.AddJumpPointClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnAddJumpPoint) and (ActiveEditor <> nil) then
|
|
OnAddJumpPoint(ActiveEditor.EditorComponent.LogicalCaretXY,
|
|
ActiveEditor.EditorComponent.TopLine, ActiveEditor, true);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.DeleteLastJumpPointClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnDeleteLastJumpPoint) then
|
|
OnDeleteLastJumpPoint(Sender);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.ViewJumpHistoryClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnViewJumpHistory) then
|
|
OnViewJumpHistory(Sender);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.BookMarkSetFreeClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnSetBookmark) then
|
|
OnSetBookmark(ActiveEditor, -1, False);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.BookMarkToggleClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnSetBookmark) then
|
|
OnSetBookmark(ActiveEditor, (Sender as TIDEMenuItem).SectionIndex, True);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.BookMarkGotoClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnGotoBookmark) then
|
|
OnGotoBookmark(ActiveEditor, (Sender as TIDEMenuItem).SectionIndex, False);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.BookMarkNextClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnGotoBookmark) then
|
|
OnGotoBookmark(ActiveEditor, -1, False);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.BookMarkPrevClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnGotoBookmark) then
|
|
OnGotoBookmark(ActiveEditor, -1, True);
|
|
end;
|
|
|
|
function TSourceEditorManager.MacroFuncCol(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
begin
|
|
if (ActiveEditor <> nil) then
|
|
Result:=IntToStr(ActiveEditor.EditorComponent.CaretX)
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceEditorManager.MacroFuncRow(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
begin
|
|
if (ActiveEditor <> nil) then
|
|
Result:=IntToStr(ActiveEditor.EditorComponent.CaretY)
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceEditorManager.MacroFuncEdFile(const s: string;
|
|
const Data: PtrInt; var Abort: boolean): string;
|
|
begin
|
|
if (ActiveEditor <> nil) then
|
|
Result := ActiveEditor.FileName
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TSourceEditorManager.MacroFuncCurToken(const s: string;
|
|
const Data: PtrInt; var Abort: boolean): string;
|
|
begin
|
|
if (ActiveEditor <> nil) then begin
|
|
with ActiveEditor.EditorComponent do
|
|
Result := GetWordAtRowCol(LogicalCaretXY)
|
|
end else
|
|
Result := '';
|
|
end;
|
|
|
|
function TSourceEditorManager.MacroFuncPrompt(const s: string;
|
|
const Data: PtrInt; var Abort: boolean): string;
|
|
begin
|
|
Result:=s;
|
|
Abort:=(ShowMacroPromptDialog(Result)<>mrOk);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.InitMacros(AMacroList: TTransferMacroList);
|
|
begin
|
|
AMacroList.Add(TTransferMacro.Create('Col','',
|
|
lisCursorColumnInCurrentEditor,@MacroFuncCol,[]));
|
|
AMacroList.Add(TTransferMacro.Create('Row','',
|
|
lisCursorRowInCUrrentEditor,@MacroFuncRow,[]));
|
|
AMacroList.Add(TTransferMacro.Create('CurToken','',
|
|
lisWordAtCursorInCurrentEditor,@MacroFuncCurToken,[]));
|
|
AMacroList.Add(TTransferMacro.Create('EdFile','',
|
|
lisExpandedFilenameOfCurrentEditor,@MacroFuncEdFile,[]));
|
|
AMacroList.Add(TTransferMacro.Create('Prompt','',
|
|
lisPromptForValue,@MacroFuncPrompt,[tmfInteractive]));
|
|
end;
|
|
|
|
procedure TSourceEditorManager.SetupShortCuts;
|
|
|
|
function GetCommand(ACommand: Word): TIDECommand; inline;
|
|
begin
|
|
Result := IDECommandList.FindIDECommand(ACommand);
|
|
end;
|
|
|
|
begin
|
|
SrcEditMenuProcedureJump.Command:=GetCommand(ecFindProcedureDefinition);
|
|
SrcEditMenuFindinFiles.Command:=GetCommand(ecFindInFiles);
|
|
|
|
SrcEditMenuCut.Command:=GetCommand(ecCut);
|
|
SrcEditMenuCopy.Command:=GetCommand(ecCopy);
|
|
SrcEditMenuPaste.Command:=GetCommand(ecPaste);
|
|
|
|
SrcEditMenuCompleteCode.Command:=GetCommand(ecCompleteCode);
|
|
SrcEditMenuRenameIdentifier.Command:=GetCommand(ecRenameIdentifier);
|
|
SrcEditMenuFindIdentifierReferences.Command:=GetCommand(ecFindIdentifierRefs);
|
|
SrcEditMenuExtractProc.Command:=GetCommand(ecExtractProc);
|
|
SrcEditMenuShowAbstractMethods.Command:=GetCommand(ecShowAbstractMethods);
|
|
SrcEditMenuShowEmptyMethods.Command:=GetCommand(ecRemoveEmptyMethods);
|
|
SrcEditMenuShowUnusedUnits.Command:=GetCommand(ecRemoveUnusedUnits);
|
|
SrcEditMenuFindOverloads.Command:=GetCommand(ecFindOverloads);
|
|
|
|
DebugBoss.SetupSourceMenuShortCuts;
|
|
end;
|
|
|
|
function TSourceEditorManager.FindUniquePageName(FileName: string;
|
|
IgnoreEditor: TSourceEditor): string;
|
|
var
|
|
I:integer;
|
|
ShortName:string;
|
|
|
|
function PageNameExists(const AName:string):boolean;
|
|
var a:integer;
|
|
begin
|
|
Result:=false;
|
|
for a := 0 to SourceEditorCount - 1 do begin
|
|
if (SourceEditors[a] <> IgnoreEditor) and
|
|
(not SourceEditors[a].IsSharedWith(IgnoreEditor)) and
|
|
(AnsiCompareText(AName, SourceEditors[a].PageName) = 0)
|
|
then begin
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if FileName='' then begin
|
|
FileName:='unit1';
|
|
if not PageNameExists(FileName) then begin
|
|
Result:=Filename;
|
|
exit;
|
|
end;
|
|
end;
|
|
if FilenameIsPascalUnit(FileName) then
|
|
ShortName:=ExtractFileNameOnly(Filename)
|
|
else
|
|
ShortName:=ExtractFileName(FileName);
|
|
Result:=ShortName;
|
|
if PageNameExists(Result) then begin
|
|
i:=1;
|
|
repeat
|
|
inc(i);
|
|
Result:=ShortName+'('+IntToStr(i)+')';
|
|
until PageNameExists(Result)=false;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManager.SomethingModified: boolean;
|
|
var
|
|
i: integer;
|
|
begin
|
|
Result:=false;
|
|
for i:=0 to SourceEditorCount - 1 do Result := Result or SourceEditors[i].Modified;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.HideHint;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to SourceWindowCount - 1 do
|
|
SourceWindows[i].HideHint;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnIdle(Sender: TObject; var Done: Boolean);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
i: Integer;
|
|
aFilename: String;
|
|
FreeList, FreeMarklings: boolean;
|
|
Marklings: TFPList;
|
|
j: Integer;
|
|
Markling: TSourceMarkling;
|
|
begin
|
|
SrcEdit:=ActiveEditor;
|
|
if not SrcEdit.FSharedValues.FMarklingsValid then
|
|
begin
|
|
//debugln(['TSourceEditorManager.OnIdle ',MarklingProducerCount]);
|
|
aFilename:=SrcEdit.FileName;
|
|
SrcEdit.EditorComponent.BeginUpdate;
|
|
for i:=0 to MarklingProducerCount-1 do
|
|
begin
|
|
Marklings:=MarklingProducers[i].GetMarklings(aFilename,FreeList,FreeMarklings);
|
|
for j:=0 to Marklings.Count-1 do
|
|
begin
|
|
Markling:=TSourceMarkling(Marklings[j]);
|
|
if Markling=nil then ;
|
|
// ToDo: add mark to synedit
|
|
//debugln(['TSourceEditorManager.OnIdle ',Markling.Id,' ',Markling.Line,',',Markling.Column]);
|
|
|
|
end;
|
|
if FreeMarklings then
|
|
for j:=0 to Marklings.Count-1 do
|
|
TObject(Marklings[j]).Free;
|
|
if FreeList then
|
|
Marklings.Free;
|
|
end;
|
|
SrcEdit.EditorComponent.EndUpdate;
|
|
SrcEdit.FSharedValues.FMarklingsValid:=true;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.LockAllEditorsInSourceChangeCache;
|
|
// lock all sourceeditors that are to be modified by the CodeToolBoss
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:=0 to SourceEditorCount - 1 do begin
|
|
if CodeToolBoss.SourceChangeCache.BufferIsModified(SourceEditors[i].CodeBuffer)
|
|
then
|
|
SourceEditors[i].BeginGlobalUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.UnlockAllEditorsInSourceChangeCache;
|
|
// unlock all sourceeditors that were modified by the CodeToolBoss
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i:=0 to SourceEditorCount - 1 do begin
|
|
if CodeToolBoss.SourceChangeCache.BufferIsModified(SourceEditors[i].CodeBuffer)
|
|
then
|
|
SourceEditors[i].EndGlobalUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.CloseFile(AEditor: TSourceEditorInterface);
|
|
var
|
|
i, j: Integer;
|
|
begin
|
|
i := SourceWindowCount - 1;
|
|
while i >= 0 do begin
|
|
j := SourceWindows[i].FindPageWithEditor(TSourceEditor(AEditor));
|
|
if j >= 0 then begin
|
|
SourceWindows[i].CloseFile(j);
|
|
break;
|
|
end;
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.HistoryJump(Sender: TObject;
|
|
CloseAction: TJumpHistoryAction);
|
|
var NewCaretXY: TPoint;
|
|
NewTopLine: integer;
|
|
NewEditor: TSourceEditor;
|
|
begin
|
|
if Assigned(OnJumpToHistoryPoint) then begin
|
|
NewCaretXY.X:=-1;
|
|
NewEditor:=nil;
|
|
OnJumpToHistoryPoint(NewCaretXY,NewTopLine,NewEditor,CloseAction);
|
|
if NewEditor<>nil then begin
|
|
ActiveEditor := NewEditor;
|
|
ShowActiveWindowOnTop(True);
|
|
with NewEditor.EditorComponent do begin
|
|
if not NewEditor.IsLocked then
|
|
TopLine:=NewTopLine;
|
|
LogicalCaretXY:=NewCaretXY;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnFilesDroping(Sender: TObject; const FileNames: Array of String);
|
|
begin
|
|
if Sender is TSourceNotebook then
|
|
ActiveSourceWindow := TSourceNotebook(Sender);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnCodeTemplateTokenNotFound(Sender: TObject;
|
|
AToken: string; AnEditor: TCustomSynEdit; var Index: integer);
|
|
var
|
|
P:TPoint;
|
|
begin
|
|
//writeln('TSourceNotebook.OnCodeTemplateTokenNotFound ',AToken,',',AnEditor.ReadOnly,',',DefaultCompletionForm.CurrentCompletionType=ctNone);
|
|
if (AnEditor.ReadOnly=false) and
|
|
(DefaultCompletionForm.CurrentCompletionType=ctNone)
|
|
then begin
|
|
DefaultCompletionForm.CurrentCompletionType:=ctTemplateCompletion;
|
|
with AnEditor do begin
|
|
P := Point(CaretXPix - length(AToken)*CharWidth,CaretYPix + LineHeight + 1);
|
|
P.X:=Max(0,Min(P.X,ClientWidth-DefaultCompletionForm.Width));
|
|
P := ClientToScreen(p);
|
|
end;
|
|
DefaultCompletionForm.Editor:=AnEditor;
|
|
DefaultCompletionForm.Execute(AToken,P.X,P.Y);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnCodeTemplateExecuteCompletion(
|
|
ASynAutoComplete: TCustomSynAutoComplete; Index: integer);
|
|
var
|
|
SrcEdit: TSourceEditorInterface;
|
|
TemplateName: string;
|
|
TemplateValue: string;
|
|
TemplateComment: string;
|
|
TemplateAttr: TStrings;
|
|
begin
|
|
SrcEdit:=FindSourceEditorWithEditorComponent(ASynAutoComplete.Editor);
|
|
if SrcEdit=nil then
|
|
SrcEdit := ActiveEditor;
|
|
//debugln('TSourceNotebook.OnCodeTemplateExecuteCompletion A ',dbgsName(SrcEdit),' ',dbgsName(ASynAutoComplete.Editor));
|
|
|
|
TemplateName:=ASynAutoComplete.Completions[Index];
|
|
TemplateValue:=ASynAutoComplete.CompletionValues[Index];
|
|
TemplateComment:=ASynAutoComplete.CompletionComments[Index];
|
|
TemplateAttr:=ASynAutoComplete.CompletionAttributes[Index];
|
|
ExecuteCodeTemplate(SrcEdit,TemplateName,TemplateValue,TemplateComment,
|
|
ASynAutoComplete.EndOfTokenChr,TemplateAttr,
|
|
ASynAutoComplete.IndentToTokenStart);
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnWordCompletionGetSource(var Source: TStrings;
|
|
SourceIndex: integer);
|
|
var TempEditor: TSourceEditor;
|
|
i:integer;
|
|
begin
|
|
TempEditor:=GetActiveSE;
|
|
if SourceIndex=0 then begin
|
|
Source:=TempEditor.EditorComponent.Lines;
|
|
end else begin
|
|
i:=0;
|
|
while (i < SourceEditorCount) do begin
|
|
if SourceEditors[i] <> TempEditor then dec(SourceIndex);
|
|
if SourceIndex = 0 then begin
|
|
Source := SourceEditors[i].EditorComponent.Lines;
|
|
exit;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Source := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnSourceCompletionTimer(Sender: TObject);
|
|
|
|
function CheckStartIdentCompletion: boolean;
|
|
var
|
|
Line: String;
|
|
LogCaret: TPoint;
|
|
p: Integer;
|
|
InStringConstant: Boolean;
|
|
SrcEdit: TSourceEditor;
|
|
Token: string;
|
|
Attri: TSynHighlighterAttributes;
|
|
begin
|
|
Result := false;
|
|
SrcEdit := ActiveEditor;
|
|
if SrcEdit = nil then exit;
|
|
Line := SrcEdit.FEditor.LineText;
|
|
LogCaret := SrcEdit.FEditor.LogicalCaretXY;
|
|
//DebugLn(['CheckStartIdentCompletion Line="',Line,'" LogCaret=',dbgs(LogCaret)]);
|
|
|
|
// check if last character is a point
|
|
if (Line='') or (LogCaret.X<=1) or (LogCaret.X-1>length(Line))
|
|
or (Line[LogCaret.X-1]<>'.') then
|
|
exit;
|
|
|
|
// check if range operator '..'
|
|
if (LogCaret.X>2) and (Line[LogCaret.X-2]='.') then
|
|
exit; // this is a double point ..
|
|
|
|
// check if in a string constant
|
|
p:=1;
|
|
InStringConstant:=false;
|
|
while (p<=LogCaret.X) and (p<=length(Line)) do begin
|
|
if Line[p]='''' then
|
|
InStringConstant:=not InStringConstant;
|
|
inc(p);
|
|
end;
|
|
if InStringConstant then exit;
|
|
|
|
// check if in a comment
|
|
Token:='';
|
|
Attri:=nil;
|
|
dec(LogCaret.X);
|
|
if SrcEdit.EditorComponent.GetHighlighterAttriAtRowCol(LogCaret,Token,Attri)
|
|
and (Attri<>nil) and (Attri.Name=SYNS_AttrComment) then
|
|
begin
|
|
exit;
|
|
end;
|
|
|
|
// invoke identifier completion
|
|
SrcEdit.StartIdentCompletionBox(false);
|
|
Result:=true;
|
|
end;
|
|
|
|
function CheckTemplateCompletion: boolean;
|
|
begin
|
|
Result:=false;
|
|
// execute context sensitive templates
|
|
//FCodeTemplateModul.ExecuteCompletion(Value,GetActiveSE.EditorComponent);
|
|
end;
|
|
|
|
var
|
|
TempEditor: TSourceEditor;
|
|
begin
|
|
SourceCompletionTimer.Enabled:=false;
|
|
SourceCompletionTimer.AutoEnabled:=false;
|
|
TempEditor := ActiveEditor;
|
|
if (TempEditor <> nil) and TempEditor.EditorComponent.Focused and
|
|
(ComparePoints(TempEditor.EditorComponent.CaretXY, SourceCompletionCaretXY) = 0)
|
|
then begin
|
|
if CheckStartIdentCompletion then begin
|
|
end
|
|
else if CheckTemplateCompletion then begin
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditorManager.OnSourceMarksGetSourceEditorID(
|
|
ASrcEdit: TSourceEditorInterface): TObject;
|
|
begin
|
|
Result := TSourceEditor(ASrcEdit).FSharedValues;
|
|
end;
|
|
|
|
function TSourceEditorManager.OnSourceMarksGetFilename(ASourceEditor: TObject
|
|
): string;
|
|
begin
|
|
if (ASourceEditor = nil) or (not (ASourceEditor is TSourceEditor)) then
|
|
RaiseException('TSourceNotebook.OnSourceMarksGetFilename');
|
|
Result := TSourceEditor(ASourceEditor).Filename;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.OnSourceMarksAction(AMark: TSourceMark;
|
|
AAction: TMarksAction);
|
|
var
|
|
Editor: TSourceEditor;
|
|
i: Integer;
|
|
begin
|
|
Editor := TSourceEditor(AMark.SourceEditor);
|
|
if Editor = nil then
|
|
Exit;
|
|
|
|
if AAction = maAdded then begin
|
|
for i := 0 to Editor.FSharedValues.SharedEditorCount - 1 do
|
|
if not AMark.HasSourceEditor(Editor.FSharedValues.SharedEditors[i]) then
|
|
AMark.AddSourceEditor(Editor.FSharedValues.SharedEditors[i]);
|
|
end;
|
|
|
|
if ( AMark.IsBreakPoint and (Editor.FSharedValues.ExecutionMark <> nil) and
|
|
(AMark.Line = Editor.ExecutionLine)
|
|
) or (AMark = Editor.FSharedValues.ExecutionMark)
|
|
then
|
|
Editor.UpdateExecutionSourceMark;
|
|
end;
|
|
|
|
function TSourceEditorManager.GotoDialog: TfrmGoto;
|
|
begin
|
|
if FGotoDialog=nil then
|
|
FGotoDialog := TfrmGoto.Create(self);
|
|
Result := FGotoDialog;
|
|
end;
|
|
|
|
constructor TSourceEditorManager.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
FDefaultCompletionForm := nil;
|
|
|
|
// word completion
|
|
if aWordCompletion=nil then begin
|
|
aWordCompletion:=TWordCompletion.Create;
|
|
with AWordCompletion do begin
|
|
WordBufferCapacity:=100;
|
|
OnGetSource:=@OnWordCompletionGetSource;
|
|
end;
|
|
end;
|
|
|
|
// identifier completion
|
|
SourceCompletionTimer := TIdleTimer.Create(Self);
|
|
with SourceCompletionTimer do begin
|
|
AutoEnabled := False;
|
|
Enabled := false;
|
|
Interval := EditorOpts.AutoDelayInMSec;
|
|
OnTimer := @OnSourceCompletionTimer;
|
|
end;
|
|
|
|
// marks
|
|
SourceEditorMarks:=TSourceMarks.Create(Self);
|
|
SourceEditorMarks.OnGetSourceEditorID := @OnSourceMarksGetSourceEditorID;
|
|
SourceEditorMarks.OnGetFilename:=@OnSourceMarksGetFilename;
|
|
SourceEditorMarks.OnAction:=@OnSourceMarksAction;
|
|
|
|
// code templates
|
|
FCodeTemplateModul:=TSynEditAutoComplete.Create(Self);
|
|
with FCodeTemplateModul do begin
|
|
if FileExistsUTF8(EditorOpts.CodeTemplateFilename) then
|
|
AutoCompleteList.LoadFromFile(UTF8ToSys(EditorOpts.CodeTemplateFilename))
|
|
else
|
|
if FileExistsUTF8('lazarus.dci') then
|
|
AutoCompleteList.LoadFromFile(UTF8ToSys('lazarus.dci'));
|
|
IndentToTokenStart := EditorOpts.CodeTemplateIndentToTokenStart;
|
|
OnTokenNotFound := @OnCodeTemplateTokenNotFound;
|
|
OnExecuteCompletion := @OnCodeTemplateExecuteCompletion;
|
|
EndOfTokenChr:=' ()[]{},.;:"+-*^@$\<>=''';
|
|
end;
|
|
|
|
// layout
|
|
IDEWindowCreators.Add(NonModalIDEWindowNames[nmiwSourceNoteBookName],
|
|
nil,@CreateSourceWindow,'250','100','+70%','+70%',
|
|
NonModalIDEWindowNames[nmiwMainIDEName],alBottom,
|
|
true,@GetDefaultLayout);
|
|
|
|
Application.AddOnIdleHandler(@OnIdle);
|
|
end;
|
|
|
|
destructor TSourceEditorManager.Destroy;
|
|
begin
|
|
Application.RemoveAllHandlersOfObject(Self);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function SortSourceWindows(SrcWin1, SrcWin2: TSourceNotebook): Integer;
|
|
begin
|
|
Result := AnsiStrComp(PChar(SrcWin1.Caption), PChar(SrcWin2.Caption));
|
|
end;
|
|
|
|
function TSourceEditorManager.CreateNewWindow(Activate: Boolean= False;
|
|
DoDisableAutoSizing: boolean = false): TSourceNotebook;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := TSourceNotebook(TSourceNotebook.NewInstance);
|
|
Result.DisableAutoSizing;
|
|
Result.Create(Self);
|
|
Result.OnDropFiles := @OnFilesDroping;
|
|
|
|
for i := 1 to FUpdateLock do
|
|
Result.IncUpdateLock;
|
|
FSourceWindowList.Add(Result);
|
|
FSourceWindowList.Sort(TListSortCompare(@SortSourceWindows));
|
|
FSourceWindowByFocusList.Add(Result);
|
|
if Activate then begin
|
|
ActiveSourceWindow := Result;
|
|
ShowActiveWindowOnTop(False);
|
|
end;
|
|
FChangeNotifyLists[semWindowCreate].CallNotifyEvents(Result);
|
|
if not DoDisableAutoSizing then
|
|
Result.EnableAutoSizing;
|
|
end;
|
|
|
|
procedure TSourceEditorManager.RemoveWindow(AWindow: TSourceNotebook);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if FSourceWindowList = nil then exit;
|
|
i := FSourceWindowList.IndexOf(AWindow);
|
|
FSourceWindowList.Remove(AWindow);
|
|
FSourceWindowByFocusList.Remove(AWindow);
|
|
if SourceWindowCount = 0 then
|
|
ActiveSourceWindow := nil
|
|
else if ActiveSourceWindow = AWindow then
|
|
ActiveSourceWindow := SourceWindows[Max(0, Min(i, SourceWindowCount-1))];
|
|
if i >= 0 then
|
|
FChangeNotifyLists[semWindowDestroy].CallNotifyEvents(AWindow);
|
|
end;
|
|
|
|
initialization
|
|
InternalInit;
|
|
{$I ../images/bookmark.lrs}
|
|
|
|
finalization
|
|
InternalFinal;
|
|
|
|
end.
|
|
|