| OLD | NEW |
| 1 #!/usr/bin/env dart | 1 #!/usr/bin/env dart |
| 2 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 2 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import 'dart:convert'; | 6 import 'dart:convert'; |
| 7 import 'dart:io'; | 7 import 'dart:io'; |
| 8 | 8 |
| 9 import 'package:args/args.dart'; | 9 import 'package:args/args.dart'; |
| 10 import 'package:path/path.dart' as path; | 10 import 'package:path/path.dart' as path; |
| 11 | 11 |
| 12 import 'package:analyzer/src/services/formatter_impl.dart'; | 12 import 'package:analyzer/src/services/formatter_impl.dart'; |
| 13 | 13 |
| 14 | |
| 15 const BINARY_NAME = 'dartfmt'; | 14 const BINARY_NAME = 'dartfmt'; |
| 16 final dartFileRegExp = new RegExp(r'^[^.].*\.dart$', caseSensitive: false); | 15 final dartFileRegExp = new RegExp(r'^[^.].*\.dart$', caseSensitive: false); |
| 17 final argParser = _initArgParser(); | 16 final argParser = _initArgParser(); |
| 18 final defaultSelection = new Selection(-1, -1); | 17 final defaultSelection = new Selection(-1, -1); |
| 19 | 18 |
| 20 var formatterSettings; | 19 var formatterSettings; |
| 21 | 20 |
| 22 CodeKind kind; | 21 CodeKind kind; |
| 23 bool machineFormat; | 22 bool machineFormat; |
| 24 bool overwriteFileContents; | 23 bool overwriteFileContents; |
| 25 Selection selection; | 24 Selection selection; |
| 26 final List<String> paths = []; | 25 final List<String> paths = []; |
| 27 | 26 |
| 28 | |
| 29 const HELP_FLAG = 'help'; | 27 const HELP_FLAG = 'help'; |
| 30 const KIND_FLAG = 'kind'; | 28 const KIND_FLAG = 'kind'; |
| 31 const MACHINE_FLAG = 'machine'; | 29 const MACHINE_FLAG = 'machine'; |
| 32 const WRITE_FLAG = 'write'; | 30 const WRITE_FLAG = 'write'; |
| 33 const SELECTION_FLAG = 'selection'; | 31 const SELECTION_FLAG = 'selection'; |
| 34 const TRANSFORM_FLAG = 'transform'; | 32 const TRANSFORM_FLAG = 'transform'; |
| 35 const MAX_LINE_FLAG = 'max_line_length'; | 33 const MAX_LINE_FLAG = 'max_line_length'; |
| 36 const INDENT_FLAG = 'indent'; | 34 const INDENT_FLAG = 'indent'; |
| 37 | 35 |
| 38 | |
| 39 const FOLLOW_LINKS = false; | 36 const FOLLOW_LINKS = false; |
| 40 | 37 |
| 41 | |
| 42 main(args) { | 38 main(args) { |
| 43 var options = argParser.parse(args); | 39 var options = argParser.parse(args); |
| 44 if (options['help']) { | 40 if (options['help']) { |
| 45 _printUsage(); | 41 _printUsage(); |
| 46 return; | 42 return; |
| 47 } | 43 } |
| 48 | 44 |
| 49 _readOptions(options); | 45 _readOptions(options); |
| 50 | 46 |
| 51 if (options.rest.isEmpty) { | 47 if (options.rest.isEmpty) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 if (val == 'INF' || val == 'INFINITY') { | 96 if (val == 'INF' || val == 'INFINITY') { |
| 101 length = -1; | 97 length = -1; |
| 102 } else { | 98 } else { |
| 103 throw new FormatterException( | 99 throw new FormatterException( |
| 104 'Line length is specified as an Integer or ' 'the value "Inf".'); | 100 'Line length is specified as an Integer or ' 'the value "Inf".'); |
| 105 } | 101 } |
| 106 } | 102 } |
| 107 return length; | 103 return length; |
| 108 } | 104 } |
| 109 | 105 |
| 110 | |
| 111 Selection _parseSelection(String selectionOption) { | 106 Selection _parseSelection(String selectionOption) { |
| 112 if (selectionOption == null) return null; | 107 if (selectionOption == null) return null; |
| 113 | 108 |
| 114 var units = selectionOption.split(','); | 109 var units = selectionOption.split(','); |
| 115 if (units.length == 2) { | 110 if (units.length == 2) { |
| 116 var offset = _toInt(units[0]); | 111 var offset = _toInt(units[0]); |
| 117 var length = _toInt(units[1]); | 112 var length = _toInt(units[1]); |
| 118 if (offset != null && length != null) { | 113 if (offset != null && length != null) { |
| 119 return new Selection(offset, length); | 114 return new Selection(offset, length); |
| 120 } | 115 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 136 } | 131 } |
| 137 | 132 |
| 138 _formatResource(resource) { | 133 _formatResource(resource) { |
| 139 if (resource is Directory) { | 134 if (resource is Directory) { |
| 140 _formatDirectory(resource); | 135 _formatDirectory(resource); |
| 141 } else if (resource is File) { | 136 } else if (resource is File) { |
| 142 _formatFile(resource); | 137 _formatFile(resource); |
| 143 } | 138 } |
| 144 } | 139 } |
| 145 | 140 |
| 146 _formatDirectory(dir) => | 141 _formatDirectory(dir) => dir |
| 147 dir.listSync( | 142 .listSync(followLinks: FOLLOW_LINKS) |
| 148 followLinks: FOLLOW_LINKS).forEach((resource) => _formatResource(resourc
e)); | 143 .forEach((resource) => _formatResource(resource)); |
| 149 | 144 |
| 150 _formatFile(file) { | 145 _formatFile(file) { |
| 151 if (_isDartFile(file)) { | 146 if (_isDartFile(file)) { |
| 152 if (_isPatchFile(file) && !paths.contains(file.path)) { | 147 if (_isPatchFile(file) && !paths.contains(file.path)) { |
| 153 _log('Skipping patch file "${file.path}"'); | 148 _log('Skipping patch file "${file.path}"'); |
| 154 return; | 149 return; |
| 155 } | 150 } |
| 156 try { | 151 try { |
| 157 var rawSource = file.readAsStringSync(); | 152 var rawSource = file.readAsStringSync(); |
| 158 var formatted = _format(rawSource, CodeKind.COMPILATION_UNIT); | 153 var formatted = _format(rawSource, CodeKind.COMPILATION_UNIT); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 169 } | 164 } |
| 170 } | 165 } |
| 171 } | 166 } |
| 172 | 167 |
| 173 _isPatchFile(file) => file.path.endsWith('_patch.dart'); | 168 _isPatchFile(file) => file.path.endsWith('_patch.dart'); |
| 174 | 169 |
| 175 _isDartFile(file) => dartFileRegExp.hasMatch(path.basename(file.path)); | 170 _isDartFile(file) => dartFileRegExp.hasMatch(path.basename(file.path)); |
| 176 | 171 |
| 177 _formatStdin(kind) { | 172 _formatStdin(kind) { |
| 178 var input = new StringBuffer(); | 173 var input = new StringBuffer(); |
| 179 stdin.transform( | 174 stdin.transform(new Utf8Decoder()).listen((data) => input.write(data), |
| 180 new Utf8Decoder()).listen( | 175 onError: (error) => _log('Error reading from stdin'), |
| 181 (data) => input.write(data), | 176 onDone: () => print(_format(input.toString(), kind))); |
| 182 onError: (error) => _log('Error reading from stdin'), | |
| 183 onDone: () => print(_format(input.toString(), kind))); | |
| 184 } | 177 } |
| 185 | 178 |
| 186 /// Initialize the arg parser instance. | 179 /// Initialize the arg parser instance. |
| 187 ArgParser _initArgParser() { | 180 ArgParser _initArgParser() { |
| 188 // NOTE: these flags are placeholders only! | 181 // NOTE: these flags are placeholders only! |
| 189 var parser = new ArgParser(); | 182 var parser = new ArgParser(); |
| 190 parser.addFlag( | 183 parser.addFlag(WRITE_FLAG, |
| 191 WRITE_FLAG, | |
| 192 abbr: 'w', | 184 abbr: 'w', |
| 193 negatable: false, | 185 negatable: false, |
| 194 help: 'Write reformatted sources to files (overwriting contents). ' | 186 help: 'Write reformatted sources to files (overwriting contents). ' |
| 195 'Do not print reformatted sources to standard output.'); | 187 'Do not print reformatted sources to standard output.'); |
| 196 parser.addFlag( | 188 parser.addFlag(TRANSFORM_FLAG, |
| 197 TRANSFORM_FLAG, | 189 abbr: 't', negatable: false, help: 'Perform code transformations.'); |
| 198 abbr: 't', | 190 parser.addOption(MAX_LINE_FLAG, |
| 199 negatable: false, | 191 abbr: 'l', defaultsTo: '80', help: 'Wrap lines longer than this length. ' |
| 200 help: 'Perform code transformations.'); | 192 'To never wrap, specify "Infinity" or "Inf" for short.'); |
| 201 parser.addOption( | 193 parser.addOption(INDENT_FLAG, |
| 202 MAX_LINE_FLAG, | |
| 203 abbr: 'l', | |
| 204 defaultsTo: '80', | |
| 205 help: 'Wrap lines longer than this length. ' | |
| 206 'To never wrap, specify "Infinity" or "Inf" for short.'); | |
| 207 parser.addOption( | |
| 208 INDENT_FLAG, | |
| 209 abbr: 'i', | 194 abbr: 'i', |
| 210 defaultsTo: '2', | 195 defaultsTo: '2', |
| 211 help: 'Specify number of spaces per indentation. ' | 196 help: 'Specify number of spaces per indentation. ' |
| 212 'To indent using tabs, specify "--$INDENT_FLAG tab".' '--- [PROVISIONA
L API].', | 197 'To indent using tabs, specify "--$INDENT_FLAG tab".' '--- [PROVISIONAL AP
I].', |
| 213 hide: true); | 198 hide: true); |
| 214 parser.addOption( | 199 parser.addOption(KIND_FLAG, |
| 215 KIND_FLAG, | |
| 216 abbr: 'k', | 200 abbr: 'k', |
| 217 defaultsTo: 'cu', | 201 defaultsTo: 'cu', |
| 218 help: 'Specify source snippet kind ("stmt" or "cu") ' '--- [PROVISIONAL AP
I].', | 202 help: 'Specify source snippet kind ("stmt" or "cu") ' '--- [PROVISIONAL AP
I].', |
| 219 hide: true); | 203 hide: true); |
| 220 parser.addOption( | 204 parser.addOption(SELECTION_FLAG, |
| 221 SELECTION_FLAG, | 205 abbr: 's', help: 'Specify selection information as an offset,length pair ' |
| 222 abbr: 's', | 206 '(e.g., -s "0,4").', hide: true); |
| 223 help: 'Specify selection information as an offset,length pair ' | 207 parser.addFlag(MACHINE_FLAG, |
| 224 '(e.g., -s "0,4").', | |
| 225 hide: true); | |
| 226 parser.addFlag( | |
| 227 MACHINE_FLAG, | |
| 228 abbr: 'm', | 208 abbr: 'm', |
| 229 negatable: false, | 209 negatable: false, |
| 230 help: 'Produce output in a format suitable for parsing.'); | 210 help: 'Produce output in a format suitable for parsing.'); |
| 231 parser.addFlag( | 211 parser.addFlag(HELP_FLAG, |
| 232 HELP_FLAG, | 212 abbr: 'h', negatable: false, help: 'Print this usage information.'); |
| 233 abbr: 'h', | |
| 234 negatable: false, | |
| 235 help: 'Print this usage information.'); | |
| 236 return parser; | 213 return parser; |
| 237 } | 214 } |
| 238 | 215 |
| 239 | |
| 240 /// Displays usage information. | 216 /// Displays usage information. |
| 241 _printUsage() { | 217 _printUsage() { |
| 242 var buffer = new StringBuffer(); | 218 var buffer = new StringBuffer(); |
| 243 buffer | 219 buffer |
| 244 ..write('$BINARY_NAME formats Dart programs.') | 220 ..write('$BINARY_NAME formats Dart programs.') |
| 245 ..write('\n\n') | 221 ..write('\n\n') |
| 246 ..write( | 222 ..write('Without an explicit path, $BINARY_NAME processes the standard ' |
| 247 'Without an explicit path, $BINARY_NAME processes the standard ' | 223 'input. Given a file, it operates on that file; given a ' |
| 248 'input. Given a file, it operates on that file; given a ' | 224 'directory, it operates on all .dart files in that directory, ' |
| 249 'directory, it operates on all .dart files in that directory, ' | 225 'recursively. (Files starting with a period are ignored.) By ' |
| 250 'recursively. (Files starting with a period are ignored.) By ' | 226 'default, $BINARY_NAME prints the reformatted sources to ' 'standard out
put.') |
| 251 'default, $BINARY_NAME prints the reformatted sources to ' 'standa
rd output.') | 227 ..write('\n\n') |
| 252 ..write('\n\n') | 228 ..write('Usage: $BINARY_NAME [flags] [path...]\n\n') |
| 253 ..write('Usage: $BINARY_NAME [flags] [path...]\n\n') | 229 ..write('Supported flags are:\n') |
| 254 ..write('Supported flags are:\n') | 230 ..write('${argParser.usage}\n\n'); |
| 255 ..write('${argParser.usage}\n\n'); | |
| 256 _log(buffer.toString()); | 231 _log(buffer.toString()); |
| 257 } | 232 } |
| 258 | 233 |
| 259 /// Format this [src], treating it as the given snippet [kind]. | 234 /// Format this [src], treating it as the given snippet [kind]. |
| 260 String _format(src, kind) { | 235 String _format(src, kind) { |
| 261 var formatResult = | 236 var formatResult = new CodeFormatter(formatterSettings).format(kind, src, |
| 262 new CodeFormatter(formatterSettings).format(kind, src, selection: selectio
n); | 237 selection: selection); |
| 263 if (machineFormat) { | 238 if (machineFormat) { |
| 264 if (formatResult.selection == null) { | 239 if (formatResult.selection == null) { |
| 265 formatResult.selection = defaultSelection; | 240 formatResult.selection = defaultSelection; |
| 266 } | 241 } |
| 267 return _toJson(formatResult); | 242 return _toJson(formatResult); |
| 268 } | 243 } |
| 269 return formatResult.source; | 244 return formatResult.source; |
| 270 } | 245 } |
| 271 | 246 |
| 272 _toJson(formatResult) => // Actual JSON format TBD | 247 _toJson(formatResult) => // Actual JSON format TBD |
| 273 JSON.encode({ | 248 JSON.encode({ |
| 274 'source': formatResult.source, | 249 'source': formatResult.source, |
| 275 'selection': { | 250 'selection': { |
| 276 'offset': formatResult.selection.offset, | 251 'offset': formatResult.selection.offset, |
| 277 'length': formatResult.selection.length | 252 'length': formatResult.selection.length |
| 278 } | 253 } |
| 279 }); | 254 }); |
| 280 | 255 |
| 281 /// Log the given [msg]. | 256 /// Log the given [msg]. |
| 282 _log(String msg) { | 257 _log(String msg) { |
| 283 //TODO(pquitslund): add proper log support | 258 //TODO(pquitslund): add proper log support |
| 284 print(msg); | 259 print(msg); |
| 285 } | 260 } |
| OLD | NEW |