This commit is contained in:
Sebastian Wilzbach 2018-09-05 22:54:28 +00:00 committed by GitHub
commit 2c615cfd79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 530 additions and 69 deletions

View File

@ -4,9 +4,6 @@ set -e
if [[ $BUILD == dub ]]; then if [[ $BUILD == dub ]]; then
dub build --build=release dub build --build=release
mkdir bin
mv dfmt ./bin
elif [[ $DC == ldc2 ]]; then elif [[ $DC == ldc2 ]]; then
git submodule update --init --recursive git submodule update --init --recursive
make ldc -j2 make ldc -j2

View File

@ -43,3 +43,55 @@ jobs:
on: on:
tags: true # must be a git tag tags: true # must be a git tag
repo: dlang-community/dfmt # must be a tag on dlang-community repo: dlang-community/dfmt # must be a tag on dlang-community
- stage: GitHub Release
#if: tag IS present
d: ldc-1.8.0
os: linux
script: echo "Deploying to GitHub releases ..." && ./release.sh
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.tar.gz
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
- stage: GitHub Release
#if: tag IS present
d: ldc-1.8.0
os: osx
script: echo "Deploying to GitHub releases ..." && ./release.sh
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.tar.gz
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
- stage: GitHub Release
#if: tag IS present
d: dmd
os: linux
language: generic
sudo: yes
script: echo "Deploying to GitHub releases ..." && ./release-windows.sh
addons:
apt:
packages:
- p7zip-full
- wine
deploy:
provider: releases
api_key: $GH_REPO_TOKEN
file_glob: true
file: bin/dfmt-*.zip
skip_cleanup: true
on:
repo: dlang-community/dfmt
tags: true
stages:
- name: test
if: type = pull_request or (type = push and branch = master)

View File

@ -41,6 +41,7 @@ found in .editorconfig files.
* **--max_line_length**: See **max_line_length** below * **--max_line_length**: See **max_line_length** below
* **--soft_max_line_length**: See **dfmt_soft_max_line_length** below * **--soft_max_line_length**: See **dfmt_soft_max_line_length** below
* **--outdent_attributes**: See **dfmt_outdent_attributes** below * **--outdent_attributes**: See **dfmt_outdent_attributes** below
* **--single_template_constraint_indent**: See **dfmt_template_constraint_style** below
* **--space_after_cast**: See **dfmt_space_after_cast** below * **--space_after_cast**: See **dfmt_space_after_cast** below
* **--space_before_function_parameters**: See **dfmt_space_before_function_parameters** below * **--space_before_function_parameters**: See **dfmt_space_before_function_parameters** below
* **--split_operator_at_line_end**: See **dfmt_split_operator_at_line_end** below * **--split_operator_at_line_end**: See **dfmt_split_operator_at_line_end** below
@ -68,7 +69,7 @@ void main(string[] args)
// argument list normally // argument list normally
getopt(args, "optionOne", &optionOne, "optionTwo", &optionTwo, "optionThree", &optionThree); getopt(args, "optionOne", &optionOne, "optionTwo", &optionTwo, "optionThree", &optionThree);
// dfmt off // dfmt off
getopt(args, getopt(args,
"optionOne", &optionOne, "optionOne", &optionOne,
"optionTwo", &optionTwo, "optionTwo", &optionTwo,
@ -105,6 +106,7 @@ dfmt_space_before_function_parameters | `true`, `false` | `false` | Insert space
dfmt_selective_import_space | `true`, `false` | `true` | Insert space after the module name and before the `:` for selective imports. dfmt_selective_import_space | `true`, `false` | `true` | Insert space after the module name and before the `:` for selective imports.
dfmt_compact_labeled_statements | `true`, `false` | `true` | Place labels on the same line as the labeled `switch`, `for`, `foreach`, or `while` statement. dfmt_compact_labeled_statements | `true`, `false` | `true` | Place labels on the same line as the labeled `switch`, `for`, `foreach`, or `while` statement.
dfmt_template_constraint_style | `conditional_newline_indent` `conditional_newline` `always_newline` `always_newline_indent` | `conditional_newline_indent` | Control the formatting of template constraints. dfmt_template_constraint_style | `conditional_newline_indent` `conditional_newline` `always_newline` `always_newline_indent` | `conditional_newline_indent` | Control the formatting of template constraints.
dfmt_single_template_constraint_indent | `true`, `false` | `false` | Set if the constraints are indented by a single tab instead of two. Has only an effect for if indentation style if set to `always_newline_indent` or `conditional_newline_indent`.
## Terminology ## Terminology
* Braces - `{` and `}` * Braces - `{` and `}`

View File

@ -4,6 +4,8 @@
"targetType": "autodetect", "targetType": "autodetect",
"license": "BSL-1.0", "license": "BSL-1.0",
"dependencies": { "dependencies": {
"libdparse": "~>0.8.0-alpha.5" "libdparse": "~>0.8.6"
} },
"targetPath" : "bin/",
"targetName" : "dfmt",
} }

@ -1 +1 @@
Subproject commit ee0fa01ab74b6bf27bed3c7bdb9d6fb789963342 Subproject commit 086cf06051bb1f33c94891ba6c39a57f164ee296

View File

@ -44,3 +44,6 @@ pkg: dmd
clean: clean:
$(RM) bin/dfmt $(RM) bin/dfmt
release:
./release.sh

25
release-windows.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
# Build the Windows binaries under Linux (requires wine)
set -eux -o pipefail
VERSION=$(git describe --abbrev=0 --tags)
OS=windows
ARCH_SUFFIX="x86"
# Allow the script to be run from anywhere
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR
# Step 1: download the DMD binaries
if [ ! -d dmd2 ] ; then
wget http://downloads.dlang.org/releases/2.x/2.079.0/dmd.2.079.0.windows.7z
7z x dmd.2.079.0.windows.7z > /dev/null
fi
# Step 2: Run DMD via wineconsole
archiveName="dfmt-$VERSION-$OS-$ARCH_SUFFIX.zip"
echo "Building $archiveName"
mkdir -p bin
DC="$DIR/dmd2/windows/bin/dmd.exe" wine cmd /C build.bat
cd bin
zip "$archiveName" dfmt.exe

23
release.sh Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -eux -o pipefail
VERSION=$(git describe --abbrev=0 --tags)
ARCH="${ARCH:-64}"
LDC_FLAGS=()
unameOut="$(uname -s)"
case "$unameOut" in
Linux*) OS=linux; LDC_FLAGS=("-flto=full" "-linker=gold" "-static") ;;
Darwin*) OS=osx; LDC_FLAGS+=("-L-macosx_version_min" "-L10.7" "-L-lcrt1.o"); ;;
*) echo "Unknown OS: $unameOut"; exit 1
esac
case "$ARCH" in
64) ARCH_SUFFIX="x86_64";;
32) ARCH_SUFFIX="x86";;
*) echo "Unknown ARCH: $ARCH"; exit 1
esac
archiveName="dfmt-$VERSION-$OS-$ARCH_SUFFIX.tar.gz"
echo "Building $archiveName"
${MAKE:-make} ldc LDC_FLAGS="${LDC_FLAGS[*]}"
tar cvfz "bin/$archiveName" -C bin dfmt

View File

@ -1,5 +0,0 @@
### First dfmt release with neptune!
Well there we go, from now on with proper Changelog and all that.
Since previous releases were done without using neptune guidelines, we are missing proper release notes / a changelog for this release, but for new releases you can expect much more comprehensive release notes.

View File

@ -8,13 +8,29 @@ module dfmt.ast_info;
import dparse.lexer; import dparse.lexer;
import dparse.ast; import dparse.ast;
enum BraceIndentInfoFlags
{
tempIndent = 1 << 0,
}
struct BraceIndentInfo
{
size_t startLocation;
size_t endLocation;
uint flags;
uint beginIndentLevel;
}
/// AST information that is needed by the formatter. /// AST information that is needed by the formatter.
struct ASTInformation struct ASTInformation
{ {
/// Sorts the arrays so that binary search will work on them /// Sorts the arrays so that binary search will work on them
void cleanup() void cleanup()
{ {
import std.algorithm : sort; import std.algorithm : sort, uniq;
import std.array : array;
sort(doubleNewlineLocations); sort(doubleNewlineLocations);
sort(spaceAfterLocations); sort(spaceAfterLocations);
@ -33,6 +49,10 @@ struct ASTInformation
sort(constructorDestructorLocations); sort(constructorDestructorLocations);
sort(staticConstructorDestructorLocations); sort(staticConstructorDestructorLocations);
sort(sharedStaticConstructorDestructorLocations); sort(sharedStaticConstructorDestructorLocations);
sort!((a,b) => a.endLocation < b.endLocation)
(indentInfoSortedByEndLocation);
sort(ufcsHintLocations);
ufcsHintLocations = ufcsHintLocations.uniq().array();
} }
/// Locations of end braces for struct bodies /// Locations of end braces for struct bodies
@ -85,6 +105,11 @@ struct ASTInformation
/// Locations of constructor/destructor "this" tokens ? /// Locations of constructor/destructor "this" tokens ?
size_t[] constructorDestructorLocations; size_t[] constructorDestructorLocations;
/// Locations of '.' characters that might be UFCS chains.
size_t[] ufcsHintLocations;
BraceIndentInfo[] indentInfoSortedByEndLocation;
} }
/// Collects information from the AST that is useful for the formatter /// Collects information from the AST that is useful for the formatter
@ -187,8 +212,12 @@ final class FormatVisitor : ASTVisitor
{ {
if (funcLit.functionBody !is null) if (funcLit.functionBody !is null)
{ {
astInformation.funLitStartLocations ~= funcLit.functionBody.blockStatement.startLocation; const bs = funcLit.functionBody.blockStatement;
astInformation.funLitEndLocations ~= funcLit.functionBody.blockStatement.endLocation;
astInformation.funLitStartLocations ~= bs.startLocation;
astInformation.funLitEndLocations ~= bs.endLocation;
astInformation.indentInfoSortedByEndLocation ~=
BraceIndentInfo(bs.startLocation, bs.endLocation);
} }
funcLit.accept(this); funcLit.accept(this);
} }
@ -226,6 +255,9 @@ final class FormatVisitor : ASTVisitor
{ {
astInformation.structInitStartLocations ~= structInitializer.startLocation; astInformation.structInitStartLocations ~= structInitializer.startLocation;
astInformation.structInitEndLocations ~= structInitializer.endLocation; astInformation.structInitEndLocations ~= structInitializer.endLocation;
astInformation.indentInfoSortedByEndLocation ~=
BraceIndentInfo(structInitializer.startLocation, structInitializer.endLocation);
structInitializer.accept(this); structInitializer.accept(this);
} }
@ -268,6 +300,26 @@ final class FormatVisitor : ASTVisitor
override void visit(const UnaryExpression unary) 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!"&" if (unary.prefix.type == tok!"~" || unary.prefix.type == tok!"&"
|| unary.prefix.type == tok!"*" || unary.prefix.type == tok!"*"
|| unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-") || unary.prefix.type == tok!"+" || unary.prefix.type == tok!"-")

View File

@ -53,6 +53,8 @@ struct Config
OptionalBoolean dfmt_compact_labeled_statements; OptionalBoolean dfmt_compact_labeled_statements;
/// ///
TemplateConstraintStyle dfmt_template_constraint_style; TemplateConstraintStyle dfmt_template_constraint_style;
///
OptionalBoolean dfmt_single_template_constraint_indent;
mixin StandardEditorConfigFields; mixin StandardEditorConfigFields;
@ -79,6 +81,7 @@ struct Config
dfmt_selective_import_space = OptionalBoolean.t; dfmt_selective_import_space = OptionalBoolean.t;
dfmt_compact_labeled_statements = OptionalBoolean.t; dfmt_compact_labeled_statements = OptionalBoolean.t;
dfmt_template_constraint_style = TemplateConstraintStyle.conditional_newline_indent; dfmt_template_constraint_style = TemplateConstraintStyle.conditional_newline_indent;
dfmt_single_template_constraint_indent = OptionalBoolean.f;
} }
/** /**

View File

@ -283,6 +283,10 @@ private:
{ {
formatKeyword(); formatKeyword();
} }
else if (current.text == "body" && peekBackIsFunctionDeclarationEnding())
{
formatKeyword();
}
else if (isBasicType(current.type)) else if (isBasicType(current.type))
{ {
writeToken(); writeToken();
@ -324,6 +328,7 @@ private:
void formatConstraint() void formatConstraint()
{ {
import dfmt.editorconfig : OB = OptionalBoolean;
with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style) with (TemplateConstraintStyle) final switch (config.dfmt_template_constraint_style)
{ {
case unspecified: case unspecified:
@ -342,15 +347,19 @@ private:
immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]); immutable l = currentLineLength + betweenParenLength(tokens[index + 1 .. $]);
if (l > config.dfmt_soft_max_line_length) if (l > config.dfmt_soft_max_line_length)
{ {
pushWrapIndent(tok!"!"); config.dfmt_single_template_constraint_indent == OB.t ?
pushWrapIndent() : pushWrapIndent(tok!"!");
newline(); newline();
} }
else if (peekBackIs(tok!")")) else if (peekBackIs(tok!")"))
write(" "); write(" ");
break; break;
case always_newline_indent: case always_newline_indent:
pushWrapIndent(tok!"!"); {
newline(); config.dfmt_single_template_constraint_indent == OB.t ?
pushWrapIndent() : pushWrapIndent(tok!"!");
newline();
}
break; break;
} }
// if // if
@ -370,7 +379,12 @@ private:
if (commentText[0 .. 2] == "//") if (commentText[0 .. 2] == "//")
commentText = commentText[2 .. $]; commentText = commentText[2 .. $];
else else
commentText = commentText[2 .. $ - 2]; {
if (commentText.length > 3)
commentText = commentText[2 .. $ - 2];
else
commentText = commentText[2 .. $];
}
return commentText.strip(); return commentText.strip();
} }
@ -586,8 +600,10 @@ private:
indents.pop(); indents.pop();
if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in") if (parenDepth == 0 && (peekIs(tok!"is") || peekIs(tok!"in")
|| peekIs(tok!"out") || peekIs(tok!"body"))) || peekIs(tok!"out") || peekIs(tok!"do") || peekIsBody))
{
writeToken(); writeToken();
}
else if (peekIsLiteralOrIdent() || peekIsBasicType()) else if (peekIsLiteralOrIdent() || peekIsBasicType())
{ {
writeToken(); writeToken();
@ -732,7 +748,9 @@ private:
{ {
import std.algorithm : map, sum, canFind; import std.algorithm : map, sum, canFind;
if (astInformation.structInitStartLocations.canFindIndex(tokens[index].index)) auto tIndex = tokens[index].index;
if (astInformation.structInitStartLocations.canFindIndex(tIndex))
{ {
sBraceDepth++; sBraceDepth++;
auto e = expressionEndIndex(index); auto e = expressionEndIndex(index);
@ -741,13 +759,21 @@ private:
writeToken(); writeToken();
if (l > config.dfmt_soft_max_line_length) if (l > config.dfmt_soft_max_line_length)
{ {
import std.algorithm.searching : find;
auto indentInfo = astInformation.indentInfoSortedByEndLocation
.find!((a,b) => a.startLocation == b)(tIndex);
assert(indentInfo.length > 0);
cast()indentInfo[0].flags |= BraceIndentInfoFlags.tempIndent;
cast()indentInfo[0].beginIndentLevel = indents.indentLevel;
indents.push(tok!"{"); indents.push(tok!"{");
newline(); newline();
} }
else else
niBraceDepth++; niBraceDepth++;
} }
else if (astInformation.funLitStartLocations.canFindIndex(tokens[index].index)) else if (astInformation.funLitStartLocations.canFindIndex(tIndex))
{ {
sBraceDepth++; sBraceDepth++;
if (peekBackIs(tok!")")) if (peekBackIs(tok!")"))
@ -803,15 +829,34 @@ private:
void formatRightBrace() void formatRightBrace()
{ {
if (astInformation.structInitEndLocations.canFindIndex(tokens[index].index)) void popToBeginIndent(BraceIndentInfo indentInfo)
{
foreach(i; indentInfo.beginIndentLevel .. indents.indentLevel)
{
indents.pop();
}
indentLevel = indentInfo.beginIndentLevel;
}
size_t pos;
if (astInformation.structInitEndLocations.canFindIndex(tokens[index].index, &pos))
{ {
if (sBraceDepth > 0) if (sBraceDepth > 0)
sBraceDepth--; sBraceDepth--;
if (niBraceDepth > 0) if (niBraceDepth > 0)
niBraceDepth--; niBraceDepth--;
auto indentInfo = astInformation.indentInfoSortedByEndLocation[pos];
if (indentInfo.flags & BraceIndentInfoFlags.tempIndent)
{
popToBeginIndent(indentInfo);
simpleNewline();
indent();
}
writeToken(); writeToken();
} }
else if (astInformation.funLitEndLocations.canFindIndex(tokens[index].index)) else if (astInformation.funLitEndLocations.canFindIndex(tokens[index].index, &pos))
{ {
if (niBraceDepth > 0) if (niBraceDepth > 0)
{ {
@ -913,9 +958,11 @@ private:
if (!currentIs(tok!"{") && !currentIs(tok!";")) if (!currentIs(tok!"{") && !currentIs(tok!";"))
write(" "); write(" ");
} }
else if (!currentIs(tok!"{") && !currentIs(tok!";") else if (!currentIs(tok!"{") && !currentIs(tok!";") && !currentIs(tok!"in") &&
&& !currentIs(tok!"in") && !currentIs(tok!"out") && !currentIs(tok!"body")) !currentIs(tok!"out") && !currentIs(tok!"do") && current.text != "body")
{
newline(); newline();
}
else if (currentIs(tok!"{") && indents.topAre(tok!"static", tok!"if")) else if (currentIs(tok!"{") && indents.topAre(tok!"static", tok!"if"))
{ {
// Hacks to format braced vs non-braced static if declarations. // Hacks to format braced vs non-braced static if declarations.
@ -1004,7 +1051,12 @@ private:
if (!currentIs(tok!"{")) if (!currentIs(tok!"{"))
newline(); newline();
break; break;
case tok!"body": case tok!"identifier":
if (current.text == "body")
goto case tok!"do";
else
goto default;
case tok!"do":
if (!peekBackIs(tok!"}")) if (!peekBackIs(tok!"}"))
newline(); newline();
writeToken(); writeToken();
@ -1190,11 +1242,14 @@ private:
break; break;
case tok!".": case tok!".":
regenLineBreakHintsIfNecessary(index); regenLineBreakHintsIfNecessary(index);
if (linebreakHints.canFind(index) || (linebreakHints.length == 0 immutable bool ufcsWrap = astInformation.ufcsHintLocations.canFindIndex(current.index);
if (ufcsWrap || linebreakHints.canFind(index) || (linebreakHints.length == 0
&& currentLineLength + nextTokenLength() > config.max_line_length)) && currentLineLength + nextTokenLength() > config.max_line_length))
{ {
pushWrapIndent(); pushWrapIndent();
newline(); newline();
if (ufcsWrap)
regenLineBreakHints(index);
} }
writeToken(); writeToken();
break; break;
@ -1317,7 +1372,18 @@ private:
void regenLineBreakHints(immutable size_t i) void regenLineBreakHints(immutable size_t i)
{ {
immutable size_t j = expressionEndIndex(i); import std.range : assumeSorted;
import std.algorithm.comparison : min;
import std.algorithm.searching : countUntil;
// The end of the tokens considered by the line break algorithm is
// either the expression end index or the next mandatory line break,
// whichever is first.
auto r = assumeSorted(astInformation.ufcsHintLocations).upperBound(tokens[i].index);
immutable ufcsBreakLocation = r.empty
? size_t.max
: tokens[i .. $].countUntil!(t => t.index == r.front) + i;
immutable size_t j = min(expressionEndIndex(i), ufcsBreakLocation);
// Use magical negative value for array literals and wrap indents // Use magical negative value for array literals and wrap indents
immutable inLvl = (indents.topIsWrap() || indents.topIs(tok!"]")) ? -indentLevel immutable inLvl = (indents.topIsWrap() || indents.topIs(tok!"]")) ? -indentLevel
: indentLevel; : indentLevel;
@ -1659,10 +1725,7 @@ const pure @safe @nogc:
const(Token) peekBack(uint distance = 1) nothrow const(Token) peekBack(uint distance = 1) nothrow
{ {
if (index < distance) assert(index >= distance, "Trying to peek before the first token");
{
assert(0, "Trying to peek before the first token");
}
return tokens[index - distance]; return tokens[index - distance];
} }
@ -1793,6 +1856,18 @@ const pure @safe @nogc:
return peekImplementation(tokenType, 1, ignoreComments); return peekImplementation(tokenType, 1, ignoreComments);
} }
bool peekIsBody() nothrow
{
return index + 1 < tokens.length && tokens[index + 1].text == "body";
}
bool peekBackIsFunctionDeclarationEnding() nothrow
{
return peekBackIsOneOf(false, tok!")", tok!"const", tok!"immutable",
tok!"inout", tok!"shared", tok!"@", tok!"pure", tok!"nothrow",
tok!"return", tok!"scope");
}
bool peekBackIsSlashSlash() nothrow bool peekBackIsSlashSlash() nothrow
{ {
return index > 0 && tokens[index - 1].type == tok!"comment" return index > 0 && tokens[index - 1].type == tok!"comment"
@ -1844,9 +1919,28 @@ const pure @safe @nogc:
} }
} }
bool canFindIndex(const size_t[] items, size_t index) pure @safe @nogc bool canFindIndex(const size_t[] items, size_t index, size_t* pos = null) pure @safe @nogc
{ {
import std.range : assumeSorted; import std.range : assumeSorted;
if (!pos)
return !assumeSorted(items).equalRange(index).empty; {
return !assumeSorted(items).equalRange(index).empty;
}
else
{
auto trisection_result = assumeSorted(items).trisect(index);
if (trisection_result[1].length == 1)
{
*pos = trisection_result[0].length;
return true;
}
else if (trisection_result[1].length == 0)
{
return false;
}
else
{
assert(0, "the constraint of having unique locations has been violated");
}
}
} }

View File

@ -68,7 +68,13 @@ struct IndentStack
void push(IdType item) pure nothrow void push(IdType item) pure nothrow
{ {
arr[index] = item; arr[index] = item;
index = index + 1 == arr.length ? index : index + 1; //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++;
}
} }
/** /**
@ -76,7 +82,8 @@ struct IndentStack
*/ */
void pop() pure nothrow void pop() pure nothrow
{ {
index = index == 0 ? index : index - 1; if (index)
index--;
} }
/** /**

View File

@ -18,18 +18,18 @@ static immutable VERSION = () {
{ {
// takes the `git describe --tags` output and removes the leading // takes the `git describe --tags` output and removes the leading
// 'v' as well as any kind of newline // 'v' as well as any kind of newline
// if the tag is considered malformed it gets used verbatim // if the tag is considered malformed it gets used verbatim
enum gitDescribeOutput = import("VERSION"); enum gitDescribeOutput = import("VERSION");
string result; string result;
if (gitDescribeOutput[0] == 'v') if (gitDescribeOutput[0] == 'v')
result = gitDescribeOutput[1 .. $]; result = gitDescribeOutput[1 .. $];
else else
result = null; result = null;
uint minusCount; uint minusCount;
foreach (i, c; result) foreach (i, c; result)
{ {
@ -39,17 +39,17 @@ static immutable VERSION = () {
break; break;
} }
if (c == '-') if (c == '-')
{ {
++minusCount; ++minusCount;
} }
} }
if (minusCount > 1) if (minusCount > 1)
result = null; result = null;
return result ? result ~ DEBUG_SUFFIX return result ? result ~ DEBUG_SUFFIX
: gitDescribeOutput ~ DEBUG_SUFFIX; : gitDescribeOutput ~ DEBUG_SUFFIX;
} }
else else
@ -85,9 +85,9 @@ else
void handleBooleans(string option, string value) void handleBooleans(string option, string value)
{ {
import dfmt.editorconfig : OptionalBoolean; import dfmt.editorconfig : OptionalBoolean;
import std.exception : enforceEx; import std.exception : enforce;
enforceEx!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)
@ -103,7 +103,7 @@ else
break; break;
case "space_before_function_parameters": case "space_before_function_parameters":
optConfig.dfmt_space_before_function_parameters = optVal; optConfig.dfmt_space_before_function_parameters = optVal;
break; break;
case "split_operator_at_line_end": case "split_operator_at_line_end":
optConfig.dfmt_split_operator_at_line_end = optVal; optConfig.dfmt_split_operator_at_line_end = optVal;
break; break;
@ -113,6 +113,9 @@ else
case "compact_labeled_statements": case "compact_labeled_statements":
optConfig.dfmt_compact_labeled_statements = optVal; optConfig.dfmt_compact_labeled_statements = optVal;
break; break;
case "single_template_constraint_indent":
optConfig.dfmt_single_template_constraint_indent = optVal;
break;
default: default:
assert(false, "Invalid command-line switch"); assert(false, "Invalid command-line switch");
} }
@ -139,6 +142,7 @@ else
"space_before_function_parameters", &handleBooleans, "space_before_function_parameters", &handleBooleans,
"split_operator_at_line_end", &handleBooleans, "split_operator_at_line_end", &handleBooleans,
"compact_labeled_statements", &handleBooleans, "compact_labeled_statements", &handleBooleans,
"single_template_constraint_indent", &handleBooleans,
"tab_width", &optConfig.tab_width, "tab_width", &optConfig.tab_width,
"template_constraint_style", &optConfig.dfmt_template_constraint_style); "template_constraint_style", &optConfig.dfmt_template_constraint_style);
// dfmt on // dfmt on
@ -293,26 +297,25 @@ private version (Windows)
} }
} }
private string optionsToString(E)() if (is(E == enum)) template optionsToString(E) if (is(E == enum))
{ {
import std.traits : EnumMembers; enum optionsToString = () {
import std.conv : to;
string result = "("; string result = "(";
foreach (i, option; EnumMembers!E) foreach (s; [__traits(allMembers, E)])
{ {
immutable s = to!string(option); if (s != "unspecified")
if (s != "unspecified") result ~= s ~ "|";
result ~= s ~ "|"; }
} result = result[0 .. $ - 1] ~ ")";
result = result[0 .. $ - 1] ~ ")"; return result;
return result; } ();
} }
private void printHelp() private void printHelp()
{ {
writeln(`dfmt `, VERSION, ` writeln(`dfmt `, VERSION, `
https://github.com/Hackerpilot/dfmt https://github.com/dlang-community/dfmt
Options: Options:
--help, -h Print this help message --help, -h Print this help message
@ -322,23 +325,24 @@ 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)), `
--soft_max_line_length --soft_max_line_length
--max_line_length --max_line_length
--outdent_attributes --outdent_attributes
--space_after_cast --space_after_cast
--space_before_function_parameters --space_before_function_parameters
--selective_import_space --selective_import_space
--single_template_constraint_indent
--split_operator_at_line_end --split_operator_at_line_end
--compact_labeled_statements --compact_labeled_statements
--template_constraint_style --template_constraint_style
`, `,
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)

View File

@ -217,7 +217,7 @@ private string generateFixedLengthCases()
a => format(`case tok!"%s": return %d + 1;`, a, a.length)).join("\n\t"); a => format(`case tok!"%s": return %d + 1;`, a, a.length)).join("\n\t");
string[] identifierTokens = [ string[] identifierTokens = [
"abstract", "alias", "align", "asm", "assert", "auto", "body", "bool", "abstract", "alias", "align", "asm", "assert", "auto", "bool",
"break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class", "break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class",
"const", "continue", "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated", "const", "continue", "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated",
"do", "double", "else", "enum", "export", "extern", "false", "final", "finally", "float", "do", "double", "else", "enum", "export", "extern", "false", "final", "finally", "float",

@ -1 +1 @@
Subproject commit 7487970b58f4a2c0d495679329a8a2857111f3fd Subproject commit b7778fd6bf5f9aaaa87dd27f989cefbf9b3b365f

View File

@ -3,7 +3,8 @@ unittest
{ {
{ {
foreach (abcde, def; abcdef.map!(battlecruiser => battlecruiser[123 .. 1231231]) foreach (abcde, def; abcdef.map!(battlecruiser => battlecruiser[123 .. 1231231])
.filter!(bravo => charlie[10] > 90000).sum()) .filter!(bravo => charlie[10] > 90000)
.sum())
{ {
} }

View File

@ -0,0 +1,9 @@
void foo()()
if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees
&& cows && sheeps && monkeys && whales)
{
}
void foo()() if (dogs && pigs && birds)
{
}

View File

@ -0,0 +1,10 @@
void foo()()
if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees
&& cows && sheeps && monkeys && whales)
{
}
void foo()()
if (dogs && pigs && birds)
{
}

View File

@ -0,0 +1,19 @@
import character.body;
void body() @nogc
in
{
}
body
{
body = null;
}
void body()
in
{
}
do
{
body = null;
}

View File

@ -0,0 +1,40 @@
void fn()
{
{
{
{
auto file = {
"integrationtest/feed/etc/config.iniaasdfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"etc/config.ini"
};
{
int x;
}
}
}
}
}
struct A
{
int x, y, z;
}
int main()
{
int fun()
{
import std.stdio : writeln;
import std.typecons : tuple;
A a = {
tuple(Variant(1))[0].get!int, tuple(Variant(2))[0].get!int,
tuple(Variant(3))[0].get!int
};
A b = {
tuple(Variant(1))[0].get!int, tuple(Variant(2))[0].get!int,
tuple(Variant(3))[0].get!int
};
writeln(a);
}
}

View File

@ -0,0 +1,6 @@
void main()
{
stuff[].map!(things => stuff.doThings)
.filter!(stuff)
.array();
}

View File

@ -0,0 +1,2 @@
--template_constraint_style=conditional_newline_indent
--single_template_constraint_indent=true

View File

@ -0,0 +1,4 @@
void foo()() if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees && cows && sheeps && monkeys && whales)
{}
void foo()() if (dogs && pigs && birds) {}

View File

@ -0,0 +1,2 @@
--template_constraint_style=always_newline_indent
--single_template_constraint_indent=true

View File

@ -0,0 +1,4 @@
void foo()() if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees && cows && sheeps && monkeys && whales)
{}
void foo()() if (dogs && pigs && birds) {}

7
tests/do_body.d Normal file
View File

@ -0,0 +1,7 @@
import character.body;
void body() @nogc
in{} body{body = null;}
void body()
in{} do{ body = null;}

22
tests/issue0237.d Normal file
View File

@ -0,0 +1,22 @@
void fn () {{{{
auto file =
{ "integrationtest/feed/etc/config.iniaasdfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"etc/config.ini" };
{ int x; }
}}}}
struct A
{
int x, y, z;
}
int main()
{
int fun()
{
import std.stdio : writeln;
import std.typecons : tuple;
A a = { tuple(Variant(1))[0].get!int, tuple(Variant(2))[0].get!int, tuple(Variant(3))[0].get!int };
A b = { tuple(Variant(1))[0].get!int, tuple(Variant(2))[0].get!int, tuple(Variant(3))[0].get!int };
writeln(a);
}
}

View File

@ -2,7 +2,8 @@ unittest {
{ {
{ {
foreach (abcde, def; abcdef.map!(battlecruiser => battlecruiser[123 .. 1231231]) foreach (abcde, def; abcdef.map!(battlecruiser => battlecruiser[123 .. 1231231])
.filter!(bravo => charlie[10] > 90000).sum()) { .filter!(bravo => charlie[10] > 90000)
.sum()) {
} }
abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234) abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234)

View File

@ -0,0 +1,7 @@
void foo()()
if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees
&& cows && sheeps && monkeys && whales) {
}
void foo()() if (dogs && pigs && birds) {
}

View File

@ -0,0 +1,8 @@
void foo()()
if (dogs && pigs && birds && ants && foxes && flies && cats && bugs && bees
&& cows && sheeps && monkeys && whales) {
}
void foo()()
if (dogs && pigs && birds) {
}

15
tests/otbs/do_body.d.ref Normal file
View File

@ -0,0 +1,15 @@
import character.body;
void body() @nogc
in {
}
body {
body = null;
}
void body()
in {
}
do {
body = null;
}

View File

@ -0,0 +1,36 @@
void fn() {
{
{
{
auto file = {
"integrationtest/feed/etc/config.iniaasdfaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"etc/config.ini"
};
{
int x;
}
}
}
}
}
struct A {
int x, y, z;
}
int main() {
int fun() {
import std.stdio : writeln;
import std.typecons : tuple;
A a = {
tuple(Variant(1))[0].get!int, tuple(Variant(2))[0].get!int,
tuple(Variant(3))[0].get!int
};
A b = {
tuple(Variant(1))[0].get!int, tuple(Variant(2))[0].get!int,
tuple(Variant(3))[0].get!int
};
writeln(a);
}
}

View File

@ -0,0 +1,5 @@
void main() {
stuff[].map!(things => stuff.doThings)
.filter!(stuff)
.array();
}

4
tests/ufcschain.d Normal file
View File

@ -0,0 +1,4 @@
void main()
{
stuff[].map!(things => stuff.doThings).filter!(stuff).array();
}