Saturday, December 03, 2005

Creating a Script Template Engine for the Borland Developer Studio 2006

As you might already know, the new version of the Borland Developer Studio has "live templates," that allow you to get many coding tasks easily done. The react either automatically or manually at special keywords and fill in the gaps for you. Further, those live templates are completely done in XML and thus can be changed rather easily. Further, you can add scripts to those templates allowing you to invoke code completion, refactoring among many other feature of the IDE.

However, you can even write your very own template scripting engine, allowing you to further expand the power of those code templates. Thanks to Adam "Sparky" Markowitz, I have just done that. The source code can be downloaded at CodeCentral ID 23866. I will not indulge to much on the how-to here, as the source code comes with a readme and is fully commented.

Let's first take a look at what I have done. When the user enters "search" in the code editor and presses [Tab] or [Ctrl+J], the live template will be invoked automatically and tell him to enter the keywords to search for.
user input
enter keywords

Now, the user can enter his search keywords. Once he (or she) presses tab to leave the syncronization point, a script will be called which invokes my new template scripting engine and it will start an online search in the users default browser.
user search keywords
search results online

The template scripting engine can be accessed through the new IOTACodeTemplateScriptEngine interface, defined in the CodeTemplateAPI.pas file, which is in your sources folder of your Delphi 2006 installation. The whole source is online at Borlands CodeCentral (see link above). Below you can see the XML template (click for a larger view).
online search xml template


Anonymous Anonymous said...


2 minor recommendations:

1. It should probably be a 'manual' template since 'search' could conflict with any number of user declared variables, but that's just a preference of mine.

2. I'd recommend doing a UTF8Decode() on PointName when it's retrieved from the stringlist and then using WideSameText() instead of AnsiSameText() for comparing point names.

Great example Daniel! Keep'em comin'!


8:12 PM  
Blogger Daniel "sakura" Wischnewski said...

Hi Adam,

thanks :-) I have uploaded the changes as you've recommended them. More will come, that's sure and Delphi 2006 is definitely the right way to go!

8:42 PM  
Anonymous Anonymous said...

Rock on!

8:46 PM  
Anonymous Anonymous said...

Is it just me, or could we come up with a more interesting example? I cannot imagine why I would want to type an internet search command into the Delphi editor.

10:34 AM  
Blogger Daniel "sakura" Wischnewski said...

Hi Kristofer,

I know that the example itself is not really great, but all I wanted to show was how to do it. Starting with a scripting engine, which would really interpret some instructions was not the goal of this example ;-) That would be something worth a whole own topic besides the integration intpo the OTA of the BDS ;-)

So I hope this will give you a head start on how to integrate with the BDS templates.

10:41 AM  
Anonymous Anonymous said...


thanks very much for sharing your experience with script engines! With the help of your example I've already implemented my own little script enginge!
I have however a small problem with the code: whenever I recompile the package while it is already loaded I get an exception: "Registration procedure, Lwscriptengine.Register in package xxx.bpl raised exception class EAccessViolation: Access violation at address xxx in module 'rtl100.bpl'. Read of address xxx.
I've also tried to unregister the language in the finalization section, but that doesn't help. I also can't reinstall the package; I have to re-start Delphi!
Have you seen this error and by any chance do you know how to avoid the AV?

1:11 AM  
Blogger Daniel "sakura" Wischnewski said...

Hi Sebastian,

I actually had no problems with installing/reinstalling the IDE plugin. To my surprise, I could even recompile it while it was loaded. However, usually I start an instance without the plugin loaded, compile and install it (directly in the registry) and start a second instance for testing and debugging.

5:13 PM  
Anonymous Anonymous said...

Thanks for the Example.
For anyone looking, here is some code I added to support the scripting concept: ExtractToEOL();

begin |EOL| end; (Description)


For wrapping a single line in a
begin end without selecting it,
and invoking it the hard way.

Add this to Execute:
Function ExtractToEOL(): String;
Pos: IOTAEditPosition;
Block: IOTAEditBlock;

Pos := Services.TopView.Buffer.EditPosition;
Block := Services.TopView.Buffer.EditBlock;
Block.Visible := False;
Block.Style := btNonInclusive;
Result := Block.Text;

Then simply add CONST:
sExtract = 'ExtractToEOL';

Finally, in the code after
the clipboard code:
end else if Pos(sExtract, Str) > 0 then
begin // OnValidate ONLY
First := GetArg(Str, Delim);
Pt := ATemplate.FindPoint(First);
if Assigned(Pt) then
Pt.Value := ExtractToEOL();


5:18 AM  

Post a Comment

<< Home

Search WWW Search