More line wrapping tuning
This commit is contained in:
parent
3e4a131069
commit
48bc7ba0c2
|
@ -9,172 +9,182 @@ import std.d.lexer;
|
||||||
import dfmt.tokens;
|
import dfmt.tokens;
|
||||||
import dfmt.config;
|
import dfmt.config;
|
||||||
|
|
||||||
|
version = WTF_DMD;
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
this(uint breaks, const Token[] tokens, immutable short[] depths, int depth,
|
this(uint breaks, const Token[] tokens, immutable short[] depths,
|
||||||
const Config* config, int currentLineLength, int indentLevel) pure @safe
|
const Config* config, int currentLineLength, int indentLevel) pure @safe
|
||||||
{
|
{
|
||||||
import std.math : abs;
|
import std.math : abs;
|
||||||
import core.bitop : popcnt, bsf;
|
import core.bitop : popcnt, bsf;
|
||||||
import std.algorithm:min;
|
import std.algorithm : min;
|
||||||
|
import std.algorithm : map, sum;
|
||||||
|
|
||||||
immutable remainingCharsMultiplier = 40;
|
// TODO: Figure out what is going on here.
|
||||||
immutable newlinePenalty = 800;
|
version (WTF_DMD)
|
||||||
|
{
|
||||||
|
enum int remainingCharsMultiplier = 40;
|
||||||
|
enum int newlinePenalty = 800;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
immutable int remainingCharsMultiplier = config.columnHardLimit - config.columnSoftLimit;
|
||||||
|
immutable int newlinePenalty = remainingCharsMultiplier * 20;
|
||||||
|
assert(remainingCharsMultiplier == 40);
|
||||||
|
assert(newlinePenalty == 800);
|
||||||
|
}
|
||||||
|
|
||||||
this.breaks = breaks;
|
int cost = 0;
|
||||||
this._depth = depth;
|
for (size_t i = 0; i != uint.sizeof * 8; ++i)
|
||||||
import std.algorithm : map, sum;
|
{
|
||||||
|
if (((1 << i) & breaks) == 0)
|
||||||
|
continue;
|
||||||
|
immutable b = tokens[i].type;
|
||||||
|
immutable p = abs(depths[i]);
|
||||||
|
immutable bc = breakCost(b) * (p == 0 ? 1 : p * 2);
|
||||||
|
cost += bc;
|
||||||
|
}
|
||||||
|
int ll = currentLineLength;
|
||||||
|
bool solved = true;
|
||||||
|
if (breaks == 0)
|
||||||
|
{
|
||||||
|
immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
|
||||||
|
cost = l;
|
||||||
|
if (l > config.columnSoftLimit)
|
||||||
|
{
|
||||||
|
immutable int longPenalty = (l - config.columnSoftLimit) * remainingCharsMultiplier;
|
||||||
|
cost += longPenalty;
|
||||||
|
solved = longPenalty < newlinePenalty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solved = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
foreach (_; 0 .. uint.sizeof * 8)
|
||||||
|
{
|
||||||
|
immutable size_t k = breaks >>> i;
|
||||||
|
immutable bool b = k == 0;
|
||||||
|
immutable size_t j = min(i + bsf(k) + 1, tokens.length);
|
||||||
|
ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
|
||||||
|
if (ll > config.columnHardLimit)
|
||||||
|
{
|
||||||
|
solved = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (ll > config.columnSoftLimit)
|
||||||
|
cost += (ll - config.columnSoftLimit) * remainingCharsMultiplier;
|
||||||
|
i = j;
|
||||||
|
ll = indentLevel * config.indentSize;
|
||||||
|
if (b)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cost += popcnt(breaks) * newlinePenalty;
|
||||||
|
|
||||||
this._cost = 0;
|
this.breaks = breaks;
|
||||||
for (size_t i = 0; i != uint.sizeof * 8; ++i)
|
this._cost = cost;
|
||||||
{
|
this._solved = solved;
|
||||||
if (((1 << i) & breaks) == 0)
|
}
|
||||||
continue;
|
|
||||||
immutable b = tokens[i].type;
|
|
||||||
immutable p = abs(depths[i]);
|
|
||||||
immutable bc = breakCost(b) * (p == 0 ? 1 : p * 2);
|
|
||||||
this._cost += bc;
|
|
||||||
}
|
|
||||||
int ll = currentLineLength;
|
|
||||||
this._solved = true;
|
|
||||||
if (breaks == 0)
|
|
||||||
{
|
|
||||||
immutable int l = currentLineLength + tokens.map!(a => tokenLength(a)).sum();
|
|
||||||
_cost = l;
|
|
||||||
if (l > config.columnSoftLimit)
|
|
||||||
{
|
|
||||||
immutable longPenalty = (l - config.columnSoftLimit) * remainingCharsMultiplier;
|
|
||||||
_cost += longPenalty;
|
|
||||||
this._solved = longPenalty < newlinePenalty;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
this._solved = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
foreach (_; 0 .. 32)
|
|
||||||
{
|
|
||||||
immutable size_t k = breaks >>> i;
|
|
||||||
immutable bool b = k == 0;
|
|
||||||
immutable size_t j = min(i + bsf(k) + 1, tokens.length);
|
|
||||||
ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
|
|
||||||
if (ll > config.columnHardLimit)
|
|
||||||
{
|
|
||||||
this._solved = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (ll > config.columnSoftLimit)
|
|
||||||
_cost += (ll - config.columnSoftLimit) * remainingCharsMultiplier;
|
|
||||||
i = j;
|
|
||||||
ll = indentLevel * config.indentSize;
|
|
||||||
if (b)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._cost += popcnt(breaks) * newlinePenalty;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cost() const pure nothrow @safe @property
|
int cost() const pure nothrow @safe @property
|
||||||
{
|
{
|
||||||
return _cost;
|
return _cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
int depth() const pure nothrow @safe @property
|
int solved() const pure nothrow @safe @property
|
||||||
{
|
{
|
||||||
return _depth;
|
return _solved;
|
||||||
}
|
}
|
||||||
|
|
||||||
int solved() const pure nothrow @safe @property
|
int opCmp(ref const State other) const pure nothrow @safe
|
||||||
{
|
{
|
||||||
return _solved;
|
import core.bitop : bsf, popcnt;
|
||||||
}
|
|
||||||
|
|
||||||
int opCmp(ref const State other) const pure nothrow @safe
|
if (cost < other.cost || (cost == other.cost && ((popcnt(breaks)
|
||||||
{
|
&& popcnt(other.breaks) && bsf(breaks) > bsf(other.breaks))
|
||||||
import core.bitop : bsf , popcnt;
|
|| (_solved && !other.solved))))
|
||||||
if (cost < other.cost || (cost == other.cost && ((popcnt(breaks)
|
{
|
||||||
&& popcnt(other.breaks) && bsf(breaks) > bsf(other.breaks)) || (_solved && !other.solved))))
|
return -1;
|
||||||
{
|
}
|
||||||
return -1;
|
return other.cost > _cost;
|
||||||
}
|
}
|
||||||
return other.cost > _cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool opEquals(ref const State other) const pure nothrow @safe
|
bool opEquals(ref const State other) const pure nothrow @safe
|
||||||
{
|
{
|
||||||
return other.breaks == breaks;
|
return other.breaks == breaks;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t toHash() const nothrow @safe
|
size_t toHash() const pure nothrow @safe
|
||||||
{
|
{
|
||||||
return typeid(breaks).getHash(&breaks);
|
return breaks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint breaks;
|
||||||
|
|
||||||
uint breaks;
|
|
||||||
private:
|
private:
|
||||||
int _cost;
|
int _cost;
|
||||||
int _depth;
|
bool _solved;
|
||||||
bool _solved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens, immutable short[] depths,
|
size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
|
||||||
const Config* config, int currentLineLength, int indentLevel)
|
immutable short[] depths, const Config* config, int currentLineLength, int indentLevel)
|
||||||
{
|
{
|
||||||
import std.container.rbtree : RedBlackTree;
|
import std.container.rbtree : RedBlackTree;
|
||||||
import std.algorithm : filter, min;
|
import std.algorithm : filter, min;
|
||||||
import core.bitop:popcnt;
|
import core.bitop : popcnt;
|
||||||
|
|
||||||
static size_t[] genRetVal(uint breaks, size_t index) pure nothrow @safe
|
static size_t[] genRetVal(uint breaks, size_t index) pure nothrow @safe
|
||||||
{
|
{
|
||||||
auto retVal = new size_t[](popcnt(breaks));
|
auto retVal = new size_t[](popcnt(breaks));
|
||||||
size_t j = 0;
|
size_t j = 0;
|
||||||
foreach (uint i; 0 .. uint.sizeof * 8)
|
foreach (uint i; 0 .. uint.sizeof * 8)
|
||||||
if ((1 << i) & breaks)
|
if ((1 << i) & breaks)
|
||||||
retVal[j++] = index + i;
|
retVal[j++] = index + i;
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8;
|
enum ALGORITHMIC_COMPLEXITY_SUCKS = uint.sizeof * 8;
|
||||||
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
|
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS);
|
||||||
int depth = 0;
|
auto open = new RedBlackTree!State;
|
||||||
auto open = new RedBlackTree!State;
|
open.insert(State(0, tokens[0 .. tokensEnd], depths[0 .. tokensEnd],
|
||||||
open.insert(State(0, tokens[0 .. tokensEnd],
|
config, currentLineLength, indentLevel));
|
||||||
depths[0 .. tokensEnd], depth, config, currentLineLength, indentLevel));
|
State lowest;
|
||||||
State lowest;
|
while (!open.empty)
|
||||||
while (!open.empty)
|
{
|
||||||
{
|
State current = open.front();
|
||||||
State current = open.front();
|
if (current.cost < lowest.cost)
|
||||||
if (current.cost < lowest.cost)
|
lowest = current;
|
||||||
lowest = current;
|
open.removeFront();
|
||||||
open.removeFront();
|
if (current.solved)
|
||||||
if (current.solved)
|
{
|
||||||
{
|
return genRetVal(current.breaks, index);
|
||||||
return genRetVal(current.breaks, index);
|
}
|
||||||
}
|
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd],
|
||||||
validMoves!(typeof(open))(open, tokens[0 .. tokensEnd], depths[0 .. tokensEnd],
|
depths[0 .. tokensEnd], current.breaks, config, currentLineLength, indentLevel);
|
||||||
current.breaks, config, currentLineLength, indentLevel, depth);
|
}
|
||||||
}
|
if (open.empty)
|
||||||
if (open.empty)
|
return genRetVal(lowest.breaks, index);
|
||||||
return genRetVal(lowest.breaks, index);
|
foreach (r; open[].filter!(a => a.solved))
|
||||||
foreach (r; open[].filter!(a => a.solved))
|
return genRetVal(r.breaks, index);
|
||||||
return genRetVal(r.breaks, index);
|
assert(false);
|
||||||
assert(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void validMoves(OR)(auto ref OR output, const Token[] tokens, immutable short[] depths,
|
void validMoves(OR)(auto ref OR output, const Token[] tokens,
|
||||||
uint current, const Config* config, int currentLineLength, int indentLevel,
|
immutable short[] depths, uint current, const Config* config,
|
||||||
int depth) pure
|
int currentLineLength, int indentLevel) pure
|
||||||
{
|
{
|
||||||
import std.algorithm : sort, canFind;
|
import std.algorithm : sort, canFind;
|
||||||
import std.array : insertInPlace;
|
import std.array : insertInPlace;
|
||||||
|
|
||||||
foreach (i, token; tokens)
|
foreach (i, token; tokens)
|
||||||
{
|
{
|
||||||
if (!isBreakToken(token.type) || (((1 << i) & current) != 0))
|
if (!isBreakToken(token.type) || (((1 << i) & current) != 0))
|
||||||
continue;
|
continue;
|
||||||
immutable uint breaks = current | (1 << i);
|
immutable uint breaks = current | (1 << i);
|
||||||
output.insert(State(breaks, tokens, depths, depth + 1, config,
|
output.insert(State(breaks, tokens, depths, config,
|
||||||
currentLineLength, indentLevel));
|
currentLineLength, indentLevel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue