dexed/src/ce_staticmacro.pas

205 lines
4.9 KiB
Plaintext

unit ce_staticmacro;
{$I ce_defines.inc}
interface
uses
Classes, Sysutils, SynEdit, SynEditAutoComplete, SynCompletion,
ce_interfaces, ce_writableComponent, ce_synmemo;
type
(**
* TCEStaticEditorMacro is used to insert static macros (parameter-less code snippets)
* in an editor. A macro begins with the dollar symbol and ends with an alphanum.
*
* The dollar symbol is used as starter because it's usually accessible without
* modifier: no CTRL, no ALT, no SHIFT.
* Erroneous insertion is avoided because in D '$' is either followed
* by a symbol: '$-1', '$]' or by a blank '$ ]'
*
* Shift + SPACE works automatically on the right editor (ICEMultiDocObserver)
* Automatic insertion is handled in TCESynMemo.KeyUp()
*)
TCEStaticEditorMacro = class(TWritableComponent, ICEMultiDocObserver)
private
fCompletor: TSynAutoComplete;
fMacros: TStringList;
fDoc: TCESynMemo;
fAutomatic: boolean;
procedure sanitize;
procedure addDefaults;
procedure updateCompletor;
procedure setMacros(aValue: TStringList);
// ICEMultiDocObserver
procedure docNew(aDoc: TCESynMemo);
procedure docFocused(aDoc: TCESynMemo);
procedure docChanged(aDoc: TCESynMemo);
procedure docClosing(aDoc: TCESynMemo);
published
// list of string with the format $<..>alnum=<..>
property macros: TStringList read fMacros write setMacros;
property automatic: boolean read fAutomatic write fAutomatic;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
// execute using the editor
procedure Execute; overload;
// execute in aEditor, according to aToken
procedure Execute(aEditor: TCustomSynEdit; const aToken: string); overload;
end;
const
macFname = 'staticMacros.txt';
defMacros: array[0..5] of string = (
'$a=auto',
'$c=class {}',
'$s=struct {}',
'$ut=unittest{}',
'$fo=for(auto i = 0; ; )',
'$fe=foreach(elem; )'
);
var
StaticEditorMacro: TCEStaticEditorMacro = nil;
implementation
uses
ce_observer, ce_common;
{$REGION Standard Comp/Obj -----------------------------------------------------}
constructor TCEStaticEditorMacro.create(aOwner: TComponent);
var
fname: string;
begin
inherited;
fAutomatic := true;
fCompletor := TSynAutoComplete.Create(self);
fMacros := TStringList.Create;
fMacros.Delimiter := '=';
assert(fCompletor.ShortCut <> 0);
//
fname := getDocPath + macFname;
if fileExists(fname) then loadFromFile(fname);
addDefaults;
//
sanitize;
updateCompletor;
//
EntitiesConnector.addObserver(Self);
end;
destructor TCEStaticEditorMacro.destroy;
begin
saveToFile(getDocPath + macFname);
EntitiesConnector.removeObserver(Self);
//
fMacros.Free;
inherited;
end;
procedure TCEStaticEditorMacro.setMacros(aValue: TStringList);
begin
fMacros.Assign(aValue);
addDefaults;
sanitize;
updateCompletor;
end;
{$ENDREGION}
{$REGION ICEMultiDocObserver ---------------------------------------------------}
procedure TCEStaticEditorMacro.docNew(aDoc: TCESynMemo);
begin
fDoc := aDoc;
fCompletor.Editor := fDoc;
end;
procedure TCEStaticEditorMacro.docFocused(aDoc: TCESynMemo);
begin
fDoc := aDoc;
fCompletor.Editor := fDoc;
end;
procedure TCEStaticEditorMacro.docChanged(aDoc: TCESynMemo);
begin
if aDoc <> fDoc then
exit;
end;
procedure TCEStaticEditorMacro.docClosing(aDoc: TCESynMemo);
begin
if aDoc <> fDoc then
exit;
fDoc := nil;
end;
{$ENDREGION}
{$REGION Macros things ---------------------------------------------------------}
procedure TCEStaticEditorMacro.sanitize;
var
i: Integer;
text: string;
macro: string;
begin
for i := fMacros.Count-1 downto 0 do
begin
text := fMacros.Strings[i];
if length(text) >= 4 then
if text[1] = '$' then
if Pos('=', text) > 2 then
begin
macro := fMacros.Names[i];
if (macro[length(macro)] in ['a'..'z', 'A'..'Z', '0'..'9']) then
continue;
end;
fMacros.Delete(i);
end;
end;
procedure TCEStaticEditorMacro.addDefaults;
var
i: Integer;
begin
for i := 0 to high(defMacros) do
if fMacros.IndexOf(defMacros[i]) = -1 then
fMacros.Add(defMacros[i]);
end;
procedure TCEStaticEditorMacro.updateCompletor;
var
i: Integer;
tok, val: string;
begin
fCompletor.AutoCompleteList.Clear;
for i := 0 to fMacros.Count-1 do
begin
tok := fMacros.Names[i];
val := fMacros.ValueFromIndex[i];
fCompletor.AutoCompleteList.Add(tok);
fCompletor.AutoCompleteList.Add('=' + val);
end;
end;
procedure TCEStaticEditorMacro.Execute;
begin
if fDoc <> nil then
fCompletor.Execute(fDoc.Identifier, fDoc);
end;
procedure TCEStaticEditorMacro.Execute(aEditor: TCustomSynEdit; const aToken: string);
begin
if aEditor <> nil then
fCompletor.Execute(aToken, aEditor);
end;
{$ENDREGION}
initialization
StaticEditorMacro := TCEStaticEditorMacro.create(nil);
finalization
StaticEditorMacro.Free;;
end.