7
7
[ summary ] : #summary
8
8
9
9
Add a new kind of multi-line string literal for embedding code which
10
- plays nicely with ` rustfmt ` .
10
+ plays nicely with ` rustfmt ` and doesn't introduce unwanted whitespace
11
+ into multi-line string literals.
11
12
12
13
# Motivation
13
14
[ motivation ] : #motivation
@@ -79,6 +80,12 @@ plays nicely with `rustfmt`.
79
80
of using an `\` at the end of each line cannot be applied
80
81
because escape characters are not recognised .
81
82
83
+ - The existing string literals introduce extra unwanted whitespace
84
+ into the literal value . Even if that extra whitespace does not
85
+ semantically affect the nested code , it results in ugly output
86
+ if the code is ever logged (such as might happen when logging
87
+ SQL query executions ).
88
+
82
89
# Guide - level explanation
83
90
[guide - level - explanation ]: #guide - level - explanation
84
91
@@ -92,10 +99,10 @@ of string literal exists: code string literals.
92
99
I can use special characters like "" and \ freely.
93
100
94
101
Indentation is preserved * relative* to the indentation level
95
- of the first line .
102
+ of the terminating triple backticks .
96
103
97
104
It is an error for a line to have "negative" indentation (ie. be
98
- indented less than the indentation of the opening backticks) unless
105
+ indented less than the final triple backticks) unless
99
106
the line is empty.
100
107
```;
101
108
```
@@ -129,6 +136,15 @@ let code = ````
129
136
````;
130
137
```
131
138
139
+ In order to suppress the final newline, the literal may instead be
140
+ closed with ` !``` ` , eg.
141
+
142
+ ``` rust
143
+ let code = ```
144
+ Text with no final newline
145
+ ! ```;
146
+ ```
147
+
132
148
# Reference-level explanation
133
149
[ reference-level-explanation ] : #reference-level-explanation
134
150
@@ -139,35 +155,37 @@ to begin the literal.
139
155
The value of the string literal will be determined using the following
140
156
steps:
141
157
142
- 1 . Start from the first newline after the opening backticks.
143
- 2 . Take the string exactly as written until the closing backticks.
144
- 3 . Remove equal numbers of spaces or tabs from every non-empty line
145
- until the first character of the first non-empty line is neither
146
- a space nor a tab, or until every line is empty.
147
- Raise a compile error if this could not be done
148
- due to a "negative" indent or inconsistent whitespace (eg. if
149
- some lines are indented using tabs and some using spaces).
158
+ 1 . Measure the whitespace indenting the closing backticks. If a
159
+ non-whitespace character (other than a single ` ! ` ) exists before
160
+ the closing backticks on the same line, then issue a compiler error.
161
+ 2 . Take the lines * between* (but not including) the opening and
162
+ closing backticks exactly as written.
163
+ 3 . Remove exactly the measured whitespace from each line. If this
164
+ cannot be done, then issue a compiler error.
165
+ 4 . If the string was terminated with ` !``` ` , then remove the
166
+ final newline.
150
167
151
168
Here are some edge case examples:
152
169
153
170
``` rust
154
171
// Empty string
155
172
assert_eq! (```foo
156
- ```, "" );
173
+ ```, "" );
157
174
158
175
// Newline
159
176
assert_eq! (```
160
177
161
- ```, " \ n" );
178
+ ```, " \ n" );
162
179
163
180
// No terminating newline
164
181
assert_eq! (```
165
- bar ```, " bar" );
182
+ bar
183
+ ! ```, " bar" );
166
184
167
185
// Terminating newline
168
186
assert_eq! (```
169
187
bar
170
- ```, " bar\ n" );
188
+ ```, " bar\ n" );
171
189
172
190
// Preserved indent
173
191
assert_eq! (```
@@ -179,15 +197,15 @@ Here are some edge case examples:
179
197
assert_eq! (```
180
198
if a :
181
199
print (42 )
182
- ```, " if a:\ n print(42)\ n" );
200
+ ```, " if a:\ n print(42)\ n" );
183
201
184
- // Relative to first non-empty line
202
+ // Relative to closing backticks
185
203
assert_eq! (```
186
204
187
205
188
206
if a :
189
207
print (42 )
190
- ```, " \ n\ n if a:\ n print(42)\ n" );
208
+ ```, " \ n\ n if a:\ n print(42)\ n" );
191
209
```
192
210
193
211
The text between the opening backticks and the first newline is
@@ -229,11 +247,133 @@ interfere with the ability to paste Rust code snippets into such
229
247
blocks. Experimentally, markdown parsers do not seem to have any
230
248
problems with this (as demonstrated in this document).
231
249
250
+ ## A list of all options regarding syntax
251
+
252
+ ### Quote style
253
+
254
+ - ** 3+N backticks**
255
+ ``` rust
256
+ let _ = ```
257
+ some code
258
+ ```;
259
+ ```
260
+
261
+ - * * 3 + N double - quotes **
262
+ ```rust
263
+ let _ = """
264
+ some code
265
+ """ ;
266
+ ```
267
+
268
+ - * * 3 + N single quotes **
269
+ ```rust
270
+ let _ = '''
271
+ some code
272
+ ''' ;
273
+ ```
274
+
275
+ - * * Word prefix + N + 1 hashes **
276
+ ```rust
277
+ let _ = code #"
278
+ some code
279
+ " #;
280
+ ```
281
+
282
+ - * * Single character prefix + N + 1 hashes **
283
+ ```rust
284
+ let _ = m #"
285
+ some code
286
+ " #;
287
+ ```
288
+ (note : `c ` is already reserved for C strings )
289
+
290
+ ### Indentation rules
291
+
292
+ - * * Relative to closing quote + retain final newline **
293
+
294
+ Benefits :
295
+ - Allows every possible indentation to be represented .
296
+ - Simple rule .
297
+ - The value of the string is obvious and intuitive .
298
+
299
+ Drawbacks :
300
+ - It is not possible to represent strings without a trailing newline .
301
+
302
+ - * * Relative to closing quote + remove final newline **
303
+
304
+ Benefits :
305
+ - Allows every possible indentation to be represented .
306
+ - Simple rule .
307
+ - Strings without a final newline can be represented .
308
+
309
+ Drawbacks :
310
+ - There are two ways to represent the empty string .
311
+ - It is unintuitive that two empty lines between quotes results in
312
+ a single newline .
313
+
314
+ - * * Relative to first non - empty line **
315
+
316
+ Benefits :
317
+ - Simple rule .
318
+ - The value of the string is obvious and intuitive .
319
+ - Strings without a final newline can be represented .
320
+
321
+ Drawbacks :
322
+ - Some indentations cannot be represented .
323
+
324
+ - * * Relative to least indented line **
325
+
326
+ Benefits :
327
+ - Simple rule .
328
+ - The value of the string is obvious and intuitive .
329
+ - Strings without a final newline can be represented .
330
+
331
+ Drawbacks :
332
+ - Some indentations cannot be represented .
333
+
334
+ ### Miscellaneous
335
+
336
+ - * * Language hint directly following opening quote **
337
+
338
+ This is intended to allow extra information (eg . language ) to be
339
+ conveyed by the programmer to macros and / or their IDE . For example :
340
+ ```rust
341
+ let _ = ```sql
342
+ SELECT * FROM table ;
343
+ ```;
344
+ ```
345
+ Here , an intelligent IDE could apply syntax highlighting to the nested
346
+ code block , knowing that the code is SQL .
347
+
348
+ - * * Annotation on closing quote to remove trailing newline **
349
+
350
+ For indentation rules where the final quote must appear on
351
+ its own line and there is no way to represent a string without
352
+ a trailing newline , a modification character could be used .
353
+
354
+ For example :
355
+ ```rust
356
+ let _ = ```
357
+ no trailing newline
358
+ ! ```;
359
+ ```
360
+ This could be used with any quote style and is unambiguous because
361
+ nothing can otherwise appear on the same line prior to the closing
362
+ quote .
363
+
232
364
# Prior art
233
365
[prior - art ]: #prior - art
234
366
235
- The proposed syntax is primarily based on markdown code block syntax,
236
- which is widely used and should be familiar to most programmers.
367
+ The proposed quote style is primarily based on markdown code block syntax ,
368
+ which is widely used and should be familiar to most programmers . This is
369
+ also where the language hint comes from .
370
+
371
+ The indentation rules are borrowed from [Perl 's " Indented Here-docs" ](https : // perldoc.perl.org/perlop#EOF) and [PHP's "Heredoc" syntax](https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc)
372
+
373
+ The [`indoc ` crate ](https : // docs.rs/indoc/latest/indoc/) exists to remove
374
+ leading indentation from multiline string literals . However , it cannot
375
+ help with the reformatting done by `rustfmt `, and is generally not understood
376
+ by IDEs .
237
377
238
378
239
379
# Unresolved questions
@@ -255,7 +395,7 @@ which is widely used and should be familiar to most programmers.
255
395
```rust
256
396
query! (```postgresql
257
397
<query>
258
- ```)
398
+ ```)
259
399
```
260
400
261
401
could parse the query in a PostgreSQL specific way.
0 commit comments