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