Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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);
}
55 changes: 20 additions & 35 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 @@ -134,61 +132,52 @@ final class GroupCode extends Code {
}

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

/// The number of spaces of indentation after this newline.
final int _indent;

_NewlineCode({required bool blank, required int indent})
: _indent = indent,
_blank = blank;
}
required final int _indent,
}) extends Code;

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

_TextCode(this._text);
}
final class _TextCode(final String _text) extends Code;

/// 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 {
final class _MarkerCode(
/// What kind of selection endpoint is being marked.
final _Marker _marker;
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 int _offset,
) extends Code;

_MarkerCode(this._marker, this._offset);
}

final class _EnableFormattingCode extends Code {
final class _EnableFormattingCode(
/// Whether this comment disables formatting (`format off`) or re-enables it
/// (`format on`).
final bool _enabled;
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);
}
final int _sourceOffset,
) extends Code;

/// 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 +216,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 +235,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
23 changes: 8 additions & 15 deletions lib/src/back_end/solver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ 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.
final class Solver {
final SolutionCache _cache;

final int _pageWidth;
final class Solver(
final SolutionCache _cache, {
required final int _pageWidth,

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

int final int _leadingIndent = 0,
int? subsequentIndent,
}) {
/// The number of spaces of indentation on all lines after the first.
final int _subsequentIndent;
final int _subsequentIndent = subsequentIndent ?? _leadingIndent;

final PriorityQueue<Solution> _queue = PriorityQueue();

Expand All @@ -60,14 +60,7 @@ 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,
int? subsequentIndent,
}) : _pageWidth = pageWidth,
_leadingIndent = leadingIndent,
_subsequentIndent = subsequentIndent ?? leadingIndent;
this;

/// Finds the best set of line splits for [root] piece and returns the
/// resulting formatted code.
Expand Down
8 changes: 4 additions & 4 deletions lib/src/cli/format_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ final class FormatCommand extends Command<int> {
@override
String get name => 'format';

@override
final String category;

@override
String get description => 'Idiomatically format Dart source code.';

@override
String get invocation =>
'${runner!.executableName} $name [options...] <files or directories...>';

@override
final String category;

FormatCommand({bool verbose = false, this.category = ''}) {
new({bool verbose = false, this.category = ''}) {
argParser.addFlag(
'verbose',
abbr: 'v',
Expand Down
Loading
Loading