SynEdit: Added code-template mode: Edit params in cells

git-svn-id: trunk@20732 -
This commit is contained in:
martin 2009-06-24 19:33:05 +00:00
parent 7f6096c9bf
commit d6b3aff8c9
19 changed files with 2430 additions and 396 deletions

2
.gitattributes vendored
View File

@ -1629,6 +1629,8 @@ components/synedit/synhighlightervb.pas svneol=native#text/plain
components/synedit/synhighlighterxml.pas svneol=native#text/pascal
components/synedit/synmacrorecorder.pas svneol=native#text/pascal
components/synedit/synmemo.pas svneol=native#text/pascal
components/synedit/synpluginsynceditbase.pp svneol=native#text/pascal
components/synedit/synplugintemplateedit.pp svneol=native#text/pascal
components/synedit/synpropertyeditobjectlist.lfm svneol=native#text/plain
components/synedit/synpropertyeditobjectlist.lrs svneol=native#text/pascal
components/synedit/synpropertyeditobjectlist.pas svneol=native#text/plain

View File

@ -19,6 +19,7 @@ uses
SynEdit, SynEditHighlighter, SynCompletion, SynEditAutoComplete,
SynEditLazDsgn, SynRegExpr, SynEditRegexSearch, SynEditExport,
SynExportHTML, SynMemo, SynMacroRecorder, SynEditPlugins,
SynPluginSyncEditBase, SynPluginTemplateEdit,
SynHighlighterAny,
SynhighlighterCPP,
SynHighlighterCss,

View File

@ -160,6 +160,11 @@ type
var AChar: {$IFDEF SYN_LAZARUS}TUTF8Char{$ELSE}Char{$ENDIF};
Data: pointer; HandlerData: pointer) of object;
THookedKeyTranslationEvent = procedure(Sender: TObject;
Code: word; SState: TShiftState; var Data: pointer; var IsStartOfCombo: boolean;
var Handled: boolean; var Command: TSynEditorCommand;
FinishComboOnly: Boolean; var ComboKeyStrokes: TSynEditKeyStrokes) of object;
TPaintEvent = procedure(Sender: TObject; ACanvas: TCanvas) of object;
TProcessCommandEvent = procedure(Sender: TObject;
@ -280,15 +285,24 @@ type
{ TSynEditPlugin }
TSynEditPlugin = class(TSynEditFriend)
private
procedure SetSynedit(const AValue: TCustomSynEdit);
function GetSynEdit: TCustomSynEdit;
protected
procedure SetEditor(const AValue: TCustomSynEdit); virtual;
function GetEditor: TCustomSynEdit;
function OwnedByEditor: Boolean; virtual; // if true, this will be destroyed by synedit
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Editor: TCustomSynEdit read GetSynEdit write SetSynedit;
property Editor: TCustomSynEdit read GetEditor write SetEditor;
end;
{ TSynHookedKeyTranslationList }
TSynHookedKeyTranslationList = Class(TMethodList)
public
procedure CallHookedKeyTranslationHandlers(Sender: TObject;
Code: word; SState: TShiftState; var Data: pointer;
var IsStartOfCombo: boolean; var Handled: boolean;
var Command: TSynEditorCommand; var ComboKeyStrokes: TSynEditKeyStrokes);
end;
TSynMouseLinkEvent = procedure (
@ -377,7 +391,6 @@ type
{$ENDIF}
fUndoList: TSynEditUndoList;
fRedoList: TSynEditUndoList;
FIsUndoing: Boolean;
fBookMarks: array[0..9] of TSynEditMark;
fMouseDownX: integer;
fMouseDownY: integer;
@ -391,7 +404,7 @@ type
fInsertCaret: TSynEditCaretType;
FCaretOffset: TPoint;
FCaretWidth: Integer; // Width of caret in chars (for Overwrite caret)
fKeyStrokes: TSynEditKeyStrokes;
FKeyStrokes, FLastKeyStrokes: TSynEditKeyStrokes;
FMouseActions, FMouseSelActions: TSynEditMouseActions;
fModified: Boolean;
fMarkList: TSynEditMarkList;
@ -408,10 +421,9 @@ type
fOptions2: TSynEditorOptions2;
{$ENDIF}
fStatusChanges: TSynStatusChanges;
fLastKey: word;
fLastShiftState: TShiftState;
fTSearch: TSynEditSearch;
fHookedCommandHandlers: TList;
FHookedKeyTranslationList: TSynHookedKeyTranslationList;
fPlugins: TList;
fScrollTimer: TTimer;
fScrollDeltaX, fScrollDeltaY: Integer;
@ -438,6 +450,7 @@ type
procedure AquirePrimarySelection;
function GetDefSelectionMode: TSynSelectionMode;
function GetFoldState: String;
function GetPlugin(Index: Integer): TSynEditPlugin;
function GetUndoList: TSynEditUndoList;
function GetDividerDrawLevel: Integer; deprecated;
procedure SetDefSelectionMode(const AValue: TSynSelectionMode);
@ -606,6 +619,8 @@ type
function GetViewedTextBuffer: TSynEditStrings; override;
function GetTextBuffer: TSynEditStrings; override;
procedure SetLines(Value: TStrings); override;
function GetMarkupMgr: TObject; override;
function GetCaretObj: TSynEditCaret; override;
procedure ScanFromAfterLock;
procedure DecPaintLock;
procedure DestroyWnd; override;
@ -662,10 +677,6 @@ type
procedure SetSelTextPrimitive(PasteMode: TSynSelectionMode; Value: PChar;
AddToUndoList: Boolean = false);
procedure ShowCaret;
// If the translations requires Data, memory will be allocated for it via a
// GetMem call. The client must call FreeMem on Data if it is not NIL.
function TranslateKeyCode(Code: word; Shift: TShiftState; var Data: pointer
{$IFDEF SYN_LAZARUS};out IsStartOfCombo: boolean{$ENDIF}): TSynEditorCommand;
procedure UndoItem(Item: TSynEditUndoItem);
property UndoList: TSynEditUndoList read GetUndoList;
protected
@ -800,6 +811,9 @@ type
procedure Redo;
procedure RegisterCommandHandler(AHandlerProc: THookedCommandEvent;
AHandlerData: pointer);
procedure UnregisterCommandHandler(AHandlerProc: THookedCommandEvent);
procedure RegisterKeyTranslationHandler(AHandlerProc: THookedKeyTranslationEvent);
procedure UnRegisterKeyTranslationHandler(AHandlerProc: THookedKeyTranslationEvent);
function RowColumnToPixels(
{$IFDEF SYN_LAZARUS}const {$ENDIF}RowCol: TPoint): TPoint;
function SearchReplace(const ASearch, AReplace: string;
@ -825,7 +839,6 @@ type
function HasDebugMark(ALine: Integer): Boolean;
procedure SetDebugMarks(AFirst, ALast: Integer);
procedure ClearDebugMarks;
procedure UnregisterCommandHandler(AHandlerProc: THookedCommandEvent);
{$IFDEF SYN_COMPILER_4_UP}
function UpdateAction(TheAction: TBasicAction): boolean; override;
{$ENDIF}
@ -879,9 +892,10 @@ type
property OnKeyPress;
property OnProcessCommand: TProcessCommandEvent
read FOnProcessCommand write FOnProcessCommand;
function PluginCount: Integer;
property Plugin[Index: Integer]: TSynEditPlugin read GetPlugin;
function MarkupCount: Integer;
property Markup[Index: integer]: TSynEditMarkup
read GetMarkup;
property Markup[Index: integer]: TSynEditMarkup read GetMarkup;
property MarkupByClass[Index: TSynEditMarkupClass]: TSynEditMarkup
read GetMarkupByClass;
property TrimSpaceType: TSynEditStringTrimmingType
@ -1322,6 +1336,11 @@ begin
Result := FFoldedLinesView.GetFoldDescription(0, 0, -1, -1, True);
end;
function TCustomSynEdit.GetPlugin(Index: Integer): TSynEditPlugin;
begin
Result := TSynEditPlugin(fPlugins[Index]);
end;
function TCustomSynEdit.GetDividerDrawLevel: Integer;
begin
Result := fHighlighter.DrawDividerLevel;
@ -1513,6 +1532,7 @@ begin
fRedoList := TSynEditUndoList.Create;
fRedoList.OnAddedUndo := {$IFDEF FPC}@{$ENDIF}UndoRedoAdded;
FIsUndoing := False;
FIsRedoing := False;
TSynEditStringList(FLines).UndoList := fUndoList;
TSynEditStringList(FLines).RedoList := fRedoList;
@ -1553,6 +1573,8 @@ begin
Height := 150;
Width := 200;
Cursor := crIBeam;
fPlugins := TList.Create;
FHookedKeyTranslationList := TSynHookedKeyTranslationList.Create;
{$IFDEF SYN_LAZARUS}
// needed before setting color
fMarkupHighCaret := TSynEditMarkupHighlightAllCaret.Create(self);
@ -1608,7 +1630,8 @@ begin
{$ENDIF}
fInsertCaret := ctVerticalLine;
fOverwriteCaret := ctBlock;
fKeystrokes := TSynEditKeyStrokes.Create(Self);
FKeystrokes := TSynEditKeyStrokes.Create(Self);
FLastKeyStrokes := nil;
if assigned(Owner) and not (csLoading in Owner.ComponentState) then begin
SetDefaultKeystrokes;
end;
@ -1734,24 +1757,26 @@ var
i: integer;
begin
SurrenderPrimarySelection;
Highlighter := nil;
{$IFDEF SYN_LAZARUS}
if HandleAllocated then LCLIntf.DestroyCaret(Handle);
Beautifier:=nil;
{$ENDIF}
RemoveHooksFromHighlighter;
FHighlighter := nil;
// free listeners while other fields are still valid
if Assigned(fHookedCommandHandlers) then begin
for i := 0 to fHookedCommandHandlers.Count - 1 do
THookedCommandHandlerEntry(fHookedCommandHandlers[i]).Free;
fHookedCommandHandlers.Free;
FreeAndNil(fHookedCommandHandlers);
end;
if fPlugins <> nil then begin
for i := fPlugins.Count - 1 downto 0 do
if TSynEditPlugin(fPlugins[i]).OwnedByEditor then
TSynEditPlugin(fPlugins[i]).Free;
fPlugins.Free;
TSynEditPlugin(fPlugins[i]).Free
else
TSynEditPlugin(fPlugins[i]).Editor := nil;
FreeAndNil(fPlugins);
end;
FreeAndNil(FHookedKeyTranslationList);
{$IFNDEF SYN_LAZARUS}
fScrollTimer.Free;
fTSearch.Free;
@ -2160,37 +2185,46 @@ var
Data: pointer;
C: char;
Cmd: TSynEditorCommand;
{$IFDEF SYN_LAZARUS}
IsStartOfCombo: boolean;
{$ENDIF}
IsStartOfCombo, Handled: boolean;
begin
FInMouseClickEvent := False;
{$IFDEF VerboseKeys}
DebugLn('[TCustomSynEdit.KeyDown] ',dbgs(Key),' ',dbgs(Shift));
{$ENDIF}
inherited;
{$IFDEF SYN_LAZARUS}
if assigned(fMarkupCtrlMouse) then
fMarkupCtrlMouse.UpdateCtrlState;
{$ENDIF}
Data := nil;
C := #0;
try
Cmd := TranslateKeyCode(Key, Shift, Data {$IFDEF SYN_LAZARUS},IsStartOfCombo{$ENDIF});
IsStartOfCombo := False;
Handled := False;
// If the translations requires Data, memory will be allocated for it via a
// GetMem call. The client must call FreeMem on Data if it is not NIL.
if FLastKeyStrokes = FKeyStrokes then begin
Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo, True);
Handled := Cmd <> ecNone;
end;
// Hooked
if not Handled then
FHookedKeyTranslationList.CallHookedKeyTranslationHandlers(self,
Key, Shift, Data, IsStartOfCombo, Handled, Cmd, FLastKeyStrokes);
if not Handled then begin
Cmd := KeyStrokes.FindKeycodeEx(Key, Shift, Data, IsStartOfCombo);
if IsStartOfCombo then
FLastKeyStrokes := FKeyStrokes;
end;
if Cmd <> ecNone then begin
{$IFDEF SYN_LAZARUS}
LastMouseCaret:=Point(-1,-1);
{$ENDIF}
//DebugLn(['[TCustomSynEdit.KeyDown] key translated ',cmd]);
Key := 0; // eat it.
Include(fStateFlags, sfIgnoreNextChar);
CommandProcessor(Cmd, C, Data);
{$IFDEF SYN_LAZARUS}
end else if IsStartOfCombo then begin
// this key could be the start of a two-key-combo shortcut
Key := 0; // eat it.
Include(fStateFlags, sfIgnoreNextChar);
{$ENDIF}
end else
Exclude(fStateFlags, sfIgnoreNextChar);
finally
@ -3626,6 +3660,11 @@ begin
inherited Invalidate;
end;
function TCustomSynEdit.PluginCount: Integer;
begin
Result := fPlugins.Count;
end;
function TCustomSynEdit.MarkupCount: Integer;
begin
Result := FMarkupManager.Count;
@ -3840,6 +3879,16 @@ begin
FStrings.Assign(Value);
end;
function TCustomSynEdit.GetMarkupMgr: TObject;
begin
Result := fMarkupManager;
end;
function TCustomSynEdit.GetCaretObj: TSynEditCaret;
begin
Result := FCaret;
end;
procedure TCustomSynEdit.SetLineText(Value: string);
begin
FCaret.LineText := Value;
@ -4020,16 +4069,10 @@ begin
end;
procedure TCustomSynEdit.MoveCaretIgnoreEOL(const NewCaret: TPoint);
var
NewX: LongInt;
begin
CaretXY:=NewCaret;
NewX:=Max(1,Min(fMaxLeftChar,NewCaret.X));
if CaretX<>NewX then begin
IncPaintLock;
CaretX:=NewX;
DecPaintLock;
end;
FCaret.IncForcePastEOL;
FCaret.LineCharPos := NewCaret;
FCaret.DecForcePastEOL;
end;
procedure TCustomSynEdit.MoveLogicalCaretIgnoreEOL(const NewLogCaret: TPoint);
@ -4770,6 +4813,7 @@ begin
Group := fRedoList.PopItem;
if Group <> nil then begin;
IncPaintLock;
FIsRedoing := True;
Item := Group.Pop;
if Item <> nil then begin
BeginUndoBlock;
@ -4784,6 +4828,7 @@ begin
EndUndoBlock;
end;
end;
FIsRedoing := False;
Group.Free;
if fRedoList.IsTopMarkedAsUnmodified then
fUndoList.MarkTopAsUnmodified;
@ -5518,46 +5563,6 @@ begin
FKeystrokes.ResetDefaults;
end;
// If the translations requires Data, memory will be allocated for it via a
// GetMem call. The client must call FreeMem on Data if it is not NIL.
function TCustomSynEdit.TranslateKeyCode(Code: word; Shift: TShiftState;
var Data: pointer
{$IFDEF SYN_LAZARUS};out IsStartOfCombo: boolean{$ENDIF}
): TSynEditorCommand;
var
i: integer;
{$IFNDEF SYN_COMPILER_3_UP}
const
VK_ACCEPT = $30;
{$ENDIF}
begin
i := KeyStrokes.FindKeycode2(fLastKey, fLastShiftState, Code, Shift);
if i >= 0 then begin
Result := KeyStrokes[i].Command
end else begin
i := Keystrokes.FindKeycode(Code, Shift);
if i >= 0 then begin
Result := Keystrokes[i].Command
end else
Result := ecNone;
end;
if (Result = ecNone) and (Code >= VK_ACCEPT) and (Code <= VK_SCROLL) then
begin
fLastKey := Code;
fLastShiftState := Shift;
{$IFDEF SYN_LAZARUS}
IsStartOfCombo:=KeyStrokes.FindKeycode2Start(Code,Shift)>=0;
{$ENDIF}
end else begin
fLastKey := 0;
fLastShiftState := [];
{$IFDEF SYN_LAZARUS}
IsStartOfCombo:=false;
{$ENDIF}
end;
end;
procedure TCustomSynEdit.CommandProcessor(Command: TSynEditorCommand;
AChar: {$IFDEF SYN_LAZARUS}TUTF8Char{$ELSE}Char{$ENDIF};
Data: pointer);
@ -5932,7 +5937,6 @@ begin
ecInsertLine,
ecLineBreak:
if not ReadOnly then begin
// current line is empty (len = 0)
if FTheLinesView.Count = 0 then
FTheLinesView.Add('');
if SelAvail then begin
@ -8511,6 +8515,16 @@ begin
{$ENDIF}
end;
procedure TCustomSynEdit.RegisterKeyTranslationHandler(AHandlerProc: THookedKeyTranslationEvent);
begin
FHookedKeyTranslationList.Add(TMEthod(AHandlerProc));
end;
procedure TCustomSynEdit.UnRegisterKeyTranslationHandler(AHandlerProc: THookedKeyTranslationEvent);
begin
FHookedKeyTranslationList.Remove(TMEthod(AHandlerProc));
end;
procedure TCustomSynEdit.NotifyHookedCommandHandlers(AfterProcessing: boolean;
var Command: TSynEditorCommand;
var AChar: {$IFDEF SYN_LAZARUS}TUTF8Char{$ELSE}Char{$ENDIF}; Data: pointer);
@ -8726,27 +8740,24 @@ begin
inherited Destroy;
end;
procedure TSynEditPlugin.SetSynedit(const AValue: TCustomSynEdit);
procedure TSynEditPlugin.SetEditor(const AValue: TCustomSynEdit);
begin
if AValue = FriendEdit then exit;
if (FriendEdit <> nil) and (Editor.fPlugins <> nil) then
Editor.fPlugins.Remove(FriendEdit);
FriendEdit := AValue;
if FriendEdit <> nil then begin
if Editor.fPlugins = nil then
Editor.fPlugins := TList.Create;
if FriendEdit <> nil then
Editor.fPlugins.Add(Self);
end;
end;
function TSynEditPlugin.GetSynEdit: TCustomSynEdit;
function TSynEditPlugin.GetEditor: TCustomSynEdit;
begin
Result := FriendEdit as TSynEdit;
end;
function TSynEditPlugin.OwnedByEditor: Boolean;
begin
Result := False;
Result := Owner = nil;
end;
procedure Register;
@ -8775,6 +8786,27 @@ begin
RegisterPropertyToSkip(TSynEdit, 'CFDividerDrawLevel', '', '');
end;
{ TSynHookedKeyTranslationList }
procedure TSynHookedKeyTranslationList.CallHookedKeyTranslationHandlers(Sender: TObject;
Code: word; SState: TShiftState; var Data: pointer; var IsStartOfCombo: boolean;
var Handled: boolean; var Command: TSynEditorCommand;
var ComboKeyStrokes: TSynEditKeyStrokes);
var
i: Integer;
begin
// Finish Combo ?
for i := 0 to Count - 1 do
THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
IsStartOfCombo, Handled, Command, True, ComboKeyStrokes);
if Handled then
exit;
// New Stroke ?
for i := 0 to Count - 1 do
THookedKeyTranslationEvent(Items[i])(Sender, Code, SState, Data,
IsStartOfCombo, Handled, Command, False, ComboKeyStrokes);
end;
initialization
SynDefaultBeautifier := TSynBeautifier.Create(Application);
Register;

View File

@ -248,11 +248,22 @@ const
ecUserFirst = 1001; // Start of user-defined commands
ecPluginFirst = 20000;
// Plugins don't know of other plugins, so they need to map the codes
// In order to save Keymaps, Plugins all start at ecPluginFirst (overlapping)
// If ask by SynEdit they add an offset
// Return the next offset
function AllocatePluginKeyRange(Count: Integer): integer;
type
ESynKeyError = class(Exception);
TSynEditorCommand = type word;
{ TSynEditKeyStroke }
TSynEditKeyStroke = class(TCollectionItem)
private
FKey: word; // Virtual keycode, i.e. VK_xxx
@ -260,9 +271,10 @@ type
FKey2: word;
FShift2: TShiftState;
FCommand: TSynEditorCommand;
function GetCommand: TSynEditorCommand;
function GetShortCut: TShortCut;
function GetShortCut2: TShortCut;
procedure SetCommand(const Value: TSynEditorCommand);
procedure SetCommand(Value: TSynEditorCommand);
procedure SetKey(const Value: word);
procedure SetKey2(const Value: word);
procedure SetShift(const Value: TShiftState);
@ -285,7 +297,7 @@ type
property Shift: TShiftState read FShift write SetShift;
property Shift2: TShiftState read FShift2 write SetShift2;
published
property Command: TSynEditorCommand read FCommand write SetCommand;
property Command: TSynEditorCommand read GetCommand write SetCommand;
property ShortCut: TShortCut read GetShortCut write SetShortCut
default 0; //mh 2000-11-07
property ShortCut2: TShortCut read GetShortCut2 write SetShortCut2
@ -297,29 +309,41 @@ type
TSynEditKeyStrokes = class(TCollection)
private
FOwner: TPersistent;
fLastKey: word;
fLastShiftState: TShiftState;
FPluginOffset: Integer;
FUsePluginOffset: Boolean;
function GetItem(Index: Integer): TSynEditKeyStroke;
procedure SetItem(Index: Integer; Value: TSynEditKeyStroke);
protected
{$IFDEF SYN_COMPILER_3_UP}
function GetOwner: TPersistent; override;
{$ENDIF}
function FindKeycode2(Code1: word; SS1: TShiftState;
Code2: word; SS2: TShiftState): integer;
function FindKeycode2Start(Code: word; SS: TShiftState): integer;
public
constructor Create(AOwner: TPersistent);
function Add: TSynEditKeyStroke;
procedure Assign(Source: TPersistent); override;
function FindCommand(Cmd: TSynEditorCommand): integer;
function FindKeycode(Code: word; SS: TShiftState): integer;
function FindKeycode2(Code1: word; SS1: TShiftState;
Code2: word; SS2: TShiftState): integer;
function FindKeycode2Start(Code: word; SS: TShiftState): integer;
function FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer;
out IsStartOfCombo: boolean;
FinishComboOnly: Boolean = False): TSynEditorCommand;
procedure ResetKeyCombo;
function FindShortcut(SC: TShortcut): integer;
function FindShortcut2(SC, SC2: TShortcut): integer;
procedure LoadFromStream(AStream: TStream); //ac 2000-07-05
procedure ResetDefaults;
procedure ResetDefaults; virtual;
procedure SaveToStream(AStream: TStream); //ac 2000-07-05
public
property Items[Index: Integer]: TSynEditKeyStroke read GetItem
write SetItem; default;
property PluginOffset: Integer read FPluginOffset write FPluginOffset;
// only switch on while needed.
// So streaming will always see the constant, unmodified values
property UsePluginOffset: Boolean read FUsePluginOffset write FUsePluginOffset;
end;
// These are mainly for the TSynEditorCommand property editor, but could be
@ -616,6 +640,14 @@ begin
{$ENDIF}
end;
function AllocatePluginKeyRange(Count: Integer): integer;
const
CurOffset : integer = 0;
begin
Result := CurOffset;
inc(CurOffset, Count);
end;
function EditorCommandToDescrString(Cmd: TSynEditorCommand): string;
begin
// Doesn't do anything yet.
@ -660,8 +692,21 @@ begin
Result := Menus.ShortCut(Key, Shift);
end;
procedure TSynEditKeyStroke.SetCommand(const Value: TSynEditorCommand);
function TSynEditKeyStroke.GetCommand: TSynEditorCommand;
begin
Result:= FCommand;
if TSynEditKeyStrokes(Collection).UsePluginOffset and (Result >= ecPluginFirst) then
Inc(Result, TSynEditKeyStrokes(Collection).PluginOffset);
end;
procedure TSynEditKeyStroke.SetCommand(Value: TSynEditorCommand);
begin
if TSynEditKeyStrokes(Collection).UsePluginOffset and (Value >= ecPluginFirst) then
begin
Dec(Value, TSynEditKeyStrokes(Collection).PluginOffset);
if (Value < ecPluginFirst) then
Value := ecNone;
end;
if Value <> FCommand then
FCommand := Value;
end;
@ -792,6 +837,10 @@ constructor TSynEditKeyStrokes.Create(AOwner: TPersistent);
begin
inherited Create(TSynEditKeyStroke);
FOwner := AOwner;
fLastKey := 0;
fLastShiftState := [];
FPluginOffset := 0;
FUsePluginOffset := False;
end;
function TSynEditKeyStrokes.FindCommand(Cmd: TSynEditorCommand): integer;
@ -820,6 +869,42 @@ begin
end;
end;
function TSynEditKeyStrokes.FindKeycodeEx(Code: word; SS: TShiftState; var Data: pointer; out
IsStartOfCombo: boolean; FinishComboOnly: Boolean = False): TSynEditorCommand;
var
i: integer;
{$IFNDEF SYN_COMPILER_3_UP}
const
VK_ACCEPT = $30;
{$ENDIF}
begin
i := FindKeycode2(fLastKey, fLastShiftState, Code, SS);
if (i < 0) and not FinishComboOnly then
i := FindKeycode(Code, SS);
if i >= 0 then
Result := Items[i].Command
else
Result := ecNone;
if (Result = ecNone) and (Code >= VK_ACCEPT) and (Code <= VK_SCROLL) and
(FindKeycode2Start(Code, SS) >= 0) and not FinishComboOnly then
begin
fLastKey := Code;
fLastShiftState := SS;
IsStartOfCombo := True;
end else begin
fLastKey := 0;
fLastShiftState := [];
IsStartOfCombo := False;
end;
end;
procedure TSynEditKeyStrokes.ResetKeyCombo;
begin
fLastKey := 0;
fLastShiftState := [];
end;
function TSynEditKeyStrokes.FindKeycode2(Code1: word; SS1: TShiftState;
Code2: word; SS2: TShiftState): integer;
var
@ -878,7 +963,7 @@ end;
function TSynEditKeyStrokes.GetItem(Index: Integer): TSynEditKeyStroke;
begin
Result := TSynEditKeyStroke(inherited GetItem(Index));
Result := TSynEditKeyStroke(inherited GetItem(Index));
end;
{$IFDEF SYN_COMPILER_3_UP}
@ -1028,7 +1113,7 @@ end;
procedure TSynEditKeyStrokes.SetItem(Index: Integer; Value: TSynEditKeyStroke);
begin
inherited SetItem(Index, Value);
inherited SetItem(Index, Value);
end;
{begin} //ac 2000-07-05

View File

@ -60,14 +60,16 @@ type
procedure SetFrameColor(const AValue : TColor);
procedure SetStyle(const AValue : TFontStyles);
procedure MarkupChanged(AMarkup: TObject);
protected
procedure MarkupChanged(AMarkup: TObject);
procedure SetInvalidateLinesMethod(const AValue : TInvalidateLines); virtual;
procedure SetLines(const AValue : TSynEditStrings); virtual;
procedure SetTopLine(const AValue : Integer); virtual;
procedure SetLinesInWindow(const AValue : Integer); virtual;
procedure SetCaret(const AValue : TSynEditCaret); virtual;
procedure DoEnabledChanged(Sender: TObject); virtual;
procedure DoCaretChanged(Sender: TObject); virtual;
procedure DoTopLineChanged(OldTopLine : Integer); virtual;
procedure DoLinesInWindoChanged(OldLinesInWindow : Integer); virtual;
@ -79,6 +81,7 @@ type
function RowToScreenRow(aRow : Integer) : Integer;
function LogicalToPhysicalPos(const p: TPoint): TPoint;
function Highlighter: TSynCustomHighlighter;
function OwnedByMgr: Boolean; virtual; // overwrite, do prevent destruction by mgr
property SynEdit : TSynEditBase read fSynEdit;
public
@ -127,6 +130,7 @@ type
destructor Destroy; override;
Procedure AddMarkUp(aMarkUp : TSynEditMarkup);
Procedure RemoveMarkUp(aMarkUp : TSynEditMarkup);
function Count: Integer;
property Markup[Index: integer]: TSynEditMarkup
read GetMarkup;
@ -186,6 +190,7 @@ procedure TSynEditMarkup.SetEnabled(const AValue: Boolean);
begin
if AValue = FEnabled then exit;
FEnabled := AValue;
DoEnabledChanged(self);
end;
procedure TSynEditMarkup.SetFGColor(const AValue : TColor);
@ -236,6 +241,10 @@ begin
FCaret.AddChangeHandler(@DoCaretChanged);
end;
procedure TSynEditMarkup.DoEnabledChanged(Sender: TObject);
begin
end;
procedure TSynEditMarkup.SetTopLine(const AValue : Integer);
var
OldValue : Integer;
@ -302,6 +311,11 @@ begin
Result := TSynEdit(SynEdit).Highlighter;
end;
function TSynEditMarkup.OwnedByMgr: Boolean;
begin
Result := True;
end;
constructor TSynEditMarkup.Create(ASynEdit : TSynEditBase);
begin
inherited Create();
@ -359,7 +373,8 @@ var
i : integer;
begin
for i := 0 to fMarkUpList.Count-1 do
TSynEditMarkup(fMarkUpList[i]).destroy;
if TSynEditMarkup(fMarkUpList[i]).OwnedByMgr then
TSynEditMarkup(fMarkUpList[i]).destroy;
FreeAndNil(fMarkUpList);
inherited Destroy;
end;
@ -374,6 +389,15 @@ begin
aMarkUp.InvalidateLinesMethod := FInvalidateLinesMethod;
end;
procedure TSynEditMarkupManager.RemoveMarkUp(aMarkUp: TSynEditMarkup);
var
i: LongInt;
begin
i := fMarkUpList.IndexOf(aMarkUp);
if i >= 0 then
fMarkUpList.Delete(i);
end;
function TSynEditMarkupManager.Count: Integer;
begin
Result := fMarkUpList.Count;

View File

@ -48,7 +48,7 @@ uses
Windows,
{$ENDIF}
Classes, Graphics, Controls, SysUtils, Clipbrd,
SynEditMiscProcs, SynEditTypes, SynEditTextBase;
SynEditMiscProcs, SynEditTypes, SynEditTextBase, SynEditPointClasses;
type
@ -59,28 +59,38 @@ type
TSynEditBase = class(TCustomControl)
protected
FIsUndoing, FIsRedoing: Boolean;
function GetMarkupMgr: TObject; virtual; abstract;
function GetLines: TStrings; virtual; abstract;
function GetCaretObj: TSynEditCaret; virtual; abstract;
procedure SetLines(Value: TStrings); virtual; abstract;
function GetViewedTextBuffer: TSynEditStrings; virtual; abstract;
function GetTextBuffer: TSynEditStrings; virtual; abstract;
property MarkupMgr: TObject read GetMarkupMgr;
property ViewedTextBuffer: TSynEditStrings read GetViewedTextBuffer; // As viewed internally (with uncommited spaces / TODO: expanded tabs, folds). This may change, use with care
property TextBuffer: TSynEditStrings read GetTextBuffer; // No uncommited (trailing/trimmable) spaces
public
property Lines: TStrings read GetLines write SetLines;
end;
{ TSynEditPluginBase }
{ TSynEditFriend }
TSynEditFriend = class(TComponent)
private
FFriendEdit: TSynEditBase;
function GetCaretObj: TSynEditCaret;
function GetIsRedoing: Boolean;
function GetIsUndoing: Boolean;
function GetMarkupMgr: TObject;
function GetViewedTextBuffer: TSynEditStrings;
protected
property FriendEdit: TSynEditBase read FFriendEdit write FFriendEdit;
property ViewedTextBuffer: TSynEditStrings read GetViewedTextBuffer; // As viewed internally (with uncommited spaces / TODO: expanded tabs, folds). This may change, use with care
property CaretObj: TSynEditCaret read GetCaretObj;
property MarkupMgr: TObject read GetMarkupMgr;
property IsUndoing: Boolean read GetIsUndoing;
property IsRedoing: Boolean read GetIsRedoing;
end;
@ -340,6 +350,26 @@ begin
Result := FFriendEdit.ViewedTextBuffer;
end;
function TSynEditFriend.GetMarkupMgr: TObject;
begin
Result := FFriendEdit.MarkupMgr;
end;
function TSynEditFriend.GetIsRedoing: Boolean;
begin
Result := FFriendEdit.FIsRedoing;
end;
function TSynEditFriend.GetCaretObj: TSynEditCaret;
begin
Result := FFriendEdit.GetCaretObj;
end;
function TSynEditFriend.GetIsUndoing: Boolean;
begin
Result := FFriendEdit.FIsUndoing;
end;
{ TSynSelectedColor }
constructor TSynSelectedColor.Create;

View File

@ -201,6 +201,7 @@ type
procedure RemoveEditHandler(AHandler: TStringListLineEditEvent); override;
function GetPhysicalCharWidths(const Line: String; Index: Integer): TPhysicalCharWidths; override;
property NextLines: TSynEditStrings read fSynStrings;
public
// LogX, LogY are 1-based
procedure EditInsert(LogX, LogY: Integer; AText: String); override;

View File

@ -708,8 +708,9 @@ end;
procedure TSynEditStringTrimmingList.EditInsert(LogX, LogY: Integer; AText: String);
var
t: String;
Len, LenNS: Integer;
Len, LenNS, SaveLogX: Integer;
IsSpaces: Boolean;
SaveText: String;
begin
if (not fEnabled) then begin
fSynStrings.EditInsert(LogX, LogY, AText);
@ -717,6 +718,8 @@ begin
end;
IgnoreSendNotification(senrEditAction, True);
SaveText := AText;
SaveLogX := LogX;
t := Strings[LogY - 1]; // include trailing
if LogX - 1 > Length(t) then begin
AText := StringOfChar(' ', LogX - 1 - Length(t)) + AText;
@ -761,20 +764,21 @@ begin
// update spaces
UpdateLineText(LogY);
IgnoreSendNotification(senrEditAction, False);
SendNotification(senrEditAction, self, LogY, 0, LogX, length(AText), AText);
SendNotification(senrEditAction, self, LogY, 0, SaveLogX, length(SaveText), SaveText);
end;
Function TSynEditStringTrimmingList.EditDelete(LogX, LogY, ByteLen
: Integer): String;
Function TSynEditStringTrimmingList.EditDelete(LogX, LogY, ByteLen: Integer): String;
var
t: String;
Len: Integer;
SaveByteLen: LongInt;
begin
if (not fEnabled) then begin
fSynStrings.EditDelete(LogX, LogY, ByteLen);
exit;
end;
SaveByteLen := ByteLen;
Result := '';
t := fSynStrings[LogY - 1];
Len := length(t);
@ -801,7 +805,7 @@ begin
EditMoveToTrim(LogY, length(t) - LastNoneSpacePos(t));
IgnoreSendNotification(senrEditAction, False);
SendNotification(senrEditAction, self, LogY, 0, LogX, -ByteLen, '');
SendNotification(senrEditAction, self, LogY, 0, LogX, -SaveByteLen, '');
end;
procedure TSynEditStringTrimmingList.EditLineBreak(LogX, LogY: Integer);

View File

@ -0,0 +1,641 @@
{-------------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
Alternatively, the contents of this file may be used under the terms of the
GNU General Public License Version 2 or later (the "GPL"), in which case
the provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms
of the GPL and not to allow others to use your version of this file
under the MPL, indicate your decision by deleting the provisions above and
replace them with the notice and other provisions required by the GPL.
If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
-------------------------------------------------------------------------------}
unit SynPluginSyncEditBase;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, math, Graphics,
SynEditMiscClasses, SynEdit, SynEditMarkup, SynEditMiscProcs, SynEditTextBase;
type
{ TSynPluginSyncEditCell }
TSynPluginSyncEditCell = class
private
FLogStart, FLogEnd: TPoint;
FGroup: Integer;
public
procedure Assign(Src: TSynPluginSyncEditCell); reintroduce;
property LogStart: TPoint read FLogStart write FLogStart;
property LogEnd: TPoint read FLogEnd write FLogEnd;
property Group: Integer read FGroup write FGroup;
end;
TSynPluginSyncEditCellChangedEvent = procedure(aIndex: Integer;
aOldVal, aNewVal: TSynPluginSyncEditCell) of object;
{ TSynPluginSyncEditList }
TSynPluginSyncEditList = class
private
FCells: Array of TSynPluginSyncEditCell;
FOnCellChange: TSynPluginSyncEditCellChangedEvent;
function GetCell(aIndex: Integer): TSynPluginSyncEditCell;
function GetGroupCell(aGroup, aIndex: Integer): TSynPluginSyncEditCell;
procedure SetCell(aIndex: Integer; const AValue: TSynPluginSyncEditCell);
protected
property OnCellChange: TSynPluginSyncEditCellChangedEvent // For Markup
read FOnCellChange write FOnCellChange;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function Add(aCell: TSynPluginSyncEditCell): Integer;
function AddNew: TSynPluginSyncEditCell; virtual;
procedure Delete(aIndex: Integer);
function IndexOf(aCell: TSynPluginSyncEditCell): Integer;
function IndexOf(aX, aY: Integer; IncludeLast: Boolean = False): Integer;
function Count: Integer;
function GroupCount(aGroup: Integer): Integer;
property Cell[aIndex: Integer]: TSynPluginSyncEditCell
read GetCell write SetCell; default;
property GroupCell[aGroup, aIndex: Integer]: TSynPluginSyncEditCell
read GetGroupCell;
end;
{ TSynPluginSyncEditMarkup }
TSynPluginSyncEditMarkup = class(TSynEditMarkup)
private
FCells: TSynPluginSyncEditList;
FCurrentCell: Integer;
fMarkupInfoCurrent: TSynSelectedColor;
fMarkupInfoSync: TSynSelectedColor;
procedure SetCells(const AValue: TSynPluginSyncEditList);
procedure CellChanged(aIndex: Integer; aOldVal, aNewVal: TSynPluginSyncEditCell);
procedure SetCurrentCell(const AValue: Integer);
protected
function OwnedByMgr: Boolean; override;
procedure DoEnabledChanged(Sender: TObject); override;
property CurrentCell: Integer read FCurrentCell write SetCurrentCell;
property Cells: TSynPluginSyncEditList read FCells write SetCells;
public
constructor Create(ASynEdit: TSynEditBase);
destructor Destroy; override;
function GetMarkupAttributeAtRowCol(const aRow, aCol: Integer): TSynSelectedColor; override;
function GetNextMarkupColAfterRowCol(const aRow, aCol: Integer): Integer; override;
property MarkupInfoCurrent: TSynSelectedColor read fMarkupInfoCurrent;
property MarkupInfoSync: TSynSelectedColor read fMarkupInfoSync;
end;
{ TSynPluginSyncEditBase }
TSynPluginSyncEditBase = class(TSynEditPlugin)
private
FActive: Boolean;
FCells: TSynPluginSyncEditList;
FCurrentCell: Integer;
FEnabled: Boolean;
FMarkup: TSynPluginSyncEditMarkup;
FEditing: Boolean;
function GetActive: Boolean;
procedure SetActive(const AValue: Boolean);
procedure SetCurrentCell(const AValue: Integer);
procedure SetEnabled(const AValue: Boolean);
protected
procedure SetEditor(const AValue: TCustomSynEdit); override;
procedure DoLinesEdited(Sender: TSynEditStrings; aLinePos, aBytePos, aCount,
aLineBrkCnt: Integer; aText: String);
procedure DoBeforeEdit(aX, aY: Integer); virtual;
procedure DoAfterEdit(aX, aY: Integer); virtual;
procedure DoOnActivate; virtual;
procedure DoOnDeactivate; virtual;
property CurrentCell: Integer read FCurrentCell write SetCurrentCell;
property Cells: TSynPluginSyncEditList read FCells;
property Markup: TSynPluginSyncEditMarkup read FMarkup;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Clear;
property Enabled: Boolean read FEnabled write SetEnabled;
property Active: Boolean read GetActive write SetActive;
end;
implementation
function CellsAreEqual(c1, c2: TSynPluginSyncEditCell): boolean;
begin
Result := (CompareCarets(c1.LogStart, c2.LogStart) = 0) and
(CompareCarets(c1.LogEnd, c2.LogEnd) = 0) and
(c1.Group = c2.Group);
end;
{ TSynPluginSyncEditList }
constructor TSynPluginSyncEditList.Create;
begin
inherited;
Clear;
end;
destructor TSynPluginSyncEditList.Destroy;
begin
Clear;
inherited Destroy;
end;
procedure TSynPluginSyncEditList.Clear;
var
i: Integer;
begin
for i := 0 to length(FCells) - 1 do begin
if assigned(FOnCellChange) then
FOnCellChange(i, FCells[i], nil);
FCells[i].Free;
end;
SetLength(FCells, 0);
end;
function TSynPluginSyncEditList.GetCell(aIndex: Integer): TSynPluginSyncEditCell;
begin
Result := FCells[aIndex];
end;
function TSynPluginSyncEditList.GetGroupCell(aGroup,
aIndex: Integer): TSynPluginSyncEditCell;
var
i: Integer;
begin
i := 0;
while i < length(FCells) do begin
if FCells[i].Group = aGroup then begin
dec(aIndex);
if aIndex < 0 then exit(FCells[i]);
end;
inc(i);
end;
Result := nil;
end;
procedure TSynPluginSyncEditList.SetCell(aIndex: Integer;
const AValue: TSynPluginSyncEditCell);
var
OldVal: TSynPluginSyncEditCell;
begin
OldVal := FCells[aIndex];
if CellsAreEqual(OldVal, AValue) then exit;
FCells[aIndex] := AValue;
if assigned(FOnCellChange) then
FOnCellChange(aIndex, OldVal, AValue);
end;
function TSynPluginSyncEditList.Add(aCell: TSynPluginSyncEditCell): Integer;
var
i: Integer;
begin
i := length(FCells);
SetLength(FCells, i + 1);
FCells[i] := aCell;
Result := i;
if assigned(FOnCellChange) then
FOnCellChange(i, nil, FCells[i]);
end;
function TSynPluginSyncEditList.AddNew: TSynPluginSyncEditCell;
begin
Result := TSynPluginSyncEditCell.Create;
Add(Result);
end;
procedure TSynPluginSyncEditList.Delete(aIndex: Integer);
var
i: Integer;
begin
FCells[aIndex].Free;
i := length(FCells) - 1;
if aIndex < i then
System.Move(FCells[aIndex+1], FCells[aIndex], (i-aIndex) * SizeOf(TSynPluginSyncEditCell));
SetLength(FCells, i);
if assigned(FOnCellChange) then
FOnCellChange(aIndex, FCells[i], nil);
end;
function TSynPluginSyncEditList.IndexOf(aCell: TSynPluginSyncEditCell): Integer;
var
i: Integer;
begin
i := 0;
while i < length(FCells) do
if CellsAreEqual(FCells[i], aCell) then exit(i);
Result := -1;
end;
function TSynPluginSyncEditList.IndexOf(aX, aY: Integer; IncludeLast: Boolean): Integer;
var
a, i: Integer;
begin
if IncludeLast then
a := 1
else
a := 0;;
for i := 0 to Count -1 do begin
if ( (FCells[i].LogStart.Y < aY) or
((FCells[i].LogStart.Y = aY) and (FCells[i].LogStart.X <= aX)) ) and
( (FCells[i].LogEnd.Y > aY) or
((FCells[i].LogEnd.Y = aY) and (FCells[i].LogEnd.X + a > aX)) )
then
exit(i);
end;
Result := -1;
end;
function TSynPluginSyncEditList.Count: Integer;
begin
Result := length(FCells);
end;
function TSynPluginSyncEditList.GroupCount(aGroup: Integer): Integer;
var
i: Integer;
begin
i := 0;
Result := 0;
while i < length(FCells) do
if FCells[i].Group = aGroup then
inc(Result);
end;
{ TSynPluginSyncEditMarkup }
procedure TSynPluginSyncEditMarkup.SetCells(const AValue: TSynPluginSyncEditList);
begin
if FCells = AValue then exit;
if FCells <> nil then
FCells.OnCellChange := nil;
FCells := AValue;
if FCells <> nil then
FCells.OnCellChange := @CellChanged;
end;
procedure TSynPluginSyncEditMarkup.CellChanged(aIndex: Integer; aOldVal,
aNewVal: TSynPluginSyncEditCell);
begin
if aOldVal <> nil then
InvalidateSynLines(aOldVal.LogStart.Y, aOldVal.LogEnd.Y);
if aNewVal <> nil then
InvalidateSynLines(aNewVal.LogStart.Y, aNewVal.LogEnd.Y);
end;
procedure TSynPluginSyncEditMarkup.SetCurrentCell(const AValue: Integer);
var
i, j: Integer;
begin
if FCurrentCell = AValue then exit;
if (FCurrentCell >= 0) and (FCurrentCell < Cells.Count) then begin
j := Cells[FCurrentCell].Group;
for i := 0 to Cells.Count -1 do
if Cells[i].Group = j then
InvalidateSynLines(Cells[i].LogStart.Y, Cells[i].LogEnd.Y);
end;
FCurrentCell := AValue;
if (FCurrentCell >= 0) and (FCurrentCell < Cells.Count) then begin
j := Cells[FCurrentCell].Group;
for i := 0 to Cells.Count -1 do
if Cells[i].Group = j then
InvalidateSynLines(Cells[i].LogStart.Y, Cells[i].LogEnd.Y);
end;
end;
function TSynPluginSyncEditMarkup.OwnedByMgr: Boolean;
begin
Result := False;
end;
procedure TSynPluginSyncEditMarkup.DoEnabledChanged(Sender: TObject);
var
i: Integer;
begin
for i := 0 to FCells.Count - 1 do
CellChanged(i, Cells[i], Cells[i]);
end;
constructor TSynPluginSyncEditMarkup.Create(ASynEdit: TSynEditBase);
begin
FCells := nil;
inherited;
fMarkupInfoCurrent := TSynSelectedColor.Create;
fMarkupInfoCurrent.OnChange := @MarkupChanged;
fMarkupInfoSync := TSynSelectedColor.Create;
fMarkupInfoSync.OnChange := @MarkupChanged;
MarkupInfo.FrameColor := clMaroon;
MarkupInfo.Background := clNone;
MarkupInfo.Foreground := clNone;
MarkupInfoCurrent.FrameColor := clAqua;
MarkupInfoCurrent.Background := clNone;
MarkupInfoCurrent.Foreground := clNone;
MarkupInfoSync.FrameColor := clFuchsia;
MarkupInfoSync.Background := clNone;
MarkupInfoSync.Foreground := clNone;
end;
destructor TSynPluginSyncEditMarkup.Destroy;
begin
Cells := nil;
FreeAndNil(fMarkupInfoCurrent);
FreeAndNil(fMarkupInfoSync);
inherited Destroy;
end;
function TSynPluginSyncEditMarkup.GetMarkupAttributeAtRowCol(const aRow,
aCol: Integer): TSynSelectedColor;
var
i: Integer;
m : TSynSelectedColor;
begin
Result := nil;
for i := 0 to Cells.Count -1 do begin
if ( ((Cells[i].LogStart.y = aRow) and (Cells[i].LogStart.x <= aCol)) or
(Cells[i].LogStart.y < aRow) ) and
( ((Cells[i].LogEnd.y = aRow) and (Cells[i].LogEnd.x > aCol)) or
(Cells[i].LogEnd.y > aRow) ) and
(Cells[i].Group >= 0) // dont't display negative groups
then begin
if i = CurrentCell then
m := MarkupInfoCurrent
else
if (CurrentCell >= 0) and (Cells[i].Group = Cells[CurrentCell].Group) then
m := MarkupInfoSync
else
m := MarkupInfo;
m.StartX := Cells[i].LogStart.x;
if Cells[i].LogStart.y < aRow then
m.StartX := -1;
m.EndX := Cells[i].LogEnd.x - 1;
if Cells[i].LogEnd.y > aRow then
m.EndX := -1;
exit(m);
end;
end;
end;
function TSynPluginSyncEditMarkup.GetNextMarkupColAfterRowCol(const aRow,
aCol: Integer): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to Cells.Count -1 do begin
if (Cells[i].LogStart.y = aRow) and (Cells[i].LogStart.x > aCol) and
( (Cells[i].LogStart.x < Result) or (Result < 0) )
then
Result := Cells[i].LogStart.x;
if (Cells[i].LogEnd.y = aRow) and (Cells[i].LogEnd.x > aCol) and
( (Cells[i].LogEnd.x < Result) or (Result < 0) )
then
Result := Cells[i].LogEnd.x;
end
end;
{ TSynPluginSyncEditBase }
constructor TSynPluginSyncEditBase.Create(AOwner: TComponent);
begin
FCells := TSynPluginSyncEditList.Create;
CurrentCell := -1;
inherited Create(AOwner);
FEnabled := True;
Active := False;
FEditing := False;
end;
destructor TSynPluginSyncEditBase.Destroy;
begin
Editor := nil;
FreeAndNil(FMarkup);
FreeAndNil(FCells);
inherited;
end;
procedure TSynPluginSyncEditBase.Clear;
begin
FCells.Clear;
CurrentCell := -1;
Active := False;
end;
procedure TSynPluginSyncEditBase.SetEditor(const AValue: TCustomSynEdit);
begin
if AValue = Editor then exit;
Active := False;
if Editor <> nil then begin
ViewedTextBuffer.RemoveEditHandler(@DoLinesEdited);
if FMarkup <> nil then begin
TSynEditMarkupManager(MarkupMgr).RemoveMarkUp(FMarkup);
FreeAndNil(FMarkup);
end;
end;
inherited SetEditor(AValue);
if AValue <> nil then begin
FMarkup := TSynPluginSyncEditMarkup.Create(Editor);
FMarkup.Cells := FCells;
FMarkup.CurrentCell := FCurrentCell;
FMarkup.Enabled := Active;
TSynEditMarkupManager(MarkupMgr).AddMarkUp(FMarkup);
ViewedTextBuffer.AddEditHandler(@DoLinesEdited);
end;
end;
procedure TSynPluginSyncEditBase.SetCurrentCell(const AValue: Integer);
begin
if FCurrentCell = AValue then exit;
FCurrentCell := AValue;
if FMarkup <> nil then
FMarkup.CurrentCell := FCurrentCell;
end;
procedure TSynPluginSyncEditBase.SetEnabled(const AValue: Boolean);
var
IsActive: Boolean;
begin
IsActive := Active;
FEnabled := AValue;
if FMarkup <> nil then
FMarkup.Enabled := Active;
if IsActive <> Active then begin
if Active
then DoOnActivate
else DoOnDeactivate;
end;
end;
function TSynPluginSyncEditBase.GetActive: Boolean;
begin
Result := FActive and FEnabled and (Editor <> nil);
end;
procedure TSynPluginSyncEditBase.SetActive(const AValue: Boolean);
var
IsActive: Boolean;
begin
IsActive := Active;
FActive := AValue;
if FMarkup <> nil then
FMarkup.Enabled := Active;
if IsActive <> Active then begin
if Active
then DoOnActivate
else DoOnDeactivate;
end;
end;
procedure TSynPluginSyncEditBase.DoLinesEdited(Sender: TSynEditStrings;
aLinePos, aBytePos, aCount, aLineBrkCnt: Integer; aText: String);
var
Pos, Pos2: TPoint;
function AdjustPoint(aPoint: Tpoint): TPoint;
begin
Result := aPoint;
if aLineBrkCnt < 0 then begin
(* Lines Deleted *)
if aPoint.y > aLinePos then
Result.y := Max(aLinePos, Result.y + aLineBrkCnt);
if Result.y = aLinePos then
Result.x := Result.x + Pos.x - 1;
end
else
if aLineBrkCnt > 0 then begin
(* Lines Inserted *)
if aPoint.y = aLinePos then
Result.x := Result.x - Pos.x + 1;
if aPoint.y >= aLinePos then
Result.y := Result.y + aLineBrkCnt;
end
else
if aCount <> 0 then begin
(* Chars Insert/Deleted *)
if (aPoint.y = aLinePos) and (aPoint.x >= Pos.x) then
Result.x := Max(Pos.x, Result.x + aCount);
end;
end;
var
i, a: Integer;
CurCell: TSynPluginSyncEditCell;
Y2, X2: Integer;
begin
if (not Active) or (FCells.Count = 0) then exit;
Pos := ViewedTextBuffer.LogicalToPhysicalPos(Point(aBytePos, aLinePos));
Pos2 := Pos;
if Not FEditing then
DoBeforeEdit(Pos.x, Pos.y);
for i := 0 to FCells.Count - 1 do begin
CurCell := Cells[i];
a := CompareCarets(Pos, CurCell.LogStart);
if (a > 0) then
CurCell.LogStart := AdjustPoint(CurCell.LogStart);
a := CompareCarets(Pos, CurCell.LogEnd);
if (a > 0) or ((a = 0) and ((i = FCurrentCell) or FEditing)) then
CurCell.LogEnd := AdjustPoint(CurCell.LogEnd);
Cells[i] := CurCell;
end;
if (not (FEditing or IsUndoing or IsRedoing)) and
(FCurrentCell >= 0) and (FCurrentCell < Cells.Count) and
(CompareCarets(Pos, FCells[FCurrentCell].LogStart) <= 0) and
(CompareCarets(Pos, FCells[FCurrentCell].LogEnd) >= 0)
then begin
FEditing := True;
CurCell := FCells[FCurrentCell];
a := CurCell.Group;
Pos.Y := Pos.Y - CurCell.LogStart.y;
if Pos.y = 0 then
Pos.X := Pos.X - CurCell.LogStart.x;
for i := 0 to FCells.Count - 1 do
if (i <> FCurrentCell) and (FCells[i].Group = a) and
( (FCells[i].LogStart.Y + Pos.Y < FCells[i].LogEnd.Y) or
((FCells[i].LogStart.Y + Pos.Y = FCells[i].LogEnd.Y) and
(FCells[i].LogStart.X + Pos.X <= FCells[i].LogEnd.X))
)
then begin
Y2 := FCells[i].LogStart.Y + Pos.Y;
X2 := Pos.X;
if Pos.Y = 0 then
X2 := X2 + FCells[i].LogStart.X;
if aLineBrkCnt = -1 then begin
ViewedTextBuffer.EditLineJoin(Y2);
end
else if aLineBrkCnt < -1 then begin
ViewedTextBuffer.EditLinesDelete(Y2, -aLineBrkCnt);
end
else if aLineBrkCnt = 1 then begin
ViewedTextBuffer.EditLineBreak(X2, Y2);
end
else if aLineBrkCnt > 1 then begin
ViewedTextBuffer.EditLinesInsert(Y2, aLineBrkCnt);
end
else if aCount < 0 then begin
ViewedTextBuffer.EditDelete(X2, Y2, -aCount);
end
else if aCount > 0 then begin
ViewedTextBuffer.EditInsert(X2, Y2, aText);
end;
end;
FEditing := False;
if Pos.y = 0 then
pos2.x := pos.x + CurCell.LogStart.x;
Pos2.y := Pos.y + CurCell.LogStart.y;
end;
if Not FEditing then
DoAfterEdit(Pos2.x, Pos2.y);
end;
procedure TSynPluginSyncEditBase.DoBeforeEdit(aX, aY: Integer);
begin
(* Do Nothing *);
end;
procedure TSynPluginSyncEditBase.DoAfterEdit(aX, aY: Integer);
begin
(* Do Nothing *);
end;
procedure TSynPluginSyncEditBase.DoOnActivate;
begin
(* Do Nothing *);
end;
procedure TSynPluginSyncEditBase.DoOnDeactivate;
begin
(* Do Nothing *);
end;
{ TSynPluginSyncEditCell }
procedure TSynPluginSyncEditCell.Assign(Src: TSynPluginSyncEditCell);
begin
if Src = nil then exit;
FLogStart := Src.FLogStart;
FLogEnd := Src.FLogEnd;
FGroup := Src.FGroup;
end;
end.

View File

@ -0,0 +1,677 @@
{-------------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
Alternatively, the contents of this file may be used under the terms of the
GNU General Public License Version 2 or later (the "GPL"), in which case
the provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms
of the GPL and not to allow others to use your version of this file
under the MPL, indicate your decision by deleting the provisions above and
replace them with the notice and other provisions required by the GPL.
If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
-------------------------------------------------------------------------------}
unit SynPluginTemplateEdit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, math, Graphics, LCLType, SynEditMiscClasses,
SynPluginSyncEditBase, SynEditKeyCmds, SynEdit, SynEditMiscProcs,
SynEditTextTrimmer, SynEditTextBase, LCLProc;
type
{ TSynEditTemplateEditKeyStrokes }
TSynEditTemplateEditKeyStrokes = class(TSynEditKeyStrokes)
public
procedure ResetDefaults; override;
end;
{ TSynEditTemplateEditKeyStrokesOffCell }
TSynEditTemplateEditKeyStrokesOffCell = class(TSynEditKeyStrokes)
public
procedure ResetDefaults; override;
end;
{ TSynPluginTemplateEdit }
TSynPluginTemplateEdit = class(TSynPluginSyncEditBase)
private
FCellParserEnabled: Boolean;
FKeystrokes, FKeyStrokesOffCell: TSynEditKeyStrokes;
FStartPoint: TPoint;
FLastCell: Integer;
function GetMarkupInfo: TSynSelectedColor;
function GetMarkupInfoCurrent: TSynSelectedColor;
function GetMarkupInfoSync: TSynSelectedColor;
procedure SetKeystrokes(const AValue: TSynEditKeyStrokes);
procedure SetKeystrokesOffCell(const AValue: TSynEditKeyStrokes);
protected
procedure SetEditor(const AValue: TCustomSynEdit); override;
procedure DoBeforeEdit(aX, aY: Integer); override;
procedure DoOnActivate; override;
procedure DoOnDeactivate; override;
procedure UpdateCurrentCell;
procedure DoCaretChanged(Sender: TObject); virtual;
procedure TranslateKey(Sender: TObject; Code: word; SState: TShiftState;
var Data: pointer; var IsStartOfCombo: boolean; var Handled: boolean;
var Command: TSynEditorCommand; FinishComboOnly: Boolean;
var ComboKeyStrokes: TSynEditKeyStrokes);
procedure ProcessSynCommand(Sender: TObject; AfterProcessing: boolean;
var Handled: boolean; var Command: TSynEditorCommand;
var AChar: TUTF8Char; Data: pointer; HandlerData: pointer);
procedure SelectCurrentCell(Reverse: Boolean = False);
procedure PreviousCell(SetSelect: Boolean = True);
procedure NextCell(SetSelect: Boolean = True; CycleToFirst: Boolean = False);
procedure CellCaretHome;
procedure CellCaretEnd;
procedure SetFinalCaret;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
class function ConvertCommandToBase(Command: TSynEditorCommand): TSynEditorCommand;
class function ConvertBaseToCommand(Command: TSynEditorCommand): TSynEditorCommand;
class function ConvertCommandToBaseOff(Command: TSynEditorCommand): TSynEditorCommand;
class function ConvertBaseToCommandOff(Command: TSynEditorCommand): TSynEditorCommand;
procedure SetTemplate(aTmpl: String; aCaretPos: TPoint); // Replaces current selection
// Coords relativ to the template. base (1, 1)
procedure AddEditCells(aCellList: TSynPluginSyncEditList);
property CellParserEnabled: Boolean read FCellParserEnabled write FCellParserEnabled;
property Keystrokes: TSynEditKeyStrokes
read FKeystrokes write SetKeystrokes;
property KeystrokesOffCell: TSynEditKeyStrokes
read FKeystrokesOffCell write SetKeystrokesOffCell;
property MarkupInfo: TSynSelectedColor read GetMarkupInfo;
property MarkupInfoCurrent: TSynSelectedColor read GetMarkupInfoCurrent;
property MarkupInfoSync: TSynSelectedColor read GetMarkupInfoSync;
end;
const
ecSynPTmplEdNextCell = ecPluginFirst + 0;
ecSynPTmplEdNextCellSel = ecPluginFirst + 1;
ecSynPTmplEdNextCellRotate = ecPluginFirst + 2;
ecSynPTmplEdNextCellSelRotate = ecPluginFirst + 3;
ecSynPTmplEdPrevCell = ecPluginFirst + 4;
ecSynPTmplEdPrevCellSel = ecPluginFirst + 5;
ecSynPTmplEdCellHome = ecPluginFirst + 6;
ecSynPTmplEdCellEnd = ecPluginFirst + 7;
ecSynPTmplEdCellSelect = ecPluginFirst + 8;
ecSynPTmplEdFinish = ecPluginFirst + 9;
ecSynPTmplEdEscape = ecPluginFirst + 10;
ecSynPTmplEdLast = ecPluginFirst + 10;
implementation
var
KeyOffset, KeyOffsetOff: integer;
{ TSynPluginTemplateEdit }
constructor TSynPluginTemplateEdit.Create(AOwner: TComponent);
begin
FKeystrokes := TSynEditTemplateEditKeyStrokes.Create(Self);
FKeystrokes.ResetDefaults;
FKeystrokes.PluginOffset := KeyOffset;
FKeyStrokesOffCell := TSynEditTemplateEditKeyStrokesOffCell.Create(self);
FKeyStrokesOffCell.ResetDefaults;
FKeyStrokesOffCell.PluginOffset := KeyOffsetOff;
inherited Create(AOwner);
CellParserEnabled := True;
end;
destructor TSynPluginTemplateEdit.Destroy;
begin
inherited Destroy;
FreeAndNil(FKeystrokes);
FreeAndNil(FKeyStrokesOffCell);
end;
class function TSynPluginTemplateEdit.ConvertCommandToBase
(Command: TSynEditorCommand): TSynEditorCommand;
begin
if (Command >= ecPluginFirst + KeyOffset) and
(Command <= ecPluginFirst + KeyOffset + ecSynPTmplEdLast)
then
Result := Command - KeyOffset
else
Result := ecNone;
end;
class function TSynPluginTemplateEdit.ConvertBaseToCommand(Command: TSynEditorCommand): TSynEditorCommand;
begin
if (Command >= ecPluginFirst) and (Command <= ecPluginFirst + ecSynPTmplEdLast)
then
Result := Command + KeyOffset
else
Result := ecNone;
end;
class function TSynPluginTemplateEdit.ConvertCommandToBaseOff
(Command: TSynEditorCommand): TSynEditorCommand;
begin
if (Command >= ecPluginFirst + KeyOffsetOff) and
(Command <= ecPluginFirst + KeyOffsetOff + ecSynPTmplEdLast)
then
Result := Command - KeyOffsetOff
else
Result := ecNone;
end;
class function TSynPluginTemplateEdit.ConvertBaseToCommandOff(Command: TSynEditorCommand): TSynEditorCommand;
begin
if (Command >= ecPluginFirst) and (Command <= ecPluginFirst + ecSynPTmplEdLast)
then
Result := Command + KeyOffsetOff
else
Result := ecNone;
end;
procedure TSynPluginTemplateEdit.SetEditor(const AValue: TCustomSynEdit);
begin
if Editor = AValue then exit;
if Editor <> nil then begin
CaretObj.RemoveChangeHandler(@DoCaretChanged);
Editor.UnRegisterKeyTranslationHandler(@TranslateKey);
Editor.UnregisterCommandHandler(@ProcessSynCommand);
end;
inherited SetEditor(AValue);
if Editor <> nil then begin
Editor.RegisterCommandHandler(@ProcessSynCommand, nil);
Editor.RegisterKeyTranslationHandler(@TranslateKey);
CaretObj.AddChangeHandler(@DoCaretChanged);
end;
end;
procedure TSynPluginTemplateEdit.SetKeystrokes(const AValue: TSynEditKeyStrokes);
begin
if AValue = nil then
FKeystrokes.Clear
else
FKeystrokes.Assign(AValue);
end;
procedure TSynPluginTemplateEdit.SetKeystrokesOffCell(const AValue: TSynEditKeyStrokes);
begin
if AValue = nil then
FKeyStrokesOffCell.Clear
else
FKeyStrokesOffCell.Assign(AValue);
end;
function TSynPluginTemplateEdit.GetMarkupInfo: TSynSelectedColor;
begin
Result := Markup.MarkupInfo;
end;
function TSynPluginTemplateEdit.GetMarkupInfoCurrent: TSynSelectedColor;
begin
Result := Markup.MarkupInfoCurrent;
end;
function TSynPluginTemplateEdit.GetMarkupInfoSync: TSynSelectedColor;
begin
Result := Markup.MarkupInfoSync;
end;
procedure TSynPluginTemplateEdit.DoBeforeEdit(aX, aY: Integer);
begin
UpdateCurrentCell;
if CurrentCell < 0 then begin
Clear;
Active := False;
end;
end;
procedure TSynPluginTemplateEdit.DoOnActivate;
var
b: TSynEditStrings;
begin
b := ViewedTextBuffer;
while b <> nil do begin
if b is TSynEditStringTrimmingList then TSynEditStringTrimmingList(b).Lock;
if b is TSynEditStringsLinked then
b := TSynEditStringsLinked(b).NextLines
else
b := nil;;
end;
end;
procedure TSynPluginTemplateEdit.DoOnDeactivate;
var
b: TSynEditStrings;
begin
b := ViewedTextBuffer;
while b <> nil do begin
if b is TSynEditStringTrimmingList then TSynEditStringTrimmingList(b).UnLock;
if b is TSynEditStringsLinked then
b := TSynEditStringsLinked(b).NextLines
else
b := nil;;
end;
end;
procedure TSynPluginTemplateEdit.UpdateCurrentCell;
var
i: Integer;
begin
i := Cells.IndexOf(CaretObj.BytePos, CaretObj.LinePos, True);
if (i <> CurrentCell) and (CurrentCell >= 0) then
FLastCell := CurrentCell;
CurrentCell := i;
end;
procedure TSynPluginTemplateEdit.DoCaretChanged(Sender: TObject);
begin
if not Active then exit;
UpdateCurrentCell;
end;
procedure TSynPluginTemplateEdit.TranslateKey(Sender: TObject; Code: word;
SState: TShiftState; var Data: pointer; var IsStartOfCombo: boolean; var Handled: boolean;
var Command: TSynEditorCommand; FinishComboOnly: Boolean;
var ComboKeyStrokes: TSynEditKeyStrokes);
var
keys: TSynEditKeyStrokes;
begin
if (not Active) or Handled then
exit;
if CurrentCell < 0 then begin
keys := FKeyStrokesOffCell;
FKeyStrokes.ResetKeyCombo;
end
else begin
keys := FKeyStrokes;
FKeyStrokesOffCell.ResetKeyCombo;
end;
if (FinishComboOnly and (ComboKeyStrokes <> keys)) then begin
keys.ResetKeyCombo;
exit;
end;
IsStartOfCombo := False;
try
keys.UsePluginOffset := True;
Command := keys.FindKeycodeEx(Code, SState, Data, IsStartOfCombo,
FinishComboOnly);
finally
keys.UsePluginOffset := False;
end;
Handled := (Command <> ecNone) or IsStartOfCombo;
if Handled then begin
ComboKeyStrokes := keys;
end;
end;
procedure TSynPluginTemplateEdit.ProcessSynCommand(Sender: TObject; AfterProcessing: boolean;
var Handled: boolean; var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer;
HandlerData: pointer);
var
Cmd: TSynEditorCommand;
begin
if Handled or AfterProcessing or not Active then exit;
Cmd := ConvertCommandToBase(Command);
if Cmd = ecNone then
Cmd := ConvertCommandToBaseOff(Command);
Handled := True;
case Cmd of
ecSynPTmplEdNextCell: NextCell(False);
ecSynPTmplEdNextCellSel: NextCell(True);
ecSynPTmplEdNextCellRotate: NextCell(False, True);
ecSynPTmplEdNextCellSelRotate: NextCell(True, True);
ecSynPTmplEdPrevCell: PreviousCell(False);
ecSynPTmplEdPrevCellSel: PreviousCell(True);
ecSynPTmplEdCellHome: CellCaretHome;
ecSynPTmplEdCellEnd: CellCaretEnd;
ecSynPTmplEdCellSelect: SelectCurrentCell;
ecSynPTmplEdFinish: SetFinalCaret;
ecSynPTmplEdEscape:
begin
Clear;
Active := False;
end;
else
Handled := False;
end;
end;
procedure TSynPluginTemplateEdit.SelectCurrentCell(Reverse: Boolean = False);
begin
if (CurrentCell < 0) and (FLastCell >= 0) then
CurrentCell := FLastCell;
if (CurrentCell < 0) then
exit;
if Reverse then begin
CaretObj.LineBytePos := Cells[CurrentCell].LogStart;
Editor.BlockBegin := Cells[CurrentCell].LogEnd;
Editor.BlockEnd := Cells[CurrentCell].LogStart;
end else begin
CaretObj.LineBytePos := Cells[CurrentCell].LogEnd;
Editor.BlockBegin := Cells[CurrentCell].LogStart;
Editor.BlockEnd := Cells[CurrentCell].LogEnd;
end;
end;
procedure TSynPluginTemplateEdit.PreviousCell(SetSelect: Boolean = True);
var
i, j: Integer;
Pos: TPoint;
begin
Pos := CaretObj.LineBytePos;
i := Cells.IndexOf(Pos.x, Pos.y, True);
if i < 0 then begin
i := 0;
while (i < Cells.Count) and
((Cells[i].Group < 0) or (CompareCarets(Cells[i].LogEnd, Pos) >= 0))
do
inc(i);
end;
j := 0;
Repeat
dec(i);
inc(j);
if i < 0 then
i := Cells.Count - 1;
until (j > Cells.Count) or (Cells[i].Group >= 0);
CurrentCell := i;
if CurrentCell < 0 then
exit;
CaretObj.LineBytePos := Cells[CurrentCell].LogEnd;
if SetSelect then
SelectCurrentCell
else
Editor.BlockBegin := Cells[CurrentCell].LogEnd;
end;
procedure TSynPluginTemplateEdit.NextCell(SetSelect: Boolean = True;
CycleToFirst: Boolean = False);
var
Pos: TPoint;
i, j: Integer;
begin
Pos := CaretObj.LineBytePos;
i := Cells.IndexOf(Pos.x, Pos.y, True);
if i < 0 then begin
i := Cells.Count - 1;
while (i >= 0) and
((Cells[i].Group < 0) or (CompareCarets(Cells[i].LogEnd, Pos) <= 0))
do
dec(i);
end;
j := 0;
Repeat
inc(i);
inc(j);
if i >= Cells.Count then begin
if CycleToFirst then
i := 0
else begin
SetFinalCaret;
exit;
end;
end;
until (j > Cells.Count) or (Cells[i].Group >= 0);
CurrentCell := i;
if CurrentCell < 0 then
exit;
CaretObj.LineBytePos := Cells[CurrentCell].LogStart;
if SetSelect then
SelectCurrentCell(True)
else
Editor.BlockBegin := Cells[CurrentCell].LogStart;
end;
procedure TSynPluginTemplateEdit.CellCaretHome;
begin
if (CurrentCell < 0) and (FLastCell >= 0) then
CurrentCell := FLastCell;
if (CurrentCell < 0) then
exit;
CaretObj.LineBytePos := Cells[CurrentCell].LogStart;
Editor.BlockBegin := Cells[CurrentCell].LogStart;
end;
procedure TSynPluginTemplateEdit.CellCaretEnd;
begin
if (CurrentCell < 0) and (FLastCell >= 0) then
CurrentCell := FLastCell;
if (CurrentCell < 0) then
exit;
CaretObj.LineBytePos := Cells[CurrentCell].LogEnd;
Editor.BlockBegin := Cells[CurrentCell].LogEnd;
end;
procedure TSynPluginTemplateEdit.SetFinalCaret;
var
c: TSynPluginSyncEditCell;
begin
c := Cells.GroupCell[-2, 0];
Editor.BlockBegin := c.LogStart;
CaretObj.IncForcePastEOL;
CaretObj.LineBytePos := c.LogStart;
CaretObj.DecForcePastEOL;
Cells.Clear;
Active := False;
end;
procedure TSynPluginTemplateEdit.SetTemplate(aTmpl: String; aCaretPos: TPoint);
var
Temp: TStringList;
CellStart, StartPos: TPoint;
i, j, k, XOffs, Grp: Integer;
s, s2: string;
begin
Clear;
Active := False;
StartPos := Editor.BlockBegin;
FStartPoint := StartPos;
if CellParserEnabled then begin
Temp := TStringList.Create;
try
Temp.Text := aTmpl;
if (aTmpl <> '') and (aTmpl[length(aTmpl)] in [#10,#13]) then
Temp.Add('');
XOffs := StartPos.X - 1;
i := 0;
Grp := 1;
while i < Temp.Count do begin
CellStart.y := StartPos.y + i;
CellStart.x := -1;
s := Temp[i];
j := 1;
k := 1;
SetLength(s2, length(s));
while j <= length(s) do begin
case s[j] of
'{':
if (j + 1 <= Length(s)) and (s[j+1] = '{') then begin
inc(j);
s2[k] := s[j];
inc(k);
end else begin
CellStart.x := k + XOffs;
end;
'}':
if (j + 1 <= Length(s)) and (s[j+1] = '}') then begin
inc(j);
s2[k] := s[j];
inc(k);
end else
if CellStart.x > 0 then begin
with Cells.AddNew do begin
LogStart := CellStart;
LogEnd := Point(k +XOffs, CellStart.y);
Group := grp;
end;
inc(grp);
CellStart.x := -1;
end;
else
begin
s2[k] := s[j];
inc(k);
end;
end;
inc(j);
end;
SetLength(s2, k-1);
Temp[i] := s2;
inc(i);
XOffs := 0;
end;
aTmpl := Temp.Text;
// strip the trailing #13#10 that was appended by the stringlist
i := Length(aTmpl);
if (i >= 1) and (aTmpl[i] in [#10,#13]) then begin
dec(i);
if (i >= 1) and (aTmpl[i] in [#10,#13]) and (aTmpl[i] <> aTmpl[i+1]) then
dec(i);
SetLength(aTmpl, i);
end;
finally
Temp.Free;
end;
end;
Editor.SelText := aTmpl;
with Cells.AddNew do begin
Group := -2;
LogStart := aCaretPos;
LogEnd := aCaretPos;
end;
if (Cells.Count > 1) then begin
Active := True;
CurrentCell := 0;
CaretObj.LineBytePos := Cells[0].LogStart;
SelectCurrentCell;
end
else
Editor.MoveCaretIgnoreEOL(aCaretPos);
end;
procedure TSynPluginTemplateEdit.AddEditCells(aCellList: TSynPluginSyncEditList);
var
i, XOffs, YOffs: Integer;
CurCell: TSynPluginSyncEditCell;
CaretPos: TSynPluginSyncEditCell;
begin
CaretPos := nil;
if Cells.GroupCell[-2, 0] <> nil then begin
CaretPos := TSynPluginSyncEditCell.Create;
CaretPos.Assign(Cells.GroupCell[-2, 0]);
end;
Cells.Clear;
XOffs := FStartPoint.x - 1;
YOffs := FStartPoint.y - 1;
for i := 0 to aCellList.Count - 1 do begin
CurCell := aCellList[i];
with Cells.AddNew do begin;
Assign(CurCell);
if LogStart.y = 1 then
LogStart.x := LogStart.x + XOffs;
LogStart.y := LogStart.y + YOffs;
if LogEnd.y = 1 then
LogEnd.x := LogEnd.x + XOffs;
LogEnd.y := LogEnd.y + YOffs;
end;
end;
if CaretPos <> nil then
Cells.AddNew.Assign(CaretPos);
FreeAndNil(CaretPos);
if aCellList.Count > 0 then begin
Active := True;
CurrentCell := 0;
CaretObj.LineBytePos := Cells[0].LogStart;
SelectCurrentCell;
end;
end;
{ TSynEditTemplateEditKeyStrokes }
procedure TSynEditTemplateEditKeyStrokes.ResetDefaults;
procedure AddKey(const ACmd: TSynEditorCommand; const AKey: word;
const AShift: TShiftState);
begin
with Add do
begin
Key := AKey;
Shift := AShift;
Command := ACmd;
end;
end;
begin
Clear;
AddKey(ecSynPTmplEdNextCellRotate, VK_RIGHT, [ssCtrl]);
AddKey(ecSynPTmplEdNextCellSel, VK_TAB, []);
AddKey(ecSynPTmplEdPrevCell, VK_LEFT, [ssCtrl]);
AddKey(ecSynPTmplEdPrevCellSel, VK_TAB, [ssShift]);
AddKey(ecSynPTmplEdCellHome, VK_HOME, []);
AddKey(ecSynPTmplEdCellEnd, VK_END, []);
AddKey(ecSynPTmplEdCellSelect, VK_A, [ssCtrl]);
AddKey(ecSynPTmplEdFinish, VK_RETURN, []);
AddKey(ecSynPTmplEdEscape, VK_ESCAPE, []);
end;
{ TSynEditTemplateEditKeyStrokesOffCell }
procedure TSynEditTemplateEditKeyStrokesOffCell.ResetDefaults;
procedure AddKey(const ACmd: TSynEditorCommand; const AKey: word;
const AShift: TShiftState);
begin
with Add do
begin
Key := AKey;
Shift := AShift;
Command := ACmd;
end;
end;
begin
Clear;
AddKey(ecSynPTmplEdNextCellRotate, VK_RIGHT, [ssCtrl]);
AddKey(ecSynPTmplEdNextCellSel, VK_TAB, []);
AddKey(ecSynPTmplEdPrevCell, VK_LEFT, [ssCtrl]);
AddKey(ecSynPTmplEdPrevCellSel, VK_TAB, [ssShift]);
AddKey(ecSynPTmplEdFinish, VK_RETURN, []);
AddKey(ecSynPTmplEdEscape, VK_ESCAPE, []);
end;
initialization
KeyOffset := AllocatePluginKeyRange(ecSynPTmplEdLast + 1);
KeyOffsetOff := AllocatePluginKeyRange(ecSynPTmplEdLast + 1);
end.

View File

@ -32,7 +32,8 @@ interface
uses
Classes, SysUtils, LCLProc, LResources, Forms, Controls, Graphics, Dialogs,
SynEditAutoComplete, SynEdit, MacroIntf, LazIDEIntf, SrcEditorIntf;
SynEditAutoComplete, SynPluginTemplateEdit, SynPluginSyncEditBase, SynEdit,
MacroIntf, LazIDEIntf, SrcEditorIntf;
type
TCodeMacroPromptDlg = class(TForm)
@ -40,17 +41,328 @@ type
{ private declarations }
public
{ public declarations }
end;
end;
TLazSynPluginSyncEditCell = class(TSynPluginSyncEditCell)
public
CellValue: String;
end;
{ TLazSynPluginSyncEditList }
TLazSynPluginSyncEditList = class(TSynPluginSyncEditList)
private
public
function AddNew: TSynPluginSyncEditCell; override;
end;
{ TLazTemplateParser }
TLazTemplateParser = class(TIDETemplateParser)
private
FCaret: TPoint;
FEditCellList: TSynPluginSyncEditList;
FEnableMacros: Boolean;
FIndent: String;
FSrcTemplate: String;
FDestTemplate: String;
FSrcPosition: Integer;
FDestPosition: Integer;
FDestPosX: Integer;
FDestPosY: Integer;
FLevel: Integer;
FSrcEdit: TSourceEditorInterface;
protected
// nested macros, get the X pos of the outer macro
function GetSrcPosition: Integer; override;
function GetDestPosition: Integer; override;
function GetDestPosX: Integer; override;
function GetDestPosY: Integer; override;
function GetSrcTemplate: String; override;
function GetDestTemplate: String; override;
function SubstituteMacro(const MacroName, MacroParameter: string;
var MacroValue: string): boolean;
function SubstituteMacros(var Template: String): boolean;
public
constructor Create(TheTemplate: String);
destructor Destroy; override;
function SubstituteCodeMacros(SrcEdit: TSourceEditorInterface): boolean;
property EnableMacros: Boolean read FEnableMacros write FEnableMacros;
property Indent: String read FIndent write FIndent;
property DestCaret: TPoint read FCaret;
property EditCellList: TSynPluginSyncEditList read FEditCellList;
end;
function ExecuteCodeTemplate(SrcEdit: TSourceEditorInterface;
const TemplateName, TemplateValue, TemplateComment,
EndOfTokenChr: string; Attributes: TStrings;
IndentToTokenStart: boolean): boolean;
function SubstituteCodeMacros(SrcEdit: TSourceEditorInterface;
var Pattern: string): boolean;
implementation
const
MaxLevel = 10; // prevent cycling
{ TLazTemplateParser }
constructor TLazTemplateParser.Create(TheTemplate: String);
begin
inherited Create;
FEditCellList := TLazSynPluginSyncEditList.Create;
FSrcTemplate := TheTemplate;
FDestTemplate := '';
FSrcPosition := 1;
FDestPosition := 1;
FDestPosX := 1;
FDestPosY := 1;
FLevel := 0;
FCaret.y := -1;
end;
destructor TLazTemplateParser.Destroy;
begin
FEditCellList.Free;
inherited Destroy;
end;
function TLazTemplateParser.GetSrcPosition: Integer;
begin
Result := FSrcPosition;
end;
function TLazTemplateParser.GetDestPosition: Integer;
begin
Result := FDestPosition;
end;
function TLazTemplateParser.GetDestPosX: Integer;
begin
Result := FDestPosX;
end;
function TLazTemplateParser.GetDestPosY: Integer;
begin
Result := FDestPosY;
end;
function TLazTemplateParser.GetSrcTemplate: String;
begin
Result := FSrcTemplate;
end;
function TLazTemplateParser.GetDestTemplate: String;
begin
Result := FDestTemplate;
end;
function TLazTemplateParser.SubstituteMacro(const MacroName, MacroParameter: string;
var MacroValue: string): boolean;
var
Macro: TIDECodeMacro;
NewValue: String;
ErrMsg: string;
begin
Result := false;
Macro := IDECodeMacros.FindByName(MacroName);
//debugln('SubstituteMacro A ',MacroName,' ',dbgs(Macro<>nil),' ',MacroParameter);
if Macro <> nil then begin
// substitute macros in Parameter
MacroValue := MacroParameter;
if (FLevel < MaxLevel) and (not SubstituteMacros(MacroValue)) then
exit;
if Macro.Interactive then begin
// collect interactive macro
debugln('SubstitutMacros TODO interactive macros');
end else begin
// normal macro -> substitute
NewValue:='';
try
if not Macro.GetValue(MacroValue, nil, FSrcEdit, NewValue, ErrMsg, self)
then
exit;
except
exit;
end;
MacroValue:=NewValue;
end;
end else begin
// macro unknown
MacroValue:='UnknownMacro('+MacroName+')';
end;
if ErrMsg='' then ;
Result:=true;
end;
function TLazTemplateParser.SubstituteMacros(var Template: String): boolean;
procedure AppentToDest(S: String);
var
i, i2: Integer;
begin
i := 1;
i2 := 1;
while i <= length(S) do begin
case s[i] of
#10, #13:
begin
inc(i);
if (i <= length(S)) and (s[i] in [#10,#13]) and (s[i] <> s[i-1]) then
inc(i);
if (FDestTemplate <> '') and (i > i2) and
(FDestTemplate[length(FDestTemplate)] in [#10, #13])
then
FDestTemplate := FDestTemplate + FIndent;
FDestTemplate := FDestTemplate + copy(s, i2, i - i2);
i2 := i;
FDestPosX := 1 + length(FIndent);
inc(FDestPosY);
end;
else
begin
if (s[i] = '|') and (FCaret.y < 0) then begin
System.Delete(s, i, 1);
FCaret.y := FDestPosY;
FCaret.x := FDestPosX;
end
else begin
inc(i);
inc(FDestPosX);
end;
end;
end;
end;
if (FDestTemplate <> '') and (i > i2) and
(FDestTemplate[length(FDestTemplate)] in [#10, #13])
then
FDestTemplate := FDestTemplate + FIndent;
FDestTemplate := FDestTemplate + copy(s, i2, i - i2);
FDestPosition := length(FDestTemplate);
end;
var
p: LongInt;
len: Integer;
SrcCopiedPos: LongInt;
MacroStartPos: LongInt;
MacroParamStartPos: LongInt;
MacroParamEndPos: LongInt;
MacroEndPos: LongInt;
MacroName: String;
MacroParameter: String;
MacroValue: string;
Lvl: Integer;
SaveSrcPos: LongInt;
begin
// replace as many macros as possible
inc(FLevel);
p:=1;
SrcCopiedPos := 1;
len:=length(Template);
while p <= len do begin
case Template[p] of
'$':
begin
inc(p);
// could be a macro start
MacroStartPos := p - 1;
MacroEndPos := -1;
if (p <= len) and (Template[p]='$') then begin
System.Delete(Template, p, 1);
inc(FSrcPosition);
end
else begin
// find the macro end
while (p <= len) and (Template[p] in ['a'..'z','A'..'Z','0'..'9','_']) do
inc(p);
if FEnableMacros and (p <= len) and (p-MacroStartPos > 1) and
(Template[p] = '(') then
begin
inc(p);
MacroParamStartPos:=p;
Lvl:=1;
while (p<=len) and (Lvl>0) do begin
case Template[p] of
'(': inc(Lvl);
')': dec(Lvl);
end;
inc(p);
end;
if Lvl=0 then begin
// macro parameter end found
MacroParamEndPos:=p-1;
MacroEndPos:=p;
end;
end;
end;
if MacroEndPos < 0 then begin
// not a macro
p := MacroStartPos + 1;
inc(FSrcPosition);
end
else begin
// Got a Macro
if FLevel = 1 then begin
AppentToDest(copy(Template, SrcCopiedPos, MacroStartPos - SrcCopiedPos));
end;
FSrcPosition := FSrcPosition + MacroEndPos - MacroStartPos;
// read macro name
MacroName:=copy(Template,MacroStartPos+1,
MacroParamStartPos-MacroStartPos-2);
MacroParameter:=copy(Template,MacroParamStartPos,
MacroParamEndPos-MacroParamStartPos);
SaveSrcPos := FSrcPosition;
if not SubstituteMacro(MacroName,MacroParameter,MacroValue) then
exit(false);
FSrcPosition := SaveSrcPos;
//debugln('SubstituteMacros MacroName="',MacroName,'" MacroParameter="',MacroParameter,'" MacroValue="',MacroValue,'"');
Template := copy(Template, 1, MacroStartPos-1)
+ MacroValue
+ copy(Template, MacroEndPos, len);
len:=length(Template);
p:=MacroStartPos+length(MacroValue);
SrcCopiedPos := p;
// scan the result for new lines
if FLevel = 1 then
AppentToDest(MacroValue);
end;
// else it is a normal $ character
end;
else
begin
inc(p);
inc(FSrcPosition);
end;
end;
end;
if FLevel = 1 then begin
AppentToDest(copy(Template, SrcCopiedPos, p - SrcCopiedPos));
end;
dec(FLevel);
Result:=true;
end;
function TLazTemplateParser.SubstituteCodeMacros(SrcEdit: TSourceEditorInterface): boolean;
begin
FDestTemplate := '';
FDestPosition := 1;
FDestPosX := 1;
FDestPosY := 1;
FLevel := 0;
FSrcEdit := SrcEdit;
Result := SubstituteMacros(FSrcTemplate);
end;
function ExecuteCodeTemplate(SrcEdit: TSourceEditorInterface;
const TemplateName, TemplateValue, TemplateComment,
EndOfTokenChr: string; Attributes: TStrings;
@ -60,44 +372,23 @@ var
p: TPoint;
TokenStartX: LongInt;
s: string;
NewCaretPos: Boolean;
Temp: TStringList;
IndentLen: Integer;
i: Integer;
j: LongInt;
Pattern: String;
LineText: String;
Parser: TLazTemplateParser;
begin
Result:=false;
//debugln('ExecuteCodeTemplate ',dbgsName(SrcEdit),' ',dbgsName(SrcEdit.EditorControl));
AEditor:=SrcEdit.EditorControl as TCustomSynEdit;
Pattern:=TemplateValue;
if Attributes.IndexOfName(CodeTemplateEnableMacros)>=0 then begin
// macros enabled
LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);
if not SubstituteCodeMacros(SrcEdit,Pattern) then exit;
end;
Parser := TLazTemplateParser.Create(Pattern);
AEditor.BeginUpdate;
try
// get old caret position in text
p := AEditor.LogicalCaretXY;
// select token in editor
TokenStartX:=p.x;
s:=AEditor.Lines[p.y-1];
if TokenStartX>length(s) then
TokenStartX:=length(s)+1;
j:=length(TemplateName);
while (j>0)
and (AnsiCompareText(copy(TemplateName,1,j),copy(s,TokenStartX-j,j))<>0) do
dec(j);
dec(TokenStartX,j);
AEditor.BlockBegin := Point(TokenStartX, p.y);
AEditor.BlockEnd := p;
// indent the completion string if necessary, determine the caret pos
if IndentToTokenStart then begin
IndentLen := TokenStartX - 1;
end else begin
@ -112,58 +403,33 @@ begin
IndentLen:=AEditor.LogicalToPhysicalCol(s, p.y - 1, IndentLen);// consider tabs
dec(IndentLen);
end;
p := AEditor.BlockBegin;
NewCaretPos := False;
Temp := TStringList.Create;
try
Temp.Text := Pattern;
// add empty line at end if wanted
s:=Pattern;
if (s<>'') and (s[length(s)] in [#10,#13]) then
Temp.Add('');
// indent lines
if (IndentLen > 0) and (Temp.Count > 1) then
begin
s := StringOfChar(' ', IndentLen);
for i := 1 to Temp.Count - 1 do
Temp[i] := s + Temp[i];
end;
// find first '|' and use it as caret position
for i := 0 to Temp.Count - 1 do
begin
s := Temp[i];
j := Pos('|', s);
while j > 0 do
begin
Delete(s, j, 1);
Temp[i] := s;
if (not NewCaretPos) then
begin
Inc(p.y, i);
if i = 0 then
Inc(p.x, j - 1)
else
p.x := j;
NewCaretPos := TRUE;
end;
j := Pos('|', s);
//break;
end;
end;
s := Temp.Text;
// strip the trailing #13#10 that was appended by the stringlist
i := Length(s);
if (i>=1) and (s[i] in [#10,#13]) then begin
dec(i);
if (i>=1) and (s[i] in [#10,#13]) and (s[i]<>s[i+1]) then
dec(i);
SetLength(s, i);
end;
finally
Temp.Free;
Parser.EnableMacros := Attributes.IndexOfName(CodeTemplateEnableMacros)>=0;
Parser.Indent := StringOfChar(' ', IndentLen);
LazarusIDE.SaveSourceEditorChangesToCodeCache(-1);
if not Parser.SubstituteCodeMacros(SrcEdit) then exit;
s:=AEditor.Lines[p.y-1];
if TokenStartX>length(s) then
TokenStartX:=length(s)+1;
j:=length(TemplateName);
while (j>0)
and (AnsiCompareText(copy(TemplateName,1,j),copy(s,TokenStartX-j,j))<>0) do
dec(j);
dec(TokenStartX,j);
AEditor.BlockBegin := Point(TokenStartX, p.y);
AEditor.BlockEnd := p;
// New Caret
p := Parser.DestCaret ;
if p.y < 0 then
p := AEditor.CaretXY
else begin
if p.y = 1 then
p.x := p.x + TokenStartX - 1;
p.y := p.y + AEditor.BlockBegin.y - 1; // Todo: logicalToPhysical
end;
// delete double end separator (e.g. avoid creating two semicolons 'begin end;;')
if (s<>'') and (System.Pos(s[length(s)],EndOfTokenChr)>0)
and (AEditor.BlockEnd.Y>0) and (AEditor.BlockEnd.Y<=AEditor.Lines.Count)
@ -174,142 +440,35 @@ begin
if copy(LineText,AEditor.BlockEnd.X,1)=s[length(s)] then
System.Delete(s,length(s),1);
end;
// replace the selected text and position the caret
AEditor.SelText := s;
// position the caret
if NewCaretPos then
i := AEditor.PluginCount - 1;
while i >= 0 do begin
if AEditor.Plugin[i] is TSynPluginTemplateEdit then begin
TSynPluginTemplateEdit(AEditor.Plugin[i]).CellParserEnabled := False;
TSynPluginTemplateEdit(AEditor.Plugin[i]).SetTemplate(Parser.DestTemplate, p);
TSynPluginTemplateEdit(AEditor.Plugin[i]).AddEditCells(Parser.EditCellList);
break;
end;
dec(i);
end;
if i < 0 then begin
// replace the selected text and position the caret
AEditor.SelText := Parser.DestTemplate;
AEditor.MoveCaretIgnoreEOL(p);
AEditor.EnsureCursorPosVisible;
end;
finally
AEditor.EndUpdate;
Parser.Free;
end;
Result:=true;
end;
function SubstituteCodeMacros(SrcEdit: TSourceEditorInterface;
var Pattern: string): boolean;
const
MaxLevel = 10; // prevent cycling
{ TLazSynPluginSyncEditList }
function SubstituteMacros(var Pattern: string; Level: integer): boolean; forward;
function SubstituteMacro(const MacroName, MacroParameter: string;
var MacroValue: string; Level: Integer): boolean;
var
Macro: TIDECodeMacro;
NewValue: String;
ErrMsg: string;
begin
Result:=false;
Macro:=IDECodeMacros.FindByName(MacroName);
//debugln('SubstituteMacro A ',MacroName,' ',dbgs(Macro<>nil),' ',MacroParameter);
if Macro<>nil then begin
// macro found
// substitute macros in Parameter
MacroValue:=MacroParameter;
if (Level<MaxLevel) and (not SubstituteMacros(MacroValue,Level+1)) then
exit;
if Macro.Interactive then begin
// collect interactive macro
debugln('SubstituteCodeMacros TODO interactive macros');
end else begin
// normal macro -> substitute
NewValue:='';
try
if not Macro.GetValue(MacroValue,nil,SrcEdit,NewValue,ErrMsg) then
exit;
except
exit;
end;
MacroValue:=NewValue;
end;
end else begin
// macro unknown
MacroValue:='UnknownMacro('+MacroName+')';
end;
if ErrMsg='' then ;
Result:=true;
end;
function SubstituteMacros(var Pattern: string; Level: integer): boolean;
var
p: Integer;
len: Integer;
MacroStartPos: LongInt;
MacroParamStartPos: LongInt;
MacroParamEndPos: LongInt;
MacroEndPos: LongInt;
MacroName: String;
MacroParameter: String;
MacroValue: string;
begin
// replace as many macros as possible
p:=1;
len:=length(Pattern);
while p<len do begin
if Pattern[p]<>'$' then begin
inc(p);
end else begin
// could be a macro start
MacroStartPos:=p;
inc(p);
if Pattern[p+1]='$' then begin
// $$ is a simple $ character
System.Delete(Pattern,p,1);
len:=length(Pattern);
end else if Pattern[p+1] in ['a'..'z','A'..'Z'] then begin
// read macro name
while (p<len) and (Pattern[p] in ['a'..'z','A'..'Z','0'..'9','_']) do
inc(p);
if (p>len) or (p-MacroStartPos=1) or (Pattern[p]<>'(') then begin
// missing name or missing round bracket open
debugln('SubstituteMacros missing name or missing round bracket open');
end else begin
// round bracket open found
inc(p);
MacroParamStartPos:=p;
Level:=1;
while (p<=len) and (Level>0) do begin
case Pattern[p] of
'(': inc(Level);
')': dec(Level);
end;
inc(p);
end;
if Level=0 then begin
// macro parameter end found
MacroParamEndPos:=p-1;
MacroEndPos:=p;
MacroName:=copy(Pattern,MacroStartPos+1,
MacroParamStartPos-MacroStartPos-2);
MacroParameter:=copy(Pattern,MacroParamStartPos,
MacroParamEndPos-MacroParamStartPos);
if not SubstituteMacro(MacroName,MacroParameter,MacroValue,Level)
then
exit(false);
//debugln('SubstituteMacros MacroName="',MacroName,'" MacroParameter="',MacroParameter,'" MacroValue="',MacroValue,'"');
Pattern:=copy(Pattern,1,MacroStartPos-1)+MacroValue
+copy(Pattern,MacroEndPos,len);
len:=length(Pattern);
p:=MacroStartPos+length(MacroValue);
end else begin
// macro parameter end not found
debugln('SubstituteMacros macro parameter end not found');
end;
end;
end else begin
// a normal $ character
end;
end;
end;
Result:=true;
end;
function TLazSynPluginSyncEditList.AddNew: TSynPluginSyncEditCell;
begin
Result:=SubstituteMacros(Pattern,0);
Result := TLazSynPluginSyncEditCell.Create;
Add(Result);
end;
initialization

View File

@ -42,7 +42,7 @@ uses
IDECommands, TextTools, SrcEditorIntf, MenuIntf, IDEWindowIntf, LazIDEIntf,
// IDE
IDEProcs, InputHistory, LazarusIDEStrConsts, EditorOptions, CodeMacroSelect,
IDEContextHelpEdit, ButtonPanel, SynRegExpr;
IDEContextHelpEdit, ButtonPanel, SynRegExpr, CodeMacroPrompt;
type
TAutoCompleteOption = (
@ -122,7 +122,7 @@ type
SynAutoComplete: TSynEditAutoComplete;
TemplateIndex: integer;
end;
{ TLazCodeMacros }
TLazCodeMacros = class(TIDECodeMacros)
@ -618,6 +618,74 @@ begin
Result:=true;
end;
function CodeMacroEditParam(const Parameter: string;
InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface; var Value,
ErrorMsg: string; TemplateParser: TIDETemplateParser): boolean;
var
p: TLazTemplateParser;
temp: TStringList;
i, g: Integer;
s: String;
begin
p := TLazTemplateParser(TemplateParser);
Value := Parameter;
g := -1;
temp := TStringList.Create;
try
s := Parameter;
while length(s) > 0 do begin
if s[1] = '"' then begin
System.Delete(s, 1, 1);
i := pos('"', s);
end
else
i := pos(',', s);
if i < 1 then
i := length(s) + 1;
temp.add(copy(s, 1, i - 1));
System.Delete(s, 1, i);
end;
//temp.CommaText := Parameter;
if temp.Count > 0 then begin
Value := temp[0];
temp.Delete(0);
i := temp.IndexOfName('Sync');
if i < 0 then
i := temp.IndexOfName('S');
if i >= 0 then
i := StrToIntDef(temp.ValueFromIndex[i], -1)
else
if (temp.IndexOf('Sync') >= 0) or (temp.IndexOf('S') >= 0) then begin
i := p.EditCellList.Count - 1;
while i >= 0 do begin
if TLazSynPluginSyncEditCell(p.EditCellList[i]).CellValue = Value then
break;
dec(i);
end;
end;
dec(i);
if (i >= 0) and (i < p.EditCellList.Count) then begin
Value := TLazSynPluginSyncEditCell(p.EditCellList[i]).CellValue;
g := TLazSynPluginSyncEditCell(p.EditCellList[i]).Group;
end;
end;
finally
temp.Free;
end;
with TLazSynPluginSyncEditCell(p.EditCellList.AddNew) do begin
LogStart := Point(p.DestPosX, p.DestPosY);
LogEnd := Point(p.DestPosX + length(Value), p.DestPosY);
if g < 0 then
Group := p.EditCellList.Count
else
Group := g;
CellValue := Value;
end;
Result := True;
end;
procedure RegisterStandardCodeTemplatesMenuItems;
var
Path: string;
@ -707,6 +775,9 @@ begin
'importaint operation of wiping off all of the $PrevWords found. In addition here is a regexp that is used'+
'to detect words for this macro: [\w\-+*\(\)\[\].^@]+',
@CodeMacroPrevWord,nil);
RegisterCodeMacroEx('Param', lisTemplateEditParamCell,
lisTemplateEditParamCellHelp,
@CodeMacroEditParam,nil);
end;
{ TCodeTemplateEditForm }

View File

@ -37,7 +37,7 @@ uses
// RTL, FCL
Classes, SysUtils,
// LCL
Controls, Graphics, LCLProc, FileUtil, LResources,
Controls, Graphics, LCLProc, FileUtil, LResources, Forms,
// synedit
SynEdit, SynEditAutoComplete, SynEditHighlighter, SynEditHighlighterFoldBase, SynEditKeyCmds,
SynEditStrConst, SynEditMarkupBracket, SynEditMarkupHighAll, SynEditMarkupWordGroup,
@ -46,7 +46,7 @@ uses
SynHighlighterPas, SynHighlighterPerl, SynHighlighterPHP, SynHighlighterSQL,
SynHighlighterPython, SynHighlighterUNIXShellScript, SynHighlighterXML,
SynHighlighterJScript, SynEditMiscClasses, SynBeautifier, SynEditTextTrimmer,
SynEditMouseCmds,
SynEditMouseCmds, SynPluginTemplateEdit,
// codetools
LinkScanner, CodeToolManager, Laz_XMLCfg,
// IDEIntf
@ -70,6 +70,11 @@ type
phaString, phaSymbol
);
TLazSynPluginTemplateEditForm = class(TForm)
end;
TLazSynPluginTemplateEditFormOff = class(TForm)
end;
const
PascalHilightAttributeNames: array[TPascalHilightAttribute] of String = (
SYNS_AttrAssembler,
@ -93,7 +98,8 @@ type
ahaInvalidBreakpoint, ahaUnknownBreakpoint,
ahaErrorLine, ahaIncrementalSearch, ahaHighlightAll, ahaBracketMatch,
ahaMouseLink, ahaLineNumber, ahaLineHighlight, ahaModifiedLine,
ahaCodeFoldingTree, ahaHighlightWord, ahaFoldedCode, ahaWordGroup);
ahaCodeFoldingTree, ahaHighlightWord, ahaFoldedCode, ahaWordGroup,
ahaTemplateEditCur, ahaTemplateEditSync, ahaTemplateEditOther);
TSingleColorAttribute = (scaGutter, scaRightMargin);
@ -118,7 +124,10 @@ const
'Code folding tree',
'Highlight current word',
'Folded code',
'Word-Brackets'
'Word-Brackets',
'TemplateEdit Current',
'TemplateEdit Sync',
'TemplateEdit Cells'
);
SingleColorAttributes: array[TSingleColorAttribute] of String =
@ -196,7 +205,10 @@ const
{ ahaCodeFoldingTree } (BG: clWhite; FG: clSilver; FC: clNone; Styles: []; StylesMask: []),
{ ahaHighlightWord } (BG: $E6E6E6; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []),
{ ahaFoldedCode } (BG: clWhite; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []),
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: [])
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []),
{ ahaTemplateEditCur } (BG: clNone; FG: clNone; FC: clAqua; Styles: []; StylesMask: []),
{ ahaTemplateEditSync } (BG: clNone; FG: clNone; FC: clFuchsia; Styles: []; StylesMask: []),
{ ahaTemplateEditOther } (BG: clNone; FG: clNone; FC: clMaroon; Styles: []; StylesMask: [])
);
Single: (
{ shaGutter } clBtnFace,
@ -235,7 +247,10 @@ const
{ ahaCodeFoldingTree } (BG: clDefault; FG: clSilver; FC: clNone; Styles: []; StylesMask: []),
{ ahaHighlightWord } (BG: $303030; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []),
{ ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []),
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: [])
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []),
{ ahaTemplateEditCur } (BG: clNone; FG: clNone; FC: clAqua; Styles: []; StylesMask: []),
{ ahaTemplateEditSync } (BG: clNone; FG: clNone; FC: clFuchsia; Styles: []; StylesMask: []),
{ ahaTemplateEditOther } (BG: clNone; FG: clNone; FC: clMaroon; Styles: []; StylesMask: [])
);
Single: (
{ shaGutter } clBtnFace,
@ -274,7 +289,10 @@ const
{ ahaCodeFoldingTree } (BG: clDefault; FG: clSilver; FC: clNone; Styles: []; StylesMask: []),
{ ahaHighlightWord } (BG: clDefault; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []),
{ ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []),
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: [])
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []),
{ ahaTemplateEditCur } (BG: clNone; FG: clNone; FC: clAqua; Styles: []; StylesMask: []),
{ ahaTemplateEditSync } (BG: clNone; FG: clNone; FC: clFuchsia; Styles: []; StylesMask: []),
{ ahaTemplateEditOther } (BG: clNone; FG: clNone; FC: clMaroon; Styles: []; StylesMask: [])
);
Single: (
{ shaGutter } clBtnFace,
@ -313,7 +331,10 @@ const
{ ahaCodeFoldingTree } (BG: clDefault; FG: clSilver; FC: clNone; Styles: []; StylesMask: []),
{ ahaHighlightWord } (BG: clDefault; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []),
{ ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []),
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: [])
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []),
{ ahaTemplateEditCur } (BG: clNone; FG: clNone; FC: clAqua; Styles: []; StylesMask: []),
{ ahaTemplateEditSync } (BG: clNone; FG: clNone; FC: clFuchsia; Styles: []; StylesMask: []),
{ ahaTemplateEditOther } (BG: clNone; FG: clNone; FC: clMaroon; Styles: []; StylesMask: [])
);
Single: (
{ shaGutter } clBtnFace,
@ -352,7 +373,10 @@ const
{ ahaCodeFoldingTree } (BG: $F4F4F4; FG: $CC9999; FC: clNone; Styles: []; StylesMask: []),
{ ahaHighlightWord } (BG: clDefault; FG: clDefault; FC: $CCCCD6; Styles: []; StylesMask: []),
{ ahaFoldedCode } (BG: clDefault; FG: $CC9999; FC: $CC9999; Styles: []; StylesMask: []),
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: [])
{ ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []),
{ ahaTemplateEditCur } (BG: clNone; FG: clNone; FC: clAqua; Styles: []; StylesMask: []),
{ ahaTemplateEditSync } (BG: clNone; FG: clNone; FC: clFuchsia; Styles: []; StylesMask: []),
{ ahaTemplateEditOther } (BG: clNone; FG: clNone; FC: clMaroon; Styles: []; StylesMask: [])
);
Single: (
{ shaGutter } clBtnFace,
@ -3115,6 +3139,9 @@ procedure TEditorOptions.SetMarkupColors(Syn: TSrcIDEHighlighter; aSynEd: TSynEd
SetMarkupColor(aSynEd.Highlighter, AddHilightAttr,
ASynEd.Gutter.Parts.ByClass[aClass, 0].MarkupInfo);
end;
var
i: integer;
begin
SetMarkupColor(aSynEd.Highlighter, ahaTextBlock, aSynEd.SelectedColor);
SetMarkupColor(aSynEd.Highlighter, ahaIncrementalSearch, aSynEd.IncrementColor);
@ -3128,6 +3155,18 @@ begin
SetGutterColorByClass(ahaLineNumber, TSynGutterLineNumber);
SetGutterColorByClass(ahaModifiedLine, TSynGutterChanges);
SetGutterColorByClass(ahaCodeFoldingTree, TSynGutterCodeFolding);
i := aSynEd.PluginCount - 1;
while (i >= 0) and not(aSynEd.Plugin[i] is TSynPluginTemplateEdit) do
dec(i);
if i >= 0 then begin
SetMarkupColor(aSynEd.Highlighter, ahaTemplateEditOther,
TSynPluginTemplateEdit(aSynEd.Plugin[i]).MarkupInfo);
SetMarkupColor(aSynEd.Highlighter, ahaTemplateEditCur,
TSynPluginTemplateEdit(aSynEd.Plugin[i]).MarkupInfoCurrent);
SetMarkupColor(aSynEd.Highlighter, ahaTemplateEditSync,
TSynPluginTemplateEdit(aSynEd.Plugin[i]).MarkupInfoSync);
end
end;
procedure TEditorOptions.SetMarkupColor(Syn : TSrcIDEHighlighter;
@ -3176,6 +3215,7 @@ procedure TEditorOptions.GetSynEditSettings(ASynEdit: TSynEdit);
// read synedit settings from config file
var
MarkCaret: TSynEditMarkupHighlightAllCaret;
i: Integer;
begin
// general options
ASynEdit.Options := fSynEditOptions;
@ -3232,6 +3272,15 @@ begin
end;
KeyMap.AssignTo(ASynEdit.KeyStrokes, TSourceEditorWindowInterface);
i := ASynEdit.PluginCount - 1;
while (i >= 0) and not(ASynEdit.Plugin[i] is TSynPluginTemplateEdit) do
dec(i);
if i >= 0 then begin
KeyMap.AssignTo(TSynPluginTemplateEdit(ASynEdit.Plugin[i]).Keystrokes, TLazSynPluginTemplateEditForm);
KeyMap.AssignTo(TSynPluginTemplateEdit(ASynEdit.Plugin[i]).KeystrokesOffCell, TLazSynPluginTemplateEditFormOff);
end;
ASynEdit.MouseActions.Assign(MouseMap);
ASynEdit.MouseSelActions.Assign(MouseSelMap);
ASynEdit.Gutter.MouseActions.Assign(MouseGutterActions);

View File

@ -35,7 +35,7 @@ uses
LCLIntf, LCLType, LCLProc,
Forms, Classes, SysUtils, Buttons, LResources, StdCtrls, Controls,
Dialogs, StringHashList, ExtCtrls,
SynEditKeyCmds, Laz_XMLCfg,
SynEditKeyCmds, SynPluginTemplateEdit, Laz_XMLCfg,
PropEdits, IDECommands, LazarusIDEStrConsts;
type
@ -406,7 +406,20 @@ begin
ecRemoveEmptyMethods: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecRemoveUnusedUnits: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecFindOverloads: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
{
// edit templates
ecIDESynTemplateEdit + ecSynPTmplEdNextCell = srkmecSynPTmplEdNextCell;
ecIDESynTemplateEdit + ecSynPTmplEdNextCellSel = srkmecSynPTmplEdNextCellSel;
ecIDESynTemplateEdit + ecSynPTmplEdNextCellRotate = srkmecSynPTmplEdNextCellRotate;
ecIDESynTemplateEdit + ecSynPTmplEdNextCellSelRotate = srkmecSynPTmplEdNextCellSelRotate;
ecIDESynTemplateEdit + ecSynPTmplEdPrevCell = srkmecSynPTmplEdPrevCell;
ecIDESynTemplateEdit + ecSynPTmplEdPrevCellSel = srkmecSynPTmplEdPrevCellSel;
ecIDESynTemplateEdit + ecSynPTmplEdCellHome = srkmecSynPTmplEdCellHome;
ecIDESynTemplateEdit + ecSynPTmplEdCellEnd = srkmecSynPTmplEdCellEnd;
ecIDESynTemplateEdit + ecSynPTmplEdCellSelect = srkmecSynPTmplEdCellSelect;
ecIDESynTemplateEdit + ecSynPTmplEdFinish = srkmecSynPTmplEdFinish;
ecIDESynTemplateEdit + ecSynPTmplEdEscape = srkmecSynPTmplEdEscape;
}
// source notebook
ecNextEditor: SetResult(VK_TAB, [ssCtrl], VK_UNKNOWN, []);
ecPrevEditor: SetResult(VK_TAB, [ssShift,ssCtrl], VK_UNKNOWN, []);
@ -556,7 +569,37 @@ begin
ecDesignerBackOne : SetResult(VK_NEXT,[ssCtrl],VK_UNKNOWN,[]);
else
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
begin
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
case TSynPluginTemplateEdit.ConvertCommandToBase(Command) of
// Edit template
ecSynPTmplEdNextCell: SetResult(VK_RIGHT,[ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSel: SetResult(VK_TAB, [], VK_UNKNOWN,[]);
ecSynPTmplEdNextCellRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSelRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCell: SetResult(VK_LEFT, [ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCellSel: SetResult(VK_TAB, [ssShift],VK_UNKNOWN,[]);
ecSynPTmplEdCellHome: SetResult(VK_HOME, [],VK_UNKNOWN,[]);
ecSynPTmplEdCellEnd: SetResult(VK_END, [],VK_UNKNOWN,[]);
ecSynPTmplEdCellSelect: SetResult(VK_A, [ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdFinish: SetResult(VK_RETURN,[],VK_UNKNOWN,[]);
ecSynPTmplEdEscape: SetResult(VK_ESCAPE,[],VK_UNKNOWN,[]);
end;
case TSynPluginTemplateEdit.ConvertCommandToBaseOff(Command) of
// Edit template
ecSynPTmplEdNextCell: SetResult(VK_RIGHT,[ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSel: SetResult(VK_TAB, [], VK_UNKNOWN,[]);
ecSynPTmplEdNextCellRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSelRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCell: SetResult(VK_LEFT, [ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCellSel: SetResult(VK_TAB, [ssShift],VK_UNKNOWN,[]);
ecSynPTmplEdCellHome: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellEnd: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellSelect: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdFinish: SetResult(VK_RETURN,[],VK_UNKNOWN,[]);
ecSynPTmplEdEscape: SetResult(VK_ESCAPE,[],VK_UNKNOWN,[]);
end;
end;
end;
end;
@ -899,7 +942,38 @@ begin
ecDesignerBackOne : SetResult(VK_NEXT,[ssCtrl],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
else
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
begin
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
case TSynPluginTemplateEdit.ConvertCommandToBase(Command) of
// Edit template
ecSynPTmplEdNextCell: SetResult(VK_RIGHT,[ssCtrl],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSel: SetResult(VK_TAB, [], VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSelRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCell: SetResult(VK_LEFT, [ssCtrl],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCellSel: SetResult(VK_TAB, [ssShift],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellHome: SetResult(VK_HOME, [],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellEnd: SetResult(VK_END, [],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellSelect: SetResult(VK_A, [ssCtrl],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdFinish: SetResult(VK_RETURN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdEscape: SetResult(VK_ESCAPE,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
end;
case TSynPluginTemplateEdit.ConvertCommandToBaseOff(Command) of
// Edit template
ecSynPTmplEdNextCell: SetResult(VK_RIGHT,[ssCtrl],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSel: SetResult(VK_TAB, [], VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSelRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCell: SetResult(VK_LEFT, [ssCtrl],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCellSel: SetResult(VK_TAB, [ssShift],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellHome: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellEnd: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellSelect: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdFinish: SetResult(VK_RETURN,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdEscape: SetResult(VK_ESCAPE,[],VK_UNKNOWN,[],VK_UNKNOWN,[],VK_UNKNOWN,[]);
end;
end;
end;
(*//F1 Topic Search
//Ctrl+F1 Topic Search
@ -1432,7 +1506,38 @@ begin
ecDesignerBackOne : SetResult(VK_NEXT,[ssMeta],VK_UNKNOWN,[]);
else
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
begin
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
case TSynPluginTemplateEdit.ConvertCommandToBase(Command) of
// Edit template
ecSynPTmplEdNextCell: SetResult(VK_RIGHT,[ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSel: SetResult(VK_TAB, [], VK_UNKNOWN,[]);
ecSynPTmplEdNextCellRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSelRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCell: SetResult(VK_LEFT, [ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCellSel: SetResult(VK_TAB, [ssShift],VK_UNKNOWN,[]);
ecSynPTmplEdCellHome: SetResult(VK_HOME, [],VK_UNKNOWN,[]);
ecSynPTmplEdCellEnd: SetResult(VK_END, [],VK_UNKNOWN,[]);
ecSynPTmplEdCellSelect: SetResult(VK_A, [ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdFinish: SetResult(VK_RETURN,[],VK_UNKNOWN,[]);
ecSynPTmplEdEscape: SetResult(VK_ESCAPE,[],VK_UNKNOWN,[]);
end;
case TSynPluginTemplateEdit.ConvertCommandToBaseOff(Command) of
// Edit template
ecSynPTmplEdNextCell: SetResult(VK_RIGHT,[ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSel: SetResult(VK_TAB, [], VK_UNKNOWN,[]);
ecSynPTmplEdNextCellRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdNextCellSelRotate: SetResult(VK_UNKNOWN, [],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCell: SetResult(VK_LEFT, [ssCtrl],VK_UNKNOWN,[]);
ecSynPTmplEdPrevCellSel: SetResult(VK_TAB, [ssShift],VK_UNKNOWN,[]);
ecSynPTmplEdCellHome: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellEnd: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdCellSelect: SetResult(VK_UNKNOWN,[],VK_UNKNOWN,[]);
ecSynPTmplEdFinish: SetResult(VK_RETURN,[],VK_UNKNOWN,[]);
ecSynPTmplEdEscape: SetResult(VK_ESCAPE,[],VK_UNKNOWN,[]);
end;
end;
end;
end;
@ -1842,7 +1947,37 @@ begin
ecDesignerBackOne : Result:= lisDsgOrderBackOne;
else
Result:= srkmecunknown;
begin
Result:= srkmecunknown;
case TSynPluginTemplateEdit.ConvertCommandToBase(cmd) of
// Edit template
ecSynPTmplEdNextCell: Result := srkmecSynPTmplEdNextCell;
ecSynPTmplEdNextCellSel: Result := srkmecSynPTmplEdNextCellSel;
ecSynPTmplEdNextCellRotate: Result := srkmecSynPTmplEdNextCellRotate;
ecSynPTmplEdNextCellSelRotate: Result := srkmecSynPTmplEdNextCellSelRotate;
ecSynPTmplEdPrevCell: Result := srkmecSynPTmplEdPrevCell;
ecSynPTmplEdPrevCellSel: Result := srkmecSynPTmplEdPrevCellSel;
ecSynPTmplEdCellHome: Result := srkmecSynPTmplEdCellHome;
ecSynPTmplEdCellEnd: Result := srkmecSynPTmplEdCellEnd;
ecSynPTmplEdCellSelect: Result := srkmecSynPTmplEdCellSelect;
ecSynPTmplEdFinish: Result := srkmecSynPTmplEdFinish;
ecSynPTmplEdEscape: Result := srkmecSynPTmplEdEscape;
end;
case TSynPluginTemplateEdit.ConvertCommandToBaseOff(cmd) of
// Edit template
ecSynPTmplEdNextCell: Result := srkmecSynPTmplEdNextCell;
ecSynPTmplEdNextCellSel: Result := srkmecSynPTmplEdNextCellSel;
ecSynPTmplEdNextCellRotate: Result := srkmecSynPTmplEdNextCellRotate;
ecSynPTmplEdNextCellSelRotate: Result := srkmecSynPTmplEdNextCellSelRotate;
ecSynPTmplEdPrevCell: Result := srkmecSynPTmplEdPrevCell;
ecSynPTmplEdPrevCellSel: Result := srkmecSynPTmplEdPrevCellSel;
ecSynPTmplEdCellHome: Result := srkmecSynPTmplEdCellHome;
ecSynPTmplEdCellEnd: Result := srkmecSynPTmplEdCellEnd;
ecSynPTmplEdCellSelect: Result := srkmecSynPTmplEdCellSelect;
ecSynPTmplEdFinish: Result := srkmecSynPTmplEdFinish;
ecSynPTmplEdEscape: Result := srkmecSynPTmplEdEscape;
end;
end;
end;
end;
@ -1971,6 +2106,7 @@ end;
procedure TKeyCommandRelationList.CreateDefaultMapping;
var
C: TIDECommandCategory;
o: LongInt;
begin
Clear;
@ -2229,6 +2365,36 @@ begin
AddDefault(C, 'Find overloads', srkmecFindOverloads,
ecFindOverloads);
// Template editing
C:=Categories[AddCategory('Edit Template', srkmCatTemplateEdit, IDECmdScopeSrcEditOnlyTmplEdit)];
o := TSynPluginTemplateEdit.ConvertBaseToCommand(ecPluginFirst) - ecPluginFirst;
AddDefault(C, 'Edit Template Next Cell', srkmecSynPTmplEdNextCell, ecSynPTmplEdNextCell + o);
AddDefault(C, 'Edit Template Next Cell (all selected)', srkmecSynPTmplEdNextCellSel, ecSynPTmplEdNextCellSel + o);
AddDefault(C, 'Edit Template Next Cell (rotate / all selected)', srkmecSynPTmplEdNextCellRotate, ecSynPTmplEdNextCellRotate + o);
AddDefault(C, 'Edit Template Next Cell (rotate / all selected)', srkmecSynPTmplEdNextCellSelRotate, ecSynPTmplEdNextCellSelRotate + o);
AddDefault(C, 'Edit Template Previous Cell', srkmecSynPTmplEdPrevCell, ecSynPTmplEdPrevCell + o);
AddDefault(C, 'Edit Template Previous Cell (all selected)', srkmecSynPTmplEdPrevCellSel, ecSynPTmplEdPrevCellSel + o);
AddDefault(C, 'Edit Template Goto first pos in cell', srkmecSynPTmplEdCellHome, ecSynPTmplEdCellHome + o);
AddDefault(C, 'Edit Template Goto last pos in cell', srkmecSynPTmplEdCellEnd, ecSynPTmplEdCellEnd + o);
AddDefault(C, 'Edit Template Select cell', srkmecSynPTmplEdCellSelect, ecSynPTmplEdCellSelect + o);
AddDefault(C, 'Edit Template Finish', srkmecSynPTmplEdFinish, ecSynPTmplEdFinish + o);
AddDefault(C, 'Edit Template Escape', srkmecSynPTmplEdEscape, ecSynPTmplEdEscape + o);
// Template editing not in cell
C:=Categories[AddCategory('Edit Template Off', srkmCatTemplateEditOff, IDECmdScopeSrcEditOnlyTmplEditOff)];
o := TSynPluginTemplateEdit.ConvertBaseToCommandOff(ecPluginFirst) - ecPluginFirst;
AddDefault(C, 'Edit Template (off) Next Cell', srkmecSynPTmplEdNextCell, ecSynPTmplEdNextCell + o);
AddDefault(C, 'Edit Template (off) Next Cell (all selected)', srkmecSynPTmplEdNextCellSel, ecSynPTmplEdNextCellSel + o);
AddDefault(C, 'Edit Template (off) Next Cell (rotate / all selected)', srkmecSynPTmplEdNextCellRotate, ecSynPTmplEdNextCellRotate + o);
AddDefault(C, 'Edit Template (off) Next Cell (rotate / all selected)', srkmecSynPTmplEdNextCellSelRotate, ecSynPTmplEdNextCellSelRotate + o);
AddDefault(C, 'Edit Template (off) Previous Cell', srkmecSynPTmplEdPrevCell, ecSynPTmplEdPrevCell + o);
AddDefault(C, 'Edit Template (off) Previous Cell (all selected)', srkmecSynPTmplEdPrevCellSel, ecSynPTmplEdPrevCellSel + o);
AddDefault(C, 'Edit Template (off) Goto first pos in cell', srkmecSynPTmplEdCellHome, ecSynPTmplEdCellHome + o);
AddDefault(C, 'Edit Template (off) Goto last pos in cell', srkmecSynPTmplEdCellEnd, ecSynPTmplEdCellEnd + o);
AddDefault(C, 'Edit Template (off) Select cell', srkmecSynPTmplEdCellSelect, ecSynPTmplEdCellSelect + o);
AddDefault(C, 'Edit Template (off) Finish', srkmecSynPTmplEdFinish, ecSynPTmplEdFinish + o);
AddDefault(C, 'Edit Template (off) Escape', srkmecSynPTmplEdEscape, ecSynPTmplEdEscape + o);
// source notebook - without menu items in the IDE bar
C:=Categories[AddCategory('SourceNotebook',srkmCatSrcNoteBook,
IDECmdScopeSrcEdit)];
@ -2711,81 +2877,86 @@ var
Key: TSynEditKeyStroke;
CurRelation: TKeyCommandRelation;
begin
for a:=0 to FRelations.Count-1 do begin
CurRelation:=Relations[a];
if (CurRelation.ShortcutA.Key1=VK_UNKNOWN)
or ((IDEWindowClass<>nil) and (CurRelation.Category.Scope<>nil)
and (not CurRelation.Category.Scope.HasIDEWindowClass(IDEWindowClass)))
then
MaxKeyCnt:=0
else if CurRelation.ShortcutB.Key1=VK_UNKNOWN then
MaxKeyCnt:=1
else
MaxKeyCnt:=2;
KeyCnt:=1;
b:=ASynEditKeyStrokes.Count-1;
// replace keys
while b>=0 do begin
Key:=ASynEditKeyStrokes[b];
if Key.Command=CurRelation.Command then begin
if KeyCnt>MaxKeyCnt then begin
// All keys with this command are already defined
// -> delete this one
Key.Free;
end else if KeyCnt=1 then begin
// Define key1 for this command
try
ASynEditKeyStrokes.UsePluginOffset := True;
for a:=0 to FRelations.Count-1 do begin
CurRelation:=Relations[a];
if (CurRelation.ShortcutA.Key1=VK_UNKNOWN)
or ((IDEWindowClass<>nil) and (CurRelation.Category.Scope<>nil)
and (not CurRelation.Category.Scope.HasIDEWindowClass(IDEWindowClass)))
then
MaxKeyCnt:=0
else if CurRelation.ShortcutB.Key1=VK_UNKNOWN then
MaxKeyCnt:=1
else
MaxKeyCnt:=2;
KeyCnt:=1;
b:=ASynEditKeyStrokes.Count-1;
// replace keys
while b>=0 do begin
Key:=ASynEditKeyStrokes[b];
if Key.Command=CurRelation.Command then begin
if KeyCnt>MaxKeyCnt then begin
// All keys with this command are already defined
// -> delete this one
Key.Free;
end else if KeyCnt=1 then begin
// Define key1 for this command
Key.Key:=CurRelation.ShortcutA.Key1;
Key.Shift:=CurRelation.ShortcutA.Shift1;
Key.Key2:=CurRelation.ShortcutA.Key2;
Key.Shift2:=CurRelation.ShortcutA.Shift2;
end else if KeyCnt=2 then begin
// Define key2 for this command
Key.Key:=CurRelation.ShortcutB.Key1;
Key.Shift:=CurRelation.ShortcutB.Shift1;
Key.Key2:=CurRelation.ShortcutB.Key2;
Key.Shift2:=CurRelation.ShortcutB.Shift2;
end;
inc(KeyCnt);
end
else
if MaxKeyCnt > 0 then begin
// Key with a different ecCommand => Remove if it has a conflicting keystroke(s)
if ( (CurRelation.ShortcutA.Key1 <> VK_UNKNOWN) and
(Key.Key = CurRelation.ShortcutA.Key1) and
(Key.Shift = CurRelation.ShortcutA.Shift1) and
( (CurRelation.ShortcutA.Key2 = VK_UNKNOWN) or
( (Key.Key2 = CurRelation.ShortcutA.Key2) and
(Key.Shift2 = CurRelation.ShortcutA.Shift2) )
) )
OR ( (CurRelation.ShortcutB.Key1 <> VK_UNKNOWN) and
(Key.Key = CurRelation.ShortcutB.Key1) and
(Key.Shift = CurRelation.ShortcutB.Shift1) and
( (CurRelation.ShortcutB.Key2 = VK_UNKNOWN) or
( (Key.Key2 = CurRelation.ShortcutB.Key2) and
(Key.Shift2 = CurRelation.ShortcutB.Shift2) )
) )
then
Key.Free;
end;
dec(b);
end;
// add missing keys
while KeyCnt<=MaxKeyCnt do begin
Key:=ASynEditKeyStrokes.Add;
Key.Command:=CurRelation.Command;
if KeyCnt=1 then begin
Key.Key:=CurRelation.ShortcutA.Key1;
Key.Shift:=CurRelation.ShortcutA.Shift1;
Key.Key2:=CurRelation.ShortcutA.Key2;
Key.Shift2:=CurRelation.ShortcutA.Shift2;
end else if KeyCnt=2 then begin
// Define key2 for this command
end else begin
Key.Key:=CurRelation.ShortcutB.Key1;
Key.Shift:=CurRelation.ShortcutB.Shift1;
Key.Key2:=CurRelation.ShortcutB.Key2;
Key.Shift2:=CurRelation.ShortcutB.Shift2;
end;
inc(KeyCnt);
end
else
if MaxKeyCnt > 0 then begin
// Key with a different ecCommand => Remove if it has a conflicting keystroke(s)
if ( (CurRelation.ShortcutA.Key1 <> VK_UNKNOWN) and
(Key.Key = CurRelation.ShortcutA.Key1) and
(Key.Shift = CurRelation.ShortcutA.Shift1) and
( (CurRelation.ShortcutA.Key2 = VK_UNKNOWN) or
( (Key.Key2 = CurRelation.ShortcutA.Key2) and
(Key.Shift2 = CurRelation.ShortcutA.Shift2) )
) )
OR ( (CurRelation.ShortcutB.Key1 <> VK_UNKNOWN) and
(Key.Key = CurRelation.ShortcutB.Key1) and
(Key.Shift = CurRelation.ShortcutB.Shift1) and
( (CurRelation.ShortcutB.Key2 = VK_UNKNOWN) or
( (Key.Key2 = CurRelation.ShortcutB.Key2) and
(Key.Shift2 = CurRelation.ShortcutB.Shift2) )
) )
then
Key.Free;
end;
dec(b);
end;
// add missing keys
while KeyCnt<=MaxKeyCnt do begin
Key:=ASynEditKeyStrokes.Add;
Key.Command:=CurRelation.Command;
if KeyCnt=1 then begin
Key.Key:=CurRelation.ShortcutA.Key1;
Key.Shift:=CurRelation.ShortcutA.Shift1;
Key.Key2:=CurRelation.ShortcutA.Key2;
Key.Shift2:=CurRelation.ShortcutA.Shift2;
end else begin
Key.Key:=CurRelation.ShortcutB.Key1;
Key.Shift:=CurRelation.ShortcutB.Shift1;
Key.Key2:=CurRelation.ShortcutB.Key2;
Key.Shift2:=CurRelation.ShortcutB.Shift2;
end;
inc(KeyCnt);
end;
finally
ASynEditKeyStrokes.UsePluginOffset := False;
end;
end;

View File

@ -2186,6 +2186,19 @@ resourcestring
srkmecRemoveUnusedUnits = 'Remove unused units';
srkmecFindOverloads = 'Find overloads';
//Plugin template Edit
srkmecSynPTmplEdNextCell = 'Next Cell';
srkmecSynPTmplEdNextCellSel = 'Next Cell (all selected)';
srkmecSynPTmplEdNextCellRotate = 'Next Cell (rotate)';
srkmecSynPTmplEdNextCellSelRotate = 'Next Cell (rotate / all selected)';
srkmecSynPTmplEdPrevCell = 'Previous Cell';
srkmecSynPTmplEdPrevCellSel = 'Previous Cell (all selected)';
srkmecSynPTmplEdCellHome = 'Goto first pos in cell';
srkmecSynPTmplEdCellEnd = 'Goto last pos in cell';
srkmecSynPTmplEdCellSelect = 'Select cell';
srkmecSynPTmplEdFinish = 'Finish';
srkmecSynPTmplEdEscape = 'Escape';
// run menu
srkmecBuild = 'build program/project';
srkmecBuildAll = 'build all files of program/project';
@ -2244,6 +2257,8 @@ resourcestring
srkmCatFold = 'Text folding commands';
lisKMSetFreeBookmark = 'Set free Bookmark';
srkmCatCodeTools = 'CodeTools commands';
srkmCatTemplateEdit = 'Template Editing';
srkmCatTemplateEditOff= 'Template Editing (not in Cell)';
srkmCatSrcNoteBook = 'Source Notebook commands';
srkmCatFileMenu = 'File menu commands';
lisKMGoToSourceEditor10 = 'Go to source editor 10';
@ -4292,6 +4307,10 @@ resourcestring
lisReturnsListOfAllValuesOfCaseVariableInFrontOfVaria = 'returns list of '
+'all values of case variable in front of variable';
lisGetWordAtCurrentCursorPosition = 'get word at current cursor position';
lisTemplateEditParamCell = 'Editable Cell';
lisTemplateEditParamCellHelp = 'Inserts an editable Cell, with a default value'
+ LineEnding + '"",Sync=n (,S=n), to Sync with a previous cell (n=1 to highest prev cell'
+ LineEnding + '"default",Sync, to Sync with a previous cell of equal default';
lisPrecedingWord = 'Preceding word';
implementation

View File

@ -1908,6 +1908,9 @@ begin
IDECmdScopeSrcEdit.AddWindowClass(nil);
IDECmdScopeSrcEditOnly.AddWindowClass(TSourceEditorWindowInterface);
IDECmdScopeSrcEditOnlyTmplEdit.AddWindowClass(TLazSynPluginTemplateEditForm);
IDECmdScopeSrcEditOnlyTmplEditOff.AddWindowClass(TLazSynPluginTemplateEditFormOff);
EditorOpts.KeyMap.CreateDefaultMapping;
end;

View File

@ -51,7 +51,7 @@ uses
SynEditStrConst, SynEditTypes, SynEdit, SynRegExpr, SynEditHighlighter,
SynEditAutoComplete, SynEditKeyCmds, SynCompletion, SynEditMiscClasses,
SynEditMarkupHighAll, SynGutterLineNumber, SynEditMarks, SynBeautifier,
SynEditTextBase,
SynEditTextBase, SynPluginTemplateEdit,
// IDE interface
MacroIntf, ProjectIntf, SrcEditorIntf, MenuIntf, LazIDEIntf, PackageIntf,
IDEDialogs, IDEHelpIntf, IDEWindowIntf, IDEImagesIntf,
@ -2545,12 +2545,12 @@ Begin
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);
TSynPluginTemplateEdit.Create(FEditor);
RefreshEditorSettings;
FEditor.EndUpdate;
end else begin

View File

@ -294,6 +294,7 @@ const
ecLazarusLast = ecFirstLazarus + 2000;
type
TIDECommand = class;
TIDECommandCategory = class;
@ -492,6 +493,8 @@ var
var
IDECmdScopeSrcEdit: TIDECommandScope;
IDECmdScopeSrcEditOnly: TIDECommandScope;
IDECmdScopeSrcEditOnlyTmplEdit: TIDECommandScope;
IDECmdScopeSrcEditOnlyTmplEditOff: TIDECommandScope;
IDECmdScopeDesignerOnly: TIDECommandScope;
IDECmdScopeObjectInspectorOnly: TIDECommandScope;
@ -578,6 +581,8 @@ begin
IDECommandScopes:=TIDECommandScopes.Create;
IDECmdScopeSrcEdit:=RegisterIDECommandScope('SourceEditor');
IDECmdScopeSrcEditOnly:=RegisterIDECommandScope('SourceEditorOnly');
IDECmdScopeSrcEditOnlyTmplEdit:=RegisterIDECommandScope('SourceEditorOnlyTemplateEdit');
IDECmdScopeSrcEditOnlyTmplEditOff:=RegisterIDECommandScope('SourceEditorOnlyTemplateEditOff');
IDECmdScopeDesignerOnly:=RegisterIDECommandScope('DesignerOnly');
IDECmdScopeObjectInspectorOnly:=RegisterIDECommandScope('ObjectInspectorOnly');
end;

View File

@ -177,6 +177,24 @@ type
property Value: string read FValue write FValue;
end;
{ TIDETemplateParser }
TIDETemplateParser = class
protected
function GetSrcPosition: Integer; virtual; abstract;
function GetDestPosition: Integer; virtual; abstract;
function GetDestPosX: Integer; virtual; abstract;
function GetDestPosY: Integer; virtual; abstract;
function GetSrcTemplate: String; virtual; abstract;
function GetDestTemplate: String; virtual; abstract;
public
property SrcTemplate: String read GetSrcTemplate;
property DestTemplate: String read GetDestTemplate;
property SrcPosition: Integer read GetSrcPosition;
property DestPosition: Integer read GetDestPosition;
property DestPosX: Integer read GetDestPosX;
property DestPosY: Integer read GetDestPosY;
end;
TIDECodeMacroGetValueProc = function(const Parameter: string;
InteractiveValue: TPersistent;
@ -187,6 +205,17 @@ type
SrcEdit: TSourceEditorInterface;
var Value, ErrorMsg: string): boolean of object;
TIDECodeMacroGetValueExProc = function(const Parameter: string;
InteractiveValue: TPersistent;
SrcEdit: TSourceEditorInterface;
var Value, ErrorMsg: string;
TemplateParser: TIDETemplateParser): boolean;
TIDECodeMacroGetValueExMethod = function(const Parameter: string;
InteractiveValue: TPersistent;
SrcEdit: TSourceEditorInterface;
var Value, ErrorMsg: string;
TemplateParser: TIDETemplateParser): boolean of object;
{ TIDECodeMacro }
TIDECodeMacro = class
@ -197,6 +226,8 @@ type
FName: string;
FOnGetValueMethod: TIDECodeMacroGetValueMethod;
FOnGetValueProc: TIDECodeMacroGetValueProc;
FOnGetValueExMethod: TIDECodeMacroGetValueExMethod;
FOnGetValueExProc: TIDECodeMacroGetValueExProc;
FShortDescription: string;
protected
procedure Init; virtual;
@ -209,9 +240,13 @@ type
write FOnGetValueProc;
property OnGetValueMethod: TIDECodeMacroGetValueMethod read FOnGetValueMethod
write FOnGetValueMethod;
property OnGetValueExProc: TIDECodeMacroGetValueExProc read FOnGetValueExProc
write FOnGetValueExProc;
property OnGetValueExMethod: TIDECodeMacroGetValueExMethod read FOnGetValueExMethod
write FOnGetValueExMethod;
function GetValue(const Parameter: string; InteractiveValue: TPersistent;
SrcEdit: TSourceEditorInterface;
out Value, ErrorMsg: string): boolean; virtual;
SrcEdit: TSourceEditorInterface; out Value, ErrorMsg: string;
TemplateParser: TIDETemplateParser = nil): boolean; virtual;
property Interactive: boolean read FInteractive write FInteractive;
property InteractiveValueClass: TPersistentClass read FInteractiveValueClass
write FInteractiveValueClass;
@ -239,6 +274,10 @@ function RegisterCodeMacro(const Name: string;
OnGetValueProc: TIDECodeMacroGetValueProc;
OnGetValueMethod: TIDECodeMacroGetValueMethod): TIDECodeMacro;
function RegisterCodeMacroEx(const Name: string;
const ShortDescription, LongDescription: string;
OnGetValueProc: TIDECodeMacroGetValueExProc;
OnGetValueMethod: TIDECodeMacroGetValueExMethod): TIDECodeMacro;
{ SearchInFile to search in a file.
This can be interactively or without user interaction.
@ -288,6 +327,21 @@ begin
IDECodeMacros.Add(Result);
end;
function RegisterCodeMacroEx(const Name: string; const ShortDescription,
LongDescription: string; OnGetValueProc: TIDECodeMacroGetValueExProc;
OnGetValueMethod: TIDECodeMacroGetValueExMethod): TIDECodeMacro;
var
NewName: String;
begin
NewName:=IDECodeMacros.CreateUniqueName(Name);
Result:=TIDECodeMacro.Create(NewName);
Result.ShortDescription:=ConvertLineEndings(ShortDescription);
Result.LongDescription:=ConvertLineEndings(LongDescription);
Result.OnGetValueExProc:=OnGetValueProc;
Result.OnGetValueExMethod:=OnGetValueMethod;
IDECodeMacros.Add(Result);
end;
{ TSourceEditorInterface }
procedure TSourceEditorInterface.SelectText(LineNum, CharStart, LineNum2,
@ -324,7 +378,7 @@ end;
function TIDECodeMacro.GetValue(const Parameter: string;
InteractiveValue: TPersistent; SrcEdit: TSourceEditorInterface;
out Value, ErrorMsg: string): boolean;
out Value, ErrorMsg: string; TemplateParser: TIDETemplateParser = nil): boolean;
begin
Value:=Parameter;
ErrorMsg:='';
@ -332,6 +386,12 @@ begin
Result:=OnGetValueProc(Parameter,InteractiveValue,SrcEdit,Value,ErrorMsg)
else if Assigned(OnGetValueMethod) then
Result:=OnGetValueMethod(Parameter,InteractiveValue,SrcEdit,Value,ErrorMsg)
else if Assigned(OnGetValueExProc) then
Result:=OnGetValueExProc(Parameter,InteractiveValue,SrcEdit,Value,ErrorMsg,
TemplateParser)
else if Assigned(OnGetValueExMethod) then
Result:=OnGetValueExMethod(Parameter,InteractiveValue,SrcEdit,Value,ErrorMsg,
TemplateParser)
else
Result:=true;
end;