Merge b845d96ee2
into 2ea6c43a66
This commit is contained in:
commit
2bd4b4179c
|
@ -1,9 +1,9 @@
|
||||||
[submodule "libdparse"]
|
|
||||||
path = libdparse
|
|
||||||
url = https://github.com/dlang-community/libdparse.git
|
|
||||||
[submodule "stdx-allocator"]
|
[submodule "stdx-allocator"]
|
||||||
path = stdx-allocator
|
path = stdx-allocator
|
||||||
url = https://github.com/dlang-community/stdx-allocator
|
url = https://github.com/dlang-community/stdx-allocator
|
||||||
[submodule "d-test-utils"]
|
[submodule "d-test-utils"]
|
||||||
path = d-test-utils
|
path = d-test-utils
|
||||||
url = https://github.com/dlang-community/d-test-utils.git
|
url = https://github.com/dlang-community/d-test-utils.git
|
||||||
|
[submodule "dmd"]
|
||||||
|
path = dmd
|
||||||
|
url = https://github.com/dlang/dmd.git
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit b859107c37a948d0492fccb7a319f0a96b0eecb1
|
12
dub.json
12
dub.json
|
@ -4,17 +4,17 @@
|
||||||
"targetType": "autodetect",
|
"targetType": "autodetect",
|
||||||
"license": "BSL-1.0",
|
"license": "BSL-1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"libdparse": ">=0.19.2 <1.0.0"
|
"dmd": "~>2.107.0-beta.1"
|
||||||
},
|
},
|
||||||
"targetPath" : "bin/",
|
"targetPath": "bin/",
|
||||||
"targetName" : "dfmt",
|
"targetName": "dfmt",
|
||||||
"stringImportPaths" : [
|
"stringImportPaths": [
|
||||||
"bin"
|
"bin"
|
||||||
],
|
],
|
||||||
"versions" : [
|
"versions": [
|
||||||
"built_with_dub"
|
"built_with_dub"
|
||||||
],
|
],
|
||||||
"preBuildCommands" : [
|
"preBuildCommands": [
|
||||||
"$DC -run \"$PACKAGE_DIR/dubhash.d\""
|
"$DC -run \"$PACKAGE_DIR/dubhash.d\""
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit fe6d1e38fb4fc04323170389cfec67ed7fd4e24a
|
|
36
makefile
36
makefile
|
@ -1,8 +1,36 @@
|
||||||
|
DMD_ROOT_SRC := \
|
||||||
|
$(shell find dmd/compiler/src/dmd/common -name "*.d")\
|
||||||
|
$(shell find dmd/compiler/src/dmd/root -name "*.d")
|
||||||
|
DMD_LEXER_SRC := \
|
||||||
|
dmd/compiler/src/dmd/console.d \
|
||||||
|
dmd/compiler/src/dmd/entity.d \
|
||||||
|
dmd/compiler/src/dmd/errors.d \
|
||||||
|
dmd/compiler/src/dmd/errorsink.d \
|
||||||
|
dmd/compiler/src/dmd/location.d \
|
||||||
|
dmd/compiler/src/dmd/file_manager.d \
|
||||||
|
dmd/compiler/src/dmd/globals.d \
|
||||||
|
dmd/compiler/src/dmd/id.d \
|
||||||
|
dmd/compiler/src/dmd/identifier.d \
|
||||||
|
dmd/compiler/src/dmd/lexer.d \
|
||||||
|
dmd/compiler/src/dmd/tokens.d \
|
||||||
|
dmd/compiler/src/dmd/utils.d \
|
||||||
|
$(DMD_ROOT_SRC)
|
||||||
|
|
||||||
|
DMD_PARSER_SRC := \
|
||||||
|
dmd/compiler/src/dmd/astbase.d \
|
||||||
|
dmd/compiler/src/dmd/parse.d \
|
||||||
|
dmd/compiler/src/dmd/parsetimevisitor.d \
|
||||||
|
dmd/compiler/src/dmd/transitivevisitor.d \
|
||||||
|
dmd/compiler/src/dmd/permissivevisitor.d \
|
||||||
|
dmd/compiler/src/dmd/strictvisitor.d \
|
||||||
|
dmd/compiler/src/dmd/astenums.d \
|
||||||
|
$(DMD_LEXER_SRC)
|
||||||
|
|
||||||
SRC := $(shell find src -name "*.d") \
|
SRC := $(shell find src -name "*.d") \
|
||||||
$(shell find libdparse/src -name "*.d") \
|
$(shell find stdx-allocator/source -name "*.d") \
|
||||||
$(shell find stdx-allocator/source -name "*.d")
|
$(DMD_PARSER_SRC)
|
||||||
INCLUDE_PATHS := -Ilibdparse/src -Istdx-allocator/source -Isrc -Jbin
|
INCLUDE_PATHS := -Ilibdparse/src -Istdx-allocator/source -Isrc -Idmd/compiler/src -Jbin -Jdmd
|
||||||
DMD_COMMON_FLAGS := -dip25 -w $(INCLUDE_PATHS)
|
DMD_COMMON_FLAGS := -w $(INCLUDE_PATHS)
|
||||||
DMD_DEBUG_FLAGS := -debug -g $(DMD_COMMON_FLAGS)
|
DMD_DEBUG_FLAGS := -debug -g $(DMD_COMMON_FLAGS)
|
||||||
DMD_FLAGS := -O -inline $(DMD_COMMON_FLAGS)
|
DMD_FLAGS := -O -inline $(DMD_COMMON_FLAGS)
|
||||||
DMD_TEST_FLAGS := -unittest -g $(DMD_COMMON_FLAGS)
|
DMD_TEST_FLAGS := -unittest -g $(DMD_COMMON_FLAGS)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,488 +0,0 @@
|
||||||
// Copyright Brian Schott 2015.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module dfmt.ast_info;
|
|
||||||
|
|
||||||
import dparse.lexer;
|
|
||||||
import dparse.ast;
|
|
||||||
|
|
||||||
enum BraceIndentInfoFlags
|
|
||||||
{
|
|
||||||
tempIndent = 1 << 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BraceIndentInfo
|
|
||||||
{
|
|
||||||
size_t startLocation;
|
|
||||||
size_t endLocation;
|
|
||||||
|
|
||||||
uint flags;
|
|
||||||
|
|
||||||
uint beginIndentLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct StructInitializerInfo
|
|
||||||
{
|
|
||||||
size_t startLocation;
|
|
||||||
size_t endLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AST information that is needed by the formatter.
|
|
||||||
struct ASTInformation
|
|
||||||
{
|
|
||||||
/// Sorts the arrays so that binary search will work on them
|
|
||||||
void cleanup()
|
|
||||||
{
|
|
||||||
import std.algorithm : sort, uniq;
|
|
||||||
import std.array : array;
|
|
||||||
|
|
||||||
sort(doubleNewlineLocations);
|
|
||||||
sort(spaceAfterLocations);
|
|
||||||
sort(unaryLocations);
|
|
||||||
sort(attributeDeclarationLines);
|
|
||||||
sort(atAttributeStartLocations);
|
|
||||||
sort(caseEndLocations);
|
|
||||||
sort(structInitStartLocations);
|
|
||||||
sort(structInitEndLocations);
|
|
||||||
sort(funLitStartLocations);
|
|
||||||
sort(funLitEndLocations);
|
|
||||||
sort(conditionalWithElseLocations);
|
|
||||||
sort(conditionalStatementLocations);
|
|
||||||
sort(arrayStartLocations);
|
|
||||||
sort(assocArrayStartLocations);
|
|
||||||
sort(contractLocations);
|
|
||||||
sort(constraintLocations);
|
|
||||||
sort(constructorDestructorLocations);
|
|
||||||
sort(staticConstructorDestructorLocations);
|
|
||||||
sort(sharedStaticConstructorDestructorLocations);
|
|
||||||
sort!((a,b) => a.endLocation < b.endLocation)
|
|
||||||
(indentInfoSortedByEndLocation);
|
|
||||||
sort!((a,b) => a.endLocation < b.endLocation)
|
|
||||||
(structInfoSortedByEndLocation);
|
|
||||||
sort(ufcsHintLocations);
|
|
||||||
ufcsHintLocations = ufcsHintLocations.uniq().array();
|
|
||||||
sort(ternaryColonLocations);
|
|
||||||
sort(namedArgumentColonLocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Locations of end braces for struct bodies
|
|
||||||
size_t[] doubleNewlineLocations;
|
|
||||||
|
|
||||||
/// Locations of tokens where a space is needed (such as the '*' in a type)
|
|
||||||
size_t[] spaceAfterLocations;
|
|
||||||
|
|
||||||
/// Locations of unary operators
|
|
||||||
size_t[] unaryLocations;
|
|
||||||
|
|
||||||
/// Lines containing attribute declarations
|
|
||||||
size_t[] attributeDeclarationLines;
|
|
||||||
|
|
||||||
/// Lines containing attribute declarations that can be followed by a new line
|
|
||||||
size_t[] atAttributeStartLocations;
|
|
||||||
|
|
||||||
/// Case statement colon locations
|
|
||||||
size_t[] caseEndLocations;
|
|
||||||
|
|
||||||
/// Opening braces of struct initializers
|
|
||||||
size_t[] structInitStartLocations;
|
|
||||||
|
|
||||||
/// Closing braces of struct initializers
|
|
||||||
size_t[] structInitEndLocations;
|
|
||||||
|
|
||||||
/// Opening braces of function literals
|
|
||||||
size_t[] funLitStartLocations;
|
|
||||||
|
|
||||||
/// Closing braces of function literals
|
|
||||||
size_t[] funLitEndLocations;
|
|
||||||
|
|
||||||
/// Locations of aggregate bodies (struct, class, union)
|
|
||||||
size_t[] aggregateBodyLocations;
|
|
||||||
|
|
||||||
/// Locations of function bodies
|
|
||||||
size_t[] funBodyLocations;
|
|
||||||
|
|
||||||
/// Conditional statements that have matching "else" statements
|
|
||||||
size_t[] conditionalWithElseLocations;
|
|
||||||
|
|
||||||
/// Conditional statement locations
|
|
||||||
size_t[] conditionalStatementLocations;
|
|
||||||
|
|
||||||
/// Locations of start locations of array initializers
|
|
||||||
size_t[] arrayStartLocations;
|
|
||||||
|
|
||||||
/// Locations of start locations of associative array initializers
|
|
||||||
size_t[] assocArrayStartLocations;
|
|
||||||
|
|
||||||
/// Locations of "in" and "out" tokens that begin contracts
|
|
||||||
size_t[] contractLocations;
|
|
||||||
|
|
||||||
/// Locations of template constraint "if" tokens
|
|
||||||
size_t[] constraintLocations;
|
|
||||||
|
|
||||||
/// Locations of constructor/destructor "shared" tokens ?
|
|
||||||
size_t[] sharedStaticConstructorDestructorLocations;
|
|
||||||
|
|
||||||
/// Locations of constructor/destructor "static" tokens ?
|
|
||||||
size_t[] staticConstructorDestructorLocations;
|
|
||||||
|
|
||||||
/// Locations of constructor/destructor "this" tokens ?
|
|
||||||
size_t[] constructorDestructorLocations;
|
|
||||||
|
|
||||||
/// Locations of '.' characters that might be UFCS chains.
|
|
||||||
size_t[] ufcsHintLocations;
|
|
||||||
|
|
||||||
BraceIndentInfo[] indentInfoSortedByEndLocation;
|
|
||||||
|
|
||||||
/// Opening & closing braces of struct initializers
|
|
||||||
StructInitializerInfo[] structInfoSortedByEndLocation;
|
|
||||||
|
|
||||||
/// Locations ternary expression colons.
|
|
||||||
size_t[] ternaryColonLocations;
|
|
||||||
|
|
||||||
/// Locations of named arguments of function call or struct constructor.
|
|
||||||
size_t[] namedArgumentColonLocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Collects information from the AST that is useful for the formatter
|
|
||||||
final class FormatVisitor : ASTVisitor
|
|
||||||
{
|
|
||||||
alias visit = ASTVisitor.visit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Params:
|
|
||||||
* astInformation = the AST information that will be filled in
|
|
||||||
*/
|
|
||||||
this(ASTInformation* astInformation)
|
|
||||||
{
|
|
||||||
this.astInformation = astInformation;
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const ArrayInitializer arrayInitializer)
|
|
||||||
{
|
|
||||||
astInformation.arrayStartLocations ~= arrayInitializer.startLocation;
|
|
||||||
arrayInitializer.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const ArrayLiteral arrayLiteral)
|
|
||||||
{
|
|
||||||
astInformation.arrayStartLocations ~= arrayLiteral.tokens[0].index;
|
|
||||||
arrayLiteral.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const AssocArrayLiteral assocArrayLiteral)
|
|
||||||
{
|
|
||||||
astInformation.arrayStartLocations ~= assocArrayLiteral.tokens[0].index;
|
|
||||||
astInformation.assocArrayStartLocations ~= assocArrayLiteral.tokens[0].index;
|
|
||||||
assocArrayLiteral.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const SharedStaticConstructor sharedStaticConstructor)
|
|
||||||
{
|
|
||||||
astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticConstructor.location;
|
|
||||||
sharedStaticConstructor.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const SharedStaticDestructor sharedStaticDestructor)
|
|
||||||
{
|
|
||||||
astInformation.sharedStaticConstructorDestructorLocations ~= sharedStaticDestructor.location;
|
|
||||||
sharedStaticDestructor.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const StaticConstructor staticConstructor)
|
|
||||||
{
|
|
||||||
astInformation.staticConstructorDestructorLocations ~= staticConstructor.location;
|
|
||||||
staticConstructor.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const StaticDestructor staticDestructor)
|
|
||||||
{
|
|
||||||
astInformation.staticConstructorDestructorLocations ~= staticDestructor.location;
|
|
||||||
staticDestructor.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const Constructor constructor)
|
|
||||||
{
|
|
||||||
astInformation.constructorDestructorLocations ~= constructor.location;
|
|
||||||
constructor.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const Destructor destructor)
|
|
||||||
{
|
|
||||||
astInformation.constructorDestructorLocations ~= destructor.index;
|
|
||||||
destructor.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit (const FunctionBody functionBody)
|
|
||||||
{
|
|
||||||
if (auto bd = functionBody.specifiedFunctionBody)
|
|
||||||
{
|
|
||||||
if (bd.blockStatement)
|
|
||||||
{
|
|
||||||
astInformation.funBodyLocations ~= bd.blockStatement.startLocation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
functionBody.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const ConditionalDeclaration dec)
|
|
||||||
{
|
|
||||||
if (dec.hasElse)
|
|
||||||
{
|
|
||||||
auto condition = dec.compileCondition;
|
|
||||||
if (condition.versionCondition !is null)
|
|
||||||
{
|
|
||||||
astInformation.conditionalWithElseLocations
|
|
||||||
~= condition.versionCondition.versionIndex;
|
|
||||||
}
|
|
||||||
else if (condition.debugCondition !is null)
|
|
||||||
{
|
|
||||||
astInformation.conditionalWithElseLocations ~= condition.debugCondition.debugIndex;
|
|
||||||
}
|
|
||||||
// Skip "static if" because the formatting for normal "if" handles
|
|
||||||
// it properly
|
|
||||||
}
|
|
||||||
dec.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const Constraint constraint)
|
|
||||||
{
|
|
||||||
astInformation.constraintLocations ~= constraint.location;
|
|
||||||
constraint.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const ConditionalStatement statement)
|
|
||||||
{
|
|
||||||
auto condition = statement.compileCondition;
|
|
||||||
if (condition.versionCondition !is null)
|
|
||||||
{
|
|
||||||
astInformation.conditionalStatementLocations ~= condition.versionCondition.versionIndex;
|
|
||||||
}
|
|
||||||
else if (condition.debugCondition !is null)
|
|
||||||
{
|
|
||||||
astInformation.conditionalStatementLocations ~= condition.debugCondition.debugIndex;
|
|
||||||
}
|
|
||||||
statement.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const FunctionLiteralExpression funcLit)
|
|
||||||
{
|
|
||||||
if (funcLit.specifiedFunctionBody !is null)
|
|
||||||
{
|
|
||||||
const bs = funcLit.specifiedFunctionBody.blockStatement;
|
|
||||||
|
|
||||||
astInformation.funLitStartLocations ~= bs.startLocation;
|
|
||||||
astInformation.funLitEndLocations ~= bs.endLocation;
|
|
||||||
astInformation.indentInfoSortedByEndLocation ~=
|
|
||||||
BraceIndentInfo(bs.startLocation, bs.endLocation);
|
|
||||||
}
|
|
||||||
funcLit.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const DefaultStatement defaultStatement)
|
|
||||||
{
|
|
||||||
astInformation.caseEndLocations ~= defaultStatement.colonLocation;
|
|
||||||
defaultStatement.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const CaseStatement caseStatement)
|
|
||||||
{
|
|
||||||
astInformation.caseEndLocations ~= caseStatement.colonLocation;
|
|
||||||
caseStatement.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const CaseRangeStatement caseRangeStatement)
|
|
||||||
{
|
|
||||||
astInformation.caseEndLocations ~= caseRangeStatement.colonLocation;
|
|
||||||
caseRangeStatement.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const SpecifiedFunctionBody specifiedFunctionBody)
|
|
||||||
{
|
|
||||||
if (specifiedFunctionBody.blockStatement !is null)
|
|
||||||
astInformation.doubleNewlineLocations ~= specifiedFunctionBody.blockStatement.endLocation;
|
|
||||||
specifiedFunctionBody.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const StructInitializer structInitializer)
|
|
||||||
{
|
|
||||||
astInformation.structInitStartLocations ~= structInitializer.startLocation;
|
|
||||||
astInformation.structInitEndLocations ~= structInitializer.endLocation;
|
|
||||||
astInformation.structInfoSortedByEndLocation ~=
|
|
||||||
StructInitializerInfo(structInitializer.startLocation, structInitializer.endLocation);
|
|
||||||
astInformation.indentInfoSortedByEndLocation ~=
|
|
||||||
BraceIndentInfo(structInitializer.startLocation, structInitializer.endLocation);
|
|
||||||
|
|
||||||
structInitializer.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const EnumBody enumBody)
|
|
||||||
{
|
|
||||||
astInformation.doubleNewlineLocations ~= enumBody.endLocation;
|
|
||||||
enumBody.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const Unittest unittest_)
|
|
||||||
{
|
|
||||||
astInformation.doubleNewlineLocations ~= unittest_.blockStatement.endLocation;
|
|
||||||
unittest_.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const Invariant invariant_)
|
|
||||||
{
|
|
||||||
if (invariant_.blockStatement !is null)
|
|
||||||
astInformation.doubleNewlineLocations ~= invariant_.blockStatement.endLocation;
|
|
||||||
|
|
||||||
invariant_.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const StructBody structBody)
|
|
||||||
{
|
|
||||||
astInformation.aggregateBodyLocations ~= structBody.startLocation;
|
|
||||||
astInformation.doubleNewlineLocations ~= structBody.endLocation;
|
|
||||||
structBody.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const TemplateDeclaration templateDeclaration)
|
|
||||||
{
|
|
||||||
astInformation.doubleNewlineLocations ~= templateDeclaration.endLocation;
|
|
||||||
templateDeclaration.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const TypeSuffix typeSuffix)
|
|
||||||
{
|
|
||||||
if (typeSuffix.star.type != tok!"")
|
|
||||||
astInformation.spaceAfterLocations ~= typeSuffix.star.index;
|
|
||||||
typeSuffix.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const UnaryExpression unary)
|
|
||||||
{
|
|
||||||
import std.typecons : rebindable;
|
|
||||||
|
|
||||||
int chainLength;
|
|
||||||
auto u = rebindable(unary);
|
|
||||||
while (u !is null)
|
|
||||||
{
|
|
||||||
if (u.identifierOrTemplateInstance !is null
|
|
||||||
&& u.identifierOrTemplateInstance.templateInstance !is null)
|
|
||||||
chainLength++;
|
|
||||||
u = u.unaryExpression;
|
|
||||||
}
|
|
||||||
if (chainLength > 1)
|
|
||||||
{
|
|
||||||
u = unary;
|
|
||||||
while (u.unaryExpression !is null)
|
|
||||||
{
|
|
||||||
astInformation.ufcsHintLocations ~= u.dotLocation;
|
|
||||||
u = u.unaryExpression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&"
|
|
||||||
|| unary.prefix.type == tok!"*"
|
|
||||||
|| unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-")
|
|
||||||
{
|
|
||||||
astInformation.unaryLocations ~= unary.prefix.index;
|
|
||||||
}
|
|
||||||
unary.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const AttributeDeclaration attributeDeclaration)
|
|
||||||
{
|
|
||||||
astInformation.attributeDeclarationLines ~= attributeDeclaration.line;
|
|
||||||
attributeDeclaration.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const FunctionAttribute functionAttribute)
|
|
||||||
{
|
|
||||||
if (functionAttribute.atAttribute !is null)
|
|
||||||
astInformation.atAttributeStartLocations ~= functionAttribute.atAttribute.startLocation;
|
|
||||||
functionAttribute.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const MemberFunctionAttribute memberFunctionAttribute)
|
|
||||||
{
|
|
||||||
if (memberFunctionAttribute.atAttribute !is null)
|
|
||||||
astInformation.atAttributeStartLocations ~= memberFunctionAttribute.atAttribute.startLocation;
|
|
||||||
memberFunctionAttribute.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const Attribute attribute)
|
|
||||||
{
|
|
||||||
if (attribute.atAttribute !is null)
|
|
||||||
astInformation.atAttributeStartLocations ~= attribute.atAttribute.startLocation;
|
|
||||||
attribute.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const StorageClass storageClass)
|
|
||||||
{
|
|
||||||
if (storageClass.atAttribute !is null)
|
|
||||||
astInformation.atAttributeStartLocations ~= storageClass.atAttribute.startLocation;
|
|
||||||
storageClass.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const InContractExpression inContractExpression)
|
|
||||||
{
|
|
||||||
astInformation.contractLocations ~= inContractExpression.inTokenLocation;
|
|
||||||
inContractExpression.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const InStatement inStatement)
|
|
||||||
{
|
|
||||||
astInformation.contractLocations ~= inStatement.inTokenLocation;
|
|
||||||
inStatement.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const OutContractExpression outContractExpression)
|
|
||||||
{
|
|
||||||
astInformation.contractLocations ~= outContractExpression.outTokenLocation;
|
|
||||||
outContractExpression.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const OutStatement outStatement)
|
|
||||||
{
|
|
||||||
astInformation.contractLocations ~= outStatement.outTokenLocation;
|
|
||||||
outStatement.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const TernaryExpression ternaryExpression)
|
|
||||||
{
|
|
||||||
astInformation.ternaryColonLocations ~= ternaryExpression.colon.index;
|
|
||||||
ternaryExpression.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const FunctionCallExpression functionCall)
|
|
||||||
{
|
|
||||||
// Check if function has any arguments.
|
|
||||||
if (functionCall.arguments.namedArgumentList is null)
|
|
||||||
{
|
|
||||||
functionCall.accept(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (item; functionCall.arguments.namedArgumentList.items)
|
|
||||||
{
|
|
||||||
// Do nothing if not a named argument.
|
|
||||||
if (item.name == tok!"")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find first colon if named argument.
|
|
||||||
foreach (t; item.tokens)
|
|
||||||
{
|
|
||||||
if (t.type == tok!":")
|
|
||||||
{
|
|
||||||
astInformation.namedArgumentColonLocations ~= t.index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
functionCall.accept(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ASTInformation* astInformation;
|
|
||||||
}
|
|
|
@ -66,8 +66,6 @@ struct Config
|
||||||
///
|
///
|
||||||
OptionalBoolean dfmt_reflow_property_chains;
|
OptionalBoolean dfmt_reflow_property_chains;
|
||||||
///
|
///
|
||||||
OptionalBoolean dfmt_space_after_statement_keyword;
|
|
||||||
///
|
|
||||||
OptionalBoolean dfmt_space_before_named_arg_colon;
|
OptionalBoolean dfmt_space_before_named_arg_colon;
|
||||||
|
|
||||||
mixin StandardEditorConfigFields;
|
mixin StandardEditorConfigFields;
|
||||||
|
|
|
@ -123,8 +123,7 @@ EC getConfigFor(EC)(string path)
|
||||||
{
|
{
|
||||||
import std.stdio : File;
|
import std.stdio : File;
|
||||||
import std.regex : regex, match;
|
import std.regex : regex, match;
|
||||||
import std.path : globMatch, dirName, baseName, pathSplitter, buildPath,
|
import std.path : globMatch, dirName, baseName, pathSplitter, buildPath, absolutePath;
|
||||||
absolutePath;
|
|
||||||
import std.algorithm : reverse, map, filter;
|
import std.algorithm : reverse, map, filter;
|
||||||
import std.array : array;
|
import std.array : array;
|
||||||
import std.file : isDir;
|
import std.file : isDir;
|
||||||
|
@ -141,7 +140,9 @@ EC getConfigFor(EC)(string path)
|
||||||
EC[] sections = parseConfig!EC(buildPath(pathParts[0 .. i]));
|
EC[] sections = parseConfig!EC(buildPath(pathParts[0 .. i]));
|
||||||
if (sections.length)
|
if (sections.length)
|
||||||
configs ~= sections;
|
configs ~= sections;
|
||||||
if (!sections.map!(a => a.root).filter!(a => a == OptionalBoolean.t).empty)
|
if (!sections.map!(a => a.root)
|
||||||
|
.filter!(a => a == OptionalBoolean.t)
|
||||||
|
.empty)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reverse(configs);
|
reverse(configs);
|
||||||
|
|
2391
src/dfmt/formatter.d
2391
src/dfmt/formatter.d
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@ import std.path : filenameCharCmp, isDirSeparator;
|
||||||
// * changes meaning to match all characters except '/'
|
// * changes meaning to match all characters except '/'
|
||||||
// ** added to take over the old meaning of *
|
// ** added to take over the old meaning of *
|
||||||
bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)(
|
bool globMatchEditorConfig(CaseSensitive cs = CaseSensitive.osDefault, C, Range)(
|
||||||
Range path, const(C)[] pattern) @safe pure nothrow
|
Range path, const(C)[] pattern) @safe pure
|
||||||
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range)
|
if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range)
|
||||||
&& isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range)))
|
&& isSomeChar!C && is(Unqual!C == Unqual!(ElementEncodingType!Range)))
|
||||||
in
|
in
|
||||||
|
|
|
@ -1,333 +0,0 @@
|
||||||
// Copyright Brian Schott 2015.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module dfmt.indentation;
|
|
||||||
|
|
||||||
import dfmt.config;
|
|
||||||
import dfmt.editorconfig;
|
|
||||||
import dparse.lexer;
|
|
||||||
|
|
||||||
import std.bitmanip : bitfields;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: true if the given token type is a wrap indent type
|
|
||||||
*/
|
|
||||||
bool isWrapIndent(IdType type) pure nothrow @nogc @safe
|
|
||||||
{
|
|
||||||
return type != tok!"{" && type != tok!"case" && type != tok!"@"
|
|
||||||
&& type != tok!"]" && type != tok!"(" && type != tok!")" && isOperator(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: true if the given token type is a temporary indent type
|
|
||||||
*/
|
|
||||||
bool isTempIndent(IdType type) pure nothrow @nogc @safe
|
|
||||||
{
|
|
||||||
return type != tok!")" && type != tok!"{" && type != tok!"case" && type != tok!"@";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stack for managing indent levels.
|
|
||||||
*/
|
|
||||||
struct IndentStack
|
|
||||||
{
|
|
||||||
/// Configuration
|
|
||||||
private const Config* config;
|
|
||||||
|
|
||||||
this(const Config* config)
|
|
||||||
{
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct Details
|
|
||||||
{
|
|
||||||
mixin(bitfields!(
|
|
||||||
// generally true for all operators except {, case, @, ], (, )
|
|
||||||
bool, "wrap", 1,
|
|
||||||
// temporary indentation which get's reverted when a block starts
|
|
||||||
// generally true for all tokens except ), {, case, @
|
|
||||||
bool, "temp", 1,
|
|
||||||
// emit minimal newlines
|
|
||||||
bool, "mini", 1,
|
|
||||||
// for associative arrays or arrays containing them, break after every item
|
|
||||||
bool, "breakEveryItem", 1,
|
|
||||||
// when an item inside an array would break mid-item, definitely break at the comma first
|
|
||||||
bool, "preferLongBreaking", 1,
|
|
||||||
uint, "", 27));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the indent size at the most recent occurrence of the given indent type
|
|
||||||
*/
|
|
||||||
int indentToMostRecent(IdType item) const
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
return -1;
|
|
||||||
size_t i = index - 1;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (arr[i] == item)
|
|
||||||
return indentSize(i);
|
|
||||||
if (i > 0)
|
|
||||||
i--;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int wrapIndents() const pure nothrow @property
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
return 0;
|
|
||||||
int tempIndentCount = 0;
|
|
||||||
for (size_t i = index; i > 0; i--)
|
|
||||||
{
|
|
||||||
if (!details[i - 1].wrap && arr[i - 1] != tok!"]")
|
|
||||||
break;
|
|
||||||
tempIndentCount++;
|
|
||||||
}
|
|
||||||
return tempIndentCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes the given indent type on to the stack.
|
|
||||||
*/
|
|
||||||
void push(IdType item) pure nothrow
|
|
||||||
{
|
|
||||||
Details detail;
|
|
||||||
detail.wrap = isWrapIndent(item);
|
|
||||||
detail.temp = isTempIndent(item);
|
|
||||||
push(item, detail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes the given indent type on to the stack.
|
|
||||||
*/
|
|
||||||
void push(IdType item, Details detail) pure nothrow
|
|
||||||
{
|
|
||||||
arr[index] = item;
|
|
||||||
details[index] = detail;
|
|
||||||
//FIXME this is actually a bad thing to do,
|
|
||||||
//we should not just override when the stack is
|
|
||||||
//at it's limit
|
|
||||||
if (index < arr.length)
|
|
||||||
{
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops the top indent from the stack.
|
|
||||||
*/
|
|
||||||
void pop() pure nothrow
|
|
||||||
{
|
|
||||||
if (index)
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops all wrapping indents from the top of the stack.
|
|
||||||
*/
|
|
||||||
void popWrapIndents() pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
while (index > 0 && details[index - 1].wrap)
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops all temporary indents from the top of the stack.
|
|
||||||
*/
|
|
||||||
void popTempIndents() pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
while (index > 0 && details[index - 1].temp)
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool topAre(IdType[] types...)
|
|
||||||
{
|
|
||||||
if (types.length > index)
|
|
||||||
return false;
|
|
||||||
return arr[index - types.length .. index] == types;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: `true` if the top of the indent stack is the given indent type.
|
|
||||||
*/
|
|
||||||
bool topIs(IdType type) const pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
return index > 0 && index <= arr.length && arr[index - 1] == type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: `true` if the top of the indent stack is a temporary indent
|
|
||||||
*/
|
|
||||||
bool topIsTemp()
|
|
||||||
{
|
|
||||||
return index > 0 && index <= arr.length && details[index - 1].temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: `true` if the top of the indent stack is a temporary indent with the specified token
|
|
||||||
*/
|
|
||||||
bool topIsTemp(IdType item)
|
|
||||||
{
|
|
||||||
return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1].temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: `true` if the top of the indent stack is a wrapping indent
|
|
||||||
*/
|
|
||||||
bool topIsWrap()
|
|
||||||
{
|
|
||||||
return index > 0 && index <= arr.length && details[index - 1].wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: `true` if the top of the indent stack is a temporary indent with the specified token
|
|
||||||
*/
|
|
||||||
bool topIsWrap(IdType item)
|
|
||||||
{
|
|
||||||
return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1].wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns: `true` if the top of the indent stack is one of the given token
|
|
||||||
* types.
|
|
||||||
*/
|
|
||||||
bool topIsOneOf(IdType[] types...) const pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
return false;
|
|
||||||
immutable topType = arr[index - 1];
|
|
||||||
foreach (t; types)
|
|
||||||
if (t == topType)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdType top() const pure nothrow @property @safe @nogc
|
|
||||||
{
|
|
||||||
return arr[index - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
Details topDetails() const pure nothrow @property @safe @nogc
|
|
||||||
{
|
|
||||||
return details[index - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
int indentLevel() const pure nothrow @property @safe @nogc
|
|
||||||
{
|
|
||||||
return indentSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
int length() const pure nothrow @property @safe @nogc
|
|
||||||
{
|
|
||||||
return cast(int) index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dumps the current state of the indentation stack to `stderr`. Used for debugging.
|
|
||||||
*/
|
|
||||||
void dump(size_t pos = size_t.max, string file = __FILE__, uint line = __LINE__) const
|
|
||||||
{
|
|
||||||
import dparse.lexer : str;
|
|
||||||
import std.algorithm.iteration : map;
|
|
||||||
import std.stdio : stderr;
|
|
||||||
|
|
||||||
if (pos == size_t.max)
|
|
||||||
stderr.writefln("\033[31m%s:%d %(%s %)\033[0m", file, line, arr[0 .. index].map!(a => str(a)));
|
|
||||||
else
|
|
||||||
stderr.writefln("\033[31m%s:%d at %d %(%s %)\033[0m", file, line, pos, arr[0 .. index].map!(a => str(a)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
IdType[256] arr;
|
|
||||||
Details[arr.length] details;
|
|
||||||
|
|
||||||
int indentSize(const size_t k = size_t.max) const pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
import std.algorithm : among;
|
|
||||||
if (index == 0 || k == 0)
|
|
||||||
return 0;
|
|
||||||
immutable size_t j = k == size_t.max ? index : k;
|
|
||||||
int size = 0;
|
|
||||||
int parenCount;
|
|
||||||
foreach (i; 0 .. j)
|
|
||||||
{
|
|
||||||
immutable int pc = (arr[i] == tok!"!" || arr[i] == tok!"(" || arr[i] == tok!")") ? parenCount + 1
|
|
||||||
: parenCount;
|
|
||||||
if ((details[i].wrap || arr[i] == tok!"(") && parenCount > 1)
|
|
||||||
{
|
|
||||||
parenCount = pc;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i + 1 < index)
|
|
||||||
{
|
|
||||||
if (config.dfmt_single_indent == OptionalBoolean.t && skipDoubleIndent(i, parenCount))
|
|
||||||
{
|
|
||||||
parenCount = pc;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
immutable currentIsNonWrapTemp = !details[i].wrap
|
|
||||||
&& details[i].temp && arr[i] != tok!")" && arr[i] != tok!"!";
|
|
||||||
|
|
||||||
if (currentIsNonWrapTemp && arr[i + 1] == tok!"]")
|
|
||||||
{
|
|
||||||
parenCount = pc;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arr[i] == tok!"static"
|
|
||||||
&& arr[i + 1].among!(tok!"if", tok!"else", tok!"foreach", tok!"foreach_reverse")
|
|
||||||
&& (i + 2 >= index || arr[i + 2] != tok!"{"))
|
|
||||||
{
|
|
||||||
parenCount = pc;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (currentIsNonWrapTemp && (arr[i + 1] == tok!"switch"
|
|
||||||
|| arr[i + 1] == tok!"{" || arr[i + 1] == tok!")"))
|
|
||||||
{
|
|
||||||
parenCount = pc;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (parenCount == 0 && arr[i] == tok!"(" && config.dfmt_single_indent == OptionalBoolean.f)
|
|
||||||
size++;
|
|
||||||
|
|
||||||
if (arr[i] == tok!"!")
|
|
||||||
size++;
|
|
||||||
|
|
||||||
parenCount = pc;
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skipDoubleIndent(size_t i, int parenCount) const pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
return (details[i + 1].wrap && arr[i] == tok!")")
|
|
||||||
|| (parenCount == 0 && arr[i + 1] == tok!"," && arr[i] == tok!"(");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
IndentStack stack;
|
|
||||||
stack.push(tok!"{");
|
|
||||||
assert(stack.length == 1);
|
|
||||||
assert(stack.indentLevel == 1);
|
|
||||||
stack.pop();
|
|
||||||
assert(stack.length == 0);
|
|
||||||
assert(stack.indentLevel == 0);
|
|
||||||
stack.push(tok!"if");
|
|
||||||
assert(stack.topIsTemp());
|
|
||||||
stack.popTempIndents();
|
|
||||||
assert(stack.length == 0);
|
|
||||||
}
|
|
|
@ -30,24 +30,18 @@ static immutable VERSION = () {
|
||||||
}
|
}
|
||||||
|
|
||||||
return DFMT_VERSION ~ DEBUG_SUFFIX;
|
return DFMT_VERSION ~ DEBUG_SUFFIX;
|
||||||
} ();
|
}();
|
||||||
|
|
||||||
|
import dfmt.config : Config;
|
||||||
|
import dfmt.editorconfig : getConfigFor;
|
||||||
|
import dfmt.formatter : format;
|
||||||
|
import std.array : appender, front, popFront;
|
||||||
|
import std.getopt : getopt, GetOptException;
|
||||||
|
import std.path : buildPath, dirName, expandTilde;
|
||||||
|
import std.stdio : File, stderr, stdin, stdout, writeln;
|
||||||
|
|
||||||
version (NoMain)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
import dfmt.config : Config;
|
|
||||||
import dfmt.editorconfig : getConfigFor;
|
|
||||||
import dfmt.formatter : format;
|
|
||||||
import std.array : appender, front, popFront;
|
|
||||||
import std.getopt : getopt, GetOptException;
|
|
||||||
import std.path : buildPath, dirName, expandTilde;
|
|
||||||
import std.stdio : File, stderr, stdin, stdout, writeln;
|
|
||||||
|
|
||||||
int main(string[] args)
|
|
||||||
{
|
|
||||||
bool inplace = false;
|
bool inplace = false;
|
||||||
Config optConfig;
|
Config optConfig;
|
||||||
optConfig.pattern = "*.d";
|
optConfig.pattern = "*.d";
|
||||||
|
@ -61,8 +55,7 @@ else
|
||||||
import std.exception : enforce;
|
import std.exception : enforce;
|
||||||
|
|
||||||
enforce!GetOptException(value == "true" || value == "false", "Invalid argument");
|
enforce!GetOptException(value == "true" || value == "false", "Invalid argument");
|
||||||
immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t
|
immutable OptionalBoolean optVal = value == "true" ? OptionalBoolean.t : OptionalBoolean.f;
|
||||||
: OptionalBoolean.f;
|
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
case "align_switch_statements":
|
case "align_switch_statements":
|
||||||
|
@ -171,6 +164,7 @@ else
|
||||||
// See Phobos' stdio.File.rawWrite
|
// See Phobos' stdio.File.rawWrite
|
||||||
{
|
{
|
||||||
import std.stdio : _O_BINARY;
|
import std.stdio : _O_BINARY;
|
||||||
|
|
||||||
immutable fd = stdout.fileno;
|
immutable fd = stdout.fileno;
|
||||||
_setmode(fd, _O_BINARY);
|
_setmode(fd, _O_BINARY);
|
||||||
version (CRuntime_DigitalMars)
|
version (CRuntime_DigitalMars)
|
||||||
|
@ -273,34 +267,29 @@ else
|
||||||
{
|
{
|
||||||
buffer = new ubyte[](cast(size_t) f.size);
|
buffer = new ubyte[](cast(size_t) f.size);
|
||||||
f.rawRead(buffer);
|
f.rawRead(buffer);
|
||||||
auto output = appender!string;
|
File.LockingTextWriter output;
|
||||||
immutable bool formatSuccess = format(path, buffer, output, &config);
|
|
||||||
if (formatSuccess)
|
|
||||||
{
|
|
||||||
if (inplace)
|
if (inplace)
|
||||||
File(path, "wb").rawWrite(output.data);
|
output = File(path, "wb").lockingTextWriter();
|
||||||
else
|
else
|
||||||
stdout.rawWrite(output.data);
|
output = stdout.lockingTextWriter();
|
||||||
}
|
immutable bool formatSuccess = format(path, buffer, output, &config);
|
||||||
else
|
retVal = formatSuccess ? 0 : 1;
|
||||||
retVal = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private version (Windows)
|
private version (Windows)
|
||||||
{
|
{
|
||||||
version(CRuntime_DigitalMars)
|
version (CRuntime_DigitalMars)
|
||||||
{
|
{
|
||||||
extern(C) int setmode(int, int) nothrow @nogc;
|
extern (C) int setmode(int, int) nothrow @nogc;
|
||||||
alias _setmode = setmode;
|
alias _setmode = setmode;
|
||||||
}
|
}
|
||||||
else version(CRuntime_Microsoft)
|
else version (CRuntime_Microsoft)
|
||||||
{
|
{
|
||||||
extern(C) int _setmode(int, int) nothrow @nogc;
|
extern (C) int _setmode(int, int) nothrow @nogc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,11 +307,14 @@ template optionsToString(E) if (is(E == enum))
|
||||||
}
|
}
|
||||||
result = result[0 .. $ - 1] ~ ")";
|
result = result[0 .. $ - 1] ~ ")";
|
||||||
return result;
|
return result;
|
||||||
} ();
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printHelp()
|
private void printHelp()
|
||||||
{
|
{
|
||||||
|
import std.stdio : writeln;
|
||||||
|
import dfmt.config;
|
||||||
|
|
||||||
writeln(`dfmt `, VERSION, `
|
writeln(`dfmt `, VERSION, `
|
||||||
https://github.com/dlang-community/dfmt
|
https://github.com/dlang-community/dfmt
|
||||||
|
|
||||||
|
@ -334,12 +326,10 @@ Options:
|
||||||
|
|
||||||
Formatting Options:
|
Formatting Options:
|
||||||
--align_switch_statements
|
--align_switch_statements
|
||||||
--brace_style `, optionsToString!(typeof(Config.dfmt_brace_style)),
|
--brace_style `, optionsToString!(typeof(Config.dfmt_brace_style)), `
|
||||||
`
|
|
||||||
--end_of_line `, optionsToString!(typeof(Config.end_of_line)), `
|
--end_of_line `, optionsToString!(typeof(Config.end_of_line)), `
|
||||||
--indent_size
|
--indent_size
|
||||||
--indent_style, -t `,
|
--indent_style, -t `, optionsToString!(typeof(Config.indent_style)), `
|
||||||
optionsToString!(typeof(Config.indent_style)), `
|
|
||||||
--keep_line_breaks
|
--keep_line_breaks
|
||||||
--soft_max_line_length
|
--soft_max_line_length
|
||||||
--max_line_length
|
--max_line_length
|
||||||
|
@ -356,14 +346,13 @@ Formatting Options:
|
||||||
--space_before_named_arg_colon
|
--space_before_named_arg_colon
|
||||||
--single_indent
|
--single_indent
|
||||||
--reflow_property_chains
|
--reflow_property_chains
|
||||||
`,
|
`, optionsToString!(typeof(Config.dfmt_template_constraint_style)));
|
||||||
optionsToString!(typeof(Config.dfmt_template_constraint_style)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string createFilePath(bool readFromStdin, string fileName)
|
private string createFilePath(bool readFromStdin, string fileName)
|
||||||
{
|
{
|
||||||
import std.file : getcwd;
|
import std.file : getcwd;
|
||||||
import std.path : isRooted;
|
import std.path : isRooted, buildPath;
|
||||||
|
|
||||||
immutable string cwd = getcwd();
|
immutable string cwd = getcwd();
|
||||||
if (readFromStdin)
|
if (readFromStdin)
|
||||||
|
|
|
@ -1,243 +0,0 @@
|
||||||
// Copyright Brian Schott 2015.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module dfmt.tokens;
|
|
||||||
|
|
||||||
import dparse.lexer;
|
|
||||||
|
|
||||||
/// Length of an invalid token
|
|
||||||
enum int INVALID_TOKEN_LENGTH = -1;
|
|
||||||
|
|
||||||
uint betweenParenLength(const Token[] tokens) pure @safe @nogc
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assert(tokens[0].type == tok!"(");
|
|
||||||
}
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint length = 0;
|
|
||||||
size_t i = 1;
|
|
||||||
int depth = 1;
|
|
||||||
while (i < tokens.length && depth > 0)
|
|
||||||
{
|
|
||||||
if (tokens[i].type == tok!"(")
|
|
||||||
depth++;
|
|
||||||
else if (tokens[i].type == tok!")")
|
|
||||||
depth--;
|
|
||||||
length += tokenLength(tokens[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tokenLength(ref const Token t) pure @safe @nogc
|
|
||||||
{
|
|
||||||
import std.algorithm : countUntil;
|
|
||||||
|
|
||||||
int c;
|
|
||||||
switch (t.type)
|
|
||||||
{
|
|
||||||
case tok!"doubleLiteral":
|
|
||||||
case tok!"floatLiteral":
|
|
||||||
case tok!"idoubleLiteral":
|
|
||||||
case tok!"ifloatLiteral":
|
|
||||||
case tok!"intLiteral":
|
|
||||||
case tok!"longLiteral":
|
|
||||||
case tok!"realLiteral":
|
|
||||||
case tok!"irealLiteral":
|
|
||||||
case tok!"uintLiteral":
|
|
||||||
case tok!"ulongLiteral":
|
|
||||||
case tok!"characterLiteral":
|
|
||||||
return cast(int) t.text.length;
|
|
||||||
case tok!"identifier":
|
|
||||||
case tok!"stringLiteral":
|
|
||||||
case tok!"wstringLiteral":
|
|
||||||
case tok!"dstringLiteral":
|
|
||||||
// TODO: Unicode line breaks and old-Mac line endings
|
|
||||||
c = cast(int) t.text.countUntil('\n');
|
|
||||||
if (c == -1)
|
|
||||||
return cast(int) t.text.length;
|
|
||||||
else
|
|
||||||
return c;
|
|
||||||
mixin(generateFixedLengthCases());
|
|
||||||
default:
|
|
||||||
return INVALID_TOKEN_LENGTH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBreakToken(IdType t) pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
switch (t)
|
|
||||||
{
|
|
||||||
case tok!"||":
|
|
||||||
case tok!"&&":
|
|
||||||
case tok!"(":
|
|
||||||
case tok!"[":
|
|
||||||
case tok!",":
|
|
||||||
case tok!":":
|
|
||||||
case tok!";":
|
|
||||||
case tok!"^^":
|
|
||||||
case tok!"^=":
|
|
||||||
case tok!"^":
|
|
||||||
case tok!"~=":
|
|
||||||
case tok!"<<=":
|
|
||||||
case tok!"<<":
|
|
||||||
case tok!"<=":
|
|
||||||
case tok!"<>=":
|
|
||||||
case tok!"<>":
|
|
||||||
case tok!"<":
|
|
||||||
case tok!"==":
|
|
||||||
case tok!"=>":
|
|
||||||
case tok!"=":
|
|
||||||
case tok!">=":
|
|
||||||
case tok!">>=":
|
|
||||||
case tok!">>>=":
|
|
||||||
case tok!">>>":
|
|
||||||
case tok!">>":
|
|
||||||
case tok!">":
|
|
||||||
case tok!"|=":
|
|
||||||
case tok!"|":
|
|
||||||
case tok!"-=":
|
|
||||||
case tok!"!<=":
|
|
||||||
case tok!"!<>=":
|
|
||||||
case tok!"!<>":
|
|
||||||
case tok!"!<":
|
|
||||||
case tok!"!=":
|
|
||||||
case tok!"!>=":
|
|
||||||
case tok!"!>":
|
|
||||||
case tok!"?":
|
|
||||||
case tok!"/=":
|
|
||||||
case tok!"/":
|
|
||||||
case tok!"..":
|
|
||||||
case tok!"*=":
|
|
||||||
case tok!"*":
|
|
||||||
case tok!"&=":
|
|
||||||
case tok!"%=":
|
|
||||||
case tok!"%":
|
|
||||||
case tok!"+=":
|
|
||||||
case tok!".":
|
|
||||||
case tok!"~":
|
|
||||||
case tok!"+":
|
|
||||||
case tok!"-":
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int breakCost(IdType p, IdType c) pure nothrow @safe @nogc
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case tok!"||":
|
|
||||||
case tok!"&&":
|
|
||||||
case tok!",":
|
|
||||||
case tok!"?":
|
|
||||||
return 0;
|
|
||||||
case tok!"(":
|
|
||||||
return 60;
|
|
||||||
case tok!"[":
|
|
||||||
return 300;
|
|
||||||
case tok!";":
|
|
||||||
case tok!"^^":
|
|
||||||
case tok!"^=":
|
|
||||||
case tok!"^":
|
|
||||||
case tok!"~=":
|
|
||||||
case tok!"<<=":
|
|
||||||
case tok!"<<":
|
|
||||||
case tok!"<=":
|
|
||||||
case tok!"<>=":
|
|
||||||
case tok!"<>":
|
|
||||||
case tok!"<":
|
|
||||||
case tok!"==":
|
|
||||||
case tok!"=>":
|
|
||||||
case tok!"=":
|
|
||||||
case tok!">=":
|
|
||||||
case tok!">>=":
|
|
||||||
case tok!">>>=":
|
|
||||||
case tok!">>>":
|
|
||||||
case tok!">>":
|
|
||||||
case tok!">":
|
|
||||||
case tok!"|=":
|
|
||||||
case tok!"|":
|
|
||||||
case tok!"-=":
|
|
||||||
case tok!"!<=":
|
|
||||||
case tok!"!<>=":
|
|
||||||
case tok!"!<>":
|
|
||||||
case tok!"!<":
|
|
||||||
case tok!"!=":
|
|
||||||
case tok!"!>=":
|
|
||||||
case tok!"!>":
|
|
||||||
case tok!"/=":
|
|
||||||
case tok!"/":
|
|
||||||
case tok!"..":
|
|
||||||
case tok!"*=":
|
|
||||||
case tok!"*":
|
|
||||||
case tok!"&=":
|
|
||||||
case tok!"%=":
|
|
||||||
case tok!"%":
|
|
||||||
case tok!"+":
|
|
||||||
case tok!"-":
|
|
||||||
case tok!"~":
|
|
||||||
case tok!"+=":
|
|
||||||
return 200;
|
|
||||||
case tok!":":
|
|
||||||
// colon could be after a label or an import, where it should normally wrap like before
|
|
||||||
// for everything else (associative arrays) try not breaking around colons
|
|
||||||
return p == tok!"identifier" ? 0 : 300;
|
|
||||||
case tok!".":
|
|
||||||
return p == tok!")" ? 0 : 300;
|
|
||||||
default:
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pure nothrow @safe @nogc unittest
|
|
||||||
{
|
|
||||||
foreach (ubyte u; 0 .. ubyte.max)
|
|
||||||
if (isBreakToken(u))
|
|
||||||
assert(breakCost(tok!".", u) != 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string generateFixedLengthCases()
|
|
||||||
{
|
|
||||||
import std.algorithm : map;
|
|
||||||
import std.string : format;
|
|
||||||
import std.array : join;
|
|
||||||
|
|
||||||
assert(__ctfe);
|
|
||||||
|
|
||||||
string[] spacedOperatorTokens = [
|
|
||||||
",", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=",
|
|
||||||
"!>", "!>=", "%", "%=", "&", "&&", "&=", "*", "*=", "+", "+=", "-",
|
|
||||||
"-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>",
|
|
||||||
">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "^", "^=", "^^",
|
|
||||||
"^^=", "|", "|=", "||", "~", "~="
|
|
||||||
];
|
|
||||||
immutable spacedOperatorTokenCases = spacedOperatorTokens.map!(
|
|
||||||
a => format(`case tok!"%s": return %d + 1;`, a, a.length)).join("\n\t");
|
|
||||||
|
|
||||||
string[] identifierTokens = [
|
|
||||||
"abstract", "alias", "align", "asm", "assert", "auto", "bool",
|
|
||||||
"break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class",
|
|
||||||
"const", "continue", "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated",
|
|
||||||
"do", "double", "else", "enum", "export", "extern", "false", "final", "finally", "float",
|
|
||||||
"for", "foreach", "foreach_reverse", "function", "goto", "idouble", "if", "ifloat", "immutable",
|
|
||||||
"import", "in", "inout", "int", "interface", "invariant", "ireal", "is",
|
|
||||||
"lazy", "long", "macro", "mixin", "module", "new", "nothrow", "null", "out", "override",
|
|
||||||
"package", "pragma", "private", "protected", "public", "pure", "real", "ref", "return", "scope",
|
|
||||||
"shared", "short", "static", "struct", "super", "switch", "synchronized", "template", "this",
|
|
||||||
"throw", "true", "try", "typedef", "typeid", "typeof", "ubyte", "ucent", "uint", "ulong",
|
|
||||||
"union", "unittest", "ushort", "version", "void", "wchar",
|
|
||||||
"while", "with", "__DATE__", "__EOF__", "__FILE__",
|
|
||||||
"__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters",
|
|
||||||
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__",
|
|
||||||
"__traits", "__vector", "__VENDOR__", "__VERSION__", "$", "++", "--",
|
|
||||||
".", "[", "]", "(", ")", "{", "}"
|
|
||||||
];
|
|
||||||
immutable identifierTokenCases = identifierTokens.map!(
|
|
||||||
a => format(`case tok!"%s": return %d;`, a, a.length)).join("\n\t");
|
|
||||||
return spacedOperatorTokenCases ~ identifierTokenCases;
|
|
||||||
}
|
|
|
@ -1,182 +0,0 @@
|
||||||
// Copyright Brian Schott 2015.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// (See accompanying file LICENSE.txt or copy at
|
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
module dfmt.wrapping;
|
|
||||||
|
|
||||||
import dparse.lexer;
|
|
||||||
import dfmt.tokens;
|
|
||||||
import dfmt.config;
|
|
||||||
|
|
||||||
struct State
|
|
||||||
{
|
|
||||||
this(uint breaks, const Token[] tokens, immutable short[] depths,
|
|
||||||
const Config* config, int currentLineLength, int indentLevel) pure @safe
|
|
||||||
{
|
|
||||||
import std.math : abs;
|
|
||||||
import core.bitop : popcnt, bsf;
|
|
||||||
import std.algorithm : min, map, sum;
|
|
||||||
|
|
||||||
immutable int remainingCharsMultiplier = 25;
|
|
||||||
immutable int newlinePenalty = 480;
|
|
||||||
|
|
||||||
this.breaks = breaks;
|
|
||||||
this._cost = 0;
|
|
||||||
this._solved = true;
|
|
||||||
|
|
||||||
if (breaks == 0)
|
|
||||||
{
|
|
||||||
immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
|
|
||||||
if (l > config.dfmt_soft_max_line_length)
|
|
||||||
{
|
|
||||||
immutable int longPenalty = (l - config.dfmt_soft_max_line_length)
|
|
||||||
* remainingCharsMultiplier;
|
|
||||||
this._cost += longPenalty;
|
|
||||||
this._solved = longPenalty < newlinePenalty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (size_t i; 0 .. (uint.sizeof * 8))
|
|
||||||
{
|
|
||||||
if (((1 << i) & breaks) == 0)
|
|
||||||
continue;
|
|
||||||
immutable prevType = i > 0 ? tokens[i - 1].type : tok!"";
|
|
||||||
immutable currentType = tokens[i].type;
|
|
||||||
immutable p = abs(depths[i]);
|
|
||||||
immutable bc = breakCost(prevType, currentType) * (p == 0 ? 1 : p * 2);
|
|
||||||
this._cost += bc + newlinePenalty;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ll = currentLineLength;
|
|
||||||
size_t i = 0;
|
|
||||||
foreach (_; 0 .. uint.sizeof * 8)
|
|
||||||
{
|
|
||||||
immutable uint k = breaks >>> i;
|
|
||||||
immutable bool b = k == 0;
|
|
||||||
immutable uint bits = b ? ALGORITHMIC_COMPLEXITY_SUCKS : bsf(k);
|
|
||||||
immutable size_t j = min(i + bits + 1, tokens.length);
|
|
||||||
ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
|
|
||||||
if (ll > config.dfmt_soft_max_line_length)
|
|
||||||
{
|
|
||||||
immutable int longPenalty = (ll - config.dfmt_soft_max_line_length)
|
|
||||||
* remainingCharsMultiplier;
|
|
||||||
this._cost += longPenalty;
|
|
||||||
}
|
|
||||||
if (ll > config.max_line_length)
|
|
||||||
{
|
|
||||||
this._solved = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i = j;
|
|
||||||
if (indentLevel < 0)
|
|
||||||
ll = (abs(indentLevel) + 1) * config.indent_size;
|
|
||||||
else
|
|
||||||
ll = (indentLevel + (i == 0 ? 0 : 1)) * config.indent_size;
|
|
||||||
if (b)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cost() const pure nothrow @safe @property
|
|
||||||
{
|
|
||||||
return _cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
int solved() const pure nothrow @safe @property
|
|
||||||
{
|
|
||||||
return _solved;
|
|
||||||
}
|
|
||||||
|
|
||||||
int opCmp(ref const State other) const pure nothrow @safe
|
|
||||||
{
|
|
||||||
import core.bitop : bsf, popcnt;
|
|
||||||
|
|
||||||
if (_cost < other._cost)
|
|
||||||
return -1;
|
|
||||||
if (_cost == other._cost && (breaks != 0 && other.breaks != 0
|
|
||||||
&& bsf(breaks) > bsf(other.breaks)))
|
|
||||||
return -1;
|
|
||||||
return _cost > other._cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool opEquals(ref const State other) const pure nothrow @safe
|
|
||||||
{
|
|
||||||
return other.breaks == breaks;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t toHash() const pure nothrow @safe
|
|
||||||
{
|
|
||||||
return breaks;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint breaks;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _cost;
|
|
||||||
bool _solved;
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Negative values for `indentLevel` are treated specially: costs for
|
|
||||||
* continuation indents are reduced. This is used for array literals.
|
|
||||||
*/
|
|
||||||
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
|
|
||||||
immutable short[] depths, const Config* config, int currentLineLength, int indentLevel)
|
|
||||||
{
|
|
||||||
import std.container.rbtree : RedBlackTree;
|
|
||||||
import std.algorithm : filter, min;
|
|
||||||
import core.bitop : popcnt;
|
|
||||||
|
|
||||||
static size_t[] genRetVal(uint breaks, size_t index) pure nothrow @safe
|
|
||||||
{
|
|
||||||
auto retVal = new size_t[](popcnt(breaks));
|
|
||||||
size_t j = 0;
|
|
||||||
foreach (uint i; 0 .. uint.sizeof * 8)
|
|
||||||
if ((1 << i) & breaks)
|
|
||||||
retVal[j++] = index + i;
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
|
|
||||||
auto open = new RedBlackTree!State;
|
|
||||||
open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], config,
|
|
||||||
currentLineLength, indentLevel));
|
|
||||||
State lowest;
|
|
||||||
lowest._solved = false;
|
|
||||||
int tries = 0;
|
|
||||||
while (!open.empty && tries < 10_00)
|
|
||||||
{
|
|
||||||
tries++;
|
|
||||||
State current = open.front();
|
|
||||||
open.removeFront();
|
|
||||||
if (current.solved)
|
|
||||||
return genRetVal(current.breaks, index);
|
|
||||||
if (current < lowest)
|
|
||||||
lowest = current;
|
|
||||||
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], depths[0 .. tokensEnd],
|
|
||||||
current.breaks, config, currentLineLength, indentLevel);
|
|
||||||
}
|
|
||||||
foreach (r; open[].filter!(a => a.solved))
|
|
||||||
return genRetVal(r.breaks, index);
|
|
||||||
if (open[].front < lowest)
|
|
||||||
return genRetVal(open[].front.breaks, index);
|
|
||||||
else
|
|
||||||
return genRetVal(lowest.breaks, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void validMoves(OR)(auto ref OR output, const Token[] tokens, immutable short[] depths,
|
|
||||||
uint current, const Config* config, int currentLineLength, int indentLevel)
|
|
||||||
{
|
|
||||||
foreach (i, token; tokens)
|
|
||||||
{
|
|
||||||
if (!isBreakToken(token.type) || (((1 << i) & current) != 0))
|
|
||||||
continue;
|
|
||||||
immutable uint breaks = current | (1 << i);
|
|
||||||
output.insert(State(breaks, tokens, depths, config, currentLineLength, indentLevel));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue