OLD | NEW |
1 The dart_style package defines an automatic, opinionated formatter for Dart | 1 The dart_style package defines an automatic, opinionated formatter for Dart |
2 code. It replaces the whitespace in your program with what it deems to be the | 2 code. It replaces the whitespace in your program with what it deems to be the |
3 best formatting for it. Resulting code should following the [Dart style guide][] | 3 best formatting for it. Resulting code should follow the [Dart style guide][] |
4 but, moreso, should look nice to most human readers, most of the time. | 4 but, moreso, should look nice to most human readers, most of the time. |
5 | 5 |
6 [dart style guide]: https://www.dartlang.org/articles/style-guide/ | 6 [dart style guide]: https://www.dartlang.org/articles/style-guide/ |
7 | 7 |
8 It handles indentation, inline whitespace and (by far the most difficult), | 8 The formatter handles indentation, inline whitespace and |
9 intelligent line wrapping. It has no problems with nested collections, function | 9 (by far the most difficult), intelligent line wrapping. |
| 10 It has no problems with nested collections, function |
10 expressions, long argument lists, or otherwise tricky code. | 11 expressions, long argument lists, or otherwise tricky code. |
11 | 12 |
12 ## Usage | 13 The formatter turns code like this: |
13 | 14 |
14 The package exposes a simple command-line wrapper around the core formatting | 15 ``` |
15 library. The easiest way to invoke it is to [globally activate][] the package | 16 // BEFORE formatting |
16 and let pub put its executable on your path: | 17 if (tag=='style'||tag=='script'&&(type==null||type == TYPE_JS |
| 18 ||type==TYPE_DART)|| |
| 19 tag=='link'&&(rel=='stylesheet'||rel=='import')) {} |
| 20 ``` |
| 21 |
| 22 into: |
| 23 |
| 24 ``` |
| 25 // AFTER formatting |
| 26 if (tag == 'style' || |
| 27 tag == 'script' && |
| 28 (type == null || type == TYPE_JS || type == TYPE_DART) || |
| 29 tag == 'link' && (rel == 'stylesheet' || rel == 'import')) {} |
| 30 ``` |
| 31 |
| 32 The formatter will never break your code—you can safely invoke it |
| 33 automatically from build and presubmit scripts. |
| 34 |
| 35 ## Getting dartfmt |
| 36 |
| 37 Dartfmt is included in the Dart SDK, so you might want to add the SDK's bin |
| 38 directory to your system path. |
| 39 |
| 40 If you want to make sure you are running the latest version of dartfmt, |
| 41 you can [globally activate][] the package from the dart_style package |
| 42 on pub.dartlang.org, and let pub put its executable on your path: |
17 | 43 |
18 $ pub global activate dart_style | 44 $ pub global activate dart_style |
19 $ dartfmt ... | 45 $ dartfmt ... |
20 | 46 |
21 [globally activate]: https://www.dartlang.org/tools/pub/cmd/pub-global.html | 47 [globally activate]: https://www.dartlang.org/tools/pub/cmd/pub-global.html |
22 | 48 |
23 If you don't want `dartformat` on your path, you can run it explicitly: | 49 If you don't want `dartfmt` on your path, you can run it explicitly: |
24 | 50 |
25 $ pub global activate dart_style --no-executables | 51 $ pub global activate dart_style --no-executables |
26 $ pub global run dart_style:format ... | 52 $ pub global run dart_style:format ... |
27 | 53 |
28 The formatter takes a list of paths, which can point to directories or files. | 54 ## Using dartfmt |
| 55 |
| 56 IDEs and editors that support Dart usually provide easy ways to run the |
| 57 formatter. For example, in WebStorm you can right-click a .dart file |
| 58 and then choose **Reformat with Dart Style**. |
| 59 |
| 60 Here's a simple example of using dartfmt on the command line: |
| 61 |
| 62 ``` |
| 63 dartfmt test.dart |
| 64 ``` |
| 65 |
| 66 This command formats the `test.dart` file and writes the result to |
| 67 standard output. |
| 68 |
| 69 Dartfmt takes a list of paths, which can point to directories or files. |
29 If the path is a directory, it processes every `.dart` file in that directory | 70 If the path is a directory, it processes every `.dart` file in that directory |
30 or any of its subdirectories. | 71 or any of its subdirectories. |
| 72 If no file or directory is specified, dartfmt reads from standard input. |
31 | 73 |
32 By default, it formats each file and just prints the resulting code to stdout. | 74 By default, it formats each file and just prints the resulting code to stdout. |
33 If you pass `-w`, it will instead overwrite your existing files with the | 75 If you pass `-w`, it overwrites your existing files with the |
34 formatted results. | 76 formatted results. |
35 | 77 |
36 You may pass a `--line-length` option to control the width of the page that it | 78 You may pass a `-l` option to control the width of the page that it |
37 wraps lines to fit within, but you're strongly encouraged to keep the default | 79 wraps lines to fit within, but you're strongly encouraged to keep the default |
38 line length of 80 columns. | 80 line length of 80 columns. |
39 | 81 |
40 ### Validating files | 82 ### Validating files |
41 | 83 |
42 If you want to use the formatter in something like a [presubmit script][] or | 84 If you want to use the formatter in something like a [presubmit script][] or |
43 [commit hook][], you can use the `--dry-run` option. If you pass that, the | 85 [commit hook][], you can use the `-n` dry run option. If you specify `-n`, the |
44 formatter prints the paths of the files whose contents would change if the | 86 formatter prints the paths of the files whose contents would change if the |
45 formatter were run normally. If it prints no output, then everything is already | 87 formatter were run normally. If it prints no output, then everything is already |
46 correctly formatted. | 88 correctly formatted. |
47 | 89 |
48 [presubmit script]: http://www.chromium.org/developers/how-tos/depottools/presub
mit-scripts | 90 [presubmit script]: http://www.chromium.org/developers/how-tos/depottools/presub
mit-scripts |
49 [commit hook]: http://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks | 91 [commit hook]: http://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks |
50 | 92 |
51 ### Using it programmatically | 93 ## Using the dart_style API |
52 | 94 |
53 The package also exposes a single dart_style library containing a programmatic | 95 The package also exposes a single dart_style library containing a programmatic |
54 API for formatting code. Simple usage looks like this: | 96 API for formatting code. Simple usage looks like this: |
55 | 97 |
56 import 'package:dart_style/dart_style.dart'; | 98 import 'package:dart_style/dart_style.dart'; |
57 | 99 |
58 main() { | 100 main() { |
59 var formatter = new DartFormatter(); | 101 var formatter = new DartFormatter(); |
60 | 102 |
61 try { | 103 try { |
62 print(formatter.format(""" | 104 print(formatter.format(""" |
63 library an_entire_compilation_unit; | 105 library an_entire_compilation_unit; |
64 | 106 |
65 class SomeClass {} | 107 class SomeClass {} |
66 """)); | 108 """)); |
67 | 109 |
68 print(formatter.formatStatement("aSingle(statement);")); | 110 print(formatter.formatStatement("aSingle(statement);")); |
69 } on FormatterException catch (ex) { | 111 } on FormatterException catch (ex) { |
70 print(ex); | 112 print(ex); |
71 } | 113 } |
72 } | 114 } |
73 | 115 |
74 ## FAQ | 116 ## Other resources |
75 | 117 |
76 ### Why have a formatter? | 118 * Before sending an email, see if you are asking a |
| 119 [frequently asked question][faq]. |
77 | 120 |
78 The has a few goals, in order of descending priority: | 121 * Before filing a bug, or if you want to understand how work on the |
79 | 122 formatter is managed, see how we [track issues][]. |
80 1. **Produce consistently formatted code.** Consistent style improves | |
81 readability because you aren't distracted by variance in style between | |
82 different parts of a program. It makes it easier to contribute to others' | |
83 code because their style will already be familiar to you. | |
84 | |
85 2. **End debates about style issues in code reviews.** This consumes an | |
86 astonishingly large quantity of very valuable engineering energy. Style | |
87 debates are time-consuming, upset people, and rarely change anyone's mind. | |
88 They make code reviews take longer and be more acromonious. | |
89 | |
90 3. **Free users from having to think about and apply formatting.** When | |
91 writing code, you don't have to try to figure out the best way to split a | |
92 line and then pain-stakingly add in the line breaks. When you do a global | |
93 refactor that changes the length of some identifier, you don't have to go | |
94 back and rewrap all of the lines. When you're in the zone, you can just | |
95 pump out code and let the formatter tidy it up for you as you go. | |
96 | |
97 4. **Produce beautiful, readable output that helps users understand the code.** | |
98 We could solve all of the above goals with a formatter that just removed | |
99 *all* whitespace, but that wouldn't be very human-friendly. So, finally, | |
100 the formatter tries very hard to produce output that is not just consistent | |
101 but readable to a human. It tries to use indentation and line breaks to | |
102 highlight the structure and organization of the code. | |
103 | |
104 In several cases, the formatter has pointed out bugs where the existing | |
105 indentation was misleading and didn't represent what the code actually did. | |
106 For example, automated formatted would have helped make Apple's | |
107 ["gotofail"][gotofail] security bug easier to notice: | |
108 | |
109 ```c | |
110 if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) | |
111 goto fail; | |
112 goto fail; | |
113 if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) | |
114 goto fail; | |
115 ``` | |
116 | |
117 The formatter would change this to: | |
118 | |
119 ```c | |
120 if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) | |
121 goto fail; | |
122 goto fail; // <-- not clearly not under the "if". | |
123 if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) | |
124 goto fail; | |
125 ``` | |
126 | 123 |
127 [gotofail]: https://gotofail.com/ | 124 [faq]: https://github.com/dart-lang/dart_style/wiki/FAQ |
128 | 125 [track issues]: https://github.com/dart-lang/dart_style/wiki/Tracking-issues |
129 ### I don't like the output! | |
130 | |
131 First of all, that's not a question. But, yes, sometimes you may dislike the | |
132 output of the formatter. This may be a bug or it may be a deliberate stylistic | |
133 choice of the formatter that you disagree with. The simplest way to find out is | |
134 to file an [issue][]. | |
135 | |
136 [issue]: https://github.com/dart-lang/dart_style/issues | |
137 | |
138 Now that the formatter is fairly mature, it's more likely that the output is | |
139 deliberate. If your bug gets closed as "as designed", try not to be too sad. | |
140 Even if the formatter doesn't follow your personal preferences, what it *does* | |
141 do is spare you the effort of hand-formatting, and ensure your code is | |
142 *consistently* formatted. I hope you'll appreciate the real value in both of | |
143 those. | |
144 | |
145 ### How stable is it? | |
146 | |
147 You can rely on the formatter to not break your code or change its semantics. | |
148 If it does do so, this is a critical bug and we'll fix it quickly. | |
149 | |
150 The rules the formatter uses to determine the "best" way to split a line may | |
151 change over time. We don't promise that code produced by the formatter today | |
152 will be identical to the same code run through a later version of the formatter. | |
153 We do hope that you'll like the output of the later version more. | |
154 | |
155 ### Why can't I tell the formatter to ignore a region of code? | |
156 | |
157 Even a really sophisticated formatter can't beat a human in *all* cases. Our | |
158 semantic knowledge of the code can let us show more than the formatter can. One | |
159 escape hatch would be to have a comment telling the formatter "leave this | |
160 alone". | |
161 | |
162 This might help the fourth goal above, but does so at the expense of the first | |
163 three. We want code that is *consistent* and we want you to stop thinking about | |
164 formatting. If you can decide to turn off the formatter, now you have regions | |
165 of code that are inconsistent by design. | |
166 | |
167 Further, you're right back into debates about how the code in there should be | |
168 formatted, with the extra bonus of now debating whether or not that annotation | |
169 should be used and where. None of this is making your life better. | |
170 | |
171 Yes, *maybe* you can hand-format some things better than the formatter. (Though, | |
172 in most cases where users have asked for this, I've seen formatting errors in | |
173 the examples they provided!) But does doing that really add enough value to | |
174 make up for re-opening that can of worms? | |
175 | |
176 ### Why does the formatter mess up my collection literals? | |
177 | |
178 Large collection literals are often used to define big chunks of structured | |
179 data, like: | |
180 | |
181 ```dart | |
182 /// Maps ASCII character values to what kind of character they represent. | |
183 const characterTypes = const [ | |
184 other, other, other, other, other, other, other, other, | |
185 other, white, white, other, other, white, | |
186 other, other, other, other, other, other, other, other, | |
187 other, other, other, other, other, other, other, other, | |
188 other, other, white, | |
189 punct, other, punct, punct, punct, punct, other, | |
190 brace, brace, punct, punct, comma, punct, punct, punct, | |
191 digit, digit, digit, digit, digit, | |
192 digit, digit, digit, digit, digit, | |
193 punct, punct, punct, punct, punct, punct, punct, | |
194 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
195 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
196 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
197 alpha, alpha, brace, punct, brace, punct, alpha, other, | |
198 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
199 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
200 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
201 alpha, alpha, brace, punct, brace, punct | |
202 ]; | |
203 ``` | |
204 | |
205 The formatter doesn't know those newlines are meaningful, so it wipes it out | |
206 to: | |
207 | |
208 ```dart | |
209 /// Maps ASCII character values to what kind of character they represent. | |
210 const characterTypes = const [ | |
211 other, | |
212 other, | |
213 other, | |
214 | |
215 // lots more ... | |
216 | |
217 punct, | |
218 brace, | |
219 punct | |
220 ]; | |
221 ``` | |
222 | |
223 In many cases, ignoring these newlines is a good thing. If you've removed a few | |
224 items from a list, it's a win for the formatter to repack it into one line if | |
225 it fits. But here it clearly loses useful information. | |
226 | |
227 Fortunately, in most cases, structured collections like this have comments | |
228 describing their structure: | |
229 | |
230 ```dart | |
231 const characterTypes = const [ | |
232 other, other, other, other, other, other, other, other, | |
233 other, white, white, other, other, white, | |
234 other, other, other, other, other, other, other, other, | |
235 other, other, other, other, other, other, other, other, | |
236 other, other, white, | |
237 punct, other, punct, punct, punct, punct, other, // !"#$%&ยด | |
238 brace, brace, punct, punct, comma, punct, punct, punct, // ()*+,-./ | |
239 digit, digit, digit, digit, digit, // 01234 | |
240 digit, digit, digit, digit, digit, // 56789 | |
241 punct, punct, punct, punct, punct, punct, punct, // :;<=>?@ | |
242 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, // ABCDEFGH | |
243 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
244 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
245 alpha, alpha, brace, punct, brace, punct, alpha, other, // YZ[\]^_' | |
246 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, // abcdefgh | |
247 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
248 alpha, alpha, alpha, alpha, alpha, alpha, alpha, alpha, | |
249 alpha, alpha, brace, punct, brace, punct // yz{|}~ | |
250 ]; | |
251 ``` | |
252 | |
253 In that case, the formatter is smart enough to recognize this and preserve your | |
254 original newlines. So, if you have a collection that you have carefully split | |
255 into lines, add at least one line comment somewhere inside it to get it to | |
256 preserve all of the newlines in it. | |
257 | |
258 ### Why doesn't the formatter handle multi-line `if` statements better? | |
259 | |
260 If you have a statement like: | |
261 | |
262 ```dart | |
263 if (someVeryLongConditional || anotherLongConditional) function(argument, argume
nt); | |
264 ``` | |
265 | |
266 It will format it like: | |
267 | |
268 ```dart | |
269 if (someVeryLongConditional || anotherLongConditional) function( | |
270 argument, argument); | |
271 ``` | |
272 | |
273 You might expect it to break before `function`. But the Dart style guide | |
274 explicitly forbids multi-line `if` statements that do not use `{}` bodies. | |
275 Given that, there's never a reason for the formatter to allow splitting after | |
276 the condition. This is true of other control flow statements too, of course. | |
277 | |
278 ### Why doesn't the formatter add curlies or otherwise clean up code then? | |
279 | |
280 The formatter has a simple, restricted charter: it rewrites *only the | |
281 non-semantic whitespace of your program.* It makes absolutely no other changes | |
282 to your code. | |
283 | |
284 This helps keep the scope of the project limited. The set of "clean-ups" you | |
285 may want to do is unbounded and much fuzzier to define. | |
286 | |
287 It also makes it more reliable to run the formatter automatically in things | |
288 like presubmit scripts where a human may not be vetting the output. If the | |
289 formatter only touches whitespace, it's easier for a human to trust its output. | |
OLD | NEW |