Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuring project-wide page width using a surrounding analysis_options.yaml file #1571

Merged
merged 7 commits into from
Oct 7, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Merge branch 'main' into analysis-options
# Conflicts:
#	lib/src/language_version_cache.dart
  • Loading branch information
munificent committed Oct 7, 2024
commit 2e37ca37641501caaf7b80c5bca027e9317c2967
4 changes: 2 additions & 2 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ jobs:
matrix:
sdk: [3.4.0, dev]
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
with:
sdk: ${{ matrix.sdk }}
@@ -52,7 +52,7 @@ jobs:
os: [ubuntu-latest]
sdk: [3.4.0, dev]
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
- uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672
with:
sdk: ${{ matrix.sdk }}
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -67,6 +67,12 @@
If `--stdin-name` and `--language-version` are both omitted, then parses
stdin using the latest supported language version.

* **Apply class modifiers to API classes.** The dart_style package exposes only
a few classes in its public API: `DartFormatter`, `SourceCode`,
`FormatterException`, and `UnexpectedOutputException`. None were ever
intended to be extended or implemented. They are now all marked `final` to
make that intention explicit.

## 2.3.7

* Allow passing a language version to `DartFomatter()`. Formatted code will be
2 changes: 1 addition & 1 deletion lib/src/analysis_options/analysis_options_file.dart
Original file line number Diff line number Diff line change
@@ -105,7 +105,7 @@ Future<AnalysisOptions> readAnalysisOptions(

/// Exception thrown when an analysis options file contains a "package:" URI in
/// an include and resolving the URI to a file path failed.
class PackageResolutionException implements Exception {
final class PackageResolutionException implements Exception {
final String _message;

PackageResolutionException(this._message);
4 changes: 2 additions & 2 deletions lib/src/analysis_options/io_file_system.dart
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import 'package:path/path.dart' as p;
import 'file_system.dart';

/// An implementation of [FileSystem] using `dart:io`.
class IOFileSystem implements FileSystem {
final class IOFileSystem implements FileSystem {
Future<IOFileSystemPath> makePath(String path) async =>
IOFileSystemPath._(path);

@@ -42,7 +42,7 @@ class IOFileSystem implements FileSystem {
/// An abstraction over a file path string, used by [IOFileSystem].
///
/// To create an instance of this, use [IOFileSystem.makePath()].
class IOFileSystemPath implements FileSystemPath {
final class IOFileSystemPath implements FileSystemPath {
/// The underlying physical file system path.
final String path;

2 changes: 1 addition & 1 deletion lib/src/back_end/code.dart
Original file line number Diff line number Diff line change
@@ -177,7 +177,7 @@ enum _Marker { start, end }

/// Traverses a [Code] tree and produces the final string of output code and
/// the selection markers, if any.
class _StringBuilder {
final class _StringBuilder {
/// Pre-calculated whitespace strings for various common levels of
/// indentation.
///
4 changes: 2 additions & 2 deletions lib/src/back_end/code_writer.dart
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ import 'solution_cache.dart';
/// an instance of this class. It has methods that the piece can call to add
/// output text to the resulting code, recursively format child pieces, insert
/// whitespace, etc.
class CodeWriter {
final class CodeWriter {
final int _pageWidth;

/// Previously cached formatted subtrees.
@@ -415,7 +415,7 @@ enum Whitespace {
}

/// A level of indentation in the indentation stack.
class _Indent {
final class _Indent {
/// The total number of spaces of indentation.
final int indent;

2 changes: 1 addition & 1 deletion lib/src/back_end/solution.dart
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ import 'solution_cache.dart';
/// of the pieces in the tree so they can format themselves. That in turn
/// yields a total number of overflow characters, cost, and formatted output,
/// which are all stored here.
class Solution implements Comparable<Solution> {
final class Solution implements Comparable<Solution> {
/// The states that pieces have been bound to.
///
/// Note that order that keys are inserted into this map is significant. When
2 changes: 1 addition & 1 deletion lib/src/back_end/solution_cache.dart
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import 'solver.dart';
/// the same child Piece and wanting to format it separately with the same
/// indentation. When that happens, sharing this cache allows us to reuse that
/// cached subtree Solution.
class SolutionCache {
final class SolutionCache {
final _cache = <_Key, Solution>{};

/// Returns a previously cached solution for formatting [root] with leading
2 changes: 1 addition & 1 deletion lib/src/back_end/solver.dart
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ const _maxAttempts = 10000;
/// use it across different Solutions. This enables us to both divide and
/// conquer the Piece tree and solve portions separately, while also
/// reusing work across different solutions.
class Solver {
final class Solver {
final SolutionCache _cache;

final int _pageWidth;
2 changes: 1 addition & 1 deletion lib/src/cli/format_command.dart
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ import 'output.dart';
import 'show.dart';
import 'summary.dart';

class FormatCommand extends Command<int> {
final class FormatCommand extends Command<int> {
@override
String get name => 'format';

2 changes: 1 addition & 1 deletion lib/src/cli/formatter_options.dart
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ import 'summary.dart';
const dartStyleVersion = '2.3.7';

/// Global options that affect how the formatter produces and uses its outputs.
class FormatterOptions {
final class FormatterOptions {
/// The language version formatted code should be parsed at or `null` if not
/// specified.
final Version? languageVersion;
6 changes: 3 additions & 3 deletions lib/src/cli/summary.dart
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import '../source_code.dart';
import 'formatter_options.dart';

/// The kind of summary shown after all formatting is complete.
class Summary {
final class Summary {
static const Summary none = Summary._();

/// Creates a Summary that tracks how many files were formatted and the total
@@ -41,7 +41,7 @@ class Summary {
}

/// Tracks how many files were formatted and the total time.
class _LineSummary extends Summary {
final class _LineSummary extends Summary {
final DateTime _start = DateTime.now();

/// The number of processed files.
@@ -81,7 +81,7 @@ class _LineSummary extends Summary {
}

/// Reports how long it took for format each file.
class _ProfileSummary implements Summary {
final class _ProfileSummary implements Summary {
/// The files that have been started but have not completed yet.
///
/// Maps a file label to the time that it started being formatted.
2 changes: 1 addition & 1 deletion lib/src/config_cache.dart
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ import 'profile.dart';
///
/// This class also directly caches the language versions and page widths that
/// are then inferred from the package config and analysis_options.yaml files.
class ConfigCache {
final class ConfigCache {
/// The previously cached package config for all files immediately within a
/// given directory.
final Map<String, PackageConfig?> _directoryConfigs = {};
4 changes: 2 additions & 2 deletions lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ const tallStyleExperimentFlag = 'tall-style';

/// Constants for the cost heuristics used to determine which set of splits is
/// most desirable.
class Cost {
final class Cost {
/// The cost of splitting after the `=>` in a lambda or arrow-bodied member.
///
/// We make this zero because there is already a span around the entire body
@@ -64,7 +64,7 @@ class Cost {
}

/// Constants for the number of spaces for various kinds of indentation.
class Indent {
final class Indent {
/// Reset back to no indentation.
static const none = 0;

22 changes: 20 additions & 2 deletions lib/src/dart_formatter.dart
Original file line number Diff line number Diff line change
@@ -21,8 +21,13 @@ import 'short/source_visitor.dart';
import 'source_code.dart';
import 'string_compare.dart' as string_compare;

/// Regular expression that matches a format width comment like:
///
/// // dart format width=123
final RegExp _widthCommentPattern = RegExp(r'^// dart format width=(\d+)$');

/// Dart source code formatter.
class DartFormatter {
final class DartFormatter {
/// The latest Dart language version that can be parsed and formatted by this
/// version of the formatter.
static final latestLanguageVersion = Version(3, 3, 0);
@@ -182,8 +187,21 @@ class DartFormatter {

SourceCode output;
if (experimentFlags.contains(tallStyleExperimentFlag)) {
// Look for a page width comment before the code.
int? pageWidthFromComment;
for (Token? comment = node.beginToken.precedingComments;
comment != null;
comment = comment.next) {
if (_widthCommentPattern.firstMatch(comment.lexeme) case var match?) {
// If integer parsing fails for some reason, the returned `null`
// means we correctly ignore the comment.
pageWidthFromComment = int.tryParse(match[1]!);
break;
}
}

var visitor = AstNodeVisitor(this, lineInfo, unitSourceCode);
output = visitor.run(unitSourceCode, node);
output = visitor.run(unitSourceCode, node, pageWidthFromComment);
} else {
var visitor = SourceVisitor(this, lineInfo, unitSourceCode);
output = visitor.run(node);
2 changes: 1 addition & 1 deletion lib/src/debug.dart
Original file line number Diff line number Diff line change
@@ -277,7 +277,7 @@ String pieceTree(Piece piece) {
}

/// A stringified representation of a tree of pieces for debug output.
class _PieceDebugTree {
final class _PieceDebugTree {
final String label;
final List<_PieceDebugTree> children = [];

4 changes: 2 additions & 2 deletions lib/src/exceptions.dart
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ import 'package:source_span/source_span.dart';

/// Thrown when one or more errors occurs while parsing the code to be
/// formatted.
class FormatterException implements Exception {
final class FormatterException implements Exception {
/// The [AnalysisError]s that occurred.
final List<AnalysisError> errors;

@@ -53,7 +53,7 @@ class FormatterException implements Exception {

/// Exception thrown when the internal sanity check that only whitespace
/// changes are made fails.
class UnexpectedOutputException implements Exception {
final class UnexpectedOutputException implements Exception {
/// The source being formatted.
final String _input;

9 changes: 6 additions & 3 deletions lib/src/front_end/ast_node_visitor.dart
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ import 'sequence_builder.dart';
/// To avoid this class becoming a monolith, functionality is divided into a
/// couple of mixins, one for each area of functionality. This class then
/// contains only shared state and the visitor methods for the AST.
class AstNodeVisitor extends ThrowingAstVisitor<void> with PieceFactory {
final class AstNodeVisitor extends ThrowingAstVisitor<void> with PieceFactory {
@override
final PieceWriter pieces;

@@ -66,7 +66,10 @@ class AstNodeVisitor extends ThrowingAstVisitor<void> with PieceFactory {
///
/// This is the only method that should be called externally. Everything else
/// is effectively private.
SourceCode run(SourceCode source, AstNode node) {
///
/// If there is a `// dart format width=123` comment before the formatted
/// code, then [pageWidthFromComment] is that width.
SourceCode run(SourceCode source, AstNode node, [int? pageWidthFromComment]) {
Profile.begin('AstNodeVisitor.run()');

Profile.begin('AstNodeVisitor build Piece tree');
@@ -123,7 +126,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<void> with PieceFactory {
Profile.end('AstNodeVisitor build Piece tree');

// Finish writing and return the complete result.
var result = pieces.finish(source, unitPiece);
var result = pieces.finish(source, unitPiece, pageWidthFromComment);

Profile.end('AstNodeVisitor.run()');

2 changes: 1 addition & 1 deletion lib/src/front_end/chain_builder.dart
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ import 'piece_factory.dart';
///
/// This lets us create a single [ChainPiece] for the entire series of dotted
/// operations, so that we can control splitting them or not as a unit.
class ChainBuilder {
final class ChainBuilder {
final PieceFactory _visitor;

/// The outermost expression being converted to a chain.
6 changes: 3 additions & 3 deletions lib/src/front_end/comment_writer.dart
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ import '../comment_type.dart';
/// construct. These get directly embedded in the [TextPiece] of the code being
/// written. When that [TextPiece] is output later, it will include the comments
/// as well.
class CommentWriter {
final class CommentWriter {
final LineInfo _lineInfo;

/// The tokens whose preceding comments have already been taken by calls to
@@ -147,7 +147,7 @@ class CommentWriter {

/// A comment in the source, with a bit of information about the surrounding
/// whitespace.
class SourceComment {
final class SourceComment {
/// The text of the comment, including `//`, `/*`, and `*/`.
final String text;

@@ -210,7 +210,7 @@ class SourceComment {
/// * 2 newlines between `/* c2 */` and `/* c3 */`
/// * Comment `/* c3 */`
/// * 3 newlines between `/* c3 */` and `b`
class CommentSequence extends ListBase<SourceComment> {
final class CommentSequence extends ListBase<SourceComment> {
static const CommentSequence empty = CommentSequence._([0], []);

/// The number of newlines between a pair of comments or the preceding or
2 changes: 1 addition & 1 deletion lib/src/front_end/delimited_list_builder.dart
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ import 'piece_factory.dart';
/// delimiter token. Then call [add()] for each [AstNode] that is inside the
/// delimiters. The [rightBracket()] with the closing delimiter and finally
/// [build()] to get the resulting [ListPiece].
class DelimitedListBuilder {
final class DelimitedListBuilder {
final PieceFactory _visitor;

/// The opening bracket before the elements, if any.
3 changes: 2 additions & 1 deletion lib/src/front_end/piece_factory.dart
Original file line number Diff line number Diff line change
@@ -775,7 +775,8 @@ mixin PieceFactory {
pieces.token(catchKeyword);
pieces.space();

var parameters = DelimitedListBuilder(this);
var parameters = DelimitedListBuilder(
this, const ListStyle(commas: Commas.nonTrailing));
parameters.leftBracket(catchClause.leftParenthesis!);
if (catchClause.exceptionParameter case var exceptionParameter?) {
parameters.visit(exceptionParameter);
11 changes: 8 additions & 3 deletions lib/src/front_end/piece_writer.dart
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ import 'sequence_builder.dart';
///
/// Handles updating selection markers and attaching comments to the tokens
/// before and after the comments.
class PieceWriter {
final class PieceWriter {
final DartFormatter _formatter;

final SourceCode _source;
@@ -390,7 +390,11 @@ class PieceWriter {

/// Finishes writing and returns a [SourceCode] containing the final output
/// and updated selection, if any.
SourceCode finish(SourceCode source, Piece rootPiece) {
///
/// If there is a `// dart format width=123` comment before the formatted
/// code, then [pageWidthFromComment] is that width.
SourceCode finish(
SourceCode source, Piece rootPiece, int? pageWidthFromComment) {
if (debug.tracePieceBuilder) {
debug.log(debug.pieceTree(rootPiece));
}
@@ -399,7 +403,8 @@ class PieceWriter {

var cache = SolutionCache();
var solver = Solver(cache,
pageWidth: _formatter.pageWidth, leadingIndent: _formatter.indent);
pageWidth: pageWidthFromComment ?? _formatter.pageWidth,
leadingIndent: _formatter.indent);
var solution = solver.format(rootPiece);
var output = solution.code.build(source, _formatter.lineEnding);

2 changes: 1 addition & 1 deletion lib/src/front_end/sequence_builder.dart
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ import 'piece_factory.dart';
/// separate statements inside the sequence. This lets us gracefully handle
/// indenting them and supporting blank lines around them the same way we handle
/// other statements or members in a sequence.
class SequenceBuilder {
final class SequenceBuilder {
final PieceFactory _visitor;

/// The opening bracket before the elements, if any.
2 changes: 1 addition & 1 deletion lib/src/piece/adjacent.dart
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import '../back_end/code_writer.dart';
import 'piece.dart';

/// A simple piece that just writes its child pieces one after the other.
class AdjacentPiece extends Piece {
final class AdjacentPiece extends Piece {
final List<Piece> pieces;

AdjacentPiece(this.pieces);
2 changes: 1 addition & 1 deletion lib/src/piece/assign.dart
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ import 'piece.dart';
/// var [unsplitBlock] =
/// longOperand +
/// anotherOperand;
class AssignPiece extends Piece {
final class AssignPiece extends Piece {
/// Force the block left-hand side to split and allow the right-hand side to
/// split.
static const State _blockSplitLeft = State(1);
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.