Skip to content

Commit e6fe5df

Browse files
committed
Improve line wrapping heuristics
1 parent 0eea53a commit e6fe5df

26 files changed

+203
-102
lines changed

src/dfmt/formatter.d

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,8 +1220,10 @@ private:
12201220
void regenLineBreakHints(immutable size_t i)
12211221
{
12221222
immutable size_t j = expressionEndIndex(i);
1223+
// Use magical negative value for array literals and wrap indents
1224+
immutable inLvl = (indents.topIsWrap() || indents.topIs(tok!"]")) ? -indentLevel : indentLevel;
12231225
linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j],
1224-
config, currentLineLength, indentLevel);
1226+
config, currentLineLength, inLvl);
12251227
}
12261228

12271229
void regenLineBreakHintsIfNecessary(immutable size_t i)

src/dfmt/indentation.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ private:
209209
continue;
210210
}
211211
}
212+
else if (parenCount == 0 && arr[i] == tok!"(")
213+
size++;
212214
if (arr[i] == tok!"!")
213215
size++;
214216
parenCount = pc;

src/dfmt/tokens.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ int breakCost(IdType p, IdType c) pure nothrow @safe @nogc
136136
case tok!"(":
137137
return 60;
138138
case tok!"[":
139-
return 400;
139+
return 300;
140140
case tok!":":
141141
case tok!";":
142142
case tok!"^^":
@@ -182,7 +182,7 @@ int breakCost(IdType p, IdType c) pure nothrow @safe @nogc
182182
case tok!"+=":
183183
return 200;
184184
case tok!".":
185-
return p == tok!")" ? 0 : 900;
185+
return p == tok!")" ? 0 : 300;
186186
default:
187187
return 1000;
188188
}

src/dfmt/wrapping.d

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ struct State
1818
import core.bitop : popcnt, bsf;
1919
import std.algorithm : min, map, sum;
2020

21-
immutable int remainingCharsMultiplier = config.max_line_length
22-
- config.dfmt_soft_max_line_length;
23-
immutable int newlinePenalty = remainingCharsMultiplier * 20;
21+
immutable int remainingCharsMultiplier = 25;
22+
immutable int newlinePenalty = 480;
2423

2524
this.breaks = breaks;
2625
this._cost = 0;
2726
this._solved = true;
28-
int ll = currentLineLength;
2927

3028
if (breaks == 0)
3129
{
@@ -36,8 +34,6 @@ struct State
3634
this._cost += longPenalty;
3735
this._solved = longPenalty < newlinePenalty;
3836
}
39-
else
40-
this._solved = true;
4137
}
4238
else
4339
{
@@ -49,15 +45,16 @@ struct State
4945
immutable currentType = tokens[i].type;
5046
immutable p = abs(depths[i]);
5147
immutable bc = breakCost(prevType, currentType) * (p == 0 ? 1 : p * 2);
52-
this._cost += bc;
48+
this._cost += bc + newlinePenalty;
5349
}
5450

51+
int ll = currentLineLength;
5552
size_t i = 0;
5653
foreach (_; 0 .. uint.sizeof * 8)
5754
{
5855
immutable uint k = breaks >>> i;
5956
immutable bool b = k == 0;
60-
immutable uint bits = b ? 0 : bsf(k);
57+
immutable uint bits = b ? ALGORITHMIC_COMPLEXITY_SUCKS : bsf(k);
6158
immutable size_t j = min(i + bits + 1, tokens.length);
6259
ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
6360
if (ll > config.dfmt_soft_max_line_length)
@@ -71,12 +68,14 @@ struct State
7168
break;
7269
}
7370
i = j;
74-
ll = indentLevel * config.indent_size;
71+
if (indentLevel < 0)
72+
ll = (abs(indentLevel) + 1) * config.indent_size;
73+
else
74+
ll = (indentLevel + (i == 0 ? 0 : 1)) * config.indent_size;
7575
if (b)
7676
break;
7777
}
7878
}
79-
this._cost += popcnt(breaks) * newlinePenalty;
8079
}
8180

8281
int cost() const pure nothrow @safe @property
@@ -93,13 +92,12 @@ struct State
9392
{
9493
import core.bitop : bsf, popcnt;
9594

96-
if (_cost < other._cost || (_cost == other._cost && ((breaks != 0
97-
&& other.breaks != 0 && bsf(breaks) > bsf(other.breaks))
98-
|| (_solved && !other.solved))))
99-
{
95+
if (_cost < other._cost)
10096
return -1;
101-
}
102-
return other._cost > _cost;
97+
if (_cost == other._cost && (breaks != 0 && other.breaks != 0
98+
&& bsf(breaks) > bsf(other.breaks)))
99+
return -1;
100+
return _cost > other._cost;
103101
}
104102

105103
bool opEquals(ref const State other) const pure nothrow @safe
@@ -119,6 +117,12 @@ private:
119117
bool _solved;
120118
}
121119

120+
private enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8;
121+
122+
/**
123+
* Note: Negative values for `indentLevel` are treated specially: costs for
124+
* continuation indents are reduced. This is used for array literals.
125+
*/
122126
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
123127
immutable short[] depths, const Config* config, int currentLineLength, int indentLevel)
124128
{
@@ -136,24 +140,24 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
136140
return retVal;
137141
}
138142

139-
enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8;
140143
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
141144
auto open = new RedBlackTree!State;
142145
open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd], config,
143146
currentLineLength, indentLevel));
144147
State lowest;
145-
while (!open.empty)
148+
lowest._solved = false;
149+
int tries = 0;
150+
while (!open.empty && tries < 10_00)
146151
{
152+
tries++;
147153
State current = open.front();
148-
if (current.cost < lowest.cost)
149-
lowest = current;
150154
open.removeFront();
151155
if (current.solved)
152-
{
153156
return genRetVal(current.breaks, index);
154-
}
155-
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd],
156-
depths[0 .. tokensEnd], current.breaks, config, currentLineLength, indentLevel);
157+
if (current < lowest)
158+
lowest = current;
159+
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], depths[0 .. tokensEnd],
160+
current.breaks, config, currentLineLength, indentLevel);
157161
}
158162
if (open.empty)
159163
return genRetVal(lowest.breaks, index);
@@ -166,7 +170,7 @@ void validMoves(OR)(auto ref OR output, const Token[] tokens,
166170
immutable short[] depths, uint current, const Config* config,
167171
int currentLineLength, int indentLevel)
168172
{
169-
import std.algorithm : sort, canFind;
173+
import std.algorithm : sort, canFind, min;
170174
import std.array : insertInPlace;
171175

172176
foreach (i, token; tokens)

tests/allman/breakOnDots.d.ref

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ unittest
77
{
88

99
}
10-
abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234)
11-
.abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234);
10+
abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234)
11+
.abcdeabcdeabcde(12341234).abcdeabcdeabcde(12341234);
1212
}
1313
}
1414
}

tests/allman/issue0023.d.d.ref

Whitespace-only changes.

tests/allman/issue0023.d.ref

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,25 @@ string generateFixedLengthCases()
99

1010
string[] fixedLengthTokens = [
1111
"abstract", "alias", "align", "asm", "assert", "auto", "body", "bool",
12-
"break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat",
13-
"char", "class", "const", "continue", "creal", "dchar", "debug",
14-
"default", "delegate", "delete", "deprecated", "do", "double", "else",
15-
"enum", "export", "extern", "false", "final", "finally", "float",
16-
"for", "foreach", "foreach_reverse", "function", "goto", "idouble",
17-
"if", "ifloat", "immutable", "import", "in", "inout", "int",
18-
"interface", "invariant", "ireal", "is", "lazy", "long", "macro",
19-
"mixin", "module", "new", "nothrow", "null", "out", "override",
20-
"package", "pragma", "private", "protected", "public", "pure", "real",
21-
"ref", "return", "scope", "shared", "short", "static", "struct",
22-
"super", "switch", "synchronized", "template", "this", "throw", "true",
23-
"try", "typedef", "typeid", "typeof", "ubyte", "ucent", "uint",
24-
"ulong", "union", "unittest", "ushort", "version", "void", "volatile",
25-
"wchar", "while", "with", "__DATE__", "__EOF__", "__FILE__",
12+
"break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", "char", "class",
13+
"const", "continue", "creal", "dchar", "debug", "default", "delegate", "delete", "deprecated",
14+
"do", "double", "else", "enum", "export", "extern", "false", "final", "finally", "float",
15+
"for", "foreach", "foreach_reverse", "function", "goto", "idouble", "if", "ifloat", "immutable",
16+
"import", "in", "inout", "int", "interface", "invariant", "ireal", "is",
17+
"lazy", "long", "macro", "mixin", "module", "new", "nothrow", "null", "out", "override",
18+
"package", "pragma", "private", "protected", "public", "pure", "real", "ref", "return", "scope",
19+
"shared", "short", "static", "struct", "super", "switch", "synchronized", "template", "this",
20+
"throw", "true", "try", "typedef", "typeid", "typeof", "ubyte", "ucent", "uint", "ulong",
21+
"union", "unittest", "ushort", "version", "void", "volatile", "wchar",
22+
"while", "with", "__DATE__", "__EOF__", "__FILE__",
2623
"__FUNCTION__", "__gshared", "__LINE__", "__MODULE__", "__parameters",
27-
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits",
28-
"__vector", "__VENDOR__", "__VERSION__", ",", ".", "..", "...", "/",
29-
"/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", "!>", "!>=", "$", "%",
30-
"%=", "&", "&&", "&=", "(", ")", "*", "*=", "+", "++", "+=", "-",
31-
"--", "-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==",
32-
"=>", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", "]", "^",
33-
"^=", "^^", "^^=", "{", "|", "|=", "||", "}", "~", "~="
24+
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__",
25+
"__traits", "__vector", "__VENDOR__", "__VERSION__", ",", ".", "..",
26+
"...", "/", "/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", "!>", "!>=",
27+
"$", "%", "%=", "&", "&&", "&=", "(", ")", "*", "*=", "+", "++",
28+
"+=", "-", "--", "-=", ":", ";", "<", "<<", "<<=", "<=", "<>", "<>=",
29+
"=", "==", "=>", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
30+
"]", "^", "^=", "^^", "^^=", "{", "|", "|=", "||", "}", "~", "~="
3431
];
3532

3633
}

tests/allman/issue0111.d.ref

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
struct Test
22
{
3-
this(string name, string[] aliasList, string briefDescription, string examDesc,
4-
string onOpenDesc, string openDesc, string onCloseDesc,
5-
string closeDesc, Flag!"canOpen" canOpen, Flag!"canClose" canClose,
6-
Flag!"isOpen" isOpen)
3+
this(string name, string[] aliasList, string briefDescription, string examDesc, string onOpenDesc,
4+
string openDesc, string onCloseDesc, string closeDesc,
5+
Flag!"canOpen" canOpen, Flag!"canClose" canClose, Flag!"isOpen" isOpen)
76
{
87
}
98
}

tests/allman/issue0112.d.ref

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
unittest
2+
{
3+
testScene = new Scene("TestScene : Test", sceneDescriptions["TestScene"],
4+
connectDescriptions["TestScene"], delegate(Scene scene) {
5+
import std.stdio;
6+
7+
if (!scene.alreadyEntered)
8+
{
9+
fwriteln(
10+
"This is a test. This is a test. This is a test. This is a test. This is a test. Test12.");
11+
auto p = cast(Portal) sceneManager.previousScene;
12+
scene.destroyCurrentScript();
13+
}
14+
});
15+
}

tests/allman/issue0119.d.ref

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ unittest
1717
});
1818
callFunc({
1919
int i = 10;
20-
foo(alpha_longVarName, bravo_longVarName, charlie_longVarName,
21-
delta_longVarName, echo_longVarName, foxtrot_longVarName,
22-
golf_longVarName, echo_longVarName);
20+
foo(alpha_longVarName, bravo_longVarName, charlie_longVarName, delta_longVarName,
21+
echo_longVarName, foxtrot_longVarName, golf_longVarName, echo_longVarName);
2322
doStuff(withThings, andOtherStuff);
2423
return i;
2524
}, more_stuff);

0 commit comments

Comments
 (0)