Now no longer goes completely out of control with long expressions
This commit is contained in:
parent
96501f7418
commit
30c8134b93
48
src/dfmt.d
48
src/dfmt.d
|
@ -391,7 +391,8 @@ private:
|
||||||
writeToken();
|
writeToken();
|
||||||
break;
|
break;
|
||||||
case tok!",":
|
case tok!",":
|
||||||
if (linebreakHints.canFind(index))
|
if (linebreakHints.canFind(index) || (linebreakHints.length == 0
|
||||||
|
&& currentLineLength > config.columnSoftLimit))
|
||||||
{
|
{
|
||||||
writeToken();
|
writeToken();
|
||||||
pushIndent();
|
pushIndent();
|
||||||
|
@ -402,6 +403,9 @@ private:
|
||||||
writeToken();
|
writeToken();
|
||||||
write(" ");
|
write(" ");
|
||||||
}
|
}
|
||||||
|
immutable size_t i = expressionEndIndex();
|
||||||
|
linebreakHints = chooseLineBreakTokens(index, tokens[index .. i],
|
||||||
|
config, currentLineLength, indentLevel);
|
||||||
break;
|
break;
|
||||||
case tok!"=":
|
case tok!"=":
|
||||||
case tok!">=":
|
case tok!">=":
|
||||||
|
@ -1141,11 +1145,11 @@ int breakCost(IdType t)
|
||||||
case tok!"-":
|
case tok!"-":
|
||||||
case tok!"~":
|
case tok!"~":
|
||||||
case tok!"+=":
|
case tok!"+=":
|
||||||
return 55;
|
return 100;
|
||||||
case tok!".":
|
case tok!".":
|
||||||
return 89;
|
return 200;
|
||||||
default:
|
default:
|
||||||
return 144;
|
return 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,7 +1162,7 @@ struct State
|
||||||
this.breaks = breaks;
|
this.breaks = breaks;
|
||||||
this._depth = depth;
|
this._depth = depth;
|
||||||
import std.algorithm : map, sum;
|
import std.algorithm : map, sum;
|
||||||
this._cost = breaks.map!(b => breakCost(tokens[b].type)).sum() + ((depth - 1) * 50);
|
this._cost = breaks.map!(b => breakCost(tokens[b].type)).sum() + ((depth - 1) * 200);
|
||||||
int ll = currentLineLength;
|
int ll = currentLineLength;
|
||||||
size_t breakIndex = 0;
|
size_t breakIndex = 0;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
@ -1166,7 +1170,8 @@ struct State
|
||||||
if (breaks.length == 0)
|
if (breaks.length == 0)
|
||||||
{
|
{
|
||||||
_cost = int.max;
|
_cost = int.max;
|
||||||
s = tokens.map!(a => tokenLength(a)).sum() < formatterConfig.columnSoftLimit;
|
immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
|
||||||
|
s = l < formatterConfig.columnSoftLimit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1195,8 +1200,9 @@ struct State
|
||||||
int opCmp(ref const State other) const pure nothrow @safe
|
int opCmp(ref const State other) const pure nothrow @safe
|
||||||
{
|
{
|
||||||
if (cost < other.cost
|
if (cost < other.cost
|
||||||
|| (cost == other.cost && breaks.length && other.breaks.length && breaks[0] > other.breaks[0])
|
|| (cost == other.cost
|
||||||
|| (cost == other.cost && _solved && !other.solved))
|
&& ((breaks.length && other.breaks.length && breaks[0] > other.breaks[0])
|
||||||
|
|| (_solved && !other.solved))))
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1219,42 +1225,42 @@ private:
|
||||||
int _depth;
|
int _depth;
|
||||||
bool _solved;
|
bool _solved;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
|
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
|
||||||
const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel)
|
const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel)
|
||||||
{
|
{
|
||||||
import std.container.rbtree : RedBlackTree;
|
import std.container.rbtree : RedBlackTree;
|
||||||
|
import std.algorithm : min;
|
||||||
|
|
||||||
|
enum ALGORITHMIC_COMPLEXITY_SUCKS = 20;
|
||||||
|
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
auto open = new RedBlackTree!State;
|
auto open = new RedBlackTree!State;
|
||||||
open.insert(State(cast(size_t[])[], tokens, depth, formatterConfig, currentLineLength, indentLevel));
|
open.insert(State(cast(size_t[])[], tokens[0 .. tokensEnd], depth, formatterConfig,
|
||||||
|
currentLineLength, indentLevel));
|
||||||
while (!open.empty)
|
while (!open.empty)
|
||||||
{
|
{
|
||||||
State current = open.front();
|
State current = open.front();
|
||||||
open.removeFront();
|
open.removeFront();
|
||||||
if (current.solved)
|
if (current.solved)
|
||||||
{
|
{
|
||||||
foreach (ref b; current.breaks)
|
current.breaks[] += index;
|
||||||
b += index;
|
|
||||||
return current.breaks;
|
return current.breaks;
|
||||||
}
|
}
|
||||||
foreach (next; validMoves(tokens, current, formatterConfig, currentLineLength, indentLevel, depth))
|
foreach (next; validMoves(tokens[0 .. tokensEnd], current, formatterConfig,
|
||||||
|
currentLineLength, indentLevel, depth))
|
||||||
{
|
{
|
||||||
open.insert(next);
|
open.insert(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t[] retVal = open.empty ? [] : open.front().breaks;
|
size_t[] retVal = open.empty ? [] : open.front().breaks;
|
||||||
foreach (ref b; retVal)
|
retVal[] += index;
|
||||||
b += index;
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
State[] validMoves(const Token[] tokens, ref const State current,
|
State[] validMoves(const Token[] tokens, ref const State current,
|
||||||
const FormatterConfig* formatterConfig, int currentLineLength,
|
const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth)
|
||||||
int indentLevel, int depth)
|
|
||||||
{
|
{
|
||||||
import std.algorithm : sort, canFind;
|
import std.algorithm : sort, canFind;
|
||||||
import std.array:insertInPlace;
|
import std.array : insertInPlace;
|
||||||
|
|
||||||
State[] states;
|
State[] states;
|
||||||
foreach (i, token; tokens)
|
foreach (i, token; tokens)
|
||||||
|
@ -1273,6 +1279,7 @@ State[] validMoves(const Token[] tokens, ref const State current,
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
|
import std.string : format;
|
||||||
auto sourceCode = q{const Token[] tokens, ref const State current, const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth};
|
auto sourceCode = q{const Token[] tokens, ref const State current, const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth};
|
||||||
LexerConfig config;
|
LexerConfig config;
|
||||||
config.stringBehavior = StringBehavior.source;
|
config.stringBehavior = StringBehavior.source;
|
||||||
|
@ -1280,5 +1287,6 @@ unittest
|
||||||
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
StringCache cache = StringCache(StringCache.defaultBucketCount);
|
||||||
auto tokens = byToken(cast(ubyte[]) sourceCode, config, &cache).array();
|
auto tokens = byToken(cast(ubyte[]) sourceCode, config, &cache).array();
|
||||||
FormatterConfig formatterConfig;
|
FormatterConfig formatterConfig;
|
||||||
assert ([15] == chooseLineBreakTokens(0, tokens, &formatterConfig, 0, 0));
|
auto result = chooseLineBreakTokens(0, tokens, &formatterConfig, 0, 0);
|
||||||
|
assert ([15] == result, "%s".format(result));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue