Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a GUID when evoking a Live Template in Delphi?

I am using Live Templates a lot in Delphi but have tried to come up with a solution to add GUIDS to templates. Does anyone know how to do this?

Below the template I have now with GUID as a word I need to replace manually.

<?xml version="1.0" encoding="utf-8" ?>
<codetemplate   xmlns="http://schemas.borland.com/Delphi/2005/codetemplates"
            version="1.0.0">
<template name="iacc" surround="false" invoke="manual">
    <point name="name">
        <text>
            IntfAccessors
        </text>
        <hint>
            Accessors name
        </hint>
    </point>
    <description>
        accessor declaration
    </description>
    <author>
        PMH
    </author>
    <code language="Delphi" context="methoddecl" delimiter="|">    <![CDATA[I|name|Accessors = interface(IInterface)
GUID <-- here I want a GUID
end;


I|name| = interface(I|name|Accessors)
GUID <-- here I want a GUID
end;
    ]]>
        </code>
    </template>
</codetemplate>
like image 613
Paul Michael Avatar asked Aug 31 '16 11:08

Paul Michael


1 Answers

You can extend the IDE by writing a custom scripting engine to do this. (Here's an article written by Nick Hodges with a similar example which inserts current date.)

I assume that the two different interfaces from your example template need two different IIDs so I wrote the scripting engine to load the point names from the "script" (it's just a list of name=value pairs where the name is the point name and the value must be NewGuid otherwise it's ignored) so you can create templates with multiple points, each receiving a separate new IID.

Example template intf.xml:

<?xml version="1.0" encoding="utf-8" ?>
<codetemplate   xmlns="http://schemas.borland.com/Delphi/2005/codetemplates" version="1.0.0">
<template name="iacc" surround="false" invoke="manual">
    <point name="name">
        <text>
            Accessor
        </text>
        <hint>
            Accessors name
        </hint>
    </point>
    <point name="guid1"/>
    <point name="guid2"/>
    <description>
        accessor declaration
    </description>
    <author>
        PMH
    </author>
    <script language="NewGuidScript" onvalidate="true">
        guid1=NewGuid
        guid2=NewGuid
    </script>
    <code language="Delphi" context="any" delimiter="|">    <![CDATA[I|name|Accessors = interface(IInterface)
|*||guid1|
end;

I|name| = interface(I|name|Accessors)
|*||guid2|
end;]]>
    </code>
    </template>
</codetemplate>

NewGuidScriptEngine.pas:

unit NewGuidScriptEngine;

interface

uses
  Classes, SysUtils,
  ToolsApi, CodeTemplateApi, DesignEditors;

type
  TNewGuidScriptEngine = class(TNotifierObject, IOTACodeTemplateScriptEngine)
  public
    procedure Execute(const ATemplate: IOTACodeTemplate; const APoint: IOTACodeTemplatePoint; const ASyncPoints: IOTASyncEditPoints; const AScript: IOTACodeTemplateScript; var Cancel: Boolean);
    function GetIDString: WideString;
    function GetLanguage: WideString;
  end;

procedure Register;

implementation

uses
  ActiveX,
  ComObj;

procedure Register;
begin
  (BorlandIDEServices as IOTACodeTemplateServices).RegisterScriptEngine(TNewGuidScriptEngine.Create);
end;

procedure TNewGuidScriptEngine.Execute(const ATemplate: IOTACodeTemplate; const APoint: IOTACodeTemplatePoint;
  const ASyncPoints: IOTASyncEditPoints; const AScript: IOTACodeTemplateScript; var Cancel: Boolean);
var
  I: Integer;
  Guid: TGUID;
  P: IOTACodeTemplatePoint;
  Points: TStringList;
begin
  Cancel := False;
  if not Assigned(ATemplate) then
    Exit;

  Points := TStringList.Create;
  try
    Points.Text := AScript.Script;
    for I := 0 to Points.Count - 1 do
      Points.Strings[I] := Trim(Points[I]);

    for I := 0 to Points.Count - 1 do
      if Points.ValueFromIndex[I] = 'NewGuid' then
      begin
        P := ATemplate.FindPoint(Points.Names[I]);
        if Assigned(P) then
        begin
          OleCheck(CoCreateGuid(Guid));
          P.Editable := False;
          P.Value := '[''' + GUIDToString(Guid) + ''']';
        end;
      end;
  finally
    Points.Free;
  end;
end;

function TNewGuidScriptEngine.GetIDString: WideString;
begin
  Result := 'OndrejKelle.NewGuidScriptEngine';
end;

function TNewGuidScriptEngine.GetLanguage: WideString;
begin
  Result := 'NewGuidScript';
end;

end.

Put the above unit into a designtime-only package, add a reference to designide.dcp to its requires clause and install the package in the IDE.

Another useful, similar template might look like this:

<?xml version="1.0" encoding="utf-8" ?>
<codetemplate   xmlns="http://schemas.borland.com/Delphi/2005/codetemplates" version="1.0.0">
<template name="iacc" surround="false" invoke="manual">
    <point name="name">
        <text>
        </text>
        <hint>
            Accessors name
        </hint>
    </point>
    <point name="guid1"/>
    <point name="guid2"/>
    <description>
        accessor declaration
    </description>
    <author>
        PMH
    </author>
    <script language="NewGuidScript" onvalidate="true">
        guid1=NewGuid
        guid2=NewGuid
    </script>
    <code language="Delphi" context="any" delimiter="|">    <![CDATA[const
  SIID_I|name|Accessors = |guid1|;
  IID_I|name|Accessors: TGUID = SIID_I|name|Accessors;
  SIID_I|name| = |guid2|;
  IID_I|name|: TGUID = SIID_I|name|;

type
  I|name|Accessors = interface
    [SIID_I|name|Accessors]
  end;

  I|name| = interface(I|name|Accessors)
    [SIID_I|name|]
  end;]]>
    </code>
    </template>
</codetemplate>

This would declare string as well as TGUID constants and also reuse them in the interface declarations. In this case, the inserted GUID values should not be enclosed in square brackets. You have several options to adjust the scripting engine to do this:

  1. modify the code to just not use the square brackets
  2. introduce a separate new function NewGuidNoBrackets and use it in the template
  3. introduce some simple syntax like NewGuid(false) which your engine could parse and use the parameter value to determine if square brackets should be used or not.
like image 74
Ondrej Kelle Avatar answered Sep 18 '22 17:09

Ondrej Kelle