Skip to content

Commit 3075b76

Browse files
committed
Remove the old CLI options and executables.
Before the `dart format` command was added to the core Dart SDK, users accessed the formatter by running a separate `dartfmt` executable that was included with the Dart SDK. That executable had a different CLI interface. For example, you had to pass `-w` to get it to overwrite files and if you passed no arguments at all, it silently sat there waiting for input on stdin. When we added `dart format`, we took that opportunity to revamp the CLI options. However, the dart_style package still exposed an executable with the old CLI. If you ran `dart pub global activate dart_style`, this would give you a `dartfmt` (and `dartformat`) executable with the old CLI options. Now that almost everyone is using `dart format`, we have removed the old CLI and the old package executables. You can still run the formatter on the CLI through the package (for example, if you want to use a particular version of dart_style instead of the one bundled with your Dart SDK). But it now uses the exact same CLI options and arguments as the `dart format` command. You can invoke it with `dart run dart_style:format <args...>`.
1 parent 5d35f4d commit 3075b76

File tree

12 files changed

+257
-1000
lines changed

12 files changed

+257
-1000
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
## 3.0.0-wip
2+
3+
* **Remove the old formatter executables and CLI options.**
4+
5+
Before the `dart format` command was added to the core Dart SDK, users
6+
accessed the formatter by running a separate `dartfmt` executable that was
7+
included with the Dart SDK. That executable had a different CLI interface.
8+
For example, you had to pass `-w` to get it to overwrite files and if you
9+
passed no arguments at all, it silently sat there waiting for input on stdin.
10+
When we added `dart format`, we took that opportunity to revamp the CLI
11+
options.
12+
13+
However, the dart_style package still exposed an executable with the old CLI.
14+
If you ran `dart pub global activate dart_style`, this would give you a
15+
`dartfmt` (and `dartformat`) executable with the old CLI options. Now that
16+
almost everyone is using `dart format`, we have removed the old CLI and the
17+
old package executables.
18+
19+
You can still run the formatter on the CLI through the package (for example,
20+
if you want to use a particular version of dart_style instead of the one
21+
bundled with your Dart SDK). But it now uses the exact same CLI options and
22+
arguments as the `dart format` command. You can invoke it with
23+
`dart run dart_style:format <args...>`.
24+
125
## 2.3.7
226

327
* Allow passing a language version to `DartFomatter()`. Formatted code will be

bin/format.dart

Lines changed: 13 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -3,169 +3,21 @@
33
// BSD-style license that can be found in the LICENSE file.
44
import 'dart:io';
55

6-
import 'package:args/args.dart';
7-
import 'package:dart_style/src/cli/formatter_options.dart';
8-
import 'package:dart_style/src/cli/options.dart';
9-
import 'package:dart_style/src/cli/output.dart';
10-
import 'package:dart_style/src/cli/show.dart';
11-
import 'package:dart_style/src/cli/summary.dart';
12-
import 'package:dart_style/src/io.dart';
13-
import 'package:dart_style/src/short/style_fix.dart';
6+
import 'package:args/command_runner.dart';
7+
import 'package:dart_style/src/cli/format_command.dart';
148

15-
void main(List<String> args) async {
16-
var parser = ArgParser(allowTrailingOptions: true);
9+
void main(List<String> arguments) async {
10+
var runner =
11+
CommandRunner<int>('format', 'Idiomatically format Dart source code.');
12+
runner.argParser.addFlag('verbose',
13+
abbr: 'v', negatable: false, help: 'Show verbose help.');
14+
runner.addCommand(FormatCommand(
15+
verbose: arguments.contains('-v') || arguments.contains('--verbose')));
1716

18-
defineOptions(parser,
19-
oldCli: true, verbose: args.contains('--verbose') || args.contains('-v'));
20-
21-
ArgResults argResults;
22-
try {
23-
argResults = parser.parse(args);
24-
} on FormatException catch (err) {
25-
usageError(parser, err.message);
26-
}
27-
28-
if (argResults['help'] as bool) {
29-
printUsage(parser);
30-
return;
31-
}
32-
33-
if (argResults['version'] as bool) {
34-
print(dartStyleVersion);
35-
return;
36-
}
37-
38-
if (argResults['verbose'] as bool && !(argResults['help'] as bool)) {
39-
usageError(parser, 'Can only use --verbose with --help.');
40-
}
41-
42-
List<int>? selection;
43-
try {
44-
selection = parseSelection(argResults, 'preserve');
45-
} on FormatException catch (exception) {
46-
usageError(parser, exception.message);
47-
}
48-
49-
if (argResults['dry-run'] as bool && argResults['overwrite'] as bool) {
50-
usageError(
51-
parser, 'Cannot use --dry-run and --overwrite at the same time.');
52-
}
53-
54-
void checkForReporterCollision(String chosen, String other) {
55-
if (!(argResults[other] as bool)) return;
56-
57-
usageError(parser, 'Cannot use --$chosen and --$other at the same time.');
58-
}
59-
60-
var show = Show.legacy;
61-
var summary = Summary.none;
62-
var output = Output.show;
63-
var setExitIfChanged = false;
64-
if (argResults['dry-run'] as bool) {
65-
checkForReporterCollision('dry-run', 'overwrite');
66-
checkForReporterCollision('dry-run', 'machine');
67-
68-
show = Show.dryRun;
69-
output = Output.none;
70-
} else if (argResults['overwrite'] as bool) {
71-
checkForReporterCollision('overwrite', 'machine');
72-
73-
if (argResults.rest.isEmpty) {
74-
usageError(parser,
75-
'Cannot use --overwrite without providing any paths to format.');
76-
}
77-
78-
show = Show.overwrite;
79-
output = Output.write;
80-
} else if (argResults['machine'] as bool) {
81-
output = Output.json;
82-
}
83-
84-
if (argResults['profile'] as bool) summary = Summary.profile();
85-
86-
setExitIfChanged = argResults['set-exit-if-changed'] as bool;
87-
88-
int pageWidth;
89-
try {
90-
pageWidth = int.parse(argResults['line-length'] as String);
91-
} on FormatException catch (_) {
92-
usageError(
93-
parser,
94-
'--line-length must be an integer, was '
95-
'"${argResults['line-length']}".');
96-
}
97-
98-
int indent;
9917
try {
100-
indent = int.parse(argResults['indent'] as String);
101-
if (indent < 0 || indent.toInt() != indent) throw const FormatException();
102-
} on FormatException catch (_) {
103-
usageError(
104-
parser,
105-
'--indent must be a non-negative integer, was '
106-
'"${argResults['indent']}".');
107-
}
108-
109-
var followLinks = argResults['follow-links'] as bool;
110-
111-
var fixes = <StyleFix>[];
112-
if (argResults['fix'] as bool) fixes.addAll(StyleFix.all);
113-
for (var fix in StyleFix.all) {
114-
if (argResults['fix-${fix.name}'] as bool) {
115-
if (argResults['fix'] as bool) {
116-
usageError(parser, '--fix-${fix.name} is redundant with --fix.');
117-
}
118-
119-
fixes.add(fix);
120-
}
121-
}
122-
123-
if (argResults.wasParsed('stdin-name') && argResults.rest.isNotEmpty) {
124-
usageError(parser, 'Cannot pass --stdin-name when not reading from stdin.');
125-
}
126-
127-
var options = FormatterOptions(
128-
indent: indent,
129-
pageWidth: pageWidth,
130-
followLinks: followLinks,
131-
fixes: fixes,
132-
show: show,
133-
output: output,
134-
summary: summary,
135-
setExitIfChanged: setExitIfChanged,
136-
experimentFlags: argResults['enable-experiment'] as List<String>);
137-
138-
if (argResults.rest.isEmpty) {
139-
await formatStdin(options, selection, argResults['stdin-name'] as String);
140-
} else {
141-
await formatPaths(options, argResults.rest);
142-
}
143-
144-
options.summary.show();
145-
}
146-
147-
/// Prints [error] and usage help then exits with exit code 64.
148-
Never usageError(ArgParser parser, String error) {
149-
printUsage(parser, error);
150-
exit(64);
151-
}
152-
153-
void printUsage(ArgParser parser, [String? error]) {
154-
var output = stdout;
155-
156-
var message = 'Idiomatically format Dart source code.';
157-
if (error != null) {
158-
message = error;
159-
output = stdout;
18+
await runner.runCommand(runner.parse(['format', ...arguments]));
19+
} on UsageException catch (exception) {
20+
stderr.writeln(exception);
21+
exit(64);
16022
}
161-
162-
output.write('''$message
163-
164-
Usage: dartfmt [options...] [files or directories...]
165-
166-
Example: dartfmt -w .
167-
Reformats every Dart file in the current directory tree.
168-
169-
${parser.usage}
170-
''');
17123
}

lib/src/cli/format_command.dart

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
// BSD-style license that can be found in the LICENSE file.
44
import 'dart:io';
55

6+
import 'package:args/args.dart';
67
import 'package:args/command_runner.dart';
78
import 'package:pub_semver/pub_semver.dart';
89

910
import '../dart_formatter.dart';
1011
import '../io.dart';
1112
import '../short/style_fix.dart';
1213
import 'formatter_options.dart';
13-
import 'options.dart';
1414
import 'output.dart';
1515
import 'show.dart';
1616
import 'summary.dart';
@@ -27,7 +27,102 @@ class FormatCommand extends Command<int> {
2727
'${runner!.executableName} $name [options...] <files or directories...>';
2828

2929
FormatCommand({bool verbose = false}) {
30-
defineOptions(argParser, oldCli: false, verbose: verbose);
30+
argParser.addFlag('verbose',
31+
abbr: 'v',
32+
negatable: false,
33+
help: 'Show all options and flags with --help.');
34+
35+
if (verbose) argParser.addSeparator('Output options:');
36+
37+
argParser.addOption('output',
38+
abbr: 'o',
39+
help: 'Set where to write formatted output.',
40+
allowed: ['write', 'show', 'json', 'none'],
41+
allowedHelp: {
42+
'write': 'Overwrite formatted files on disk.',
43+
'show': 'Print code to terminal.',
44+
'json': 'Print code and selection as JSON.',
45+
'none': 'Discard output.'
46+
},
47+
defaultsTo: 'write');
48+
argParser.addOption('show',
49+
help: 'Set which filenames to print.',
50+
allowed: ['all', 'changed', 'none'],
51+
allowedHelp: {
52+
'all': 'All visited files and directories.',
53+
'changed': 'Only the names of files whose formatting is changed.',
54+
'none': 'No file names or directories.',
55+
},
56+
defaultsTo: 'changed',
57+
hide: !verbose);
58+
argParser.addOption('summary',
59+
help: 'Show the specified summary after formatting.',
60+
allowed: ['line', 'profile', 'none'],
61+
allowedHelp: {
62+
'line': 'Single-line summary.',
63+
'profile': 'How long it took for format each file.',
64+
'none': 'No summary.'
65+
},
66+
defaultsTo: 'line',
67+
hide: !verbose);
68+
69+
argParser.addOption('language-version',
70+
help: 'Language version of formatted code.\n'
71+
'Use "latest" to parse as the latest supported version.\n'
72+
'Omit to look for a surrounding package config.',
73+
// TODO(rnystrom): Show this when the tall-style experiment ships.
74+
hide: true);
75+
76+
argParser.addFlag('set-exit-if-changed',
77+
negatable: false,
78+
help: 'Return exit code 1 if there are any formatting changes.');
79+
80+
if (verbose) {
81+
argParser.addSeparator('Non-whitespace fixes (off by default):');
82+
}
83+
84+
argParser.addFlag('fix',
85+
negatable: false, help: 'Apply all style fixes.', hide: !verbose);
86+
87+
for (var fix in StyleFix.all) {
88+
argParser.addFlag('fix-${fix.name}',
89+
negatable: false, help: fix.description, hide: !verbose);
90+
}
91+
92+
if (verbose) argParser.addSeparator('Other options:');
93+
94+
argParser.addOption('line-length',
95+
abbr: 'l',
96+
help: 'Wrap lines longer than this.',
97+
defaultsTo: '80',
98+
hide: true);
99+
argParser.addOption('indent',
100+
abbr: 'i',
101+
help: 'Add this many spaces of leading indentation.',
102+
defaultsTo: '0',
103+
hide: !verbose);
104+
105+
argParser.addFlag('follow-links',
106+
negatable: false,
107+
help: 'Follow links to files and directories.\n'
108+
'If unset, links will be ignored.',
109+
hide: !verbose);
110+
argParser.addFlag('version',
111+
negatable: false, help: 'Show dart_style version.', hide: !verbose);
112+
argParser.addMultiOption('enable-experiment',
113+
help: 'Enable one or more experimental features.\n'
114+
'See dart.dev/go/experiments.',
115+
hide: !verbose);
116+
117+
if (verbose) argParser.addSeparator('Options when formatting from stdin:');
118+
119+
argParser.addOption('selection',
120+
help: 'Track selection (given as "start:length") through formatting.',
121+
hide: !verbose);
122+
argParser.addOption('stdin-name',
123+
help: 'Use this path in error messages when input is read from stdin.',
124+
defaultsTo: 'stdin',
125+
hide: !verbose);
31126
}
32127

33128
@override
@@ -130,7 +225,7 @@ class FormatCommand extends Command<int> {
130225

131226
List<int>? selection;
132227
try {
133-
selection = parseSelection(argResults, 'selection');
228+
selection = _parseSelection(argResults, 'selection');
134229
} on FormatException catch (exception) {
135230
usageException(exception.message);
136231
}
@@ -178,4 +273,30 @@ class FormatCommand extends Command<int> {
178273
// and set their own exitCode.
179274
return exitCode;
180275
}
276+
277+
List<int>? _parseSelection(ArgResults argResults, String optionName) {
278+
var option = argResults[optionName] as String?;
279+
if (option == null) return null;
280+
281+
// Can only preserve a selection when parsing from stdin.
282+
if (argResults.rest.isNotEmpty) {
283+
throw FormatException(
284+
'Can only use --$optionName when reading from stdin.');
285+
}
286+
287+
try {
288+
var coordinates = option.split(':');
289+
if (coordinates.length != 2) {
290+
throw const FormatException(
291+
'Selection should be a colon-separated pair of integers, '
292+
'"123:45".');
293+
}
294+
295+
return coordinates.map<int>((coord) => int.parse(coord.trim())).toList();
296+
} on FormatException catch (_) {
297+
throw FormatException(
298+
'--$optionName must be a colon-separated pair of integers, was '
299+
'"${argResults[optionName]}".');
300+
}
301+
}
181302
}

lib/src/cli/formatter_options.dart

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,4 @@ class FormatterOptions {
9595
// Set the exit code.
9696
if (setExitIfChanged && changed) exitCode = 1;
9797
}
98-
99-
/// Describes the directory whose contents are about to be processed.
100-
void showDirectory(String path) {
101-
if (output != Output.json) {
102-
show.directory(path);
103-
}
104-
}
105-
106-
/// Describes the symlink at [path] that wasn't followed.
107-
void showSkippedLink(String path) {
108-
show.skippedLink(path);
109-
}
110-
111-
/// Describes the hidden [path] that wasn't processed.
112-
void showHiddenPath(String path) {
113-
show.hiddenPath(path);
114-
}
11598
}

0 commit comments

Comments
 (0)