Skip to content
Open
Show file tree
Hide file tree
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
8 changes: 3 additions & 5 deletions lib/src/analysis_options/analysis_options_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,9 @@ 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.
final class PackageResolutionException implements Exception {
final String _message;

PackageResolutionException(this._message);

final class PackageResolutionException(
final String _message,
) implements Exception {
@override
String toString() => _message;
}
7 changes: 3 additions & 4 deletions lib/src/analysis_options/io_file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ final class IOFileSystem implements FileSystem {
/// An abstraction over a file path string, used by [IOFileSystem].
///
/// To create an instance of this, use [IOFileSystem.makePath()].
final class IOFileSystemPath implements FileSystemPath {
final class IOFileSystemPath._(
/// The underlying physical file system path.
final String path;
final String path,
) implements FileSystemPath;

IOFileSystemPath._(this.path);
}
77 changes: 35 additions & 42 deletions lib/src/back_end/code.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@ sealed class Code {

/// A [Code] object which can be written to and contain other child [Code]
/// objects.
final class GroupCode extends Code {
final class GroupCode(
/// How many spaces the first text inside this group should be indented.
final int _indent;

final int _indent,
) extends Code {
/// The child [Code] objects contained in this group.
final List<Code> _children = [];

GroupCode(this._indent);

/// Appends [text] to this code.
void write(String text) {
_children.add(_TextCode(text));
Expand Down Expand Up @@ -135,60 +133,59 @@ final class GroupCode extends Code {

/// A [Code] object for a newline followed by any leading indentation.
final class _NewlineCode extends Code {
/// Whether a blank line (two newlines) should be written.
final bool _blank;

/// The number of spaces of indentation after this newline.
final int _indent;
this({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use an in-body constructor for _NewlineCode, _TextCode, _MarkerCode etc? I think _StringBuilder looks nicer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong answer, I just felt like those had big enough constructor parameter lists that it looked weird to stuff it in the class header and bury the extends Code part.

/// Whether a blank line (two newlines) should be written.
required final bool _blank,

_NewlineCode({required bool blank, required int indent})
: _indent = indent,
_blank = blank;
/// The number of spaces of indentation after this newline.
required final int _indent,
});
}

/// A [Code] object for literal source text.
final class _TextCode extends Code {
final String _text;

_TextCode(this._text);
this(final String _text);
}

/// Marks the location of the beginning or end of a selection as occurring
/// [_offset] characters past the point where this marker object appears in the
/// list of [Code] objects.
final class _MarkerCode extends Code {
/// What kind of selection endpoint is being marked.
final _Marker _marker;

/// The number of characters into the next [Code] object where the marker
/// should appear in the resulting output.
final int _offset;

_MarkerCode(this._marker, this._offset);
this(
/// What kind of selection endpoint is being marked.
final _Marker _marker,

/// The number of characters into the next [Code] object where the marker
/// should appear in the resulting output.
final int _offset,
);
}

final class _EnableFormattingCode extends Code {
/// Whether this comment disables formatting (`format off`) or re-enables it
/// (`format on`).
final bool _enabled;

/// The number of code points from the beginning of the unformatted source
/// where the unformatted code should begin or end.
///
/// If this piece is for `// dart format off`, then the offset is just past
/// the `off`. If this piece is for `// dart format on`, it points to just
/// before `//`.
final int _sourceOffset;

_EnableFormattingCode(this._enabled, this._sourceOffset);
this(
/// Whether this comment disables formatting (`format off`) or re-enables it
/// (`format on`).
final bool _enabled,

/// The number of code points from the beginning of the unformatted source
/// where the unformatted code should begin or end.
///
/// If this piece is for `// dart format off`, then the offset is just past
/// the `off`. If this piece is for `// dart format on`, it points to just
/// before `//`.
final int _sourceOffset,
);
}

/// Which selection marker is pointed to by a [_MarkerCode].
enum _Marker { start, end }

/// Traverses a [Code] tree and produces the final string of output code and
/// the selection markers, if any.
final class _StringBuilder {
final class _StringBuilder(
final SourceCode _source,
final String _lineEnding,
) {
/// Pre-calculated whitespace strings for various common levels of
/// indentation.
///
Expand Down Expand Up @@ -227,8 +224,6 @@ final class _StringBuilder {
60: ' ',
};

final SourceCode _source;
final String _lineEnding;
final StringBuffer _buffer = StringBuffer();

/// The offset from the beginning of the source to where the selection start
Expand All @@ -248,8 +243,6 @@ final class _StringBuilder {
/// Otherwise, -1 to indicate that formatting is enabled.
int _disableFormattingStart = -1;

_StringBuilder(this._source, this._lineEnding);

void traverse(Code code) {
switch (code) {
case _NewlineCode():
Expand Down
80 changes: 33 additions & 47 deletions lib/src/back_end/code_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ 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.
final class CodeWriter {
final int _pageWidth;

final class CodeWriter(
final int _pageWidth,
int leadingIndent,
int subsequentIndent,
/// Previously cached formatted subtrees.
final SolutionCache _cache;
final SolutionCache _cache,

/// The solution this [CodeWriter] is generating code for.
final Solution _solution;

final Solution _solution,
) {
/// The code being written.
final GroupCode _code;
final GroupCode _code = GroupCode(leadingIndent);

/// What whitespace should be written before the next non-whitespace text.
///
Expand All @@ -47,17 +48,25 @@ final class CodeWriter {
/// The number of spaces of indentation that should be begin the next line
/// when [_pendingWhitespace] is [Whitespace.newline] or
/// [Whitespace.blankLine].
int _pendingIndent = 0;
int _pendingIndent = leadingIndent;

/// The number of characters in the line currently being written.
int _column = 0;
int _column = leadingIndent;

/// The stack of indentation levels.
///
/// Each entry in the stack is the absolute number of spaces of leading
/// indentation that should be written when beginning a new line to account
/// for block nesting, expression wrapping, constructor initializers, etc.
final List<_IndentLevel> _indentStack = [];
final List<_IndentLevel> _indentStack = [
_IndentLevel(Indent.none, leadingIndent),

// If there is additional indentation on subsequent lines, then push that
// onto the stack. When the first newline is written, [_pendingIndent] will
// pick this up and use it for subsequent lines.
if (subsequentIndent > leadingIndent)
_IndentLevel(Indent.none, subsequentIndent)
];

/// The stack of information for each [Piece] currently being formatted.
///
Expand Down Expand Up @@ -102,26 +111,7 @@ final class CodeWriter {
/// beginning of the first line and [subsequentIndent] is the indentation of
/// each line after that, independent of indentation created by pieces being
/// written.
CodeWriter(
this._pageWidth,
int leadingIndent,
int subsequentIndent,
this._cache,
this._solution,
) : _code = GroupCode(leadingIndent) {
_indentStack.add(_IndentLevel(Indent.none, leadingIndent));

// Track the leading indent before the first line.
_pendingIndent = leadingIndent;
_column = _pendingIndent;

// If there is additional indentation on subsequent lines, then push that
// onto the stack. When the first newline is written, [_pendingIndent] will
// pick this up and use it for subsequent lines.
if (subsequentIndent > leadingIndent) {
_indentStack.add(_IndentLevel(Indent.none, subsequentIndent));
}
}
this;

/// Returns the final formatted code and the next pieces that can be expanded
/// from the solution this [CodeWriter] is writing, if any.
Expand Down Expand Up @@ -541,7 +531,10 @@ enum Whitespace {
/// is also semantic: a type describes *why* it writes that, or what kind of
/// syntax its coming from. This allows us to merge or combine indentation in
/// smarter ways in some contexts.
enum Indent {
enum const Indent(
/// The number of spaces this type of indentation applies.
final int spaces,
) {
// No indentation.
none(0),

Expand Down Expand Up @@ -575,29 +568,22 @@ enum Indent {

/// Constructor initializer when the parameter list does have optional or
/// named parameters.
initializerWithOptionalParameter(3);

/// The number of spaces this type of indentation applies.
final int spaces;

const Indent(this.spaces);
initializerWithOptionalParameter(3),
}

/// Information for each piece currently being formatted while [CodeWriter]
/// traverses the piece tree.
class _FormatState {
class _FormatState(
/// The piece being formatted.
final Piece piece;

final Piece piece,
) {
/// The piece's shape.
///
/// This changes based on the newlines the piece writes.
Shape shape = Shape.inline;

/// How a newline affects the shape of this piece.
ShapeMode mode = ShapeMode.merge;

_FormatState(this.piece);
}

/// Determines how a newline inside a piece or a child piece affects the shape
Expand Down Expand Up @@ -626,23 +612,23 @@ enum ShapeMode {
}

/// A level of indentation in the indentation stack.
final class _IndentLevel {
final class _IndentLevel(
/// The reason this indentation was added.
///
/// Not used for 3.7 style.
final Indent type;
final Indent type,

/// The total number of spaces of indentation.
final int spaces;

final int spaces,
) {
/// How many spaces of [spaces] can be collapsed with further indentation.
///
/// Only used for 3.7 style.
final int collapsible;

_IndentLevel.v3Dot7(this.spaces, this.collapsible) : type = Indent.none;

_IndentLevel(this.type, this.spaces) : collapsible = 0;
this : collapsible = 0;

@override
String toString() => '${type.name}:$spaces';
Expand Down
4 changes: 2 additions & 2 deletions lib/src/back_end/solution.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ final class Solution implements Comparable<Solution> {
/// Creates a new [Solution] with no pieces set to any state (which
/// implicitly means they have state [State.unsplit] unless they're pinned to
/// another state).
factory Solution(
factory(
SolutionCache cache,
Piece root, {
required int pageWidth,
Expand All @@ -126,7 +126,7 @@ final class Solution implements Comparable<Solution> {
return solution;
}

Solution._(
new _(
Piece root,
this._cost,
this._pieceStates,
Expand Down
8 changes: 3 additions & 5 deletions lib/src/back_end/solution_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ 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.
final class SolutionCache {
final class SolutionCache({
/// Whether this cache and all solutions in it use the 3.7 style solver.
final bool is3Dot7;

required final bool is3Dot7,
}) {
final _cache = <_Key, Solution>{};

SolutionCache({required this.is3Dot7});

/// Returns a previously cached solution for formatting [root] with leading
/// [indent] (and [subsequentIndent] for lines after the first) or produces a
/// new solution, caches it, and returns it.
Expand Down
21 changes: 7 additions & 14 deletions lib/src/back_end/solver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ const _maxAttempts = 10000;
/// conquer the Piece tree and solve portions separately, while also
/// reusing work across different solutions.
final class Solver {
final SolutionCache _cache;

final int _pageWidth;

/// The number of spaces of indentation on the first line.
final int _leadingIndent;

/// The number of spaces of indentation on all lines after the first.
final int _subsequentIndent;

Expand All @@ -60,14 +53,14 @@ final class Solver {
/// The first line is indented by [leadingIndent] spaces and all lines after
/// that are indented by [subsequentIndent]. If [subsequentIndent] is omitted,
/// defaults to [leadingIndent].
Solver(
this._cache, {
required int pageWidth,
int leadingIndent = 0,
this(
final SolutionCache _cache, {
required final int _pageWidth,

/// The number of spaces of indentation on the first line.
int final int _leadingIndent = 0,
int? subsequentIndent,
}) : _pageWidth = pageWidth,
_leadingIndent = leadingIndent,
_subsequentIndent = subsequentIndent ?? leadingIndent;
}) : _subsequentIndent = subsequentIndent ?? leadingIndent;

/// Finds the best set of line splits for [root] piece and returns the
/// resulting formatted code.
Expand Down
Loading
Loading