Add details to indentation stack

This makes more advanced state handling easily possible.
Also moved isWrapIndent/isTempIndent into this, which allows
for exceptions for certain tokens and more control.
This commit is contained in:
WebFreak001 2019-01-11 00:47:50 +01:00
parent 6e4136a353
commit 053b775cd1
2 changed files with 78 additions and 15 deletions

View File

@ -1240,8 +1240,13 @@ private:
break; break;
case tok!"]": case tok!"]":
indents.popWrapIndents(); indents.popWrapIndents();
if (indents.topIs(tok!"]")) if (indents.topIsTemp(tok!"]"))
newline(); {
if (!indents.topDetails.mini)
newline();
else
indents.pop();
}
writeToken(); writeToken();
if (currentIs(tok!"identifier")) if (currentIs(tok!"identifier"))
write(" "); write(" ");
@ -1402,7 +1407,7 @@ private:
: tokens[i .. $].countUntil!(t => t.index == r.front) + i; : tokens[i .. $].countUntil!(t => t.index == r.front) + i;
immutable size_t j = min(expressionEndIndex(i), ufcsBreakLocation); 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.topIsTemp(tok!"]")) ? -indentLevel
: indentLevel; : indentLevel;
linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j], linebreakHints = chooseLineBreakTokens(i, tokens[i .. j], depths[i .. j],
config, currentLineLength, inLvl); config, currentLineLength, inLvl);
@ -1528,7 +1533,7 @@ private:
else if (currentIs(tok!"]")) else if (currentIs(tok!"]"))
{ {
indents.popWrapIndents(); indents.popWrapIndents();
if (indents.topIs(tok!"]")) if (indents.topIsTemp(tok!"]"))
{ {
indents.pop(); indents.pop();
indentLevel = indents.indentLevel; indentLevel = indents.indentLevel;
@ -1671,13 +1676,21 @@ private:
void pushWrapIndent(IdType type = tok!"") void pushWrapIndent(IdType type = tok!"")
{ {
immutable t = type == tok!"" ? tokens[index].type : type; immutable t = type == tok!"" ? tokens[index].type : type;
IndentStack.Details detail;
detail.wrap = isWrapIndent(t);
detail.temp = isTempIndent(t);
pushWrapIndent(t, detail);
}
void pushWrapIndent(IdType type, IndentStack.Details detail)
{
if (parenDepth == 0) if (parenDepth == 0)
{ {
if (indents.wrapIndents == 0) if (indents.wrapIndents == 0)
indents.push(t); indents.push(type, detail);
} }
else if (indents.wrapIndents < 1) else if (indents.wrapIndents < 1)
indents.push(t); indents.push(type, detail);
} }
const pure @safe @nogc: const pure @safe @nogc:

View File

@ -7,6 +7,8 @@ module dfmt.indentation;
import dparse.lexer; import dparse.lexer;
import std.bitmanip : bitfields;
/** /**
* Returns: true if the given token type is a wrap indent type * Returns: true if the given token type is a wrap indent type
*/ */
@ -29,6 +31,20 @@ bool isTempIndent(IdType type) pure nothrow @nogc @safe
*/ */
struct IndentStack struct IndentStack
{ {
static struct Details
{
mixin(bitfields!(
// generally true for all operators except {, case, @, ], (, )
bool, "wrap", 1,
// temporary indentation which get's reverted when a block starts
// generally true for all tokens except ), {, case, @
bool, "temp", 1,
// emit minimal newlines
bool, "mini", 1,
bool, "isAA", 1,
uint, "", 28));
}
/** /**
* Get the indent size at the most recent occurrence of the given indent type * Get the indent size at the most recent occurrence of the given indent type
*/ */
@ -55,7 +71,7 @@ struct IndentStack
int tempIndentCount = 0; int tempIndentCount = 0;
for (size_t i = index; i > 0; i--) for (size_t i = index; i > 0; i--)
{ {
if (!isWrapIndent(arr[i - 1]) && arr[i - 1] != tok!"]") if (!details[i - 1].wrap && arr[i - 1] != tok!"]")
break; break;
tempIndentCount++; tempIndentCount++;
} }
@ -66,8 +82,20 @@ struct IndentStack
* Pushes the given indent type on to the stack. * Pushes the given indent type on to the stack.
*/ */
void push(IdType item) pure nothrow void push(IdType item) pure nothrow
{
Details detail;
detail.wrap = isWrapIndent(item);
detail.temp = isTempIndent(item);
push(item, detail);
}
/**
* Pushes the given indent type on to the stack.
*/
void push(IdType item, Details detail) pure nothrow
{ {
arr[index] = item; arr[index] = item;
details[index] = detail;
//FIXME this is actually a bad thing to do, //FIXME this is actually a bad thing to do,
//we should not just override when the stack is //we should not just override when the stack is
//at it's limit //at it's limit
@ -91,7 +119,7 @@ struct IndentStack
*/ */
void popWrapIndents() pure nothrow @safe @nogc void popWrapIndents() pure nothrow @safe @nogc
{ {
while (index > 0 && isWrapIndent(arr[index - 1])) while (index > 0 && details[index - 1].wrap)
index--; index--;
} }
@ -100,7 +128,7 @@ struct IndentStack
*/ */
void popTempIndents() pure nothrow @safe @nogc void popTempIndents() pure nothrow @safe @nogc
{ {
while (index > 0 && isTempIndent(arr[index - 1])) while (index > 0 && details[index - 1].temp)
index--; index--;
} }
@ -125,7 +153,15 @@ struct IndentStack
*/ */
bool topIsTemp() bool topIsTemp()
{ {
return index > 0 && index <= arr.length && isTempIndent(arr[index - 1]); return index > 0 && index <= arr.length && details[index - 1].temp;
}
/**
* Returns: `true` if the top of the indent stack is a temporary indent with the specified token
*/
bool topIsTemp(IdType item)
{
return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1].temp;
} }
/** /**
@ -133,7 +169,15 @@ struct IndentStack
*/ */
bool topIsWrap() bool topIsWrap()
{ {
return index > 0 && index <= arr.length && isWrapIndent(arr[index - 1]); return index > 0 && index <= arr.length && details[index - 1].wrap;
}
/**
* Returns: `true` if the top of the indent stack is a temporary indent with the specified token
*/
bool topIsWrap(IdType item)
{
return index > 0 && index <= arr.length && arr[index - 1] == item && details[index - 1].wrap;
} }
/** /**
@ -156,6 +200,11 @@ struct IndentStack
return arr[index - 1]; return arr[index - 1];
} }
Details topDetails() const pure nothrow @property @safe @nogc
{
return details[index - 1];
}
int indentLevel() const pure nothrow @property @safe @nogc int indentLevel() const pure nothrow @property @safe @nogc
{ {
return indentSize(); return indentSize();
@ -183,6 +232,7 @@ private:
size_t index; size_t index;
IdType[256] arr; IdType[256] arr;
Details[arr.length] details;
int indentSize(const size_t k = size_t.max) const pure nothrow @safe @nogc int indentSize(const size_t k = size_t.max) const pure nothrow @safe @nogc
{ {
@ -196,17 +246,17 @@ private:
{ {
immutable int pc = (arr[i] == tok!"!" || arr[i] == tok!"(" || arr[i] == tok!")") ? parenCount + 1 immutable int pc = (arr[i] == tok!"!" || arr[i] == tok!"(" || arr[i] == tok!")") ? parenCount + 1
: parenCount; : parenCount;
if ((isWrapIndent(arr[i]) || arr[i] == tok!"(") && parenCount > 1) if ((details[i].wrap || arr[i] == tok!"(") && parenCount > 1)
{ {
parenCount = pc; parenCount = pc;
continue; continue;
} }
if (i + 1 < index) if (i + 1 < index)
{ {
if (arr[i] == tok!"]") if (arr[i] == tok!"]" && details[i].temp)
continue; continue;
immutable currentIsNonWrapTemp = !isWrapIndent(arr[i]) immutable currentIsNonWrapTemp = !details[i].wrap
&& isTempIndent(arr[i]) && arr[i] != tok!")" && arr[i] != tok!"!"; && details[i].temp && arr[i] != tok!")" && arr[i] != tok!"!";
if (arr[i] == tok!"static" if (arr[i] == tok!"static"
&& arr[i + 1].among!(tok!"if", tok!"else", tok!"foreach", tok!"foreach_reverse") && arr[i + 1].among!(tok!"if", tok!"else", tok!"foreach", tok!"foreach_reverse")
&& (i + 2 >= index || arr[i + 2] != tok!"{")) && (i + 2 >= index || arr[i + 2] != tok!"{"))