OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:convert'; | 5 import 'dart:convert'; |
6 import 'dart:io'; | 6 import 'dart:io'; |
7 | 7 |
8 import 'package:args/args.dart'; | 8 import 'package:args/args.dart'; |
9 import 'package:dart_style/src/dart_formatter.dart'; | 9 import 'package:dart_style/src/dart_formatter.dart'; |
10 import 'package:dart_style/src/formatter_exception.dart'; | 10 import 'package:dart_style/src/formatter_exception.dart'; |
11 import 'package:dart_style/src/formatter_options.dart'; | 11 import 'package:dart_style/src/formatter_options.dart'; |
12 import 'package:dart_style/src/io.dart'; | 12 import 'package:dart_style/src/io.dart'; |
| 13 import 'package:dart_style/src/source_code.dart'; |
13 | 14 |
14 void main(List<String> args) { | 15 void main(List<String> args) { |
15 var parser = new ArgParser(allowTrailingOptions: true); | 16 var parser = new ArgParser(allowTrailingOptions: true); |
16 | 17 |
17 parser.addFlag("help", abbr: "h", negatable: false, | 18 parser.addFlag("help", abbr: "h", negatable: false, |
18 help: "Shows usage information."); | 19 help: "Shows usage information."); |
19 parser.addOption("line-length", abbr: "l", | 20 parser.addOption("line-length", abbr: "l", |
20 help: "Wrap lines longer than this.", | 21 help: "Wrap lines longer than this.", |
21 defaultsTo: "80"); | 22 defaultsTo: "80"); |
| 23 parser.addOption("preserve", |
| 24 help: 'Selection to preserve, formatted as "start:length".'); |
22 parser.addFlag("dry-run", abbr: "n", negatable: false, | 25 parser.addFlag("dry-run", abbr: "n", negatable: false, |
23 help: "Show which files would be modified but make no changes."); | 26 help: "Show which files would be modified but make no changes."); |
24 parser.addFlag("overwrite", abbr: "w", negatable: false, | 27 parser.addFlag("overwrite", abbr: "w", negatable: false, |
25 help: "Overwrite input files with formatted output."); | 28 help: "Overwrite input files with formatted output."); |
26 parser.addFlag("machine", abbr: "m", negatable: false, | 29 parser.addFlag("machine", abbr: "m", negatable: false, |
27 help: "Produce machine-readable JSON output."); | 30 help: "Produce machine-readable JSON output."); |
28 parser.addFlag("follow-links", negatable: false, | 31 parser.addFlag("follow-links", negatable: false, |
29 help: "Follow links to files and directories.\n" | 32 help: "Follow links to files and directories.\n" |
30 "If unset, links will be ignored."); | 33 "If unset, links will be ignored."); |
31 parser.addFlag("transform", abbr: "t", negatable: false, | 34 parser.addFlag("transform", abbr: "t", negatable: false, |
32 help: "Unused flag for compability with the old formatter."); | 35 help: "Unused flag for compability with the old formatter."); |
33 | 36 |
34 var argResults; | 37 var argResults; |
35 try { | 38 try { |
36 argResults = parser.parse(args); | 39 argResults = parser.parse(args); |
37 } on FormatException catch (err) { | 40 } on FormatException catch (err) { |
38 printUsage(parser, err.message); | 41 usageError(parser, err.message); |
39 exitCode = 64; | |
40 return; | |
41 } | 42 } |
42 | 43 |
43 if (argResults["help"]) { | 44 if (argResults["help"]) { |
44 printUsage(parser); | 45 printUsage(parser); |
45 return; | 46 return; |
46 } | 47 } |
47 | 48 |
| 49 // Can only preserve a selection when parsing from stdin. |
| 50 var selection; |
| 51 |
| 52 if (argResults["preserve"] != null && argResults.rest.isNotEmpty) { |
| 53 usageError(parser, "Can only use --preserve when reading from stdin."); |
| 54 } |
| 55 |
| 56 try { |
| 57 selection = parseSelection(argResults["preserve"]); |
| 58 } on FormatException catch (_) { |
| 59 usageError(parser, |
| 60 '--preserve must be a colon-separated pair of integers, was ' |
| 61 '"${argResults['preserve']}".'); |
| 62 } |
| 63 |
48 if (argResults["dry-run"] && argResults["overwrite"]) { | 64 if (argResults["dry-run"] && argResults["overwrite"]) { |
49 printUsage(parser, | 65 usageError(parser, |
50 "Cannot use --dry-run and --overwrite at the same time."); | 66 "Cannot use --dry-run and --overwrite at the same time."); |
51 exitCode = 64; | |
52 return; | |
53 } | 67 } |
54 | 68 |
55 checkForReporterCollision(String chosen, String other) { | 69 checkForReporterCollision(String chosen, String other) { |
56 if (!argResults[other]) return false; | 70 if (!argResults[other]) return; |
57 | 71 |
58 printUsage(parser, | 72 usageError(parser, |
59 "Cannot use --$chosen and --$other at the same time."); | 73 "Cannot use --$chosen and --$other at the same time."); |
60 exitCode = 64; | |
61 return true; | |
62 } | 74 } |
63 | 75 |
64 var reporter = OutputReporter.print; | 76 var reporter = OutputReporter.print; |
65 if (argResults["dry-run"]) { | 77 if (argResults["dry-run"]) { |
66 if (checkForReporterCollision("dry-run", "overwrite")) return; | 78 checkForReporterCollision("dry-run", "overwrite"); |
67 if (checkForReporterCollision("dry-run", "machine")) return; | 79 checkForReporterCollision("dry-run", "machine"); |
68 | 80 |
69 reporter = OutputReporter.dryRun; | 81 reporter = OutputReporter.dryRun; |
70 } else if (argResults["overwrite"]) { | 82 } else if (argResults["overwrite"]) { |
71 if (checkForReporterCollision("overwrite", "machine")) return; | 83 checkForReporterCollision("overwrite", "machine"); |
72 | 84 |
73 if (argResults.rest.isEmpty) { | 85 if (argResults.rest.isEmpty) { |
74 printUsage(parser, | 86 usageError(parser, |
75 "Cannot use --overwrite without providing any paths to format."); | 87 "Cannot use --overwrite without providing any paths to format."); |
76 exitCode = 64; | |
77 return; | |
78 } | 88 } |
79 | 89 |
80 reporter = OutputReporter.overwrite; | 90 reporter = OutputReporter.overwrite; |
81 } else if (argResults["machine"]) { | 91 } else if (argResults["machine"]) { |
82 reporter = OutputReporter.printJson; | 92 reporter = OutputReporter.printJson; |
83 } | 93 } |
84 | 94 |
85 var pageWidth; | 95 var pageWidth; |
86 | 96 |
87 try { | 97 try { |
88 pageWidth = int.parse(argResults["line-length"]); | 98 pageWidth = int.parse(argResults["line-length"]); |
89 } on FormatException catch (_) { | 99 } on FormatException catch (_) { |
90 printUsage(parser, '--line-length must be an integer, was ' | 100 usageError(parser, '--line-length must be an integer, was ' |
91 '"${argResults['line-length']}".'); | 101 '"${argResults['line-length']}".'); |
92 exitCode = 64; | |
93 return; | |
94 } | 102 } |
95 | 103 |
96 var followLinks = argResults["follow-links"]; | 104 var followLinks = argResults["follow-links"]; |
97 | 105 |
98 var options = new FormatterOptions(reporter, | 106 var options = new FormatterOptions(reporter, |
99 pageWidth: pageWidth, followLinks: followLinks); | 107 pageWidth: pageWidth, followLinks: followLinks); |
100 | 108 |
101 if (argResults.rest.isEmpty) { | 109 if (argResults.rest.isEmpty) { |
102 formatStdin(options); | 110 formatStdin(options, selection); |
103 } else { | 111 } else { |
104 formatPaths(options, argResults.rest); | 112 formatPaths(options, argResults.rest); |
105 } | 113 } |
106 } | 114 } |
107 | 115 |
| 116 List<int> parseSelection(String selection) { |
| 117 if (selection == null) return null; |
| 118 |
| 119 var coordinates = selection.split(":"); |
| 120 if (coordinates.length != 2) { |
| 121 throw new FormatException( |
| 122 'Selection should be a colon-separated pair of integers, "123:45".'); |
| 123 } |
| 124 |
| 125 return coordinates.map((coord) => coord.trim()).map(int.parse).toList(); |
| 126 } |
| 127 |
108 /// Reads input from stdin until it's closed, and the formats it. | 128 /// Reads input from stdin until it's closed, and the formats it. |
109 void formatStdin(FormatterOptions options) { | 129 void formatStdin(FormatterOptions options, List<int> selection) { |
| 130 var selectionStart = 0; |
| 131 var selectionLength = 0; |
| 132 |
| 133 if (selection != null) { |
| 134 selectionStart = selection[0]; |
| 135 selectionLength = selection[1]; |
| 136 } |
| 137 |
110 var input = new StringBuffer(); | 138 var input = new StringBuffer(); |
111 stdin.transform(new Utf8Decoder()).listen(input.write, onDone: () { | 139 stdin.transform(new Utf8Decoder()).listen(input.write, onDone: () { |
112 var formatter = new DartFormatter(pageWidth: options.pageWidth); | 140 var formatter = new DartFormatter(pageWidth: options.pageWidth); |
113 try { | 141 try { |
114 var source = input.toString(); | 142 var source = new SourceCode(input.toString(), |
115 var output = formatter.format(source, uri: "stdin"); | 143 uri: "stdin", |
| 144 selectionStart: selectionStart, |
| 145 selectionLength: selectionLength); |
| 146 var output = formatter.formatSource(source); |
116 options.reporter.showFile(null, "<stdin>", output, | 147 options.reporter.showFile(null, "<stdin>", output, |
117 changed: source != output); | 148 changed: source != output); |
118 return true; | 149 return true; |
119 } on FormatterException catch (err) { | 150 } on FormatterException catch (err) { |
120 stderr.writeln(err.message()); | 151 stderr.writeln(err.message()); |
121 } catch (err, stack) { | 152 } catch (err, stack) { |
122 stderr.writeln('''Hit a bug in the formatter when formatting stdin. | 153 stderr.writeln('''Hit a bug in the formatter when formatting stdin. |
123 Please report at: github.com/dart-lang/dart_style/issues | 154 Please report at: github.com/dart-lang/dart_style/issues |
124 $err | 155 $err |
125 $stack'''); | 156 $stack'''); |
(...skipping 16 matching lines...) Expand all Loading... |
142 if (file.existsSync()) { | 173 if (file.existsSync()) { |
143 if (!processFile(options, file)) { | 174 if (!processFile(options, file)) { |
144 exitCode = 65; | 175 exitCode = 65; |
145 } | 176 } |
146 } else { | 177 } else { |
147 stderr.writeln('No file or directory found at "$path".'); | 178 stderr.writeln('No file or directory found at "$path".'); |
148 } | 179 } |
149 } | 180 } |
150 } | 181 } |
151 | 182 |
| 183 /// Prints [error] and usage help then exits with exit code 64. |
| 184 void usageError(ArgParser parser, String error) { |
| 185 printUsage(parser, error); |
| 186 exit(64); |
| 187 } |
| 188 |
152 void printUsage(ArgParser parser, [String error]) { | 189 void printUsage(ArgParser parser, [String error]) { |
153 var output = stdout; | 190 var output = stdout; |
154 | 191 |
155 var message = "Reformats whitespace in Dart source files."; | 192 var message = "Reformats whitespace in Dart source files."; |
156 if (error != null) { | 193 if (error != null) { |
157 message = error; | 194 message = error; |
158 output = stdout; | 195 output = stdout; |
159 } | 196 } |
160 | 197 |
161 output.write("""$message | 198 output.write("""$message |
162 | 199 |
163 Usage: dartfmt [-n|-w] [files or directories...] | 200 Usage: dartfmt [-n|-w] [files or directories...] |
164 | 201 |
165 ${parser.usage} | 202 ${parser.usage} |
166 """); | 203 """); |
167 } | 204 } |
OLD | NEW |