mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-13 00:49:23 +02:00
6880 lines
216 KiB
ObjectPascal
6880 lines
216 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}
|
|
|
|
uses
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
MemCheck,
|
|
{$ENDIF}
|
|
Classes, SysUtils, Math, Controls, LCLProc, LCLType, LResources, LCLIntf,
|
|
FileUtil, Forms, Buttons, ComCtrls, Dialogs, StdCtrls, GraphType, Graphics,
|
|
Translations, ClipBrd, TypInfo, Extctrls, Menus, HelpIntfs, LazHelpIntf,
|
|
LConvEncoding, LDockCtrl,
|
|
// codetools
|
|
CodeToolManager, CodeCache, SourceLog,
|
|
// synedit
|
|
SynEditStrConst, SynEditTypes, SynEdit, SynRegExpr, SynEditHighlighter,
|
|
SynEditAutoComplete, SynEditKeyCmds, SynCompletion, SynEditMiscClasses,
|
|
SynEditMarkupHighAll, SynGutterLineNumber, SynEditMarks,
|
|
// IDE interface
|
|
MacroIntf, ProjectIntf, SrcEditorIntf, MenuIntf, LazIDEIntf, PackageIntf,
|
|
IDEDialogs, IDEHelpIntf, IDEWindowIntf, IDEImagesIntf,
|
|
// IDE units
|
|
LazarusIDEStrConsts, LazConf, IDECommands, EditorOptions, KeyMapping, Project,
|
|
WordCompletion, FindReplaceDialog, FindInFilesDlg, IDEProcs, IDEOptionDefs,
|
|
MacroPromptDlg, TransferMacros, CodeContextForm, SrcEditHintFrm,
|
|
EnvironmentOpts, MsgView, SearchResultView, InputHistory, CodeMacroPrompt,
|
|
CodeTemplatesDlg, TodoDlg, TodoList,
|
|
SortSelectionDlg, EncloseSelectionDlg, DiffDialog, ConDef, InvertAssignTool,
|
|
SourceEditProcs, SourceMarks, CharacterMapDlg, SearchFrm,
|
|
FPDocHints, FPDocEditWindow,
|
|
BaseDebugManager, Debugger, MainIntf, GotoFrm;
|
|
|
|
type
|
|
TSourceNotebook = class;
|
|
|
|
TNotifyFileEvent = procedure(Sender: TObject; Filename : AnsiString) of object;
|
|
|
|
TOnAddWatch = function(Sender: TObject): boolean 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;
|
|
|
|
TSynEditPlugin1 = class(TSynEditPlugin)
|
|
private
|
|
FOnLinesInserted : TOnLinesInsertedDeleted;
|
|
FOnLinesDeleted : TOnLinesInsertedDeleted;
|
|
protected
|
|
procedure AfterPaint(ACanvas: TCanvas; AClip: TRect;
|
|
FirstLine, LastLine: integer); override;
|
|
procedure LinesInserted(FirstLine, Count: integer); override;
|
|
procedure LinesDeleted(FirstLine, Count: integer); override;
|
|
public
|
|
property OnLinesInserted : TOnLinesInsertedDeleted
|
|
read FOnLinesinserted write FOnLinesInserted;
|
|
property OnLinesDeleted : TOnLinesInsertedDeleted
|
|
read FOnLinesDeleted write FOnLinesDeleted;
|
|
|
|
constructor Create(AOwner: TCustomSynEdit);
|
|
end;
|
|
|
|
|
|
TCharSet = set of Char;
|
|
|
|
{---- TSource Editor ---
|
|
TSourceEditor is the class that controls access for the Editor.
|
|
---- TSource Editor ---}
|
|
|
|
{ TSourceEditor }
|
|
|
|
TSourceEditor = class(TSourceEditorInterface)
|
|
private
|
|
//FAOwner is normally a TSourceNotebook. This is set in the Create constructor.
|
|
FAOwner: TComponent;
|
|
FEditor: TSynEdit;
|
|
FEditPlugin: TSynEditPlugin1; // used to get the LinesInserted and
|
|
// LinesDeleted messages
|
|
FCodeTemplates: TSynEditAutoComplete;
|
|
FHasExecutionMarks: Boolean;
|
|
FMarksRequested: Boolean;
|
|
FPageName: string;
|
|
|
|
FCodeBuffer: TCodeBuffer;
|
|
FIgnoreCodeBufferLock: integer;
|
|
FEditorStampCommitedToCodetools: int64;
|
|
|
|
FPopUpMenu: TPopupMenu;
|
|
FSyntaxHighlighterType: TLazSyntaxHighlighter;
|
|
FErrorLine: integer;
|
|
FErrorColumn: integer;
|
|
FExecutionLine: integer;
|
|
FExecutionMark: TSourceMark;
|
|
FLineInfoNotification: TIDELineInfoNotification;
|
|
FModified: boolean;
|
|
|
|
FOnAfterClose: TNotifyEvent;
|
|
FOnAfterOpen: TNotifyEvent;
|
|
FOnAfterSave: TNotifyEvent;
|
|
FOnBeforeClose: TNotifyEvent;
|
|
FOnBeforeOpen: TNotifyEvent;
|
|
FOnBeforeSave: TNotifyEvent;
|
|
FOnEditorChange: TNotifyEvent;
|
|
FVisible: Boolean;
|
|
FOnMouseMove: TMouseMoveEvent;
|
|
FOnMouseDown: TMouseEvent;
|
|
FOnClickLink: TMouseEvent;
|
|
FOnMouseLink: TSynMouseLinkEvent;
|
|
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 EditorClickLink(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X,Y: Integer);
|
|
procedure EditorMouseLink(
|
|
Sender: TObject; X,Y: Integer; var AllowMouseLink: Boolean);
|
|
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 SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
|
|
function GetSource: TStrings;
|
|
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 SetCodeTemplates(NewCodeTemplates: TSynEditAutoComplete);
|
|
procedure SetPopupMenu(NewPopupMenu: TPopupMenu);
|
|
|
|
function GotoLine(Value: Integer): Integer;
|
|
|
|
procedure CreateEditor(AOwner: TComponent; AParent: TWinControl);
|
|
procedure SetVisible(Value: boolean);
|
|
procedure UnbindEditor;
|
|
protected
|
|
ErrorMsgs: TStrings;
|
|
procedure ReParent(AParent: TWinControl);
|
|
|
|
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;
|
|
|
|
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 OnCodeBufferChanged(Sender: TSourceLog;
|
|
SrcLogEntry: TSourceLogEntry);
|
|
procedure StartIdentCompletion(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;
|
|
|
|
property Visible: Boolean read FVisible write SetVisible default False;
|
|
public
|
|
constructor Create(AOwner: TComponent; AParent: TWinControl);
|
|
destructor Destroy; override;
|
|
Function Close: Boolean;
|
|
|
|
// codebuffer
|
|
procedure BeginUndoBlock; override;
|
|
procedure EndUndoBlock; override;
|
|
procedure BeginUpdate; override;
|
|
procedure EndUpdate; override;
|
|
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 InitGotoDialog;
|
|
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 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 InsertTodo;
|
|
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 GetWordAtPosition(Position: TPoint): String;
|
|
function GetWordFromCaret(const ACaretPos: TPoint): String;
|
|
function GetWordAtCurrentCaret: String;
|
|
function CaretInSelection(const ACaretPos: TPoint): Boolean;
|
|
function PositionInSelection(const APosition: TPoint): Boolean;
|
|
|
|
// cursor
|
|
function GetCaretPosFromCursorPos(const CursorPos: TPoint): TPoint;
|
|
procedure CenterCursor;
|
|
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;
|
|
|
|
// 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;
|
|
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);
|
|
public
|
|
// properties
|
|
property CodeBuffer: TCodeBuffer read FCodeBuffer write SetCodeBuffer;
|
|
property CodeTemplates: TSynEditAutoComplete
|
|
read FCodeTemplates write SetCodeTemplates;
|
|
property CurrentCursorXLine: Integer
|
|
read GetCurrentCursorXLine write SetCurrentCursorXLine;
|
|
property CurrentCursorYLine: Integer
|
|
read GetCurrentCursorYLine write SetCurrentCursorYLine;
|
|
property EditorComponent: TSynEdit read FEditor;
|
|
property ErrorLine: integer read FErrorLine write SetErrorLine;
|
|
property ExecutionLine: integer read FExecutionLine write SetExecutionLine;
|
|
property HasExecutionMarks: Boolean read FHasExecutionMarks;
|
|
property InsertMode: Boolean read GetInsertmode;
|
|
property OnAfterClose: TNotifyEvent read FOnAfterClose write FOnAfterClose;
|
|
property OnBeforeClose: TNotifyEvent read FOnBeforeClose
|
|
write FOnBeforeClose;
|
|
property OnAfterOpen: TNotifyEvent read FOnAfterOpen write FOnAfterOpen;
|
|
property OnBeforeOpen: TNotifyEvent read FOnBeforeOpen write FOnBeforeOpen;
|
|
property OnAfterSave: TNotifyEvent read FOnAfterSave write FOnAfterSave;
|
|
property OnBeforeSave: TNotifyEvent read FOnBeforeSave write FOnBeforeSave;
|
|
property OnEditorChange: TNotifyEvent read FOnEditorChange
|
|
write FOnEditorChange;
|
|
property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
|
|
property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
|
|
property OnClickLink: TMouseEvent read FOnClickLink write FOnClickLink;
|
|
property OnMouseLink: TSynMouseLinkEvent read FOnMouseLink write FOnMouseLink;
|
|
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;
|
|
end;
|
|
|
|
//============================================================================
|
|
|
|
{ TSourceNotebook }
|
|
|
|
TJumpHistoryAction = (jhaBack, jhaForward, jhaViewWindow);
|
|
|
|
TOnJumpToHistoryPoint = procedure(var NewCaretXY: TPoint;
|
|
var NewTopLine, NewPageIndex: integer;
|
|
Action: TJumpHistoryAction) of object;
|
|
TOnAddJumpPoint = procedure(ACaretXY: TPoint; ATopLine: integer;
|
|
APageIndex: integer; 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;
|
|
|
|
TSourceNotebookState = (
|
|
snIncrementalFind,
|
|
snWarnedFont
|
|
);
|
|
TSourceNotebookStates = set of TSourceNotebookState;
|
|
|
|
{ TSourceNotebook }
|
|
|
|
TSourceNotebook = class(TSourceEditorWindowInterface)
|
|
Notebook: TNoteBook;
|
|
SrcPopUpMenu: TPopupMenu;
|
|
StatusBar: TStatusBar;
|
|
procedure AddBreakpointClicked(Sender: TObject);
|
|
procedure StatusBarDblClick(Sender: TObject);
|
|
procedure ToggleBreakpointClicked(Sender: TObject);
|
|
procedure CompleteCodeMenuItemClick(Sender: TObject);
|
|
procedure DeleteBreakpointClicked(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 AddWatchAtCursor(Sender: TObject);
|
|
procedure BookmarkGoTo(Index: Integer);
|
|
procedure BookmarkGotoNext(GoForward: boolean);
|
|
procedure BookMarkNextClicked(Sender: TObject);
|
|
procedure BookMarkPrevClicked(Sender: TObject);
|
|
procedure BookMarkGotoClicked(Sender: TObject);
|
|
procedure BookMarkSet(Value: Integer; Toggle: boolean = false);
|
|
procedure BookMarkSetFree;// set a free bookmark
|
|
procedure BookMarkToggleClicked(Sender: TObject);
|
|
procedure BookmarkSetFreeClicked(Sender: TObject);
|
|
procedure EditorPropertiesClicked(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 InsertTodoClicked(Sender: TObject);
|
|
procedure MoveEditorLeftClicked(Sender: TObject);
|
|
procedure MoveEditorRightClicked(Sender: TObject);
|
|
procedure MoveEditorFirstClicked(Sender: TObject);
|
|
procedure MoveEditorLastClicked(Sender: TObject);
|
|
procedure DockingClicked(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 OnPopupMenuOpenLRSFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenSFile(Sender: TObject);
|
|
procedure OnPopupMenuOpenFile(Sender: TObject);
|
|
procedure ShowUnitInfo(Sender: TObject);
|
|
procedure SrcPopUpMenuPopup(Sender: TObject);
|
|
procedure ToggleLineNumbersClicked(Sender: TObject);
|
|
procedure InsertCharacter(const C: TUTF8Char);
|
|
private
|
|
fAutoFocusLock: integer;
|
|
FCodeTemplateModul: TSynEditAutoComplete;
|
|
fIdentCompletionJumpToError: boolean;
|
|
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;
|
|
FOnAddJumpPoint: TOnAddJumpPoint;
|
|
FOnAddWatchAtCursor: TOnAddWatch;
|
|
FOnCloseClicked: TOnCloseSrcEditor;
|
|
FOnClickLink: TMouseEvent;
|
|
FOnMouseLink: TSynMouseLinkEvent;
|
|
FOnCurrentCodeBufferChanged: TNotifyEvent;
|
|
FOnDeleteLastJumpPoint: TNotifyEvent;
|
|
FOnEditorChanged: TNotifyEvent;
|
|
FOnEditorPropertiesClicked: TNotifyEvent;
|
|
FOnEditorVisibleChanged: TNotifyEvent;
|
|
FOnFindDeclarationClicked: TNotifyEvent;
|
|
FOnInitIdentCompletion: TOnInitIdentCompletion;
|
|
FOnInsertTodoClicked: TNotifyEvent;
|
|
FOnShowCodeContext: TOnShowCodeContext;
|
|
FOnJumpToHistoryPoint: TOnJumpToHistoryPoint;
|
|
FOnMovingPage: TOnMovingPage;
|
|
FOnOpenFileAtCursorClicked: TNotifyEvent;
|
|
FOnProcessUserCommand: TOnProcessUserCommand;
|
|
fOnReadOnlyChanged: TNotifyEvent;
|
|
FOnShowHintForSource: TOnShowHintForSource;
|
|
FOnShowSearchResultsView: TNotifyEvent;
|
|
FOnShowUnitInfo: TNotifyEvent;
|
|
FOnToggleFormUnitClicked: TNotifyEvent;
|
|
FOnToggleObjectInspClicked: TNotifyEvent;
|
|
FOnUserCommandProcessed: TOnProcessUserCommand;
|
|
FOnViewJumpHistory: TNotifyEvent;
|
|
FProcessingCommand: boolean;
|
|
FSourceEditorList: TList; // list of TSourceEditor
|
|
FOnPopupMenu: TSrcEditPopupMenuEvent;
|
|
private
|
|
// colors for the completion form (popup form, e.g. word completion)
|
|
FActiveEditDefaultFGColor: TColor;
|
|
FActiveEditDefaultBGColor: TColor;
|
|
FActiveEditSelectedFGColor: TColor;
|
|
FActiveEditSelectedBGColor: TColor;
|
|
FActiveEditKeyFGColor: TColor;
|
|
FActiveEditKeyBGColor: TColor;
|
|
FActiveEditSymbolFGColor: TColor;
|
|
FActiveEditSymbolBGColor: TColor;
|
|
|
|
// PopupMenu
|
|
procedure BuildPopupMenu;
|
|
procedure UpdateHighlightMenuItems;
|
|
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;
|
|
|
|
procedure UpdateActiveEditColors(AEditor: TSynEdit);
|
|
procedure SetIncrementalSearchStr(const AValue: string);
|
|
procedure IncrementalSearch(ANext, ABackward: Boolean);
|
|
|
|
// 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;
|
|
protected
|
|
ccSelection: String;
|
|
States: TSourceNotebookStates;
|
|
|
|
function CreateNotebook: Boolean;
|
|
function NewSE(Pagenum: Integer): TSourceEditor;
|
|
procedure EditorChanged(Sender: TObject);
|
|
|
|
procedure ccExecute(Sender: TObject);
|
|
procedure ccCancel(Sender: TObject);
|
|
procedure ccComplete(var Value: string; SourceValue: string; 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);
|
|
procedure DeactivateCompletionForm;
|
|
procedure InitIdentCompletion(S: TStrings);
|
|
|
|
procedure EditorMouseMove(Sender: TObject; Shift: TShiftstate;
|
|
X,Y: Integer);
|
|
procedure EditorMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftstate; X,Y: Integer);
|
|
procedure EditorClickLink(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftstate; X,Y: Integer);
|
|
procedure EditorMouseLink(
|
|
Sender: TObject; X,Y: Integer; var AllowMouseLink: 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);
|
|
|
|
// hintwindow stuff
|
|
FHintWindow: THintWindow;
|
|
FHintTimer: TTimer;
|
|
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(PageIndex: integer);
|
|
procedure MoveEditorRight(PageIndex: integer);
|
|
procedure MoveActivePageLeft;
|
|
procedure MoveActivePageRight;
|
|
procedure MoveEditorFirst(PageIndex: integer);
|
|
procedure MoveEditorLast(PageIndex: integer);
|
|
procedure MoveActivePageFirst;
|
|
procedure MoveActivePageLast;
|
|
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 GetCompletionBoxPosition: integer; override;
|
|
|
|
// marks
|
|
function FindBookmark(BookmarkID: integer): TSourceEditor;
|
|
function OnSourceMarksGetSourceEditor(ASynEdit: TCustomSynEdit): TObject;
|
|
function OnSourceMarksGetFilename(ASourceEditor: TObject): string;
|
|
procedure OnSourceMarksAction(AMark: TSourceMark; AAction: TListNotification);
|
|
|
|
function GetItems(Index: integer): TSourceEditorInterface; override;
|
|
function GetEditors(Index:integer): TSourceEditor;
|
|
|
|
procedure KeyDownBeforeInterface(var Key: Word; Shift: TShiftState); override;
|
|
|
|
procedure BeginAutoFocusLock;
|
|
procedure EndAutoFocusLock;
|
|
public
|
|
FindReplaceDlgHistoryIndex: array[TFindDlgComponent] of integer;
|
|
FindReplaceDlgUserText: array[TFindDlgComponent] of string;
|
|
ControlDocker: TLazControlDocker;
|
|
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure InitMacros(AMacroList: TTransferMacroList);
|
|
procedure CreateCompletionForm;
|
|
|
|
procedure ShowFPDocEditor;
|
|
procedure UpdateFPDocEditor;
|
|
|
|
property Editors[Index:integer]:TSourceEditor read GetEditors;
|
|
function EditorCount:integer;
|
|
function Count: integer; override;
|
|
function Empty: boolean;
|
|
|
|
function FindSourceEditorWithPageIndex(PageIndex:integer):TSourceEditor;
|
|
function FindPageWithEditor(ASourceEditor: TSourceEditor):integer;
|
|
function FindSourceEditorWithEditorComponent(
|
|
EditorComp: TComponent): TSourceEditor;
|
|
function FindSourceEditorWithFilename(const Filename: string): TSourceEditor;
|
|
function GetActiveSE: TSourceEditor;
|
|
procedure SetActiveSE(SrcEdit: TSourceEditor);
|
|
function GetActiveEditor: TSourceEditorInterface; override;
|
|
procedure SetActiveEditor(const AValue: TSourceEditorInterface); override;
|
|
procedure CheckCurrentCodeBufferChanged;
|
|
|
|
procedure LockAllEditorsInSourceChangeCache;
|
|
procedure UnlockAllEditorsInSourceChangeCache;
|
|
function GetDiffFiles: TDiffFiles;
|
|
procedure GetSourceText(PageIndex: integer; OnlySelection: boolean;
|
|
var Source: string);
|
|
|
|
function ActiveFileName: AnsiString;
|
|
function FindUniquePageName(FileName:string; IgnorePageIndex:integer):string;
|
|
function SomethingModified: boolean;
|
|
procedure UpdateStatusBar;
|
|
procedure ClearErrorLines; override;
|
|
procedure ClearExecutionLines;
|
|
procedure ClearExecutionMarks;
|
|
|
|
procedure CloseTabClicked(Sender: TObject);
|
|
procedure CloseClicked(Sender: TObject);
|
|
procedure ToggleFormUnitClicked(Sender: TObject);
|
|
procedure ToggleObjectInspClicked(Sender: TObject);
|
|
|
|
// find / replace text
|
|
procedure InitFindDialog;
|
|
procedure FindClicked(Sender: TObject);
|
|
procedure FindNextClicked(Sender: TObject);
|
|
procedure FindPreviousClicked(Sender: TObject);
|
|
procedure ReplaceClicked(Sender: TObject);
|
|
|
|
// incremental find
|
|
procedure IncrementalFindClicked(Sender: TObject);
|
|
procedure BeginIncrementalFind;
|
|
procedure EndIncrementalFind;
|
|
property IncrementalSearchStr: string
|
|
read FIncrementalSearchStr write SetIncrementalSearchStr;
|
|
|
|
// FindInFiles
|
|
procedure FindInFilesPerDialog(AProject: TProject);
|
|
procedure FindInFiles(AProject: TProject; const FindText: string);
|
|
procedure ShowSearchResultsView;
|
|
function CreateFindInFilesDialog: TLazFindInFilesDialog;
|
|
procedure LoadFindInFilesHistory(ADialog: TLazFindInFilesDialog);
|
|
procedure SaveFindInFilesHistory(ADialog: TLazFindInFilesDialog);
|
|
procedure FIFSearchProject(AProject: TProject;
|
|
ADialog: TLazFindInFilesDialog);
|
|
procedure FIFSearchOpenFiles(ADialog: TLazFindInFilesDialog);
|
|
procedure FIFSearchDir(ADialog: TLazFindInFilesDialog);
|
|
function FIFCreateSearchForm(ADialog:TLazFindInFilesDialog): TSearchForm;
|
|
procedure DoFindInFiles(ASearchForm: TSearchForm);
|
|
|
|
// goto line number
|
|
procedure GotoLineClicked(Sender: TObject);
|
|
|
|
// history jumping
|
|
procedure HistoryJump(Sender: TObject; CloseAction: TJumpHistoryAction);
|
|
procedure JumpBackClicked(Sender: TObject);
|
|
procedure JumpForwardClicked(Sender: TObject);
|
|
procedure AddJumpPointClicked(Sender: TObject);
|
|
procedure DeleteLastJumpPointClicked(Sender: TObject);
|
|
procedure ViewJumpHistoryClicked(Sender: TObject);
|
|
|
|
// hints
|
|
procedure ActivateHint(const ScreenPos: TPoint;
|
|
const BaseURL, TheHint: string);
|
|
procedure HideHint;
|
|
procedure StartShowCodeContext(JumpToError: boolean);
|
|
procedure StartShowCodeHelp;
|
|
|
|
// new, close, focus
|
|
function NewFile(const NewShortName: String; ASource: TCodeBuffer;
|
|
FocusIt: boolean): TSourceEditor;
|
|
procedure CloseFile(PageIndex:integer);
|
|
procedure FocusEditor;
|
|
|
|
// paste and copy
|
|
procedure CutClicked(Sender: TObject);
|
|
procedure CopyClicked(Sender: TObject);
|
|
procedure PasteClicked(Sender: TObject);
|
|
procedure CopyFilenameClicked(Sender: TObject);
|
|
|
|
// bookmarks
|
|
procedure ToggleBookmark(Value: Integer);
|
|
procedure SetBookmark(Value: Integer);
|
|
procedure GotoBookmark(Value: Integer);
|
|
|
|
procedure ReloadEditorOptions;
|
|
procedure ReloadHighlighters;
|
|
procedure CheckFont;
|
|
procedure GetSynEditPreviewSettings(APreviewEditor: TObject);
|
|
function GetEditorControlSettings(EditControl: TControl): boolean; override;
|
|
function GetHighlighterSettings(Highlighter: TObject): boolean; override;
|
|
|
|
property CodeTemplateModul: TSynEditAutoComplete
|
|
read FCodeTemplateModul write FCodeTemplateModul;
|
|
procedure OnCodeTemplateTokenNotFound(Sender: TObject; AToken: string;
|
|
AnEditor: TCustomSynEdit; var Index:integer);
|
|
procedure OnCodeTemplateExecuteCompletion(
|
|
ASynAutoComplete: TCustomSynAutoComplete;
|
|
Index: integer);
|
|
procedure OnWordCompletionGetSource(
|
|
var Source: TStrings; SourceIndex: integer);
|
|
procedure OnSourceCompletionTimer(Sender: TObject);
|
|
|
|
procedure FindReplaceDlgKey(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState; FindDlgComponent: TFindDlgComponent);
|
|
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 OnDeleteLastJumpPoint: TNotifyEvent
|
|
read FOnDeleteLastJumpPoint write FOnDeleteLastJumpPoint;
|
|
property OnEditorVisibleChanged: TNotifyEvent
|
|
read FOnEditorVisibleChanged write FOnEditorVisibleChanged;
|
|
property OnEditorChanged: TNotifyEvent
|
|
read FOnEditorChanged write FOnEditorChanged;
|
|
property OnEditorPropertiesClicked: TNotifyEvent
|
|
read FOnEditorPropertiesClicked write FOnEditorPropertiesClicked;
|
|
property OnCurrentCodeBufferChanged: TNotifyEvent
|
|
read FOnCurrentCodeBufferChanged write FOnCurrentCodeBufferChanged;
|
|
property OnFindDeclarationClicked: TNotifyEvent
|
|
read FOnFindDeclarationClicked write FOnFindDeclarationClicked;
|
|
property OnInitIdentCompletion: TOnInitIdentCompletion
|
|
read FOnInitIdentCompletion write FOnInitIdentCompletion;
|
|
property OnInsertTodoClicked: TNotifyEvent
|
|
read FOnInsertTodoClicked write FOnInsertTodoClicked;
|
|
property OnShowCodeContext: TOnShowCodeContext
|
|
read FOnShowCodeContext write FOnShowCodeContext;
|
|
property OnJumpToHistoryPoint: TOnJumpToHistoryPoint
|
|
read FOnJumpToHistoryPoint write FOnJumpToHistoryPoint;
|
|
property OnMovingPage: TOnMovingPage read FOnMovingPage write FOnMovingPage;
|
|
property OnOpenFileAtCursorClicked: TNotifyEvent
|
|
read FOnOpenFileAtCursorClicked write FOnOpenFileAtCursorClicked;
|
|
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 OnProcessUserCommand: TOnProcessUserCommand
|
|
read FOnProcessUserCommand write FOnProcessUserCommand;
|
|
property OnUserCommandProcessed: TOnUserCommandProcessed
|
|
read FOnUserCommandProcessed write FOnUserCommandProcessed;
|
|
property OnViewJumpHistory: TNotifyEvent
|
|
read FOnViewJumpHistory write FOnViewJumpHistory;
|
|
property OnAddWatchAtCursor: TOnAddWatch
|
|
read FOnAddWatchAtCursor write FOnAddWatchAtCursor;
|
|
property OnShowSearchResultsView: TNotifyEvent
|
|
read FOnShowSearchResultsView write FOnShowSearchResultsView;
|
|
property OnPopupMenu: TSrcEditPopupMenuEvent read FOnPopupMenu write FOnPopupMenu;
|
|
end;
|
|
|
|
var
|
|
SourceNotebook: TSourceNotebook = nil;
|
|
|
|
//=============================================================================
|
|
|
|
const
|
|
SourceEditorMenuRootName = 'SourceEditor';
|
|
|
|
var
|
|
SrcEditMenuFindDeclaration: TIDEMenuCommand;
|
|
// finding / jumping
|
|
SrcEditMenuProcedureJump: TIDEMenuCommand;
|
|
SrcEditMenuFindNextWordOccurrence: TIDEMenuCommand;
|
|
SrcEditMenuFindPrevWordOccurrence: TIDEMenuCommand;
|
|
SrcEditMenuFindinFiles: TIDEMenuCommand;
|
|
// open file
|
|
SrcEditMenuOpenFileAtCursor: TIDEMenuCommand;
|
|
SrcEditMenuClosePage: TIDEMenuCommand;
|
|
SrcEditMenuCut: TIDEMenuCommand;
|
|
SrcEditMenuCopy: TIDEMenuCommand;
|
|
SrcEditMenuPaste: TIDEMenuCommand;
|
|
SrcEditMenuCopyFilename: TIDEMenuCommand;
|
|
// bookmarks
|
|
SrcEditMenuNextBookmark: TIDEMenuCommand;
|
|
SrcEditMenuPrevBookmark: TIDEMenuCommand;
|
|
SrcEditMenuSetFreeBookmark: TIDEMenuCommand;
|
|
// debugging
|
|
SrcEditMenuToggleBreakpoint: TIDEMenuCommand;
|
|
SrcEditMenuRunToCursor: TIDEMenuCommand;
|
|
SrcEditMenuAddWatchAtCursor: TIDEMenuCommand;
|
|
SrcEditMenuViewCallStack: TIDEMenuCommand;
|
|
// refactoring
|
|
SrcEditMenuCompleteCode: TIDEMenuCommand;
|
|
SrcEditMenuEncloseSelection: TIDEMenuCommand;
|
|
SrcEditMenuRenameIdentifier: TIDEMenuCommand;
|
|
SrcEditMenuFindIdentifierReferences: TIDEMenuCommand;
|
|
SrcEditMenuExtractProc: TIDEMenuCommand;
|
|
SrcEditMenuInvertAssignment: TIDEMenuCommand;
|
|
SrcEditMenuShowAbstractMethods: TIDEMenuCommand;
|
|
SrcEditMenuShowEmptyMethods: TIDEMenuCommand;
|
|
SrcEditMenuShowUnusedUnits: TIDEMenuCommand;
|
|
SrcEditMenuFindOverloads: TIDEMenuCommand;
|
|
SrcEditMenuInsertTodo: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorLeft: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorRight: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorFirst: TIDEMenuCommand;
|
|
SrcEditMenuMoveEditorLast: TIDEMenuCommand;
|
|
SrcEditMenuDocking: TIDEMenuCommand;
|
|
SrcEditMenuReadOnly: TIDEMenuCommand;
|
|
SrcEditMenuShowLineNumbers: TIDEMenuCommand;
|
|
SrcEditMenuShowUnitInfo: TIDEMenuCommand;
|
|
SrcEditMenuEditorProperties: TIDEMenuCommand;
|
|
|
|
|
|
procedure RegisterStandardSourceEditorMenuItems;
|
|
|
|
|
|
implementation
|
|
|
|
var
|
|
Highlighters: array[TLazSyntaxHighlighter] of TSynCustomHighlighter;
|
|
// aCompletion:
|
|
// The component controlling the completion form. It is created on demand
|
|
// and killed when the IDE ends.
|
|
aCompletion: TSynCompletion = nil;
|
|
// CurCompletionControl contains aCompletion whenever the completion form is
|
|
// active
|
|
CurCompletionControl: TSynCompletion = nil;
|
|
CurrentCompletionType: TCompletionType;
|
|
SourceCompletionTimer: TIdleTimer = nil;
|
|
SourceCompletionCaretXY: TPoint;
|
|
AWordCompletion: TWordCompletion = nil;
|
|
|
|
GotoDialog: TfrmGoto = nil;
|
|
|
|
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');
|
|
// register the sub menu Open File
|
|
SrcEditSubMenuOpenFile:=RegisterIDESubMenu(SrcEditMenuSectionFirstStatic,
|
|
'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 Move Page sub menu
|
|
SrcEditSubMenuMovePage:=RegisterIDESubMenu(SrcEditMenuSectionFirstStatic,
|
|
'Move Page ...', lisMovePage);
|
|
AParent:=SrcEditSubMenuMovePage;
|
|
SrcEditMenuMoveEditorLeft:=RegisterIDEMenuCommand(AParent,'MoveEditorLeft',
|
|
uemMoveEditorLeft);
|
|
SrcEditMenuMoveEditorRight:=RegisterIDEMenuCommand(AParent,'MoveEditorRight',
|
|
uemMoveEditorRight);
|
|
SrcEditMenuMoveEditorFirst:=RegisterIDEMenuCommand(AParent,'MoveEditorLeftmost',
|
|
uemMoveEditorLeftmost);
|
|
SrcEditMenuMoveEditorLast:=RegisterIDEMenuCommand(AParent,'MoveEditorRightmost',
|
|
uemMoveEditorRightmost);
|
|
|
|
AParent:=SrcEditMenuSectionFirstStatic;
|
|
SrcEditMenuClosePage:=RegisterIDEMenuCommand(AParent,
|
|
'Close Page',uemClosePage, nil, nil, nil, 'menu_close');
|
|
|
|
// 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 submenu
|
|
SrcEditSubMenuDebug:=RegisterIDESubMenu(SrcEditMenuSectionMarks,
|
|
'Debug',uemDebugWord);
|
|
AParent:=SrcEditSubMenuDebug;
|
|
// register the Debug submenu items
|
|
SrcEditMenuToggleBreakpoint:=RegisterIDEMenuCommand(AParent,'Toggle Breakpoint',
|
|
uemToggleBreakpoint);
|
|
SrcEditMenuAddWatchAtCursor:=RegisterIDEMenuCommand(AParent,
|
|
'Add Watch at Cursor',uemAddWatchAtCursor);
|
|
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}
|
|
|
|
SrcEditMenuInsertTodo:=RegisterIDEMenuCommand(SourceEditorMenuRoot,
|
|
'InsertTodo',uemInsertTodo, nil, nil, nil, 'item_todo');
|
|
|
|
// register the Flags section
|
|
SrcEditSubMenuFlags:=RegisterIDESubMenu(SourceEditorMenuRoot,
|
|
'Flags section', lisFileSettings);
|
|
AParent:=SrcEditSubMenuFlags;
|
|
SrcEditMenuReadOnly:=RegisterIDEMenuCommand(AParent,'ReadOnly',uemReadOnly);
|
|
SrcEditMenuReadOnly.ShowAlwaysCheckable:=true;
|
|
SrcEditMenuShowLineNumbers:=RegisterIDEMenuCommand(AParent,
|
|
'ShowLineNumbers',uemShowLineNumbers);
|
|
SrcEditMenuShowLineNumbers.ShowAlwaysCheckable:=true;
|
|
SrcEditMenuShowUnitInfo:=RegisterIDEMenuCommand(AParent,'ShowUnitInfo',
|
|
uemShowUnitInfo);
|
|
SrcEditSubMenuHighlighter:=RegisterIDESubMenu(AParent,'Highlighter',
|
|
uemHighlighter);
|
|
SrcEditSubMenuEncoding:=RegisterIDESubMenu(AParent,'Encoding',
|
|
uemEncoding);
|
|
|
|
SrcEditMenuEditorProperties:=RegisterIDEMenuCommand(SourceEditorMenuRoot,
|
|
'EditorProperties', dlgFROpts, nil, nil, nil, 'menu_environment_options');
|
|
SrcEditMenuDocking:=RegisterIDEMenuCommand(SourceEditorMenuRoot, 'Docking',
|
|
lisMVDocking);
|
|
{$IFNDEF EnableIDEDocking}
|
|
SrcEditMenuDocking.Visible:=false;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{ TSourceEditor }
|
|
|
|
{ The constructor for @link(TSourceEditor).
|
|
AOwner is the @link(TSourceNotebook)
|
|
and the AParent is usually a page of a @link(TNotebook) }
|
|
constructor TSourceEditor.Create(AOwner: TComponent; AParent: TWinControl);
|
|
Begin
|
|
inherited Create;
|
|
FAOwner := AOwner;
|
|
if (FAOwner<>nil) and (FAOwner is TSourceNotebook) then
|
|
FSourceNoteBook:=TSourceNotebook(FAOwner)
|
|
else
|
|
FSourceNoteBook:=nil;
|
|
|
|
FSyntaxHighlighterType:=lshNone;
|
|
FErrorLine:=-1;
|
|
FErrorColumn:=-1;
|
|
FExecutionLine:=-1;
|
|
FExecutionMark := nil;
|
|
FHasExecutionMarks := False;
|
|
FMarksRequested := False;
|
|
FLineInfoNotification := TIDELineInfoNotification.Create;
|
|
FLineInfoNotification.AddReference;
|
|
FLineInfoNotification.OnChange := @LineInfoNotificationChange;
|
|
|
|
CreateEditor(AOwner,AParent);
|
|
|
|
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
|
|
//writeln('TSourceEditor.Destroy A ',FEditor.Name);
|
|
if (FAOwner<>nil) and (FEditor<>nil) then begin
|
|
UnbindEditor;
|
|
FEditor.Visible:=false;
|
|
FEditor.Parent:=nil;
|
|
if SourceEditorMarks<>nil then
|
|
SourceEditorMarks.DeleteAllForEditor(FEditor);
|
|
TSourceNotebook(FAOwner).FSourceEditorList.Remove(Self);
|
|
// free the synedit control after processing the events
|
|
Application.ReleaseComponent(FEditor);
|
|
end;
|
|
FEditor:=nil;
|
|
CodeBuffer := nil;
|
|
if (DebugBoss <> nil) and (DebugBoss.LineInfo <> nil) then
|
|
DebugBoss.LineInfo.RemoveNotification(FLineInfoNotification);
|
|
FLineInfoNotification.ReleaseReference;
|
|
//writeln('TSourceEditor.Destroy B ');
|
|
inherited Destroy;
|
|
//writeln('TSourceEditor.Destroy END ');
|
|
end;
|
|
|
|
{------------------------------G O T O L I N E -----------------------------}
|
|
Function TSourceEditor.GotoLine(Value: Integer): Integer;
|
|
Var
|
|
P: TPoint;
|
|
NewTopLine: integer;
|
|
Begin
|
|
TSourceNotebook(Owner).AddJumpPointClicked(Self);
|
|
P.X := 1;
|
|
P.Y := Value;
|
|
NewTopLine := P.Y - (FEditor.LinesInWindow div 2);
|
|
if NewTopLine < 1 then NewTopLine:=1;
|
|
FEditor.CaretXY := P;
|
|
with FEditor do begin
|
|
BlockBegin:=CaretXY;
|
|
BlockEnd:=CaretXY;
|
|
end;
|
|
FEditor.TopLine := NewTopLine;
|
|
Result:=FEditor.CaretY;
|
|
end;
|
|
|
|
procedure TSourceEditor.ShowGotoLineDialog;
|
|
var
|
|
NewLeft: integer;
|
|
NewTop: integer;
|
|
begin
|
|
InitGotoDialog;
|
|
GotoDialog.Edit1.Text:='';
|
|
GetDialogPosition(GotoDialog.Width,GotoDialog.Height,NewLeft,NewTop);
|
|
GotoDialog.SetBounds(NewLeft,NewTop,GotoDialog.Width,GotoDialog.Height);
|
|
if (GotoDialog.ShowModal = mrOK) then
|
|
GotoLine(StrToIntDef(GotoDialog.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);
|
|
var ALeft,ATop:integer;
|
|
bSelectedTextOption: Boolean;
|
|
begin
|
|
if SourceNotebook<>nil then
|
|
SourceNotebook.InitFindDialog;
|
|
//debugln('TSourceEditor.StartFindAndReplace A LazFindReplaceDialog.FindText="',dbgstr(LazFindReplaceDialog.FindText),'"');
|
|
if ReadOnly then Replace := False;
|
|
if Replace then
|
|
LazFindReplaceDialog.Options :=
|
|
LazFindReplaceDialog.Options + [ssoReplace, ssoReplaceAll]
|
|
else
|
|
LazFindReplaceDialog.Options :=
|
|
LazFindReplaceDialog.Options - [ssoReplace, ssoReplaceAll];
|
|
|
|
// 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;
|
|
// 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]
|
|
end;
|
|
|
|
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];
|
|
|
|
if (LazFindReplaceDialog.ShowModal = mrCancel) then begin
|
|
exit;
|
|
end;
|
|
//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;
|
|
|
|
procedure TSourceEditor.InitGotoDialog;
|
|
begin
|
|
if GotoDialog=nil then
|
|
GotoDialog := TfrmGoto.Create(SourceNotebook);
|
|
end;
|
|
|
|
function TSourceEditor.DoFindAndReplace: integer;
|
|
var
|
|
OldCaretXY: TPoint;
|
|
AText, ACaption: String;
|
|
NewTopLine: integer;
|
|
begin
|
|
Result:=0;
|
|
if SourceNotebook<>nil then
|
|
SourceNotebook.AddJumpPointClicked(Self);
|
|
if (ssoReplace in LazFindReplaceDialog.Options)
|
|
and ReadOnly then begin
|
|
DebugLn(['TSourceEditor.DoFindAndReplace Read only']);
|
|
exit;
|
|
end;
|
|
|
|
OldCaretXY:=EditorComponent.CaretXY;
|
|
if EditorComponent.SelAvail then begin
|
|
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);
|
|
TSourceNotebook(Owner).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}
|
|
writeln('TSourceEditor.FocusEditor A ',PageName,' ',FEditor.Name);
|
|
{$ENDIF}
|
|
if SourceNotebook<>nil then SourceNotebook.Visible:=true;
|
|
FEditor.SetFocus;
|
|
//DebugLn('TSourceEditor.FocusEditor ',dbgsName(FindOwnerControl(GetFocus)),' ',dbgs(GetFocus));
|
|
{$IFDEF VerboseFocus}
|
|
writeln('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;
|
|
|
|
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));
|
|
|
|
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
|
|
TSourceNotebook(FaOwner).AddJumpPointClicked(Self);
|
|
end;
|
|
|
|
ecCopy,ecCut:
|
|
begin
|
|
if (not FEditor.SelAvail) then begin
|
|
// nothing selected
|
|
if EditorOpts.CopyWordAtCursorOnCopyNone then begin
|
|
FEditor.SetSelWord;
|
|
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 EditorOpts.AutoIdentifierCompletion 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;
|
|
end;
|
|
|
|
ecPrevBookmark: // Note: book mark commands lower than ecUserFirst must be handled here
|
|
TSourceNotebook(FaOwner).BookmarkGotoNext(false);
|
|
|
|
ecNextBookmark:
|
|
TSourceNotebook(FaOwner).BookmarkGotoNext(true);
|
|
|
|
ecGotoMarker0..ecGotoMarker9:
|
|
TSourceNotebook(FaOwner).BookmarkGoto(Command - ecGotoMarker0);
|
|
|
|
ecSetMarker0..ecSetMarker9:
|
|
TSourceNotebook(FaOwner).BookmarkSet(Command - ecSetMarker0);
|
|
|
|
ecToggleMarker0..ecToggleMarker9:
|
|
TSourceNotebook(FaOwner).BookmarkSet(Command - ecToggleMarker0,true);
|
|
|
|
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
|
|
I: Integer;
|
|
P: TPoint;
|
|
Texts, Texts2: String;
|
|
Handled: boolean;
|
|
LogCaret: TPoint;
|
|
Begin
|
|
//debugln('TSourceEditor.ProcessUserCommand A ',dbgs(Command));
|
|
Handled:=true;
|
|
|
|
case Command of
|
|
|
|
ecContextHelp:
|
|
FindHelpForSourceAtCursor;
|
|
|
|
ecIdentCompletion :
|
|
StartIdentCompletion(true);
|
|
|
|
ecShowCodeContext :
|
|
SourceNotebook.StartShowCodeContext(true);
|
|
|
|
ecWordCompletion :
|
|
if not TCustomSynEdit(Sender).ReadOnly then begin
|
|
SourceNotebook.CreateCompletionForm;
|
|
CurrentCompletionType:=ctWordCompletion;
|
|
TextS := FEditor.LineText;
|
|
LogCaret:=FEditor.LogicalCaretXY;
|
|
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 TCustomSynEdit(Sender) do begin
|
|
P := Point(CaretXPix - length(TextS2)*CharWidth,CaretYPix + LineHeight + 1);
|
|
P.X:=Max(0,Min(P.X,ClientWidth-aCompletion.Width));
|
|
P := ClientToScreen(p);
|
|
end;
|
|
aCompletion.Editor:=TCustomSynEdit(Sender);
|
|
aCompletion.Execute(TextS2,P.X,P.Y);
|
|
end;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
ecInsertTodo:
|
|
InsertTodo;
|
|
|
|
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');
|
|
|
|
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: ;
|
|
|
|
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:=CompareCaret(EditorComponent.BlockBegin,EditorComponent.BlockEnd)<>0;
|
|
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;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
FEditor.SelText:=UpperCase(EditorComponent.SelText);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.LowerCaseSelection
|
|
|
|
Turns current text selection lowercase.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.LowerCaseSelection;
|
|
var OldBlockBegin, OldBlockEnd: TPoint;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
FEditor.SelText:=LowerCase(EditorComponent.SelText);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.TabsToSpacesInSelection
|
|
|
|
Convert all tabs into spaces in current text selection.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.TabsToSpacesInSelection;
|
|
var
|
|
OldBlockBegin, OldBlockEnd: TPoint;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
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.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.CommentSelection;
|
|
var
|
|
OldBlockBegin, OldBlockEnd: TPoint;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
// ToDo: replace step by step to keep bookmarks and breakpoints
|
|
FEditor.SelText:=CommentLines(EditorComponent.SelText);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
|
|
procedure TSourceEditor.UncommentSelection;
|
|
var
|
|
OldBlockBegin, OldBlockEnd: TPoint;
|
|
begin
|
|
if ReadOnly then exit;
|
|
if not EditorComponent.SelAvail then exit;
|
|
OldBlockBegin:=FEditor.BlockBegin;
|
|
OldBlockEnd:=FEditor.BlockEnd;
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
// ToDo: replace step by step to keep bookmarks and breakpoints
|
|
FEditor.SelText:=UncommentLines(EditorComponent.SelText);
|
|
FEditor.BlockBegin:=OldBlockBegin;
|
|
FEditor.BlockEnd:=OldBlockEnd;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
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.SetSelWord;
|
|
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.SelText:=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.SelText:=GetCurrentUserName;
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertTodo;
|
|
Var
|
|
aTodoItem: TTodoItem;
|
|
begin
|
|
//DebugLn(['TSourceEditor.InsertTodo ']);
|
|
if ReadOnly then Exit;
|
|
aTodoItem := ExecuteTodoDialog;
|
|
try
|
|
if Assigned(aTodoItem) then
|
|
FEditor.SelText := aTodoItem.AsComment;
|
|
finally
|
|
aTodoItem.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertDateTime;
|
|
begin
|
|
if ReadOnly then Exit;
|
|
FEditor.SelText:=DateTimeToStr(now);
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertChangeLogEntry;
|
|
var s: string;
|
|
begin
|
|
if ReadOnly then Exit;
|
|
s:=DateToStr(now)+' '+GetCurrentUserName+' '+GetCurrentMailAddress;
|
|
FEditor.SelText:=s;
|
|
end;
|
|
|
|
procedure TSourceEditor.InsertCVSKeyword(const AKeyWord: string);
|
|
begin
|
|
if ReadOnly then Exit;
|
|
FEditor.SelText:='$'+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(FEditor, Line, Marks, MarkCount);
|
|
BreakFound := False;
|
|
for i := 0 to MarkCount - 1 do
|
|
begin
|
|
if not Marks[i].Visible then
|
|
Continue;
|
|
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(FEditor, 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;
|
|
begin
|
|
if (FExecutionMark = nil) then
|
|
begin
|
|
FExecutionMark := TSourceMark.Create(EditorComponent, nil);
|
|
SourceEditorMarks.Add(FExecutionMark);
|
|
EditorComponent.Marks.Add(FExecutionMark);
|
|
FExecutionMark.LineColorAttrib := ahaExecutionPoint;
|
|
FExecutionMark.Priority := 1;
|
|
end;
|
|
|
|
FExecutionMark.Visible := ExecutionLine <> -1;
|
|
if FExecutionMark.Visible then
|
|
begin
|
|
FExecutionMark.Line := ExecutionLine;
|
|
if SourceEditorMarks.FindBreakPointMark(EditorComponent, ExecutionLine) <> nil then
|
|
FExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineBreakPointImg
|
|
else
|
|
FExecutionMark.ImageIndex := SourceEditorMarks.CurrentLineImg;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetExecutionLine(NewLine: integer);
|
|
begin
|
|
if fExecutionLine=NewLine then exit;
|
|
fExecutionLine:=NewLine;
|
|
UpdateExecutionSourceMark;
|
|
EditorComponent.Invalidate;
|
|
end;
|
|
|
|
Function TSourceEditor.RefreshEditorSettings: Boolean;
|
|
Begin
|
|
Result:=true;
|
|
SetSyntaxHighlighterType(fSyntaxHighlighterType);
|
|
EditorOpts.GetSynEditSettings(FEditor);
|
|
SourceNotebook.UpdateActiveEditColors(FEditor);
|
|
if EditorOpts.CtrlMouseLinks then
|
|
FEditor.Options:=FEditor.Options+[eoShowCtrlMouseLinks]
|
|
else
|
|
FEditor.Options:=FEditor.Options-[eoShowCtrlMouseLinks];
|
|
end;
|
|
|
|
Procedure TSourceEditor.ccAddMessage(Texts: String);
|
|
Begin
|
|
ErrorMsgs.Add(Texts);
|
|
End;
|
|
|
|
function TSourceEditor.AutoCompleteChar(Char: TUTF8Char; var AddChar: boolean;
|
|
Category: TAutoCompleteOption): boolean;
|
|
var
|
|
AToken: String;
|
|
i: 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];
|
|
WordToken:=FEditor.GetWordAtRowCol(p);
|
|
if Assigned(FEditor.Highlighter) then
|
|
IdChars := FEditor.Highlighter.IdentChars
|
|
else
|
|
IdChars := ['a'..'z', 'A'..'Z'];
|
|
for i:=0 to FCodeTemplates.Completions.Count-1 do begin
|
|
AToken:=FCodeTemplates.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=',FCodeTemplates.CompletionAttributes[i].IndexOfName(CatName)]);
|
|
if (AnsiCompareText(AToken,SrcToken)=0)
|
|
and (FCodeTemplates.CompletionAttributes[i].IndexOfName(CatName)>=0)
|
|
then begin
|
|
Result:=true;
|
|
DebugLn(['TSourceEditor.AutoCompleteChar ',AToken,' SrcToken=',SrcToken,' CatName=',CatName,' Index=',FCodeTemplates.CompletionAttributes[i].IndexOfName(CatName)]);
|
|
FCodeTemplates.ExecuteCompletion(AToken,FEditor);
|
|
AddChar:=not FCodeTemplates.CompletionAttributes[i].IndexOfName(
|
|
AutoCompleteOptionNames[acoRemoveChar])>=0;
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Procedure TSourceEditor.CreateEditor(AOwner: TComponent; AParent: TWinControl);
|
|
var
|
|
NewName: string;
|
|
i: integer;
|
|
Begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceEditor.CreateEditor A ');
|
|
{$ENDIF}
|
|
if not assigned(FEditor) then Begin
|
|
i:=0;
|
|
repeat
|
|
inc(i);
|
|
NewName:='SynEdit'+IntToStr(i);
|
|
until (AOwner.FindComponent(NewName)=nil);
|
|
FEditor:=TSynEdit.Create(AOwner);
|
|
FEditor.BeginUpdate;
|
|
with FEditor do begin
|
|
Name:=NewName;
|
|
Text:='';
|
|
Parent := AParent;
|
|
Align := alClient;
|
|
BookMarkOptions.EnableKeys := false;
|
|
BookMarkOptions.LeftMargin:=1;
|
|
WantTabs := true;
|
|
|
|
// 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 := @EditorClickLink;
|
|
OnMouseLink := @EditorMouseLink;
|
|
OnKeyDown := @EditorKeyDown;
|
|
// IMPORTANT: when you change above, don't forget updating UnbindEditor
|
|
|
|
end;
|
|
if FCodeTemplates<>nil then
|
|
FCodeTemplates.AddEditor(FEditor);
|
|
if aCompletion<>nil then
|
|
aCompletion.AddEditor(FEditor);
|
|
RefreshEditorSettings;
|
|
FEditor.EndUpdate;
|
|
end else begin
|
|
FEditor.Parent:=AParent;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetCodeBuffer(NewCodeBuffer: TCodeBuffer);
|
|
begin
|
|
if NewCodeBuffer=FCodeBuffer then exit;
|
|
if FCodeBuffer<>nil then
|
|
FCodeBuffer.RemoveChangeHook(@OnCodeBufferChanged);
|
|
FCodeBuffer:=NewCodeBuffer;
|
|
if FCodeBuffer <> nil then
|
|
begin
|
|
FCodeBuffer.AddChangeHook(@OnCodeBufferChanged);
|
|
if (FIgnoreCodeBufferLock<=0) and (not FCodeBuffer.IsEqual(FEditor.Lines))
|
|
then begin
|
|
{$IFDEF IDE_DEBUG}
|
|
debugln('');
|
|
debugln('WARNING: TSourceEditor.SetCodeBuffer - loosing marks: ',Filename);
|
|
debugln('');
|
|
{$ENDIF}
|
|
FEditor.BeginUpdate;
|
|
FCodeBuffer.AssignTo(FEditor.Lines,true);
|
|
FEditorStampCommitedToCodetools:=FEditor.ChangeStamp;
|
|
FEditor.EndUpdate;
|
|
end;
|
|
if IsActiveOnNoteBook then SourceNotebook.UpdateStatusBar;
|
|
if (DebugBoss.State in [dsPause, dsRun]) and
|
|
not HasExecutionMarks and
|
|
(FileName <> '') then
|
|
FillExecutionMarks;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.OnCodeBufferChanged(Sender: TSourceLog;
|
|
SrcLogEntry: TSourceLogEntry);
|
|
|
|
procedure InsertTxt(const StartPos: TPoint; const Txt: string);
|
|
begin
|
|
FEditor.LogicalCaretXY:=StartPos;
|
|
FEditor.BlockBegin:=StartPos;
|
|
FEditor.BlockEnd:=StartPos;
|
|
FEditor.SelText:=Txt;
|
|
end;
|
|
|
|
procedure DeleteTxt(const StartPos, EndPos: TPoint);
|
|
begin
|
|
FEditor.LogicalCaretXY:=StartPos;
|
|
FEditor.BlockBegin:=StartPos;
|
|
FEditor.BlockEnd:=EndPos;
|
|
FEditor.SelText:='';
|
|
end;
|
|
|
|
procedure MoveTxt(const StartPos, EndPos, MoveToPos: TPoint;
|
|
DirectionForward: boolean);
|
|
var Txt: string;
|
|
begin
|
|
FEditor.LogicalCaretXY:=StartPos;
|
|
FEditor.BlockBegin:=StartPos;
|
|
FEditor.BlockEnd:=EndPos;
|
|
Txt:=FEditor.SelText;
|
|
if DirectionForward then begin
|
|
FEditor.LogicalCaretXY:=MoveToPos;
|
|
FEditor.BlockBegin:=MoveToPos;
|
|
FEditor.BlockEnd:=MoveToPos;
|
|
FEditor.SelText:=Txt;
|
|
FEditor.LogicalCaretXY:=StartPos;
|
|
FEditor.BlockBegin:=StartPos;
|
|
FEditor.BlockEnd:=EndPos;
|
|
FEditor.SelText:='';
|
|
end else begin
|
|
FEditor.SelText:='';
|
|
FEditor.LogicalCaretXY:=MoveToPos;
|
|
FEditor.BlockBegin:=MoveToPos;
|
|
FEditor.BlockEnd:=MoveToPos;
|
|
FEditor.SelText:=Txt;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
StartPos, EndPos, MoveToPos: TPoint;
|
|
CodeToolsInSync: Boolean;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceEditor.OnCodeBufferChanged] A ',FIgnoreCodeBufferLock,' ',SrcLogEntry<>nil);
|
|
{$ENDIF}
|
|
if FIgnoreCodeBufferLock>0 then exit;
|
|
CodeToolsInSync:=FEditorStampCommitedToCodetools=FEditor.ChangeStamp;
|
|
if SrcLogEntry<>nil then begin
|
|
FEditor.BeginUpdate;
|
|
FEditor.BeginUndoBlock;
|
|
case SrcLogEntry.Operation of
|
|
sleoInsert:
|
|
begin
|
|
Sender.AbsoluteToLineCol(SrcLogEntry.Position,StartPos.Y,StartPos.X);
|
|
if StartPos.Y>=1 then
|
|
InsertTxt(StartPos,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
|
|
DeleteTxt(StartPos,EndPos);
|
|
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;
|
|
FEditor.EndUndoBlock;
|
|
FEditor.EndUpdate;
|
|
end else begin
|
|
{$IFDEF VerboseSrcEditBufClean}
|
|
debugln(['TSourceEditor.OnCodeBufferChanged clean up ',TCodeBuffer(Sender).FileName,' ',Sender=CodeBuffer,' ',Filename]);
|
|
DumpStack;
|
|
{$ENDIF}
|
|
FEditor.BeginUpdate;
|
|
Sender.AssignTo(FEditor.Lines,false);
|
|
FEditor.EndUpdate;
|
|
end;
|
|
if CodeToolsInSync then begin
|
|
// synedit and codetools were in sync -> mark as still in sync
|
|
FEditorStampCommitedToCodetools:=FEditor.ChangeStamp;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.StartIdentCompletion(JumpToError: boolean);
|
|
var
|
|
I: Integer;
|
|
P: TPoint;
|
|
TextS, TextS2: String;
|
|
LogCaret: TPoint;
|
|
begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceEditor.StartIdentCompletion JumpToError: ',JumpToError]);
|
|
{$ENDIF}
|
|
if (FEditor.ReadOnly) or (CurrentCompletionType<>ctNone) then exit;
|
|
SourceNotebook.fIdentCompletionJumpToError:=JumpToError;
|
|
SourceNotebook.CreateCompletionForm;
|
|
CurrentCompletionType:=ctIdentCompletion;
|
|
TextS := FEditor.LineText;
|
|
LogCaret:=FEditor.LogicalCaretXY;
|
|
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-aCompletion.Width));
|
|
P := ClientToScreen(p);
|
|
end;
|
|
aCompletion.Editor:=FEditor;
|
|
aCompletion.Execute(TextS2,P.X,P.Y);
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceEditor.StartIdentCompletion END aCompletion.TheForm.Visible=',aCompletion.TheForm.Visible]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceEditor.IncreaseIgnoreCodeBufferLock;
|
|
begin
|
|
inc(FIgnoreCodeBufferLock);
|
|
end;
|
|
|
|
procedure TSourceEditor.DecreaseIgnoreCodeBufferLock;
|
|
begin
|
|
if FIgnoreCodeBufferLock<=0 then raise Exception.Create('unbalanced calls');
|
|
dec(FIgnoreCodeBufferLock);
|
|
end;
|
|
|
|
procedure TSourceEditor.UpdateCodeBuffer;
|
|
// copy the source from EditorComponent to codetools
|
|
begin
|
|
if FEditor.ChangeStamp=FEditorStampCommitedToCodetools then exit;
|
|
{$IFDEF IDE_DEBUG}
|
|
if FCodeBuffer=nil then begin
|
|
debugln('');
|
|
debugln('*********** Oh, no: UpdateCodeBuffer ************ ');
|
|
debugln('');
|
|
end;
|
|
{$ENDIF}
|
|
if FCodeBuffer=nil then exit;
|
|
//DebugLn(['TSourceEditor.UpdateCodeBuffer ',FileName]);
|
|
IncreaseIgnoreCodeBufferLock;
|
|
FEditor.BeginUpdate;
|
|
FCodeBuffer.Assign(FEditor.Lines);
|
|
FEditorStampCommitedToCodetools:=FEditor.ChangeStamp;
|
|
FEditor.EndUpdate;
|
|
DecreaseIgnoreCodeBufferLock;
|
|
end;
|
|
|
|
function TSourceEditor.NeedsUpdateCodeBuffer: boolean;
|
|
begin
|
|
Result:=FEditor.ChangeStamp<>FEditorStampCommitedToCodetools;
|
|
end;
|
|
|
|
Function TSourceEditor.GetSource: TStrings;
|
|
Begin
|
|
//return synedit's source.
|
|
Result := FEditor.Lines;
|
|
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);
|
|
NewPageName:=FPageName;
|
|
if Modified then NewPageName:='*'+NewPageName;
|
|
if SourceNotebook.NoteBook.Pages[p]<>NewPageName then
|
|
SourceNotebook.NoteBook.Pages[p]:=NewPageName;
|
|
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.BeginUndoBlock;
|
|
FEditor.BlockBegin:=Point(1,StartLine);
|
|
FEditor.BlockEnd:=Point(length(FEditor.Lines[Endline-1])+1,EndLine);
|
|
FEditor.SelText:=NewText;
|
|
FEditor.EndUndoBlock;
|
|
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 := FModified or FEditor.Modified;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetModified(const NewValue: Boolean);
|
|
var
|
|
OldModified: Boolean;
|
|
begin
|
|
OldModified := Modified;
|
|
FModified := NewValue;
|
|
if not FModified then
|
|
begin
|
|
FEditor.Modified:=false; // needed for the undo stack
|
|
FEditor.MarkTextAsSaved;
|
|
FEditorStampCommitedToCodetools:=FEditor.ChangeStamp;
|
|
end;
|
|
if OldModified <> Modified then
|
|
UpdatePageName;
|
|
end;
|
|
|
|
Function TSourceEditor.GetInsertMode: Boolean;
|
|
Begin
|
|
Result := FEditor.Insertmode;
|
|
end;
|
|
|
|
Function TSourceEditor.Close: Boolean;
|
|
Begin
|
|
Result := True;
|
|
If Assigned(FOnBeforeClose) then
|
|
FOnBeforeClose(Self);
|
|
|
|
Visible := False;
|
|
if aCompletion<>nil then
|
|
aCompletion.RemoveEditor(FEditor);
|
|
SourceEditorMarks.DeleteAllForEditor(FEditor);
|
|
UnbindEditor;
|
|
FEditor.Parent:=nil;
|
|
CodeBuffer := nil;
|
|
If Assigned(FOnAfterClose) then FOnAfterClose(Self);
|
|
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.ReParent(AParent: TWInControl);
|
|
Begin
|
|
CreateEditor(FAOwner,AParent);
|
|
End;
|
|
|
|
procedure TSourceEditor.SetCodeTemplates(
|
|
NewCodeTemplates: TSynEditAutoComplete);
|
|
begin
|
|
if NewCodeTemplates<>FCodeTemplates then begin
|
|
if FCodeTemplates<>nil then
|
|
FCodeTemplates.RemoveEditor(FEditor);
|
|
FCodeTemplates:=NewCodeTemplates;
|
|
if FCodeTemplates<>nil then
|
|
FCodeTemplates.AddEditor(FEditor);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceEditor.SetPopupMenu(NewPopupMenu: TPopupMenu);
|
|
begin
|
|
if NewPopupMenu<>FPopupMenu then begin
|
|
FPopupMenu:=NewPopupMenu;
|
|
if FEditor<>nil then FEditor.PopupMenu:=NewPopupMenu;
|
|
end;
|
|
end;
|
|
|
|
function TSourceEditor.GetFilename: string;
|
|
begin
|
|
if FCodeBuffer<>nil then
|
|
Result:=FCodeBuffer.Filename
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceEditor.GetEditorControl: TWinControl;
|
|
begin
|
|
Result:=FEditor;
|
|
end;
|
|
|
|
function TSourceEditor.GetCodeToolsBuffer: TObject;
|
|
begin
|
|
Result:=CodeBuffer;
|
|
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;
|
|
|
|
Function TSourceEditor.GetWordAtPosition(Position: TPoint): String;
|
|
var
|
|
CaretPos: TPoint;
|
|
begin
|
|
Result := '';
|
|
Caretpos := ScreenToTextPosition(GetCaretPosfromCursorPos(Position));
|
|
Result := GetWordFromCaret(CaretPos);
|
|
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.EditorMouseLink(
|
|
Sender: TObject; X, Y: Integer; var AllowMouseLink: Boolean);
|
|
begin
|
|
//DebugLn(['TSourceEditor.EditorMouseLink ',X,',',Y]);
|
|
if Assigned(OnMouseLink) then
|
|
OnMouseLink(Sender, X, Y, AllowMouseLink);
|
|
end;
|
|
|
|
procedure TSourceEditor.EditorClickLink(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
//DebugLn(['TSourceEditor.EditorClickLink ',X,',',Y]);
|
|
if Assigned(OnClickLink) then
|
|
OnClickLink(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;
|
|
|
|
Function TSourceEditor.GetCaretPosFromCursorPos(const CursorPos: TPoint): TPoint;
|
|
var
|
|
NewTopLine: Integer;
|
|
LineHeight: Integer;
|
|
LineNum: Integer;
|
|
XLine: Integer;
|
|
begin
|
|
//Figure out the line number
|
|
NewTopLine := FEditor.TopLine;
|
|
LineHeight := FEditor.LineHeight;
|
|
if CursorPos.Y > 1 then
|
|
LineNum := CursorPos.Y div LineHeight
|
|
else
|
|
LineNum := 1;
|
|
LineNum := LineNum + NewTopLine;
|
|
XLine := CursorPos.X div FEditor.CharWidth;
|
|
if XLine = 0 then inc(XLine);
|
|
|
|
Result.X := XLine;
|
|
Result.Y := LineNum;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
method TSourceEditor.CenterCursor
|
|
Params: none
|
|
Result: none
|
|
|
|
Center the current cursor line in editor.
|
|
-------------------------------------------------------------------------------}
|
|
procedure TSourceEditor.CenterCursor;
|
|
var NewTopLine: integer;
|
|
begin
|
|
NewTopLine:=EditorComponent.CaretY-((EditorComponent.LinesInWindow-1) div 2);
|
|
if NewTopLine<1 then NewTopLine:=1;
|
|
EditorComponent.TopLine:=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:=Project1.UnitWithEditorIndex(PageIndex);
|
|
end;
|
|
|
|
function TSourceEditor.GetDesigner(LoadForm: boolean): TIDesigner;
|
|
var
|
|
AProjectFile: TLazProjectFile;
|
|
begin
|
|
AProjectFile:=GetProjectFile;
|
|
if AProjectFile<>nil then
|
|
Result:=LazarusIDE.GetDesignerWithProjectFile(AProjectFile,LoadForm)
|
|
else
|
|
Result:=nil;
|
|
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.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
|
|
if (FSourceNoteBook=nil) then exit;
|
|
FSourceNoteBook.SetActiveSE(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.PositionInSelection(const APosition: TPoint): Boolean;
|
|
begin
|
|
Result := CaretInSelection(GetCaretPosfromCursorPos(APosition));
|
|
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 HasExecutionMarks then Exit;
|
|
|
|
ASource := FileName;
|
|
idx := DebugBoss.LineInfo.IndexOf(ASource);
|
|
if (idx = -1) then
|
|
begin
|
|
if not FMarksRequested then
|
|
begin
|
|
FMarksRequested := 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.Values[idx, i];
|
|
if (Addr <> 0) then
|
|
EditorComponent.SetDebugMarks(i, i);
|
|
end;
|
|
FHasExecutionMarks := True;
|
|
end;
|
|
|
|
procedure TSourceEditor.ClearExecutionMarks;
|
|
begin
|
|
EditorComponent.ClearDebugMarks;
|
|
FHasExecutionMarks := False;
|
|
FMarksRequested := 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.GetWordAtCurrentCaret: String;
|
|
var
|
|
CaretPos: TPoint;
|
|
begin
|
|
Result := '';
|
|
CaretPos.Y := CurrentCursorYLine;
|
|
CaretPos.X := CurrentCursorXLine;
|
|
Result := GetWordFromCaret(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
|
|
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
|
|
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
|
|
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;
|
|
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);
|
|
begin
|
|
inherited Create(AOwner);
|
|
IDESearchInText:=@SearchInText;
|
|
Visible:=false;
|
|
Name:=NonModalIDEWindowNames[nmiwSourceNoteBookName];
|
|
Caption := locWndSrcEditor;
|
|
KeyPreview:=true;
|
|
FProcessingCommand := false;
|
|
|
|
SourceEditorWindow:=Self;
|
|
|
|
EnvironmentOptions.IDEWindowLayoutList.Apply(Self,Name);
|
|
ControlDocker:=TLazControlDocker.Create(Self);
|
|
ControlDocker.Name:='SourceEditor';
|
|
{$IFDEF EnableIDEDocking}
|
|
ControlDocker.Manager:=LazarusIDE.DockingManager;
|
|
{$ENDIF}
|
|
|
|
FSourceEditorList := TList.Create;
|
|
|
|
// 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;
|
|
|
|
// 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.OnGetSourceEditor:=@OnSourceMarksGetSourceEditor;
|
|
SourceEditorMarks.OnGetFilename:=@OnSourceMarksGetFilename;
|
|
SourceEditorMarks.OnAction:=@OnSourceMarksAction;
|
|
|
|
// key mapping
|
|
FKeyStrokes:=TSynEditKeyStrokes.Create(Self);
|
|
EditorOpts.KeyMap.AssignTo(FKeyStrokes,TSourceEditorWindowInterface);
|
|
|
|
// popup menu
|
|
BuildPopupMenu;
|
|
|
|
// HintTimer
|
|
FHintTimer := TTimer.Create(Self);
|
|
with FHintTimer do begin
|
|
Name:=Self.Name+'_HintTimer';
|
|
Interval := 1000;
|
|
Enabled := 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;
|
|
|
|
Application.AddOnUserInputHandler(@OnApplicationUserInput,true);
|
|
end;
|
|
|
|
destructor TSourceNotebook.Destroy;
|
|
var
|
|
i: integer;
|
|
begin
|
|
FProcessingCommand:=false;
|
|
for i:=FSourceEditorList.Count-1 downto 0 do
|
|
Editors[i].Free;
|
|
if Notebook<>nil then begin
|
|
FreeThenNil(Notebook);
|
|
end;
|
|
FKeyStrokes.Free;
|
|
FCodeTemplateModul.Free;
|
|
FSourceEditorList.Free;
|
|
FreeAndNil(Gotodialog);
|
|
|
|
FreeThenNil(CodeContextFrm);
|
|
FreeThenNil(SrcEditHintWindow);
|
|
FreeThenNil(aCompletion);
|
|
FreeThenNil(FHintTimer);
|
|
FreeThenNil(FHintWindow);
|
|
SourceEditorWindow:=nil;
|
|
|
|
inherited Destroy;
|
|
if SourceNotebook=Self then
|
|
SourceNotebook:=nil;
|
|
end;
|
|
|
|
procedure TSourceNotebook.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 TSourceNotebook.CreateCompletionForm;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceNotebook.CreateCompletionForm START ',dbgsname(aCompletion)]);
|
|
{$ENDIF}
|
|
// completion form
|
|
if aCompletion<>nil then exit;
|
|
aCompletion := TSynCompletion.Create(Self);
|
|
with aCompletion do
|
|
Begin
|
|
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;
|
|
|
|
for i:=0 to EditorCount-1 do
|
|
aCompletion.AddEditor(Editors[i].FEditor);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ShowFPDocEditor;
|
|
begin
|
|
DoShowFPDocEditor;
|
|
UpdateFPDocEditor;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateFPDocEditor;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
CaretPos: TPoint;
|
|
begin
|
|
if FPDocEditor = nil then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
CaretPos := SrcEdit.EditorComponent.CaretXY;
|
|
FPDocEditor.UpdateFPDocEditor(SrcEdit.Filename,CaretPos);
|
|
end;
|
|
|
|
function TSourceNotebook.OnSynCompletionPaintItem(const AKey: string;
|
|
ACanvas: TCanvas; X, Y: integer; ItemSelected: boolean;
|
|
Index: integer): boolean;
|
|
var
|
|
MaxX: Integer;
|
|
begin
|
|
with ACanvas do begin
|
|
if (aCompletion<>nil) and (aCompletion.Editor<>nil) then
|
|
Font:=aCompletion.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:=aCompletion.TheForm.ClientWidth;
|
|
PaintCompletionItem(AKey,ACanvas,X,Y,MaxX,ItemSelected,Index,aCompletion,
|
|
CurrentCompletionType,aCompletion.Editor.Highlighter);
|
|
Result:=true;
|
|
end;
|
|
|
|
function TSourceNotebook.OnSynCompletionMeasureItem(const AKey: string;
|
|
ACanvas: TCanvas; ItemSelected: boolean; Index: integer): TPoint;
|
|
var
|
|
MaxX: Integer;
|
|
begin
|
|
with ACanvas do begin
|
|
if (aCompletion<>nil) and (aCompletion.Editor<>nil) then
|
|
Font:=aCompletion.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;
|
|
Result := PaintCompletionItem(AKey,ACanvas,0,0,MaxX,ItemSelected,Index,
|
|
aCompletion,CurrentCompletionType,nil,True);
|
|
if CurCompletionControl<>nil then
|
|
Result.Y:=CurCompletionControl.FontHeight;
|
|
end;
|
|
|
|
procedure TSourceNotebook.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<FSourceEditorList.Count) do begin
|
|
if Editors[i]<>TempEditor then dec(SourceIndex);
|
|
if SourceIndex=0 then begin
|
|
Source:=Editors[i].EditorComponent.Lines;
|
|
exit;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Source:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.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:=GetActiveSE;
|
|
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.StartIdentCompletion(false);
|
|
Result:=true;
|
|
end;
|
|
|
|
function CheckTemplateCompletion: boolean;
|
|
begin
|
|
Result:=false;
|
|
// execute context sensitive templates
|
|
//FCodeTemplateModul.ExecuteCompletion(Value,GetActiveSE.EditorComponent);
|
|
end;
|
|
|
|
var
|
|
TempEditor: TSourceEditor;
|
|
begin
|
|
//debugln('TSourceNotebook.OnIdentCompletionTimer');
|
|
SourceCompletionTimer.Enabled:=false;
|
|
SourceCompletionTimer.AutoEnabled:=false;
|
|
TempEditor:=GetActiveSE;
|
|
if (TempEditor<>nil)
|
|
and (ComparePoints(TempEditor.EditorComponent.CaretXY,SourceCompletionCaretXY)=0)
|
|
and TempEditor.EditorComponent.Focused
|
|
then begin
|
|
if CheckStartIdentCompletion then begin
|
|
end else if CheckTemplateCompletion then begin
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnCodeTemplateTokenNotFound(Sender: TObject;
|
|
AToken: string; AnEditor: TCustomSynEdit; var Index:integer);
|
|
var P:TPoint;
|
|
begin
|
|
//writeln('TSourceNotebook.OnCodeTemplateTokenNotFound ',AToken,',',AnEditor.ReadOnly,',',CurrentCompletionType=ctNone);
|
|
if (AnEditor.ReadOnly=false) and (CurrentCompletionType=ctNone) then begin
|
|
SourceNotebook.CreateCompletionForm;
|
|
CurrentCompletionType:=ctTemplateCompletion;
|
|
with AnEditor do begin
|
|
P := Point(CaretXPix - length(AToken)*CharWidth,CaretYPix + LineHeight + 1);
|
|
P.X:=Max(0,Min(P.X,ClientWidth-aCompletion.Width));
|
|
P := ClientToScreen(p);
|
|
end;
|
|
aCompletion.Editor:=AnEditor;
|
|
aCompletion.Execute(AToken,P.X,P.Y);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.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:=GetActiveEditor;
|
|
//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 TSourceNotebook.OnSynCompletionSearchPosition(var APosition:integer);
|
|
// prefix changed -> filter list
|
|
var
|
|
i,x:integer;
|
|
CurStr,s:Ansistring;
|
|
SL:TStringList;
|
|
ItemCnt: Integer;
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
case CurrentCompletionType of
|
|
|
|
ctIdentCompletion:
|
|
begin
|
|
// rebuild completion list
|
|
APosition:=0;
|
|
CurStr:=CurCompletionControl.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
|
|
CurCompletionControl.ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
ctTemplateCompletion:
|
|
begin
|
|
// search CurrentString in bold words (words after #3'B')
|
|
CurStr:=CurCompletionControl.CurrentString;
|
|
i:=0;
|
|
while i<CurCompletionControl.ItemList.Count do begin
|
|
s:=CurCompletionControl.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:=CurCompletionControl.CurrentString;
|
|
SL:=TStringList.Create;
|
|
try
|
|
aWordCompletion.GetWordList(SL, CurStr, false, 100);
|
|
CurCompletionControl.ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSynCompletionCompletePrefix(Sender: TObject);
|
|
var
|
|
OldPrefix: String;
|
|
NewPrefix: String;
|
|
SL: TStringList;
|
|
AddPrefix: String;
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
OldPrefix:=CurCompletionControl.CurrentString;
|
|
NewPrefix:=OldPrefix;
|
|
|
|
case CurrentCompletionType of
|
|
|
|
ctIdentCompletion:
|
|
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));
|
|
CurCompletionControl.Editor.SelText:=AddPrefix;
|
|
CurCompletionControl.Editor.LogicalCaretXY:=
|
|
CurCompletionControl.Editor.BlockBegin;
|
|
if CurrentCompletionType=ctWordCompletion then begin
|
|
SL:=TStringList.Create;
|
|
try
|
|
aWordCompletion.GetWordList(SL, NewPrefix, false, 100);
|
|
CurCompletionControl.ItemList:=SL;
|
|
finally
|
|
SL.Free;
|
|
end;
|
|
end;
|
|
CurCompletionControl.CurrentString:=NewPrefix;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSynCompletionNextChar(Sender: TObject);
|
|
var
|
|
NewPrefix: String;
|
|
SrcEdit: TSourceEditor;
|
|
Line: String;
|
|
Editor: TSynEdit;
|
|
LogCaret: TPoint;
|
|
CharLen: LongInt;
|
|
AddPrefix: String;
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
Editor:=SrcEdit.EditorComponent;
|
|
LogCaret:=Editor.LogicalCaretXY;
|
|
if LogCaret.Y>=Editor.Lines.Count then exit;
|
|
Line:=SrcEdit.EditorComponent.Lines[LogCaret.Y-1];
|
|
if LogCaret.X>length(Line) then exit;
|
|
CharLen:=UTF8CharacterLength(@Line[LogCaret.X]);
|
|
AddPrefix:=copy(Line,LogCaret.X,CharLen);
|
|
NewPrefix:=CurCompletionControl.CurrentString+AddPrefix;
|
|
//debugln('TSourceNotebook.OnSynCompletionNextChar NewPrefix="',NewPrefix,'" LogCaret.X=',dbgs(LogCaret.X));
|
|
inc(LogCaret.X);
|
|
CurCompletionControl.Editor.LogicalCaretXY:=LogCaret;
|
|
CurCompletionControl.CurrentString:=NewPrefix;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSynCompletionPrevChar(Sender: TObject);
|
|
var
|
|
NewPrefix: String;
|
|
SrcEdit: TSourceEditor;
|
|
Editor: TSynEdit;
|
|
NewLen: LongInt;
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
NewPrefix:=CurCompletionControl.CurrentString;
|
|
if NewPrefix='' then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
Editor:=SrcEdit.EditorComponent;
|
|
Editor.CaretX:=Editor.CaretX-1;
|
|
NewLen:=UTF8FindNearestCharStart(PChar(NewPrefix),length(NewPrefix),
|
|
length(NewPrefix))-1;
|
|
NewPrefix:=copy(NewPrefix,1,NewLen);
|
|
CurCompletionControl.CurrentString:=NewPrefix;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSynCompletionKeyPress(Sender: TObject;
|
|
var Key: Char);
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
if (System.Pos(Key,CurCompletionControl.EndOfTokenChr)>0) then begin
|
|
// identifier completed
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress A');
|
|
CurCompletionControl.TheForm.OnValidate(Sender,Key,[]);
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress B');
|
|
Key:=#0;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSynCompletionUTF8KeyPress(Sender: TObject;
|
|
var UTF8Key: TUTF8Char);
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
if (length(UTF8Key)=1)
|
|
and (System.Pos(UTF8Key[1],CurCompletionControl.EndOfTokenChr)>0) then begin
|
|
// identifier completed
|
|
//debugln('TSourceNotebook.OnSynCompletionUTF8KeyPress A');
|
|
CurCompletionControl.TheForm.OnValidate(Sender,UTF8Key,[]);
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress B');
|
|
UTF8Key:='';
|
|
end else begin
|
|
aCompletion.Editor.CommandProcessor(ecChar,UTF8Key,nil);
|
|
UTF8Key:='';
|
|
end;
|
|
//debugln('TSourceNotebook.OnSynCompletionKeyPress B UTF8Key=',dbgstr(UTF8Key));
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSynCompletionPositionChanged(Sender: TObject);
|
|
begin
|
|
if SrcEditHintWindow<>nil then
|
|
SrcEditHintWindow.UpdateHints;
|
|
end;
|
|
|
|
procedure TSourceNotebook.DeactivateCompletionForm;
|
|
var
|
|
ActSE: TSourceEditor;
|
|
OldCompletionControl: TSynCompletion;
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
|
|
// clear the IdentifierList (otherwise it would try to update everytime
|
|
// the codetools are used)
|
|
CodeToolBoss.IdentifierList.Clear;
|
|
|
|
OldCompletionControl:=CurCompletionControl;
|
|
CurCompletionControl:=nil;
|
|
OldCompletionControl.Deactivate;
|
|
|
|
CurrentCompletionType:=ctNone;
|
|
ActSE:=GetActiveSE;
|
|
if ActSE<>nil then begin
|
|
LCLIntf.ShowCaret(ActSE.EditorComponent.Handle);
|
|
ActSE.EditorComponent.SetFocus;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.InitIdentCompletion(S: TStrings);
|
|
var
|
|
i: integer;
|
|
Handled: boolean;
|
|
Abort: boolean;
|
|
Prefix: string;
|
|
ItemCnt: Integer;
|
|
begin
|
|
Prefix := CurCompletionControl.CurrentString;
|
|
if Assigned(OnInitIdentCompletion) then begin
|
|
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));
|
|
CurCompletionControl.Position:=0;
|
|
for i:=0 to ItemCnt-1 do
|
|
s.Add('Dummy');
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ccComplete(var Value: string; SourceValue: string; 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;
|
|
SrcEdit: TSourceEditor;
|
|
NewCaretXY: TPoint;
|
|
CursorToLeft: integer;
|
|
NewValue: String;
|
|
Editor: TSynEdit;
|
|
OldCompletionType: TCompletionType;
|
|
Begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceNotebook.ccComplete START']);
|
|
{$ENDIF}
|
|
if CurCompletionControl=nil then
|
|
begin
|
|
Value := SourceValue;
|
|
exit;
|
|
end;
|
|
OldCompletionType:=CurrentCompletionType;
|
|
case CurrentCompletionType of
|
|
|
|
ctIdentCompletion:
|
|
begin
|
|
// add to history
|
|
CodeToolBoss.IdentifierHistory.Add(
|
|
CodeToolBoss.IdentifierList.FilteredItems[aCompletion.Position]);
|
|
// get value
|
|
NewValue:=GetIdentCompletionValue(aCompletion,KeyChar,
|
|
ValueType,CursorToLeft);
|
|
if ValueType=icvIdentifier then ;
|
|
// insert value plus special chars like brackets, semicolons, ...
|
|
SrcEdit:=GetActiveSE;
|
|
Editor:=SrcEdit.EditorComponent;
|
|
Editor.SelText:=NewValue;
|
|
if CursorToLeft>0 then
|
|
begin
|
|
NewCaretXY:=Editor.LogicalToPhysicalPos(Editor.BlockEnd);
|
|
dec(NewCaretXY.X,CursorToLeft);
|
|
Editor.CaretXY:=NewCaretXY;
|
|
end;
|
|
ccSelection := '';
|
|
Value:='';
|
|
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
|
|
FCodeTemplateModul.ExecuteCompletion(Value,
|
|
GetActiveSE.EditorComponent);
|
|
Value:='';
|
|
end;
|
|
|
|
ctWordCompletion:
|
|
// the completion is already in Value
|
|
begin
|
|
ccSelection := '';
|
|
if Value<>'' then AWordCompletion.AddWord(Value);
|
|
end;
|
|
|
|
else begin
|
|
Value:='';
|
|
end;
|
|
end;
|
|
|
|
DeactivateCompletionForm;
|
|
|
|
//DebugLn(['TSourceNotebook.ccComplete ',KeyChar,' ',OldCompletionType=ctIdentCompletion]);
|
|
SrcEdit:=GetActiveSE;
|
|
Editor:=SrcEdit.EditorComponent;
|
|
if (KeyChar='.') and (OldCompletionType=ctIdentCompletion) then
|
|
begin
|
|
SourceCompletionCaretXY:=Editor.CaretXY;
|
|
SourceCompletionTimer.AutoEnabled:=true;
|
|
end;
|
|
End;
|
|
|
|
Procedure TSourceNotebook.ccCancel(Sender: TObject);
|
|
// user cancels completion form
|
|
begin
|
|
if CurCompletionControl=nil then exit;
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceNotebook.ccCancel START']);
|
|
//debugln(GetStackTrace(true));
|
|
{$ENDIF}
|
|
DeactivateCompletionForm;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ccExecute(Sender: TObject);
|
|
// init completion form
|
|
// called by aCompletion.OnExecute just before showing
|
|
var
|
|
S: TStrings;
|
|
Prefix: String;
|
|
I: Integer;
|
|
NewStr: String;
|
|
CurEdit: TSynEdit;
|
|
Begin
|
|
{$IFDEF VerboseIDECompletionBox}
|
|
debugln(['TSourceNotebook.ccExecute START']);
|
|
{$ENDIF}
|
|
CurCompletionControl := Sender as TSynCompletion;
|
|
S := TStringList.Create;
|
|
Prefix := CurCompletionControl.CurrentString;
|
|
CurEdit:=GetActiveSE.EditorComponent;
|
|
case CurrentCompletionType of
|
|
ctIdentCompletion:
|
|
InitIdentCompletion(S);
|
|
|
|
ctWordCompletion:
|
|
begin
|
|
ccSelection:='';
|
|
end;
|
|
|
|
ctTemplateCompletion:
|
|
begin
|
|
ccSelection:='';
|
|
for I:=0 to FCodeTemplateModul.Completions.Count-1 do begin
|
|
NewStr:=FCodeTemplateModul.Completions[I];
|
|
if NewStr<>'' then begin
|
|
NewStr:=#3'B'+NewStr+#3'b';
|
|
while length(NewStr)<10+4 do NewStr:=NewStr+' ';
|
|
NewStr:=NewStr+' '+FCodeTemplateModul.CompletionComments[I];
|
|
S.Add(NewStr);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
CurCompletionControl.ItemList := S;
|
|
S.Free;
|
|
CurCompletionControl.CurrentString:=Prefix;
|
|
// set colors
|
|
if (CurEdit<>nil) and (CurCompletionControl.TheForm<>nil) then begin
|
|
with CurCompletionControl.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 then
|
|
StartShowCodeHelp
|
|
else if SrcEditHintWindow<>nil then
|
|
SrcEditHintWindow.HelpEnabled:=false;
|
|
end;
|
|
End;
|
|
|
|
Function TSourceNotebook.CreateNotebook: Boolean;
|
|
Begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] START');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] A ');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] A');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] B ');
|
|
{$ENDIF}
|
|
Result := False;
|
|
if not assigned(Notebook) then
|
|
Begin
|
|
Result := True;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] B');
|
|
{$ENDIF}
|
|
Notebook := TNotebook.Create(self);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] C');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] C ');
|
|
{$ENDIF}
|
|
with Notebook do
|
|
Begin
|
|
Name:='SrcEditNotebook';
|
|
Parent := Self;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] D');
|
|
{$ENDIF}
|
|
Align := alClient;
|
|
if PageCount>0 then
|
|
Pages.Strings[0] := 'unit1'
|
|
else
|
|
Pages.Add('unit1');
|
|
PageIndex := 0; // Set it to the first page
|
|
PopupMenu := SrcPopupMenu;
|
|
if EditorOpts.ShowTabCloseButtons then
|
|
Options:=Options+[nboShowCloseButtons]
|
|
else
|
|
Options:=Options-[nboShowCloseButtons];
|
|
OnPageChanged := @NotebookPageChanged;
|
|
OnCloseTabClicked:=@CloseTabClicked;
|
|
OnMouseDown:=@NotebookMouseDown;
|
|
ShowHint:=true;
|
|
OnShowHint:=@NotebookShowTabHint;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] E');
|
|
{$ENDIF}
|
|
Visible := true;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] F');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] F ');
|
|
{$ENDIF}
|
|
end; //with
|
|
Show; //used to display the code form
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.CreateNotebook] END');
|
|
{$ENDIF}
|
|
{$IFDEF IDE_MEM_CHECK}
|
|
CheckHeapWrtMemCnt('[TSourceNotebook.CreateNotebook] END ');
|
|
{$ENDIF}
|
|
End;
|
|
|
|
procedure TSourceNotebook.EditorPropertiesClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnEditorPropertiesClicked) then
|
|
FOnEditorPropertiesClicked(Sender);
|
|
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:=GetSystemEncoding;
|
|
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;
|
|
DebugLn(['TSourceNotebook.EncodingClicked Change file to ',SrcEdit.CodeBuffer.DiskEncoding]);
|
|
if (not SrcEdit.CodeBuffer.IsVirtual)
|
|
and (LazarusIDE.DoSaveEditorFile(SrcEdit.PageIndex,[])<>mrOk) then begin
|
|
DebugLn(['TSourceNotebook.EncodingClicked LazarusIDE.DoSaveEditorFile failed']);
|
|
end;
|
|
end else if CurResult=mrOK then begin
|
|
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,true);
|
|
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
|
|
ASrcEdit: TSourceEditor;
|
|
BookMarkID, BookMarkX, BookMarkY: integer;
|
|
MarkSrcEdit: TSourceEditor;
|
|
MarkDesc: String;
|
|
MarkEditorIndex: Integer;
|
|
MarkMenuItem: TIDEMenuItem;
|
|
EditorComp: TSynEdit;
|
|
Marks: PSourceMark;
|
|
MarkCount: integer;
|
|
i: Integer;
|
|
CurMark: TSourceMark;
|
|
EditorPopupPoint: TPoint;
|
|
SelAvail: Boolean;
|
|
SelAvailAndWritable: Boolean;
|
|
CurFilename: String;
|
|
CurWordAtCursor: String;
|
|
AtIdentifier: Boolean;
|
|
begin
|
|
//DebugLn(['TSourceNotebook.SrcPopUpMenuPopup ',dbgsName(Sender)]);
|
|
//SourceEditorMenuRoot.WriteDebugReport('TSourceNotebook.SrcPopUpMenuPopup START ',true);
|
|
//SourceEditorMenuRoot.ConsistencyCheck;
|
|
|
|
SourceEditorMenuRoot.BeginUpdate;
|
|
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;
|
|
|
|
// Readonly, ShowLineNumbers
|
|
SrcEditMenuReadOnly.MenuItem.Checked:=ASrcEdit.ReadOnly;
|
|
SrcEditMenuShowLineNumbers.MenuItem.Checked :=
|
|
EditorComp.Gutter.LineNumberPart.Visible;
|
|
UpdateHighlightMenuItems;
|
|
UpdateEncodingMenuItems;
|
|
|
|
// bookmarks
|
|
for BookMarkID:=0 to 9 do begin
|
|
MarkDesc:=' '+IntToStr(BookMarkID);
|
|
MarkSrcEdit:=FindBookmark(BookMarkID);
|
|
if (MarkSrcEdit<>nil)
|
|
and MarkSrcEdit.EditorComponent.GetBookMark(BookMarkID,BookMarkX,BookMarkY)
|
|
then begin
|
|
MarkEditorIndex:=FindPageWithEditor(MarkSrcEdit);
|
|
MarkDesc:=MarkDesc+': '+Notebook.Pages[MarkEditorIndex]
|
|
+' ('+IntToStr(BookMarkY)+','+IntToStr(BookMarkX)+')';
|
|
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:=
|
|
(NoteBook<>nil) and (NoteBook.PageCount>1);
|
|
SrcEditMenuMoveEditorRight.MenuItem.Enabled:=
|
|
(NoteBook<>nil) and (NoteBook.PageCount>1);
|
|
SrcEditMenuMoveEditorFirst.MenuItem.Enabled:=
|
|
(NoteBook<>nil) and (NoteBook.PageCount>1)
|
|
and (NoteBook.PageIndex>0);
|
|
SrcEditMenuMoveEditorLast.MenuItem.Enabled:=
|
|
(NoteBook<>nil) and (NoteBook.PageCount>1)
|
|
and (NoteBook.PageIndex<(NoteBook.PageCount-1));
|
|
|
|
EditorPopupPoint:=EditorComp.ScreenToClient(SrcPopUpMenu.PopupPoint);
|
|
if EditorPopupPoint.X>EditorComp.GutterWidth then begin
|
|
// user clicked on text
|
|
// collect some flags
|
|
SelAvail:=ASrcEdit.EditorComponent.SelAvail;
|
|
SelAvailAndWritable:=SelAvail and (not ASrcEdit.ReadOnly);
|
|
SrcEditMenuEncloseSelection.Enabled := SelAvailAndWritable;
|
|
SrcEditMenuExtractProc.Enabled := SelAvailAndWritable;
|
|
SrcEditMenuInvertAssignment.Enabled := SelAvailAndWritable;
|
|
CurWordAtCursor:=ASrcEdit.GetWordAtCurrentCaret;
|
|
AtIdentifier:=IsValidIdent(CurWordAtCursor);
|
|
// enable menu items
|
|
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
|
|
// user clicked on gutter
|
|
SourceEditorMarks.GetMarksForLine(EditorComp,EditorComp.CaretY,
|
|
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;
|
|
if (FilenameIsAbsolute(CurFilename)) then begin
|
|
if FilenameIsPascalUnit(CurFilename) then begin
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,'.lfm')) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(ExtractFileName(CurFilename),'.lfm')]),
|
|
true,@OnPopupMenuOpenLFMFile);
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,'.lrs')) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(ExtractFileName(CurFilename),'.lrs')]),
|
|
true,@OnPopupMenuOpenLRSFile);
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,'.s')) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(ExtractFileName(CurFilename),'.s')]),
|
|
true,@OnPopupMenuOpenSFile);
|
|
end;
|
|
if (CompareFileExt(CurFilename,'.lfm',true)=0) then begin
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,'.pas')) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(ExtractFileName(CurFilename),'.pas')]),
|
|
true,@OnPopupMenuOpenPasFile);
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,'.pp')) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(ExtractFileName(CurFilename),'.pp')]),
|
|
true,@OnPopupMenuOpenPPFile);
|
|
if FileExistsUTF8(ChangeFileExt(CurFilename,'.p')) then
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ChangeFileExt(ExtractFileName(CurFilename),'.p')]),
|
|
true,@OnPopupMenuOpenPFile);
|
|
end;
|
|
if (CompareFileExt(CurFilename,'.lpi',true)=0)
|
|
or (CompareFileExt(CurFilename,'.lpk',true)=0) then begin
|
|
AddContextPopupMenuItem(Format(lisOpenLfm,
|
|
[ExtractFileName(CurFilename)]),true,@OnPopupMenuOpenFile);
|
|
end;
|
|
end;
|
|
|
|
if Assigned(OnPopupMenu) then 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 (NoteBook=nil) or (HintInfo=nil) then exit;
|
|
TabIndex:=NoteBook.TabIndexAtClientPos(
|
|
Notebook.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.OnSourceMarksGetFilename(ASourceEditor: TObject
|
|
): string;
|
|
begin
|
|
if (ASourceEditor=nil) or (not (ASourceEditor is TSourceEditor)) then
|
|
RaiseException('TSourceNotebook.OnSourceMarksGetFilename');
|
|
Result:=TSourceEditor(ASourceEditor).Filename;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnSourceMarksAction(AMark: TSourceMark;
|
|
AAction: TListNotification);
|
|
var
|
|
Editor: TSourceEditor;
|
|
begin
|
|
Editor := FindSourceEditorWithEditorComponent(AMark.SynEdit);
|
|
if Editor = nil then
|
|
Exit;
|
|
|
|
if AMark.IsBreakPoint and (Editor.FExecutionMark <> nil) and
|
|
(AMark.CompareEditorAndLine(Editor.FExecutionMark.SynEdit, Editor.FExecutionMark.Line) = 0) then
|
|
Editor.UpdateExecutionSourceMark;
|
|
end;
|
|
|
|
function TSourceNotebook.GetItems(Index: integer): TSourceEditorInterface;
|
|
begin
|
|
Result:=TSourceEditorInterface(FSourceEditorList[Index]);
|
|
end;
|
|
|
|
function TSourceNotebook.OnSourceMarksGetSourceEditor(ASynEdit: TCustomSynEdit
|
|
): TObject;
|
|
begin
|
|
Result:=FindSourceEditorWithEditorComponent(ASynEdit);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.BuildPopupMenu;
|
|
var
|
|
i: Integer;
|
|
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}
|
|
SourceEditorMenuRoot.MenuItem:=SrcPopupMenu.Items;
|
|
|
|
SrcEditMenuFindDeclaration.OnClick:=@FindDeclarationClicked;
|
|
SrcEditMenuProcedureJump.OnClick:=@ProcedureJumpClicked;
|
|
SrcEditMenuFindNextWordOccurrence.OnClick:=@FindNextWordOccurrenceClicked;
|
|
SrcEditMenuFindPrevWordOccurrence.OnClick:=@FindPrevWordOccurrenceClicked;
|
|
SrcEditMenuFindinFiles.OnClick:=@FindInFilesClicked;
|
|
SrcEditMenuOpenFileAtCursor.OnClick:=@OpenAtCursorClicked;
|
|
|
|
SrcEditMenuClosePage.OnClick:=@CloseClicked;
|
|
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:=@BookmarkGotoClicked;
|
|
SrcEditSubMenuToggleBookmarks.FindByName('ToggleBookmark'+IntToStr(i))
|
|
.OnClick:=@BookMarkToggleClicked;
|
|
end;
|
|
SrcEditMenuSetFreeBookmark.OnClick:=@BookMarkSetFreeClicked;
|
|
SrcEditMenuNextBookmark.OnClick:=@BookMarkNextClicked;
|
|
SrcEditMenuPrevBookmark.OnClick:=@BookMarkPrevClicked;
|
|
|
|
SrcEditMenuToggleBreakpoint.OnClick:=@ToggleBreakpointClicked;
|
|
SrcEditMenuAddWatchAtCursor.OnClick:=@AddWatchAtCursor;
|
|
SrcEditMenuRunToCursor.OnClick:=@RunToClicked;
|
|
SrcEditMenuViewCallStack.OnClick:=@ViewCallStackClick;
|
|
|
|
SrcEditMenuMoveEditorLeft.OnClick:=@MoveEditorLeftClicked;
|
|
SrcEditMenuMoveEditorRight.OnClick:=@MoveEditorRightClicked;
|
|
SrcEditMenuMoveEditorFirst.OnClick:=@MoveEditorFirstClicked;
|
|
SrcEditMenuMoveEditorLast.OnClick:=@MoveEditorLastClicked;
|
|
SrcEditMenuMoveEditorLast.OnClick:=@MoveEditorLastClicked;
|
|
SrcEditMenuDocking.OnClick:=@DockingClicked;
|
|
|
|
SrcEditMenuInsertTodo.OnClick:=@InsertTodoClicked;
|
|
|
|
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;
|
|
SrcEditMenuShowUnitInfo.OnClick:=@ShowUnitInfo;
|
|
SrcEditMenuEditorProperties.OnClick:=@EditorPropertiesClicked;
|
|
end;
|
|
|
|
function TSourceNotebook.GetCompletionBoxPosition: integer;
|
|
begin
|
|
Result:=-1;
|
|
if CurCompletionControl<>nil then
|
|
Result:=CurCompletionControl.Position;
|
|
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.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:=GetSystemEncoding;
|
|
//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:=GetSystemEncoding;
|
|
if (SysEncoding<>'') and (SysUtils.CompareText(SysEncoding,EncodingAnsi)<>0)
|
|
then
|
|
CurCaption:=CurCaption+' ('+GetSystemEncoding+')';
|
|
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(OnEditorChanged) then
|
|
OnEditorChanged(Sender);
|
|
End;
|
|
|
|
function TSourceNotebook.NewSE(PageNum: Integer): TSourceEditor;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE A ');
|
|
{$ENDIF}
|
|
if CreateNotebook then Pagenum := 0;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE A2 ');
|
|
{$ENDIF}
|
|
if Pagenum < 0 then begin
|
|
// add a new page right to the current
|
|
Pagenum := Notebook.PageIndex+1;
|
|
Notebook.Pages.Insert(PageNum,FindUniquePageName('',-1));
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE B ',Notebook.PageIndex,',',NoteBook.Pages.Count);
|
|
{$ENDIF}
|
|
Result := TSourceEditor.Create(Self,Notebook.Page[PageNum]);
|
|
Result.EditorComponent.BeginUpdate;
|
|
FSourceEditorList.Add(Result);
|
|
Result.CodeTemplates:=CodeTemplateModul;
|
|
Notebook.PageIndex := Pagenum;
|
|
//debugln(['TSourceNotebook.NewSE C GetActiveSE=Result=',GetActiveSE=Result]);
|
|
Result.FPageName:=NoteBook.Pages[Pagenum];
|
|
Result.EditorComponent.BookMarkOptions.BookmarkImages := SourceEditorMarks.ImgList;
|
|
Result.EditorComponent.Gutter.MarksPart.DebugMarksImageIndex := SourceEditorMarks.SourceLineImg;
|
|
Result.PopupMenu := SrcPopupMenu;
|
|
Result.OnEditorChange := @EditorChanged;
|
|
Result.OnMouseMove := @EditorMouseMove;
|
|
Result.OnMouseDown := @EditorMouseDown;
|
|
Result.OnMouseWheel := @EditorMouseWheel;
|
|
Result.OnClickLink := @EditorClickLink;
|
|
Result.OnMouseLink := @EditorMouseLink;
|
|
Result.OnKeyDown := @EditorKeyDown;
|
|
|
|
Result.EditorComponent.EndUpdate;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.NewSE end ');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TSourceNotebook.FindSourceEditorWithPageIndex(
|
|
PageIndex: integer): TSourceEditor;
|
|
var I: integer;
|
|
TempEditor: TControl;
|
|
begin
|
|
Result := nil;
|
|
if (FSourceEditorList=nil)
|
|
or (Notebook=nil)
|
|
or (PageIndex<0) or (PageIndex>=Notebook.PageCount) then exit;
|
|
TempEditor:=nil;
|
|
with Notebook.Page[PageIndex] 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 (Notebook=nil) or (Notebook.PageIndex<0) then exit;
|
|
Result:=FindSourceEditorWithPageIndex(Notebook.PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.SetActiveSE(SrcEdit: TSourceEditor);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i:=FindPageWithEditor(SrcEdit);
|
|
if i>=0 then
|
|
NoteBook.PageIndex:=i;
|
|
end;
|
|
|
|
function TSourceNotebook.GetActiveEditor: TSourceEditorInterface;
|
|
begin
|
|
Result:=GetActiveSE;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SetActiveEditor(const AValue: TSourceEditorInterface
|
|
);
|
|
begin
|
|
SetActiveSE(AValue as TSourceEditor);
|
|
end;
|
|
|
|
procedure TSourceNotebook.CheckCurrentCodeBufferChanged;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit = nil then Exit;
|
|
if FLastCodeBuffer=SrcEdit.CodeBuffer then exit;
|
|
FLastCodeBuffer:=SrcEdit.CodeBuffer;
|
|
if Assigned(OnCurrentCodeBufferChanged) then
|
|
OnCurrentCodeBufferChanged(Self);
|
|
end;
|
|
|
|
procedure TSourceNotebook.LockAllEditorsInSourceChangeCache;
|
|
// lock all sourceeditors that are to be modified by the CodeToolBoss
|
|
var i: integer;
|
|
begin
|
|
for i:=0 to EditorCount-1 do begin
|
|
if CodeToolBoss.SourceChangeCache.BufferIsModified(Editors[i].CodeBuffer)
|
|
then begin
|
|
with Editors[i].EditorComponent do begin
|
|
BeginUpdate;
|
|
BeginUndoBlock;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.UnlockAllEditorsInSourceChangeCache;
|
|
// unlock all sourceeditors that were modified by the CodeToolBoss
|
|
var i: integer;
|
|
begin
|
|
for i:=0 to EditorCount-1 do begin
|
|
if CodeToolBoss.SourceChangeCache.BufferIsModified(Editors[i].CodeBuffer)
|
|
then begin
|
|
with Editors[i].EditorComponent do begin
|
|
EndUndoBlock;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TSourceNotebook.GetDiffFiles: TDiffFiles;
|
|
var
|
|
i: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
Result:=TDiffFiles.Create;
|
|
if Notebook=nil then exit;
|
|
for i:=0 to NoteBook.PageCount-1 do begin
|
|
SrcEdit:=FindSourceEditorWithPageIndex(i);
|
|
Result.Add(TDiffFile.Create(NoteBook.Pages[i],i,SrcEdit.SelectionAvailable));
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.GetSourceText(PageIndex: integer;
|
|
OnlySelection: boolean; var Source: string);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=FindSourceEditorWithPageIndex(PageIndex);
|
|
if SrcEdit=nil then
|
|
Source:=''
|
|
else
|
|
Source:=SrcEdit.GetText(OnlySelection);
|
|
end;
|
|
|
|
Function TSourceNotebook.Empty: Boolean;
|
|
Begin
|
|
Result := (not assigned(Notebook)) or (Notebook.PageCount = 0);
|
|
end;
|
|
|
|
procedure TSourceNotebook.FindReplaceDlgKey(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState; FindDlgComponent: TFindDlgComponent);
|
|
var
|
|
HistoryList: TStringList;
|
|
CurText: string;
|
|
CurIndex: integer;
|
|
|
|
procedure SetHistoryText;
|
|
var s: string;
|
|
begin
|
|
if FindReplaceDlgHistoryIndex[FindDlgComponent]>=0 then
|
|
s:=HistoryList[FindReplaceDlgHistoryIndex[FindDlgComponent]]
|
|
else
|
|
s:=FindReplaceDlgUserText[FindDlgComponent];
|
|
//writeln(' SetHistoryText "',s,'"');
|
|
LazFindReplaceDialog.ComponentText[FindDlgComponent]:=s
|
|
end;
|
|
|
|
procedure FetchFocus;
|
|
begin
|
|
if Sender is TWinControl then
|
|
TWinControl(Sender).SetFocus;
|
|
end;
|
|
|
|
begin
|
|
if FindDlgComponent=fdcText then
|
|
HistoryList:=InputHistories.FindHistory
|
|
else
|
|
HistoryList:=InputHistories.ReplaceHistory;
|
|
CurIndex:=FindReplaceDlgHistoryIndex[FindDlgComponent];
|
|
CurText:=LazFindReplaceDialog.ComponentText[FindDlgComponent];
|
|
//writeln('TSourceNotebook.FindReplaceDlgKey CurIndex=',CurIndex,' CurText="',CurText,'"');
|
|
if Key=VK_UP then begin
|
|
// go forward in history
|
|
if CurIndex>=0 then begin
|
|
if (HistoryList[CurIndex]<>CurText) then begin
|
|
// save user text
|
|
FindReplaceDlgUserText[FindDlgComponent]:=CurText;
|
|
end;
|
|
dec(FindReplaceDlgHistoryIndex[FindDlgComponent]);
|
|
SetHistoryText;
|
|
end;
|
|
FetchFocus;
|
|
Key:=VK_UNKNOWN;
|
|
end else if Key=VK_DOWN then begin
|
|
if (CurIndex<0)
|
|
or (HistoryList[CurIndex]<>CurText) then
|
|
begin
|
|
// save user text
|
|
FindReplaceDlgUserText[FindDlgComponent]:=CurText;
|
|
end;
|
|
// go back in history
|
|
if CurIndex<HistoryList.Count-1 then
|
|
begin
|
|
inc(FindReplaceDlgHistoryIndex[FindDlgComponent]);
|
|
SetHistoryText;
|
|
end;
|
|
FetchFocus;
|
|
Key:=VK_UNKNOWN;
|
|
end;
|
|
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;
|
|
|
|
function TSourceNotebook.SomethingModified: boolean;
|
|
var i: integer;
|
|
begin
|
|
Result:=false;
|
|
for i:=0 to EditorCount-1 do Result:=Result or Editors[i].Modified;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.NextEditor;
|
|
Begin
|
|
if NoteBook=nil then exit;
|
|
if Notebook.PageIndex < Notebook.PageCount-1 then
|
|
Notebook.PageIndex := Notebook.PageIndex+1
|
|
else
|
|
NoteBook.PageIndex := 0;
|
|
NotebookPageChanged(Self);
|
|
End;
|
|
|
|
Procedure TSourceNotebook.PrevEditor;
|
|
Begin
|
|
if NoteBook=nil then exit;
|
|
if Notebook.PageIndex > 0 then
|
|
Notebook.PageIndex := Notebook.PageIndex-1
|
|
else
|
|
NoteBook.PageIndex := NoteBook.PageCount-1;
|
|
NotebookPageChanged(Self);
|
|
End;
|
|
|
|
procedure TSourceNotebook.MoveEditor(OldPageIndex, NewPageIndex: integer);
|
|
begin
|
|
if (NoteBook=nil) or (NoteBook.PageCount<=1)
|
|
or (OldPageIndex=NewPageIndex)
|
|
or (OldPageIndex<0) or (OldPageIndex>=Notebook.PageCount)
|
|
or (NewPageIndex<0) or (NewPageIndex>=Notebook.PageCount) then exit;
|
|
if Assigned(OnMovingPage) then
|
|
OnMovingPage(Self,OldPageIndex,NewPageIndex);
|
|
NoteBook.Pages.Move(OldPageIndex,NewPageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorLeft(PageIndex: integer);
|
|
begin
|
|
if (NoteBook=nil) or (NoteBook.PageCount<=1) then exit;
|
|
if PageIndex>0 then
|
|
MoveEditor(PageIndex,PageIndex-1)
|
|
else
|
|
MoveEditor(PageIndex,NoteBook.PageCount-1);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorRight(PageIndex: integer);
|
|
begin
|
|
if (NoteBook=nil) or (NoteBook.PageCount<=1) then exit;
|
|
if PageIndex<Notebook.PageCount-1 then
|
|
MoveEditor(PageIndex,PageIndex+1)
|
|
else
|
|
MoveEditor(PageIndex,0);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorFirst(PageIndex: integer);
|
|
begin
|
|
if (NoteBook=nil) or (NoteBook.PageCount<=1) then exit;
|
|
MoveEditor(PageIndex,0)
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveEditorLast(PageIndex: integer);
|
|
begin
|
|
if (NoteBook=nil) or (NoteBook.PageCount<=1) then exit;
|
|
MoveEditor(PageIndex,NoteBook.PageCount-1);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageLeft;
|
|
begin
|
|
if (NoteBook=nil) then exit;
|
|
MoveEditorLeft(NoteBook.PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageRight;
|
|
begin
|
|
if (NoteBook=nil) then exit;
|
|
MoveEditorRight(NoteBook.PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageFirst;
|
|
begin
|
|
if (NoteBook=nil) then exit;
|
|
MoveEditorFirst(NoteBook.PageIndex);
|
|
end;
|
|
|
|
procedure TSourceNotebook.MoveActivePageLast;
|
|
begin
|
|
if (NoteBook=nil) then exit;
|
|
MoveEditorLast(NoteBook.PageIndex);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.FindClicked(Sender: TObject);
|
|
var TempEditor:TSourceEditor;
|
|
Begin
|
|
TempEditor:=GetActiveSE;
|
|
if TempEditor <> nil then TempEditor.StartFindAndReplace(false);
|
|
End;
|
|
|
|
Procedure TSourceNotebook.ReplaceClicked(Sender: TObject);
|
|
var TempEditor:TSourceEditor;
|
|
Begin
|
|
TempEditor:=GetActiveSE;
|
|
if TempEditor <> nil then TempEditor.StartFindAndReplace(true);
|
|
End;
|
|
|
|
procedure TSourceNotebook.IncrementalFindClicked(Sender: TObject);
|
|
begin
|
|
BeginIncrementalFind;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.FindNextClicked(Sender: TObject);
|
|
var TempEditor:TSourceEditor;
|
|
Begin
|
|
TempEditor:=GetActiveSe;
|
|
if TempEditor <> nil then TempEditor.FindNextUTF8;
|
|
End;
|
|
|
|
Procedure TSourceNotebook.FindPreviousClicked(Sender: TObject);
|
|
var TempEditor:TSourceEditor;
|
|
Begin
|
|
TempEditor:=GetActiveSe;
|
|
if TempEditor <> nil then TempEditor.FindPrevious;
|
|
End;
|
|
|
|
function TSourceNotebook.CreateFindInFilesDialog: TLazFindInFilesDialog;
|
|
begin
|
|
Result := TLazFindInFilesDialog.Create(Application);
|
|
LoadFindInFilesHistory(Result);
|
|
end;
|
|
|
|
procedure TSourceNotebook.LoadFindInFilesHistory(ADialog: TLazFindInFilesDialog);
|
|
|
|
procedure AssignToComboBox(AComboBox: TComboBox; Strings: TStrings);
|
|
begin
|
|
AComboBox.Items.Assign(Strings);
|
|
if AComboBox.Items.Count>0 then
|
|
AComboBox.ItemIndex := 0;
|
|
end;
|
|
|
|
procedure AddFileToComboBox(AComboBox: TComboBox; const Filename: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Filename='' then exit;
|
|
for i:=0 to AComboBox.Items.Count-1 do begin
|
|
if CompareFilenames(Filename,AComboBox.Items[i])=0 then begin
|
|
// move to front (but not top, top should be the last used directory)
|
|
if i>2 then
|
|
AComboBox.Items.Move(i,1);
|
|
exit;
|
|
end;
|
|
end;
|
|
// insert in front (but not top, top should be the last used directory)
|
|
if AComboBox.Items.Count>0 then
|
|
i:=1
|
|
else
|
|
i:=0;
|
|
AComboBox.Items.Insert(i,Filename);
|
|
end;
|
|
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if not Assigned(ADialog) then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
with ADialog, InputHistories do
|
|
begin
|
|
//DebugLn('TSourceNotebook.LoadFindInFilesHistory ',dbgsName(TextToFindComboBox),' ',dbgsName(FindHistory));
|
|
TextToFindComboBox.Items.Assign(FindHistory);
|
|
ReplaceTextComboBox.Items.Assign(ReplaceHistory);
|
|
if not EditorOpts.FindTextAtCursor then begin
|
|
if TextToFindComboBox.Items.Count>0 then begin
|
|
//debugln('TSourceNotebook.LoadFindInFilesHistory A TextToFindComboBox.Text=',TextToFindComboBox.Text);
|
|
TextToFindComboBox.ItemIndex:=0;
|
|
TextToFindComboBox.SelectAll;
|
|
//debugln('TSourceNotebook.LoadFindInFilesHistory B TextToFindComboBox.Text=',TextToFindComboBox.Text);
|
|
end;
|
|
end;
|
|
// show last used directories and directory of current file
|
|
AssignToComboBox(DirectoryComboBox, FindInFilesPathHistory);
|
|
if (SrcEdit<>nil) and (FilenameIsAbsolute(SrcEdit.FileName)) then
|
|
AddFileToComboBox(DirectoryComboBox, ExtractFilePath(SrcEdit.FileName));
|
|
// show last used file masks
|
|
AssignToComboBox(FileMaskComboBox, FindInFilesMaskHistory);
|
|
Options:=FindInFilesSearchOptions;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.SaveFindInFilesHistory(ADialog: TLazFindInFilesDialog);
|
|
begin
|
|
if Assigned(ADialog) then
|
|
begin
|
|
with ADialog do
|
|
begin
|
|
InputHistories.AddToFindHistory(FindText);
|
|
InputHistories.AddToFindInFilesPathHistory(DirectoryComboBox.Text);
|
|
InputHistories.AddToFindInFilesMaskHistory(FileMaskComboBox.Text);
|
|
InputHistories.FindInFilesSearchOptions:=Options;
|
|
end;
|
|
InputHistories.Save;
|
|
end;
|
|
end;
|
|
|
|
{Search All the files in a project and add the results to the SearchResultsView
|
|
Dialog}
|
|
procedure TSourceNotebook.FIFSearchProject(AProject: TProject;
|
|
ADialog: TLazFindInFilesDialog);
|
|
var
|
|
AnUnitInfo: TUnitInfo;
|
|
TheFileList: TStringList;
|
|
SearchForm: TSearchForm;
|
|
begin
|
|
try
|
|
TheFileList:= TStringList.Create;
|
|
AnUnitInfo:=AProject.FirstPartOfProject;
|
|
while AnUnitInfo<>nil do begin
|
|
//Only if file exists on disk.
|
|
if FilenameIsAbsolute(AnUnitInfo.FileName)
|
|
and FileExistsUTF8(AnUnitInfo.FileName) then
|
|
TheFileList.Add(AnUnitInfo.FileName);
|
|
AnUnitInfo:=AnUnitInfo.NextPartOfProject;
|
|
end;
|
|
SearchForm:= FIFCreateSearchForm(ADialog);
|
|
SearchForm.SearchFileList:= TheFileList;
|
|
DoFindInFiles(SearchForm);
|
|
finally
|
|
FreeAndNil(TheFileList);
|
|
FreeAndNil(SearchForm);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.FIFSearchDir(ADialog: TLazFindInFilesDialog);
|
|
var
|
|
SearchForm: TSearchForm;
|
|
begin
|
|
try
|
|
SearchForm:= FIFCreateSearchForm(ADialog);
|
|
SearchForm.SearchFileList:= Nil;
|
|
DoFindInFiles(SearchForm);
|
|
finally
|
|
FreeAndNil(SearchForm);
|
|
end;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.DoFindInFiles(ASearchForm: TSearchForm);
|
|
var
|
|
ListIndex: integer;
|
|
begin
|
|
ShowSearchResultsView;
|
|
ListIndex:=SearchResultsView.AddSearch(ASearchForm.SearchText,
|
|
ASearchForm.SearchText,
|
|
ASearchForm.ReplaceText,
|
|
ASearchForm.SearchDirectory,
|
|
ASearchForm.SearchMask,
|
|
ASearchForm.SearchOptions);
|
|
|
|
try
|
|
SearchResultsView.BeginUpdate(ListIndex);
|
|
ASearchForm.ResultsList:= SearchResultsView.Items[ListIndex];
|
|
SearchResultsView.Items[ListIndex].Clear;
|
|
ASearchForm.ResultsWindow:= ListIndex;
|
|
try
|
|
ASearchForm.Show;
|
|
// update Window Menu, the OnIdle event does not occur when searching
|
|
MainIDEInterface.UpdateWindowMenu;
|
|
ASearchForm.DoSearch;
|
|
except
|
|
on E: ERegExpr do
|
|
MessageDlg(lisUEErrorInRegularExpression, E.Message,mtError,
|
|
[mbCancel],0);
|
|
end;
|
|
finally
|
|
SearchResultsView.EndUpdate(ListIndex);
|
|
SearchResultsView.ShowOnTop;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.FIFSearchOpenFiles(ADialog: TLazFindInFilesDialog);
|
|
var
|
|
i: integer;
|
|
TheFileList: TStringList;
|
|
SearchForm: TSearchForm;
|
|
begin
|
|
try
|
|
TheFileList:= TStringList.Create;
|
|
for i:= 0 to self.EditorCount -1 do
|
|
begin
|
|
//only if file exists on disk
|
|
if FilenameIsAbsolute(Editors[i].FileName) and
|
|
FileExistsUTF8(Editors[i].FileName) then
|
|
begin
|
|
TheFileList.Add(Editors[i].FileName);
|
|
end;//if
|
|
end;//for
|
|
SearchForm:= FIFCreateSearchForm(ADialog);
|
|
SearchForm.SearchFileList:= TheFileList;
|
|
DoFindInFiles(SearchForm);
|
|
finally
|
|
FreeAndNil(TheFileList);
|
|
FreeAndNil(SearchForm);
|
|
end;//finally
|
|
end;//FIFSearchOpenFiles
|
|
|
|
{Creates the search form and loads the options selected in the
|
|
findinfilesdialog}
|
|
function TSourceNotebook.FIFCreateSearchForm
|
|
(ADialog: TLazFindInFilesDialog): TSearchForm;
|
|
begin
|
|
result:= TSearchForm.Create(SearchResultsView);
|
|
with result do
|
|
begin
|
|
SearchOptions:= ADialog.Options;
|
|
SearchText:= ADialog.FindText;
|
|
ReplaceText:= ADialog.ReplaceText;
|
|
SearchMask:= ADialog.FileMaskComboBox.Text;
|
|
SearchDirectory:= ADialog.DirectoryComboBox.Text;
|
|
end;//with
|
|
end;//FIFCreateSearchForm
|
|
|
|
Procedure TSourceNotebook.FindInFilesPerDialog(AProject: TProject);
|
|
var
|
|
TempEditor: TSourceEditor;
|
|
FindText: string;
|
|
Begin
|
|
FindText:='';
|
|
TempEditor := GetActiveSE;
|
|
if TempEditor <> nil
|
|
then with TempEditor, EditorComponent do
|
|
begin
|
|
if EditorOpts.FindTextAtCursor
|
|
then begin
|
|
if SelAvail and (BlockBegin.Y = BlockEnd.Y)
|
|
then FindText := SelText
|
|
else FindText := GetWordAtRowCol(LogicalCaretXY);
|
|
end else begin
|
|
if InputHistories.FindHistory.Count>0 then
|
|
FindText:=InputHistories.FindHistory[0];
|
|
end;
|
|
end;
|
|
|
|
FindInFiles(AProject, FindText);
|
|
End;
|
|
|
|
procedure TSourceNotebook.FindInFiles(AProject: TProject;
|
|
const FindText: string);
|
|
begin
|
|
if FindInFilesDialog = nil then
|
|
FindInFilesDialog := CreateFindInFilesDialog
|
|
else
|
|
LoadFindInFilesHistory(FindInFilesDialog);
|
|
|
|
// if there is no FindText, use the most recently used FindText
|
|
FindInFilesDialog.FindText:= FindText;
|
|
if (FindInFilesDialog.FindText='') and (InputHistories.FindHistory.Count > 0) then
|
|
FindInFilesDialog.FindText:=InputHistories.FindHistory[0];
|
|
|
|
// disable replace. Find in files is often called,
|
|
// but almost never to replace with the same parameters
|
|
FindInFilesDialog.Options:=
|
|
FindInFilesDialog.Options-[fifReplace,fifReplaceAll];
|
|
if FindInFilesDialog.ShowModal=mrOk then
|
|
begin
|
|
SaveFindInFilesHistory(FindInFilesDialog);
|
|
|
|
if FindInFilesDialog.FindText <>'' then
|
|
begin
|
|
case FindInFilesDialog.WhereRadioGroup.ItemIndex of
|
|
0: FIFSearchProject(AProject, FindInFilesDialog);
|
|
1: FIFSearchOpenFiles(FindInFilesDialog);
|
|
2: FIFSearchDir(FindInFilesDialog);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ShowSearchResultsView;
|
|
begin
|
|
if Assigned(OnShowSearchResultsView) then OnShowSearchResultsView(Self);
|
|
end;
|
|
|
|
procedure TSourceNotebook.GotoLineClicked(Sender: TObject);
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit := GetActiveSE;
|
|
if SrcEdit <> nil then
|
|
SrcEdit.ShowGotoLineDialog;
|
|
end;
|
|
|
|
procedure TSourceNotebook.HistoryJump(Sender: TObject;
|
|
CloseAction: TJumpHistoryAction);
|
|
var NewCaretXY: TPoint;
|
|
NewTopLine: integer;
|
|
NewPageIndex: integer;
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if (NoteBook<>nil) and Assigned(OnJumpToHistoryPoint) then begin
|
|
NewCaretXY.X:=-1;
|
|
NewPageIndex:=-1;
|
|
OnJumpToHistoryPoint(NewCaretXY,NewTopLine,NewPageIndex,CloseAction);
|
|
SrcEdit:=FindSourceEditorWithPageIndex(NewPageIndex);
|
|
if SrcEdit<>nil then begin
|
|
NoteBook.PageIndex:=NewPageIndex;
|
|
with SrcEdit.EditorComponent do begin
|
|
TopLine:=NewTopLine;
|
|
LogicalCaretXY:=NewCaretXY;
|
|
BlockBegin:=NewCaretXY;
|
|
BlockEnd:=NewCaretXY;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.JumpBackClicked(Sender: TObject);
|
|
begin
|
|
HistoryJump(Sender,jhaBack);
|
|
end;
|
|
|
|
procedure TSourceNotebook.JumpForwardClicked(Sender: TObject);
|
|
begin
|
|
HistoryJump(Sender,jhaForward);
|
|
end;
|
|
|
|
procedure TSourceNotebook.AddJumpPointClicked(Sender: TObject);
|
|
var SrcEdit: TSourceEditor;
|
|
begin
|
|
if Assigned(OnAddJumpPoint) then begin
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit<>nil then begin
|
|
OnAddJumpPoint(SrcEdit.EditorComponent.LogicalCaretXY,
|
|
SrcEdit.EditorComponent.TopLine, Notebook.PageIndex, true);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.DeleteLastJumpPointClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnDeleteLastJumpPoint) then
|
|
OnDeleteLastJumpPoint(Sender);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ViewJumpHistoryClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(OnViewJumpHistory) then
|
|
OnViewJumpHistory(Sender);
|
|
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 FHintTimer<>nil then
|
|
FHintTimer.Enabled:=false;
|
|
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 OnShowCodeContext<>nil then begin
|
|
OnShowCodeContext(JumpToError,Abort);
|
|
if Abort then ;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.StartShowCodeHelp;
|
|
begin
|
|
if SrcEditHintWindow=nil then begin
|
|
SrcEditHintWindow:=TSrcEditHintWindow.Create(Self);
|
|
SrcEditHintWindow.Name:='TSourceNotebook_SrcEditHintWindow';
|
|
SrcEditHintWindow.Provider:=TFPDocHintProvider.Create(SrcEditHintWindow);
|
|
end;
|
|
SrcEditHintWindow.AnchorForm:=CurCompletionControl.TheForm;
|
|
{$IFDEF EnableCodeHelp}
|
|
SrcEditHintWindow.HelpEnabled:=true;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceNotebook.BookMarkToggleClicked(Sender: TObject);
|
|
// popup menu: toggle bookmark clicked
|
|
var
|
|
MenuItem: TIDEMenuItem;
|
|
Begin
|
|
MenuItem := Sender as TIDEMenuItem;
|
|
BookMarkSet(MenuItem.SectionIndex,true);
|
|
end;
|
|
|
|
procedure TSourceNotebook.BookmarkSetFreeClicked(Sender: TObject);
|
|
begin
|
|
BookMarkSetFree;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.BookMarkGotoClicked(Sender: TObject);
|
|
// popup menu goto bookmark clicked
|
|
var
|
|
MenuItem: TIDEMenuItem;
|
|
Begin
|
|
MenuItem := Sender as TIDEMenuItem;
|
|
GotoBookMark(MenuItem.SectionIndex);
|
|
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(OnReadOnlyChanged) then
|
|
OnReadOnlyChanged(Self);
|
|
UpdateStatusBar;
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenPasFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.pas'),
|
|
Notebook.PageIndex+1,
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenPPFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.pp'),
|
|
Notebook.PageIndex+1,
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenPFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.p'),
|
|
Notebook.PageIndex+1,
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenLFMFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.lfm'),
|
|
Notebook.PageIndex+1,
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenLRSFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.lrs'),
|
|
Notebook.PageIndex+1,
|
|
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofUseCache,ofDoNotLoadResource]);
|
|
end;
|
|
|
|
procedure TSourceNotebook.OnPopupMenuOpenSFile(Sender: TObject);
|
|
begin
|
|
MainIDEInterface.DoOpenEditorFile(ChangeFileExt(GetActiveSE.Filename,'.s'),
|
|
Notebook.PageIndex+1,
|
|
[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(FOnShowUnitInfo) then FOnShowUnitInfo(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.OpenAtCursorClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnOpenFileAtCursorClicked) then
|
|
FOnOpenFileAtCursorClicked(Sender);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.FindDeclarationClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnFindDeclarationClicked) then
|
|
FOnFindDeclarationClicked(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.InsertTodoClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnInsertTodoClicked) then
|
|
FOnInsertTodoClicked(Sender);
|
|
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.DockingClicked(Sender: TObject);
|
|
begin
|
|
ControlDocker.ShowDockingEditor;
|
|
end;
|
|
|
|
{This is called from outside to toggle a bookmark}
|
|
Procedure TSourceNotebook.ToggleBookmark(Value: Integer);
|
|
Begin
|
|
BookMarkSet(Value,true);
|
|
End;
|
|
|
|
procedure TSourceNotebook.AddBreakpointClicked(Sender: TObject );
|
|
var
|
|
ASrcEdit: TSourceEditor;
|
|
begin
|
|
ASrcEdit:=GetActiveSE;
|
|
if ASrcEdit=nil then exit;
|
|
DebugBoss.DoCreateBreakPoint(ASrcEdit.Filename,
|
|
ASrcEdit.EditorComponent.CaretY,true);
|
|
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 StatusBar.GetPanelIndexAt(P.X, P.Y) = 0 then
|
|
begin
|
|
// then show goto line dialog
|
|
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.FEditor,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;
|
|
|
|
Procedure TSourceNotebook.BookMarkSet(Value: Integer; Toggle: boolean);
|
|
var
|
|
ActEdit, AnEdit: TSourceEditor;
|
|
Cmd: TIDEMenuCommand;
|
|
OldX, OldY: integer;
|
|
NewXY: TPoint;
|
|
SetMark: Boolean;
|
|
Begin
|
|
ActEdit:=GetActiveSE;
|
|
NewXY:=ActEdit.EditorComponent.CaretXY;
|
|
|
|
SetMark:=true;
|
|
AnEdit:=FindBookmark(Value);
|
|
if (AnEdit<>nil) and AnEdit.EditorComponent.GetBookMark(Value,OldX,OldY) then
|
|
begin
|
|
if (not Toggle) and (OldX=NewXY.X) and (OldY=NewXY.Y) then
|
|
exit; // no change
|
|
AnEdit.EditorComponent.ClearBookMark(Value);
|
|
if Toggle and (OldY=NewXY.Y) then
|
|
SetMark:=false;
|
|
end;
|
|
if SetMark then
|
|
ActEdit.EditorComponent.SetBookMark(Value,NewXY.X,NewXY.Y);
|
|
Cmd:=SrcEditSubMenuToggleBookmarks[Value] as TIDEMenuCommand;
|
|
Cmd.Checked := SetMark;
|
|
if Project1<>nil then
|
|
Project1.SessionModified:=true;
|
|
end;
|
|
|
|
procedure TSourceNotebook.BookMarkSetFree;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to 9 do
|
|
if (FindBookmark(i)=nil) then begin
|
|
BookMarkSet(i);
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
{This is called from outside to set a bookmark}
|
|
procedure TSourceNotebook.SetBookmark(Value: Integer);
|
|
Begin
|
|
BookMarkSet(Value);
|
|
End;
|
|
|
|
procedure TSourceNotebook.BookmarkGotoNext(GoForward: boolean);
|
|
var
|
|
CurBookmarkID: Integer;
|
|
x: Integer;
|
|
y: Integer;
|
|
SrcEdit: TSourceEditor;
|
|
StartY: LongInt;
|
|
CurEditorComponent: TSynEdit;
|
|
StartEditorComponent: TSynEdit;
|
|
BestBookmarkID: Integer;
|
|
BestY: Integer;
|
|
CurPageIndex: Integer;
|
|
CurSrcEdit: TSourceEditor;
|
|
StartPageIndex: LongInt;
|
|
BetterFound: Boolean;
|
|
PageDistance: Integer;
|
|
BestPageDistance: Integer;
|
|
begin
|
|
if Notebook=nil then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
// init best bookmark
|
|
BestBookmarkID:=-1;
|
|
BestY:=-1;
|
|
BestPageDistance:=-1;
|
|
// where is the cursor
|
|
StartPageIndex:=Notebook.PageIndex;
|
|
StartEditorComponent:=SrcEdit.EditorComponent;
|
|
StartY:=StartEditorComponent.CaretY;
|
|
// go through all bookmarks
|
|
for CurPageIndex:=0 to Notebook.PageCount-1 do begin
|
|
CurSrcEdit:=FindSourceEditorWithPageIndex(CurPageIndex);
|
|
CurEditorComponent:=CurSrcEdit.EditorComponent;
|
|
for CurBookmarkID:=0 to 9 do begin
|
|
if CurEditorComponent.GetBookmark(CurBookmarkID,x,y) then begin
|
|
if (CurPageIndex=StartPageIndex) and (y=StartY) then
|
|
continue;
|
|
|
|
// for GoForward=true we are searching the nearest bookmark down the
|
|
// current page, then the pages from left to right, starting at the
|
|
// current page. That means the lines above the cursor are the most
|
|
// far away.
|
|
|
|
// calculate the distance of pages between the current bookmark
|
|
// and the current page
|
|
PageDistance:=(StartPageIndex-CurPageIndex);
|
|
if GoForward then PageDistance:=-PageDistance;
|
|
if PageDistance<0 then
|
|
// for GoForward=true the pages on the left are farer than the pages
|
|
// on the right (and vice versus)
|
|
inc(PageDistance,Notebook.PageCount);
|
|
if (PageDistance=0) then begin
|
|
// for GoForward=true the lines in front are farer than the pages
|
|
// on the left side
|
|
if (GoForward and (y<StartY))
|
|
or ((not GoForward) and (y>StartY)) then
|
|
inc(PageDistance,Notebook.PageCount);
|
|
end;
|
|
|
|
BetterFound:=false;
|
|
if BestBookmarkID<0 then
|
|
BetterFound:=true
|
|
else if PageDistance<BestPageDistance then begin
|
|
BetterFound:=true;
|
|
end else if PageDistance=BestPageDistance then begin
|
|
if (GoForward and (y<BestY))
|
|
or ((not GoForward) and (y>BestY)) then
|
|
BetterFound:=true;
|
|
end;
|
|
//debugln('TSourceNotebook.BookmarkGotoNext GoForward=',dbgs(GoForward),
|
|
// ' CurBookmarkID=',dbgs(CurBookmarkID),
|
|
// ' PageDistance=',dbgs(PageDistance),' BestPageDistance='+dbgs(BestPageDistance),
|
|
// ' y='+dbgs(y),' BestY='+dbgs(BestY),' StartY=',dbgs(StartY),
|
|
// ' StartPageIndex='+dbgs(StartPageIndex),' CurPageIndex='+dbgs(CurPageIndex),
|
|
// ' BetterFound='+dbgs(BetterFound));
|
|
|
|
if BetterFound then begin
|
|
// nearer bookmark found
|
|
BestBookmarkID:=CurBookmarkID;
|
|
BestY:=y;
|
|
BestPageDistance:=PageDistance;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
if BestBookmarkID>=0 then
|
|
BookMarkGoto(BestBookmarkID);
|
|
end;
|
|
|
|
procedure TSourceNotebook.BookMarkGoto(Index: Integer);
|
|
var
|
|
AnEditor:TSourceEditor;
|
|
begin
|
|
if Notebook=nil then exit;
|
|
AnEditor:=FindBookmark(Index);
|
|
if AnEditor<>nil then begin
|
|
AnEditor.EditorComponent.GotoBookMark(Index);
|
|
AnEditor.CenterCursor;
|
|
Notebook.PageIndex:=FindPageWithEditor(AnEditor);
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.BookMarkNextClicked(Sender: TObject);
|
|
begin
|
|
BookmarkGotoNext(true);
|
|
end;
|
|
|
|
procedure TSourceNotebook.BookMarkPrevClicked(Sender: TObject);
|
|
begin
|
|
BookmarkGotoNext(false);
|
|
end;
|
|
|
|
{This is called from outside to Go to a bookmark}
|
|
Procedure TSourceNotebook.GoToBookmark(Value: Integer);
|
|
begin
|
|
BookMarkGoTo(Value);
|
|
End;
|
|
|
|
function TSourceNotebook.NewFile(const NewShortName: String;
|
|
ASource: TCodeBuffer; FocusIt: boolean): TSourceEditor;
|
|
Begin
|
|
//create a new page
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] A ');
|
|
{$ENDIF}
|
|
Visible:=true;
|
|
Result := NewSE(-1);
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] B ');
|
|
{$ENDIF}
|
|
Result.CodeBuffer:=ASource;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] D ');
|
|
{$ENDIF}
|
|
Result.PageName:=FindUniquePageName(NewShortName,Notebook.PageIndex);
|
|
if FocusIt then FocusEditor;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('[TSourceNotebook.NewFile] end');
|
|
{$ENDIF}
|
|
CheckFont;
|
|
end;
|
|
|
|
procedure TSourceNotebook.CloseFile(PageIndex:integer);
|
|
var
|
|
TempEditor: TSourceEditor;
|
|
begin
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.CloseFile A PageIndex=',PageIndex);
|
|
{$ENDIF}
|
|
TempEditor:=FindSourceEditorWithPageIndex(PageIndex);
|
|
if TempEditor=nil then exit;
|
|
//debugln(['TSourceNotebook.CloseFile ',TempEditor.FileName,' ',TempEditor.PageIndex]);
|
|
Visible:=true;
|
|
EndIncrementalFind;
|
|
TempEditor.Close;
|
|
TempEditor.Free;
|
|
if Notebook.PageCount>1 then
|
|
begin
|
|
//writeln('TSourceNotebook.CloseFile B PageIndex=',PageIndex,' Notebook.PageIndex=',Notebook.PageIndex);
|
|
// if this is the current page, switch to right PageIndex (if possible)
|
|
if (Notebook.PageIndex = PageIndex) then
|
|
Notebook.PageIndex := PageIndex +
|
|
IfThen(PageIndex + 1 < Notebook.PageCount, 1, -1);
|
|
// delete the page
|
|
//writeln('TSourceNotebook.CloseFile C PageIndex=',PageIndex,' Notebook.PageCount=',Notebook.PageCount,' NoteBook.PageIndex=',Notebook.PageIndex);
|
|
Notebook.Pages.Delete(PageIndex);
|
|
//writeln('TSourceNotebook.CloseFile D PageIndex=',PageIndex,' Notebook.PageCount=',Notebook.PageCount,' NoteBook.PageIndex=',Notebook.PageIndex);
|
|
UpdateStatusBar;
|
|
// set focus to new editor
|
|
TempEditor:=FindSourceEditorWithPageIndex(Notebook.PageIndex);
|
|
if (TempEditor <> nil) then
|
|
TempEditor.EditorComponent.SetFocus;
|
|
end else
|
|
begin
|
|
//writeln('TSourceNotebook.CloseFile E PageIndex=',PageIndex);
|
|
Notebook.Free;
|
|
//writeln('TSourceNotebook.CloseFile F PageIndex=',PageIndex);
|
|
Notebook:=nil;
|
|
Hide;
|
|
end;
|
|
{$IFDEF IDE_DEBUG}
|
|
writeln('TSourceNotebook.CloseFile END');
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TSourceNotebook.FocusEditor;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
if (NoteBook=nil) or (fAutoFocusLock>0) then exit;
|
|
SrcEdit:=GetActiveSE;
|
|
if SrcEdit=nil then exit;
|
|
Show;
|
|
SrcEdit.FocusEditor;
|
|
end;
|
|
|
|
Function TSourceNotebook.ActiveFileName: AnsiString;
|
|
Begin
|
|
Result := GetActiveSE.FileName;
|
|
end;
|
|
|
|
function TSourceNotebook.GetEditors(Index:integer):TSourceEditor;
|
|
begin
|
|
Result:=TSourceEditor(FSourceEditorList[Index]);
|
|
end;
|
|
|
|
function TSourceNotebook.EditorCount:integer;
|
|
begin
|
|
Result:=FSourceEditorList.Count;
|
|
end;
|
|
|
|
function TSourceNotebook.Count: integer;
|
|
begin
|
|
Result:=FSourceEditorList.Count;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.CloseClicked(Sender: TObject);
|
|
Begin
|
|
if Assigned(FOnCloseClicked) then FOnCloseClicked(Sender,false);
|
|
end;
|
|
|
|
Function TSourceNotebook.FindUniquePageName(FileName:string;
|
|
IgnorePageIndex:integer):string;
|
|
var I:integer;
|
|
ShortName:string;
|
|
|
|
function PageNameExists(const AName:string):boolean;
|
|
var a:integer;
|
|
begin
|
|
Result:=false;
|
|
if Notebook=nil then exit;
|
|
for a:=0 to Notebook.PageCount-1 do begin
|
|
if (a<>IgnorePageIndex)
|
|
and (AnsiCompareText(AName,FindSourceEditorWithPageIndex(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;
|
|
|
|
procedure TSourceNotebook.ToggleFormUnitClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnToggleFormUnitClicked) then FOnToggleFormUnitClicked(Sender);
|
|
end;
|
|
|
|
procedure TSourceNotebook.ToggleObjectInspClicked(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnToggleObjectInspClicked) then FOnToggleObjectInspClicked(Sender);
|
|
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.SelText := C;
|
|
end;
|
|
end;
|
|
|
|
procedure TSourceNotebook.InitFindDialog;
|
|
var c: TFindDlgComponent;
|
|
begin
|
|
LazFindReplaceDialog.OnKey:=@FindReplaceDlgKey;
|
|
for c:=Low(TFindDlgComponent) to High(TFindDlgComponent) do
|
|
FindReplaceDlgHistoryIndex[c]:=-1;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.UpdateStatusBar;
|
|
var
|
|
tempEditor: TSourceEditor;
|
|
PanelFilename: String;
|
|
PanelCharMode: string;
|
|
PanelXY: string;
|
|
PanelFileMode: string;
|
|
CurEditor: TSynEdit;
|
|
begin
|
|
if not Visible then exit;
|
|
TempEditor := GetActiveSE;
|
|
if TempEditor = nil then Exit;
|
|
CurEditor:=TempEditor.EditorComponent;
|
|
|
|
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
|
|
if PanelFileMode <> '' then
|
|
PanelFileMode := Format(lisUEReadOnly, [PanelFileMode])
|
|
else
|
|
PanelFileMode := uepReadonly;
|
|
|
|
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;
|
|
UpdateFPDocEditor;
|
|
End;
|
|
|
|
function TSourceNotebook.FindBookmark(BookmarkID: integer): TSourceEditor;
|
|
var i,x,y:integer;
|
|
begin
|
|
for i:=0 to EditorCount-1 do begin
|
|
if Editors[i].EditorComponent.GetBookmark(BookMarkID,x,y) then begin
|
|
Result:=Editors[i];
|
|
exit;
|
|
end;
|
|
end;
|
|
Result:=nil;
|
|
end;
|
|
|
|
function TSourceNotebook.FindPageWithEditor(
|
|
ASourceEditor: TSourceEditor):integer;
|
|
var i:integer;
|
|
begin
|
|
if Notebook=nil then begin
|
|
Result:=-1;
|
|
end else begin
|
|
Result:=Notebook.PageCount-1;
|
|
while (Result>=0) do begin
|
|
with Notebook.Page[Result] do
|
|
for I := 0 to ControlCount-1 do
|
|
if Controls[I]=ASourceEditor.EditorComponent then exit;
|
|
dec(Result);
|
|
end;
|
|
end;
|
|
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;
|
|
|
|
function TSourceNotebook.FindSourceEditorWithFilename(const Filename: string
|
|
): TSourceEditor;
|
|
var i: integer;
|
|
begin
|
|
for i:=0 to EditorCount-1 do begin
|
|
Result:=Editors[i];
|
|
if CompareFilenames(Result.Filename,Filename)=0 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 := Notebook.TabIndexAtClientPos(point(X,Y));
|
|
if TabIndex>=0 then
|
|
CloseClicked(Notebook.Page[TabIndex]);
|
|
end;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.NotebookPageChanged(Sender: TObject);
|
|
var TempEditor:TSourceEditor;
|
|
Begin
|
|
TempEditor:=GetActiveSE;
|
|
|
|
//writeln('TSourceNotebook.NotebookPageChanged ',Notebook.Pageindex,' ',TempEditor <> nil,' fAutoFocusLock=',fAutoFocusLock);
|
|
if TempEditor <> nil then
|
|
begin
|
|
if fAutoFocusLock=0 then begin
|
|
{$IFDEF VerboseFocus}
|
|
writeln('TSourceNotebook.NotebookPageChanged BEFORE SetFocus ',
|
|
TempEditor.EditorComponent.Name,' ',
|
|
NoteBook.Pages[FindPageWithEditor(TempEditor)]);
|
|
{$ENDIF}
|
|
TempEditor.FocusEditor;
|
|
{$IFDEF VerboseFocus}
|
|
writeln('TSourceNotebook.NotebookPageChanged AFTER SetFocus ',
|
|
TempEditor.EditorComponent.Name,' ',
|
|
NoteBook.Pages[FindPageWithEditor(TempEditor)]);
|
|
{$ENDIF}
|
|
end;
|
|
UpdateStatusBar;
|
|
UpdateActiveEditColors(TempEditor.EditorComponent);
|
|
if (DebugBoss.State in [dsPause, dsRun]) and
|
|
not TempEditor.HasExecutionMarks and
|
|
(TempEditor.FileName <> '') then
|
|
TempEditor.FillExecutionMarks;
|
|
if Assigned(FOnEditorVisibleChanged) then
|
|
FOnEditorVisibleChanged(sender);
|
|
end;
|
|
|
|
CheckCurrentCodeBufferChanged;
|
|
UpdateFPDocEditor;
|
|
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(FOnProcessUserCommand) then begin
|
|
Handled:=false;
|
|
FOnProcessUserCommand(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;
|
|
|
|
ecOpenFileAtCursor:
|
|
OpenAtCursorClicked(self);
|
|
|
|
ecGotoEditor1..ecGotoEditor9,ecGotoEditor0:
|
|
if Notebook.PageCount>Command-ecGotoEditor1 then
|
|
Notebook.PageIndex:=Command-ecGotoEditor1;
|
|
|
|
ecToggleFormUnit:
|
|
ToggleFormUnitClicked(Self);
|
|
|
|
ecToggleObjectInsp:
|
|
ToggleObjectInspClicked(Self);
|
|
|
|
ecSetFreeBookmark:
|
|
BookMarkSetFree;
|
|
|
|
ecJumpBack:
|
|
HistoryJump(Self,jhaBack);
|
|
|
|
ecJumpForward:
|
|
HistoryJump(Self,jhaForward);
|
|
|
|
ecAddJumpPoint:
|
|
AddJumpPointClicked(Self);
|
|
|
|
ecViewJumpHistory:
|
|
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(FOnUserCommandProcessed) then begin
|
|
Handled:=false;
|
|
FOnUserCommandProcessed(Self,Command,Handled);
|
|
if Handled then exit;
|
|
end;
|
|
|
|
Handled:=(Command=ecClose);
|
|
|
|
if Handled then Command:=ecNone;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.ReloadEditorOptions;
|
|
var
|
|
I: integer;
|
|
h: TLazSyntaxHighlighter;
|
|
Begin
|
|
// this reloads the colors for the highlighter and other editor settings.
|
|
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
|
|
if Highlighters[h]<>nil then
|
|
EditorOpts.GetHighlighterSettings(Highlighters[h]);
|
|
ReloadHighlighters;
|
|
for i := 0 to EditorCount-1 do
|
|
Editors[i].RefreshEditorSettings;
|
|
|
|
// 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;
|
|
|
|
EditorOpts.KeyMap.AssignTo(FKeyStrokes,TSourceEditorWindowInterface);
|
|
if NoteBook<>nil then begin
|
|
if EditorOpts.ShowTabCloseButtons then
|
|
NoteBook.Options:=NoteBook.Options+[nboShowCloseButtons]
|
|
else
|
|
NoteBook.Options:=NoteBook.Options-[nboShowCloseButtons];
|
|
end;
|
|
|
|
SourceCompletionTimer.Interval:=EditorOpts.AutoDelayInMSec;
|
|
|
|
Exclude(States,snWarnedFont);
|
|
CheckFont;
|
|
end;
|
|
|
|
procedure TSourceNotebook.ReloadHighlighters;
|
|
var
|
|
i: Integer;
|
|
ASrcEdit: TSourceEditor;
|
|
AnUnitInfo: TUnitInfo;
|
|
begin
|
|
for i := 0 to EditorCount-1 do begin
|
|
ASrcEdit:=Editors[i];
|
|
AnUnitInfo:=Project1.UnitWithEditorIndex(i);
|
|
if AnUnitInfo<>nil then
|
|
ASrcEdit.SyntaxHighlighterType:=AnUnitInfo.SyntaxHighlighter;
|
|
end;
|
|
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);
|
|
i := FKeyStrokes.FindKeycode(Key, Shift);
|
|
if i>=0 then begin
|
|
Command:=FKeyStrokes[i].Command;
|
|
case Command of
|
|
|
|
ecGotoMarker0..ecGotoMarker9:
|
|
begin
|
|
BookMarkGoto(Command - ecGotoMarker0);
|
|
Key:=0;
|
|
end;
|
|
|
|
ecSetMarker0..ecSetMarker9:
|
|
begin
|
|
BookMarkSet(Command - ecSetMarker0);
|
|
Key:=0;
|
|
end;
|
|
|
|
ecToggleMarker0..ecToggleMarker9:
|
|
begin
|
|
BookMarkSet(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
|
|
// restart hint timer
|
|
//DebugLn(['TSourceNotebook.EditorMouseMove ']);
|
|
FHintTimer.Enabled := False;
|
|
FHintTimer.Enabled := (EditorOpts.AutoToolTipSymbTools or
|
|
EditorOpts.AutoToolTipExprEval)
|
|
and Visible;
|
|
end;
|
|
|
|
procedure TSourceNotebook.EditorMouseWheel(Sender: TObject; Shift: TShiftState;
|
|
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
|
|
begin
|
|
// restart hint timer
|
|
//DebugLn(['TSourceNotebook.EditorMouseWheel ']);
|
|
HideHint;
|
|
FHintTimer.Enabled := (EditorOpts.AutoToolTipSymbTools or
|
|
EditorOpts.AutoToolTipExprEval) and Visible;
|
|
//handled:=true; //The scrooling 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;
|
|
|
|
procedure TSourceNotebook.EditorMouseLink(
|
|
Sender: TObject; X, Y: Integer; var AllowMouseLink: Boolean);
|
|
begin
|
|
if Assigned(OnMouseLink) then
|
|
OnMouseLink(Sender, X, Y, AllowMouseLink);
|
|
end;
|
|
|
|
Procedure TSourceNotebook.HintTimer(sender: TObject);
|
|
var
|
|
MousePos: TPoint;
|
|
AControl: TControl;
|
|
begin
|
|
//DebugLn(['TSourceNotebook.HintTimer ']);
|
|
FHintTimer.Enabled := False;
|
|
MousePos := Mouse.CursorPos;
|
|
AControl:=FindLCLControl(MousePos);
|
|
if (AControl=nil) or (GetParentForm(AControl)<>Self) 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.EditorClickLink(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftstate; X, Y: Integer);
|
|
begin
|
|
// click link = Find Declaration
|
|
if Assigned(FOnClickLink) then
|
|
FOnClickLink(Sender,Button,Shift,X,Y);
|
|
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
|
|
AMark:=TSourceMark(LineMarks[i]);
|
|
if not (AMark is TSourceMark) 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(OnShowHintForSource) then
|
|
OnShowHintForSource(ASrcEdit,EditPos,EditCaret);
|
|
end;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.AddWatchAtCursor(Sender: TObject);
|
|
begin
|
|
if Assigned(OnAddWatchAtCursor) then
|
|
OnAddWatchAtCursor(Self);
|
|
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);
|
|
CurEdit.LogicalCaretXY:=CurEdit.BlockEnd;
|
|
|
|
// 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;
|
|
|
|
function TSourceNotebook.MacroFuncCol(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if (SrcEdit<>nil) then
|
|
Result:=IntToStr(SrcEdit.EditorComponent.CaretX)
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceNotebook.MacroFuncRow(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if (SrcEdit<>nil) then
|
|
Result:=IntToStr(SrcEdit.EditorComponent.CaretY)
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceNotebook.MacroFuncEdFile(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if (SrcEdit<>nil) then
|
|
Result:=SrcEdit.FileName
|
|
else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceNotebook.MacroFuncCurToken(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
var
|
|
SrcEdit: TSourceEditor;
|
|
begin
|
|
SrcEdit:=GetActiveSE;
|
|
if (SrcEdit<>nil) then begin
|
|
with SrcEdit.EditorComponent do
|
|
Result:=GetWordAtRowCol(LogicalCaretXY)
|
|
end else
|
|
Result:='';
|
|
end;
|
|
|
|
function TSourceNotebook.MacroFuncPrompt(const s: string; const Data: PtrInt;
|
|
var Abort: boolean): string;
|
|
begin
|
|
Result:=s;
|
|
Abort:=(ShowMacroPromptDialog(Result)<>mrOk);
|
|
end;
|
|
|
|
procedure TSourceNotebook.UpdateActiveEditColors(AEditor: TSynEdit);
|
|
var
|
|
s, sm : TFontStyles;
|
|
begin
|
|
if AEditor=nil then exit;
|
|
|
|
EditorOpts.SetMarkupColors(AEditor.Highlighter, AEditor);
|
|
|
|
FActiveEditDefaultFGColor:=AEditor.Font.Color;
|
|
FActiveEditDefaultBGColor:=AEditor.Color;
|
|
EditorOpts.GetLineColors(AEditor.Highlighter, ahaTextBlock, {TODO: MFR use AEditor.SelectedColor which includes styles / or have a copy}
|
|
FActiveEditSelectedFGColor, FActiveEditSelectedBGColor, s ,sm);
|
|
|
|
FActiveEditKeyFGColor:=FActiveEditDefaultFGColor;
|
|
FActiveEditKeyBGColor:=FActiveEditDefaultBGColor;
|
|
FActiveEditSymbolFGColor:=FActiveEditDefaultFGColor;
|
|
FActiveEditSymbolBGColor:=FActiveEditDefaultBGColor;
|
|
|
|
if AEditor.Highlighter<>nil
|
|
then begin
|
|
with AEditor.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;
|
|
if KeywordAttribute<>nil
|
|
then begin
|
|
if KeywordAttribute.ForeGround<>clNone then
|
|
FActiveEditKeyFGColor:=KeywordAttribute.ForeGround;
|
|
if KeywordAttribute.BackGround<>clNone then
|
|
FActiveEditKeyBGColor:=KeywordAttribute.BackGround;
|
|
end;
|
|
if SymbolAttribute<>nil
|
|
then begin
|
|
if SymbolAttribute.ForeGround<>clNone then
|
|
FActiveEditSymbolFGColor:=SymbolAttribute.ForeGround;
|
|
if SymbolAttribute.BackGround<>clNone then
|
|
FActiveEditSymbolBGColor:=SymbolAttribute.BackGround;
|
|
end;
|
|
end;
|
|
end;
|
|
AEditor.UseIncrementalColor:= snIncrementalFind in States;
|
|
end;
|
|
|
|
Procedure TSourceNotebook.GetSynEditPreviewSettings(APreviewEditor: TObject);
|
|
var ASynEdit: TSynEdit;
|
|
begin
|
|
if not (APreviewEditor is TSynEdit) then exit;
|
|
ASynEdit:=TSynEdit(APreviewEditor);
|
|
EditorOpts.GetSynEditPreviewSettings(ASynEdit);
|
|
ASynEdit.Highlighter:=Highlighters[lshFreePascal];
|
|
end;
|
|
|
|
function TSourceNotebook.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 TSourceNotebook.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;
|
|
|
|
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
|
|
if Assigned(FOnCloseClicked) then
|
|
FOnCloseClicked(Sender,GetKeyState(VK_CONTROL)<0);
|
|
end;
|
|
|
|
{ TSynEditPlugin1 }
|
|
|
|
constructor TSynEditPlugin1.Create(AOwner: TCustomSynEdit);
|
|
Begin
|
|
inherited Create(AOwner);
|
|
end;
|
|
|
|
procedure TSynEditPlugin1.AfterPaint(ACanvas: TCanvas; AClip: TRect; FirstLine,
|
|
LastLine: integer);
|
|
begin
|
|
//don't do anything
|
|
end;
|
|
|
|
procedure TSynEditPlugin1.LinesDeleted(FirstLine, Count: integer);
|
|
begin
|
|
if Assigned(OnLinesDeleted) then
|
|
OnLinesDeleted(self,Firstline,Count);
|
|
end;
|
|
|
|
procedure TSynEditPlugin1.LinesInserted(FirstLine, Count: integer);
|
|
begin
|
|
if Assigned(OnLinesInserted) then
|
|
OnLinesInserted(self,Firstline,Count);
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
procedure InternalInit;
|
|
var h: TLazSyntaxHighlighter;
|
|
begin
|
|
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
|
|
Highlighters[h]:=nil;
|
|
end;
|
|
|
|
procedure InternalFinal;
|
|
var h: TLazSyntaxHighlighter;
|
|
begin
|
|
for h:=Low(TLazSyntaxHighlighter) to High(TLazSyntaxHighlighter) do
|
|
FreeThenNil(Highlighters[h]);
|
|
FreeThenNil(aWordCompletion);
|
|
end;
|
|
|
|
|
|
initialization
|
|
InternalInit;
|
|
{$I sourceeditor.lrs}
|
|
{$I ../images/bookmark.lrs}
|
|
|
|
finalization
|
|
InternalFinal;
|
|
|
|
end.
|
|
|