OLD | NEW |
(Empty) | |
| 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 |
| 3 best formatting for it. Resulting code should following the [Dart style guide][] |
| 4 but, moreso, should look nice to most human readers, most of the time. |
| 5 |
| 6 [dart style guide]: https://www.dartlang.org/articles/style-guide/ |
| 7 |
| 8 It handles indentation, inline whitespace and (by far the most difficult), |
| 9 intelligent line wrapping. It has no problems with nested collections, function |
| 10 expressions, long argument lists, or otherwise tricky code. |
| 11 |
| 12 ## Usage |
| 13 |
| 14 The package exposes a simple command-line wrapper around the core formatting |
| 15 library. The easiest way to invoke it is to [globally activate][] the package |
| 16 and let pub put its executable on your path: |
| 17 |
| 18 $ pub global activate dart_style |
| 19 $ dartfmt ... |
| 20 |
| 21 [globally activate]: https://www.dartlang.org/tools/pub/cmd/pub-global.html |
| 22 |
| 23 If you don't want `dartformat` on your path, you can run it explicitly: |
| 24 |
| 25 $ pub global activate dart_style --no-executables |
| 26 $ pub global run dart_style:format ... |
| 27 |
| 28 The formatter 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 |
| 30 or any of its subdirectories. |
| 31 |
| 32 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 |
| 34 formatted results. |
| 35 |
| 36 You may pass a `--line-length` 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 |
| 38 line length of 80 columns. |
| 39 |
| 40 ### Validating files |
| 41 |
| 42 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 |
| 44 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 |
| 46 correctly formatted. |
| 47 |
| 48 [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 |
| 50 |
| 51 ### Using it programmatically |
| 52 |
| 53 The package also exposes a single dart_style library containing a programmatic |
| 54 API for formatting code. Simple usage looks like this: |
| 55 |
| 56 import 'package:dart_style/dart_style.dart'; |
| 57 |
| 58 main() { |
| 59 var formatter = new DartFormatter(); |
| 60 |
| 61 try { |
| 62 print(formatter.format(""" |
| 63 library an_entire_compilation_unit; |
| 64 |
| 65 class SomeClass {} |
| 66 """)); |
| 67 |
| 68 print(formatter.formatStatement("aSingle(statement);")); |
| 69 } on FormatterException catch (ex) { |
| 70 print(ex); |
| 71 } |
| 72 } |
| 73 |
| 74 ## FAQ |
| 75 |
| 76 ### Why have a formatter? |
| 77 |
| 78 The has a few goals, in order of descending priority: |
| 79 |
| 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 |
| 127 [gotofail]: https://gotofail.com/ |
| 128 |
| 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 |