Skip to content

Commit 6d60708

Browse files
committed
Allow a comment in code to explicitly configure the page width.
If the code being formatted contains a comment anywhere in it like: ``` // dart format width=123 ``` Then the code is formatted at that width instead of the default width. The intent is that tools that generate code and then format it will put this comment in the generated code. That way, the tool doesn't have to handle the complex logic to find a surrounding analysis_options.yaml file and get the user's project-wide page width configuration. End users may also want to use this comment in rare cases. For example, maybe they have a library that contains a large value of data that looks better as a big wide table but they don't want their entire project to have a wider page width.
1 parent f46aa31 commit 6d60708

File tree

4 files changed

+275
-1
lines changed

4 files changed

+275
-1
lines changed

lib/src/front_end/comment_writer.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,29 @@ import '../comment_type.dart';
4242
/// written. When that [TextPiece] is output later, it will include the comments
4343
/// as well.
4444
class CommentWriter {
45+
/// Regular expression that matches a format width comment like:
46+
///
47+
/// // dart format width=123
48+
static final RegExp _widthCommentPattern =
49+
RegExp(r'^// dart format width=(\d+)$');
50+
4551
final LineInfo _lineInfo;
4652

4753
/// The tokens whose preceding comments have already been taken by calls to
4854
/// [takeCommentsBefore()].
4955
final Set<Token> _takenTokens = {};
5056

57+
/// If we have encountered a comment that sets an explicit page width, that
58+
/// width, otherwise `null`.
59+
///
60+
/// The comment looks like:
61+
///
62+
/// // dart format width=123
63+
///
64+
/// If there are multiple of these comments, the first one wins.
65+
int? get pageWidthFromComment => _pageWidthFromComment;
66+
int? _pageWidthFromComment;
67+
5168
CommentWriter(this._lineInfo);
5269

5370
/// Returns the comments that appear before [token].
@@ -106,6 +123,14 @@ class CommentWriter {
106123
if (comment == token.precedingComments) linesBefore = 2;
107124
}
108125

126+
// If this comment configures the page width, remember it.
127+
if (_widthCommentPattern.firstMatch(text) case var match?
128+
when _pageWidthFromComment == null) {
129+
// If integer parsing fails for some reason, the returned `null`
130+
// means we correctly ignore the comment.
131+
_pageWidthFromComment = int.tryParse(match[1]!);
132+
}
133+
109134
CommentType type;
110135
if (text.startsWith('///') && !text.startsWith('////') ||
111136
text.startsWith('/**') && text != '/**/') {

lib/src/front_end/piece_writer.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ class PieceWriter {
399399

400400
var cache = SolutionCache();
401401
var solver = Solver(cache,
402-
pageWidth: _formatter.pageWidth, leadingIndent: _formatter.indent);
402+
pageWidth: _comments.pageWidthFromComment ?? _formatter.pageWidth,
403+
leadingIndent: _formatter.indent);
403404
var solution = solver.format(rootPiece);
404405
var output = solution.code.build(source, _formatter.lineEnding);
405406

test/tall/other/format_off.unit

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,134 @@ main() {
193193
unformatted + code + // dart format on
194194
after +
195195
region;
196+
}
197+
>>> "dart format off" whitespace must match exactly.
198+
main() {
199+
//dart format off
200+
unformatted + code;
201+
// dart format on
202+
203+
// dart format off
204+
unformatted + code;
205+
// dart format on
206+
207+
// dart format off
208+
unformatted + code;
209+
// dart format on
210+
211+
// dart format off
212+
unformatted + code;
213+
// dart format on
214+
}
215+
<<<
216+
main() {
217+
//dart format off
218+
unformatted + code;
219+
// dart format on
220+
221+
// dart format off
222+
unformatted + code;
223+
// dart format on
224+
225+
// dart format off
226+
unformatted + code;
227+
// dart format on
228+
229+
// dart format off
230+
unformatted + code;
231+
// dart format on
232+
}
233+
>>> "dart format on" whitespace must match exactly.
234+
main() {
235+
// dart format off
236+
// Doesn't actually turn back on:
237+
//dart format on
238+
unformatted + code;
239+
240+
// Does now:
241+
// dart format on
242+
unformatted + code;
243+
244+
// dart format off
245+
// Doesn't actually turn back on:
246+
// dart format on
247+
unformatted + code;
248+
249+
// Does now:
250+
// dart format on
251+
unformatted + code;
252+
253+
// dart format off
254+
// Doesn't actually turn back on:
255+
// dart format on
256+
unformatted + code;
257+
258+
// Does now:
259+
// dart format on
260+
unformatted + code;
261+
262+
// dart format off
263+
// Doesn't actually turn back on:
264+
// dart format on
265+
unformatted + code;
266+
267+
// Does now:
268+
// dart format on
269+
unformatted + code;
270+
}
271+
<<<
272+
main() {
273+
// dart format off
274+
// Doesn't actually turn back on:
275+
//dart format on
276+
unformatted + code;
277+
278+
// Does now:
279+
// dart format on
280+
unformatted + code;
281+
282+
// dart format off
283+
// Doesn't actually turn back on:
284+
// dart format on
285+
unformatted + code;
286+
287+
// Does now:
288+
// dart format on
289+
unformatted + code;
290+
291+
// dart format off
292+
// Doesn't actually turn back on:
293+
// dart format on
294+
unformatted + code;
295+
296+
// Does now:
297+
// dart format on
298+
unformatted + code;
299+
300+
// dart format off
301+
// Doesn't actually turn back on:
302+
// dart format on
303+
unformatted + code;
304+
305+
// Does now:
306+
// dart format on
307+
unformatted + code;
308+
}
309+
>>> Can't be doc comment.
310+
main() {
311+
here + gets + formatted ;
312+
/// dart format off
313+
here + does + too ;
314+
/// dart format on
315+
and + here + does ;
316+
}
317+
<<<
318+
main() {
319+
here + gets + formatted;
320+
321+
/// dart format off
322+
here + does + too;
323+
324+
/// dart format on
325+
and + here + does;
196326
}

test/tall/other/format_width.unit

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
40 columns |
2+
### Tests for the comment to set formatting width.
3+
>>> Comment sets page width.
4+
main() {
5+
// dart format width=30
6+
fitsUnsplitAt40 + butNotAt30;
7+
}
8+
<<<
9+
main() {
10+
// dart format width=30
11+
fitsUnsplitAt40 +
12+
butNotAt30;
13+
}
14+
>>> Comment anywhere affects all code.
15+
main() {
16+
fitsUnsplitAt40 + butNotAt30;
17+
}
18+
// dart format width=30
19+
<<<
20+
main() {
21+
fitsUnsplitAt40 +
22+
butNotAt30;
23+
}
24+
25+
// dart format width=30
26+
>>> If multiple comments, first one wins.
27+
main() {
28+
// dart format width=30
29+
// dart format width=60
30+
fitsUnsplitAt40 + butNotAt30;
31+
}
32+
<<<
33+
main() {
34+
// dart format width=30
35+
// dart format width=60
36+
fitsUnsplitAt40 +
37+
butNotAt30;
38+
}
39+
>>> Does nothing if width is not an integer.
40+
main() {
41+
// dart format width=wat
42+
fitsUnsplitAt40 + butNotAt30;
43+
}
44+
<<<
45+
main() {
46+
// dart format width=wat
47+
fitsUnsplitAt40 + butNotAt30;
48+
}
49+
>>> Can't have trailing text.
50+
main() {
51+
// dart format width=30 some more text
52+
fitsUnsplitAt40 + butNotAt30;
53+
}
54+
<<<
55+
main() {
56+
// dart format width=30 some more text
57+
fitsUnsplitAt40 + butNotAt30;
58+
}
59+
>>> Whitespace must match exactly.
60+
main() {
61+
//dart format width=30
62+
fitsUnsplitAt40 + butNotAt30;
63+
}
64+
<<<
65+
main() {
66+
//dart format width=30
67+
fitsUnsplitAt40 + butNotAt30;
68+
}
69+
>>> Whitespace must match exactly.
70+
main() {
71+
// dart format width=30
72+
fitsUnsplitAt40 + butNotAt30;
73+
}
74+
<<<
75+
main() {
76+
// dart format width=30
77+
fitsUnsplitAt40 + butNotAt30;
78+
}
79+
>>> Whitespace must match exactly.
80+
main() {
81+
// dart format width = 30
82+
fitsUnsplitAt40 + butNotAt30;
83+
}
84+
<<<
85+
main() {
86+
// dart format width = 30
87+
fitsUnsplitAt40 + butNotAt30;
88+
}
89+
>>> Can't be doc comment.
90+
main() {
91+
/// dart format width=30
92+
fitsUnsplitAt40 + butNotAt30;
93+
}
94+
<<<
95+
main() {
96+
/// dart format width=30
97+
fitsUnsplitAt40 + butNotAt30;
98+
}
99+
>>> Can't be nested inside other comment.
100+
main() {
101+
/* // dart format width=30 */
102+
fitsUnsplitAt40 + butNotAt30;
103+
}
104+
<<<
105+
main() {
106+
/* // dart format width=30 */
107+
fitsUnsplitAt40 + butNotAt30;
108+
}
109+
>>> Can't be inside string literal.
110+
main() {
111+
var c = '// dart format width=30';
112+
fitsUnsplitAt40 + butNotAt30;
113+
}
114+
<<<
115+
main() {
116+
var c = '// dart format width=30';
117+
fitsUnsplitAt40 + butNotAt30;
118+
}

0 commit comments

Comments
 (0)