Better line wrapping

This commit is contained in:
Hackerpilot 2015-02-19 17:10:01 -08:00
parent ebe56f3e56
commit df676b9fad
1 changed files with 59 additions and 34 deletions

View File

@ -425,6 +425,12 @@ private:
linebreakHints = chooseLineBreakTokens(index, tokens[index .. i], linebreakHints = chooseLineBreakTokens(index, tokens[index .. i],
config, currentLineLength, indentLevel); config, currentLineLength, indentLevel);
break; break;
case tok!"&&":
case tok!"||":
immutable size_t i = expressionEndIndex();
linebreakHints = chooseLineBreakTokens(index, tokens[index .. i],
config, currentLineLength, indentLevel);
goto case;
case tok!"^^": case tok!"^^":
case tok!"^=": case tok!"^=":
case tok!"^": case tok!"^":
@ -440,7 +446,6 @@ private:
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!"!<>=":
@ -453,7 +458,6 @@ private:
case tok!"/": case tok!"/":
case tok!"..": case tok!"..":
case tok!"%": case tok!"%":
case tok!"&&":
binary: binary:
if (linebreakHints.canFind(index)) if (linebreakHints.canFind(index))
{ {
@ -986,21 +990,21 @@ string generateFixedLengthCases()
"finally", "float", "for", "foreach", "foreach_reverse", "function", "finally", "float", "for", "foreach", "foreach_reverse", "function",
"goto", "idouble", "if", "ifloat", "immutable", "import", "in", "inout", "goto", "idouble", "if", "ifloat", "immutable", "import", "in", "inout",
"int", "interface", "invariant", "ireal", "is", "lazy", "long", "macro", "int", "interface", "invariant", "ireal", "is", "lazy", "long", "macro",
"mixin", "module", "new", "nothrow", "null", "out", "override", "mixin", "module", "new", "nothrow", "null", "out", "override", "package",
"package", "pragma", "private", "protected", "public", "pure", "real", "pragma", "private", "protected", "public", "pure", "real", "ref",
"ref", "return", "scope", "shared", "short", "static", "struct", "super", "return", "scope", "shared", "short", "static", "struct", "super",
"switch", "synchronized", "template", "this", "throw", "true", "try", "switch", "synchronized", "template", "this", "throw", "true", "try",
"typedef", "typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "typedef", "typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "union",
"union", "unittest", "ushort", "version", "void", "volatile", "wchar", "unittest", "ushort", "version", "void", "volatile", "wchar", "while",
"while", "with", "__DATE__", "__EOF__", "__FILE__", "__FUNCTION__", "with", "__DATE__", "__EOF__", "__FILE__", "__FUNCTION__", "__gshared",
"__gshared", "__LINE__", "__MODULE__", "__parameters", "__LINE__", "__MODULE__", "__parameters", "__PRETTY_FUNCTION__",
"__PRETTY_FUNCTION__", "__TIME__", "__TIMESTAMP__", "__traits", "__TIME__", "__TIMESTAMP__", "__traits", "__vector", "__VENDOR__",
"__vector", "__VENDOR__", "__VERSION__", ",", ".", "..", "...", "/", "__VERSION__", ",", ".", "..", "...", "/", "/=", "!", "!<", "!<=", "!<>",
"/=", "!", "!<", "!<=", "!<>", "!<>=", "!=", "!>", "!>=", "$", "%", "%=", "!<>=", "!=", "!>", "!>=", "$", "%", "%=", "&", "&&", "&=", "(", ")", "*",
"&", "&&", "&=", "(", ")", "*", "*=", "+", "++", "+=", "-", "--", "-=", "*=", "+", "++", "+=", "-", "--", "-=", ":", ";", "<", "<<", "<<=", "<=",
":", ";", "<", "<<", "<<=", "<=", "<>", "<>=", "=", "==", "=>", ">", "<>", "<>=", "=", "==", "=>", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?",
">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", "]", "^", "^=", "^^", "@", "[", "]", "^", "^=", "^^", "^^=", "{", "|", "|=", "||", "}", "~",
"^^=", "{", "|", "|=", "||", "}", "~", "~="]; "~="];
return fixedLengthTokens.map!(a => format(`case tok!"%s": return %d;`, a, return fixedLengthTokens.map!(a => format(`case tok!"%s": return %d;`, a,
a.length)).join("\n\t"); a.length)).join("\n\t");
} }
@ -1162,7 +1166,9 @@ 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) * 200);
this._cost = breaks.map!(b => breakCost(tokens[b].type)).sum()
+ (depth * 300);
int ll = currentLineLength; int ll = currentLineLength;
size_t breakIndex = 0; size_t breakIndex = 0;
size_t i = 0; size_t i = 0;
@ -1177,7 +1183,8 @@ struct State
{ {
do do
{ {
immutable size_t j = breakIndex < breaks.length ? breaks[breakIndex] : tokens.length; immutable size_t j = breakIndex < breaks.length
? breaks[breakIndex] : tokens.length;
ll += tokens[i .. j].map!(a => tokenLength(a)).sum(); ll += tokens[i .. j].map!(a => tokenLength(a)).sum();
if (ll > formatterConfig.columnSoftLimit) if (ll > formatterConfig.columnSoftLimit)
{ {
@ -1193,16 +1200,26 @@ struct State
this._solved = s; this._solved = s;
} }
int cost() const pure nothrow @safe @property { return _cost; } int cost() const pure nothrow @safe @property
int depth() const pure nothrow @safe @property { return _depth; } {
int solved() const pure nothrow @safe @property { return _solved; } return _cost;
}
int depth() const pure nothrow @safe @property
{
return _depth;
}
int solved() const pure nothrow @safe @property
{
return _solved;
}
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
|| (cost == other.cost && other.breaks.length && breaks[0] > other.breaks[0]) || (_solved
&& ((breaks.length && other.breaks.length && breaks[0] > other.breaks[0]) && !other.solved))))
|| (_solved && !other.solved))))
{ {
return -1; return -1;
} }
@ -1225,19 +1242,20 @@ 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; import std.algorithm : filter, min;
import core.memory : GC; import core.memory : GC;
enum ALGORITHMIC_COMPLEXITY_SUCKS = 20; enum ALGORITHMIC_COMPLEXITY_SUCKS = 20;
immutable size_t tokensEnd = min(tokens.length, ALGORITHMIC_COMPLEXITY_SUCKS); 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[0 .. tokensEnd], depth, formatterConfig, open.insert(State(cast(size_t[])[], tokens[0 .. tokensEnd], depth,
currentLineLength, indentLevel)); formatterConfig, currentLineLength, indentLevel));
GC.disable(); GC.disable();
scope(exit) GC.enable(); scope(exit) GC.enable();
while (!open.empty) while (!open.empty)
@ -1249,18 +1267,25 @@ size_t[] chooseLineBreakTokens(size_t index, const Token[] tokens,
current.breaks[] += index; current.breaks[] += index;
return current.breaks; return current.breaks;
} }
foreach (next; validMoves(tokens[0 .. tokensEnd], current, formatterConfig, foreach (next; validMoves(tokens[0 .. tokensEnd], current,
currentLineLength, indentLevel, depth)) formatterConfig, currentLineLength, indentLevel, depth))
{ {
open.insert(next); open.insert(next);
} }
} }
size_t[] retVal = open.empty ? [] : open.front().breaks; if (open.empty)
retVal[] += index; return isBreakToken(tokens[0].type) ? [index] : [];
return retVal; foreach (r; open[].filter!(a => a.solved))
{
r.breaks[] += index;
return r.breaks;
}
assert (false);
} }
State[] validMoves(const Token[] tokens, ref const State current, State[] validMoves(const Token[] tokens, ref const State current,
const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel, int depth) const FormatterConfig* formatterConfig, int currentLineLength, int indentLevel,
int depth)
{ {
import std.algorithm : sort, canFind; import std.algorithm : sort, canFind;
import std.array : insertInPlace; import std.array : insertInPlace;