Today I'll release a Vim script I wrote a few weeks ago (and have been planing to write for a long time). What it does is enable fast typing of idiomatic things like for loops, STL container declarations etc. The philosophy behind using a script like this is in line with the general philosophy of Vim, which is to make editing as fast as possible (fewest keystrokes to achieve a result). Also, writing idiomatic code is known to be error prone (ever typed ++i in an inner loop instead of ++j?) and is definitely tedious.
Another reason for writing this script are TopCoder competitions. Unlike most algorithm competitions, at TopCoder speed is a big factor. You only have 75 mintes to solve 3 problems (of increasing difficulty) and your submissions are timed from the moment you open the problem statement. Also, there is no partial credit for problems. After the coding phase, there's a short intermission and then a 15 minute challenge phase where other coders get a chance to view your source code and construct legal inputs that will break it (thus getting additional points for themselves and bringing your point total for that problem to 0). Finally, if your code survives the challenge phase, it has to pass all the automated system tests (some of which are "random", and some of which are specifically constructed to trip up wrong approaches). Some people at TopCoder use macros to achieve pretty much the same effect as this script. The main problem I have with this option is that it makes the code look ugly (sort of obfuscated). This makes it unnecesarilly hard for other people to challenge (although that's probably not the main intention) and, more importantly, it's bad style. Of course, using this script (or the macro method) probably won't increase your TopCoder rating; TopCoder algorithm competitions are primarily about quicky inventing (or applying) the correct algorithm, and the implementing it correctly and with reasonable efficiency. Still, being able to type code faster is always a good thing :).
So let me finally give you a short tour of what exaclty the script does (for the full list, see the comment on top of the file). The current functionality can be seperated into two groups: loop/block expansion and containers and type expansions.
Very often, you'll want to loop through an STL container, or repeat something n times. To do this, you'll write something like this:
for (int i=0; i<(int)my_vec.size(); ++i) {
// per-item code goes here
}
Note that in "real" code you might use
size_t
or, better yet, vector<int>::size_type
. Also notice the int
cast on the container size. Comparing a signed to an unsigned value is not entirely safe in C++ (The int
gets converted to an unsigned
(assuming vector<int>::size_type
is size_t
and size_t
is a typedef
for unsigned
, as is common on PCs) in what is called the usual arithmetic conversions. This can cause problems if the value of the int
is negative, in which case, on a 2s complement machine, becomes a positive number and you get the "wrong answer".). Still, in idiomatic code like this, using a cast is an OK option IMO.Anyway, to write the above loop with this script, you'd write:
@f i #my_vec
and press <F2> (I'll talk about the keyboard mappings in a sec). Vim will then expand the line to the above code (without the
// per-item code goes here
comment, of course :) and (if you were in insert mode) position the cursor at the "right" place (one indent level inside the block) so you can continue hacking.If you want to loop to a value (or variable), and not trough a container, you'd write something like this:
@f i n
and get
for (int i=0; i<n; ++i) {
}
You probably guessed it, but the general syntax is:
@f index_var_name upper_limit
Where the upper limit can be preceded by a
#
to produce the size of a container.If you want the loop condition to be less than or equal, prefix the upper limit with an equals sign like:
@f index_var_name =upper_limit
There's also a version that lets you specify a non-zero lower limit
@f index_var_name lower_limit upper_limit
and versions for looping downward
@fd index_var_name [lower_limit] upper_limit
(the square brackets indicate that the
lower_limit
is optional).Finally, there are similar expressions for
while
and do-while
loops, as well as for if
branches:
@w expression
@d expression
@i expression
Finally, there is also support for
for
loops with iterators through containers. The syntax for this is (I'll explain what <container_expression>
and <expanded_container_expression>
are in the next paragraph):
@iter iter_name <container_expression> container_name
which generates
for (<expanded_container_expression>::iterator iter_name=container_name.begin(); iter_name!=container_name.end(); ++iter_name) {
}
There's also a
@iterc
version that generates a ::const_iterator
iteration.The second part of the functionality is container and type expansions. Basically, for:
@vi
(and <F2>) you get:
vector<int>
This works in all parts of the line (except in double quotes and comments), unlike the loop/block expansions that only work on the start of lines (modulo whitespace characters). I won't list all the supported expansions, but all the
vector
, set
, map
and pair
that I tend to use frequently are supported. A few examples:
@vvi
@sd
@msi
@pllll
expands to:
vector< vector<int> >
set<double>
map<string, int>
pair<long long, long long>
Keyboard mappings are defined at the end of the script (so you can easily change it, if you like).
nmap <F2> :call BudaCppExpand()<Enter>
imap <F2> <Esc>:call BudaCppExpand()<Enter>A
I have some further ideas that I'm going to add in the short term. Since this post has gotten very long, I won't discuss them here except to say that you can read about them in the comment on top of the script :).
One important thing in Vim is making a habit out of things (so you don't have to think about whether or not you're going to press 'i' or 'a' or 'A' etc.). Since this script is pretty new I still haven't really gotten into the habit of using it as much as I'd like, but I'm trying :).
Without further ado, you can get the script here. To use it, you can put it into the ftplugins Vim directory.
If you find the script useful, have any suggestions about improvements and possible further additions or find a bug, please let me know!
Edit:
While writing this post, I noticed that it might be useful (and in line with the style of the script) to be able to expand things after
} else
to form if/else
blocks properly which wasn't possible with the version I posted. I fixed that now so you should be able to do things like
if (a > b) {
// do something
} else @i a+b+c > 42
and get it expanded into
if (a > b) {
// do something
} else if (a+b+c > 42) {
}
1 comments:
Congratulation for the great post. Those who come to read your Information will find lots of helpful and informative tips. Pedicure Kits online
Post a Comment