Delphi macro power tip: Moving to end-of-word

Today’s Delphi-macro power tip: moving the cursor to the end of the current word.

This isn’t an everyday need, but it comes up from time to time, and there’s not an immediately obvious way to do it. But it’s easy if you know the trick.

The big problem here is that Ctrl+Right arrow won’t work, because it moves to the beginning of the next word, not the end of this word. Sometimes you know what you expect the line to look like, and know you can just hit Left arrow twice and be where you want; but then again, sometimes you’d really rather just go to end-of-word and be done with it.

Here’s the trick: Ctrl+K, T, Right arrow, Left arrow.

Ctrl+K T selects the word under the cursor — it’s just like double-clicking. And the cursor is left at the end of the selection. So the cursor is left at the end of the word, right where you want it; all you need to do is clear the selection, which is easily accomplished by hitting Right and then Left.

Using macros as a second clipboard

This isn’t really either a macro recipe or a power tip, but it’s a useful trick.

Sometimes I’ll run into a situation where I want two different things on the clipboard at once. Maybe I’m passing a filename through several layers of methods, and at each layer, I’m typing

; AFileName: string

twice (once in the class declaration, once in the method implementation), and

, AFileName

once (where the value needs to be passed along to the next guy). Wouldn’t it be nice if I had two clipboards, each with its own “paste” keystroke?

Once you think to use a macro as the second “clipboard”, it’s trivial. Select ; AFileName: string and copy it to the clipboard; then start recording a macro, type , AFileName, and stop recording.

Voila — two clipboards. Paste one with Ctrl+V, and the other with Ctrl+Shift+P.

Saving macros for later

Several people clued me in on a couple of ways to save macros for later. I haven’t had a chance to try either one yet (so someone correct me if I say something wrong about either), but they both sound great — and both are open-source.

(I’m really curious how they do it… I should look at their code sometime.)

GExperts Macro Library

GExperts includes a dockable Macro Library window. It lets you have multiple macros, lets you assign names and descriptions to them, and automatically saves them when you close the IDE.

I’m not sure where it saves them, though. This would be terrific if we could save them in revision control somehow — otherwise, with eight development machines, the macro I want would inevitably be on one of the other computers.

Keyboard macro manager on CodeCentral

TOndrej wrote a keyboard macro manager that you can compile into a design-time package and register in the IDE.

This one definitely can save the macros to a file, so could probably be used to share macros between computers.

Delphi macro power tip: Start of line

Today’s Delphi-macro power tip: getting to the start of a line — for several different definitions of “start”.

This is most useful for macros that operate on a single line at a time, but it can sometimes be helpful in other sorts of macros as well.

Example

The Fields to Properties macro recipe starts with Home, followed by Ctrl+Right arrow.

Column 1

What “start of line” means will depend on what your macro does. Sometimes you just want to get your cursor to the beginning of the line. For this, plain old Home is what you want.

First alphanumeric character

Sometimes you want to get the cursor to the first non-blank character on the line. Unfortunately, I don’t know an easy way to do this in all cases.

But often, it’s good enough to get to the first alphanumeric character on the line. This worked well enough for the Fields to Properties macro recipe.

To do this, just do Home followed by Ctrl+Right arrow.

The downside is, if the line starts with punctuation — an open parenthesis, for example — Ctrl+Right arrow will skip right past it. This isn’t always what you want, and I don’t know of a clean and reliable way to get to the first non-whitespace character. But there are several things that can get you close.

Column N

Never underestimate the simplest thing. If, for every line you’ll be operating on, the interesting stuff will always start in column 5, don’t be afraid to do Home followed by pressing Right arrow four times. It sounds silly, but sometimes it’s just what you need.

Correcting after Ctrl+Right arrow

If you know that every line is going to start with an open parenthesis, followed immediately by an alphanumeric character, then simply do Home, Ctrl+Right arrow, and then correct for it with Left arrow to put the cursor before the parenthesis.

If you don’t know that every line will have that open parenthesis, then do whatever you think will get you closest most of the time — probably Home followed by Ctrl+Right arrow — but do it at the end of the macro, not the beginning. Then you can adjust the cursor position as necessary before you hit Ctrl+Shift+P.

Deleting leading whitespace

Okay, I do know of one way to put the cursor just before the first non-space character on the line, even if it’s punctuation. You don’t do it by moving the cursor — instead, you do it by moving the text, by deleting the leading whitespace! If you’re radically rewriting the line, sometimes you can get away with this.

If you know the line has leading whitespace, do Home followed by Ctrl+T.

I love Ctrl+T. It’s called “delete to end of word”, and it deletes everything from the current cursor position, through the end of the current word, plus any whitespace following it. It’s kind of like Ctrl+Shift+Right arrow followed by Delete, with one very interesting exception: unlike Ctrl+Right arrow, Ctrl+T stops at punctuation. So Ctrl+T, at the beginning of a line, will delete only the whitespace.

One catch is that, if you end up with a line that doesn’t have leading whitespace, you’ll delete the first word in the line! To avoid that, add whitespace first (yes, it’s cheesy, but it works): Home, Space bar, Home again (or Left arrow), then Ctrl+T.

Delphi macro power tip: Advance last

Today’s Delphi-macro power tip:

Your macro should usually end with something that advances the cursor.

Important note: This only applies when you trust the macro to do what you want it to do. If you’re not sure you got it right, then you should advance the cursor manually between playbacks. But if you’re pretty confident that you did it right, this tip will speed you up greatly.

Example

Take a look back at the Fields to Properties macro recipe. The last step, before ending the macro recording, was pressing Down arrow.

Why?

You wouldn’t record a macro for something you only do once. The whole point is to do something to the code, then do it again somewhere else.

If you can automate the thing about finding the next “somewhere else”, then playing back is much faster. You can just hit Ctrl+Shift+P repeatedly.

Why at the end?

So it makes sense to put cursor advancement inside the macro. Why at the end, rather than at the beginning?

You can do either, but I’ve found that putting it at the end usually works better, because you can see the next place it’s going to run, before you run it.

Let’s say you’re transforming a long list of field declarations into properties. What if there are comments in the middle of that list? Your macro probably won’t do the right thing if you run it on a comment line. But if you advance at the end, there’s no problem: after you play the macro on the previous line, you’ll see that the cursor is now on a comment line. All you need to do is press Down arrow before you hit Ctrl+Shift+P again.

If you advanced the cursor at the beginning of the macro, the editor window might not have scrolled the next line into view yet (especially true if you’re operating on multi-line constructs). And if you’re moving by an irregular amount (e.g., with F3), you might not even know the next place it’s going to play back. So all you can do is hit Ctrl+Shift+P, realize that it screwed up, hit Undo, figure out where you need to move the cursor so it’ll be in the right spot after it advances, and try again. Advancing at the end is just simpler.

Advancing at the end also makes it easy to tell when your work is done. If you’re operating on a list of fields, you stop hitting Ctrl+Shift+P as soon as you end up on a line that’s not a field anymore. When you advance at the beginning of the macro, it’s harder to tell when you’re done.

Horizontal vs. vertical

When you’re writing a line-oriented macro, you’ll generally have both horizontal and vertical positioning to do. Just because you do your vertical positioning at the end of the macro, doesn’t mean you need to do the horizontal positioning there as well.

It really comes down to confidence. If you know that, for every line you’ll be operating on, Home and Ctrl+Right arrow will get you to the place you want to start, then put the horizontal positioning at the beginning of the macro. But if you want to be able to see the horizontal position before you play back, put it at the end.

Doing it twice

If you do your horizontal positioning at the end of the macro, there is one downside: the horizontal positioning, at least, usually needs to be done twice. You need to get the cursor to the right spot before you start recording, and again at the end of the macro.

If your horizontal positioning was done with Home followed by Ctrl+Right arrow, the sequence would look like this:

  1. Press Home.
  2. Press Ctrl+Right arrow.
  3. Press Ctrl+Shift+R to start recording.
  4. Press Down arrow to move to the next line.
  5. Press Home.
  6. Press Ctrl+Right arrow.
  7. Press Ctrl+Shift+R to stop recording.

If you trust your horizontal positioning, then don’t bother repeating it; just put it at the start of the macro. It makes life a bit simpler.

Not just Down arrow

Ending with Down arrow only makes sense when you’re operating on a line at a time. If you’re writing a different kind of macro, you need a different kind of advancement.

  • If your macro operates on each value in a list (e.g., say you’re changing the Hungarian prefix on each value in an enum), you might end with Ctrl+Right arrow.
  • If your macro operates on a bunch of empty method bodies (e.g., say you’ve just Class Completed a bunch of methods, and want to insert code inside each one to throw an exception), you might end by pressing Down arrow five times — just the right amount to usually get you to the blank line in the next method body. You can always adjust the cursor before the next Ctrl+Shift+P if, for example, the next one is six lines away because its parameter list wrapped onto two lines.
  • If your macro operates on each place a particular method is called, you might end with F3. (Do your Find before you start recording the macro — it doesn’t work properly if you do a Find while you’re recording. But F3 — Find Next — works quite nicely in a macro.)

Delphi macros: on recipes and power tips

As I blog sporadically about Delphi macros, I’ll have two kinds of posts.

One will be recipes: detailed steps to get something done. Little or no theory — I won’t say much about why these particular steps. But I’ll talk about what the macro does, and when and why to use it. You’ve already seen this with my Fields to Properties macro recipe.

The other sort of post will be power tips. This is where I’ll dig into the theory and the building blocks — where I will get into “why these steps instead of something else”. When you would use Ctrl+Arrow and when something else would be better — that sort of thing. These are the things you can use to build your own power macros, and to tune the recipes to your needs.

Don’t be surprised if you also see some posts about when not to use macros — when some other IDE feature will serve you better. It’s all about the easiest way to get something done.

A complete list of all my macro-related posts — both recipes and power tips — is available through my blog’s “macros” tag.

The first power tips will be coming soon. As always, if you have questions or suggestions, fire away in the comments.

Delphi macro recipes: Fields to properties

Today I’m going to share a Delphi IDE macro that I record and use several times a week: transforming fields to properties.

The basic idea is: You’ve just added seven fields to your class, and you want to make properties for all of them.

Why not use Class Completion?

If you declare the property first, Class Completion will add the field (and, optionally, the setter as well) for you, right? So why use a macro instead?

First and foremost, Class Completion for properties is horribly, horribly broken in Delphi 2006 and in BDS 2007. We use strict private in our code, which means we run up into the Delphi bug that makes Class Completion unusable. It also tends to complete to the wrong class. And I’m sure there are other bugs that I just don’t remember, because I never use it. I’ve learned better than to complete properties.

A macro also gives you more control. It’s easy to tune it to make read-only properties, or read and write the field with no SetXXX method. You can do that with Class Completion too (if you can get it to work), but you have to do extra typing for every property. With a macro, you just cut a swath through the code.

What it looks like

You start by copying your field declarations to the end of the public section (or wherever you want your properties to go). Then the macro transforms those field declarations into property declarations.

For today’s example, we’ll do read-only properties. So this:

FFoo: Integer;
FBar: string;
FBaz: TPoint;

will become:

property Foo: Integer read FFoo;
property Bar: string read FBar;
property Baz: TPoint read FBaz;

Note some limitations. With imagination, you can get around some of these, but the simple recipe I’ll give here won’t deal with anything complex.

  • You need one complete field declaration per line. This won’t deal with FFoo, FBar: Integer;.
  • It won’t turn array declarations into indexed properties, or anything uber-fancy like that. You need to write a method to make that work, and this is simple text transformation, not code generation.
  • This assumes no comments on the same line with the variable declarations.
  • The steps, as written, assume that you follow the Delphi convention of prefixing field names with F. If you have some other convention, alter the steps accordingly.

So, nothing too fancy. But macros make short work of simple, repetitive stuff. Let’s get started.

The setup

Highlight the lines with your field declarations. Copy them. Paste where you want your properties to end up (usually the end of one of the visibility sections, e.g. at the end of the public section).

Now put the cursor back on the first line you pasted. The macro will transform each line into a property declaration, then move to the next line.

The macro

  1. Press Ctrl+Shift+R to start recording.
  2. Press Home to go to the beginning of the line.
  3. Press Ctrl+Right arrow to go to the beginning of the field name.
  4. Press Ctrl+K, T to select the field name.
  5. Press Ctrl+C to copy the field name to the clipboard.
  6. Press Ctrl+Left arrow to go back to the beginning of the field name.
  7. Press Del to delete the F off the beginning of the field name.
  8. Type property and hit the Space bar.
  9. Press End to move to the end of the line, just after the semicolon.
  10. Press Left arrow to move just before the semicolon.
  11. Type Space bar, read, Space bar.
  12. Press Ctrl+V to paste the field name.
  13. Press Down arrow to move to the next line.
  14. Press Ctrl+Shift+R to stop recording.

Of course, with macros, you always do the first one by hand. The first line should now be a property declaration just like you wanted.

Now press Ctrl+Shift+P to play back the macro. The next line will be transformed from a field declaration into a read-only property declaration. Keep hitting Ctrl+Shift+P, and you’re in business.

One last cute trick: If there’s a line you want to skip — maybe you copied some comment lines along with the variable declarations — just hit Down arrow before your next Ctrl+Shift+P.