Closed lucaswerkmeister closed 10 years ago
indentBefore
for next tokenAn alternative way to implement 3 would be to add a nextIndentBefore
argument which is added to the indentBefore
of the next token. Advantage: Works even if the next token closes a context, and the concept might be easier to explain / understand as it’s nearer to the original indentation (what you mean really is an indentBefore
of the following token).
Problem: I no longer have the guarantee that there’s no other context to be closed, so
Token
s probably have a set of contexts they close instead of one.
Actually, that’s not a problem at all, as closing a context also pops / closes all contexts on top of it – therefore, if the token has a context it closes and there is a “volatile” context to close as well, the context of the Token
in the queue is the “older” of the two contexts.
This means that 3.5’s
Advantage: Works even if the next token closes a context
isn’t valid.
I’m leaning towards 3.5 because it has the advantages of 3 – simple usage, only requires FormattingVisitor
changes in one place – but seems a bit more familiar with the general architecture.
@lucaswerkmeister have you reviewed how Correct Indentation handles this? It treats a line that starts with an =
or =>
, or follows a line which ends in an =
or =>
as a "continuation" line, giving it a double indent. i.e. it does the same thing with =
and =>
that it does with +
and friends.
@gavinking This isn’t about lines that start with =
– I have regular indentBefore
for these (although it might be just 1 for =
, I’ll have to check that). The issue is that indentation after a =
normally stacks, so in the current architecture, I have to choose between
value v = foo(
bar);
// two levels – `=` (unnecessary here) and `(`
or (current behavior)
value v =
foo(bar);
// no levels, because to avoid the above, `=` doesn’t add any indentation
while I really want
value v =
foo(bar);
// one level
IIRC, the IDE currently produces
value v =
foo(bar);
Actually, writing these code samples got me thinking again. What about these:
value v
= foo(
bar);
value v =
foo(
bar);
With the solutions I proposed above, this would be formatted as
value v
= foo(
bar);
value v =
foo(
bar);
Is this right? Or should it be
value v
= foo(
bar);
value v =
foo(
bar);
which would mean that the indentation introduced by the =
token – in one case before it, in the other case after it – does stack. But still,
value v = foo(
bar);
// NOT
value v = foo(
bar);
which would mean that the indentation after the =
stacks iff there’s a line break after the token, and the indentation before the =
stacks iff there’s a line breaks before the token.
(Currently, indentation after a token always stacks, indentation before a token never stacks.)
FTR, the IDE currently yields
value v
= foo(
bar);
value v =
foo(
bar);
I think the IDE's behavior is correct and desirable. I personally really like stuff like:
Html html
=> Html {
head = .... ;
body = .... ;
};
Consider the alternatives:
Html html
=> Html {
head = .... ;
body = .... ;
};
Html html
=> Html {
head = .... ;
body = .... ;
};
Html html
=> Html {
head = .... ;
body = .... ;
};
I don't find any of these better, though, in fairness, the third would be OK.
I would have thought that the last alternative would be okay, but you’re right, in your code sample it makes a lot more sense to not stack. That’s the current behavior, so yay, no change necessary :D
This still leaves the question of what to do with
Html html =>
Html {
head = nothing;
body = nothing;
};
I think this should be
Html html =>
Html {
head = nothing;
body = nothing;
};
which would mean that the =>
’s indentAfter
should stack normally, but only if the =>
is the last token of its line.
(Note that breaking the line after the =>
only happens if it’s that way in the user code; if the original code doesn’t contain any line breaks, or if you use the formatter without a token stream, you get
Html html => Html {
head = nothing;
body = nothing;
};
instead.)
Hm, the IDE proposes
Html html =>
Html {
head = nothing;
body = nothing;
};
instead. @gavinking what do you think?
I’ve pushed the following solution to the issue-37-solution-5
branch:
indentAfter
only stacks if the token is the last of its lineAdds a parameter to FormattingWriter.writeToken
to only use the token’s indentAfter
if the token is the last of its line. That is, in
Html html =>
Html {
head = nothing;
body = nothing;
}
the =>
opens a context, but in
Html html => Html {
head = nothing;
body = nothing;
}
it doesn’t.
@gavinking if you don’t object, I’ll merge this into master
tomorrow-ish.
That's fine, I guess, but it's going to be annoying that the formatter can't be made to produce the same indentation that Correct Indentation produces...
Okay, so option then. Names: indentationAfterSpecifierExpressionStart in { stack, addPreIndent }
or something like that? I’ll add that tomorrow.
Currently, the formatter turns
into
which is obviously wrong. However, if I simply give the
=
anindentAfter
of 1, that will stack everywhere, which is wrong as well. Potential solutions:1. disallow line breaks after
=
Cheap solution, and I suppose I could live with it. The correct way to format the above would then be
2.
indentAfter = 1
, savecontext
in a global variable and close it with next tokenUgly because I have to remember to close that context in a thousand places, and dangerous if I forget it in one place. Still, simple solution that requires no changes to the architecture.
3. add notion of “volatile” indentation to FormattingWriter
Basically the same thing as 2, except built into the FormattingWriter: a context marked
volatile = true
isn’t returned, but instead automatically closed on nextwriteToken
. Problem: I no longer have the guarantee that there’s no other context to be closed, soToken
s probably have a set of contexts they close instead of one.4. completely decouple context stacking and direction of indentation
Currently,
indentBefore
never stacks,indentAfter
always does. I could add two flagsstackIndentBefore
, -After
, and makefalse
andtrue
the defaults.=
would then havestackIndentAfter = false
. 3 is basically one half of this.I’m leaning towards solution 3.