From a6af7e6a52b0eb362ee8606fd182a81b90e43c56 Mon Sep 17 00:00:00 2001 From: eggnstone Date: Sun, 21 Jul 2024 11:36:36 +0200 Subject: [PATCH] Fixed ClassDeclaration indentation. --- lib/src/Constants/Constants.dart | 3 ++ lib/src/FormatState.dart | 40 +++++++++++++------ lib/src/FormatVisitor.dart | 3 +- lib/src/Formatter.dart | 7 +++- .../Formatters/ClassDeclarationFormatter.dart | 13 ++++++ lib/src/Formatters/DefaultFormatter.dart | 12 +++++- lib/src/Formatters/IFormatter.dart | 17 +++++--- .../Formatters/MethodInvocationFormatter.dart | 6 ++- .../AddNewLineAfterToken_test.dart | 13 +++++- .../ClassDeclarationFormatter_test.dart | 12 ++++++ 10 files changed, 99 insertions(+), 27 deletions(-) diff --git a/lib/src/Constants/Constants.dart b/lib/src/Constants/Constants.dart index 122e35f..13dc978 100644 --- a/lib/src/Constants/Constants.dart +++ b/lib/src/Constants/Constants.dart @@ -11,12 +11,15 @@ class Constants static const bool DEBUG_FORMATTER_DEFAULT = (DEBUG && false) || DEBUG_ALL; static const bool DEBUG_I_FORMATTER = (DEBUG && false) || DEBUG_ALL; static const bool DEBUG_I_FORMATTER_OFFSETS = (DEBUG && false) || DEBUG_ALL; + static const bool DEBUG_I_FORMATTER_TIME = (DEBUG && false) || DEBUG_ALL; static const bool DEBUG_STRING_TOOLS = (DEBUG && false) || DEBUG_ALL; static const bool DEBUG_TODOS = (DEBUG && false) || DEBUG_ALL; static const int HTTP_TOOLS_WAIT_BETWEEN_FLUSH_AND_CLOSE_IN_MILLISECONDS = 100; static const int MAX_DEBUG_LENGTH = 50; + static const int MAX_FORMAT_TIME_IN_SECONDS = DEBUG ? 10 : 50; + static const int MAX_FORMAT_TIME_IN_SECONDS_FOR_TESTS = 1; static const int PREFERRED_PORT = 7777; diff --git a/lib/src/FormatState.dart b/lib/src/FormatState.dart index b1ae8e1..ea79447 100644 --- a/lib/src/FormatState.dart +++ b/lib/src/FormatState.dart @@ -19,8 +19,10 @@ import 'Types/IndentationType.dart'; class FormatState { final int _indentationSpacesPerLevel; + final DateTime _maxDateTime; final ParseStringResult _parseResult; final bool _removeTrailingCommas; + final DateTime _startDateTime; final List _textBuffers = [StringBufferEx()]; final List _indentations = []; @@ -30,21 +32,27 @@ class FormatState int logIndent = 0; - CompilationUnit get compilationUnit - => _parseResult.unit; + CompilationUnit get compilationUnit => _parseResult.unit; - int get lastConsumedPosition - => _lastConsumedPosition; + int get lastConsumedPosition => _lastConsumedPosition; + + DateTime get maxDateTime => _maxDateTime; + + DateTime get startDateTime => _startDateTime; FormatState( ParseStringResult parseResult, { required int indentationSpacesPerLevel, - required bool removeTrailingCommas + required DateTime maxDateTime, + required bool removeTrailingCommas, + required DateTime startDateTime } ) : _indentationSpacesPerLevel = indentationSpacesPerLevel, + _maxDateTime = maxDateTime, _removeTrailingCommas = removeTrailingCommas, - _parseResult = parseResult; + _parseResult = parseResult, + _startDateTime = startDateTime; factory FormatState.test(ParseStringResult parseResult, { required int indentationSpacesPerLevel, @@ -53,13 +61,19 @@ class FormatState String? trailing } ) - => FormatState( - parseResult, - indentationSpacesPerLevel: indentationSpacesPerLevel, - removeTrailingCommas : removeTrailingCommas - ) - .._lastConsumedPosition = leading?.length ?? 0 - .._trailingForTests = trailing; + { + final DateTime startDateTime = DateTime.now(); + final DateTime maxDateTime = startDateTime.add(const Duration(seconds: Constants.MAX_FORMAT_TIME_IN_SECONDS_FOR_TESTS)); + return FormatState( + parseResult, + indentationSpacesPerLevel: indentationSpacesPerLevel, + maxDateTime: maxDateTime, + removeTrailingCommas : removeTrailingCommas, + startDateTime: startDateTime + ) + .._lastConsumedPosition = leading?.length ?? 0 + .._trailingForTests = trailing; + } void acceptListWithPeriod(List nodes, AstVisitor astVisitor, String source) { diff --git a/lib/src/FormatVisitor.dart b/lib/src/FormatVisitor.dart index e48ab6e..61f2949 100644 --- a/lib/src/FormatVisitor.dart +++ b/lib/src/FormatVisitor.dart @@ -77,8 +77,7 @@ import 'Formatters/YieldStatementFormatter.dart'; class FormatVisitor extends AstVisitor { final Config config; - - late final FormatState _formatState; + final FormatState _formatState; late final ArgumentListFormatter _argumentListFormatter = ArgumentListFormatter(config, this, _formatState); late final AssertInitializerFormatter _assertInitializerFormatter = AssertInitializerFormatter(config, this, _formatState); diff --git a/lib/src/Formatter.dart b/lib/src/Formatter.dart index c17fb81..0b1df59 100644 --- a/lib/src/Formatter.dart +++ b/lib/src/Formatter.dart @@ -43,11 +43,16 @@ class Formatter if (errors.isNotEmpty) _logAndThrowWarning(errors.first.message, parseResult.lineInfo.getLocation(errors.first.offset)); + final DateTime startDateTime = DateTime.now(); + final DateTime maxDateTime = startDateTime.add(const Duration(seconds: Constants.MAX_FORMAT_TIME_IN_SECONDS)); final FormatState formatState = FormatState( parseResult, indentationSpacesPerLevel: _config.indentationSpacesPerLevel, - removeTrailingCommas: _config.removeTrailingCommas + maxDateTime: maxDateTime, + removeTrailingCommas: _config.removeTrailingCommas, + startDateTime: startDateTime ); + final FormatVisitor visitor = FormatVisitor(config: _config, formatState: formatState); formatState.compilationUnit.accept(visitor); String result = formatState.getResult(); diff --git a/lib/src/Formatters/ClassDeclarationFormatter.dart b/lib/src/Formatters/ClassDeclarationFormatter.dart index da0cede..3bd4d5d 100644 --- a/lib/src/Formatters/ClassDeclarationFormatter.dart +++ b/lib/src/Formatters/ClassDeclarationFormatter.dart @@ -25,6 +25,11 @@ class ClassDeclarationFormatter extends IFormatter if (node is! ClassDeclaration) throw FormatException('Not a ClassDeclaration: ${node.runtimeType}'); + final String textWithPossibleLineBreak = formatState.getText(node.classKeyword.offset, node.leftBracket.offset); + //log('textWithPossibleLineBreak: ${StringTools.toDisplayString(textWithPossibleLineBreak)}', 0); + final bool pushLevel = textWithPossibleLineBreak.contains('\n'); + //log('pushLevel: $pushLevel', 0); + formatState.acceptList(node.sortedCommentAndAnnotations, astVisitor, '$methodName/node.sortedCommentAndAnnotations'); formatState.copyEntity(node.sealedKeyword, astVisitor, '$methodName/node.abstractKeyword'); formatState.copyEntity(node.abstractKeyword, astVisitor, '$methodName/node.abstractKeyword'); @@ -33,11 +38,19 @@ class ClassDeclarationFormatter extends IFormatter formatState.copyEntity(node.interfaceKeyword, astVisitor, '$methodName/node.interfaceKeyword'); formatState.copyEntity(node.finalKeyword, astVisitor, '$methodName/node.finalKeyword'); formatState.copyEntity(node.classKeyword, astVisitor, '$methodName/node.classKeyword'); + + if (pushLevel) + formatState.pushLevel('$methodName/node.classKeyword/after'); + formatState.copyEntity(node.name, astVisitor, '$methodName/node.name'); formatState.copyEntity(node.typeParameters, astVisitor, '$methodName/node.typeParameters'); formatState.copyEntity(node.extendsClause, astVisitor, '$methodName/node.extendsClause'); formatState.copyEntity(node.withClause, astVisitor, '$methodName/node.withClause'); formatState.copyEntity(node.implementsClause, astVisitor, '$methodName/node.implementsClause'); + + if (pushLevel) + formatState.popLevelAndIndent(); + formatState.copyOpeningBraceAndPushLevel(node.leftBracket, config, '$methodName/node.leftBracket'); formatState.acceptList(node.members, astVisitor, '$methodName/node.members'); formatState.copyClosingBraceAndPopLevel(node.rightBracket, config, '$methodName/node.rightBracket'); diff --git a/lib/src/Formatters/DefaultFormatter.dart b/lib/src/Formatters/DefaultFormatter.dart index e841ec8..fc0ee17 100644 --- a/lib/src/Formatters/DefaultFormatter.dart +++ b/lib/src/Formatters/DefaultFormatter.dart @@ -23,7 +23,15 @@ class DefaultFormatter extends IFormatter void format(AstNode node) { const String methodName = 'DefaultFormatter.format'; - if (Constants.DEBUG_I_FORMATTER) log('START $methodName(${node.runtimeType}: ${StringTools.toDisplayString(node, Constants.MAX_DEBUG_LENGTH)})', formatState.logIndent++, node.offset); + + if (DateTime.now().isAfter(formatState.maxDateTime)) + throw DartFormatException.error('Timeout'); + + if (Constants.DEBUG_I_FORMATTER) + { + final String message = 'START $methodName(${node.runtimeType}: ${StringTools.toDisplayString(node, Constants.MAX_DEBUG_LENGTH)})'; + log(message, formatState.logIndent++, offset: node.offset, startDateTime: formatState.startDateTime); + } node.childEntities.forEach((SyntacticEntity child) { @@ -58,6 +66,6 @@ class DefaultFormatter extends IFormatter } ); - if (Constants.DEBUG_I_FORMATTER) log('END $methodName(${node.runtimeType}: ${StringTools.toDisplayString(node, Constants.MAX_DEBUG_LENGTH)})', --formatState.logIndent, node.end); + if (Constants.DEBUG_I_FORMATTER) log('END $methodName(${node.runtimeType}: ${StringTools.toDisplayString(node, Constants.MAX_DEBUG_LENGTH)})', --formatState.logIndent, offset: node.end); } } diff --git a/lib/src/Formatters/IFormatter.dart b/lib/src/Formatters/IFormatter.dart index 9a8ec40..ee9b3a3 100644 --- a/lib/src/Formatters/IFormatter.dart +++ b/lib/src/Formatters/IFormatter.dart @@ -7,12 +7,19 @@ abstract class IFormatter { void format(AstNode node); - void log(String s, int indent, [int? offset]) + void log(String s, int indent, {int? offset, DateTime? startDateTime}) { - if (Constants.DEBUG_I_FORMATTER_OFFSETS && offset == null) - logInternal('${offset} ${' ' * indent}$s'); - else - logInternal(' ' * indent + s); + final String indentation = ' ' * indent; + String prefix = ''; + + if (Constants.DEBUG_I_FORMATTER_OFFSETS && offset != null) + prefix += '${offset} '; + + if (Constants.DEBUG_I_FORMATTER_TIME && startDateTime != null) + prefix += '${DateTime.now().difference(startDateTime).inMilliseconds}ms '; + + final String finalS = indentation + prefix + s; + logInternal(finalS); } void logInfo(String s) diff --git a/lib/src/Formatters/MethodInvocationFormatter.dart b/lib/src/Formatters/MethodInvocationFormatter.dart index 0f04ef0..cd947f5 100644 --- a/lib/src/Formatters/MethodInvocationFormatter.dart +++ b/lib/src/Formatters/MethodInvocationFormatter.dart @@ -29,8 +29,10 @@ class MethodInvocationFormatter extends IFormatter bool pushLevel = false; if (node.target != null && node.operator != null && node.operator!.type == TokenType.PERIOD) { - final String textBetweenTargetAndOperator = formatState.getText(node.target!.end, node.operator!.offset); - pushLevel = textBetweenTargetAndOperator.contains('\n'); + final String textWithPossibleLineBreak = formatState.getText(node.target!.end, node.operator!.offset); + //logDebug('textWithPossibleLineBreak: ${StringTools.toDisplayString(textWithPossibleLineBreak)}'); + pushLevel = textWithPossibleLineBreak.contains('\n'); + //logDebug('pushLevel: $pushLevel'); } formatState.copyEntity(node.target, astVisitor, '$methodName/node.target'); diff --git a/test/FormateState/AddNewLineAfterToken_test.dart b/test/FormateState/AddNewLineAfterToken_test.dart index a55021f..b3f243d 100644 --- a/test/FormateState/AddNewLineAfterToken_test.dart +++ b/test/FormateState/AddNewLineAfterToken_test.dart @@ -1,6 +1,7 @@ import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/utilities.dart' as AnalyzerUtilities; // ignore: library_prefixes import 'package:analyzer/dart/ast/token.dart'; +import 'package:dart_format/src/Constants/Constants.dart'; import 'package:dart_format/src/FormatState.dart'; import 'package:test/test.dart'; @@ -25,10 +26,14 @@ void main() inputToken3.next = inputToken4; final ParseStringResult parseResult = AnalyzerUtilities.parseString(content: inputText); + final DateTime startDateTime = DateTime.now(); + final DateTime maxDateTime = startDateTime.add(const Duration(seconds: Constants.MAX_FORMAT_TIME_IN_SECONDS_FOR_TESTS)); final FormatState formatState = FormatState( parseResult, indentationSpacesPerLevel: 4, - removeTrailingCommas: true + maxDateTime: maxDateTime, + removeTrailingCommas: true, + startDateTime: startDateTime ); formatState.addText('int i=0', 'SOURCE'); @@ -62,10 +67,14 @@ void main() inputToken2.next = inputToken3; final ParseStringResult parseResult = AnalyzerUtilities.parseString(content: inputText); + final DateTime startDateTime = DateTime.now(); + final DateTime maxDateTime = startDateTime.add(const Duration(seconds: Constants.MAX_FORMAT_TIME_IN_SECONDS_FOR_TESTS)); final FormatState formatState = FormatState( parseResult, indentationSpacesPerLevel: 4, - removeTrailingCommas: false + maxDateTime: maxDateTime, + removeTrailingCommas: false, + startDateTime: startDateTime ); formatState.addText('void f(void Function()g,int i){}void h(){f((){}', 'SOURCE'); diff --git a/test/Formatters/ClassDeclarationFormatter_test.dart b/test/Formatters/ClassDeclarationFormatter_test.dart index adf5f17..748a584 100644 --- a/test/Formatters/ClassDeclarationFormatter_test.dart +++ b/test/Formatters/ClassDeclarationFormatter_test.dart @@ -67,6 +67,18 @@ void main() TestConfig.none(), TestConfig('abstract mixin class C\n{\n}\n') ] + ), + TestGroupConfig( + inputNodeCreator: AstCreator.createDeclaration, + inputMiddle: 'class C\nwith M{}', + name: r'ClassDeclaration / class C\nwith M{}', + astVisitors: >[ + TestVisitor(8, 'with M') + ], + testConfigs: [ + TestConfig.none(), + TestConfig('class C\n with M\n{\n}\n') + ] ) ];