Skip to content

Commit

Permalink
Stdin name search (#1566)
Browse files Browse the repository at this point in the history
Use --stdin-name as a file path for inferring the language version.

If --stdin-name is given, then look for a surrounding package config to
infer the default language version from for code read from stdin. To
avoid that behavior, you can pass in a language version explicitly
using --language-version.

Fix #1530.
  • Loading branch information
munificent authored Sep 13, 2024
1 parent 49832b6 commit 0c1f628
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 106 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@
arguments as the `dart format` command. You can invoke it with
`dart run dart_style:format <args...>`.

* **Treat the `--stdin-name` name as a path when inferring language version.**
When reading input on stdin, the formatter still needs to know what language
version to parse the code as. If the `--stdin-name` option is set, then that
is treated as a file path and the formatter looks for a package config
surrounding that file path to infer the language version from.

If you don't want that behavior, pass in an explicit language version using
`--language-version=`, or use `--language-version=latest` to parse the input
using the latest language version supported by the formatter.

If `--stdin-name` and `--language-version` are both omitted, then parses
stdin using the latest supported language version.

## 2.3.7

* Allow passing a language version to `DartFomatter()`. Formatted code will be
Expand Down
10 changes: 7 additions & 3 deletions lib/src/cli/format_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,12 @@ class FormatCommand extends Command<int> {
help: 'Track selection (given as "start:length") through formatting.',
hide: !verbose);
argParser.addOption('stdin-name',
help: 'Use this path in error messages when input is read from stdin.',
defaultsTo: 'stdin',
help:
'The path that code read from stdin is treated as coming from.\n\n'
'This path is used in error messages and also to locate a\n'
'surrounding package to infer the code\'s language version.\n'
'To avoid searching for a surrounding package config, pass\n'
'in a language version using --language-version.',
hide: !verbose);
}

Expand Down Expand Up @@ -223,7 +227,7 @@ class FormatCommand extends Command<int> {
if (argResults.wasParsed('stdin-name') && argResults.rest.isNotEmpty) {
usageException('Cannot pass --stdin-name when not reading from stdin.');
}
var stdinName = argResults['stdin-name'] as String;
var stdinName = argResults['stdin-name'] as String?;

var options = FormatterOptions(
languageVersion: languageVersion,
Expand Down
39 changes: 24 additions & 15 deletions lib/src/io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import 'source_code.dart';

/// Reads and formats input from stdin until closed.
Future<void> formatStdin(
FormatterOptions options, List<int>? selection, String name) async {
FormatterOptions options, List<int>? selection, String? path) async {
var selectionStart = 0;
var selectionLength = 0;

Expand All @@ -26,19 +26,35 @@ Future<void> formatStdin(
selectionLength = selection[1];
}

var languageVersion = options.languageVersion;
if (languageVersion == null && path != null) {
// TODO(rnystrom): Remove the experiment check when the experiment ships.
if (options.experimentFlags.contains(tallStyleExperimentFlag)) {
var cache = LanguageVersionCache();
languageVersion = await cache.find(File(path), path);

// If the lookup failed, don't try to parse the code.
if (languageVersion == null) return;
}
}

// If they didn't specify a version or a path, default to the latest.
languageVersion ??= DartFormatter.latestLanguageVersion;

var name = path ?? 'stdin';

var completer = Completer<void>();
var input = StringBuffer();
stdin.transform(const Utf8Decoder()).listen(input.write, onDone: () {
var formatter = DartFormatter(
languageVersion:
options.languageVersion ?? DartFormatter.latestLanguageVersion,
languageVersion: languageVersion!,
indent: options.indent,
pageWidth: options.pageWidth,
experimentFlags: options.experimentFlags);
try {
options.beforeFile(null, name);
var source = SourceCode(input.toString(),
uri: name,
uri: path,
selectionStart: selectionStart,
selectionLength: selectionLength);
var output = formatter.formatSource(source);
Expand Down Expand Up @@ -138,17 +154,10 @@ Future<bool> _processFile(
// version.
Version? languageVersion;
if (cache != null) {
try {
// Look for a package config. If we don't find one, default to the latest
// language version.
languageVersion = await cache.find(file);
} catch (error) {
stderr.writeln('Could not read package configuration for '
'$displayPath:\n$error');
stderr.writeln('To avoid searching for a package configuration, '
'specify a language version using "--language-version".');
return false;
}
languageVersion = await cache.find(file, displayPath);

// If the lookup failed, don't try to parse the file.
if (languageVersion == null) return false;
} else {
languageVersion = options.languageVersion;
}
Expand Down
8 changes: 7 additions & 1 deletion lib/src/language_version_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class LanguageVersionCache {

/// Looks for a package surrounding [file] and, if found, returns the default
/// language version specified by that package.
Future<Version?> find(File file) async {
Future<Version?> find(File file, String displayPath) async {
Profile.begin('look up package config');
try {
// Use the cached version (which may be `null`) if present.
Expand All @@ -55,6 +55,12 @@ class LanguageVersionCache {

// We weren't able to resolve this file's directory, so don't try again.
return _directoryVersions[directory] = null;
} catch (error) {
stderr.writeln('Could not read package configuration for '
'$displayPath:\n$error');
stderr.writeln('To avoid searching for a package configuration, '
'specify a language version using "--language-version".');
return null;
} finally {
Profile.end('look up package config');
}
Expand Down
Loading

0 comments on commit 0c1f628

Please sign in to comment.