Editor Macros PascalScript
General
The PascalScript macro functionality is available in Lazarus 1.1 and later. To use the feature you have to install the package EditorMacroScript, which includes the PascalScript package. PascalScript is provided by REM Objects. A minimum package is provided with the Lazarus 1.1 distribution.
See also IDE_Window:_Editor_Macros
Simple actions
All simple Keyboard actions are represented as follows.
- ecLeft;
- Move Caret one to the left (in the editor that invoked the macro)
- ecChar('a');
- Inserts an 'a'
See the unit SynEditKeyCmds in pacckage SynEdit, and IDECommands in IDEIntf for a full list. Or use the Recorder to get the names of actions.
Functions
Function MessageDlg( const Msg : string; DlgType : TMsgDlgType; Buttons : TMsgDlgButtons; HelpCtx : Longint) : Integer'); Function MessageDlgPos( const Msg : string; DlgType : TMsgDlgType; Buttons : TMsgDlgButtons; HelpCtx : Longint; X, Y : Integer) : Integer'); Function MessageDlgPosHelp( const Msg : string; DlgType : TMsgDlgType; Buttons : TMsgDlgButtons; HelpCtx : Longint; X, Y : Integer; const HelpFileName : string) : Integer'); Procedure ShowMessage( const Msg : string); Procedure ShowMessagePos( const Msg : string; X, Y : Integer)'); Function InputBox( const ACaption, APrompt, ADefault : string) : string'); Function InputQuery( const ACaption, APrompt : string; var Value : string) : Boolean');
Objects provided
Scripts can refer to the invoking SynEdit via the identifier "Caller".
Caller: TSynEdit
The following methods and properties are available:
- Caret
property CaretX: Integer; property CaretY: Integer; property CaretXY: TPoint; property LogicalCaretXY: TPoint; property LogicalCaretX: TPoint; procedure MoveCaretIgnoreEOL(const NewCaret: TPoint); procedure MoveLogicalCaretIgnoreEOL(const NewLogCaret: TPoint);
- Selection
property BlockBegin: TPoint; property BlockEnd: TPoint; property SelAvail: Boolean; // read only property SelText: string; property SelectionMode: TSynSelectionMode; procedure ClearSelection; procedure SelectAll; procedure SelectToBrace; procedure SelectWord; procedure SelectLine(WithLeadSpaces: Boolean); procedure SelectParagraph;
- Search/Replace
function SearchReplace(const ASearch, AReplace: string; AOptions: TSynSearchOptions): integer; function SearchReplaceEx(const ASearch, AReplace: string; AOptions: TSynSearchOptions; AStart: TPoint): integer;
TSynSearchOptions = set of ( ssoMatchCase, ssoWholeWord, ssoBackwards, ssoEntireScope, ssoSelectedOnly, // Default is From Caret to End-of-text (or begin-of-text if backward) ssoReplace, ssoReplaceAll, // Otherwise the function does a search only ssoPrompt, // Show the prompt before replacing ssoSearchInReplacement, // continue search-replace in replacement (with ssoReplaceAll) // replace recursive ssoRegExpr, ssoRegExprMultiLine, ssoFindContinue // Assume the current selection is the last match, and start search behind selection // (before if ssoBackward) // Default is to start at caret (Only SearchReplace / SearchReplaceEx has start/end param) );
Returns the number of replacements done. When Searching, returns 1 if found, 0 if not found. If found the match will be selected (use BlockBegin/End).
if Caller.SearchReplace('FindMe', ' ', []) > 0 then begin // Selection is set to the first occurrence of FindMe (searched from position of caret) end;
- Text
property Lines[Index: Integer]: string; // read only property LineAtCaret: string; // read only procedure InsertTextAtCaret(aText: String; aCaretMode : TSynCaretAdjustMode); property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String // Logical Points procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint; const AValue: String; aFlags: TSynEditTextFlags = []; aCaretMode: TSynCaretAdjustMode; aMarksMode: TSynMarksAdjustMode; aSelectionMode: TSynSelectionMode );
- Clipboard
procedure CopyToClipboard; procedure CutToClipboard; procedure PasteFromClipboard; property CanPaste: Boolean // read only
- Logical / Physical
function LogicalToPhysicalPos(const p: TPoint): TPoint; function LogicalToPhysicalCol(const Line: String; Index, LogicalPos : integer): integer; function PhysicalToLogicalPos(const p: TPoint): TPoint; function PhysicalToLogicalCol(const Line: string; Index, PhysicalPos: integer): integer; function PhysicalLineLength(Line: String; Index: integer): integer;
ClipBoard: TClipBoard
property AsText: String;
Example
The below macro will align selected code. It will look fo a specific token in each selected line, and align each occurrence of it.
Select the 3 lines. If the selection starts right before the ":" then the ":" will be detected. A prompt will ask you to confirm the ":". Then all ":" will be aligned. (If you use a word for alignment, please note, that it will be matched regardless of word boundaries)
text: string;
a: Integer;
foo: boolean
The macro:
function IsIdent(c: Char): Boolean;
begin
Result := ((c >= 'a') and (c <= 'z')) or
((c >= 'A') and (c <= 'Z')) or
((c >= '0') and (c <= '9')) or
(c = '_');
end;
var
p1, p2: TPoint;
s1, s2: string;
i, j, k: Integer;
begin
if not Caller.SelAvail then exit;
p1 := Caller.BlockBegin;
p2 := Caller.BlockEnd;
if (p1.y > p2.y) or ((p1.y = p2.y) and (p1.x > p2.x)) then begin
p1 := Caller.BlockEnd;
p2 := Caller.BlockBegin;
end;
s1 := Caller.Lines[p1.y - 1];
s2 := '';
i := p1.x
while (i <= length(s1)) and (s1[i] in [#9, ' ']) do inc(i);
j := i;
if i <= length(s1) then begin
if IsIdent(s1[i]) then // pascal identifier
while (i <= length(s1)) and IsIdent(s1[i]) do inc(i)
else
while (i <= length(s1)) and not(IsIdent(s1[i]) or (s1[i] in [#9, ' '])) do inc(i);
end;
if i > j then s2 := copy(s1, j, i-j);
if not InputQuery( 'Align', 'Token', s2) then exit;
j := 0;
for i := p1.y to p2.y do begin
s1 := Caller.Lines[i - 1];
k := pos(s2, s1);
if (k > j) then j := k;
end;
if j < 1 then exit;
for i := p1.y to p2.y do begin
s1 := Caller.Lines[i - 1];
k := pos(s2, s1);
if (k > 0) and (k < j) then begin
Caller.LogicalCaretXY := Point(k, i);
while k < j do begin
ecChar(' ');
inc(k);
end;
end;
end;
end.