Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

State: fix column positions for multiline strings #2009

Merged
merged 8 commits into from
Jun 9, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private class BestFirstSearch private (
tokens(deepestYet.depth)
)

val style = styleMap.at(splitToken)
implicit val style = styleMap.at(splitToken)

if (curr.split != null && curr.split.modification.isNewline) {
val tokenHash = hash(splitToken.left)
Expand Down Expand Up @@ -193,7 +193,7 @@ private class BestFirstSearch private (

var optimalNotFound = true
actualSplit.foreach { split =>
val nextState = curr.next(style, split, splitToken)
val nextState = curr.next(split, splitToken)
val updateBest = !keepSlowStates && depth == 0 &&
split.modification.isNewline && !best.contains(curr.depth)
if (updateBest) {
Expand Down Expand Up @@ -289,8 +289,8 @@ private class BestFirstSearch private (
else {
runner.event(Enqueue(split))
val ft = tokens(state.depth)
val style = styleMap.at(ft)
val nextState = state.next(style, split, ft)
implicit val style = styleMap.at(ft)
val nextState = state.next(split, ft)
traverseSameLine(nextState, depth)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,7 @@ class FormatOps(val tree: Tree, baseStyle: ScalafmtConfig) {
lastToken: Token
)(implicit style: ScalafmtConfig): Policy =
if (style.binPack.parentConstructors eq BinPack.ParentCtors.Always) NoPolicy
else if (ownerSet.isEmpty) NoPolicy
else
Policy(lastToken) {
case d @ Decision(t @ FormatToken(_, _: T.KwWith, _), _)
Expand All @@ -1040,11 +1041,12 @@ class FormatOps(val tree: Tree, baseStyle: ScalafmtConfig) {
}

def binPackParentConstructorSplits(
owners: Set[Tree],
chain: Either[Template, Seq[Type.With]],
lastToken: Token,
indentLen: Int
)(implicit line: sourcecode.Line, style: ScalafmtConfig): Seq[Split] = {
val nlMod = NewlineT(acceptSpace = true)
val owners = chain.fold[Set[Tree]](Set(_), x => x.toSet)
val nlPolicy = ctorWithChain(owners, lastToken)
val nlOnelineTag = style.binPack.parentConstructors match {
case BinPack.ParentCtors.Oneline => SplitTag.Active
Expand All @@ -1057,12 +1059,13 @@ class FormatOps(val tree: Tree, baseStyle: ScalafmtConfig) {
if (isOneline) SplitTag.Active else SplitTag.Ignored
}
val indent = Indent(Num(indentLen), lastToken, ExpiresOn.After)
val extendsThenWith = chain.left.exists(_.inits.length > 1)
Seq(
Split(Space, 0).withSingleLine(lastToken),
Split(Space, 0).withSingleLine(lastToken, noSyntaxNL = extendsThenWith),
Split(nlMod, 0)
.onlyFor(nlOnelineTag)
.activateFor(nlOnelineTag)
.withSingleLine(lastToken)
.withSingleLine(lastToken, noSyntaxNL = extendsThenWith)
.withIndent(indent),
Split(nlMod, 1).withPolicy(nlPolicy).withIndent(indent)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,9 @@ class Router(formatOps: FormatOps) {
singleLineDecisionOpt.fold(Split.ignored) { sld =>
val useOpt = lambdaPolicy != null || style.activeForEdition_2020_03
val expire = if (useOpt) endOfSingleLineBlock(closeFT) else close
val policy =
SingleLineBlock(expire, penaliseNewlinesInsideTokens = true)
.andThen(sld)
Split(xmlSpace(leftOwner), 0, policy = policy)
.withOptimalToken(expire, killOnFail = true)
Split(xmlSpace(leftOwner), 0)
.withSingleLine(expire, noSyntaxNL = true, killOnFail = true)
.andThenPolicy(Policy(expire)(sld))
}

Seq(
Expand Down Expand Up @@ -322,13 +320,10 @@ class Router(formatOps: FormatOps) {
afterCurlySpace && style.activeForEdition_2020_01 &&
(!rightOwner.is[Defn] || style.newlines.sourceIs(Newlines.fold))
)
Split(Space, 0)
.withPolicy(
SingleLineBlock(
getOptimalTokenFor(endOfFunction),
penaliseNewlinesInsideTokens = true
)
)
Split(Space, 0).withSingleLineNoOptimal(
getOptimalTokenFor(endOfFunction),
noSyntaxNL = true
)
else Split.ignored
Seq(
spaceSplit,
Expand Down Expand Up @@ -371,7 +366,7 @@ class Router(formatOps: FormatOps) {
val singleLineSplit =
Split(Space, 0)
.notIf(hasSingleLineComment || noSingleLine)
.withPolicy(SingleLineBlock(endOfFunction))
.withSingleLineNoOptimal(endOfFunction)
def newlineSplit =
Split(Newline, 1 + nestedApplies(leftOwner))
.withIndent(indent, endOfFunction, expiresOn)
Expand Down Expand Up @@ -419,7 +414,7 @@ class Router(formatOps: FormatOps) {
Right(Split.ignored)
case t if t.tokens.isEmpty || caseStat.cond.isDefined =>
Right(Split(Space, 0).withSingleLineOpt(t.tokens.lastOption))
case t: Term.If if t.elsep.tokens.isEmpty =>
case t: Term.If if ifWithoutElse(t) =>
// must not use optimal token here, will lead to column overflow
Right(
Split(Space, 0).withSingleLineNoOptimal(t.cond.tokens.last)
Expand Down Expand Up @@ -1224,7 +1219,7 @@ class Router(formatOps: FormatOps) {
}
}
Seq(
Split(NoSplit, 0).withSingleLine(expire),
Split(NoSplit, 0).withSingleLine(expire, noSyntaxNL = true),
Split(NewlineT(acceptNoSplit = true), 1)
.withPolicyOpt(forcedBreakPolicy)
)
Expand Down Expand Up @@ -1283,7 +1278,8 @@ class Router(formatOps: FormatOps) {
// the newline is too cheap even it doesn't actually prevent other newlines.
val penalizeNewlinesInApply = penalizeAllNewlines(expire, 2)
val noSplitPolicy =
SingleLineBlock(expire, exclude).andThen(penalizeNewlinesInApply)
SingleLineBlock(expire, exclude, penaliseNewlinesInsideTokens = true)
.andThen(penalizeNewlinesInApply)
val newlinePolicy = breakOnEveryDot.andThen(penalizeNewlinesInApply)
val ignoreNoSplit =
style.optIn.breakChainOnFirstMethodDot && tok.hasBreak
Expand Down Expand Up @@ -1353,7 +1349,7 @@ class Router(formatOps: FormatOps) {
.orElse(template.map(_.tokens.last))
.getOrElse(rightOwner.tokens.last)
binPackParentConstructorSplits(
template.toSet,
template.toLeft(Seq.empty),
lastToken,
style.continuationIndent.extendSite
)
Expand All @@ -1371,7 +1367,7 @@ class Router(formatOps: FormatOps) {
} =>
splitWithChain(
isFirstWith(template),
Set(template),
Left(template),
templateCurly(template).getOrElse(template.tokens.last)
)

Expand Down Expand Up @@ -1405,7 +1401,7 @@ class Router(formatOps: FormatOps) {
case t @ WithChain(top) =>
splitWithChain(
!t.lhs.is[Type.With],
withChain(top).toSet,
Right(withChain(top)),
top.tokens.last
)

Expand Down Expand Up @@ -1474,10 +1470,11 @@ class Router(formatOps: FormatOps) {
}
val noSpace = isSingleLineComment(right) || shouldBreak(formatToken)
def exclude = insideBlockRanges[T.LeftBrace](formatToken, expire)
val noSyntaxNL = leftOwner.is[Term.ForYield] && right.is[T.KwYield]
Seq(
Split(Space, 0)
.notIf(noSpace)
.withPolicy(SingleLineBlock(expire, exclude = exclude)),
.withSingleLineNoOptimal(expire, exclude, noSyntaxNL = noSyntaxNL),
Split(Newline, 1).withIndent(2, expire, After)
)
case FormatToken(T.RightBrace(), T.KwElse(), _) =>
Expand All @@ -1495,10 +1492,11 @@ class Router(formatOps: FormatOps) {
val expire = rhsOptimalToken(tokens(rightOwner.tokens.last))
val noSpace = shouldBreak(formatToken)
def exclude = insideBlockRanges[T.LeftBrace](formatToken, expire)
val noSyntaxNL = formatToken.right.is[T.KwYield]
Seq(
Split(Space, 0)
.notIf(noSpace)
.withPolicy(SingleLineBlock(expire, exclude = exclude)),
.withSingleLineNoOptimal(expire, exclude, noSyntaxNL = noSyntaxNL),
Split(Newline, 1)
)
// Last else branch
Expand All @@ -1509,7 +1507,7 @@ class Router(formatOps: FormatOps) {
val expire = leftOwner.asInstanceOf[Term.If].elsep.tokens.last
val noSpace = shouldBreak(formatToken)
Seq(
Split(Space, 0).notIf(noSpace).withPolicy(SingleLineBlock(expire)),
Split(Space, 0).notIf(noSpace).withSingleLineNoOptimal(expire),
Split(Newline, 1).withIndent(2, expire, After)
)

Expand Down Expand Up @@ -1618,10 +1616,9 @@ class Router(formatOps: FormatOps) {
case tok @ FormatToken(_, cond @ T.KwIf(), _) if rightOwner.is[Case] =>
val arrow = getCaseArrow(rightOwner.asInstanceOf[Case]).left
val exclude = insideBlockRanges[T.LeftBrace](tok, arrow)
val singleLine = SingleLineBlock(arrow, exclude = exclude)

Seq(
Split(Space, 0, policy = singleLine),
Split(Space, 0).withSingleLineNoOptimal(arrow, exclude = exclude),
Split(Newline, 1).withPolicy(penalizeNewlineByNesting(cond, arrow))
)

Expand Down Expand Up @@ -1758,7 +1755,7 @@ class Router(formatOps: FormatOps) {
val lastToken = leftOwner.asInstanceOf[Term.ForYield].body.tokens.last
Seq(
// Either everything fits in one line or break on =>
Split(Space, 0).withPolicy(SingleLineBlock(lastToken)),
Split(Space, 0).withSingleLineNoOptimal(lastToken),
Split(Newline, 1).withIndent(2, lastToken, After)
)
}
Expand Down Expand Up @@ -1904,7 +1901,7 @@ class Router(formatOps: FormatOps) {

private def splitWithChain(
isFirstWith: Boolean,
chain: => Set[Tree],
chain: => Either[Template, Seq[Type.With]],
lastToken: => Token
)(implicit line: sourcecode.Line, style: ScalafmtConfig): Seq[Split] =
if (isFirstWith) {
Expand Down Expand Up @@ -1974,7 +1971,7 @@ class Router(formatOps: FormatOps) {
case _: Term.Try | _: Term.TryWithHandler =>
SingleLineBlock(expire)
case t: Term.If =>
if (t.elsep.tokens.isEmpty)
if (ifWithoutElse(t))
SingleLineBlock(t.cond.tokens.last)
else
SingleLineBlock(expire)
Expand Down Expand Up @@ -2064,7 +2061,7 @@ class Router(formatOps: FormatOps) {
body match {
case t: Term.If =>
Either.cond(
t.elsep.tokens.nonEmpty,
!ifWithoutElse(t),
SingleLineBlock(expire),
baseSpaceSplit.withSingleLine(t.cond.tokens.last)
)
Expand Down Expand Up @@ -2153,7 +2150,7 @@ class Router(formatOps: FormatOps) {
case Newlines.fold | Newlines.classic =>
postCommentFT.meta.rightOwner match {
case _: Term.Try | _: Term.TryWithHandler => Split.ignored
case t: Term.If if t.elsep.tokens.nonEmpty => Split.ignored
case t: Term.If if !ifWithoutElse(t) => Split.ignored
case t: Term.If =>
Split(Space, 1).withSingleLine(t.cond.tokens.last)
case _ =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,31 +103,41 @@ case class Split(
def withSingleLine(
expire: Token,
exclude: => Set[Range] = Set.empty,
noSyntaxNL: Boolean = false,
killOnFail: Boolean = false
)(implicit line: sourcecode.Line): Split =
withSingleLineAndOptimal(expire, expire, exclude, killOnFail)
withSingleLineAndOptimal(expire, expire, exclude, noSyntaxNL, killOnFail)

def withSingleLineOpt(
expire: Option[Token],
exclude: => Set[Range] = Set.empty,
noSyntaxNL: Boolean = false,
killOnFail: Boolean = false
)(implicit line: sourcecode.Line): Split =
expire.fold(this)(withSingleLine(_, exclude, killOnFail))
expire.fold(this)(withSingleLine(_, exclude, noSyntaxNL, killOnFail))

def withSingleLineAndOptimal(
expire: Token,
optimal: Token,
exclude: => Set[Range] = Set.empty,
noSyntaxNL: Boolean = false,
killOnFail: Boolean = false
)(implicit line: sourcecode.Line): Split =
withOptimalToken(optimal, killOnFail)
.withSingleLineNoOptimal(expire, exclude)
.withSingleLineNoOptimal(expire, exclude, noSyntaxNL)

def withSingleLineNoOptimal(
expire: Token,
exclude: => Set[Range] = Set.empty
exclude: => Set[Range] = Set.empty,
noSyntaxNL: Boolean = false
)(implicit line: sourcecode.Line): Split =
withPolicy(SingleLineBlock(expire, exclude))
withPolicy(
SingleLineBlock(
expire,
exclude,
penaliseNewlinesInsideTokens = noSyntaxNL
)
)

def withPolicyOpt(
newPolicy: => Option[Policy]
Expand Down