-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathmacros.vroom
196 lines (165 loc) · 4.34 KB
/
macros.vroom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
Sometimes you may find yourself repeating similar chunks of vroom code across
different tests. For example, let's write some tests for the 'cindent' feature:
Enter a small, unindented function
% void func()<cr>
% {<cr>
% if (true) {<cr>
% printf("hello\n!");<cr>
% }<cr>
% }<cr>
Enable cindent and set tabstop and shiftwidth to 2
:set cin ts=2 sw=2 et
> gg=G
Now function should have a 2-space indentation:
void func()
{
if (true) {
printf("hello\n!");
}
}
&
@end
@clear
Now let's test cindent again, but with another value for ts/sw. To make sure
the previous indentation won't affect this one, we start with a clear buffer:
% void func()<cr>
% {<cr>
% if (true) {<cr>
% printf("hello\n!");<cr>
% }<cr>
% }<cr>
:set cin ts=4 sw=4 et
> gg=G
void func()
{
if (true) {
printf("hello\n!");
}
}
&
@end
@clear
The above pattern of writing tests can generalized like this:
- Start with a clear buffer
- Input some text
- Call a function or command with some parameters
- Verify if the buffer is in a expected state
- Repeat but with a different set of parameters
Macros can be used to create reusable chunks of vroom code and help reduce
boilerplate across tests. Let's rewrite the above test using macros:
@macro (input_unindented_function)
% void func()<cr>
% {<cr>
% if (true) {<cr>
% printf("hello\n!");<cr>
% }<cr>
% }<cr>
@endmacro
The above defined a macro named 'input_unindented_function' that takes care of
entering an unindented function in the current buffer.
&
@end
As you can see, the buffer wasn't modified. The macro can be "executed" with
a @do directive:
@do (input_unindented_function)
void func()
{
if (true) {
printf("hello\n!");
}
}
&
@end
Now indent and verify output
:set cin ts=4 sw=4 et
> gg=G
void func()
{
if (true) {
printf("hello\n!");
}
}
&
@end
@clear
A cool thing about macros is that the lines between the @macro/@endmacro
directives can contain python format string syntax(the same syntax used by
str.format()). For example:
@macro (greet)
% hello {subject}<cr>
@endmacro
@do (greet, subject='world')
@do (greet, subject='vroom')
hello world
hello vroom
&
@end
@clear
That means we can generalize even the cindent verification:
@macro (indent_and_verify)
:set cin ts={count} sw={count} et
> gg=G
void func()
{{
{fill:{count}}if (true) {{
{fill:{count}}{fill:{count}}printf("hello\n!");
{fill:{count}}}}
}}
Notice how any braces that are part of the output need to be escaped. This is
only necessary when the macro is executed with arguments.
&
@endmacro
Let's split into two macros to improve readability:
@macro (verify)
void func()
{{
{indent}if (true) {{
{indent}{indent}printf("hello\n!");
{indent}}}
}}
&
@endmacro
@macro (indent_and_verify)
Notice how macros can be redefined at any time
:set cin ts={count} sw={count} et
> gg=G
@do (verify, indent='{fill:{count}}')
@endmacro
After the macro is defined we can easily test cindent for multiple ts/sw
values. The keyword arguments passed to @do can contain simple python
expressions:
@do (input_unindented_function)
@do (indent_and_verify, fill=' ', count=2)
@clear
@do (input_unindented_function)
@do (indent_and_verify, fill=' ', count=4)
@clear
Since macros can contain `@do` directives, the test can be simplified even
further:
@macro (test_cindent)
@do (input_unindented_function)
@do (indent_and_verify, fill=' ', count={width})
@clear
@endmacro
@do (test_cindent, width=2)
@do (test_cindent, width=4)
@do (test_cindent, width=6)
@do (test_cindent, width=8)
It's important to understand parsing macro contents is delayed until a
corresponding @do directive is found:
@macro (insert_or_verify)
{prefix}some text
@endmacro
Input the text
@do (insert_or_verify, prefix='% ')
@do (insert_or_verify, prefix='')
@clear
Finally, macro names can contain spaces for more descriptive names:
@macro (test cindent for arbitrary widths)
@do (test_cindent, width={width})
@endmacro
@do (test cindent for arbitrary widths, width=2)
@do (test cindent for arbitrary widths, width=4)
@do (test cindent for arbitrary widths, width=8)
For more details about python format syntax, see:
https://docs.python.org/2/library/string.html#format-string-syntax