Skip to content

Commit f889c3e

Browse files
committed
Incorporate feedback and suggestions
1 parent cc7e7c8 commit f889c3e

File tree

1 file changed

+161
-21
lines changed

1 file changed

+161
-21
lines changed

text/0000-code-literals.md

+161-21
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
[summary]: #summary
88

99
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.
1112

1213
# Motivation
1314
[motivation]: #motivation
@@ -79,6 +80,12 @@ plays nicely with `rustfmt`.
7980
of using an `\` at the end of each line cannot be applied
8081
because escape characters are not recognised.
8182

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+
8289
# Guide-level explanation
8390
[guide-level-explanation]: #guide-level-explanation
8491

@@ -92,10 +99,10 @@ of string literal exists: code string literals.
9299
I can use special characters like "" and \ freely.
93100

94101
Indentation is preserved *relative* to the indentation level
95-
of the first line.
102+
of the terminating triple backticks.
96103

97104
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
99106
the line is empty.
100107
```;
101108
```
@@ -129,6 +136,15 @@ let code = ````
129136
````;
130137
```
131138

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+
132148
# Reference-level explanation
133149
[reference-level-explanation]: #reference-level-explanation
134150

@@ -139,35 +155,37 @@ to begin the literal.
139155
The value of the string literal will be determined using the following
140156
steps:
141157

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.
150167

151168
Here are some edge case examples:
152169

153170
```rust
154171
// Empty string
155172
assert_eq!(```foo
156-
```, "");
173+
```, "");
157174

158175
// Newline
159176
assert_eq!(```
160177

161-
```, "\n");
178+
```, "\n");
162179

163180
// No terminating newline
164181
assert_eq!(```
165-
bar```, "bar");
182+
bar
183+
!```, "bar");
166184

167185
// Terminating newline
168186
assert_eq!(```
169187
bar
170-
```, "bar\n");
188+
```, "bar\n");
171189

172190
// Preserved indent
173191
assert_eq!(```
@@ -179,15 +197,15 @@ Here are some edge case examples:
179197
assert_eq!(```
180198
if a:
181199
print(42)
182-
```, "if a:\n print(42)\n");
200+
```, "if a:\n print(42)\n");
183201

184-
// Relative to first non-empty line
202+
// Relative to closing backticks
185203
assert_eq!(```
186204

187205

188206
if a:
189207
print(42)
190-
```, "\n\nif a:\n print(42)\n");
208+
```, "\n\n if a:\n print(42)\n");
191209
```
192210

193211
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
229247
blocks. Experimentally, markdown parsers do not seem to have any
230248
problems with this (as demonstrated in this document).
231249

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+
232364
# Prior art
233365
[prior-art]: #prior-art
234366

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.
237377

238378

239379
# Unresolved questions
@@ -255,7 +395,7 @@ which is widely used and should be familiar to most programmers.
255395
```rust
256396
query!(```postgresql
257397
<query>
258-
```)
398+
```)
259399
```
260400

261401
could parse the query in a PostgreSQL specific way.

0 commit comments

Comments
 (0)