This is an archive of the discontinued LLVM Phabricator instance.

clang-format: [JS] simplify template string wrapping.
ClosedPublic

Authored by mprobst on Aug 25 2017, 5:55 AM.

Details

Summary

Previously, clang-format would try to wrap template string substitutions
by indenting relative to the openening ${. This helped with
indenting structured strings, such as strings containing HTML, as the
substitutions would be aligned according to the structure of the string.

However it turns out that the overwhelming majority of template string +
substitution usages are for substitutions into non-structured strings,
e.g. URLs or just plain messages. For these situations, clang-format
would often produce very ugly indents, in particular for strings
containing no line breaks:

return `<a href='http://google3/${file}?l=${row}'>${file}</a>(${
                                                                row
                                                              },${
                                                                  col
                                                                }): `;

This change makes clang-format indent template string substitutions as
if they were string concatenation operations. It wraps +4 on overlong
lines and keeps all operands on the same line:

return `<a href='http://google3/${file}?l=${row}'>${file}</a>(${
    row},${col}): `;

While this breaks some lexical continuity between the ${ and row}
here, the overall effects are still a huge improvement, and users can
still manually break the string using + if desired.

Event Timeline

mprobst created this revision.Aug 25 2017, 5:55 AM
djasper accepted this revision.Aug 28 2017, 12:44 AM

Yay for *removing* complexity for a change :).
Let me know how it goes in practice.

This revision is now accepted and ready to land.Aug 28 2017, 12:44 AM
mprobst updated this revision to Diff 112858.Aug 28 2017, 2:00 AM
  • clang-format: [JS] wrap calls w/ literals in template strings.
djasper added inline comments.Aug 28 2017, 2:12 AM
lib/Format/ContinuationIndenter.cpp
1139

This is not the right way to implement this:

  • This is a static computation that we could do ahead of time. Doing it inside the combinatorial exploration of solutions is a waste.
  • You are doing this always, even in code that doesn't have template strings or isn't even JavaScript.
  • This can lead to unexpected behavior if the template string is in a completely unrelated part of the statement. E.g.
someFunction(`test`, { ... });

will be formatted differently from

someFunction('test', { ... });
mprobst added inline comments.Aug 28 2017, 2:21 AM
lib/Format/ContinuationIndenter.cpp
1139

Ack. Do you have suggestions?

I could introduce a bool ParenState::NoLineBreakMustPropagate; that controls this behaviour.

djasper added inline comments.Aug 28 2017, 3:19 AM
lib/Format/ContinuationIndenter.cpp
1139

That, too, would create a significant memory and runtime overhead to everyone just to fix this rather minor formatting detail.
If we were to set MatchingParen correctly to match up "${" to "}", we could measure the respective length and at a very early state (mustBreak()) decide that we need a line break between "${" and the corresponding "}". Now setting that correctly might be hard. Maybe it is ok, to linearly scan in that case as we would only do that if we actually find a template string ending in "${" and the distance to the "}" is usually short.

mprobst added inline comments.Aug 28 2017, 8:48 AM
lib/Format/ContinuationIndenter.cpp
1139

I cannot decide whether I must break in mustBreak - I need to just force wrapping after ${ if I need to wrap somewhere below, but if the code fits on the line, I don't want to wrap. So when I'm visiting ${ I cannot decide that, and when I'm at the object literal expression, the decision for ${ has already been made - right? Or am I missing something?

mprobst updated this revision to Diff 113036.Aug 29 2017, 1:30 AM
  • drop function name wrapping hack
mprobst added inline comments.Aug 29 2017, 1:30 AM
lib/Format/ContinuationIndenter.cpp
1139

I've dropped the function wrapping fix and will land like this, apparently we'll need to think about this a bit more.

This revision was automatically updated to reflect the committed changes.