Brian Long Consultancy & Training Services
Code Templates were added into Delphi 3 and C++Builder 3 way back in 1998 along with the other original Code Insight features, all to help boost programmer productivity. The other features added as part of Code Insight originally were, in addition to Code Templates:
Code Templates were often overlooked, but they were eventually supercharged into Live Templates (though sometimes still called Code Templates in the documentation) and became all the more powerful.
However, Code/Live Templates are still often overlooked. This article will look at the original Code Templates and the newer Live Templates and try to encourage those who don't make their own Live Templates to have a go at it. They can be a real boon!
Code Templates were, in some senses, the poor cousin of the Code Insight feature family - they were often forgotten thanks to the not particularly memorable shortcut keystroke assigned to them: Ctrl+J
Here's what you see in an old version of Delphi when you press Ctrl+J, Delphi 5 in this case.
Selecting one of the Code Templates enters it into the code editor at the cursor point. Some Code Templates have the notion of an end point - they leave the cursor at the appropriate point where you would naturally next want to type something (you can see the cursor left in this fashion in the following screenshot).
If you know the name of your target Code Template you can enter that, or the first few characters of it, and the Code Template list will be filtered down to show just those starting with what you enter.
If you enter the full name or enough so only one Code Template could apply then there will be no context menu - the Code Template will be directly applied.
Looking at the Code Insight configuration options with (in vintage versions of Delphi) Tools, Editor Options... we can see an option to control an additional feature added in Delphi 4 (Tooltip Symbol Insight, since superceded by Help Insight), as well as the area that allows customisation of the Code Templates.
The selected template is called casee and represents a case statement replete with the optional else part. Notice the pipe sign in the code template that controls the end point, instructing Delphi where to leave the cursor after the Code Template has been inserted.
This editing area in the editor options dialog is quite handy but you can equally edit the Code Templates in their definiton file, which can be found in the file delphi32.dci in the bin directory of older Delphi installations, e.g. C:\Program Files\Borland\Delphi5\Bin\delphi32.dci in the case of Delphi 5.
To see what it looked like, the section of the file pertaining to the casee Code Template looks like this:
As you can see it's quite a straightforward syntax.
It was quite trivial to add in new code templates for commonly written snippets of Delphi code. Let's say you want to simplify the process of invoking a message dialog. You could define a new Code Template called msgdlg that enters most of it for you:
Define it like this so it contains the common aspects of each call to MessageDlg:
Code Templates were simple, convenient and helpful. Apparently, though, they weren't enough - with Delphi 2006 they were supercharged and became known as Live Templates, as we'll see in the next section.
Live Templates do the same basic job as Code Templates.... and then some. They are still designed to type things in for you and thereby aid coder productivity. Some notable additional features available with Live Templates include:
When introduced, the documentation for Live templates was quite underwhelming, and various people commented on this situation, such as Marco Cantu here. Live Templates are much better documented now than the years after their introduction, as exemplified by this very useful DocWiki page on Live Templates added for Delphi XE2.
The list of Live templates is notably larger that that of the old Code Templates. Periodically the list is extended with new Live templates, for example there were a couple of new Live Templates added to Delphi/C++Builder 2010 and a swathe of Live Templates added to Delphi/C++Builder XE.
Here is the aforementioned Templates window in Delphi/C++Builder 10.1 Berlin docked, as is default, alongside the Tool Palette window. You can see this installation of RAD Studio does not include C++Builder, as the Templates available are subdivided into Delphi, HTML, IDE and XML - no hint of C/C++. That was just an issue of space in this VM - I use C++Builder regularly on several client projects, but not from within this VM.
Here is the same window undocked and stretched a bit so we can see the default list of Delphi templates.
When the Templates window is on display while you are working in the editor, the Filter toolbutton can be used to ensure you only see Live Templates designed for the language you are working with, say Delphi or C/C++. In the earlier screenshot the designer was visible, so there was no filtering despite the Filter toolbutton being pressed.
If you hover over a Live Template in the Templates window it will show you the definition of that Live Template. This all looks a bit odd, but the curious syntax is to do with the jump points mentioned earlier.
If we invoke this ifnil Live Template, either by pressing Ctrl+J, or by entering ifnil and pressing the space bar (this is an automatic Live Template so this will work), or by double-clicking ifnil in the Templates window, then we are presented with the following. Notice the SyncEdit icon sat in the editor gutter. if you are familiar with use of SyncEdit (Ctrl+Shift+J) then this will be very familiar.
The first jump point is highlighted. You can enter the variable name here and any jump points with a matching value will be kept in sync with the variable name.
You can then press Tab and you move to the next (different) jump point. Similarly Shift+Tab moves you backwards through the jump points.
When all the different jump points have been exercised another press of Tab will leave the cursor where specified, if at all.
By the way, the IDE is set up by default to not display Live Template hints. Each of the jump points can have a hint defined, but they do not show up with the default configuration. It is necessary to go into the IDE options (Tools, Options...), scroll down the tree of option categories and select Environment Options, Editor Options, Code insight and then put a check in the Hints checkbox under Code template completion.
Now we get this:
So far this is not a million miles away from what we know of Code Templates. So let's see something a bit more interesting.
The auto-invokable try Live template has a neat trick up its sleeve. When invoked we initially get this.
So far so exactly the same.
Once you have gone through the MyClass and Component jump points the Live template does something useful - it invokes Code Completion for you:
More impressive, however, is that when you leave the last jump point, the variable you create with the template is declared for you as a local!
The documentation on Live Templates does mention the half dozen script calls that can be invoked by a Live Template, and which template definition files make calls to them.
It is feasible to write an IDE package expert to implement additional script calls, and this is demontrated very ably by Adam Markowitz, Nick Hodges, Deepak Shenoy and Daniel Wischnewski in their posts from late 2005/early 2006. I won't be looking into the specifics of that niche area in this article.
Over and above regular Live Templates there is also a special subset of them that reside on a dedicated Surround submenu on the editor's context menu. These Surround Templates know how to wrap some code around the code currently selected in the editor.
This makes it a doddle to, say, set up a region around some code. You select the code and choose the region surround template:
Let's make a Live Template that simplifies entering in a call to MessageDlg, displaying a formatted string as its message.
Live Templates are defined in XML and are each stored in their own separate files. You can create a new Live Template by choosing File, New, Other..., selecting the Other Files category and choosing Code Template:
Alternatively you can use the relevant toolbutton on the Templates window:
If you really wanted you could also use the IDE Insight feature to chase it down. Press F6 or Ctrl+. and type in code template
When you create the new code template you get an XML file:
If you save the file you will quickly see that the location for user-defined Live Templates is %USERPROFILE%\Documents\Embarcadero\Studio\code_templates or, if you prefer, shell:Personal\Embarcadero\Studio\code_templates - both of these are equivalent and are valid to enter into the Windows Explorer address bar.
In contrast the Live templates supplied with the product are located in C:\Program Files (x86)\Embarcadero\Studio\18.0\ObjRepos\en\Code_Templates, with Delphi Live Templates being in the Delphi subdirectory.
First things first, let's name this template and fill in some of the other sundry items: description, language affinity and invocation type (this one will support auto-invocation with the auto but other valid values are manual and none).
While Delphi has been chosen as the language for this Live Template I might also use C for other Live Templates intended for use within C++Builder.
Now to define the template. The code you want to insert into the editor goes in the CDATA section. Let's start with the simplest and least helpful option.
This example has been amended to enter a simple call to Format nested in a call to MessageDlg. It is true to say that this code is only sensible within the implementation of a method, which is why I also added the context attribute.
This is supposed to inform the template of the context of its usage. However it does not seem to stop the template being used anywhere, so it seems to be pretty much useless. I'd love to know what I'm missing about this... Is this a bug??!
You can find the list of available values supported by the code element's context attribute on Delphi Wikia and they are also represented by the TOTATemplateKind enumerated type in CodeTemplateAPI.pas in $(BDS)\source\ToolsAPI
So the Live Template now does a simple text insertion job but this is not really good enough. Something we don't have (that we had with the Code Template earlier) is the cursor being left in a sensible place after the Live Template is inserted. We can do this using a predefined point in the Live Template data called end. To specify a point it needs to be enclosed by delimiters.
The default delimiter is a $, so the point in question defaults to $end$. Since $ is something already used in Object Pascal to represent hexadecimal numbers it is common to redefine the delimiter to something else, typically a pipe sign, making this end point |end|.
So the next iteration of the Live Template looks like this:
The cursor is now left in the string value that is the first parameter to Format:
Another predefined point is for one level of indentation, which with the custom delimiter in use is |*| - this is the equivalent of highlighting the line and pressing Tab or Ctrl+K, Ctrl+I to indent by the Block Indent level as set in Tools, Options... in the Editor options, Source options category of settings. You can use as many of these indentation points as you wish.
When utilised this is entered as follows. You can see that from the insertion point in the editor, the second line is indented one level of block indentation further.
To further enhance this Live Template we could do with some jump points, which are implemented as custom points in the Live template definition.
It just so happens that there is a predefined Live Template that has affinity with XML, the file type we are editing, and it is for creating a new jump point. It's called point but since there is just one XML Live Template, pressing Ctrl+J will immediately invoke it without a context menu so we can use this to create jump points as and when we require them.
Anyway, here is the template fleshed out a little further:
So this has three custom points or jump points defined and also referenced, each of which has some starting text and a hint defined. Assuming you have Live Template hints enabled
When you tab from the first jump point to the second one, which is for the message box type, you can press Ctrl+Space to invoke Code Completion at your leisure, thereby making it easy to select a valid identifier from the TMsgDlgType enumerated type.
As an Alternative to requiring manual Code Completion invocation we could do as the predefined templates do and have our Live Template invoke it for you!
Here we are calling a Delphi script routine from the list of available offerings. Now when you use the Live Template it really tries to "hold your hand."
You can also build your own Surround Templates. For example, maybe you often want to wrap some code up in a conditional compilation so it executes only within a debug build.
The sensible first step is to open up a Live Template that does something vaguely similar. For example the Live Template named Surround Windows does the same sort of thing, but conditionalises for the Windows platform. If you select it from the Templates window and press the Edit code template toolbutton, or choose the Edit context menu you'll see this definition complete with its (currently) incorrectly typed author name:
If you've followed thus far this should look quite straightforward.
What we see here is yet another predefined point called selected along with the introduction of the template element's surround attribute. This attribute defaults to false, but when set to true the template appears in the editor's Surround context submenu.
So a Live Template like this will do the job. It will automatically appear in the editor's Surround context submenu and expedite the job of wrapping up debug code into a conditional block.
If you find yourself writing out the same old code snippets, or at least very similar snippets of code in Delphi or C++Builder, you should really consider investing a few moments to build a Live Template and help optimise the future cases where you want much the same sort of code. It's really not that hard at all :o)
Go back to the top of this page