OLD | NEW |
| (Empty) |
1 #!/usr/bin/env dart | |
2 | |
3 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
4 // for details. All rights reserved. Use of this source code is governed by a | |
5 // BSD-style license that can be found in the LICENSE file. | |
6 | |
7 import 'dart:convert'; | |
8 import 'dart:io'; | |
9 | |
10 import 'package:args/args.dart'; | |
11 import 'package:path/path.dart' as path; | |
12 | |
13 import 'package:analyzer_experimental/src/services/formatter_impl.dart'; | |
14 | |
15 | |
16 const BINARY_NAME = 'dartfmt'; | |
17 final dartFileRegExp = new RegExp(r'^[^.].*\.dart$', caseSensitive: false); | |
18 final argParser = _initArgParser(); | |
19 final defaultSelection = new Selection(-1, -1); | |
20 | |
21 var formatterSettings; | |
22 | |
23 bool machineFormat; | |
24 bool overwriteFileContents; | |
25 Selection selection; | |
26 const followLinks = false; | |
27 | |
28 | |
29 main(args) { | |
30 var options = argParser.parse(args); | |
31 if (options['help']) { | |
32 _printUsage(); | |
33 return; | |
34 } | |
35 | |
36 _readOptions(options); | |
37 | |
38 if (options.rest.isEmpty) { | |
39 _formatStdin(options); | |
40 } else { | |
41 _formatPaths(options.rest); | |
42 } | |
43 } | |
44 | |
45 _readOptions(options) { | |
46 machineFormat = options['machine']; | |
47 overwriteFileContents = options['write']; | |
48 selection = _parseSelection(options['selection']); | |
49 formatterSettings = | |
50 new FormatterOptions(codeTransforms: options['transform']); | |
51 } | |
52 | |
53 Selection _parseSelection(selectionOption) { | |
54 if (selectionOption != null) { | |
55 var units = selectionOption.split(','); | |
56 if (units.length == 2) { | |
57 var offset = _toInt(units[0]); | |
58 var length = _toInt(units[1]); | |
59 if (offset != null && length != null) { | |
60 return new Selection(offset, length); | |
61 } | |
62 } | |
63 throw new FormatterException('Selections are specified as integer pairs ' | |
64 '(e.g., "(offset, length)".'); | |
65 } | |
66 } | |
67 | |
68 int _toInt(str) => int.parse(str, onError: (_) => null); | |
69 | |
70 _formatPaths(paths) { | |
71 paths.forEach((path) { | |
72 if (FileSystemEntity.isDirectorySync(path)) { | |
73 _formatDirectory(new Directory(path)); | |
74 } else { | |
75 _formatFile(new File(path)); | |
76 } | |
77 }); | |
78 } | |
79 | |
80 _formatResource(resource) { | |
81 if (resource is Directory) { | |
82 _formatDirectory(resource); | |
83 } else if (resource is File) { | |
84 _formatFile(resource); | |
85 } | |
86 } | |
87 | |
88 _formatDirectory(dir) => dir.listSync(followLinks: followLinks) | |
89 .forEach((resource) => _formatResource(resource)); | |
90 | |
91 _formatFile(file) { | |
92 if (_isDartFile(file)) { | |
93 try { | |
94 var buffer = new StringBuffer(); | |
95 var rawSource = file.readAsStringSync(); | |
96 var formatted = _formatCU(rawSource); | |
97 if (overwriteFileContents) { | |
98 file.writeAsStringSync(formatted); | |
99 } else { | |
100 print(formatted); | |
101 } | |
102 } catch (e) { | |
103 _log('Unable to format "${file.path}": $e'); | |
104 } | |
105 } | |
106 } | |
107 | |
108 _isDartFile(file) => dartFileRegExp.hasMatch(path.basename(file.path)); | |
109 | |
110 _formatStdin(options) { | |
111 var input = new StringBuffer(); | |
112 stdin.transform(new Utf8Decoder()) | |
113 .listen((data) => input.write(data), | |
114 onError: (error) => _log('Error reading from stdin'), | |
115 onDone: () => print(_formatCU(input.toString()))); | |
116 } | |
117 | |
118 /// Initialize the arg parser instance. | |
119 ArgParser _initArgParser() { | |
120 // NOTE: these flags are placeholders only! | |
121 var parser = new ArgParser(); | |
122 parser.addFlag('write', abbr: 'w', negatable: false, | |
123 help: 'Write reformatted sources to files (overwriting contents). ' | |
124 'Do not print reformatted sources to standard output.'); | |
125 parser.addFlag('machine', abbr: 'm', negatable: false, | |
126 help: 'Produce output in a format suitable for parsing.'); | |
127 parser.addOption('selection', abbr: 's', | |
128 help: 'Specify selection information as an offset,length pair ' | |
129 '(e.g., -s "0,4").'); | |
130 parser.addFlag('transform', abbr: 't', negatable: true, | |
131 help: 'Perform code transformations.'); | |
132 parser.addFlag('help', abbr: 'h', negatable: false, | |
133 help: 'Print this usage information.'); | |
134 return parser; | |
135 } | |
136 | |
137 | |
138 /// Displays usage information. | |
139 _printUsage() { | |
140 var buffer = new StringBuffer(); | |
141 buffer..write('$BINARY_NAME formats Dart programs.') | |
142 ..write('\n\n') | |
143 ..write('Without an explicit path, $BINARY_NAME processes the standard ' | |
144 'input. Given a file, it operates on that file; given a ' | |
145 'directory, it operates on all .dart files in that directory, ' | |
146 'recursively. (Files starting with a period are ignored.) By ' | |
147 'default, $BINARY_NAME prints the reformatted sources to ' | |
148 'standard output.') | |
149 ..write('\n\n') | |
150 ..write('Supported flags are:') | |
151 ..write('Usage: $BINARY_NAME [flags] [path...]\n\n') | |
152 ..write('${argParser.getUsage()}\n\n'); | |
153 _log(buffer.toString()); | |
154 } | |
155 | |
156 /// Format the given [src] as a compilation unit. | |
157 String _formatCU(src) { | |
158 var formatResult = new CodeFormatter(formatterSettings).format( | |
159 CodeKind.COMPILATION_UNIT, src, selection: selection); | |
160 if (machineFormat) { | |
161 if (formatResult.selection == null) { | |
162 formatResult.selection = defaultSelection; | |
163 } | |
164 return _toJson(formatResult); | |
165 } | |
166 return formatResult.source; | |
167 } | |
168 | |
169 _toJson(formatResult) => | |
170 // Actual JSON format TBD | |
171 JSON.encode({'source': formatResult.source, | |
172 'selection': { | |
173 'offset': formatResult.selection.offset, | |
174 'length': formatResult.selection.length | |
175 } | |
176 }); | |
177 | |
178 /// Log the given [msg]. | |
179 _log(String msg) { | |
180 //TODO(pquitslund): add proper log support | |
181 print(msg); | |
182 } | |
OLD | NEW |